@@ -166,6 +166,11 @@ private void CreateNetworkVariableTypeInitializers(AssemblyDefinition assembly)
166
166
167
167
foreach ( var type in m_WrappedNetworkVariableTypes )
168
168
{
169
+ if ( type . Resolve ( ) == null )
170
+ {
171
+ continue ;
172
+ }
173
+
169
174
if ( IsSpecialCaseType ( type ) )
170
175
{
171
176
continue ;
@@ -251,11 +256,15 @@ private void CreateNetworkVariableTypeInitializers(AssemblyDefinition assembly)
251
256
private FieldReference m_NetworkManager_rpc_name_table_FieldRef ;
252
257
private MethodReference m_NetworkManager_rpc_name_table_Add_MethodRef ;
253
258
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 ;
254
262
private MethodReference m_NetworkBehaviour_beginSendServerRpc_MethodRef ;
255
263
private MethodReference m_NetworkBehaviour_endSendServerRpc_MethodRef ;
256
264
private MethodReference m_NetworkBehaviour_beginSendClientRpc_MethodRef ;
257
265
private MethodReference m_NetworkBehaviour_endSendClientRpc_MethodRef ;
258
266
private FieldReference m_NetworkBehaviour_rpc_exec_stage_FieldRef ;
267
+ private FieldReference m_NetworkBehaviour_NetworkVariableFields_FieldRef ;
259
268
private MethodReference m_NetworkBehaviour_getNetworkManager_MethodRef ;
260
269
private MethodReference m_NetworkBehaviour_getOwnerClientId_MethodRef ;
261
270
private MethodReference m_NetworkHandlerDelegateCtor_MethodRef ;
@@ -275,6 +284,9 @@ private void CreateNetworkVariableTypeInitializers(AssemblyDefinition assembly)
275
284
private MethodReference m_NetworkVariableSerializationTypes_InitializeEqualityChecker_UnmanagedValueEquals_MethodRef ;
276
285
private MethodReference m_NetworkVariableSerializationTypes_InitializeEqualityChecker_ManagedClassEquals_MethodRef ;
277
286
287
+ private MethodReference m_ExceptionCtorMethodReference ;
288
+ private MethodReference m_List_NetworkVariableBase_Add ;
289
+
278
290
private MethodReference m_BytePacker_WriteValueBitPacked_Short_MethodRef ;
279
291
private MethodReference m_BytePacker_WriteValueBitPacked_UShort_MethodRef ;
280
292
private MethodReference m_BytePacker_WriteValueBitPacked_Int_MethodRef ;
@@ -348,12 +360,17 @@ private void CreateNetworkVariableTypeInitializers(AssemblyDefinition assembly)
348
360
private const string k_NetworkManager_rpc_name_table = nameof ( NetworkManager . __rpc_name_table ) ;
349
361
350
362
private const string k_NetworkBehaviour_rpc_exec_stage = nameof ( NetworkBehaviour . __rpc_exec_stage ) ;
363
+ private const string k_NetworkBehaviour_NetworkVariableFields = nameof ( NetworkBehaviour . NetworkVariableFields ) ;
351
364
private const string k_NetworkBehaviour_beginSendServerRpc = nameof ( NetworkBehaviour . __beginSendServerRpc ) ;
352
365
private const string k_NetworkBehaviour_endSendServerRpc = nameof ( NetworkBehaviour . __endSendServerRpc ) ;
353
366
private const string k_NetworkBehaviour_beginSendClientRpc = nameof ( NetworkBehaviour . __beginSendClientRpc ) ;
354
367
private const string k_NetworkBehaviour_endSendClientRpc = nameof ( NetworkBehaviour . __endSendClientRpc ) ;
368
+ private const string k_NetworkBehaviour___initializeVariables = nameof ( NetworkBehaviour . __initializeVariables ) ;
355
369
private const string k_NetworkBehaviour_NetworkManager = nameof ( NetworkBehaviour . NetworkManager ) ;
356
370
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 ) ;
357
374
358
375
private const string k_RpcAttribute_Delivery = nameof ( RpcAttribute . Delivery ) ;
359
376
private const string k_ServerRpcAttribute_RequireOwnership = nameof ( ServerRpcAttribute . RequireOwnership ) ;
@@ -379,6 +396,7 @@ private bool ImportReferences(ModuleDefinition moduleDefinition)
379
396
380
397
TypeDefinition networkManagerTypeDef = null ;
381
398
TypeDefinition networkBehaviourTypeDef = null ;
399
+ TypeDefinition networkVariableBaseTypeDef = null ;
382
400
TypeDefinition networkHandlerDelegateTypeDef = null ;
383
401
TypeDefinition rpcParamsTypeDef = null ;
384
402
TypeDefinition serverRpcParamsTypeDef = null ;
@@ -402,6 +420,12 @@ private bool ImportReferences(ModuleDefinition moduleDefinition)
402
420
continue ;
403
421
}
404
422
423
+ if ( networkVariableBaseTypeDef == null && netcodeTypeDef . Name == nameof ( NetworkVariableBase ) )
424
+ {
425
+ networkVariableBaseTypeDef = netcodeTypeDef ;
426
+ continue ;
427
+ }
428
+
405
429
if ( networkHandlerDelegateTypeDef == null && netcodeTypeDef . Name == nameof ( NetworkManager . RpcReceiveHandler ) )
406
430
{
407
431
networkHandlerDelegateTypeDef = netcodeTypeDef ;
@@ -548,6 +572,9 @@ private bool ImportReferences(ModuleDefinition moduleDefinition)
548
572
case k_NetworkBehaviour_endSendClientRpc :
549
573
m_NetworkBehaviour_endSendClientRpc_MethodRef = moduleDefinition . ImportReference ( methodDef ) ;
550
574
break ;
575
+ case k_NetworkBehaviour___nameNetworkVariable :
576
+ m_NetworkBehaviour___nameNetworkVariable_MethodRef = moduleDefinition . ImportReference ( methodDef ) ;
577
+ break ;
551
578
}
552
579
}
553
580
@@ -558,6 +585,21 @@ private bool ImportReferences(ModuleDefinition moduleDefinition)
558
585
case k_NetworkBehaviour_rpc_exec_stage :
559
586
m_NetworkBehaviour_rpc_exec_stage_FieldRef = moduleDefinition . ImportReference ( fieldDef ) ;
560
587
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 ;
561
603
}
562
604
}
563
605
@@ -785,6 +827,16 @@ private bool ImportReferences(ModuleDefinition moduleDefinition)
785
827
}
786
828
}
787
829
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
+
788
840
return true ;
789
841
}
790
842
@@ -931,6 +983,8 @@ private void ProcessNetworkBehaviour(TypeDefinition typeDefinition, string[] ass
931
983
}
932
984
}
933
985
986
+ GenerateVariableInitialization ( typeDefinition ) ;
987
+
934
988
if ( ! typeDefinition . HasGenericParameters && ! typeDefinition . IsGenericInstance )
935
989
{
936
990
var fieldTypes = new List < TypeReference > ( ) ;
@@ -1889,6 +1943,132 @@ private void InjectWriteAndCallBlocks(MethodDefinition methodDefinition, CustomA
1889
1943
instructions . ForEach ( instruction => processor . Body . Instructions . Insert ( 0 , instruction ) ) ;
1890
1944
}
1891
1945
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
+
1892
2072
private MethodDefinition GenerateStaticHandler ( MethodDefinition methodDefinition , CustomAttribute rpcAttribute , uint rpcMethodId )
1893
2073
{
1894
2074
var typeSystem = methodDefinition . Module . TypeSystem ;
0 commit comments