Skip to content

Commit be30d53

Browse files
committed
Added support for custom namespaces
1 parent 611b54a commit be30d53

8 files changed

Lines changed: 129 additions & 51 deletions

CustomScriptTemplates/GenericSOEventListenerTemplate.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using UnityEngine;
22
using UnityEngine.Events;
33
<CUSTOM_NAMESPACE_LIST>
4+
<NAMESPACE_DECLARATION_START>
45
public class <SCRIPT_NAME> : MonoBehaviour
56
{
67
[System.Serializable]
@@ -24,3 +25,4 @@ public class <SCRIPT_NAME> : MonoBehaviour
2425
response.Invoke(<ARGUMENT_LIST>); //arg1, arg2, arg3...
2526
}
2627
}
28+
<NAMESPACE_DECLARATION_END>

CustomScriptTemplates/GenericSOEventTemplate.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
using System.Collections.Generic;
22
using UnityEngine;
33
<CUSTOM_NAMESPACE_LIST>
4+
<NAMESPACE_DECLARATION_START>
45
[CreateAssetMenu(fileName ="<SO_FILE_NAME>", menuName ="EspidiGames/SO Events/<SO_MENU_NAME>", order = 20)]
56
public class <SCRIPT_NAME> : ScriptableObject
67
{
78
private List<<LISTENER_NAME>> listeners = new List<<LISTENER_NAME>>();
89

9-
1010
public void AddListener(<LISTENER_NAME> listener)
1111
{
1212
if (listeners.Contains(listener))
@@ -37,3 +37,4 @@ public class <SCRIPT_NAME> : ScriptableObject
3737
}
3838
}
3939
}
40+
<NAMESPACE_DECLARATION_END>

CustomScriptTemplates/NoArgsSOEventListenerTemplate.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using UnityEngine;
22
using UnityEngine.Events;
3+
4+
<NAMESPACE_DECLARATION_START>
35
public class <SCRIPT_NAME> : MonoBehaviour
46
{
57
[SerializeField] private <SO_EVENT_NAME> <SO_EVENT_FIELD_NAME>;
@@ -20,3 +22,4 @@ public class <SCRIPT_NAME> : MonoBehaviour
2022
response.Invoke();
2123
}
2224
}
25+
<NAMESPACE_DECLARATION_END>

CustomScriptTemplates/NoArgsSOEventTemplate.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
using System.Collections.Generic;
22
using UnityEngine;
3+
4+
<NAMESPACE_DECLARATION_START>
35
[CreateAssetMenu(fileName ="<SO_FILE_NAME>", menuName ="EspidiGames/SO Events/<SO_MENU_NAME>", order = 20)]
46
public class <SCRIPT_NAME> : ScriptableObject
57
{
68
private List<<LISTENER_NAME>> listeners = new List<<LISTENER_NAME>>();
79

8-
910
public void AddListener(<LISTENER_NAME> listener)
1011
{
1112
if (listeners.Contains(listener))
@@ -36,3 +37,4 @@ public class <SCRIPT_NAME> : ScriptableObject
3637
}
3738
}
3839
}
40+
<NAMESPACE_DECLARATION_END>

Editor/AssetCreationMenu.cs

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
using System;
12
using UnityEditor;
23
using UnityEngine;
34
using System.IO;
45
using UnityEngine.Assertions;
56
using System.Text;
67
using System.Collections;
8+
using System.Linq;
9+
using System.Text.RegularExpressions;
710
using Unity.EditorCoroutines.Editor;
811

912
namespace EG.ScriptableObjectSystem.Editor
@@ -46,7 +49,7 @@ static void OpenScriptableObjectEventCreationWindow()
4649
ScriptableObjectEventCreationWindow.OpenWindow();
4750
}
4851

