@@ -87,6 +87,53 @@ public override void Populate(BindingsData.CollectionContext context)
8787 PopulateEngineClassEnumsAndConstants ( context , engineClass ) ;
8888 }
8989
90+ if ( context . IsExtension )
91+ {
92+ // InteropUtils is only generated for the core API, not for GDExtensions.
93+ // Instead, we generate a module initializer in each for each GDExtension that populates InteropUtils.
94+ context . AddGeneratedType ( "NativeInterop/InteropUtils.cs" , new TypeInfo ( "InteropUtils" , context . Options . Namespace )
95+ {
96+ VisibilityAttributes = VisibilityAttributes . Assembly ,
97+ TypeAttributes = TypeAttributes . ReferenceType ,
98+ IsStatic = true ,
99+ DeclaredFields =
100+ {
101+ new FieldInfo ( "_isInitialized" , KnownTypes . SystemBoolean )
102+ {
103+ VisibilityAttributes = VisibilityAttributes . Private ,
104+ IsStatic = true ,
105+ } ,
106+ } ,
107+ DeclaredMethods =
108+ {
109+ new MethodInfo ( "EnsureHelpersInitialized" )
110+ {
111+ VisibilityAttributes = VisibilityAttributes . Assembly ,
112+ Attributes =
113+ {
114+ "[global::System.Runtime.CompilerServices.ModuleInitializer]" ,
115+ } ,
116+ IsStatic = true ,
117+ Body = MethodBody . Create ( writer =>
118+ {
119+ writer . WriteLine ( "if (global::System.Threading.Interlocked.Exchange(ref _isInitialized, true))" ) ;
120+ writer . WriteLine ( "{" ) ;
121+ writer . WriteLine ( " return;" ) ;
122+ writer . WriteLine ( "}" ) ;
123+
124+ foreach ( var engineClass in context . Api . Classes )
125+ {
126+ var type = context . TypeDB . GetTypeFromEngineName ( engineClass . Name ) ;
127+
128+ writer . WriteLine ( $ "global::Godot.NativeInterop.InteropUtils.RegisterExtensionBindingCallbacks({ type . FullNameWithGlobal } .NativeName, { type . FullNameWithGlobal } .BindingCallbacks);") ;
129+ }
130+ } ) ,
131+ } ,
132+ }
133+ } ) ;
134+ return ;
135+ }
136+
90137 // Generate method in InteropUtils to initialize the dictionary with helpers
91138 // used to access constructors and static methods for a Godot class from the
92139 // native class name.
@@ -575,6 +622,10 @@ private static void PopulateEngineClassSignals(BindingsData.CollectionContext co
575622 foreach ( var engineSignal in engineClass . Signals )
576623 {
577624 string eventName = NamingUtils . SnakeToPascalCase ( engineSignal . Name ) ;
625+ if ( context . IsExtension )
626+ {
627+ eventName = $ "{ eventName } Signal";
628+ }
578629
579630 List < TypeInfo > signalParameterTypes = [ ] ;
580631 List < ParameterInfo > signalParameters = [ ] ;
@@ -909,15 +960,19 @@ void AddMemberNameOrRename(HashSet<string> usedNames, MemberInfo member, string
909960
910961 foreach ( var engineSignal in engineClass . Signals )
911962 {
912- AddCachedStringName ( signalNamesType , engineSignal . Name ) ;
963+ AddCachedStringName ( signalNamesType , engineSignal . Name , context . IsExtension ? "Signal" : null ) ;
913964 }
914965
915966 type . NestedTypes . Add ( signalNamesType ) ;
916967 }
917968
918- static void AddCachedStringName ( TypeInfo cacheType , string engineName )
969+ static void AddCachedStringName ( TypeInfo cacheType , string engineName , string ? suffix = null )
919970 {
920971 string name = NamingUtils . SnakeToPascalCase ( engineName ) ;
972+ if ( ! string . IsNullOrEmpty ( suffix ) )
973+ {
974+ name = $ "{ name } { suffix } ";
975+ }
921976
922977 var nameField = new FieldInfo ( $ "_{ engineName } _Value", KnownTypes . GodotStringName )
923978 {
0 commit comments