mirror of
https://github.com/misternebula/quantum-space-buddies.git
synced 2025-04-17 08:43:30 +00:00
update mirror
This commit is contained in:
parent
05ea4fa1c3
commit
7893c593a6
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Mirror/kcp2k.dll
BIN
Mirror/kcp2k.dll
Binary file not shown.
Binary file not shown.
@ -18,8 +18,6 @@ namespace Mirror.Weaver
|
||||
|
||||
public static bool IsDerivedFrom(this TypeReference tr, Type baseClass)
|
||||
{
|
||||
if (tr == null)
|
||||
return false;
|
||||
TypeDefinition td = tr.Resolve();
|
||||
if (!td.IsClass)
|
||||
return false;
|
||||
@ -142,6 +140,18 @@ namespace Mirror.Weaver
|
||||
return module.ImportReference(reference);
|
||||
}
|
||||
|
||||
// needed for NetworkBehaviour<T> support
|
||||
// https://github.com/vis2k/Mirror/pull/3073/
|
||||
public static FieldReference MakeHostInstanceGeneric(this FieldReference self)
|
||||
{
|
||||
var declaringType = new GenericInstanceType(self.DeclaringType);
|
||||
foreach (var parameter in self.DeclaringType.GenericParameters)
|
||||
{
|
||||
declaringType.GenericArguments.Add(parameter);
|
||||
}
|
||||
return new FieldReference(self.Name, self.FieldType, declaringType);
|
||||
}
|
||||
|
||||
// Given a field of a generic class such as Writer<T>.write,
|
||||
// and a generic instance such as ArraySegment`int
|
||||
// Creates a reference to the specialized method ArraySegment`int`.get_Count
|
||||
@ -253,5 +263,75 @@ namespace Mirror.Weaver
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Takes generic arguments from child class and applies them to parent reference, if possible
|
||||
// eg makes `Base<T>` in Child<int> : Base<int> have `int` instead of `T`
|
||||
// Originally by James-Frowen under MIT
|
||||
// https://github.com/MirageNet/Mirage/commit/cf91e1d54796866d2cf87f8e919bb5c681977e45
|
||||
public static TypeReference ApplyGenericParameters(this TypeReference parentReference,
|
||||
TypeReference childReference)
|
||||
{
|
||||
// If the parent is not generic, we got nothing to apply
|
||||
if (!parentReference.IsGenericInstance)
|
||||
return parentReference;
|
||||
|
||||
GenericInstanceType parentGeneric = (GenericInstanceType)parentReference;
|
||||
// make new type so we can replace the args on it
|
||||
// resolve it so we have non-generic instance (eg just instance with <T> instead of <int>)
|
||||
// if we don't cecil will make it double generic (eg INVALID IL)
|
||||
GenericInstanceType generic = new GenericInstanceType(parentReference.Resolve());
|
||||
foreach (TypeReference arg in parentGeneric.GenericArguments)
|
||||
generic.GenericArguments.Add(arg);
|
||||
|
||||
for (int i = 0; i < generic.GenericArguments.Count; i++)
|
||||
{
|
||||
// if arg is not generic
|
||||
// eg List<int> would be int so not generic.
|
||||
// But List<T> would be T so is generic
|
||||
if (!generic.GenericArguments[i].IsGenericParameter)
|
||||
continue;
|
||||
|
||||
// get the generic name, eg T
|
||||
string name = generic.GenericArguments[i].Name;
|
||||
// find what type T is, eg turn it into `int` if `List<int>`
|
||||
TypeReference arg = FindMatchingGenericArgument(childReference, name);
|
||||
|
||||
// import just to be safe
|
||||
TypeReference imported = parentReference.Module.ImportReference(arg);
|
||||
// set arg on generic, parent ref will be Base<int> instead of just Base<T>
|
||||
generic.GenericArguments[i] = imported;
|
||||
}
|
||||
|
||||
return generic;
|
||||
}
|
||||
|
||||
// Finds the type reference for a generic parameter with the provided name in the child reference
|
||||
// Originally by James-Frowen under MIT
|
||||
// https://github.com/MirageNet/Mirage/commit/cf91e1d54796866d2cf87f8e919bb5c681977e45
|
||||
static TypeReference FindMatchingGenericArgument(TypeReference childReference, string paramName)
|
||||
{
|
||||
TypeDefinition def = childReference.Resolve();
|
||||
// child class must be generic if we are in this part of the code
|
||||
// eg Child<T> : Base<T> <--- child must have generic if Base has T
|
||||
// vs Child : Base<int> <--- wont be here if Base has int (we check if T exists before calling this)
|
||||
if (!def.HasGenericParameters)
|
||||
throw new InvalidOperationException(
|
||||
"Base class had generic parameters, but could not find them in child class");
|
||||
|
||||
// go through parameters in child class, and find the generic that matches the name
|
||||
for (int i = 0; i < def.GenericParameters.Count; i++)
|
||||
{
|
||||
GenericParameter param = def.GenericParameters[i];
|
||||
if (param.Name == paramName)
|
||||
{
|
||||
GenericInstanceType generic = (GenericInstanceType)childReference;
|
||||
// return generic arg with same index
|
||||
return generic.GenericArguments[i];
|
||||
}
|
||||
}
|
||||
|
||||
// this should never happen, if it does it means that this code is bugged
|
||||
throw new InvalidOperationException("Did not find matching generic");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,16 +68,6 @@ namespace Mirror.Weaver
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
if (netBehaviourSubclass.HasGenericParameters)
|
||||
{
|
||||
Log.Error($"{netBehaviourSubclass.Name} cannot have generic parameters", netBehaviourSubclass);
|
||||
WeavingFailed = true;
|
||||
// originally Process returned true in every case, except if already processed.
|
||||
// maybe return false here in the future.
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
MarkAsProcessed(netBehaviourSubclass);
|
||||
|
||||
// deconstruct tuple and set fields
|
||||
@ -439,8 +429,13 @@ namespace Mirror.Weaver
|
||||
worker.Emit(OpCodes.Ldarg_2);
|
||||
worker.Emit(OpCodes.Brfalse, initialStateLabel);
|
||||
|
||||
foreach (FieldDefinition syncVar in syncVars)
|
||||
foreach (FieldDefinition syncVarDef in syncVars)
|
||||
{
|
||||
FieldReference syncVar = syncVarDef;
|
||||
if (netBehaviourSubclass.HasGenericParameters)
|
||||
{
|
||||
syncVar = syncVarDef.MakeHostInstanceGeneric();
|
||||
}
|
||||
// Generates a writer call for each sync variable
|
||||
// writer
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
@ -483,8 +478,14 @@ namespace Mirror.Weaver
|
||||
|
||||
// start at number of syncvars in parent
|
||||
int dirtyBit = syncVarAccessLists.GetSyncVarStart(netBehaviourSubclass.BaseType.FullName);
|
||||
foreach (FieldDefinition syncVar in syncVars)
|
||||
foreach (FieldDefinition syncVarDef in syncVars)
|
||||
{
|
||||
|
||||
FieldReference syncVar = syncVarDef;
|
||||
if (netBehaviourSubclass.HasGenericParameters)
|
||||
{
|
||||
syncVar = syncVarDef.MakeHostInstanceGeneric();
|
||||
}
|
||||
Instruction varLabel = worker.Create(OpCodes.Nop);
|
||||
|
||||
// Generates: if ((base.get_syncVarDirtyBits() & 1uL) != 0uL)
|
||||
@ -534,303 +535,98 @@ namespace Mirror.Weaver
|
||||
netBehaviourSubclass.Methods.Add(serialize);
|
||||
}
|
||||
|
||||
void DeserializeField(FieldDefinition syncVar, ILProcessor worker, MethodDefinition deserialize, ref bool WeavingFailed)
|
||||
void DeserializeField(FieldDefinition syncVar, ILProcessor worker, ref bool WeavingFailed)
|
||||
{
|
||||
// check for Hook function
|
||||
MethodDefinition hookMethod = syncVarAttributeProcessor.GetHookMethod(netBehaviourSubclass, syncVar, ref WeavingFailed);
|
||||
// put 'this.' onto stack for 'this.syncvar' below
|
||||
worker.Append(worker.Create(OpCodes.Ldarg_0));
|
||||
|
||||
if (syncVar.FieldType.IsDerivedFrom<NetworkBehaviour>())
|
||||
// push 'ref T this.field'
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
// if the netbehaviour class is generic, we need to make the field reference generic as well for correct IL
|
||||
if (netBehaviourSubclass.HasGenericParameters)
|
||||
{
|
||||
DeserializeNetworkBehaviourField(syncVar, worker, deserialize, hookMethod, ref WeavingFailed);
|
||||
}
|
||||
else if (syncVar.FieldType.IsNetworkIdentityField())
|
||||
{
|
||||
DeserializeNetworkIdentityField(syncVar, worker, deserialize, hookMethod, ref WeavingFailed);
|
||||
worker.Emit(OpCodes.Ldflda, syncVar.MakeHostInstanceGeneric());
|
||||
}
|
||||
else
|
||||
{
|
||||
DeserializeNormalField(syncVar, worker, deserialize, hookMethod, ref WeavingFailed);
|
||||
worker.Emit(OpCodes.Ldflda, syncVar);
|
||||
}
|
||||
}
|
||||
|
||||
/// [SyncVar] GameObject/NetworkIdentity?
|
||||
void DeserializeNetworkIdentityField(FieldDefinition syncVar, ILProcessor worker, MethodDefinition deserialize, MethodDefinition hookMethod, ref bool WeavingFailed)
|
||||
{
|
||||
/*
|
||||
Generates code like:
|
||||
uint oldNetId = ___qNetId;
|
||||
// returns GetSyncVarGameObject(___qNetId)
|
||||
GameObject oldSyncVar = syncvar.getter;
|
||||
___qNetId = reader.ReadPackedUInt32();
|
||||
if (!SyncVarEqual(oldNetId, ref ___goNetId))
|
||||
{
|
||||
// getter returns GetSyncVarGameObject(___qNetId)
|
||||
OnSetQ(oldSyncVar, syncvar.getter);
|
||||
}
|
||||
*/
|
||||
|
||||
// GameObject/NetworkIdentity SyncVar:
|
||||
// OnSerialize sends writer.Write(go);
|
||||
// OnDeserialize reads to __netId manually so we can use
|
||||
// lookups in the getter (so it still works if objects
|
||||
// move in and out of range repeatedly)
|
||||
FieldDefinition netIdField = syncVarNetIds[syncVar];
|
||||
|
||||
// uint oldNetId = ___qNetId;
|
||||
VariableDefinition oldNetId = new VariableDefinition(weaverTypes.Import<uint>());
|
||||
deserialize.Body.Variables.Add(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.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
|
||||
// supposed to be called after it was changed. not before.
|
||||
// -> setting it BEFORE calling the hook fixes the following bug:
|
||||
// https://github.com/vis2k/Mirror/issues/1151 in host mode
|
||||
// where the value during the Hook call would call Cmds on
|
||||
// the host server, and they would all happen and compare
|
||||
// values BEFORE the hook even returned and hence BEFORE the
|
||||
// actual value was even set.
|
||||
// put 'this.' onto stack for 'this.netId' below
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
// reader. for 'reader.Read()' below
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
// Read()
|
||||
worker.Emit(OpCodes.Call, readers.GetReadFunc(weaverTypes.Import<uint>(), ref WeavingFailed));
|
||||
// netId
|
||||
worker.Emit(OpCodes.Stfld, netIdField);
|
||||
|
||||
// hook? then push 'new Action<T,T>(Hook)' onto stack
|
||||
MethodDefinition hookMethod = syncVarAttributeProcessor.GetHookMethod(netBehaviourSubclass, syncVar, ref WeavingFailed);
|
||||
if (hookMethod != null)
|
||||
{
|
||||
// call Hook(this.GetSyncVarGameObject/NetworkIdentity(reader.ReadPackedUInt32()))
|
||||
// because we send/receive the netID, not the GameObject/NetworkIdentity
|
||||
// but only if SyncVar changed. otherwise a client would
|
||||
// get hook calls for all initial values, even if they
|
||||
// didn't change from the default values on the client.
|
||||
// see also: https://github.com/vis2k/Mirror/issues/1278
|
||||
|
||||
// IMPORTANT: for GameObjects/NetworkIdentities we usually
|
||||
// use SyncVarGameObjectEqual to compare equality.
|
||||
// in this case however, we can just use
|
||||
// SyncVarEqual with the two uint netIds.
|
||||
// => this is easier weaver code because we don't
|
||||
// have to get the GameObject/NetworkIdentity
|
||||
// from the uint netId
|
||||
// => this is faster because we void one
|
||||
// GetComponent call for GameObjects to get
|
||||
// their NetworkIdentity when comparing.
|
||||
|
||||
// Generates: if (!SyncVarEqual);
|
||||
Instruction syncVarEqualLabel = worker.Create(OpCodes.Nop);
|
||||
|
||||
// NOTE: static function. don't Emit Ldarg_0 aka 'this'.
|
||||
|
||||
// 'oldNetId'
|
||||
worker.Emit(OpCodes.Ldloc, oldNetId);
|
||||
// 'ref this.__netId'
|
||||
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.Emit(OpCodes.Call, syncVarEqualGm);
|
||||
worker.Emit(OpCodes.Brtrue, syncVarEqualLabel);
|
||||
|
||||
// call the hook
|
||||
// Generates: OnValueChanged(oldValue, this.syncVar);
|
||||
syncVarAttributeProcessor.WriteCallHookMethodUsingField(worker, hookMethod, oldSyncVar, syncVar, ref WeavingFailed);
|
||||
|
||||
// Generates: end if (!SyncVarEqual);
|
||||
worker.Append(syncVarEqualLabel);
|
||||
syncVarAttributeProcessor.GenerateNewActionFromHookMethod(syncVar, worker, hookMethod);
|
||||
}
|
||||
}
|
||||
|
||||
// [SyncVar] NetworkBehaviour
|
||||
void DeserializeNetworkBehaviourField(FieldDefinition syncVar, ILProcessor worker, MethodDefinition deserialize, MethodDefinition hookMethod, ref bool WeavingFailed)
|
||||
{
|
||||
/*
|
||||
Generates code like:
|
||||
uint oldNetId = ___qNetId.netId;
|
||||
byte oldCompIndex = ___qNetId.componentIndex;
|
||||
T oldSyncVar = syncvar.getter;
|
||||
___qNetId.netId = reader.ReadPackedUInt32();
|
||||
___qNetId.componentIndex = reader.ReadByte();
|
||||
if (!SyncVarEqual(oldNetId, ref ___goNetId))
|
||||
{
|
||||
// getter returns GetSyncVarGameObject(___qNetId)
|
||||
OnSetQ(oldSyncVar, syncvar.getter);
|
||||
}
|
||||
*/
|
||||
|
||||
// GameObject/NetworkIdentity SyncVar:
|
||||
// OnSerialize sends writer.Write(go);
|
||||
// OnDeserialize reads to __netId manually so we can use
|
||||
// lookups in the getter (so it still works if objects
|
||||
// move in and out of range repeatedly)
|
||||
FieldDefinition netIdField = syncVarNetIds[syncVar];
|
||||
|
||||
// uint oldNetId = ___qNetId;
|
||||
VariableDefinition oldNetId = new VariableDefinition(weaverTypes.Import<NetworkBehaviour.NetworkBehaviourSyncVar>());
|
||||
deserialize.Body.Variables.Add(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.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
|
||||
// supposed to be called after it was changed. not before.
|
||||
// -> setting it BEFORE calling the hook fixes the following bug:
|
||||
// https://github.com/vis2k/Mirror/issues/1151 in host mode
|
||||
// where the value during the Hook call would call Cmds on
|
||||
// the host server, and they would all happen and compare
|
||||
// values BEFORE the hook even returned and hence BEFORE the
|
||||
// actual value was even set.
|
||||
// put 'this.' onto stack for 'this.netId' below
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
// reader. for 'reader.Read()' below
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
// Read()
|
||||
worker.Emit(OpCodes.Call, readers.GetReadFunc(weaverTypes.Import<NetworkBehaviour.NetworkBehaviourSyncVar>(), ref WeavingFailed));
|
||||
// netId
|
||||
worker.Emit(OpCodes.Stfld, netIdField);
|
||||
|
||||
if (hookMethod != null)
|
||||
// otherwise push 'null' as hook
|
||||
else
|
||||
{
|
||||
// call Hook(this.GetSyncVarGameObject/NetworkIdentity(reader.ReadPackedUInt32()))
|
||||
// because we send/receive the netID, not the GameObject/NetworkIdentity
|
||||
// but only if SyncVar changed. otherwise a client would
|
||||
// get hook calls for all initial values, even if they
|
||||
// didn't change from the default values on the client.
|
||||
// see also: https://github.com/vis2k/Mirror/issues/1278
|
||||
worker.Emit(OpCodes.Ldnull);
|
||||
}
|
||||
|
||||
// IMPORTANT: for GameObjects/NetworkIdentities we usually
|
||||
// use SyncVarGameObjectEqual to compare equality.
|
||||
// in this case however, we can just use
|
||||
// SyncVarEqual with the two uint netIds.
|
||||
// => this is easier weaver code because we don't
|
||||
// have to get the GameObject/NetworkIdentity
|
||||
// from the uint netId
|
||||
// => this is faster because we void one
|
||||
// GetComponent call for GameObjects to get
|
||||
// their NetworkIdentity when comparing.
|
||||
// call GeneratedSyncVarDeserialize<T>.
|
||||
// special cases for GameObject/NetworkIdentity/NetworkBehaviour
|
||||
// passing netId too for persistence.
|
||||
if (syncVar.FieldType.Is<UnityEngine.GameObject>())
|
||||
{
|
||||
// reader
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
|
||||
// Generates: if (!SyncVarEqual);
|
||||
Instruction syncVarEqualLabel = worker.Create(OpCodes.Nop);
|
||||
|
||||
// NOTE: static function. don't Emit Ldarg_0 aka 'this'.
|
||||
|
||||
// 'oldNetId'
|
||||
worker.Emit(OpCodes.Ldloc, oldNetId);
|
||||
// 'ref this.__netId'
|
||||
// GameObject setter needs one more parameter: netId field ref
|
||||
FieldDefinition netIdField = syncVarNetIds[syncVar];
|
||||
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.Emit(OpCodes.Call, syncVarEqualGm);
|
||||
worker.Emit(OpCodes.Brtrue, syncVarEqualLabel);
|
||||
|
||||
// call the hook
|
||||
// Generates: OnValueChanged(oldValue, this.syncVar);
|
||||
syncVarAttributeProcessor.WriteCallHookMethodUsingField(worker, hookMethod, oldSyncVar, syncVar, ref WeavingFailed);
|
||||
|
||||
// Generates: end if (!SyncVarEqual);
|
||||
worker.Append(syncVarEqualLabel);
|
||||
worker.Emit(OpCodes.Call, weaverTypes.generatedSyncVarDeserialize_GameObject);
|
||||
}
|
||||
}
|
||||
else if (syncVar.FieldType.Is<NetworkIdentity>())
|
||||
{
|
||||
// reader
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
|
||||
// [SyncVar] int/float/struct/etc.?
|
||||
void DeserializeNormalField(FieldDefinition syncVar, ILProcessor serWorker, MethodDefinition deserialize, MethodDefinition hookMethod, ref bool WeavingFailed)
|
||||
{
|
||||
/*
|
||||
Generates code like:
|
||||
// for hook
|
||||
int oldValue = a;
|
||||
Networka = reader.ReadPackedInt32();
|
||||
if (!SyncVarEqual(oldValue, ref a))
|
||||
// NetworkIdentity deserialize needs one more parameter: netId field ref
|
||||
FieldDefinition netIdField = syncVarNetIds[syncVar];
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, netIdField);
|
||||
worker.Emit(OpCodes.Call, weaverTypes.generatedSyncVarDeserialize_NetworkIdentity);
|
||||
}
|
||||
// TODO this only uses the persistent netId for types DERIVED FROM NB.
|
||||
// not if the type is just 'NetworkBehaviour'.
|
||||
// this is what original implementation did too. fix it after.
|
||||
else if (syncVar.FieldType.IsDerivedFrom<NetworkBehaviour>())
|
||||
{
|
||||
// reader
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
|
||||
// NetworkIdentity deserialize needs one more parameter: netId field ref
|
||||
// (actually its a NetworkBehaviourSyncVar type)
|
||||
FieldDefinition netIdField = syncVarNetIds[syncVar];
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, netIdField);
|
||||
// make generic version of GeneratedSyncVarSetter_NetworkBehaviour<T>
|
||||
MethodReference getFunc = weaverTypes.generatedSyncVarDeserialize_NetworkBehaviour_T.MakeGeneric(assembly.MainModule, syncVar.FieldType);
|
||||
worker.Emit(OpCodes.Call, getFunc);
|
||||
}
|
||||
else
|
||||
{
|
||||
// T value = reader.ReadT();
|
||||
// this is still in IL because otherwise weaver generated
|
||||
// readers/writers don't seem to work in tests.
|
||||
// besides, this also avoids reader.Read<T> overhead.
|
||||
MethodReference readFunc = readers.GetReadFunc(syncVar.FieldType, ref WeavingFailed);
|
||||
if (readFunc == null)
|
||||
{
|
||||
OnSetA(oldValue, Networka);
|
||||
Log.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar);
|
||||
WeavingFailed = true;
|
||||
return;
|
||||
}
|
||||
*/
|
||||
// reader. for 'reader.Read()' below
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
// reader.Read()
|
||||
worker.Emit(OpCodes.Call, readFunc);
|
||||
|
||||
MethodReference readFunc = readers.GetReadFunc(syncVar.FieldType, ref WeavingFailed);
|
||||
if (readFunc == null)
|
||||
{
|
||||
Log.Error($"{syncVar.Name} has unsupported type. Use a supported Mirror type instead", syncVar);
|
||||
WeavingFailed = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// T oldValue = value;
|
||||
VariableDefinition oldValue = new VariableDefinition(syncVar.FieldType);
|
||||
deserialize.Body.Variables.Add(oldValue);
|
||||
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
|
||||
serWorker.Append(serWorker.Create(OpCodes.Ldfld, syncVar));
|
||||
serWorker.Append(serWorker.Create(OpCodes.Stloc, oldValue));
|
||||
|
||||
// read value and store in syncvar BEFORE calling the hook
|
||||
// -> this makes way more sense. by definition, the hook is
|
||||
// supposed to be called after it was changed. not before.
|
||||
// -> setting it BEFORE calling the hook fixes the following bug:
|
||||
// https://github.com/vis2k/Mirror/issues/1151 in host mode
|
||||
// where the value during the Hook call would call Cmds on
|
||||
// the host server, and they would all happen and compare
|
||||
// values BEFORE the hook even returned and hence BEFORE the
|
||||
// actual value was even set.
|
||||
// put 'this.' onto stack for 'this.syncvar' below
|
||||
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
|
||||
// reader. for 'reader.Read()' below
|
||||
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
|
||||
// reader.Read()
|
||||
serWorker.Append(serWorker.Create(OpCodes.Call, readFunc));
|
||||
// syncvar
|
||||
serWorker.Append(serWorker.Create(OpCodes.Stfld, syncVar));
|
||||
|
||||
if (hookMethod != null)
|
||||
{
|
||||
// call hook
|
||||
// but only if SyncVar changed. otherwise a client would
|
||||
// get hook calls for all initial values, even if they
|
||||
// didn't change from the default values on the client.
|
||||
// see also: https://github.com/vis2k/Mirror/issues/1278
|
||||
|
||||
// Generates: if (!SyncVarEqual);
|
||||
Instruction syncVarEqualLabel = serWorker.Create(OpCodes.Nop);
|
||||
|
||||
// NOTE: static function. don't Emit Ldarg_0 aka 'this'.
|
||||
|
||||
// 'oldValue'
|
||||
serWorker.Append(serWorker.Create(OpCodes.Ldloc, oldValue));
|
||||
// 'ref this.syncVar'
|
||||
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
|
||||
serWorker.Append(serWorker.Create(OpCodes.Ldflda, syncVar));
|
||||
// call the function
|
||||
GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(weaverTypes.syncVarEqualReference);
|
||||
syncVarEqualGm.GenericArguments.Add(syncVar.FieldType);
|
||||
serWorker.Append(serWorker.Create(OpCodes.Call, syncVarEqualGm));
|
||||
serWorker.Append(serWorker.Create(OpCodes.Brtrue, syncVarEqualLabel));
|
||||
|
||||
// call the hook
|
||||
// Generates: OnValueChanged(oldValue, this.syncVar);
|
||||
syncVarAttributeProcessor.WriteCallHookMethodUsingField(serWorker, hookMethod, oldValue, syncVar, ref WeavingFailed);
|
||||
|
||||
// Generates: end if (!SyncVarEqual);
|
||||
serWorker.Append(syncVarEqualLabel);
|
||||
// make generic version of GeneratedSyncVarDeserialize<T>
|
||||
MethodReference generic = weaverTypes.generatedSyncVarDeserialize.MakeGeneric(assembly.MainModule, syncVar.FieldType);
|
||||
worker.Emit(OpCodes.Call, generic);
|
||||
}
|
||||
}
|
||||
|
||||
@ -878,7 +674,7 @@ namespace Mirror.Weaver
|
||||
|
||||
foreach (FieldDefinition syncVar in syncVars)
|
||||
{
|
||||
DeserializeField(syncVar, serWorker, serialize, ref WeavingFailed);
|
||||
DeserializeField(syncVar, serWorker, ref WeavingFailed);
|
||||
}
|
||||
|
||||
serWorker.Append(serWorker.Create(OpCodes.Ret));
|
||||
@ -904,7 +700,7 @@ namespace Mirror.Weaver
|
||||
serWorker.Append(serWorker.Create(OpCodes.And));
|
||||
serWorker.Append(serWorker.Create(OpCodes.Brfalse, varLabel));
|
||||
|
||||
DeserializeField(syncVar, serWorker, serialize, ref WeavingFailed);
|
||||
DeserializeField(syncVar, serWorker, ref WeavingFailed);
|
||||
|
||||
serWorker.Append(varLabel);
|
||||
dirtyBit += 1;
|
||||
@ -1036,6 +832,14 @@ namespace Mirror.Weaver
|
||||
// validate parameters for a remote function call like Rpc/Cmd
|
||||
bool ValidateParameter(MethodReference method, ParameterDefinition param, RemoteCallType callType, bool firstParam, ref bool WeavingFailed)
|
||||
{
|
||||
// need to check this before any type lookups since those will fail since generic types don't resolve
|
||||
if (param.ParameterType.IsGenericParameter)
|
||||
{
|
||||
Log.Error($"{method.Name} cannot have generic parameters", method);
|
||||
WeavingFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isNetworkConnection = param.ParameterType.Is<NetworkConnection>();
|
||||
bool isSenderConnection = IsSenderConnection(param, callType);
|
||||
|
||||
|
@ -16,6 +16,12 @@ namespace Mirror.Weaver
|
||||
|
||||
foreach (FieldDefinition fd in td.Fields)
|
||||
{
|
||||
if (fd.FieldType.IsGenericParameter)
|
||||
{
|
||||
// can't call .Resolve on generic ones
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fd.FieldType.Resolve().IsDerivedFrom<SyncObject>())
|
||||
{
|
||||
if (fd.IsStatic)
|
||||
|
@ -46,6 +46,64 @@ namespace Mirror.Weaver
|
||||
return FindHookMethod(td, syncVar, hookFunctionName, ref WeavingFailed);
|
||||
}
|
||||
|
||||
// push hook from GetHookMethod() onto the stack as a new Action<T,T>.
|
||||
// allows for reuse without handling static/virtual cases every time.
|
||||
public void GenerateNewActionFromHookMethod(FieldDefinition syncVar, ILProcessor worker, MethodDefinition hookMethod)
|
||||
{
|
||||
// IL_000a: ldarg.0
|
||||
// IL_000b: ldftn instance void Mirror.Examples.Tanks.Tank::ExampleHook(int32, int32)
|
||||
// IL_0011: newobj instance void class [netstandard]System.Action`2<int32, int32>::.ctor(object, native int)
|
||||
|
||||
// we support static hook sand instance hooks.
|
||||
if (hookMethod.IsStatic)
|
||||
{
|
||||
// for static hooks, we need to push 'null' first.
|
||||
// we can't just push nothing.
|
||||
// stack would get out of balance because we already pushed
|
||||
// other stuff above.
|
||||
worker.Emit(OpCodes.Ldnull);
|
||||
}
|
||||
else
|
||||
{
|
||||
// for instance hooks, we need to push 'this.' first.
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
}
|
||||
|
||||
MethodReference hookMethodReference;
|
||||
// if the network behaviour class is generic, we need to make the method reference generic for correct IL
|
||||
if (hookMethod.DeclaringType.HasGenericParameters)
|
||||
{
|
||||
hookMethodReference = hookMethod.MakeHostInstanceGeneric(hookMethod.Module, hookMethod.DeclaringType.MakeGenericInstanceType(hookMethod.DeclaringType.GenericParameters.ToArray()));
|
||||
}
|
||||
else
|
||||
{
|
||||
hookMethodReference = hookMethod;
|
||||
}
|
||||
|
||||
// we support regular and virtual hook functions.
|
||||
if (hookMethod.IsVirtual)
|
||||
{
|
||||
// for virtual / overwritten hooks, we need different IL.
|
||||
// this is from simply testing Action = VirtualHook; in C#.
|
||||
worker.Emit(OpCodes.Dup);
|
||||
worker.Emit(OpCodes.Ldvirtftn, hookMethodReference);
|
||||
}
|
||||
else
|
||||
{
|
||||
worker.Emit(OpCodes.Ldftn, hookMethodReference);
|
||||
}
|
||||
|
||||
// call 'new Action<T,T>()' constructor to convert the function to an action
|
||||
// we need to make an instance of the generic Action<T,T>.
|
||||
//
|
||||
// TODO this allocates a new 'Action' for every SyncVar hook call.
|
||||
// we should allocate it once and store it somewhere in the future.
|
||||
// hooks are only called on the client though, so it's not too bad for now.
|
||||
TypeReference actionRef = assembly.MainModule.ImportReference(typeof(Action<,>));
|
||||
GenericInstanceType genericInstance = actionRef.MakeGenericInstanceType(syncVar.FieldType, syncVar.FieldType);
|
||||
worker.Emit(OpCodes.Newobj, weaverTypes.ActionT_T.MakeHostInstanceGeneric(assembly.MainModule, genericInstance));
|
||||
}
|
||||
|
||||
MethodDefinition FindHookMethod(TypeDefinition td, FieldDefinition syncVar, string hookFunctionName, ref bool WeavingFailed)
|
||||
{
|
||||
List<MethodDefinition> methods = td.GetMethods(hookFunctionName);
|
||||
@ -96,6 +154,29 @@ namespace Mirror.Weaver
|
||||
|
||||
ILProcessor worker = get.Body.GetILProcessor();
|
||||
|
||||
FieldReference fr;
|
||||
if (fd.DeclaringType.HasGenericParameters)
|
||||
{
|
||||
fr = fd.MakeHostInstanceGeneric();
|
||||
}
|
||||
else
|
||||
{
|
||||
fr = fd;
|
||||
}
|
||||
|
||||
FieldReference netIdFieldReference = null;
|
||||
if (netFieldId != null)
|
||||
{
|
||||
if (netFieldId.DeclaringType.HasGenericParameters)
|
||||
{
|
||||
netIdFieldReference = netFieldId.MakeHostInstanceGeneric();
|
||||
}
|
||||
else
|
||||
{
|
||||
netIdFieldReference = netFieldId;
|
||||
}
|
||||
}
|
||||
|
||||
// [SyncVar] GameObject?
|
||||
if (fd.FieldType.Is<UnityEngine.GameObject>())
|
||||
{
|
||||
@ -103,9 +184,9 @@ namespace Mirror.Weaver
|
||||
// this.
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, netFieldId);
|
||||
worker.Emit(OpCodes.Ldfld, netIdFieldReference);
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, fd);
|
||||
worker.Emit(OpCodes.Ldflda, fr);
|
||||
worker.Emit(OpCodes.Call, weaverTypes.getSyncVarGameObjectReference);
|
||||
worker.Emit(OpCodes.Ret);
|
||||
}
|
||||
@ -116,9 +197,9 @@ namespace Mirror.Weaver
|
||||
// this.
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, netFieldId);
|
||||
worker.Emit(OpCodes.Ldfld, netIdFieldReference);
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, fd);
|
||||
worker.Emit(OpCodes.Ldflda, fr);
|
||||
worker.Emit(OpCodes.Call, weaverTypes.getSyncVarNetworkIdentityReference);
|
||||
worker.Emit(OpCodes.Ret);
|
||||
}
|
||||
@ -128,9 +209,9 @@ namespace Mirror.Weaver
|
||||
// this.
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, netFieldId);
|
||||
worker.Emit(OpCodes.Ldfld, netIdFieldReference);
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, fd);
|
||||
worker.Emit(OpCodes.Ldflda, fr);
|
||||
MethodReference getFunc = weaverTypes.getSyncVarNetworkBehaviourReference.MakeGeneric(assembly.MainModule, fd.FieldType);
|
||||
worker.Emit(OpCodes.Call, getFunc);
|
||||
worker.Emit(OpCodes.Ret);
|
||||
@ -139,7 +220,7 @@ namespace Mirror.Weaver
|
||||
else
|
||||
{
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, fd);
|
||||
worker.Emit(OpCodes.Ldfld, fr);
|
||||
worker.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
@ -168,6 +249,28 @@ namespace Mirror.Weaver
|
||||
weaverTypes.Import(typeof(void)));
|
||||
|
||||
ILProcessor worker = set.Body.GetILProcessor();
|
||||
FieldReference fr;
|
||||
if (fd.DeclaringType.HasGenericParameters)
|
||||
{
|
||||
fr = fd.MakeHostInstanceGeneric();
|
||||
}
|
||||
else
|
||||
{
|
||||
fr = fd;
|
||||
}
|
||||
|
||||
FieldReference netIdFieldReference = null;
|
||||
if (netFieldId != null)
|
||||
{
|
||||
if (netFieldId.DeclaringType.HasGenericParameters)
|
||||
{
|
||||
netIdFieldReference = netFieldId.MakeHostInstanceGeneric();
|
||||
}
|
||||
else
|
||||
{
|
||||
netIdFieldReference = netFieldId;
|
||||
}
|
||||
}
|
||||
|
||||
// if (!SyncVarEqual(value, ref playerData))
|
||||
Instruction endOfMethod = worker.Create(OpCodes.Nop);
|
||||
@ -194,37 +297,22 @@ namespace Mirror.Weaver
|
||||
|
||||
// push 'ref T this.field'
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, fd);
|
||||
worker.Emit(OpCodes.Ldflda, fr);
|
||||
|
||||
// push the dirty bit for this SyncVar
|
||||
worker.Emit(OpCodes.Ldc_I8, dirtyBit);
|
||||
|
||||
// hook?
|
||||
// hook? then push 'new Action<T,T>(Hook)' onto stack
|
||||
MethodDefinition hookMethod = GetHookMethod(td, fd, ref WeavingFailed);
|
||||
if (hookMethod != null)
|
||||
{
|
||||
// IL_000a: ldarg.0
|
||||
// IL_000b: ldftn instance void Mirror.Examples.Tanks.Tank::ExampleHook(int32, int32)
|
||||
// IL_0011: newobj instance void class [netstandard]System.Action`2<int32, int32>::.ctor(object, native int)
|
||||
|
||||
// this.
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
|
||||
// the function
|
||||
worker.Emit(OpCodes.Ldftn, hookMethod);
|
||||
|
||||
// call 'new Action<T,T>()' constructor to convert the function to an action
|
||||
// we need to make an instance of the generic Action<T,T>.
|
||||
//
|
||||
// TODO this allocates a new 'Action' for every SyncVar hook call.
|
||||
// we should allocate it once and store it somewhere in the future.
|
||||
// hooks are only called on the client though, so it's not too bad for now.
|
||||
TypeReference actionRef = assembly.MainModule.ImportReference(typeof(Action<,>));
|
||||
GenericInstanceType genericInstance = actionRef.MakeGenericInstanceType(fd.FieldType, fd.FieldType);
|
||||
worker.Emit(OpCodes.Newobj, weaverTypes.ActionT_T.MakeHostInstanceGeneric(assembly.MainModule, genericInstance));
|
||||
GenerateNewActionFromHookMethod(fd, worker, hookMethod);
|
||||
}
|
||||
// otherwise push 'null' as hook
|
||||
else
|
||||
{
|
||||
worker.Emit(OpCodes.Ldnull);
|
||||
}
|
||||
// pass 'null' as hook
|
||||
else worker.Emit(OpCodes.Ldnull);
|
||||
|
||||
// call GeneratedSyncVarSetter<T>.
|
||||
// special cases for GameObject/NetworkIdentity/NetworkBehaviour
|
||||
@ -233,14 +321,14 @@ namespace Mirror.Weaver
|
||||
{
|
||||
// GameObject setter needs one more parameter: netId field ref
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, netFieldId);
|
||||
worker.Emit(OpCodes.Ldflda, netIdFieldReference);
|
||||
worker.Emit(OpCodes.Call, weaverTypes.generatedSyncVarSetter_GameObject);
|
||||
}
|
||||
else if (fd.FieldType.Is<NetworkIdentity>())
|
||||
{
|
||||
// NetworkIdentity setter needs one more parameter: netId field ref
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, netFieldId);
|
||||
worker.Emit(OpCodes.Ldflda, netIdFieldReference);
|
||||
worker.Emit(OpCodes.Call, weaverTypes.generatedSyncVarSetter_NetworkIdentity);
|
||||
}
|
||||
// TODO this only uses the persistent netId for types DERIVED FROM NB.
|
||||
@ -251,7 +339,7 @@ namespace Mirror.Weaver
|
||||
// NetworkIdentity setter needs one more parameter: netId field ref
|
||||
// (actually its a NetworkBehaviourSyncVar type)
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, netFieldId);
|
||||
worker.Emit(OpCodes.Ldflda, netIdFieldReference);
|
||||
// make generic version of GeneratedSyncVarSetter_NetworkBehaviour<T>
|
||||
MethodReference getFunc = weaverTypes.generatedSyncVarSetter_NetworkBehaviour_T.MakeGeneric(assembly.MainModule, fd.FieldType);
|
||||
worker.Emit(OpCodes.Call, getFunc);
|
||||
@ -283,16 +371,18 @@ namespace Mirror.Weaver
|
||||
if (fd.FieldType.IsDerivedFrom<NetworkBehaviour>())
|
||||
{
|
||||
netIdField = new FieldDefinition($"___{fd.Name}NetId",
|
||||
FieldAttributes.Private,
|
||||
FieldAttributes.Family, // needs to be protected for generic classes, otherwise access isn't allowed
|
||||
weaverTypes.Import<NetworkBehaviour.NetworkBehaviourSyncVar>());
|
||||
netIdField.DeclaringType = td;
|
||||
|
||||
syncVarNetIds[fd] = netIdField;
|
||||
}
|
||||
else if (fd.FieldType.IsNetworkIdentityField())
|
||||
{
|
||||
netIdField = new FieldDefinition($"___{fd.Name}NetId",
|
||||
FieldAttributes.Private,
|
||||
FieldAttributes.Family, // needs to be protected for generic classes, otherwise access isn't allowed
|
||||
weaverTypes.Import<uint>());
|
||||
netIdField.DeclaringType = td;
|
||||
|
||||
syncVarNetIds[fd] = netIdField;
|
||||
}
|
||||
@ -345,6 +435,13 @@ namespace Mirror.Weaver
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fd.FieldType.IsGenericParameter)
|
||||
{
|
||||
Log.Error($"{fd.Name} has generic type. Generic SyncVars are not supported", fd);
|
||||
WeavingFailed = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fd.FieldType.IsArray)
|
||||
{
|
||||
Log.Error($"{fd.Name} has invalid type. Use SyncLists instead of arrays", fd);
|
||||
@ -382,72 +479,5 @@ namespace Mirror.Weaver
|
||||
|
||||
return (syncVars, syncVarNetIds);
|
||||
}
|
||||
|
||||
public void WriteCallHookMethodUsingField(ILProcessor worker, MethodDefinition hookMethod, VariableDefinition oldValue, FieldDefinition newValue, ref bool WeavingFailed)
|
||||
{
|
||||
if (newValue == null)
|
||||
{
|
||||
Log.Error("NewValue field was null when writing SyncVar hook");
|
||||
WeavingFailed = true;
|
||||
}
|
||||
|
||||
WriteCallHookMethod(worker, hookMethod, oldValue, newValue);
|
||||
}
|
||||
|
||||
void WriteCallHookMethod(ILProcessor worker, MethodDefinition hookMethod, VariableDefinition oldValue, FieldDefinition newValue)
|
||||
{
|
||||
WriteStartFunctionCall();
|
||||
|
||||
// write args
|
||||
WriteOldValue();
|
||||
WriteNewValue();
|
||||
|
||||
WriteEndFunctionCall();
|
||||
|
||||
|
||||
// *** Local functions used to write OpCodes ***
|
||||
// Local functions have access to function variables, no need to pass in args
|
||||
|
||||
void WriteOldValue()
|
||||
{
|
||||
worker.Emit(OpCodes.Ldloc, oldValue);
|
||||
}
|
||||
|
||||
void WriteNewValue()
|
||||
{
|
||||
// write arg1 or this.field
|
||||
if (newValue == null)
|
||||
{
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// this.
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
// syncvar.get
|
||||
worker.Emit(OpCodes.Ldfld, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
// Writes this before method if it is not static
|
||||
void WriteStartFunctionCall()
|
||||
{
|
||||
// don't add this (Ldarg_0) if method is static
|
||||
if (!hookMethod.IsStatic)
|
||||
{
|
||||
// this before method call
|
||||
// e.g. this.onValueChanged
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
}
|
||||
}
|
||||
|
||||
// Calls method
|
||||
void WriteEndFunctionCall()
|
||||
{
|
||||
// only use Callvirt when not static
|
||||
OpCode opcode = hookMethod.IsStatic ? OpCodes.Call : OpCodes.Callvirt;
|
||||
worker.Emit(opcode, hookMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,16 +48,21 @@ namespace Mirror.Weaver
|
||||
{
|
||||
return null;
|
||||
}
|
||||
foreach (MethodDefinition methodRef in tr.Resolve().Methods)
|
||||
foreach (MethodDefinition methodDef in tr.Resolve().Methods)
|
||||
{
|
||||
if (methodRef.Name == name)
|
||||
if (methodDef.Name == name)
|
||||
{
|
||||
MethodReference methodRef = methodDef;
|
||||
if (tr.IsGenericInstance)
|
||||
{
|
||||
methodRef = methodRef.MakeHostInstanceGeneric(tr.Module, (GenericInstanceType)tr);
|
||||
}
|
||||
return assembly.MainModule.ImportReference(methodRef);
|
||||
}
|
||||
}
|
||||
|
||||
// Could not find the method in this class, try the parent
|
||||
return TryResolveMethodInParents(tr.Resolve().BaseType, assembly, name);
|
||||
return TryResolveMethodInParents(tr.Resolve().BaseType.ApplyGenericParameters(tr), assembly, name);
|
||||
}
|
||||
|
||||
public static MethodDefinition ResolveDefaultPublicCtor(TypeReference variable)
|
||||
|
@ -35,7 +35,10 @@ namespace Mirror.Weaver
|
||||
public MethodReference generatedSyncVarSetter_GameObject;
|
||||
public MethodReference generatedSyncVarSetter_NetworkIdentity;
|
||||
public MethodReference generatedSyncVarSetter_NetworkBehaviour_T;
|
||||
public MethodReference syncVarEqualReference;
|
||||
public MethodReference generatedSyncVarDeserialize;
|
||||
public MethodReference generatedSyncVarDeserialize_GameObject;
|
||||
public MethodReference generatedSyncVarDeserialize_NetworkIdentity;
|
||||
public MethodReference generatedSyncVarDeserialize_NetworkBehaviour_T;
|
||||
public MethodReference getSyncVarGameObjectReference;
|
||||
public MethodReference getSyncVarNetworkIdentityReference;
|
||||
public MethodReference getSyncVarNetworkBehaviourReference;
|
||||
@ -102,7 +105,10 @@ namespace Mirror.Weaver
|
||||
generatedSyncVarSetter_NetworkIdentity = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarSetter_NetworkIdentity", ref WeavingFailed);
|
||||
generatedSyncVarSetter_NetworkBehaviour_T = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarSetter_NetworkBehaviour", ref WeavingFailed);
|
||||
|
||||
syncVarEqualReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SyncVarEqual", ref WeavingFailed);
|
||||
generatedSyncVarDeserialize_GameObject = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarDeserialize_GameObject", ref WeavingFailed);
|
||||
generatedSyncVarDeserialize = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarDeserialize", ref WeavingFailed);
|
||||
generatedSyncVarDeserialize_NetworkIdentity = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarDeserialize_NetworkIdentity", ref WeavingFailed);
|
||||
generatedSyncVarDeserialize_NetworkBehaviour_T = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarDeserialize_NetworkBehaviour", ref WeavingFailed);
|
||||
|
||||
getSyncVarGameObjectReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GetSyncVarGameObject", ref WeavingFailed);
|
||||
getSyncVarNetworkIdentityReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GetSyncVarNetworkIdentity", ref WeavingFailed);
|
||||
|
Loading…
x
Reference in New Issue
Block a user