mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 11:00:32 +00:00
Weaver: worker.Append(worker.Create(Opcode)) replaced with worker.Emit(Opcode)
This commit is contained in:
parent
7ba6a9ab0b
commit
020f79a8d2
@ -52,21 +52,20 @@ public static MethodDefinition ProcessCommandCall(TypeDefinition td, MethodDefin
|
||||
|
||||
// invoke internal send and return
|
||||
// load 'base.' to call the SendCommand function with
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldtoken, td));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldtoken, td);
|
||||
// invokerClass
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getTypeFromHandleReference));
|
||||
worker.Append(worker.Create(OpCodes.Ldstr, cmdName));
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.getTypeFromHandleReference);
|
||||
worker.Emit(OpCodes.Ldstr, cmdName);
|
||||
// writer
|
||||
worker.Append(worker.Create(OpCodes.Ldloc_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldc_I4, channel));
|
||||
worker.Append(worker.Create(ignoreAuthority ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0));
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.sendCommandInternal));
|
||||
worker.Emit(OpCodes.Ldloc_0);
|
||||
worker.Emit(OpCodes.Ldc_I4, channel);
|
||||
worker.Emit(ignoreAuthority ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.sendCommandInternal);
|
||||
|
||||
NetworkBehaviourProcessor.WriteRecycleWriter(worker);
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
|
||||
worker.Emit(OpCodes.Ret);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
@ -93,8 +92,8 @@ public static MethodDefinition ProcessCommandInvoke(TypeDefinition td, MethodDef
|
||||
NetworkBehaviourProcessor.WriteServerActiveCheck(worker, method.Name, label, "Command");
|
||||
|
||||
// setup for reader
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Castclass, td));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Castclass, td);
|
||||
|
||||
if (!NetworkBehaviourProcessor.ReadArguments(method, worker, RemoteCallType.Command))
|
||||
return null;
|
||||
@ -102,8 +101,8 @@ public static MethodDefinition ProcessCommandInvoke(TypeDefinition td, MethodDef
|
||||
AddSenderConnection(method, worker);
|
||||
|
||||
// invoke actual command function
|
||||
worker.Append(worker.Create(OpCodes.Callvirt, cmdCallFunc));
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Callvirt, cmdCallFunc);
|
||||
worker.Emit(OpCodes.Ret);
|
||||
|
||||
NetworkBehaviourProcessor.AddInvokeParameters(cmd.Parameters);
|
||||
|
||||
@ -119,7 +118,7 @@ static void AddSenderConnection(MethodDefinition method, ILProcessor worker)
|
||||
{
|
||||
// NetworkConnection is 3nd arg (arg0 is "obj" not "this" because method is static)
|
||||
// example: static void InvokeCmdCmdSendCommand(NetworkBehaviour obj, NetworkReader reader, NetworkConnection connection)
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_2));
|
||||
worker.Emit(OpCodes.Ldarg_2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -105,12 +105,12 @@ public bool Process()
|
||||
public static void WriteClientActiveCheck(ILProcessor worker, string mdName, Instruction label, string errString)
|
||||
{
|
||||
// client active check
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.NetworkClientGetActive));
|
||||
worker.Append(worker.Create(OpCodes.Brtrue, label));
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.NetworkClientGetActive);
|
||||
worker.Emit(OpCodes.Brtrue, label);
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Ldstr, errString + " " + mdName + " called on server."));
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.logErrorReference));
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Ldstr, errString + " " + mdName + " called on server.");
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.logErrorReference);
|
||||
worker.Emit(OpCodes.Ret);
|
||||
worker.Append(label);
|
||||
}
|
||||
/*
|
||||
@ -121,12 +121,12 @@ public static void WriteClientActiveCheck(ILProcessor worker, string mdName, Ins
|
||||
public static void WriteServerActiveCheck(ILProcessor worker, string mdName, Instruction label, string errString)
|
||||
{
|
||||
// server active check
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.NetworkServerGetActive));
|
||||
worker.Append(worker.Create(OpCodes.Brtrue, label));
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.NetworkServerGetActive);
|
||||
worker.Emit(OpCodes.Brtrue, label);
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Ldstr, errString + " " + mdName + " called on client."));
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.logErrorReference));
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Ldstr, errString + " " + mdName + " called on client.");
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.logErrorReference);
|
||||
worker.Emit(OpCodes.Ret);
|
||||
worker.Append(label);
|
||||
}
|
||||
|
||||
@ -139,15 +139,15 @@ public static void WriteSetupLocals(ILProcessor worker)
|
||||
public static void WriteCreateWriter(ILProcessor worker)
|
||||
{
|
||||
// create writer
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.GetPooledWriterReference));
|
||||
worker.Append(worker.Create(OpCodes.Stloc_0));
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.GetPooledWriterReference);
|
||||
worker.Emit(OpCodes.Stloc_0);
|
||||
}
|
||||
|
||||
public static void WriteRecycleWriter(ILProcessor worker)
|
||||
{
|
||||
// NetworkWriterPool.Recycle(writer);
|
||||
worker.Append(worker.Create(OpCodes.Ldloc_0));
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.RecycleWriterReference));
|
||||
worker.Emit(OpCodes.Ldloc_0);
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.RecycleWriterReference);
|
||||
}
|
||||
|
||||
public static bool WriteArguments(ILProcessor worker, MethodDefinition method, RemoteCallType callType)
|
||||
@ -189,11 +189,11 @@ public static bool WriteArguments(ILProcessor worker, MethodDefinition method, R
|
||||
|
||||
// use built-in writer func on writer object
|
||||
// NetworkWriter object
|
||||
worker.Append(worker.Create(OpCodes.Ldloc_0));
|
||||
worker.Emit(OpCodes.Ldloc_0);
|
||||
// add argument to call
|
||||
worker.Append(worker.Create(OpCodes.Ldarg, argNum));
|
||||
worker.Emit(OpCodes.Ldarg, argNum);
|
||||
// call writer extension method
|
||||
worker.Append(worker.Create(OpCodes.Call, writeFunc));
|
||||
worker.Emit(OpCodes.Call, writeFunc);
|
||||
argNum += 1;
|
||||
}
|
||||
return true;
|
||||
@ -214,7 +214,7 @@ public static void MarkAsProcessed(TypeDefinition td)
|
||||
{
|
||||
MethodDefinition versionMethod = new MethodDefinition(ProcessedFunctionName, MethodAttributes.Private, WeaverTypes.Import(typeof(void)));
|
||||
ILProcessor worker = versionMethod.Body.GetILProcessor();
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Ret);
|
||||
td.Methods.Add(versionMethod);
|
||||
}
|
||||
}
|
||||
@ -323,15 +323,15 @@ void GenerateConstants()
|
||||
*/
|
||||
void GenerateRegisterRemoteDelegate(ILProcessor worker, MethodReference registerMethod, MethodDefinition func, string cmdName)
|
||||
{
|
||||
worker.Append(worker.Create(OpCodes.Ldtoken, netBehaviourSubclass));
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getTypeFromHandleReference));
|
||||
worker.Append(worker.Create(OpCodes.Ldstr, cmdName));
|
||||
worker.Append(worker.Create(OpCodes.Ldnull));
|
||||
worker.Append(worker.Create(OpCodes.Ldftn, func));
|
||||
worker.Emit(OpCodes.Ldtoken, netBehaviourSubclass);
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.getTypeFromHandleReference);
|
||||
worker.Emit(OpCodes.Ldstr, cmdName);
|
||||
worker.Emit(OpCodes.Ldnull);
|
||||
worker.Emit(OpCodes.Ldftn, func);
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Newobj, WeaverTypes.CmdDelegateConstructor));
|
||||
worker.Emit(OpCodes.Newobj, WeaverTypes.CmdDelegateConstructor);
|
||||
//
|
||||
worker.Append(worker.Create(OpCodes.Call, registerMethod));
|
||||
worker.Emit(OpCodes.Call, registerMethod);
|
||||
}
|
||||
|
||||
void GenerateRegisterCommandDelegate(ILProcessor worker, MethodReference registerMethod, MethodDefinition func, CmdResult cmdResult)
|
||||
@ -339,17 +339,17 @@ void GenerateRegisterCommandDelegate(ILProcessor worker, MethodReference registe
|
||||
string cmdName = cmdResult.method.Name;
|
||||
bool ignoreAuthority = cmdResult.ignoreAuthority;
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Ldtoken, netBehaviourSubclass));
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getTypeFromHandleReference));
|
||||
worker.Append(worker.Create(OpCodes.Ldstr, cmdName));
|
||||
worker.Append(worker.Create(OpCodes.Ldnull));
|
||||
worker.Append(worker.Create(OpCodes.Ldftn, func));
|
||||
worker.Emit(OpCodes.Ldtoken, netBehaviourSubclass);
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.getTypeFromHandleReference);
|
||||
worker.Emit(OpCodes.Ldstr, cmdName);
|
||||
worker.Emit(OpCodes.Ldnull);
|
||||
worker.Emit(OpCodes.Ldftn, func);
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Newobj, WeaverTypes.CmdDelegateConstructor));
|
||||
worker.Emit(OpCodes.Newobj, WeaverTypes.CmdDelegateConstructor);
|
||||
|
||||
worker.Append(worker.Create(ignoreAuthority ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0));
|
||||
worker.Emit(ignoreAuthority ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Call, registerMethod));
|
||||
worker.Emit(OpCodes.Call, registerMethod);
|
||||
}
|
||||
|
||||
void GenerateSerialization()
|
||||
@ -384,34 +384,34 @@ void GenerateSerialization()
|
||||
if (baseSerialize != null)
|
||||
{
|
||||
// base
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
// writer
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_1));
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
// forceAll
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_2));
|
||||
worker.Append(worker.Create(OpCodes.Call, baseSerialize));
|
||||
worker.Emit(OpCodes.Ldarg_2);
|
||||
worker.Emit(OpCodes.Call, baseSerialize);
|
||||
// set dirtyLocal to result of base.OnSerialize()
|
||||
worker.Append(worker.Create(OpCodes.Stloc_0));
|
||||
worker.Emit(OpCodes.Stloc_0);
|
||||
}
|
||||
|
||||
// Generates: if (forceAll);
|
||||
Instruction initialStateLabel = worker.Create(OpCodes.Nop);
|
||||
// forceAll
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_2));
|
||||
worker.Append(worker.Create(OpCodes.Brfalse, initialStateLabel));
|
||||
worker.Emit(OpCodes.Ldarg_2);
|
||||
worker.Emit(OpCodes.Brfalse, initialStateLabel);
|
||||
|
||||
foreach (FieldDefinition syncVar in syncVars)
|
||||
{
|
||||
// Generates a writer call for each sync variable
|
||||
// writer
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_1));
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
// this
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldfld, syncVar));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, syncVar);
|
||||
MethodReference writeFunc = Writers.GetWriteFunc(syncVar.FieldType);
|
||||
if (writeFunc != null)
|
||||
{
|
||||
worker.Append(worker.Create(OpCodes.Call, writeFunc));
|
||||
worker.Emit(OpCodes.Call, writeFunc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -423,8 +423,8 @@ void GenerateSerialization()
|
||||
// always return true if forceAll
|
||||
|
||||
// Generates: return true
|
||||
worker.Append(worker.Create(OpCodes.Ldc_I4_1));
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Ldc_I4_1);
|
||||
worker.Emit(OpCodes.Ret);
|
||||
|
||||
// Generates: end if (forceAll);
|
||||
worker.Append(initialStateLabel);
|
||||
@ -432,12 +432,12 @@ void GenerateSerialization()
|
||||
// write dirty bits before the data fields
|
||||
// Generates: writer.WritePackedUInt64 (base.get_syncVarDirtyBits ());
|
||||
// writer
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_1));
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
// base
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.NetworkBehaviourDirtyBitsReference));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.NetworkBehaviourDirtyBitsReference);
|
||||
MethodReference writeUint64Func = Writers.GetWriteFunc(WeaverTypes.Import<ulong>());
|
||||
worker.Append(worker.Create(OpCodes.Call, writeUint64Func));
|
||||
worker.Emit(OpCodes.Call, writeUint64Func);
|
||||
|
||||
// generate a writer call for any dirty variable in this class
|
||||
|
||||
@ -449,24 +449,24 @@ void GenerateSerialization()
|
||||
|
||||
// Generates: if ((base.get_syncVarDirtyBits() & 1uL) != 0uL)
|
||||
// base
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.NetworkBehaviourDirtyBitsReference));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.NetworkBehaviourDirtyBitsReference);
|
||||
// 8 bytes = long
|
||||
worker.Append(worker.Create(OpCodes.Ldc_I8, 1L << dirtyBit));
|
||||
worker.Append(worker.Create(OpCodes.And));
|
||||
worker.Append(worker.Create(OpCodes.Brfalse, varLabel));
|
||||
worker.Emit(OpCodes.Ldc_I8, 1L << dirtyBit);
|
||||
worker.Emit(OpCodes.And);
|
||||
worker.Emit(OpCodes.Brfalse, varLabel);
|
||||
|
||||
// Generates a call to the writer for that field
|
||||
// writer
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_1));
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
// base
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldfld, syncVar));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, syncVar);
|
||||
|
||||
MethodReference writeFunc = Writers.GetWriteFunc(syncVar.FieldType);
|
||||
if (writeFunc != null)
|
||||
{
|
||||
worker.Append(worker.Create(OpCodes.Call, writeFunc));
|
||||
worker.Emit(OpCodes.Call, writeFunc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -475,9 +475,9 @@ void GenerateSerialization()
|
||||
}
|
||||
|
||||
// something was dirty
|
||||
worker.Append(worker.Create(OpCodes.Ldc_I4_1));
|
||||
worker.Emit(OpCodes.Ldc_I4_1);
|
||||
// set dirtyLocal to true
|
||||
worker.Append(worker.Create(OpCodes.Stloc_0));
|
||||
worker.Emit(OpCodes.Stloc_0);
|
||||
|
||||
worker.Append(varLabel);
|
||||
dirtyBit += 1;
|
||||
@ -485,13 +485,13 @@ void GenerateSerialization()
|
||||
|
||||
if (Weaver.GenerateLogErrors)
|
||||
{
|
||||
worker.Append(worker.Create(OpCodes.Ldstr, "Injected Serialize " + netBehaviourSubclass.Name));
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.logErrorReference));
|
||||
worker.Emit(OpCodes.Ldstr, "Injected Serialize " + netBehaviourSubclass.Name);
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.logErrorReference);
|
||||
}
|
||||
|
||||
// generate: return dirtyLocal
|
||||
worker.Append(worker.Create(OpCodes.Ldloc_0));
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Ldloc_0);
|
||||
worker.Emit(OpCodes.Ret);
|
||||
netBehaviourSubclass.Methods.Add(serialize);
|
||||
}
|
||||
|
||||
@ -547,16 +547,16 @@ void DeserializeNetworkIdentityField(FieldDefinition syncVar, ILProcessor worker
|
||||
// uint oldNetId = ___qNetId;
|
||||
VariableDefinition oldNetId = new VariableDefinition(WeaverTypes.Import<uint>());
|
||||
deserialize.Body.Variables.Add(oldNetId);
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldfld, netIdField));
|
||||
worker.Append(worker.Create(OpCodes.Stloc, oldNetId));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, netIdField);
|
||||
worker.Emit(OpCodes.Stloc, oldNetId);
|
||||
|
||||
// GameObject/NetworkIdentity oldSyncVar = syncvar.getter;
|
||||
VariableDefinition oldSyncVar = new VariableDefinition(syncVar.FieldType);
|
||||
deserialize.Body.Variables.Add(oldSyncVar);
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldfld, syncVar));
|
||||
worker.Append(worker.Create(OpCodes.Stloc, oldSyncVar));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, syncVar);
|
||||
worker.Emit(OpCodes.Stloc, oldSyncVar);
|
||||
|
||||
// read id and store in netId field BEFORE calling the hook
|
||||
// -> this makes way more sense. by definition, the hook is
|
||||
@ -568,13 +568,13 @@ void DeserializeNetworkIdentityField(FieldDefinition syncVar, ILProcessor worker
|
||||
// values BEFORE the hook even returned and hence BEFORE the
|
||||
// actual value was even set.
|
||||
// put 'this.' onto stack for 'this.netId' below
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
// reader. for 'reader.Read()' below
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_1));
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
// Read()
|
||||
worker.Append(worker.Create(OpCodes.Call, Readers.GetReadFunc(WeaverTypes.Import<uint>())));
|
||||
worker.Emit(OpCodes.Call, Readers.GetReadFunc(WeaverTypes.Import<uint>()));
|
||||
// netId
|
||||
worker.Append(worker.Create(OpCodes.Stfld, netIdField));
|
||||
worker.Emit(OpCodes.Stfld, netIdField);
|
||||
|
||||
if (hookMethod != null)
|
||||
{
|
||||
@ -600,17 +600,17 @@ void DeserializeNetworkIdentityField(FieldDefinition syncVar, ILProcessor worker
|
||||
Instruction syncVarEqualLabel = worker.Create(OpCodes.Nop);
|
||||
|
||||
// 'this.' for 'this.SyncVarEqual'
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
// 'oldNetId'
|
||||
worker.Append(worker.Create(OpCodes.Ldloc, oldNetId));
|
||||
worker.Emit(OpCodes.Ldloc, oldNetId);
|
||||
// 'ref this.__netId'
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldflda, netIdField));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, netIdField);
|
||||
// call the function
|
||||
GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(WeaverTypes.syncVarEqualReference);
|
||||
syncVarEqualGm.GenericArguments.Add(netIdField.FieldType);
|
||||
worker.Append(worker.Create(OpCodes.Call, syncVarEqualGm));
|
||||
worker.Append(worker.Create(OpCodes.Brtrue, syncVarEqualLabel));
|
||||
worker.Emit(OpCodes.Call, syncVarEqualGm);
|
||||
worker.Emit(OpCodes.Brtrue, syncVarEqualLabel);
|
||||
|
||||
// call the hook
|
||||
// Generates: OnValueChanged(oldValue, this.syncVar);
|
||||
@ -655,16 +655,16 @@ void DeserializeNetworkBehaviourField(FieldDefinition syncVar, ILProcessor worke
|
||||
// uint oldNetId = ___qNetId;
|
||||
VariableDefinition oldNetId = new VariableDefinition(WeaverTypes.Import<NetworkBehaviour.NetworkBehaviourSyncVar>());
|
||||
deserialize.Body.Variables.Add(oldNetId);
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldfld, netIdField));
|
||||
worker.Append(worker.Create(OpCodes.Stloc, oldNetId));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, netIdField);
|
||||
worker.Emit(OpCodes.Stloc, oldNetId);
|
||||
|
||||
// GameObject/NetworkIdentity oldSyncVar = syncvar.getter;
|
||||
VariableDefinition oldSyncVar = new VariableDefinition(syncVar.FieldType);
|
||||
deserialize.Body.Variables.Add(oldSyncVar);
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldfld, syncVar));
|
||||
worker.Append(worker.Create(OpCodes.Stloc, oldSyncVar));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, syncVar);
|
||||
worker.Emit(OpCodes.Stloc, oldSyncVar);
|
||||
|
||||
// read id and store in netId field BEFORE calling the hook
|
||||
// -> this makes way more sense. by definition, the hook is
|
||||
@ -676,13 +676,13 @@ void DeserializeNetworkBehaviourField(FieldDefinition syncVar, ILProcessor worke
|
||||
// values BEFORE the hook even returned and hence BEFORE the
|
||||
// actual value was even set.
|
||||
// put 'this.' onto stack for 'this.netId' below
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
// reader. for 'reader.Read()' below
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_1));
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
// Read()
|
||||
worker.Append(worker.Create(OpCodes.Call, Readers.GetReadFunc(WeaverTypes.Import<NetworkBehaviour.NetworkBehaviourSyncVar>())));
|
||||
worker.Emit(OpCodes.Call, Readers.GetReadFunc(WeaverTypes.Import<NetworkBehaviour.NetworkBehaviourSyncVar>()));
|
||||
// netId
|
||||
worker.Append(worker.Create(OpCodes.Stfld, netIdField));
|
||||
worker.Emit(OpCodes.Stfld, netIdField);
|
||||
|
||||
if (hookMethod != null)
|
||||
{
|
||||
@ -708,17 +708,17 @@ void DeserializeNetworkBehaviourField(FieldDefinition syncVar, ILProcessor worke
|
||||
Instruction syncVarEqualLabel = worker.Create(OpCodes.Nop);
|
||||
|
||||
// 'this.' for 'this.SyncVarEqual'
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
// 'oldNetId'
|
||||
worker.Append(worker.Create(OpCodes.Ldloc, oldNetId));
|
||||
worker.Emit(OpCodes.Ldloc, oldNetId);
|
||||
// 'ref this.__netId'
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldflda, netIdField));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, netIdField);
|
||||
// call the function
|
||||
GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(WeaverTypes.syncVarEqualReference);
|
||||
syncVarEqualGm.GenericArguments.Add(netIdField.FieldType);
|
||||
worker.Append(worker.Create(OpCodes.Call, syncVarEqualGm));
|
||||
worker.Append(worker.Create(OpCodes.Brtrue, syncVarEqualLabel));
|
||||
worker.Emit(OpCodes.Call, syncVarEqualGm);
|
||||
worker.Emit(OpCodes.Brtrue, syncVarEqualLabel);
|
||||
|
||||
// call the hook
|
||||
// Generates: OnValueChanged(oldValue, this.syncVar);
|
||||
@ -942,17 +942,17 @@ public static bool ReadArguments(MethodDefinition method, ILProcessor worker, Re
|
||||
return false;
|
||||
}
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_1));
|
||||
worker.Append(worker.Create(OpCodes.Call, readFunc));
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
worker.Emit(OpCodes.Call, readFunc);
|
||||
|
||||
// conversion.. is this needed?
|
||||
if (param.ParameterType.Is<float>())
|
||||
{
|
||||
worker.Append(worker.Create(OpCodes.Conv_R4));
|
||||
worker.Emit(OpCodes.Conv_R4);
|
||||
}
|
||||
else if (param.ParameterType.Is<double>())
|
||||
{
|
||||
worker.Append(worker.Create(OpCodes.Conv_R8));
|
||||
worker.Emit(OpCodes.Conv_R8);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -165,7 +165,7 @@ public static void InitializeReaderAndWriters(AssemblyDefinition currentAssembly
|
||||
Writers.InitializeWriters(worker);
|
||||
Readers.InitializeReaders(worker);
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Ret);
|
||||
|
||||
TypeDefinition generateClass = Weaver.WeaveLists.generateContainerClass;
|
||||
|
||||
|
@ -21,15 +21,15 @@ public static MethodDefinition ProcessRpcInvoke(TypeDefinition td, MethodDefinit
|
||||
NetworkBehaviourProcessor.WriteClientActiveCheck(worker, md.Name, label, "RPC");
|
||||
|
||||
// setup for reader
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Castclass, td));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Castclass, td);
|
||||
|
||||
if (!NetworkBehaviourProcessor.ReadArguments(md, worker, RemoteCallType.ClientRpc))
|
||||
return null;
|
||||
|
||||
// invoke actual command function
|
||||
worker.Append(worker.Create(OpCodes.Callvirt, rpcCallFunc));
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Callvirt, rpcCallFunc);
|
||||
worker.Emit(OpCodes.Ret);
|
||||
|
||||
NetworkBehaviourProcessor.AddInvokeParameters(rpc.Parameters);
|
||||
td.Methods.Add(rpc);
|
||||
@ -68,8 +68,8 @@ public static MethodDefinition ProcessRpcCall(TypeDefinition td, MethodDefinitio
|
||||
|
||||
if (Weaver.GenerateLogErrors)
|
||||
{
|
||||
worker.Append(worker.Create(OpCodes.Ldstr, "Call ClientRpc function " + md.Name));
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.logErrorReference));
|
||||
worker.Emit(OpCodes.Ldstr, "Call ClientRpc function " + md.Name);
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.logErrorReference);
|
||||
}
|
||||
|
||||
NetworkBehaviourProcessor.WriteCreateWriter(worker);
|
||||
@ -84,20 +84,20 @@ public static MethodDefinition ProcessRpcCall(TypeDefinition td, MethodDefinitio
|
||||
|
||||
// invoke SendInternal and return
|
||||
// this
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldtoken, td));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldtoken, td);
|
||||
// invokerClass
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getTypeFromHandleReference));
|
||||
worker.Append(worker.Create(OpCodes.Ldstr, rpcName));
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.getTypeFromHandleReference);
|
||||
worker.Emit(OpCodes.Ldstr, rpcName);
|
||||
// writer
|
||||
worker.Append(worker.Create(OpCodes.Ldloc_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldc_I4, channel));
|
||||
worker.Append(worker.Create(excludeOwner ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0));
|
||||
worker.Append(worker.Create(OpCodes.Callvirt, WeaverTypes.sendRpcInternal));
|
||||
worker.Emit(OpCodes.Ldloc_0);
|
||||
worker.Emit(OpCodes.Ldc_I4, channel);
|
||||
worker.Emit(excludeOwner ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
|
||||
worker.Emit(OpCodes.Callvirt, WeaverTypes.sendRpcInternal);
|
||||
|
||||
NetworkBehaviourProcessor.WriteRecycleWriter(worker);
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Ret);
|
||||
|
||||
return rpc;
|
||||
}
|
||||
|
@ -37,11 +37,11 @@ public static bool ImplementsSyncObject(TypeReference typeRef)
|
||||
*/
|
||||
static void GenerateSyncObjectRegistration(ILProcessor worker, FieldDefinition fd)
|
||||
{
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldfld, fd));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, fd);
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.InitSyncObjectReference));
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.InitSyncObjectReference);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,46 +86,46 @@ public static MethodDefinition GenerateSyncVarGetter(FieldDefinition fd, string
|
||||
{
|
||||
// return this.GetSyncVarGameObject(ref field, uint netId);
|
||||
// this.
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldfld, netFieldId));
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldflda, fd));
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getSyncVarGameObjectReference));
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, netFieldId);
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, fd);
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.getSyncVarGameObjectReference);
|
||||
worker.Emit(OpCodes.Ret);
|
||||
}
|
||||
// [SyncVar] NetworkIdentity?
|
||||
else if (fd.FieldType.Is<NetworkIdentity>())
|
||||
{
|
||||
// return this.GetSyncVarNetworkIdentity(ref field, uint netId);
|
||||
// this.
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldfld, netFieldId));
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldflda, fd));
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getSyncVarNetworkIdentityReference));
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, netFieldId);
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, fd);
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.getSyncVarNetworkIdentityReference);
|
||||
worker.Emit(OpCodes.Ret);
|
||||
}
|
||||
else if (fd.FieldType.IsDerivedFrom<NetworkBehaviour>())
|
||||
{
|
||||
// return this.GetSyncVarNetworkBehaviour<T>(ref field, uint netId);
|
||||
// this.
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldfld, netFieldId));
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldflda, fd));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, netFieldId);
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, fd);
|
||||
MethodReference getFunc = WeaverTypes.getSyncVarNetworkBehaviourReference.MakeGeneric(fd.FieldType);
|
||||
worker.Append(worker.Create(OpCodes.Call, getFunc));
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Call, getFunc);
|
||||
worker.Emit(OpCodes.Ret);
|
||||
}
|
||||
// [SyncVar] int, string, etc.
|
||||
else
|
||||
{
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldfld, fd));
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, fd);
|
||||
worker.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
get.Body.Variables.Add(new VariableDefinition(fd.FieldType));
|
||||
@ -149,94 +149,94 @@ public static MethodDefinition GenerateSyncVarSetter(TypeDefinition td, FieldDef
|
||||
Instruction endOfMethod = worker.Create(OpCodes.Nop);
|
||||
|
||||
// this
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
// new value to set
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_1));
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
// reference to field to set
|
||||
// make generic version of SetSyncVar with field type
|
||||
if (fd.FieldType.Is<UnityEngine.GameObject>())
|
||||
{
|
||||
// reference to netId Field to set
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldfld, netFieldId));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, netFieldId);
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.syncVarGameObjectEqualReference));
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.syncVarGameObjectEqualReference);
|
||||
}
|
||||
else if (fd.FieldType.Is<NetworkIdentity>())
|
||||
{
|
||||
// reference to netId Field to set
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldfld, netFieldId));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, netFieldId);
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.syncVarNetworkIdentityEqualReference));
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.syncVarNetworkIdentityEqualReference);
|
||||
}
|
||||
else if (fd.FieldType.IsDerivedFrom<NetworkBehaviour>())
|
||||
{
|
||||
// reference to netId Field to set
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldfld, netFieldId));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, netFieldId);
|
||||
|
||||
MethodReference getFunc = WeaverTypes.syncVarNetworkBehaviourEqualReference.MakeGeneric(fd.FieldType);
|
||||
worker.Append(worker.Create(OpCodes.Call, getFunc));
|
||||
worker.Emit(OpCodes.Call, getFunc);
|
||||
}
|
||||
else
|
||||
{
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldflda, fd));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, fd);
|
||||
|
||||
GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(WeaverTypes.syncVarEqualReference);
|
||||
syncVarEqualGm.GenericArguments.Add(fd.FieldType);
|
||||
worker.Append(worker.Create(OpCodes.Call, syncVarEqualGm));
|
||||
worker.Emit(OpCodes.Call, syncVarEqualGm);
|
||||
}
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Brtrue, endOfMethod));
|
||||
worker.Emit(OpCodes.Brtrue, endOfMethod);
|
||||
|
||||
// T oldValue = value;
|
||||
// TODO for GO/NI we need to backup the netId don't we?
|
||||
VariableDefinition oldValue = new VariableDefinition(fd.FieldType);
|
||||
set.Body.Variables.Add(oldValue);
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldfld, fd));
|
||||
worker.Append(worker.Create(OpCodes.Stloc, oldValue));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, fd);
|
||||
worker.Emit(OpCodes.Stloc, oldValue);
|
||||
|
||||
// this
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
|
||||
// new value to set
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_1));
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
|
||||
// reference to field to set
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldflda, fd));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, fd);
|
||||
|
||||
// dirty bit
|
||||
// 8 byte integer aka long
|
||||
worker.Append(worker.Create(OpCodes.Ldc_I8, dirtyBit));
|
||||
worker.Emit(OpCodes.Ldc_I8, dirtyBit);
|
||||
|
||||
if (fd.FieldType.Is<UnityEngine.GameObject>())
|
||||
{
|
||||
// reference to netId Field to set
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldflda, netFieldId));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, netFieldId);
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.setSyncVarGameObjectReference));
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.setSyncVarGameObjectReference);
|
||||
}
|
||||
else if (fd.FieldType.Is<NetworkIdentity>())
|
||||
{
|
||||
// reference to netId Field to set
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldflda, netFieldId));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, netFieldId);
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.setSyncVarNetworkIdentityReference));
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.setSyncVarNetworkIdentityReference);
|
||||
}
|
||||
else if (fd.FieldType.IsDerivedFrom<NetworkBehaviour>())
|
||||
{
|
||||
// reference to netId Field to set
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldflda, netFieldId));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, netFieldId);
|
||||
|
||||
MethodReference getFunc = WeaverTypes.setSyncVarNetworkBehaviourReference.MakeGeneric(fd.FieldType);
|
||||
worker.Append(worker.Create(OpCodes.Call, getFunc));
|
||||
worker.Emit(OpCodes.Call, getFunc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -245,7 +245,7 @@ public static MethodDefinition GenerateSyncVarSetter(TypeDefinition td, FieldDef
|
||||
gm.GenericArguments.Add(fd.FieldType);
|
||||
|
||||
// invoke SetSyncVar
|
||||
worker.Append(worker.Create(OpCodes.Call, gm));
|
||||
worker.Emit(OpCodes.Call, gm);
|
||||
}
|
||||
|
||||
MethodDefinition hookMethod = GetHookMethod(td, fd);
|
||||
@ -254,35 +254,35 @@ public static MethodDefinition GenerateSyncVarSetter(TypeDefinition td, FieldDef
|
||||
{
|
||||
//if (NetworkServer.localClientActive && !getSyncVarHookGuard(dirtyBit))
|
||||
Instruction label = worker.Create(OpCodes.Nop);
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.NetworkServerGetLocalClientActive));
|
||||
worker.Append(worker.Create(OpCodes.Brfalse, label));
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldc_I8, dirtyBit));
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getSyncVarHookGuard));
|
||||
worker.Append(worker.Create(OpCodes.Brtrue, label));
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.NetworkServerGetLocalClientActive);
|
||||
worker.Emit(OpCodes.Brfalse, label);
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldc_I8, dirtyBit);
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.getSyncVarHookGuard);
|
||||
worker.Emit(OpCodes.Brtrue, label);
|
||||
|
||||
// setSyncVarHookGuard(dirtyBit, true);
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldc_I8, dirtyBit));
|
||||
worker.Append(worker.Create(OpCodes.Ldc_I4_1));
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.setSyncVarHookGuard));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldc_I8, dirtyBit);
|
||||
worker.Emit(OpCodes.Ldc_I4_1);
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.setSyncVarHookGuard);
|
||||
|
||||
// call hook (oldValue, newValue)
|
||||
// Generates: OnValueChanged(oldValue, value);
|
||||
WriteCallHookMethodUsingArgument(worker, hookMethod, oldValue);
|
||||
|
||||
// setSyncVarHookGuard(dirtyBit, false);
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldc_I8, dirtyBit));
|
||||
worker.Append(worker.Create(OpCodes.Ldc_I4_0));
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.setSyncVarHookGuard));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldc_I8, dirtyBit);
|
||||
worker.Emit(OpCodes.Ldc_I4_0);
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.setSyncVarHookGuard);
|
||||
|
||||
worker.Append(label);
|
||||
}
|
||||
|
||||
worker.Append(endOfMethod);
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Ret);
|
||||
|
||||
set.Parameters.Add(new ParameterDefinition("value", ParameterAttributes.In, fd.FieldType));
|
||||
set.SemanticsAttributes = MethodSemanticsAttributes.Setter;
|
||||
@ -429,7 +429,7 @@ static void WriteCallHookMethod(ILProcessor worker, MethodDefinition hookMethod,
|
||||
|
||||
void WriteOldValue()
|
||||
{
|
||||
worker.Append(worker.Create(OpCodes.Ldloc, oldValue));
|
||||
worker.Emit(OpCodes.Ldloc, oldValue);
|
||||
}
|
||||
|
||||
void WriteNewValue()
|
||||
@ -437,14 +437,14 @@ void WriteNewValue()
|
||||
// write arg1 or this.field
|
||||
if (newValue == null)
|
||||
{
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_1));
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// this.
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
// syncvar.get
|
||||
worker.Append(worker.Create(OpCodes.Ldfld, newValue));
|
||||
worker.Emit(OpCodes.Ldfld, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
@ -456,7 +456,7 @@ void WriteStartFunctionCall()
|
||||
{
|
||||
// this before method call
|
||||
// e.g. this.onValueChanged
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -465,7 +465,7 @@ void WriteEndFunctionCall()
|
||||
{
|
||||
// only use Callvirt when not static
|
||||
OpCode opcode = hookMethod.IsStatic ? OpCodes.Call : OpCodes.Callvirt;
|
||||
worker.Append(worker.Create(opcode, hookMethod));
|
||||
worker.Emit(opcode, hookMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,15 +28,15 @@ public static MethodDefinition ProcessTargetRpcInvoke(TypeDefinition td, MethodD
|
||||
NetworkBehaviourProcessor.WriteClientActiveCheck(worker, md.Name, label, "TargetRPC");
|
||||
|
||||
// setup for reader
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Castclass, td));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Castclass, td);
|
||||
|
||||
// NetworkConnection parameter is optional
|
||||
if (HasNetworkConnectionParameter(md))
|
||||
{
|
||||
// if call has NetworkConnection write clients connection as first arg
|
||||
//ClientScene.readyconnection
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.ReadyConnectionReference));
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.ReadyConnectionReference);
|
||||
}
|
||||
|
||||
// process reader parameters and skip first one if first one is NetworkConnection
|
||||
@ -44,8 +44,8 @@ public static MethodDefinition ProcessTargetRpcInvoke(TypeDefinition td, MethodD
|
||||
return null;
|
||||
|
||||
// invoke actual command function
|
||||
worker.Append(worker.Create(OpCodes.Callvirt, rpcCallFunc));
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Callvirt, rpcCallFunc);
|
||||
worker.Emit(OpCodes.Ret);
|
||||
|
||||
NetworkBehaviourProcessor.AddInvokeParameters(rpc.Parameters);
|
||||
td.Methods.Add(rpc);
|
||||
@ -104,29 +104,29 @@ public static MethodDefinition ProcessTargetRpcCall(TypeDefinition td, MethodDef
|
||||
|
||||
// invoke SendInternal and return
|
||||
// this
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
if (HasNetworkConnectionParameter(md))
|
||||
{
|
||||
// connection
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_1));
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// null
|
||||
worker.Append(worker.Create(OpCodes.Ldnull));
|
||||
worker.Emit(OpCodes.Ldnull);
|
||||
}
|
||||
worker.Append(worker.Create(OpCodes.Ldtoken, td));
|
||||
worker.Emit(OpCodes.Ldtoken, td);
|
||||
// invokerClass
|
||||
worker.Append(worker.Create(OpCodes.Call, WeaverTypes.getTypeFromHandleReference));
|
||||
worker.Append(worker.Create(OpCodes.Ldstr, rpcName));
|
||||
worker.Emit(OpCodes.Call, WeaverTypes.getTypeFromHandleReference);
|
||||
worker.Emit(OpCodes.Ldstr, rpcName);
|
||||
// writer
|
||||
worker.Append(worker.Create(OpCodes.Ldloc_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldc_I4, targetRpcAttr.GetField("channel", 0)));
|
||||
worker.Append(worker.Create(OpCodes.Callvirt, WeaverTypes.sendTargetRpcInternal));
|
||||
worker.Emit(OpCodes.Ldloc_0);
|
||||
worker.Emit(OpCodes.Ldc_I4, targetRpcAttr.GetField("channel", 0));
|
||||
worker.Emit(OpCodes.Callvirt, WeaverTypes.sendTargetRpcInternal);
|
||||
|
||||
NetworkBehaviourProcessor.WriteRecycleWriter(worker);
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Ret);
|
||||
|
||||
return rpc;
|
||||
}
|
||||
|
@ -157,13 +157,13 @@ static MethodDefinition GenerateEnumReadFunc(TypeReference variable)
|
||||
|
||||
ILProcessor worker = readerFunc.Body.GetILProcessor();
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
|
||||
TypeReference underlyingType = variable.Resolve().GetEnumUnderlyingType();
|
||||
MethodReference underlyingFunc = GetReadFunc(underlyingType);
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Call, underlyingFunc));
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Call, underlyingFunc);
|
||||
worker.Emit(OpCodes.Ret);
|
||||
return readerFunc;
|
||||
}
|
||||
|
||||
@ -178,12 +178,12 @@ static MethodDefinition GenerateArraySegmentReadFunc(TypeReference variable)
|
||||
|
||||
// $array = reader.Read<[T]>()
|
||||
ArrayType arrayType = elementType.MakeArrayType();
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Call, GetReadFunc(arrayType)));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Call, GetReadFunc(arrayType));
|
||||
|
||||
// return new ArraySegment<T>($array);
|
||||
worker.Append(worker.Create(OpCodes.Newobj, WeaverTypes.ArraySegmentConstructorReference.MakeHostInstanceGeneric(genericInstance)));
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Newobj, WeaverTypes.ArraySegmentConstructorReference.MakeHostInstanceGeneric(genericInstance));
|
||||
worker.Emit(OpCodes.Ret);
|
||||
return readerFunc;
|
||||
}
|
||||
|
||||
@ -222,10 +222,10 @@ static MethodDefinition GenerateReadCollection(TypeReference variable, TypeRefer
|
||||
// return reader.ReadList<T>();
|
||||
|
||||
ILProcessor worker = readerFunc.Body.GetILProcessor();
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0)); // reader
|
||||
worker.Append(worker.Create(OpCodes.Call, methodRef)); // Read
|
||||
worker.Emit(OpCodes.Ldarg_0); // reader
|
||||
worker.Emit(OpCodes.Call, methodRef); // Read
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Ret);
|
||||
|
||||
return readerFunc;
|
||||
}
|
||||
@ -247,8 +247,8 @@ static MethodDefinition GenerateClassOrStructReadFunction(TypeReference variable
|
||||
CreateNew(variable, worker, td);
|
||||
ReadAllFields(variable, worker);
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Ldloc_0));
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Ldloc_0);
|
||||
worker.Emit(OpCodes.Ret);
|
||||
return readerFunc;
|
||||
}
|
||||
|
||||
@ -257,14 +257,14 @@ static void GenerateNullCheck(ILProcessor worker)
|
||||
// if (!reader.ReadBoolean()) {
|
||||
// return null;
|
||||
// }
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Call, GetReadFunc(WeaverTypes.Import<bool>())));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Call, GetReadFunc(WeaverTypes.Import<bool>()));
|
||||
|
||||
Instruction labelEmptyArray = worker.Create(OpCodes.Nop);
|
||||
worker.Append(worker.Create(OpCodes.Brtrue, labelEmptyArray));
|
||||
worker.Emit(OpCodes.Brtrue, labelEmptyArray);
|
||||
// return null
|
||||
worker.Append(worker.Create(OpCodes.Ldnull));
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Ldnull);
|
||||
worker.Emit(OpCodes.Ret);
|
||||
worker.Append(labelEmptyArray);
|
||||
}
|
||||
|
||||
@ -274,15 +274,15 @@ static void CreateNew(TypeReference variable, ILProcessor worker, TypeDefinition
|
||||
if (variable.IsValueType)
|
||||
{
|
||||
// structs are created with Initobj
|
||||
worker.Append(worker.Create(OpCodes.Ldloca, 0));
|
||||
worker.Append(worker.Create(OpCodes.Initobj, variable));
|
||||
worker.Emit(OpCodes.Ldloca, 0);
|
||||
worker.Emit(OpCodes.Initobj, variable);
|
||||
}
|
||||
else if (td.IsDerivedFrom<UnityEngine.ScriptableObject>())
|
||||
{
|
||||
GenericInstanceMethod genericInstanceMethod = new GenericInstanceMethod(WeaverTypes.ScriptableObjectCreateInstanceMethod);
|
||||
genericInstanceMethod.GenericArguments.Add(variable);
|
||||
worker.Append(worker.Create(OpCodes.Call, genericInstanceMethod));
|
||||
worker.Append(worker.Create(OpCodes.Stloc_0));
|
||||
worker.Emit(OpCodes.Call, genericInstanceMethod);
|
||||
worker.Emit(OpCodes.Stloc_0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -296,8 +296,8 @@ static void CreateNew(TypeReference variable, ILProcessor worker, TypeDefinition
|
||||
|
||||
MethodReference ctorRef = Weaver.CurrentAssembly.MainModule.ImportReference(ctor);
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Newobj, ctorRef));
|
||||
worker.Append(worker.Create(OpCodes.Stloc_0));
|
||||
worker.Emit(OpCodes.Newobj, ctorRef);
|
||||
worker.Emit(OpCodes.Stloc_0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,12 +307,12 @@ static void ReadAllFields(TypeReference variable, ILProcessor worker)
|
||||
{
|
||||
// mismatched ldloca/ldloc for struct/class combinations is invalid IL, which causes crash at runtime
|
||||
OpCode opcode = variable.IsValueType ? OpCodes.Ldloca : OpCodes.Ldloc;
|
||||
worker.Append(worker.Create(opcode, 0));
|
||||
worker.Emit(opcode, 0);
|
||||
MethodReference readFunc = GetReadFunc(field.FieldType);
|
||||
if (readFunc != null)
|
||||
{
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Call, readFunc));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Call, readFunc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -320,7 +320,7 @@ static void ReadAllFields(TypeReference variable, ILProcessor worker)
|
||||
}
|
||||
FieldReference fieldRef = Weaver.CurrentAssembly.MainModule.ImportReference(field);
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Stfld, fieldRef));
|
||||
worker.Emit(OpCodes.Stfld, fieldRef);
|
||||
}
|
||||
}
|
||||
|
||||
@ -346,16 +346,16 @@ internal static void InitializeReaders(ILProcessor worker)
|
||||
MethodReference readFunc = kvp.Value;
|
||||
|
||||
// create a Func<NetworkReader, T> delegate
|
||||
worker.Append(worker.Create(OpCodes.Ldnull));
|
||||
worker.Append(worker.Create(OpCodes.Ldftn, readFunc));
|
||||
worker.Emit(OpCodes.Ldnull);
|
||||
worker.Emit(OpCodes.Ldftn, readFunc);
|
||||
GenericInstanceType funcGenericInstance = funcRef.MakeGenericInstanceType(networkReaderRef, targetType);
|
||||
MethodReference funcConstructorInstance = funcConstructorRef.MakeHostInstanceGeneric(funcGenericInstance);
|
||||
worker.Append(worker.Create(OpCodes.Newobj, funcConstructorInstance));
|
||||
worker.Emit(OpCodes.Newobj, funcConstructorInstance);
|
||||
|
||||
// save it in Reader<T>.read
|
||||
GenericInstanceType genericInstance = genericReaderClassRef.MakeGenericInstanceType(targetType);
|
||||
FieldReference specializedField = fieldRef.SpecializeField(genericInstance);
|
||||
worker.Append(worker.Create(OpCodes.Stsfld, specializedField));
|
||||
worker.Emit(OpCodes.Stsfld, specializedField);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -171,11 +171,11 @@ static MethodDefinition GenerateEnumWriteFunc(TypeReference variable)
|
||||
|
||||
MethodReference underlyingWriter = GetWriteFunc(variable.Resolve().GetEnumUnderlyingType());
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_1));
|
||||
worker.Append(worker.Create(OpCodes.Call, underlyingWriter));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
worker.Emit(OpCodes.Call, underlyingWriter);
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Ret);
|
||||
return writerFunc;
|
||||
}
|
||||
|
||||
@ -209,7 +209,7 @@ static MethodDefinition GenerateClassOrStructWriterFunction(TypeReference variab
|
||||
if (!WriteAllFields(variable, worker))
|
||||
return null;
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Ret);
|
||||
return writerFunc;
|
||||
}
|
||||
|
||||
@ -223,18 +223,18 @@ static void WriteNullCheck(ILProcessor worker)
|
||||
//
|
||||
|
||||
Instruction labelNotNull = worker.Create(OpCodes.Nop);
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_1));
|
||||
worker.Append(worker.Create(OpCodes.Brtrue, labelNotNull));
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldc_I4_0));
|
||||
worker.Append(worker.Create(OpCodes.Call, GetWriteFunc(WeaverTypes.Import<bool>())));
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
worker.Emit(OpCodes.Brtrue, labelNotNull);
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldc_I4_0);
|
||||
worker.Emit(OpCodes.Call, GetWriteFunc(WeaverTypes.Import<bool>()));
|
||||
worker.Emit(OpCodes.Ret);
|
||||
worker.Append(labelNotNull);
|
||||
|
||||
// write.WriteBoolean(true);
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldc_I4_1));
|
||||
worker.Append(worker.Create(OpCodes.Call, GetWriteFunc(WeaverTypes.Import<bool>())));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldc_I4_1);
|
||||
worker.Emit(OpCodes.Call, GetWriteFunc(WeaverTypes.Import<bool>()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -255,10 +255,10 @@ static bool WriteAllFields(TypeReference variable, ILProcessor worker)
|
||||
FieldReference fieldRef = Weaver.CurrentAssembly.MainModule.ImportReference(field);
|
||||
|
||||
fields++;
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_1));
|
||||
worker.Append(worker.Create(OpCodes.Ldfld, fieldRef));
|
||||
worker.Append(worker.Create(OpCodes.Call, writeFunc));
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
worker.Emit(OpCodes.Ldfld, fieldRef);
|
||||
worker.Emit(OpCodes.Call, writeFunc);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -290,12 +290,12 @@ static MethodDefinition GenerateCollectionWriter(TypeReference variable, TypeRef
|
||||
// reader.WriteArray<T>(array);
|
||||
|
||||
ILProcessor worker = writerFunc.Body.GetILProcessor();
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0)); // writer
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_1)); // collection
|
||||
worker.Emit(OpCodes.Ldarg_0); // writer
|
||||
worker.Emit(OpCodes.Ldarg_1); // collection
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Call, methodRef)); // WriteArray
|
||||
worker.Emit(OpCodes.Call, methodRef); // WriteArray
|
||||
|
||||
worker.Append(worker.Create(OpCodes.Ret));
|
||||
worker.Emit(OpCodes.Ret);
|
||||
|
||||
return writerFunc;
|
||||
}
|
||||
@ -322,16 +322,16 @@ internal static void InitializeWriters(ILProcessor worker)
|
||||
MethodReference writeFunc = kvp.Value;
|
||||
|
||||
// create a Action<NetworkWriter, T> delegate
|
||||
worker.Append(worker.Create(OpCodes.Ldnull));
|
||||
worker.Append(worker.Create(OpCodes.Ldftn, writeFunc));
|
||||
worker.Emit(OpCodes.Ldnull);
|
||||
worker.Emit(OpCodes.Ldftn, writeFunc);
|
||||
GenericInstanceType actionGenericInstance = actionRef.MakeGenericInstanceType(networkWriterRef, targetType);
|
||||
MethodReference actionRefInstance = actionConstructorRef.MakeHostInstanceGeneric(actionGenericInstance);
|
||||
worker.Append(worker.Create(OpCodes.Newobj, actionRefInstance));
|
||||
worker.Emit(OpCodes.Newobj, actionRefInstance);
|
||||
|
||||
// save it in Writer<T>.write
|
||||
GenericInstanceType genericInstance = genericWriterClassRef.MakeGenericInstanceType(targetType);
|
||||
FieldReference specializedField = fieldRef.SpecializeField(genericInstance);
|
||||
worker.Append(worker.Create(OpCodes.Stsfld, specializedField));
|
||||
worker.Emit(OpCodes.Stsfld, specializedField);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user