2021-05-03 20:13:03 +01:00
using Mono.Cecil ;
using Mono.Cecil.Cil ;
namespace QNetWeaver
{
internal class SyncListStructProcessor
{
public SyncListStructProcessor ( TypeDefinition typeDef )
{
Weaver . DLog ( typeDef , "SyncListStructProcessor for " + typeDef . Name , new object [ 0 ] ) ;
2021-05-03 20:27:52 +01:00
m_TypeDef = typeDef ;
2021-05-03 20:13:03 +01:00
}
public void Process ( )
{
2021-05-03 20:27:52 +01:00
var genericInstanceType = ( GenericInstanceType ) m_TypeDef . BaseType ;
2021-05-03 20:13:03 +01:00
if ( genericInstanceType . GenericArguments . Count = = 0 )
{
Weaver . fail = true ;
Log . Error ( "SyncListStructProcessor no generic args" ) ;
}
else
{
2021-05-03 20:27:52 +01:00
m_ItemType = Weaver . scriptDef . MainModule . ImportReference ( genericInstanceType . GenericArguments [ 0 ] ) ;
Weaver . DLog ( m_TypeDef , "SyncListStructProcessor Start item:" + m_ItemType . FullName , new object [ 0 ] ) ;
2021-05-03 20:13:03 +01:00
Weaver . ResetRecursionCount ( ) ;
2021-05-03 20:27:52 +01:00
var methodReference = GenerateSerialization ( ) ;
2021-05-03 20:13:03 +01:00
if ( ! Weaver . fail )
{
2021-05-03 20:27:52 +01:00
var methodReference2 = GenerateDeserialization ( ) ;
2021-05-03 20:13:03 +01:00
if ( methodReference2 ! = null & & methodReference ! = null )
{
2021-05-03 20:27:52 +01:00
GenerateReadFunc ( methodReference2 ) ;
GenerateWriteFunc ( methodReference ) ;
Weaver . DLog ( m_TypeDef , "SyncListStructProcessor Done" , new object [ 0 ] ) ;
2021-05-03 20:13:03 +01:00
}
}
}
}
private void GenerateReadFunc ( MethodReference readItemFunc )
{
2021-05-03 20:27:52 +01:00
var text = "_ReadStruct" + m_TypeDef . Name + "_" ;
if ( m_TypeDef . DeclaringType ! = null )
2021-05-03 20:13:03 +01:00
{
2021-05-03 20:27:52 +01:00
text + = m_TypeDef . DeclaringType . Name ;
2021-05-03 20:13:03 +01:00
}
else
{
text + = "None" ;
}
2021-06-18 22:40:38 +01:00
2021-05-03 20:13:03 +01:00
var methodDefinition = new MethodDefinition ( text , MethodAttributes . FamANDAssem | MethodAttributes . Family | MethodAttributes . Static | MethodAttributes . HideBySig , Weaver . voidType ) ;
methodDefinition . Parameters . Add ( new ParameterDefinition ( "reader" , ParameterAttributes . None , Weaver . scriptDef . MainModule . ImportReference ( Weaver . NetworkReaderType ) ) ) ;
2021-05-03 20:27:52 +01:00
methodDefinition . Parameters . Add ( new ParameterDefinition ( "instance" , ParameterAttributes . None , m_TypeDef ) ) ;
2021-05-03 20:13:03 +01:00
methodDefinition . Body . Variables . Add ( new VariableDefinition ( Weaver . uint16Type ) ) ;
methodDefinition . Body . Variables . Add ( new VariableDefinition ( Weaver . uint16Type ) ) ;
methodDefinition . Body . InitLocals = true ;
var ilprocessor = methodDefinition . Body . GetILProcessor ( ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldarg_0 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Callvirt , Weaver . NetworkReadUInt16 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Stloc_0 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldarg_1 ) ) ;
var method = Helpers . MakeHostInstanceGeneric ( Weaver . SyncListClear , new TypeReference [ ]
{
2021-05-03 20:27:52 +01:00
m_ItemType
2021-05-03 20:13:03 +01:00
} ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Callvirt , method ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldc_I4_0 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Stloc_1 ) ) ;
var instruction = ilprocessor . Create ( OpCodes . Nop ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Br , instruction ) ) ;
var instruction2 = ilprocessor . Create ( OpCodes . Nop ) ;
ilprocessor . Append ( instruction2 ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldarg_1 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldarg_1 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldarg_0 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Callvirt , readItemFunc ) ) ;
var self = Weaver . ResolveMethod ( Weaver . SyncListStructType , "AddInternal" ) ;
var method2 = Helpers . MakeHostInstanceGeneric ( self , new TypeReference [ ]
{
2021-05-03 20:27:52 +01:00
m_ItemType
2021-05-03 20:13:03 +01:00
} ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Callvirt , method2 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldloc_1 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldc_I4_1 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Add ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Conv_U2 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Stloc_1 ) ) ;
ilprocessor . Append ( instruction ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldloc_1 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldloc_0 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Blt , instruction2 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ret ) ) ;
2021-05-03 20:27:52 +01:00
Weaver . RegisterReadByReferenceFunc ( m_TypeDef . FullName , methodDefinition ) ;
2021-05-03 20:13:03 +01:00
}
private void GenerateWriteFunc ( MethodReference writeItemFunc )
{
2021-05-03 20:27:52 +01:00
var text = "_WriteStruct" + m_TypeDef . GetElementType ( ) . Name + "_" ;
if ( m_TypeDef . DeclaringType ! = null )
2021-05-03 20:13:03 +01:00
{
2021-05-03 20:27:52 +01:00
text + = m_TypeDef . DeclaringType . Name ;
2021-05-03 20:13:03 +01:00
}
else
{
text + = "None" ;
}
2021-06-18 22:40:38 +01:00
2021-05-03 20:13:03 +01:00
var methodDefinition = new MethodDefinition ( text , MethodAttributes . FamANDAssem | MethodAttributes . Family | MethodAttributes . Static | MethodAttributes . HideBySig , Weaver . voidType ) ;
methodDefinition . Parameters . Add ( new ParameterDefinition ( "writer" , ParameterAttributes . None , Weaver . scriptDef . MainModule . ImportReference ( Weaver . NetworkWriterType ) ) ) ;
2021-05-03 20:27:52 +01:00
methodDefinition . Parameters . Add ( new ParameterDefinition ( "value" , ParameterAttributes . None , Weaver . scriptDef . MainModule . ImportReference ( m_TypeDef ) ) ) ;
2021-05-03 20:13:03 +01:00
methodDefinition . Body . Variables . Add ( new VariableDefinition ( Weaver . uint16Type ) ) ;
methodDefinition . Body . Variables . Add ( new VariableDefinition ( Weaver . uint16Type ) ) ;
methodDefinition . Body . InitLocals = true ;
var ilprocessor = methodDefinition . Body . GetILProcessor ( ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldarg_1 ) ) ;
var self = Weaver . ResolveMethod ( Weaver . SyncListStructType , "get_Count" ) ;
var method = Helpers . MakeHostInstanceGeneric ( self , new TypeReference [ ]
{
2021-05-03 20:27:52 +01:00
m_ItemType
2021-05-03 20:13:03 +01:00
} ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Callvirt , method ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Stloc_0 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldarg_0 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldloc_0 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Callvirt , Weaver . NetworkWriteUInt16 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldc_I4_0 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Stloc_1 ) ) ;
var instruction = ilprocessor . Create ( OpCodes . Nop ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Br , instruction ) ) ;
var instruction2 = ilprocessor . Create ( OpCodes . Nop ) ;
ilprocessor . Append ( instruction2 ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldarg_1 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldarg_0 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldarg_1 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldloc_1 ) ) ;
var self2 = Weaver . ResolveMethod ( Weaver . SyncListStructType , "GetItem" ) ;
var method2 = Helpers . MakeHostInstanceGeneric ( self2 , new TypeReference [ ]
{
2021-05-03 20:27:52 +01:00
m_ItemType
2021-05-03 20:13:03 +01:00
} ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Callvirt , method2 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Callvirt , writeItemFunc ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldloc_1 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldc_I4_1 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Add ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Conv_U2 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Stloc_1 ) ) ;
ilprocessor . Append ( instruction ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldloc_1 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldloc_0 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Blt , instruction2 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ret ) ) ;
2021-05-03 20:27:52 +01:00
Weaver . RegisterWriteFunc ( m_TypeDef . FullName , methodDefinition ) ;
2021-05-03 20:13:03 +01:00
}
private MethodReference GenerateSerialization ( )
{
2021-05-03 20:27:52 +01:00
Weaver . DLog ( m_TypeDef , " SyncListStruct GenerateSerialization" , new object [ 0 ] ) ;
foreach ( var methodDefinition in m_TypeDef . Methods )
2021-05-03 20:13:03 +01:00
{
if ( methodDefinition . Name = = "SerializeItem" )
{
2021-05-03 20:27:52 +01:00
Weaver . DLog ( m_TypeDef , " Abort - is SerializeItem" , new object [ 0 ] ) ;
2021-05-03 20:13:03 +01:00
return methodDefinition ;
}
}
2021-06-18 22:40:38 +01:00
2021-05-03 20:13:03 +01:00
var methodDefinition2 = new MethodDefinition ( "SerializeItem" , MethodAttributes . FamANDAssem | MethodAttributes . Family | MethodAttributes . Virtual | MethodAttributes . HideBySig , Weaver . voidType ) ;
methodDefinition2 . Parameters . Add ( new ParameterDefinition ( "writer" , ParameterAttributes . None , Weaver . scriptDef . MainModule . ImportReference ( Weaver . NetworkWriterType ) ) ) ;
2021-05-03 20:27:52 +01:00
methodDefinition2 . Parameters . Add ( new ParameterDefinition ( "item" , ParameterAttributes . None , m_ItemType ) ) ;
2021-05-03 20:13:03 +01:00
var ilprocessor = methodDefinition2 . Body . GetILProcessor ( ) ;
MethodReference result ;
2021-05-03 20:27:52 +01:00
if ( m_ItemType . IsGenericInstance )
2021-05-03 20:13:03 +01:00
{
Weaver . fail = true ;
2021-05-03 20:27:52 +01:00
Log . Error ( "GenerateSerialization for " + Helpers . PrettyPrintType ( m_ItemType ) + " failed. Struct passed into SyncListStruct<T> can't have generic parameters" ) ;
2021-05-03 20:13:03 +01:00
result = null ;
}
else
{
2021-05-03 20:27:52 +01:00
foreach ( var fieldDefinition in m_ItemType . Resolve ( ) . Fields )
2021-05-03 20:13:03 +01:00
{
if ( ! fieldDefinition . IsStatic & & ! fieldDefinition . IsPrivate & & ! fieldDefinition . IsSpecialName )
{
var fieldReference = Weaver . scriptDef . MainModule . ImportReference ( fieldDefinition ) ;
var typeDefinition = fieldReference . FieldType . Resolve ( ) ;
if ( typeDefinition . HasGenericParameters )
{
Weaver . fail = true ;
Log . Error ( string . Concat ( new object [ ]
{
"GenerateSerialization for " ,
2021-05-03 20:27:52 +01:00
m_TypeDef . Name ,
2021-05-03 20:13:03 +01:00
" [" ,
typeDefinition ,
"/" ,
typeDefinition . FullName ,
"]. UNet [MessageBase] member cannot have generic parameters."
} ) ) ;
return null ;
}
2021-06-18 22:40:38 +01:00
2021-05-03 20:13:03 +01:00
if ( typeDefinition . IsInterface )
{
Weaver . fail = true ;
Log . Error ( string . Concat ( new object [ ]
{
"GenerateSerialization for " ,
2021-05-03 20:27:52 +01:00
m_TypeDef . Name ,
2021-05-03 20:13:03 +01:00
" [" ,
typeDefinition ,
"/" ,
typeDefinition . FullName ,
"]. UNet [MessageBase] member cannot be an interface."
} ) ) ;
return null ;
}
2021-06-18 22:40:38 +01:00
2021-05-03 20:13:03 +01:00
var writeFunc = Weaver . GetWriteFunc ( fieldDefinition . FieldType ) ;
if ( writeFunc = = null )
{
Weaver . fail = true ;
Log . Error ( string . Concat ( new object [ ]
{
"GenerateSerialization for " ,
2021-05-03 20:27:52 +01:00
m_TypeDef . Name ,
2021-05-03 20:13:03 +01:00
" unknown type [" ,
typeDefinition ,
"/" ,
typeDefinition . FullName ,
"]. UNet [MessageBase] member variables must be basic types."
} ) ) ;
return null ;
}
2021-06-18 22:40:38 +01:00
2021-05-03 20:13:03 +01:00
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldarg_1 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldarg_2 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldfld , fieldReference ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Call , writeFunc ) ) ;
}
}
2021-06-18 22:40:38 +01:00
2021-05-03 20:13:03 +01:00
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ret ) ) ;
2021-05-03 20:27:52 +01:00
m_TypeDef . Methods . Add ( methodDefinition2 ) ;
2021-05-03 20:13:03 +01:00
result = methodDefinition2 ;
}
2021-06-18 22:40:38 +01:00
2021-05-03 20:13:03 +01:00
return result ;
}
private MethodReference GenerateDeserialization ( )
{
2021-05-03 20:27:52 +01:00
Weaver . DLog ( m_TypeDef , " GenerateDeserialization" , new object [ 0 ] ) ;
foreach ( var methodDefinition in m_TypeDef . Methods )
2021-05-03 20:13:03 +01:00
{
if ( methodDefinition . Name = = "DeserializeItem" )
{
return methodDefinition ;
}
}
2021-06-18 22:40:38 +01:00
2021-05-03 20:27:52 +01:00
var methodDefinition2 = new MethodDefinition ( "DeserializeItem" , MethodAttributes . FamANDAssem | MethodAttributes . Family | MethodAttributes . Virtual | MethodAttributes . HideBySig , m_ItemType ) ;
2021-05-03 20:13:03 +01:00
methodDefinition2 . Parameters . Add ( new ParameterDefinition ( "reader" , ParameterAttributes . None , Weaver . scriptDef . MainModule . ImportReference ( Weaver . NetworkReaderType ) ) ) ;
var ilprocessor = methodDefinition2 . Body . GetILProcessor ( ) ;
ilprocessor . Body . InitLocals = true ;
2021-05-03 20:27:52 +01:00
ilprocessor . Body . Variables . Add ( new VariableDefinition ( m_ItemType ) ) ;
2021-05-03 20:13:03 +01:00
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldloca , 0 ) ) ;
2021-05-03 20:27:52 +01:00
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Initobj , m_ItemType ) ) ;
foreach ( var fieldDefinition in m_ItemType . Resolve ( ) . Fields )
2021-05-03 20:13:03 +01:00
{
if ( ! fieldDefinition . IsStatic & & ! fieldDefinition . IsPrivate & & ! fieldDefinition . IsSpecialName )
{
var fieldReference = Weaver . scriptDef . MainModule . ImportReference ( fieldDefinition ) ;
var typeDefinition = fieldReference . FieldType . Resolve ( ) ;
var readFunc = Weaver . GetReadFunc ( fieldDefinition . FieldType ) ;
if ( readFunc = = null )
{
Weaver . fail = true ;
Log . Error ( string . Concat ( new object [ ]
{
"GenerateDeserialization for " ,
2021-05-03 20:27:52 +01:00
m_TypeDef . Name ,
2021-05-03 20:13:03 +01:00
" unknown type [" ,
typeDefinition ,
"]. UNet [SyncVar] member variables must be basic types."
} ) ) ;
return null ;
}
2021-06-18 22:40:38 +01:00
2021-05-03 20:13:03 +01:00
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldloca , 0 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldarg_1 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Call , readFunc ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Stfld , fieldReference ) ) ;
}
}
2021-06-18 22:40:38 +01:00
2021-05-03 20:13:03 +01:00
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ldloc_0 ) ) ;
ilprocessor . Append ( ilprocessor . Create ( OpCodes . Ret ) ) ;
2021-05-03 20:27:52 +01:00
m_TypeDef . Methods . Add ( methodDefinition2 ) ;
2021-05-03 20:13:03 +01:00
return methodDefinition2 ;
}
private TypeDefinition m_TypeDef ;
private TypeReference m_ItemType ;
}
}