Skip to content

Commit c766fde

Browse files
committed
merge: add Event System
2 parents 7bb3284 + 3504a25 commit c766fde

2 files changed

Lines changed: 287 additions & 0 deletions

File tree

Assets/Scripts/Core/EventSystem.cs

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
using UnityEngine;
2+
using System;
3+
using System.Collections.Generic;
4+
5+
namespace Knowledge.Core
6+
{
7+
public class EventSystem : MonoBehaviour
8+
{
9+
public static EventSystem Instance { get; private set; }
10+
11+
private Dictionary<string, List<Action<object>>> eventListeners = new Dictionary<string, List<Action<object>>>();
12+
private Dictionary<string, List<Action>> simpleEventListeners = new Dictionary<string, List<Action>>();
13+
14+
private void Awake()
15+
{
16+
if (Instance != null && Instance != this)
17+
{
18+
Destroy(gameObject);
19+
return;
20+
}
21+
22+
Instance = this;
23+
DontDestroyOnLoad(gameObject);
24+
}
25+
26+
public void Subscribe(string eventName, Action listener)
27+
{
28+
if (!simpleEventListeners.ContainsKey(eventName))
29+
{
30+
simpleEventListeners[eventName] = new List<Action>();
31+
}
32+
if (!simpleEventListeners[eventName].Contains(listener))
33+
{
34+
simpleEventListeners[eventName].Add(listener);
35+
}
36+
}
37+
38+
public void Unsubscribe(string eventName, Action listener)
39+
{
40+
if (simpleEventListeners.ContainsKey(eventName))
41+
{
42+
simpleEventListeners[eventName].Remove(listener);
43+
}
44+
}
45+
46+
public void Subscribe<T>(string eventName, Action<T> listener)
47+
{
48+
if (!eventListeners.ContainsKey(eventName))
49+
{
50+
eventListeners[eventName] = new List<Action<object>>();
51+
}
52+
53+
Action<object> wrappedListener = (data) =>
54+
{
55+
if (data is T typedData)
56+
{
57+
listener(typedData);
58+
}
59+
};
60+
61+
if (!eventListeners[eventName].Contains(wrappedListener))
62+
{
63+
eventListeners[eventName].Add(wrappedListener);
64+
}
65+
}
66+
67+
public void Unsubscribe<T>(string eventName, Action<T> listener)
68+
{
69+
if (eventListeners.ContainsKey(eventName))
70+
{
71+
Action<object> wrappedListener = (data) =>
72+
{
73+
if (data is T typedData)
74+
{
75+
listener(typedData);
76+
}
77+
};
78+
eventListeners[eventName].Remove(wrappedListener);
79+
}
80+
}
81+
82+
public void Publish(string eventName)
83+
{
84+
if (simpleEventListeners.ContainsKey(eventName))
85+
{
86+
var listeners = new List<Action>(simpleEventListeners[eventName]);
87+
foreach (var listener in listeners)
88+
{
89+
try
90+
{
91+
listener?.Invoke();
92+
}
93+
catch (Exception e)
94+
{
95+
Debug.LogError($"EventSystem: Error invoking event '{eventName}': {e.Message}");
96+
}
97+
}
98+
}
99+
}
100+
101+
public void Publish<T>(string eventName, T data)
102+
{
103+
if (eventListeners.ContainsKey(eventName))
104+
{
105+
var listeners = new List<Action<object>>(eventListeners[eventName]);
106+
foreach (var listener in listeners)
107+
{
108+
try
109+
{
110+
listener?.Invoke(data);
111+
}
112+
catch (Exception e)
113+
{
114+
Debug.LogError($"EventSystem: Error invoking event '{eventName}': {e.Message}");
115+
}
116+
}
117+
}
118+
}
119+
120+
public void ClearAllEvents()
121+
{
122+
eventListeners.Clear();
123+
simpleEventListeners.Clear();
124+
}
125+
126+
public void ClearEvent(string eventName)
127+
{
128+
if (eventListeners.ContainsKey(eventName))
129+
{
130+
eventListeners[eventName].Clear();
131+
}
132+
if (simpleEventListeners.ContainsKey(eventName))
133+
{
134+
simpleEventListeners[eventName].Clear();
135+
}
136+
}
137+
138+
public int GetListenerCount(string eventName)
139+
{
140+
int count = 0;
141+
if (eventListeners.ContainsKey(eventName))
142+
{
143+
count += eventListeners[eventName].Count;
144+
}
145+
if (simpleEventListeners.ContainsKey(eventName))
146+
{
147+
count += simpleEventListeners[eventName].Count;
148+
}
149+
return count;
150+
}
151+
152+
private void OnDestroy()
153+
{
154+
if (Instance == this)
155+
{
156+
Instance = null;
157+
}
158+
ClearAllEvents();
159+
}
160+
}
161+
162+
public static class GameEvents
163+
{
164+
public const string GamePaused = "GamePaused";
165+
public const string GameResumed = "GameResumed";
166+
public const string GameStarted = "GameStarted";
167+
public const string GameOver = "GameOver";
168+
public const string LevelUp = "LevelUp";
169+
public const string SaveLoaded = "SaveLoaded";
170+
public const string SaveSaved = "SaveSaved";
171+
172+
public const string PlayerHealthChanged = "PlayerHealthChanged";
173+
public const string PlayerEnergyChanged = "PlayerEnergyChanged";
174+
public const string PlayerDied = "PlayerDied";
175+
public const string ItemCollected = "ItemCollected";
176+
public const string ItemUsed = "ItemUsed";
177+
public const string EquipmentChanged = "EquipmentChanged";
178+
179+
public const string ElementDiscovered = "ElementDiscovered";
180+
public const string RecipeUnlocked = "RecipeUnlocked";
181+
public const string CraftingComplete = "CraftingComplete";
182+
public const string KnowledgePointsGained = "KnowledgePointsGained";
183+
184+
public const string WeatherChanged = "WeatherChanged";
185+
public const string TimeOfDayChanged = "TimeOfDayChanged";
186+
public const string EraChanged = "EraChanged";
187+
188+
public const string QuestStarted = "QuestStarted";
189+
public const string QuestCompleted = "QuestCompleted";
190+
public const string QuestFailed = "QuestFailed";
191+
192+
public const string AchievementUnlocked = "AchievementUnlocked";
193+
}
194+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
using NUnit.Framework;
2+
using UnityEngine;
3+
using System;
4+
5+
namespace Knowledge.Tests.Core
6+
{
7+
[TestFixture]
8+
public class EventSystemTests
9+
{
10+
private EventSystem eventSystem;
11+
private int eventReceivedCount;
12+
private object receivedData;
13+
14+
[SetUp]
15+
public void Setup()
16+
{
17+
var gameObject = new GameObject("EventSystem");
18+
eventSystem = gameObject.AddComponent<EventSystem>();
19+
eventReceivedCount = 0;
20+
receivedData = null;
21+
}
22+
23+
[TearDown]
24+
public void Teardown()
25+
{
26+
eventSystem.ClearAllEvents();
27+
Object.DestroyImmediate(eventSystem.gameObject);
28+
}
29+
30+
[Test]
31+
public void Subscribe_ValidEvent_AddsListener()
32+
{
33+
eventSystem.Subscribe("TestEvent", OnTestEvent);
34+
eventSystem.Publish("TestEvent");
35+
Assert.AreEqual(1, eventReceivedCount);
36+
}
37+
38+
[Test]
39+
public void Unsubscribe_RemovesListener()
40+
{
41+
eventSystem.Subscribe("TestEvent", OnTestEvent);
42+
eventSystem.Unsubscribe("TestEvent", OnTestEvent);
43+
eventSystem.Publish("TestEvent");
44+
Assert.AreEqual(0, eventReceivedCount);
45+
}
46+
47+
[Test]
48+
public void Publish_WithData_PassesDataToListener()
49+
{
50+
eventSystem.Subscribe("TestEvent", OnTestEventWithData);
51+
eventSystem.Publish("TestEvent", "TestData");
52+
Assert.AreEqual("TestData", receivedData);
53+
}
54+
55+
[Test]
56+
public void MultipleSubscribers_AllReceiveEvent()
57+
{
58+
int count1 = 0, count2 = 0;
59+
eventSystem.Subscribe("TestEvent", () => count1++);
60+
eventSystem.Subscribe("TestEvent", () => count2++);
61+
eventSystem.Publish("TestEvent");
62+
Assert.AreEqual(1, count1);
63+
Assert.AreEqual(1, count2);
64+
}
65+
66+
[Test]
67+
public void Publish_NoSubscribers_NoError()
68+
{
69+
Assert.DoesNotThrow(() => eventSystem.Publish("NonExistentEvent"));
70+
}
71+
72+
[Test]
73+
public void ClearAllEvents_RemovesAllListeners()
74+
{
75+
eventSystem.Subscribe("Event1", OnTestEvent);
76+
eventSystem.Subscribe("Event2", OnTestEvent);
77+
eventSystem.ClearAllEvents();
78+
eventSystem.Publish("Event1");
79+
eventSystem.Publish("Event2");
80+
Assert.AreEqual(0, eventReceivedCount);
81+
}
82+
83+
private void OnTestEvent()
84+
{
85+
eventReceivedCount++;
86+
}
87+
88+
private void OnTestEventWithData(object data)
89+
{
90+
receivedData = data;
91+
}
92+
}
93+
}

0 commit comments

Comments
 (0)