mirror of
https://github.com/MirrorNetworking/Mirror.git
synced 2024-11-18 02:50:32 +00:00
* fix * Test file * Syntax * NetworkBehaviour.Set/GetSyncVarNetworkIdentity functions added * add definitions to weaver * Use them * add NetworkIdentity cases everywhere else too * ProcessInstructionSetter/GetterField replaces for OnDeserialize too, so that [SyncVar]GameObjects/NetworkIdentities work with custom On(De)Serialize as well * Custom on(De)serialize test * Weaver.ProcessSiteMethod doesn't ignore OnDeserialize anymore either * [SyncVar] GameObject/NetworkIdentity hooks work again * testscene * public gameobject field test * pass gameobject field to getsyncvargameobject etc. * GetSyncVarGameObject/NetworkIdentity always returns the field if server, looks up netId otherwise; functions aren't static anymore. * Use original OnSerialize generation again, so it simply calls writer.Write(go) on server, which sends the netId internally anyway. * fixed hooks not using 'this.' because getter function isn't static anymore. * add scene referencing test * remove tests
This commit is contained in:
parent
3c0ff33c94
commit
43baeff444
@ -276,39 +276,99 @@ internal bool InvokeHandlerDelegate(int cmdHash, UNetInvokeType invokeType, Netw
|
|||||||
|
|
||||||
// ----------------------------- Helpers --------------------------------
|
// ----------------------------- Helpers --------------------------------
|
||||||
|
|
||||||
|
// helper function for [SyncVar] GameObjects.
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
protected void SetSyncVarGameObject(GameObject newGameObject, ref GameObject gameObjectField, ulong dirtyBit, ref uint netIdField)
|
protected void SetSyncVarGameObject(GameObject newGameObject, ref GameObject gameObjectField, ulong dirtyBit, ref uint netIdField)
|
||||||
{
|
{
|
||||||
if (m_SyncVarGuard)
|
if (m_SyncVarGuard)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint newGameObjectNetId = 0;
|
uint newNetId = 0;
|
||||||
if (newGameObject != null)
|
if (newGameObject != null)
|
||||||
{
|
{
|
||||||
NetworkIdentity identity = newGameObject.GetComponent<NetworkIdentity>();
|
NetworkIdentity identity = newGameObject.GetComponent<NetworkIdentity>();
|
||||||
if (identity != null)
|
if (identity != null)
|
||||||
{
|
{
|
||||||
newGameObjectNetId = identity.netId;
|
newNetId = identity.netId;
|
||||||
if (newGameObjectNetId == 0)
|
if (newNetId == 0)
|
||||||
{
|
{
|
||||||
Debug.LogWarning("SetSyncVarGameObject GameObject " + newGameObject + " has a zero netId. Maybe it is not spawned yet?");
|
Debug.LogWarning("SetSyncVarGameObject GameObject " + newGameObject + " has a zero netId. Maybe it is not spawned yet?");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint oldGameObjectNetId = 0;
|
// netId changed?
|
||||||
if (gameObjectField != null)
|
if (newNetId != netIdField)
|
||||||
{
|
{
|
||||||
oldGameObjectNetId = gameObjectField.GetComponent<NetworkIdentity>().netId;
|
if (LogFilter.Debug) { Debug.Log("SetSyncVar GameObject " + GetType().Name + " bit [" + dirtyBit + "] netfieldId:" + netIdField + "->" + newNetId); }
|
||||||
|
SetDirtyBit(dirtyBit);
|
||||||
|
gameObjectField = newGameObject; // assign new one on the server, and in case we ever need it on client too
|
||||||
|
netIdField = newNetId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function for [SyncVar] GameObjects.
|
||||||
|
// -> ref GameObject as second argument makes OnDeserialize processing easier
|
||||||
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
|
protected GameObject GetSyncVarGameObject(uint netId, ref GameObject gameObjectField)
|
||||||
|
{
|
||||||
|
// server always uses the field
|
||||||
|
if (isServer)
|
||||||
|
{
|
||||||
|
return gameObjectField;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newGameObjectNetId != oldGameObjectNetId)
|
// client always looks up based on netId because objects might get in and out of range
|
||||||
|
// over and over again, which shouldn't null them forever
|
||||||
|
NetworkIdentity identity;
|
||||||
|
if (NetworkIdentity.spawned.TryGetValue(netId, out identity) && identity != null)
|
||||||
|
return identity.gameObject;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function for [SyncVar] NetworkIdentities.
|
||||||
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
|
protected void SetSyncVarNetworkIdentity(NetworkIdentity newIdentity, ref NetworkIdentity identityField, ulong dirtyBit, ref uint netIdField)
|
||||||
|
{
|
||||||
|
if (m_SyncVarGuard)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint newNetId = 0;
|
||||||
|
if (newIdentity != null)
|
||||||
{
|
{
|
||||||
if (LogFilter.Debug) { Debug.Log("SetSyncVar GameObject " + GetType().Name + " bit [" + dirtyBit + "] netfieldId:" + oldGameObjectNetId + "->" + newGameObjectNetId); }
|
newNetId = newIdentity.netId;
|
||||||
SetDirtyBit(dirtyBit);
|
if (newNetId == 0)
|
||||||
gameObjectField = newGameObject;
|
{
|
||||||
netIdField = newGameObjectNetId;
|
Debug.LogWarning("SetSyncVarNetworkIdentity NetworkIdentity " + newIdentity + " has a zero netId. Maybe it is not spawned yet?");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// netId changed?
|
||||||
|
if (newNetId != netIdField)
|
||||||
|
{
|
||||||
|
if (LogFilter.Debug) { Debug.Log("SetSyncVarNetworkIdentity NetworkIdentity " + GetType().Name + " bit [" + dirtyBit + "] netIdField:" + netIdField + "->" + newNetId); }
|
||||||
|
SetDirtyBit(dirtyBit);
|
||||||
|
netIdField = newNetId;
|
||||||
|
identityField = newIdentity; // assign new one on the server, and in case we ever need it on client too
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// helper function for [SyncVar] NetworkIdentities.
|
||||||
|
// -> ref GameObject as second argument makes OnDeserialize processing easier
|
||||||
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
|
protected NetworkIdentity GetSyncVarNetworkIdentity(uint netId, ref NetworkIdentity identityField)
|
||||||
|
{
|
||||||
|
// server always uses the field
|
||||||
|
if (isServer)
|
||||||
|
{
|
||||||
|
return identityField;
|
||||||
|
}
|
||||||
|
|
||||||
|
// client always looks up based on netId because objects might get in and out of range
|
||||||
|
// over and over again, which shouldn't null them forever
|
||||||
|
NetworkIdentity identity;
|
||||||
|
NetworkIdentity.spawned.TryGetValue(netId, out identity);
|
||||||
|
return identity;
|
||||||
}
|
}
|
||||||
|
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
@ -440,7 +500,6 @@ private void DeSerializeObjectsDelta(NetworkReader reader)
|
|||||||
}
|
}
|
||||||
|
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
public virtual void PreStartClient() {}
|
|
||||||
public virtual void OnNetworkDestroy() {}
|
public virtual void OnNetworkDestroy() {}
|
||||||
public virtual void OnStartServer() {}
|
public virtual void OnStartServer() {}
|
||||||
public virtual void OnStartClient() {}
|
public virtual void OnStartClient() {}
|
||||||
|
@ -363,7 +363,6 @@ internal void OnStartClient()
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
comp.PreStartClient(); // generated startup to resolve object references
|
|
||||||
comp.OnStartClient(); // user implemented startup
|
comp.OnStartClient(); // user implemented startup
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -63,7 +63,6 @@ public void Process()
|
|||||||
}
|
}
|
||||||
|
|
||||||
GenerateDeSerialization();
|
GenerateDeSerialization();
|
||||||
GeneratePreStartClient();
|
|
||||||
Weaver.DLog(m_td, "Process Done");
|
Weaver.DLog(m_td, "Process Done");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -447,66 +446,9 @@ public static int GetChannelId(CustomAttribute ca)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GeneratePreStartClient()
|
|
||||||
{
|
|
||||||
int netIdFieldCounter = 0;
|
|
||||||
MethodDefinition preStartMethod = null;
|
|
||||||
ILProcessor serWorker = null;
|
|
||||||
|
|
||||||
foreach (var m in m_td.Methods)
|
|
||||||
{
|
|
||||||
if (m.Name == "PreStartClient")
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (FieldDefinition syncVar in m_SyncVars)
|
|
||||||
{
|
|
||||||
if (syncVar.FieldType.FullName == Weaver.gameObjectType.FullName)
|
|
||||||
{
|
|
||||||
if (preStartMethod == null)
|
|
||||||
{
|
|
||||||
preStartMethod = new MethodDefinition("PreStartClient", MethodAttributes.Public |
|
|
||||||
MethodAttributes.Virtual |
|
|
||||||
MethodAttributes.HideBySig,
|
|
||||||
Weaver.voidType);
|
|
||||||
|
|
||||||
serWorker = preStartMethod.Body.GetILProcessor();
|
|
||||||
}
|
|
||||||
|
|
||||||
FieldDefinition netIdField = m_SyncVarNetIds[netIdFieldCounter];
|
|
||||||
netIdFieldCounter += 1;
|
|
||||||
|
|
||||||
// Generates: if (!_crateNetId.IsEmpty()) { crate = ClientScene.FindLocalObject(_crateNetId); }
|
|
||||||
Instruction nullLabel = serWorker.Create(OpCodes.Nop);
|
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
|
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Ldfld, netIdField));
|
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Ldc_I4_0));
|
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Ceq));
|
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Brtrue, nullLabel));
|
|
||||||
|
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
|
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
|
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Ldfld, netIdField));
|
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Call, Weaver.FindLocalObjectReference));
|
|
||||||
|
|
||||||
// return value of FindLocalObjectReference is on stack, assign it to the syncvar
|
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Stfld, syncVar));
|
|
||||||
|
|
||||||
// Generates: end crateNetId != 0
|
|
||||||
serWorker.Append(nullLabel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (preStartMethod != null)
|
|
||||||
{
|
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Ret));
|
|
||||||
m_td.Methods.Add(preStartMethod);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GenerateDeSerialization()
|
void GenerateDeSerialization()
|
||||||
{
|
{
|
||||||
Weaver.DLog(m_td, " GenerateDeSerialization");
|
Weaver.DLog(m_td, " GenerateDeSerialization");
|
||||||
int netIdFieldCounter = 0;
|
|
||||||
|
|
||||||
foreach (var m in m_td.Methods)
|
foreach (var m in m_td.Methods)
|
||||||
{
|
{
|
||||||
@ -544,15 +486,21 @@ void GenerateDeSerialization()
|
|||||||
serWorker.Append(serWorker.Create(OpCodes.Ldarg_2));
|
serWorker.Append(serWorker.Create(OpCodes.Ldarg_2));
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Brfalse, initialStateLabel));
|
serWorker.Append(serWorker.Create(OpCodes.Brfalse, initialStateLabel));
|
||||||
|
|
||||||
|
int netIdFieldCounter = 0;
|
||||||
foreach (var syncVar in m_SyncVars)
|
foreach (var syncVar in m_SyncVars)
|
||||||
{
|
{
|
||||||
// assign value
|
// assign value
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
|
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
|
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
|
||||||
|
|
||||||
if (syncVar.FieldType.FullName == Weaver.gameObjectType.FullName)
|
if (syncVar.FieldType.FullName == Weaver.gameObjectType.FullName ||
|
||||||
|
syncVar.FieldType.FullName == Weaver.NetworkIdentityType.FullName)
|
||||||
{
|
{
|
||||||
// GameObject SyncVar - assign to generated netId var
|
// 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 = m_SyncVarNetIds[netIdFieldCounter];
|
FieldDefinition netIdField = m_SyncVarNetIds[netIdFieldCounter];
|
||||||
netIdFieldCounter += 1;
|
netIdFieldCounter += 1;
|
||||||
|
|
||||||
@ -592,6 +540,7 @@ void GenerateDeSerialization()
|
|||||||
serWorker.Append(serWorker.Create(OpCodes.Stloc_0));
|
serWorker.Append(serWorker.Create(OpCodes.Stloc_0));
|
||||||
|
|
||||||
// conditionally read each syncvar
|
// conditionally read each syncvar
|
||||||
|
netIdFieldCounter = 0; // reset
|
||||||
int dirtyBit = Weaver.GetSyncVarStart(m_td.BaseType.FullName); // start at number of syncvars in parent
|
int dirtyBit = Weaver.GetSyncVarStart(m_td.BaseType.FullName); // start at number of syncvars in parent
|
||||||
foreach (FieldDefinition syncVar in m_SyncVars)
|
foreach (FieldDefinition syncVar in m_SyncVars)
|
||||||
{
|
{
|
||||||
@ -603,14 +552,6 @@ void GenerateDeSerialization()
|
|||||||
serWorker.Append(serWorker.Create(OpCodes.And));
|
serWorker.Append(serWorker.Create(OpCodes.And));
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Brfalse, varLabel));
|
serWorker.Append(serWorker.Create(OpCodes.Brfalse, varLabel));
|
||||||
|
|
||||||
MethodReference readFunc = Weaver.GetReadFunc(syncVar.FieldType);
|
|
||||||
if (readFunc == null)
|
|
||||||
{
|
|
||||||
Log.Error("GenerateDeSerialization for " + m_td.Name + " unknown type [" + syncVar.FieldType + "]. UNet [SyncVar] member variables must be basic types.");
|
|
||||||
Weaver.fail = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for Hook function
|
// check for Hook function
|
||||||
MethodDefinition foundMethod;
|
MethodDefinition foundMethod;
|
||||||
if (!SyncVarProcessor.CheckForHookFunction(m_td, syncVar, out foundMethod))
|
if (!SyncVarProcessor.CheckForHookFunction(m_td, syncVar, out foundMethod))
|
||||||
@ -618,21 +559,67 @@ void GenerateDeSerialization()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (foundMethod == null)
|
if (syncVar.FieldType.FullName == Weaver.gameObjectType.FullName ||
|
||||||
|
syncVar.FieldType.FullName == Weaver.NetworkIdentityType.FullName)
|
||||||
{
|
{
|
||||||
// just assign value
|
// GameObject/NetworkIdentity SyncVar:
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
|
// OnSerialize sends writer.Write(go);
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
|
// OnDeserialize reads to __netId manually so we can use
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Call, readFunc));
|
// lookups in the getter (so it still works if objects
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Stfld, syncVar));
|
// move in and out of range repeatedly)
|
||||||
|
FieldDefinition netIdField = m_SyncVarNetIds[netIdFieldCounter];
|
||||||
|
netIdFieldCounter += 1;
|
||||||
|
|
||||||
|
if (foundMethod == null)
|
||||||
|
{
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Callvirt, Weaver.NetworkReaderReadPacked32));
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Stfld, netIdField));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// call Hook(this.GetSyncVarGameObject/NetworkIdentity(reader.ReadPackedUInt32()))
|
||||||
|
// because we send/receive the netID, not the GameObject/NetworkIdentity
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); // this.
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Callvirt, Weaver.NetworkReaderReadPacked32));
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Ldflda, syncVar));
|
||||||
|
if (syncVar.FieldType.FullName == Weaver.gameObjectType.FullName)
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Callvirt, Weaver.getSyncVarGameObjectReference));
|
||||||
|
else if (syncVar.FieldType.FullName == Weaver.NetworkIdentityType.FullName)
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Callvirt, Weaver.getSyncVarNetworkIdentityReference));
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Call, foundMethod));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// call hook instead
|
MethodReference readFunc = Weaver.GetReadFunc(syncVar.FieldType);
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
|
if (readFunc == null)
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
|
{
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Call, readFunc));
|
Log.Error("GenerateDeSerialization for " + m_td.Name + " unknown type [" + syncVar.FieldType + "]. UNet [SyncVar] member variables must be basic types.");
|
||||||
serWorker.Append(serWorker.Create(OpCodes.Call, foundMethod));
|
Weaver.fail = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (foundMethod == null)
|
||||||
|
{
|
||||||
|
// just assign value
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Call, readFunc));
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Stfld, syncVar));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// call hook instead
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Ldarg_1));
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Call, readFunc));
|
||||||
|
serWorker.Append(serWorker.Create(OpCodes.Call, foundMethod));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
serWorker.Append(varLabel);
|
serWorker.Append(varLabel);
|
||||||
dirtyBit += 1;
|
dirtyBit += 1;
|
||||||
|
@ -53,7 +53,7 @@ public static bool CheckForHookFunction(TypeDefinition td, FieldDefinition syncV
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MethodDefinition ProcessSyncVarGet(FieldDefinition fd, string originalName)
|
public static MethodDefinition ProcessSyncVarGet(FieldDefinition fd, string originalName, FieldDefinition netFieldId)
|
||||||
{
|
{
|
||||||
//Create the get method
|
//Create the get method
|
||||||
MethodDefinition get = new MethodDefinition(
|
MethodDefinition get = new MethodDefinition(
|
||||||
@ -64,9 +64,37 @@ public static MethodDefinition ProcessSyncVarGet(FieldDefinition fd, string orig
|
|||||||
|
|
||||||
ILProcessor getWorker = get.Body.GetILProcessor();
|
ILProcessor getWorker = get.Body.GetILProcessor();
|
||||||
|
|
||||||
getWorker.Append(getWorker.Create(OpCodes.Ldarg_0));
|
// [SyncVar] GameObject?
|
||||||
getWorker.Append(getWorker.Create(OpCodes.Ldfld, fd));
|
if (fd.FieldType.FullName == Weaver.gameObjectType.FullName)
|
||||||
getWorker.Append(getWorker.Create(OpCodes.Ret));
|
{
|
||||||
|
// return this.GetSyncVarGameObject(ref field, uint netId);
|
||||||
|
getWorker.Append(getWorker.Create(OpCodes.Ldarg_0)); // this.
|
||||||
|
getWorker.Append(getWorker.Create(OpCodes.Ldarg_0));
|
||||||
|
getWorker.Append(getWorker.Create(OpCodes.Ldfld, netFieldId));
|
||||||
|
getWorker.Append(getWorker.Create(OpCodes.Ldarg_0));
|
||||||
|
getWorker.Append(getWorker.Create(OpCodes.Ldflda, fd));
|
||||||
|
getWorker.Append(getWorker.Create(OpCodes.Call, Weaver.getSyncVarGameObjectReference));
|
||||||
|
getWorker.Append(getWorker.Create(OpCodes.Ret));
|
||||||
|
}
|
||||||
|
// [SyncVar] NetworkIdentity?
|
||||||
|
else if (fd.FieldType.FullName == Weaver.NetworkIdentityType.FullName)
|
||||||
|
{
|
||||||
|
// return this.GetSyncVarNetworkIdentity(ref field, uint netId);
|
||||||
|
getWorker.Append(getWorker.Create(OpCodes.Ldarg_0)); // this.
|
||||||
|
getWorker.Append(getWorker.Create(OpCodes.Ldarg_0));
|
||||||
|
getWorker.Append(getWorker.Create(OpCodes.Ldfld, netFieldId));
|
||||||
|
getWorker.Append(getWorker.Create(OpCodes.Ldarg_0));
|
||||||
|
getWorker.Append(getWorker.Create(OpCodes.Ldflda, fd));
|
||||||
|
getWorker.Append(getWorker.Create(OpCodes.Call, Weaver.getSyncVarNetworkIdentityReference));
|
||||||
|
getWorker.Append(getWorker.Create(OpCodes.Ret));
|
||||||
|
}
|
||||||
|
// [SyncVar] int, string, etc.
|
||||||
|
else
|
||||||
|
{
|
||||||
|
getWorker.Append(getWorker.Create(OpCodes.Ldarg_0));
|
||||||
|
getWorker.Append(getWorker.Create(OpCodes.Ldfld, fd));
|
||||||
|
getWorker.Append(getWorker.Create(OpCodes.Ret));
|
||||||
|
}
|
||||||
|
|
||||||
get.Body.Variables.Add(new VariableDefinition(fd.FieldType));
|
get.Body.Variables.Add(new VariableDefinition(fd.FieldType));
|
||||||
get.Body.InitLocals = true;
|
get.Body.InitLocals = true;
|
||||||
@ -137,6 +165,14 @@ public static MethodDefinition ProcessSyncVarSet(TypeDefinition td, FieldDefinit
|
|||||||
|
|
||||||
setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.setSyncVarGameObjectReference));
|
setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.setSyncVarGameObjectReference));
|
||||||
}
|
}
|
||||||
|
else if (fd.FieldType.FullName == Weaver.NetworkIdentityType.FullName)
|
||||||
|
{
|
||||||
|
// reference to netId Field to set
|
||||||
|
setWorker.Append(setWorker.Create(OpCodes.Ldarg_0));
|
||||||
|
setWorker.Append(setWorker.Create(OpCodes.Ldflda, netFieldId));
|
||||||
|
|
||||||
|
setWorker.Append(setWorker.Create(OpCodes.Call, Weaver.setSyncVarNetworkIdentityReference));
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// make generic version of SetSyncVar with field type
|
// make generic version of SetSyncVar with field type
|
||||||
@ -158,12 +194,12 @@ public static MethodDefinition ProcessSyncVarSet(TypeDefinition td, FieldDefinit
|
|||||||
public static void ProcessSyncVar(TypeDefinition td, FieldDefinition fd, List<FieldDefinition> syncVarNetIds, long dirtyBit)
|
public static void ProcessSyncVar(TypeDefinition td, FieldDefinition fd, List<FieldDefinition> syncVarNetIds, long dirtyBit)
|
||||||
{
|
{
|
||||||
string originalName = fd.Name;
|
string originalName = fd.Name;
|
||||||
|
|
||||||
Weaver.DLog(td, "Sync Var " + fd.Name + " " + fd.FieldType + " " + Weaver.gameObjectType);
|
Weaver.DLog(td, "Sync Var " + fd.Name + " " + fd.FieldType + " " + Weaver.gameObjectType);
|
||||||
|
|
||||||
// GameObject SyncVars have a new field for netId
|
// GameObject/NetworkIdentity SyncVars have a new field for netId
|
||||||
FieldDefinition netFieldId = null;
|
FieldDefinition netFieldId = null;
|
||||||
if (fd.FieldType.FullName == Weaver.gameObjectType.FullName)
|
if (fd.FieldType.FullName == Weaver.gameObjectType.FullName ||
|
||||||
|
fd.FieldType.FullName == Weaver.NetworkIdentityType.FullName)
|
||||||
{
|
{
|
||||||
netFieldId = new FieldDefinition("___" + fd.Name + "NetId",
|
netFieldId = new FieldDefinition("___" + fd.Name + "NetId",
|
||||||
FieldAttributes.Private,
|
FieldAttributes.Private,
|
||||||
@ -173,7 +209,7 @@ public static void ProcessSyncVar(TypeDefinition td, FieldDefinition fd, List<Fi
|
|||||||
Weaver.lists.netIdFields.Add(netFieldId);
|
Weaver.lists.netIdFields.Add(netFieldId);
|
||||||
}
|
}
|
||||||
|
|
||||||
var get = ProcessSyncVarGet(fd, originalName);
|
var get = ProcessSyncVarGet(fd, originalName, netFieldId);
|
||||||
var set = ProcessSyncVarSet(td, fd, originalName, dirtyBit, netFieldId);
|
var set = ProcessSyncVarSet(td, fd, originalName, dirtyBit, netFieldId);
|
||||||
|
|
||||||
//NOTE: is property even needed? Could just use a setter function?
|
//NOTE: is property even needed? Could just use a setter function?
|
||||||
@ -188,6 +224,16 @@ public static void ProcessSyncVar(TypeDefinition td, FieldDefinition fd, List<Fi
|
|||||||
td.Methods.Add(set);
|
td.Methods.Add(set);
|
||||||
td.Properties.Add(propertyDefinition);
|
td.Properties.Add(propertyDefinition);
|
||||||
Weaver.lists.replacementSetterProperties[fd] = set;
|
Weaver.lists.replacementSetterProperties[fd] = set;
|
||||||
|
|
||||||
|
// replace getter field if GameObject/NetworkIdentity so it uses
|
||||||
|
// netId instead
|
||||||
|
// -> only for GameObjects, otherwise an int syncvar's getter would
|
||||||
|
// end up in recursion.
|
||||||
|
if (fd.FieldType.FullName == Weaver.gameObjectType.FullName ||
|
||||||
|
fd.FieldType.FullName == Weaver.NetworkIdentityType.FullName)
|
||||||
|
{
|
||||||
|
Weaver.lists.replacementGetterProperties[fd] = get;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ProcessSyncVars(TypeDefinition td, List<FieldDefinition> syncVars, List<FieldDefinition> syncObjects, List<FieldDefinition> syncVarNetIds)
|
public static void ProcessSyncVars(TypeDefinition td, List<FieldDefinition> syncVars, List<FieldDefinition> syncObjects, List<FieldDefinition> syncVarNetIds)
|
||||||
|
@ -15,6 +15,8 @@ class WeaverLists
|
|||||||
{
|
{
|
||||||
// setter functions that replace [SyncVar] member variable references. dict<field, replacement>
|
// setter functions that replace [SyncVar] member variable references. dict<field, replacement>
|
||||||
public Dictionary<FieldDefinition, MethodDefinition> replacementSetterProperties = new Dictionary<FieldDefinition, MethodDefinition>();
|
public Dictionary<FieldDefinition, MethodDefinition> replacementSetterProperties = new Dictionary<FieldDefinition, MethodDefinition>();
|
||||||
|
// getter functions that replace [SyncVar] member variable references. dict<field, replacement>
|
||||||
|
public Dictionary<FieldDefinition, MethodDefinition> replacementGetterProperties = new Dictionary<FieldDefinition, MethodDefinition>();
|
||||||
// GameObject SyncVar generated netId fields
|
// GameObject SyncVar generated netId fields
|
||||||
public List<FieldDefinition> netIdFields = new List<FieldDefinition>();
|
public List<FieldDefinition> netIdFields = new List<FieldDefinition>();
|
||||||
|
|
||||||
@ -146,6 +148,9 @@ class Weaver
|
|||||||
public static MethodReference setSyncVarHookGuard;
|
public static MethodReference setSyncVarHookGuard;
|
||||||
public static MethodReference getSyncVarHookGuard;
|
public static MethodReference getSyncVarHookGuard;
|
||||||
public static MethodReference setSyncVarGameObjectReference;
|
public static MethodReference setSyncVarGameObjectReference;
|
||||||
|
public static MethodReference getSyncVarGameObjectReference;
|
||||||
|
public static MethodReference setSyncVarNetworkIdentityReference;
|
||||||
|
public static MethodReference getSyncVarNetworkIdentityReference;
|
||||||
public static MethodReference registerCommandDelegateReference;
|
public static MethodReference registerCommandDelegateReference;
|
||||||
public static MethodReference registerRpcDelegateReference;
|
public static MethodReference registerRpcDelegateReference;
|
||||||
public static MethodReference registerEventDelegateReference;
|
public static MethodReference registerEventDelegateReference;
|
||||||
@ -742,10 +747,11 @@ static void ConfirmGeneratedCodeClass(ModuleDefinition moduleDef)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// replaces syncvar write access with the NetworkXYZ.get property calls
|
||||||
static void ProcessInstructionSetterField(TypeDefinition td, MethodDefinition md, Instruction i, FieldDefinition opField)
|
static void ProcessInstructionSetterField(TypeDefinition td, MethodDefinition md, Instruction i, FieldDefinition opField)
|
||||||
{
|
{
|
||||||
// dont replace property call sites in constructors or deserialize
|
// dont replace property call sites in constructors
|
||||||
if (md.Name == ".ctor" || md.Name == "OnDeserialize")
|
if (md.Name == ".ctor")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// does it set a field that we replaced?
|
// does it set a field that we replaced?
|
||||||
@ -760,6 +766,25 @@ static void ProcessInstructionSetterField(TypeDefinition td, MethodDefinition md
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// replaces syncvar read access with the NetworkXYZ.get property calls
|
||||||
|
static void ProcessInstructionGetterField(TypeDefinition td, MethodDefinition md, Instruction i, FieldDefinition opField)
|
||||||
|
{
|
||||||
|
// dont replace property call sites in constructors
|
||||||
|
if (md.Name == ".ctor")
|
||||||
|
return;
|
||||||
|
|
||||||
|
// does it set a field that we replaced?
|
||||||
|
MethodDefinition replacement;
|
||||||
|
if (lists.replacementGetterProperties.TryGetValue(opField, out replacement))
|
||||||
|
{
|
||||||
|
//replace with property
|
||||||
|
//DLog(td, " replacing " + md.Name + ":" + i);
|
||||||
|
i.OpCode = OpCodes.Call;
|
||||||
|
i.Operand = replacement;
|
||||||
|
//DLog(td, " replaced " + md.Name + ":" + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void ProcessInstruction(ModuleDefinition moduleDef, TypeDefinition td, MethodDefinition md, Instruction i, int iCount)
|
static void ProcessInstruction(ModuleDefinition moduleDef, TypeDefinition td, MethodDefinition md, Instruction i, int iCount)
|
||||||
{
|
{
|
||||||
if (i.OpCode == OpCodes.Call || i.OpCode == OpCodes.Callvirt)
|
if (i.OpCode == OpCodes.Call || i.OpCode == OpCodes.Callvirt)
|
||||||
@ -780,6 +805,16 @@ static void ProcessInstruction(ModuleDefinition moduleDef, TypeDefinition td, Me
|
|||||||
ProcessInstructionSetterField(td, md, i, opField);
|
ProcessInstructionSetterField(td, md, i, opField);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i.OpCode == OpCodes.Ldfld)
|
||||||
|
{
|
||||||
|
// this instruction gets the value of a field. cache the field reference.
|
||||||
|
FieldDefinition opField = i.Operand as FieldDefinition;
|
||||||
|
if (opField != null)
|
||||||
|
{
|
||||||
|
ProcessInstructionGetterField(td, md, i, opField);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is required to early-out from a function with "ref" or "out" parameters
|
// this is required to early-out from a function with "ref" or "out" parameters
|
||||||
@ -885,7 +920,6 @@ static void ProcessSiteMethod(ModuleDefinition moduleDef, TypeDefinition td, Met
|
|||||||
//Weaver.DLog(td, " ProcessSiteMethod " + md);
|
//Weaver.DLog(td, " ProcessSiteMethod " + md);
|
||||||
|
|
||||||
if (md.Name == ".cctor" ||
|
if (md.Name == ".cctor" ||
|
||||||
md.Name == "OnDeserialize" ||
|
|
||||||
md.Name == NetworkBehaviourProcessor.ProcessedFunctionName ||
|
md.Name == NetworkBehaviourProcessor.ProcessedFunctionName ||
|
||||||
md.Name.StartsWith("CallCmd") ||
|
md.Name.StartsWith("CallCmd") ||
|
||||||
md.Name.StartsWith("InvokeCmd") ||
|
md.Name.StartsWith("InvokeCmd") ||
|
||||||
@ -1129,6 +1163,9 @@ static void SetupTargetTypes()
|
|||||||
getSyncVarHookGuard = Resolvers.ResolveMethod(NetworkBehaviourType, scriptDef, "get_syncVarHookGuard");
|
getSyncVarHookGuard = Resolvers.ResolveMethod(NetworkBehaviourType, scriptDef, "get_syncVarHookGuard");
|
||||||
|
|
||||||
setSyncVarGameObjectReference = Resolvers.ResolveMethod(NetworkBehaviourType, scriptDef, "SetSyncVarGameObject");
|
setSyncVarGameObjectReference = Resolvers.ResolveMethod(NetworkBehaviourType, scriptDef, "SetSyncVarGameObject");
|
||||||
|
getSyncVarGameObjectReference = Resolvers.ResolveMethod(NetworkBehaviourType, scriptDef, "GetSyncVarGameObject");
|
||||||
|
setSyncVarNetworkIdentityReference = Resolvers.ResolveMethod(NetworkBehaviourType, scriptDef, "SetSyncVarNetworkIdentity");
|
||||||
|
getSyncVarNetworkIdentityReference = Resolvers.ResolveMethod(NetworkBehaviourType, scriptDef, "GetSyncVarNetworkIdentity");
|
||||||
registerCommandDelegateReference = Resolvers.ResolveMethod(NetworkBehaviourType, scriptDef, "RegisterCommandDelegate");
|
registerCommandDelegateReference = Resolvers.ResolveMethod(NetworkBehaviourType, scriptDef, "RegisterCommandDelegate");
|
||||||
registerRpcDelegateReference = Resolvers.ResolveMethod(NetworkBehaviourType, scriptDef, "RegisterRpcDelegate");
|
registerRpcDelegateReference = Resolvers.ResolveMethod(NetworkBehaviourType, scriptDef, "RegisterRpcDelegate");
|
||||||
registerEventDelegateReference = Resolvers.ResolveMethod(NetworkBehaviourType, scriptDef, "RegisterEventDelegate");
|
registerEventDelegateReference = Resolvers.ResolveMethod(NetworkBehaviourType, scriptDef, "RegisterEventDelegate");
|
||||||
|
Loading…
Reference in New Issue
Block a user