49-
public static void CreateSOEventScripts(string eventSOName, string eventListenerName, ArgInfo[] args)
52+
public static void CreateSOEventScripts(string eventSOName, string eventListenerName, string eventNamespace, ArgInfo[] args)
5053
{
5154
//Picking the first one by default.
5255
//This will return the selected items' path, or the directory path, if no assets are selected
@@ -79,14 +82,14 @@ public static void CreateSOEventScripts(string eventSOName, string eventListener
7982

8083
var eventArgs = GenerateEventArguments(args);
8184

82-
CreateSOEventScript(creationPath, eventSOName, eventListenerName, eventArgs);
83-
CreateSOEventListenerScript(creationPath, eventSOName, eventListenerName, eventArgs);
85+
CreateSOEventScript(creationPath, eventSOName, eventListenerName, eventNamespace, eventArgs);
86+
CreateSOEventListenerScript(creationPath, eventSOName, eventListenerName, eventNamespace, eventArgs);
8487

8588
//Refresh the Asset Database
8689
AssetDatabase.Refresh();
8790
}
8891

89-
private static void CreateSOEventScript(string creationPath, string eventName, string listenerName, string[] argTypes)
92+
private static void CreateSOEventScript(string creationPath, string eventName, string listenerName, string eventNamespace, string[] argTypes)
9093
{
9194
//1-Load template asset
9295
TextAsset soEventTemplate;
@@ -110,13 +113,18 @@ private static void CreateSOEventScript(string creationPath, string eventName, s
110113
contents = contents.Replace("<SCRIPT_NAME>", eventName);
111114
contents = contents.Replace("<SO_FILE_NAME>", eventName);
112115
contents = contents.Replace("<SO_MENU_NAME>", eventName);
116+
117+
contents = ReplaceNamespaceTag(eventNamespace, contents);
118+
113119
//Event order?
114120
contents = contents.Replace("<LISTENER_NAME>", listenerName);
115121
if(argTypes != null){
116122
contents = contents.Replace("<ARGUMENT_LIST_DEFINITION>", argTypes[0]);
117123
contents = contents.Replace("<ARGUMENT_LIST>", argTypes[1]);
118124
contents = contents.Replace("<CUSTOM_NAMESPACE_LIST>", argTypes[3]);
119125
}
126+
127+
contents = FinalizeIndent(contents);
120128

121129
//4-Create file
122130
var filePath = creationPath + Path.DirectorySeparatorChar + eventName + ".cs";
@@ -131,7 +139,7 @@ private static void CreateSOEventScript(string creationPath, string eventName, s
131139
EditorCoroutineUtility.StartCoroutineOwnerless(iconClass.AddIcon(filePathInProject, EventIconRelativepath));
132140
}
133141

134-
private static void CreateSOEventListenerScript(string creationPath, string eventName, string listenerName, string[] argTypes)
142+
private static void CreateSOEventListenerScript(string creationPath, string eventName, string listenerName, string eventNamespace, string[] argTypes)
135143
{
136144
//1-Load template asset
137145
TextAsset soEventListenerTemplate;
@@ -156,6 +164,9 @@ private static void CreateSOEventListenerScript(string creationPath, string even
156164
contents = contents.Replace("<SCRIPT_NAME>", listenerName);
157165
contents = contents.Replace("<SO_EVENT_NAME>", eventName);
158166
contents = contents.Replace("<SO_EVENT_FIELD_NAME>", eventName.Replace("SO", "so"));
167+
168+
contents = ReplaceNamespaceTag(eventNamespace, contents);
169+
159170
if (argTypes != null)
160171
{
161172
contents = contents.Replace("<ARGUMENT_LIST_DEFINITION>", argTypes[0]);
@@ -164,6 +175,8 @@ private static void CreateSOEventListenerScript(string creationPath, string even
164175
contents = contents.Replace("<CUSTOM_NAMESPACE_LIST>", argTypes[3]);
165176
}
166177

178+
contents = FinalizeIndent(contents);
179+
167180
//4-Create file
168181
var filePath = creationPath + Path.DirectorySeparatorChar + listenerName + ".cs";
169182
using (var sw = new StreamWriter(string.Format(filePath)))
@@ -177,6 +190,18 @@ private static void CreateSOEventListenerScript(string creationPath, string even
177190
EditorCoroutineUtility.StartCoroutineOwnerless(iconClass.AddIcon(filePathInProject, EventListenerIconRelativePath));
178191
}
179192

193+
private static string ReplaceNamespaceTag(string eventNamespace, string contents)
194+
{
195+
var nameSpaceOpening = string.IsNullOrWhiteSpace(eventNamespace) ? string.Empty : $"namespace {eventNamespace}\n{{\n";
196+
var nameSpaceClosing = string.IsNullOrWhiteSpace(eventNamespace) ? string.Empty : "}";
197+
198+
//Using regex so the extra line is removed without doing extra tricks or line by line checks
199+
contents = Regex.Replace(contents, @"<NAMESPACE_DECLARATION_START>\n?\r?", nameSpaceOpening, RegexOptions.Multiline);
200+
contents = contents.Replace("<NAMESPACE_DECLARATION_END>", nameSpaceClosing);
201+
202+
return contents;
203+
}
204+
180205
private static string[] GenerateEventArguments(ArgInfo[] argsList)
181206
{
182207
var result = new string[4];
@@ -233,6 +258,43 @@ private static string[] GenerateEventArguments(ArgInfo[] argsList)
233258
return result;
234259
}
235260

261+
private static string FinalizeIndent(string rawCode, int spacesPerLevel = 4)
262+
{
263+
var lines = rawCode.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
264+
var sb = new StringBuilder();
265+
var currentLevel = 0;
266+
267+
foreach (string line in lines)
268+
{
269+
var trimmedLine = line.Trim();
270+
271+
if (string.IsNullOrEmpty(trimmedLine))
272+
{
273+
sb.AppendLine();
274+
continue;
275+
}
276+
277+
if (trimmedLine.StartsWith("}"))
278+
{
279+
currentLevel = Math.Max(0, currentLevel - 1);
280+
}
281+
282+
var indentation = new string(' ', currentLevel * spacesPerLevel);
283+
sb.AppendLine(indentation + trimmedLine);
284+
285+
// if (trimmedLine.EndsWith("{") || trimmedLine.EndsWith("{ //") || trimmedLine.Contains("{"))
286+
if (trimmedLine.EndsWith("{"))
287+
{
288+
if (trimmedLine.Count(f => f == '{') > trimmedLine.Count(f => f == '}'))
289+
{
290+
currentLevel++;
291+
}
292+
}
293+
}
294+
295+
return sb.ToString().Trim();
296+
}
297+
236298
private static string GetPathInProjectAssets(string fullPath)
237299
{
238300
const string AssetsFolder = "Assets";
@@ -269,7 +331,7 @@ private static string GetPathInProjectAssets(string fullPath)
269331

270332
return path;
271333
}
272-
334+
273335
private static void SetPackageData()
274336
{
275337
var assembly = typeof(AssetCreationMenu).Assembly;

Editor/ScriptableObjectEventCreationWindow.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@ public class ScriptableObjectEventCreationWindow : EditorWindow
1212
private const string EventListenerNamePattern = "{0}EventListener";
1313
private const int MaxArgs = 3;
1414

15-
private static Vector2 InitialWindowDimensions = new Vector2(300, 170);
15+
private static Vector2 InitialWindowDimensions = new Vector2(300, 190);
1616
private static float WindowArgHeightDelta = 50;
1717
private static float WindowCustomArgHeightDelta = 40;
1818

1919
private static ScriptableObjectEventCreationWindow _window;
2020

2121
private ArgInfo[] _argList = new ArgInfo[0];
2222
private string _eventName = "";
23+
private string _namespace;
2324
private string _eventSOName;
2425
private string _eventListenerName;
2526
private int _argCount = 0;
@@ -50,7 +51,7 @@ private IEnumerator MakeWindowModal()
5051
private void OnGUI()
5152
{
5253
EditorGUILayout.Space();
53-
RenderEventNameSection();
54+
RenderEventNameAndNamespaceSection();
5455
EditorGUILayout.Space();
5556
RenderArgumentsSelectorSection();
5657
GUILayout.FlexibleSpace();
@@ -63,9 +64,10 @@ void OnInspectorUpdate()
6364
Repaint();
6465
}
6566

66-
private void RenderEventNameSection()
67+
private void RenderEventNameAndNamespaceSection()
6768
{
6869
_eventName = EditorGUILayout.TextField("Event name:", _eventName);
70+
_namespace = EditorGUILayout.TextField("Namespace (Optional):", _namespace);
6971
}
7072

7173
private void RenderArgumentsSelectorSection()
@@ -136,7 +138,7 @@ private void RenderCreateAssetsButton()
136138
{
137139
if (GUILayout.Button("Create SO event scripts"))
138140
{
139-
AssetCreationMenu.CreateSOEventScripts(_eventSOName, _eventListenerName, _argList);
141+
AssetCreationMenu.CreateSOEventScripts(_eventSOName, _eventListenerName, _namespace, _argList);
140142
Close();
141143
}
142144
}
Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,29 @@
11
using UnityEngine;
22
using UnityEngine.Events;
33

4-
public class BooleanEventListener : MonoBehaviour
4+
namespace SOBaseEvents
55
{
6-
[System.Serializable]
7-
public class CustomUnityEvent : UnityEvent<bool> { } //ARGUMENT_TYPE_LIST -> Type1, Type2, Type3...
6+
public class BooleanEventListener : MonoBehaviour
7+
{
8+
[System.Serializable]
9+
public class CustomUnityEvent : UnityEvent<bool> { } //ARGUMENT_TYPE_LIST -> Type1, Type2, Type3...
810

9-
[SerializeField] private BooleanEventScriptableObject BooleanEventScriptableObject;
10-
[SerializeField] private CustomUnityEvent response;
11+
[SerializeField] private BooleanEventScriptableObject BooleanEventScriptableObject;
12+
[SerializeField] private CustomUnityEvent response;
1113

12-
void OnEnable()
13-
{
14-
BooleanEventScriptableObject.AddListener(this);
15-
}
14+
void OnEnable()
15+
{
16+
BooleanEventScriptableObject.AddListener(this);
17+
}
1618

17-
void OnDisable()
18-
{
19-
BooleanEventScriptableObject.RemoveListener(this);
20-
}
19+
void OnDisable()
20+
{
21+
BooleanEventScriptableObject.RemoveListener(this);
22+
}
2123

22-
public void RiseEvent(bool arg1) //Type1 arg1, Type2 arg2, Type3 arg3...
23-
{
24-
response.Invoke(arg1); //arg1, arg2, arg3...
24+
public void RiseEvent(bool arg1) //Type1 arg1, Type2 arg2, Type3 arg3...
25+
{
26+
response.Invoke(arg1); //arg1, arg2, arg3...
27+
}
2528
}
2629
}
Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,42 @@
11
using System.Collections.Generic;
22
using UnityEngine;
33

4-
[CreateAssetMenu(fileName ="BooleanEventScriptableObject", menuName ="EspidiGames/SO Events/BooleanEventScriptableObject", order = 20)]
5-
public class BooleanEventScriptableObject : ScriptableObject
4+
namespace SOBaseEvents
65
{
7-
private List<BooleanEventListener> listeners = new List<BooleanEventListener>();
6+
[CreateAssetMenu(fileName ="BooleanEventScriptableObject", menuName ="EspidiGames/SO Events/BooleanEventScriptableObject", order = 20)]
7+
public class BooleanEventScriptableObject : ScriptableObject
8+
{
9+
private List<BooleanEventListener> listeners = new List<BooleanEventListener>();
810

911

10-
public void AddListener(BooleanEventListener listener)
11-
{
12-
if (listeners.Contains(listener))
12+
public void AddListener(BooleanEventListener listener)
1313
{
14-
Debug.LogError($"[ScriptableObjectEvents] Listener {listener.name} of GameObject {listener.gameObject.name} already registered. Aborting registration.");
15-
return;
16-
}
14+
if (listeners.Contains(listener))
15+
{
16+
Debug.LogError($"[ScriptableObjectEvents] Listener {listener.name} of GameObject {listener.gameObject.name} already registered. Aborting registration.");
17+
return;
18+
}
1719

18-
listeners.Add(listener);
19-
}
20+
listeners.Add(listener);
21+
}
2022

21-
public void RemoveListener(BooleanEventListener listener)
22-
{
23-
if (!listeners.Contains(listener))
23+
public void RemoveListener(BooleanEventListener listener)
2424
{
25-
Debug.LogError($"[ScriptableObjectEvents] Listener {listener.name} of GameObject {listener.gameObject.name} is not registered. Aborting removal.");
26-
return;
27-
}
25+
if (!listeners.Contains(listener))
26+
{
27+
Debug.LogError($"[ScriptableObjectEvents] Listener {listener.name} of GameObject {listener.gameObject.name} is not registered. Aborting removal.");
28+
return;
29+
}
2830

29-
listeners.Remove(listener);
30-
}
31+
listeners.Remove(listener);
32+
}
3133

32-
public void RiseEvent(bool arg1) //Type1 arg1, Type2 arg2, Type3 arg3...
33-
{
34-
foreach(var listener in listeners)
34+
public void RiseEvent(bool arg1) //Type1 arg1, Type2 arg2, Type3 arg3...
3535
{
36-
listener.RiseEvent(arg1); //arg1, arg2, arg3...
36+
foreach(var listener in listeners)
37+
{
38+
listener.RiseEvent(arg1); //arg1, arg2, arg3...
39+
}
3740
}
3841
}
3942
}

0 commit comments

Comments
 (0)