mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 02:50:32 +00:00
Weaver: move [SyncVar] generated setter to C# (#3070)
* WeaverSyncVarSetter<T> * resolve * no ref * rename * simple types without hook * hook WIP * stll need 'new Action' type * pass hook * ilnine * remove now unused types * remove unused * comment * no default * cases * GeneratedSyncVarSetter_GameObject/NetworkIdentity * resolve * GO/NI setters * use the right equals * NB setter * comment
This commit is contained in:
parent
48df9ec287
commit
5369b8f47c
@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Mono.CecilX;
|
||||
using Mono.CecilX.Cil;
|
||||
using Mono.CecilX.Rocks;
|
||||
|
||||
namespace Mirror.Weaver
|
||||
{
|
||||
@ -148,6 +150,15 @@ public MethodDefinition GenerateSyncVarGetter(FieldDefinition fd, string origina
|
||||
return get;
|
||||
}
|
||||
|
||||
// for [SyncVar] health, weaver generates
|
||||
//
|
||||
// NetworkHealth
|
||||
// {
|
||||
// get => health;
|
||||
// set => GeneratedSyncVarSetter(...)
|
||||
// }
|
||||
//
|
||||
// the setter used to be manually IL generated, but we moved it to C# :)
|
||||
public MethodDefinition GenerateSyncVarSetter(TypeDefinition td, FieldDefinition fd, string originalName, long dirtyBit, FieldDefinition netFieldId, ref bool WeavingFailed)
|
||||
{
|
||||
//Create the set method
|
||||
@ -164,135 +175,94 @@ public MethodDefinition GenerateSyncVarSetter(TypeDefinition td, FieldDefinition
|
||||
// NOTE: SyncVar...Equal functions are static.
|
||||
// don't Emit Ldarg_0 aka 'this'.
|
||||
|
||||
// new value to set
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
// call WeaverSyncVarSetter<T>(T value, ref T field, ulong dirtyBit, Action<T, T> OnChanged = null)
|
||||
// IL_0000: ldarg.0
|
||||
// IL_0001: ldarg.1
|
||||
// IL_0002: ldarg.0
|
||||
// IL_0003: ldflda int32 Mirror.Examples.Tanks.Tank::health
|
||||
// IL_0008: ldc.i4.1
|
||||
// IL_0009: conv.i8
|
||||
// IL_000a: ldnull
|
||||
// IL_000b: call instance void [Mirror]Mirror.NetworkBehaviour::GeneratedSyncVarSetter<int32>(!!0, !!0&, uint64, class [netstandard]System.Action`2<!!0, !!0>)
|
||||
// IL_0010: ret
|
||||
//
|
||||
// TODO GameObject/NetworkBehaviour special cases
|
||||
|
||||
// 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.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, netFieldId);
|
||||
|
||||
worker.Emit(OpCodes.Call, weaverTypes.syncVarGameObjectEqualReference);
|
||||
}
|
||||
else if (fd.FieldType.Is<NetworkIdentity>())
|
||||
{
|
||||
// reference to netId Field to set
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, netFieldId);
|
||||
|
||||
worker.Emit(OpCodes.Call, weaverTypes.syncVarNetworkIdentityEqualReference);
|
||||
}
|
||||
else if (fd.FieldType.IsDerivedFrom<NetworkBehaviour>())
|
||||
{
|
||||
// reference to netId Field to set
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, netFieldId);
|
||||
|
||||
MethodReference getFunc = weaverTypes.syncVarNetworkBehaviourEqualReference.MakeGeneric(assembly.MainModule, fd.FieldType);
|
||||
worker.Emit(OpCodes.Call, getFunc);
|
||||
}
|
||||
else
|
||||
{
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, fd);
|
||||
|
||||
GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(weaverTypes.syncVarEqualReference);
|
||||
syncVarEqualGm.GenericArguments.Add(fd.FieldType);
|
||||
worker.Emit(OpCodes.Call, syncVarEqualGm);
|
||||
}
|
||||
|
||||
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.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldfld, fd);
|
||||
worker.Emit(OpCodes.Stloc, oldValue);
|
||||
|
||||
// this
|
||||
// 'this.' for the call
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
|
||||
// new value to set
|
||||
// first push 'value'
|
||||
worker.Emit(OpCodes.Ldarg_1);
|
||||
|
||||
// reference to field to set
|
||||
// push 'ref T this.field'
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, fd);
|
||||
|
||||
// dirty bit
|
||||
// 8 byte integer aka long
|
||||
// push the dirty bit for this SyncVar
|
||||
worker.Emit(OpCodes.Ldc_I8, dirtyBit);
|
||||
|
||||
// hook?
|
||||
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));
|
||||
}
|
||||
// pass 'null' as hook
|
||||
else worker.Emit(OpCodes.Ldnull);
|
||||
|
||||
// call GeneratedSyncVarSetter<T>.
|
||||
// special cases for GameObject/NetworkIdentity/NetworkBehaviour
|
||||
// passing netId too for persistence.
|
||||
if (fd.FieldType.Is<UnityEngine.GameObject>())
|
||||
{
|
||||
// reference to netId Field to set
|
||||
// GameObject setter needs one more parameter: netId field ref
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, netFieldId);
|
||||
|
||||
worker.Emit(OpCodes.Call, weaverTypes.setSyncVarGameObjectReference);
|
||||
worker.Emit(OpCodes.Call, weaverTypes.generatedSyncVarSetter_GameObject);
|
||||
}
|
||||
else if (fd.FieldType.Is<NetworkIdentity>())
|
||||
{
|
||||
// reference to netId Field to set
|
||||
// NetworkIdentity setter needs one more parameter: netId field ref
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, netFieldId);
|
||||
|
||||
worker.Emit(OpCodes.Call, weaverTypes.setSyncVarNetworkIdentityReference);
|
||||
worker.Emit(OpCodes.Call, weaverTypes.generatedSyncVarSetter_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 (fd.FieldType.IsDerivedFrom<NetworkBehaviour>())
|
||||
{
|
||||
// reference to netId Field to set
|
||||
// NetworkIdentity setter needs one more parameter: netId field ref
|
||||
// (actually its a NetworkBehaviourSyncVar type)
|
||||
worker.Emit(OpCodes.Ldarg_0);
|
||||
worker.Emit(OpCodes.Ldflda, netFieldId);
|
||||
|
||||
MethodReference getFunc = weaverTypes.setSyncVarNetworkBehaviourReference.MakeGeneric(assembly.MainModule, fd.FieldType);
|
||||
// make generic version of GeneratedSyncVarSetter_NetworkBehaviour<T>
|
||||
MethodReference getFunc = weaverTypes.generatedSyncVarSetter_NetworkBehaviour_T.MakeGeneric(assembly.MainModule, fd.FieldType);
|
||||
worker.Emit(OpCodes.Call, getFunc);
|
||||
}
|
||||
else
|
||||
{
|
||||
// make generic version of SetSyncVar with field type
|
||||
GenericInstanceMethod gm = new GenericInstanceMethod(weaverTypes.setSyncVarReference);
|
||||
gm.GenericArguments.Add(fd.FieldType);
|
||||
|
||||
// invoke SetSyncVar
|
||||
worker.Emit(OpCodes.Call, gm);
|
||||
}
|
||||
|
||||
MethodDefinition hookMethod = GetHookMethod(td, fd, ref WeavingFailed);
|
||||
|
||||
if (hookMethod != null)
|
||||
{
|
||||
//if (NetworkServer.localClientActive && !getSyncVarHookGuard(dirtyBit))
|
||||
Instruction label = worker.Create(OpCodes.Nop);
|
||||
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.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.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);
|
||||
// make generic version of GeneratedSyncVarSetter<T>
|
||||
MethodReference generic = weaverTypes.generatedSyncVarSetter.MakeGeneric(assembly.MainModule, fd.FieldType);
|
||||
worker.Emit(OpCodes.Call, generic);
|
||||
}
|
||||
|
||||
worker.Append(endOfMethod);
|
||||
@ -415,11 +385,6 @@ public void ProcessSyncVar(TypeDefinition td, FieldDefinition fd, Dictionary<Fie
|
||||
return (syncVars, syncVarNetIds);
|
||||
}
|
||||
|
||||
public void WriteCallHookMethodUsingArgument(ILProcessor worker, MethodDefinition hookMethod, VariableDefinition oldValue)
|
||||
{
|
||||
WriteCallHookMethod(worker, hookMethod, oldValue, null);
|
||||
}
|
||||
|
||||
public void WriteCallHookMethodUsingField(ILProcessor worker, MethodDefinition hookMethod, VariableDefinition oldValue, FieldDefinition newValue, ref bool WeavingFailed)
|
||||
{
|
||||
if (newValue == null)
|
||||
|
@ -19,7 +19,6 @@ public class WeaverTypes
|
||||
public MethodReference RemoteCallDelegateConstructor;
|
||||
|
||||
public MethodReference NetworkServerGetActive;
|
||||
public MethodReference NetworkServerGetLocalClientActive;
|
||||
public MethodReference NetworkClientGetActive;
|
||||
|
||||
// custom attribute types
|
||||
@ -28,19 +27,17 @@ public class WeaverTypes
|
||||
// array segment
|
||||
public MethodReference ArraySegmentConstructorReference;
|
||||
|
||||
// Action<T,T> for SyncVar Hooks
|
||||
public MethodReference ActionT_T;
|
||||
|
||||
// syncvar
|
||||
public MethodReference generatedSyncVarSetter;
|
||||
public MethodReference generatedSyncVarSetter_GameObject;
|
||||
public MethodReference generatedSyncVarSetter_NetworkIdentity;
|
||||
public MethodReference generatedSyncVarSetter_NetworkBehaviour_T;
|
||||
public MethodReference syncVarEqualReference;
|
||||
public MethodReference syncVarNetworkIdentityEqualReference;
|
||||
public MethodReference syncVarGameObjectEqualReference;
|
||||
public MethodReference setSyncVarReference;
|
||||
public MethodReference setSyncVarHookGuard;
|
||||
public MethodReference getSyncVarHookGuard;
|
||||
public MethodReference setSyncVarGameObjectReference;
|
||||
public MethodReference getSyncVarGameObjectReference;
|
||||
public MethodReference setSyncVarNetworkIdentityReference;
|
||||
public MethodReference getSyncVarNetworkIdentityReference;
|
||||
public MethodReference syncVarNetworkBehaviourEqualReference;
|
||||
public MethodReference setSyncVarNetworkBehaviourReference;
|
||||
public MethodReference getSyncVarNetworkBehaviourReference;
|
||||
public MethodReference registerCommandReference;
|
||||
public MethodReference registerRpcReference;
|
||||
@ -72,9 +69,11 @@ public WeaverTypes(AssemblyDefinition assembly, Logger Log, ref bool WeavingFail
|
||||
TypeReference ArraySegmentType = Import(typeof(ArraySegment<>));
|
||||
ArraySegmentConstructorReference = Resolvers.ResolveMethod(ArraySegmentType, assembly, Log, ".ctor", ref WeavingFailed);
|
||||
|
||||
TypeReference ActionType = Import(typeof(Action<,>));
|
||||
ActionT_T = Resolvers.ResolveMethod(ActionType, assembly, Log, ".ctor", ref WeavingFailed);
|
||||
|
||||
TypeReference NetworkServerType = Import(typeof(NetworkServer));
|
||||
NetworkServerGetActive = Resolvers.ResolveMethod(NetworkServerType, assembly, Log, "get_active", ref WeavingFailed);
|
||||
NetworkServerGetLocalClientActive = Resolvers.ResolveMethod(NetworkServerType, assembly, Log, "get_localClientActive", ref WeavingFailed);
|
||||
TypeReference NetworkClientType = Import(typeof(NetworkClient));
|
||||
NetworkClientGetActive = Resolvers.ResolveMethod(NetworkClientType, assembly, Log, "get_active", ref WeavingFailed);
|
||||
|
||||
@ -98,19 +97,15 @@ public WeaverTypes(AssemblyDefinition assembly, Logger Log, ref bool WeavingFail
|
||||
|
||||
NetworkClientConnectionReference = Resolvers.ResolveMethod(NetworkClientType, assembly, Log, "get_connection", ref WeavingFailed);
|
||||
|
||||
syncVarEqualReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SyncVarEqual", ref WeavingFailed);
|
||||
syncVarNetworkIdentityEqualReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SyncVarNetworkIdentityEqual", ref WeavingFailed);
|
||||
syncVarGameObjectEqualReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SyncVarGameObjectEqual", ref WeavingFailed);
|
||||
setSyncVarReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SetSyncVar", ref WeavingFailed);
|
||||
setSyncVarHookGuard = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SetSyncVarHookGuard", ref WeavingFailed);
|
||||
getSyncVarHookGuard = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GetSyncVarHookGuard", ref WeavingFailed);
|
||||
generatedSyncVarSetter = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarSetter", ref WeavingFailed);
|
||||
generatedSyncVarSetter_GameObject = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GeneratedSyncVarSetter_GameObject", ref WeavingFailed);
|
||||
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);
|
||||
|
||||
setSyncVarGameObjectReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SetSyncVarGameObject", ref WeavingFailed);
|
||||
getSyncVarGameObjectReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GetSyncVarGameObject", ref WeavingFailed);
|
||||
setSyncVarNetworkIdentityReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SetSyncVarNetworkIdentity", ref WeavingFailed);
|
||||
getSyncVarNetworkIdentityReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GetSyncVarNetworkIdentity", ref WeavingFailed);
|
||||
syncVarNetworkBehaviourEqualReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SyncVarNetworkBehaviourEqual", ref WeavingFailed);
|
||||
setSyncVarNetworkBehaviourReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "SetSyncVarNetworkBehaviour", ref WeavingFailed);
|
||||
getSyncVarNetworkBehaviourReference = Resolvers.ResolveMethod(NetworkBehaviourType, assembly, Log, "GetSyncVarNetworkBehaviour", ref WeavingFailed);
|
||||
|
||||
registerCommandReference = Resolvers.ResolveMethod(RemoteProcedureCallsType, assembly, Log, "RegisterCommand", ref WeavingFailed);
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Mirror
|
||||
@ -326,6 +327,131 @@ protected void SendTargetRPCInternal(NetworkConnection conn, string functionFull
|
||||
conn.Send(message, channelId);
|
||||
}
|
||||
|
||||
// move the [SyncVar] generated property's .set into C# to avoid much IL
|
||||
//
|
||||
// public int health = 42;
|
||||
//
|
||||
// public int Networkhealth
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// return health;
|
||||
// }
|
||||
// [param: In]
|
||||
// set
|
||||
// {
|
||||
// if (!NetworkBehaviour.SyncVarEqual(value, ref health))
|
||||
// {
|
||||
// int oldValue = health;
|
||||
// SetSyncVar(value, ref health, 1uL);
|
||||
// if (NetworkServer.localClientActive && !GetSyncVarHookGuard(1uL))
|
||||
// {
|
||||
// SetSyncVarHookGuard(1uL, value: true);
|
||||
// OnChanged(oldValue, value);
|
||||
// SetSyncVarHookGuard(1uL, value: false);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void GeneratedSyncVarSetter<T>(T value, ref T field, ulong dirtyBit, Action<T, T> OnChanged)
|
||||
{
|
||||
if (!SyncVarEqual(value, ref field))
|
||||
{
|
||||
T oldValue = field;
|
||||
SetSyncVar(value, ref field, dirtyBit);
|
||||
|
||||
// call hook (if any)
|
||||
if (OnChanged != null)
|
||||
{
|
||||
// we use hook guard to protect against deadlock where hook
|
||||
// changes syncvar, calling hook again.
|
||||
if (NetworkServer.localClientActive && !GetSyncVarHookGuard(dirtyBit))
|
||||
{
|
||||
SetSyncVarHookGuard(dirtyBit, true);
|
||||
OnChanged(oldValue, value);
|
||||
SetSyncVarHookGuard(dirtyBit, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GameObject needs custom handling for persistence via netId.
|
||||
// has one extra parameter.
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void GeneratedSyncVarSetter_GameObject(GameObject value, ref GameObject field, ulong dirtyBit, Action<GameObject, GameObject> OnChanged, ref uint netIdField)
|
||||
{
|
||||
if (!SyncVarGameObjectEqual(value, netIdField))
|
||||
{
|
||||
GameObject oldValue = field;
|
||||
SetSyncVarGameObject(value, ref field, dirtyBit, ref netIdField);
|
||||
|
||||
// call hook (if any)
|
||||
if (OnChanged != null)
|
||||
{
|
||||
// we use hook guard to protect against deadlock where hook
|
||||
// changes syncvar, calling hook again.
|
||||
if (NetworkServer.localClientActive && !GetSyncVarHookGuard(dirtyBit))
|
||||
{
|
||||
SetSyncVarHookGuard(dirtyBit, true);
|
||||
OnChanged(oldValue, value);
|
||||
SetSyncVarHookGuard(dirtyBit, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NetworkIdentity needs custom handling for persistence via netId.
|
||||
// has one extra parameter.
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void GeneratedSyncVarSetter_NetworkIdentity(NetworkIdentity value, ref NetworkIdentity field, ulong dirtyBit, Action<NetworkIdentity, NetworkIdentity> OnChanged, ref uint netIdField)
|
||||
{
|
||||
if (!SyncVarNetworkIdentityEqual(value, netIdField))
|
||||
{
|
||||
NetworkIdentity oldValue = field;
|
||||
SetSyncVarNetworkIdentity(value, ref field, dirtyBit, ref netIdField);
|
||||
|
||||
// call hook (if any)
|
||||
if (OnChanged != null)
|
||||
{
|
||||
// we use hook guard to protect against deadlock where hook
|
||||
// changes syncvar, calling hook again.
|
||||
if (NetworkServer.localClientActive && !GetSyncVarHookGuard(dirtyBit))
|
||||
{
|
||||
SetSyncVarHookGuard(dirtyBit, true);
|
||||
OnChanged(oldValue, value);
|
||||
SetSyncVarHookGuard(dirtyBit, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NetworkBehaviour needs custom handling for persistence via netId.
|
||||
// has one extra parameter.
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void GeneratedSyncVarSetter_NetworkBehaviour<T>(T value, ref T field, ulong dirtyBit, Action<T, T> OnChanged, ref NetworkBehaviourSyncVar netIdField)
|
||||
where T : NetworkBehaviour
|
||||
{
|
||||
if (!SyncVarNetworkBehaviourEqual(value, netIdField))
|
||||
{
|
||||
T oldValue = field;
|
||||
SetSyncVarNetworkBehaviour(value, ref field, dirtyBit, ref netIdField);
|
||||
|
||||
// call hook (if any)
|
||||
if (OnChanged != null)
|
||||
{
|
||||
// we use hook guard to protect against deadlock where hook
|
||||
// changes syncvar, calling hook again.
|
||||
if (NetworkServer.localClientActive && !GetSyncVarHookGuard(dirtyBit))
|
||||
{
|
||||
SetSyncVarHookGuard(dirtyBit, true);
|
||||
OnChanged(oldValue, value);
|
||||
SetSyncVarHookGuard(dirtyBit, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// helper function for [SyncVar] GameObjects.
|
||||
// needs to be public so that tests & NetworkBehaviours from other
|
||||
// assemblies both find it
|
||||
|
Loading…
Reference in New Issue
Block a user