1010using UnityEditor ;
1111using System . IO ;
1212using Unity . VisualScripting ;
13+ using Unity . VisualScripting . Community . Libraries . CSharp ;
14+ using System . Reflection ;
15+ using ParameterModifier = Unity . VisualScripting . Community . Libraries . CSharp . ParameterModifier ;
16+ using UnityEngine . UI ;
1317
14- public class AOTMethodsPrebuilder : IPreprocessBuildWithReport
18+ namespace Unity . VisualScripting . Community
1519{
16- public int callbackOrder => 1 ;
17-
18- private List < TypeGroup > typesToSupport = new ( ) ;
19-
20- public void OnPreprocessBuild ( BuildReport report )
21- {
22- GenerateScript ( ) ;
23- AssetDatabase . Refresh ( ) ;
24- }
25-
26-
27- private void GenerateScript ( )
20+ public class AOTMethodsPrebuilder : IPreprocessBuildWithReport
2821 {
29- EditorUtility . DisplayProgressBar ( "Generating Aot Support" , "Finding Script Graphs and Scenes..." , 0f ) ;
30- typesToSupport = GetTypesForAOTMethods ( ) . Distinct ( ) . ToList ( ) ;
31- typesToSupport . RemoveAll ( type => type . types . Count == 0 ) ;
32- string scriptContent = GenerateScriptContent ( typesToSupport ) ;
33- string path = Application . dataPath + "/Unity.VisualScripting.Community.Generated/Scripts/AotSupportMethods.cs" ;
34- Debug . Log ( "Generated OnUnityEvent Support script at : " + path + "\n Ensure that the script stays here" ) ;
35- HUMIO . Ensure ( path ) . Path ( ) ;
36- File . WriteAllText ( path , scriptContent ) ;
37- AssetDatabase . Refresh ( ) ;
38- EditorUtility . ClearProgressBar ( ) ;
39- }
22+ public int callbackOrder => 1 ;
4023
41- private string GenerateScriptContent ( List < TypeGroup > typeGroups )
42- {
43- HashSet < string > namespaces = new HashSet < string > ( ) ;
24+ private List < TypeGroup > typesToSupport = new List < TypeGroup > ( ) ;
4425
45- foreach ( var typeGroup in typeGroups )
26+ public void OnPreprocessBuild ( BuildReport report )
4627 {
47- foreach ( var type in typeGroup . types )
48- {
49- string namespaceName = type . Namespace ;
50- if ( ! string . IsNullOrEmpty ( namespaceName ) && ! IsIncludedNamespace ( namespaceName ) && AllowedNameSpace ( namespaceName ) )
51- {
52- namespaces . Add ( namespaceName ) ;
53- }
54- }
55-
28+ GenerateScript ( ) ;
29+ AssetDatabase . Refresh ( ) ;
5630 }
5731
58- string namespaceDeclarations = string . Join ( Environment . NewLine , namespaces . Select ( ns => $ "using { ns } ;") ) ;
59- string scriptContent = $ "{ namespaceDeclarations } \n ";
60- scriptContent += @"using System;
61- using UnityEngine.Events;
62- using Unity.VisualScripting;
63- using Unity.VisualScripting.Community;
64-
65- public static class AotSupportMethods
66- {
67- " ;
68-
69- foreach ( var typeGroup in typeGroups )
32+ private void GenerateScript ( )
7033 {
71- string methodParameters = string . Join ( ", " , typeGroup . types . Select ( type => CSharpName ( type , true ) ) ) ;
72-
73- string methodReturnType = "UnityAction<" + methodParameters + ">" ;
34+ EditorUtility . DisplayProgressBar ( "Generating Aot Support" , "Finding Script Graphs and Scenes..." , 0f ) ;
35+ typesToSupport = GetTypesForAOTMethods ( ) . Distinct ( ) . ToList ( ) ;
36+ EditorUtility . ClearProgressBar ( ) ;
37+ typesToSupport . RemoveAll ( type => type . types . Count == 0 ) ;
38+ string scriptContent = GenerateScriptContent ( typesToSupport ) ;
39+ var BasePath = Path . Combine ( Application . dataPath , AssetCompiler . GeneratedPath ) ;
40+ var ScriptsPath = Path . Combine ( BasePath , "Scripts" ) ;
41+ Debug . Log ( "Generated OnUnityEvent Support script at : " + ScriptsPath + "\n Ensure that the script stays here" ) ;
42+ File . WriteAllText ( Application . dataPath + "/" + AssetCompiler . GeneratedPath + "/Scripts" + "/AotSupportMethods.cs" , scriptContent ) ;
43+ AssetDatabase . Refresh ( ) ;
44+ }
7445
75- scriptContent += $ " public static { methodReturnType } { string . Join ( "_" , typeGroup . types . Select ( type => CSharpName ( type , false ) ) ) } Handler(GraphReference reference, OnUnityEvent onUnityEvent)\n ";
76- scriptContent += " {\n " ;
46+ private readonly List < string > includedNamespaces = new List < string >
47+ {
48+ "System" ,
49+ "UnityEngine.Events" ,
50+ "Unity.VisualScripting" ,
51+ "Unity.VisualScripting.Community"
52+ } ;
53+ private string GenerateScriptContent ( List < TypeGroup > typeGroups )
54+ {
55+ HashSet < string > namespaces = new HashSet < string > ( includedNamespaces ) ;
7756
78- // Construct argument list
79- List < string > args = new List < string > ( ) ;
80- for ( int i = 0 ; i < typeGroup . types . Count ; i ++ )
57+ foreach ( var typeGroup in typeGroups )
8158 {
82- args . Add ( "arg" + i ) ;
83- }
59+ foreach ( var type in typeGroup . types )
60+ {
61+ string namespaceName = type . Namespace ;
62+ if ( ! string . IsNullOrEmpty ( namespaceName ) && ! IsIncludedNamespace ( namespaceName ) && AllowedNameSpace ( type ) )
63+ {
64+ namespaces . Add ( namespaceName ) ;
65+ }
66+ }
8467
85- // Construct event data initialization
86- string eventData = "" ;
87- for ( int i = 0 ; i < typeGroup . types . Count ; i ++ )
88- {
89- eventData += $ "Value{ i } = arg{ i } ,{ ( i != typeGroup . types . Count - 1 ? "\n " : "" ) } \t \t \t \t ";
9068 }
9169
92- // Append method body
93- scriptContent += @$ " return ({ string . Join ( ", " , args ) } ) =>
94- {{
95- onUnityEvent.Trigger(reference, new EventData
96- {{
97- { eventData }
98- }});
99- }};
100- " ;
101- scriptContent += " }\n \n " ;
102- }
103-
104- scriptContent += "}\n " ;
70+ var @namespace = NamespaceGenerator . Namespace ( "Unity.VisualScripting.Community.Generated" ) ;
71+ var @class = ClassGenerator . Class ( RootAccessModifier . Public , ClassModifier . Static , "AotSupportMethods" , null , "" , namespaces . ToList ( ) ) ;
72+ var processedGroups = new HashSet < TypeGroup > ( ) ;
73+ foreach ( var typeGroup in typeGroups )
74+ {
75+ if ( ! processedGroups . Add ( typeGroup ) )
76+ continue ;
77+ string methodParameters = string . Join ( ", " , typeGroup . types . Select ( type => type . CSharpFullName ( true ) ) ) ;
78+ string methodReturnType = "UnityAction<" + methodParameters + ">" ;
79+ var method = MethodGenerator . Method ( AccessModifier . Public , MethodModifier . Static , methodReturnType , "UnityEngine.Events" , string . Join ( "_" , typeGroup . types . Select ( type => type . HumanName ( false ) . Replace ( " " , "" ) ) ) + "Handler" ) ;
80+ method . AddParameter ( ParameterGenerator . Parameter ( "reference" , typeof ( GraphReference ) , ParameterModifier . None ) ) ;
81+ method . AddParameter ( ParameterGenerator . Parameter ( "onUnityEvent" , typeof ( OnUnityEvent ) , ParameterModifier . None ) ) ;
82+ method . SetWarning ( $ "Method generated from { typeGroup . parent . CSharpFullName ( ) } ") ;
83+ List < string > args = new List < string > ( ) ;
84+ for ( int i = 0 ; i < typeGroup . types . Count ; i ++ )
85+ {
86+ args . Add ( "arg" + i ) ;
87+ }
10588
106- return scriptContent ;
107- }
89+ string eventData = "" ;
90+ for ( int i = 0 ; i < typeGroup . types . Count ; i ++ )
91+ {
92+ eventData += $ "Value{ i } = arg{ i } ,{ ( i != typeGroup . types . Count - 1 ? "\n " : "" ) } \t \t ";
93+ }
10894
10995
110- private string CSharpName ( Type type , bool lowerCase )
111- {
112- if ( lowerCase )
113- {
114- if ( type == null ) return "null" ;
115- if ( type == typeof ( int ) ) return "int" ;
116- if ( type == typeof ( string ) ) return "string" ;
117- if ( type == typeof ( float ) ) return "float" ;
118- if ( type == typeof ( double ) ) return "double" ;
119- if ( type == typeof ( bool ) ) return "bool" ;
120- if ( type == typeof ( byte ) ) return "byte" ;
121- if ( type == typeof ( object ) && type . BaseType == null ) return "object" ;
122- if ( type == typeof ( object [ ] ) ) return "object[]" ;
123-
124- if ( type . IsGenericType )
125- {
126- string genericTypeName = $ "{ type . Namespace } .{ type . Name . Split ( '`' ) [ 0 ] } <{ string . Join ( ", " , type . GetGenericArguments ( ) . Select ( arg => CSharpName ( arg , true ) ) ) } >";
127- return string . Concat ( genericTypeName . Where ( c => char . IsLetter ( c ) || c == '<' || c == '>' || c == '.' || c == ',' ) ) ;
96+ var body = @$ "return ({ string . Join ( ", " , args ) } ) =>
97+ {{
98+ onUnityEvent.Trigger(reference, new EventData
99+ {{
100+ { eventData }
101+ }});
102+ }};" ;
103+ method . Body ( body ) ;
104+ @class . AddMethod ( method ) ;
128105 }
129-
130- return type . Namespace + "." + type . Name ;
106+ @namespace . AddClass ( @class ) ;
107+ return @namespace . GenerateClean ( 0 ) ;
131108 }
132- else
109+
110+ private List < TypeGroup > GetTypesForAOTMethods ( )
133111 {
134- if ( type == null ) return "null" ;
135- if ( type == typeof ( int ) ) return "Int" ;
136- if ( type == typeof ( string ) ) return "String" ;
137- if ( type == typeof ( float ) ) return "Float" ;
138- if ( type == typeof ( double ) ) return "Double" ;
139- if ( type == typeof ( bool ) ) return "Bool" ;
140- if ( type == typeof ( byte ) ) return "Byte" ;
141- if ( type == typeof ( object ) && type . BaseType == null ) return type . Namespace + "Object" ;
142- if ( type == typeof ( object [ ] ) ) return "ObjectArray" ;
143-
144- string typeName = string . Concat ( type . Name . Split ( '.' ) . Select ( word => char . ToUpper ( word [ 0 ] ) + word . Substring ( 1 ) ) ) ;
145-
146- if ( type . IsGenericType )
147- {
148- typeName = typeName . Replace ( "`" , "Generic" ) ;
149- }
112+ List < TypeGroup > types = new List < TypeGroup > ( ) ;
150113
151- if ( type . IsArray )
114+ var allTypes = AppDomain . CurrentDomain . GetAssemblies ( ) . SelectMany ( assembly => assembly . GetTypes ( ) . Where ( type => typeof ( UnityEventBase ) . IsAssignableFrom ( type ) ) ) . ToList ( ) ;
115+
116+ int count = allTypes . Count ;
117+ for ( int i = 0 ; i < count ; i ++ )
152118 {
153- typeName = typeName . Replace ( "[]" , "Array" ) ;
154- }
119+ var currentType = allTypes [ i ] ;
120+ var type = currentType . IsGenericType ? currentType : currentType . BaseType ;
121+ float progress = ( float ) i / count ;
122+
123+ if ( type . IsPublic
124+ && type . IsGenericType
125+ && EditorTypeUtility . IsRuntimeType ( type )
126+ && type . GetGenericArguments ( ) . All ( arg => EditorTypeUtility . IsClosedGeneric ( arg ) ) )
127+ {
128+ EditorUtility . DisplayProgressBar ( "Generating Aot Support Methods for OnUnityEvent" , $ "Found { type . HumanName ( true ) } ...", progress ) ;
155129
156- typeName = string . Concat ( typeName . Where ( c => char . IsLetterOrDigit ( c ) || c == '_' ) ) ;
130+ types . Add ( new TypeGroup ( currentType , type . GetGenericArguments ( ) ) ) ;
131+ }
132+ }
157133
158- return typeName ;
134+ return types ;
159135 }
160- }
161-
162- public List < TypeGroup > GetTypesForAOTMethods ( )
163- {
164- List < TypeGroup > types = new List < TypeGroup > ( ) ;
165136
166- foreach ( var type in AppDomain . CurrentDomain . GetAssemblies ( ) . SelectMany ( assembly => assembly . GetTypes ( ) . Where ( type => type . Inherits ( typeof ( UnityEventBase ) ) ) ) )
137+ private bool IsIncludedNamespace ( string _namespace )
167138 {
168- if ( type . BaseType . IsGenericType && ! type . BaseType . GetGenericArguments ( ) . Any ( arg => arg . IsGenericTypeParameter ) && type . BaseType . GetGenericArguments ( ) . All ( _type => _type . IsPublic && AllowedNameSpace ( _type . Namespace ) ) )
169- {
170- types . Add ( new TypeGroup ( type . BaseType . GetGenericArguments ( ) ) ) ;
171- }
139+ if ( string . IsNullOrEmpty ( _namespace ) ) return false ;
140+ return includedNamespaces . Contains ( _namespace ) ;
172141 }
173142
174- return types ;
175- }
176-
177- private bool IsIncludedNamespace ( string _namespace )
178- {
179- if ( string . IsNullOrEmpty ( _namespace ) ) return false ;
180- return _namespace == "System" || _namespace == "UnityEngine.Events" || _namespace == "Unity.VisualScripting" || _namespace == "Unity.VisualScripting.Community" ;
181- }
182-
183- private bool AllowedNameSpace ( string _namespace )
184- {
185- if ( string . IsNullOrEmpty ( _namespace ) ) return false ;
186- if ( _namespace . Contains ( "UnityEditor" ) || _namespace . Contains ( "NUnit" ) ) return false ;
187- return true ;
188- }
189-
190- public class TypeGroup : IEquatable < TypeGroup >
191- {
192- public TypeGroup ( params Type [ ] types )
143+ private bool AllowedNameSpace ( Type type )
193144 {
194- this . types = types . ToList ( ) ;
145+ if ( string . IsNullOrEmpty ( type . Namespace ) ) return false ;
146+ var rootNamespace = type . RootNamespace ( ) ;
147+ if ( rootNamespace == "UnityEditor" || rootNamespace == "UnityEditorInternal" ||
148+ type . Namespace . Contains ( "UnityEditor" ) || type . Namespace . Contains ( "NUnit" ) ) return false ;
149+ return true ;
195150 }
196151
197- public List < Type > types = new List < Type > ( ) ;
198-
199- public bool Equals ( TypeGroup other )
152+ private class TypeGroup : IEquatable < TypeGroup >
200153 {
201- if ( other == null || other . types . Count != types . Count )
154+ public TypeGroup ( Type parent , params Type [ ] types )
202155 {
203- return false ;
156+ this . parent = parent ;
157+ this . types = types . ToList ( ) ;
204158 }
205159
206- for ( int i = 0 ; i < types . Count ; i ++ )
160+ public Type parent ;
161+ public List < Type > types = new List < Type > ( ) ;
162+
163+ public bool Equals ( TypeGroup other )
207164 {
208- if ( types [ i ] != other . types [ i ] )
165+ if ( other == null || other . types . Count != types . Count )
209166 {
210167 return false ;
211168 }
212- }
213169
214- return true ;
215- }
170+ for ( int i = 0 ; i < types . Count ; i ++ )
171+ {
172+ if ( types [ i ] != other . types [ i ] )
173+ {
174+ return false ;
175+ }
176+ }
216177
217- public override bool Equals ( object obj )
218- {
219- if ( obj is TypeGroup other )
178+ return true ;
179+ }
180+
181+ public override bool Equals ( object obj )
220182 {
221- return Equals ( other ) ;
183+ if ( obj is TypeGroup other )
184+ {
185+ return Equals ( other ) ;
186+ }
187+ return false ;
222188 }
223- return false ;
224- }
225189
226- public override int GetHashCode ( )
227- {
228- unchecked
190+ public override int GetHashCode ( )
229191 {
230- int hash = 17 ;
231- foreach ( var type in types )
192+ unchecked
232193 {
233- hash = hash * 23 + type . GetHashCode ( ) ;
194+ int hash = 17 ;
195+ foreach ( var type in types )
196+ {
197+ hash = hash * 23 + type . GetHashCode ( ) ;
198+ }
199+ return hash ;
234200 }
235- return hash ;
236201 }
237202 }
238203 }
239- }
204+ }
0 commit comments