@@ -166,6 +166,11 @@ private void CreateNetworkVariableTypeInitializers(AssemblyDefinition assembly)
166166
167167 foreach ( var type in m_WrappedNetworkVariableTypes )
168168 {
169+ if ( type . Resolve ( ) == null )
170+ {
171+ continue ;
172+ }
173+
169174 if ( IsSpecialCaseType ( type ) )
170175 {
171176 continue ;
@@ -251,11 +256,15 @@ private void CreateNetworkVariableTypeInitializers(AssemblyDefinition assembly)
251256 private FieldReference m_NetworkManager_rpc_name_table_FieldRef ;
252257 private MethodReference m_NetworkManager_rpc_name_table_Add_MethodRef ;
253258 private TypeReference m_NetworkBehaviour_TypeRef ;
259+ private TypeReference m_NetworkVariableBase_TypeRef ;
260+ private MethodReference m_NetworkVariableBase_Initialize_MethodRef ;
261+ private MethodReference m_NetworkBehaviour___nameNetworkVariable_MethodRef ;
254262 private MethodReference m_NetworkBehaviour_beginSendServerRpc_MethodRef ;
255263 private MethodReference m_NetworkBehaviour_endSendServerRpc_MethodRef ;
256264 private MethodReference m_NetworkBehaviour_beginSendClientRpc_MethodRef ;
257265 private MethodReference m_NetworkBehaviour_endSendClientRpc_MethodRef ;
258266 private FieldReference m_NetworkBehaviour_rpc_exec_stage_FieldRef ;
267+ private FieldReference m_NetworkBehaviour_NetworkVariableFields_FieldRef ;
259268 private MethodReference m_NetworkBehaviour_getNetworkManager_MethodRef ;
260269 private MethodReference m_NetworkBehaviour_getOwnerClientId_MethodRef ;
261270 private MethodReference m_NetworkHandlerDelegateCtor_MethodRef ;
@@ -275,6 +284,9 @@ private void CreateNetworkVariableTypeInitializers(AssemblyDefinition assembly)
275284 private MethodReference m_NetworkVariableSerializationTypes_InitializeEqualityChecker_UnmanagedValueEquals_MethodRef ;
276285 private MethodReference m_NetworkVariableSerializationTypes_InitializeEqualityChecker_ManagedClassEquals_MethodRef ;
277286
287+ private MethodReference m_ExceptionCtorMethodReference ;
288+ private MethodReference m_List_NetworkVariableBase_Add ;
289+
278290 private MethodReference m_BytePacker_WriteValueBitPacked_Short_MethodRef ;
279291 private MethodReference m_BytePacker_WriteValueBitPacked_UShort_MethodRef ;
280292 private MethodReference m_BytePacker_WriteValueBitPacked_Int_MethodRef ;
@@ -348,12 +360,17 @@ private void CreateNetworkVariableTypeInitializers(AssemblyDefinition assembly)
348360 private const string k_NetworkManager_rpc_name_table = nameof ( NetworkManager . __rpc_name_table ) ;
349361
350362 private const string k_NetworkBehaviour_rpc_exec_stage = nameof ( NetworkBehaviour . __rpc_exec_stage ) ;
363+ private const string k_NetworkBehaviour_NetworkVariableFields = nameof ( NetworkBehaviour . NetworkVariableFields ) ;
351364 private const string k_NetworkBehaviour_beginSendServerRpc = nameof ( NetworkBehaviour . __beginSendServerRpc ) ;
352365 private const string k_NetworkBehaviour_endSendServerRpc = nameof ( NetworkBehaviour . __endSendServerRpc ) ;
353366 private const string k_NetworkBehaviour_beginSendClientRpc = nameof ( NetworkBehaviour . __beginSendClientRpc ) ;
354367 private const string k_NetworkBehaviour_endSendClientRpc = nameof ( NetworkBehaviour . __endSendClientRpc ) ;
368+ private const string k_NetworkBehaviour___initializeVariables = nameof ( NetworkBehaviour . __initializeVariables ) ;
355369 private const string k_NetworkBehaviour_NetworkManager = nameof ( NetworkBehaviour . NetworkManager ) ;
356370 private const string k_NetworkBehaviour_OwnerClientId = nameof ( NetworkBehaviour . OwnerClientId ) ;
371+ private const string k_NetworkBehaviour___nameNetworkVariable = nameof ( NetworkBehaviour . __nameNetworkVariable ) ;
372+
373+ private const string k_NetworkVariableBase_Initialize = nameof ( NetworkVariableBase . Initialize ) ;
357374
358375 private const string k_RpcAttribute_Delivery = nameof ( RpcAttribute . Delivery ) ;
359376 private const string k_ServerRpcAttribute_RequireOwnership = nameof ( ServerRpcAttribute . RequireOwnership ) ;
@@ -379,6 +396,7 @@ private bool ImportReferences(ModuleDefinition moduleDefinition)
379396
380397 TypeDefinition networkManagerTypeDef = null ;
381398 TypeDefinition networkBehaviourTypeDef = null ;
399+ TypeDefinition networkVariableBaseTypeDef = null ;
382400 TypeDefinition networkHandlerDelegateTypeDef = null ;
383401 TypeDefinition rpcParamsTypeDef = null ;
384402 TypeDefinition serverRpcParamsTypeDef = null ;
@@ -402,6 +420,12 @@ private bool ImportReferences(ModuleDefinition moduleDefinition)
402420 continue ;
403421 }
404422
423+ if ( networkVariableBaseTypeDef == null && netcodeTypeDef . Name == nameof ( NetworkVariableBase ) )
424+ {
425+ networkVariableBaseTypeDef = netcodeTypeDef ;
426+ continue ;
427+ }
428+
405429 if ( networkHandlerDelegateTypeDef == null && netcodeTypeDef . Name == nameof ( NetworkManager . RpcReceiveHandler ) )
406430 {
407431 networkHandlerDelegateTypeDef = netcodeTypeDef ;
@@ -548,6 +572,9 @@ private bool ImportReferences(ModuleDefinition moduleDefinition)
548572 case k_NetworkBehaviour_endSendClientRpc :
549573 m_NetworkBehaviour_endSendClientRpc_MethodRef = moduleDefinition . ImportReference ( methodDef ) ;
550574 break ;
575+ case k_NetworkBehaviour___nameNetworkVariable :
576+ m_NetworkBehaviour___nameNetworkVariable_MethodRef = moduleDefinition . ImportReference ( methodDef ) ;
577+ break ;
551578 }
552579 }
553580
@@ -558,6 +585,21 @@ private bool ImportReferences(ModuleDefinition moduleDefinition)
558585 case k_NetworkBehaviour_rpc_exec_stage :
559586 m_NetworkBehaviour_rpc_exec_stage_FieldRef = moduleDefinition . ImportReference ( fieldDef ) ;
560587 break ;
588+ case k_NetworkBehaviour_NetworkVariableFields :
589+ m_NetworkBehaviour_NetworkVariableFields_FieldRef = moduleDefinition . ImportReference ( fieldDef ) ;
590+ break ;
591+ }
592+ }
593+
594+
595+ m_NetworkVariableBase_TypeRef = moduleDefinition . ImportReference ( networkVariableBaseTypeDef ) ;
596+ foreach ( var methodDef in networkVariableBaseTypeDef . Methods )
597+ {
598+ switch ( methodDef . Name )
599+ {
600+ case k_NetworkVariableBase_Initialize :
601+ m_NetworkVariableBase_Initialize_MethodRef = moduleDefinition . ImportReference ( methodDef ) ;
602+ break ;
561603 }
562604 }
563605
@@ -785,6 +827,16 @@ private bool ImportReferences(ModuleDefinition moduleDefinition)
785827 }
786828 }
787829
830+ // Standard types are really hard to reliably find using the Mono Cecil way, they resolve differently in Mono vs .NET Core
831+ // Importing with typeof() is less dangerous for standard framework types though, so we can just do it
832+ var exceptionType = typeof ( Exception ) ;
833+ var exceptionCtor = exceptionType . GetConstructor ( new [ ] { typeof ( string ) } ) ;
834+ m_ExceptionCtorMethodReference = m_MainModule . ImportReference ( exceptionCtor ) ;
835+
836+ var listType = typeof ( List < NetworkVariableBase > ) ;
837+ var addMethod = listType . GetMethod ( nameof ( List < NetworkVariableBase > . Add ) , new [ ] { typeof ( NetworkVariableBase ) } ) ;
838+ m_List_NetworkVariableBase_Add = moduleDefinition . ImportReference ( addMethod ) ;
839+
788840 return true ;
789841 }
790842
@@ -931,6 +983,8 @@ private void ProcessNetworkBehaviour(TypeDefinition typeDefinition, string[] ass
931983 }
932984 }
933985
986+ GenerateVariableInitialization ( typeDefinition ) ;
987+
934988 if ( ! typeDefinition . HasGenericParameters && ! typeDefinition . IsGenericInstance )
935989 {
936990 var fieldTypes = new List < TypeReference > ( ) ;
@@ -1889,6 +1943,132 @@ private void InjectWriteAndCallBlocks(MethodDefinition methodDefinition, CustomA
18891943 instructions . ForEach ( instruction => processor . Body . Instructions . Insert ( 0 , instruction ) ) ;
18901944 }
18911945
1946+ private void GenerateVariableInitialization ( TypeDefinition type )
1947+ {
1948+ foreach ( var methodDefinition in type . Methods )
1949+ {
1950+ if ( methodDefinition . Name == k_NetworkBehaviour___initializeVariables )
1951+ {
1952+ // If this hits, we've already generated the method for this class because a child class got processed first.
1953+ return ;
1954+ }
1955+ }
1956+
1957+ var method = new MethodDefinition (
1958+ k_NetworkBehaviour___initializeVariables ,
1959+ MethodAttributes . Family | MethodAttributes . Virtual | MethodAttributes . HideBySig ,
1960+ m_MainModule . TypeSystem . Void ) ;
1961+
1962+ var processor = method . Body . GetILProcessor ( ) ;
1963+
1964+ method . Body . Variables . Add ( new VariableDefinition ( m_MainModule . TypeSystem . Boolean ) ) ;
1965+
1966+ processor . Emit ( OpCodes . Nop ) ;
1967+
1968+ foreach ( var fieldDefinition in type . Fields )
1969+ {
1970+ FieldReference field = fieldDefinition ;
1971+ if ( type . HasGenericParameters )
1972+ {
1973+ var genericType = new GenericInstanceType ( fieldDefinition . DeclaringType ) ;
1974+ foreach ( var parameter in fieldDefinition . DeclaringType . GenericParameters )
1975+ {
1976+ genericType . GenericArguments . Add ( parameter ) ;
1977+ }
1978+ field = new FieldReference ( fieldDefinition . Name , fieldDefinition . FieldType , genericType ) ;
1979+ }
1980+ if ( field . FieldType . IsSubclassOf ( m_NetworkVariableBase_TypeRef ) )
1981+ {
1982+ // if({variable} != null) {
1983+ processor . Emit ( OpCodes . Ldarg_0 ) ;
1984+ processor . Emit ( OpCodes . Ldfld , field ) ;
1985+ processor . Emit ( OpCodes . Ldnull ) ;
1986+ processor . Emit ( OpCodes . Ceq ) ;
1987+ processor . Emit ( OpCodes . Stloc_0 ) ;
1988+ processor . Emit ( OpCodes . Ldloc_0 ) ;
1989+
1990+ var afterThrowInstruction = processor . Create ( OpCodes . Nop ) ;
1991+
1992+ processor . Emit ( OpCodes . Brfalse , afterThrowInstruction ) ;
1993+
1994+ // throw new Exception("...");
1995+ processor . Emit ( OpCodes . Nop ) ;
1996+ processor . Emit ( OpCodes . Ldstr , $ "{ type . Name } .{ field . Name } cannot be null. All { nameof ( NetworkVariableBase ) } instances must be initialized.") ;
1997+ processor . Emit ( OpCodes . Newobj , m_ExceptionCtorMethodReference ) ;
1998+ processor . Emit ( OpCodes . Throw ) ;
1999+
2000+ // }
2001+ processor . Append ( afterThrowInstruction ) ;
2002+
2003+ // {variable}.Initialize(this);
2004+ processor . Emit ( OpCodes . Ldarg_0 ) ;
2005+ processor . Emit ( OpCodes . Ldfld , field ) ;
2006+ processor . Emit ( OpCodes . Ldarg_0 ) ;
2007+ processor . Emit ( OpCodes . Callvirt , m_NetworkVariableBase_Initialize_MethodRef ) ;
2008+
2009+ // __nameNetworkVariable({variable}, "{variable}");
2010+ processor . Emit ( OpCodes . Nop ) ;
2011+ processor . Emit ( OpCodes . Ldarg_0 ) ;
2012+ processor . Emit ( OpCodes . Ldarg_0 ) ;
2013+ processor . Emit ( OpCodes . Ldfld , field ) ;
2014+ processor . Emit ( OpCodes . Ldstr , field . Name . Replace ( "<" , string . Empty ) . Replace ( ">k__BackingField" , string . Empty ) ) ;
2015+ processor . Emit ( OpCodes . Call , m_NetworkBehaviour___nameNetworkVariable_MethodRef ) ;
2016+
2017+ // NetworkVariableFields.Add({variable});
2018+ processor . Emit ( OpCodes . Nop ) ;
2019+ processor . Emit ( OpCodes . Ldarg_0 ) ;
2020+ processor . Emit ( OpCodes . Ldfld , m_NetworkBehaviour_NetworkVariableFields_FieldRef ) ;
2021+ processor . Emit ( OpCodes . Ldarg_0 ) ;
2022+ processor . Emit ( OpCodes . Ldfld , field ) ;
2023+ processor . Emit ( OpCodes . Callvirt , m_List_NetworkVariableBase_Add ) ;
2024+ }
2025+ }
2026+
2027+ // Find the base method...
2028+ MethodReference initializeVariablesBaseReference = null ;
2029+ foreach ( var methodDefinition in type . BaseType . Resolve ( ) . Methods )
2030+ {
2031+ if ( methodDefinition . Name == k_NetworkBehaviour___initializeVariables )
2032+ {
2033+ initializeVariablesBaseReference = m_MainModule . ImportReference ( methodDefinition ) ;
2034+ break ;
2035+ }
2036+ }
2037+
2038+ if ( initializeVariablesBaseReference == null )
2039+ {
2040+ // If we couldn't find it, we have to go ahead and add it.
2041+ // The base class could be in another assembly... that's ok, this won't
2042+ // actually save but it'll generate the same method the same way later,
2043+ // so this at least allows us to reference it.
2044+ GenerateVariableInitialization ( type . BaseType . Resolve ( ) ) ;
2045+ foreach ( var methodDefinition in type . BaseType . Resolve ( ) . Methods )
2046+ {
2047+ if ( methodDefinition . Name == k_NetworkBehaviour___initializeVariables )
2048+ {
2049+ initializeVariablesBaseReference = m_MainModule . ImportReference ( methodDefinition ) ;
2050+ break ;
2051+ }
2052+ }
2053+ }
2054+
2055+ if ( type . BaseType . Resolve ( ) . HasGenericParameters )
2056+ {
2057+ var baseTypeInstance = ( GenericInstanceType ) type . BaseType ;
2058+ initializeVariablesBaseReference = initializeVariablesBaseReference . MakeGeneric ( baseTypeInstance . GenericArguments . ToArray ( ) ) ;
2059+ }
2060+
2061+ // base.__initializeVariables();
2062+ processor . Emit ( OpCodes . Nop ) ;
2063+ processor . Emit ( OpCodes . Ldarg_0 ) ;
2064+ processor . Emit ( OpCodes . Call , initializeVariablesBaseReference ) ;
2065+ processor . Emit ( OpCodes . Nop ) ;
2066+
2067+ processor . Emit ( OpCodes . Ret ) ;
2068+
2069+ type . Methods . Add ( method ) ;
2070+ }
2071+
18922072 private MethodDefinition GenerateStaticHandler ( MethodDefinition methodDefinition , CustomAttribute rpcAttribute , uint rpcMethodId )
18932073 {
18942074 var typeSystem = methodDefinition . Module . TypeSystem ;
0 commit comments