Skip to content

Commit

Permalink
fix: #1278 - only call initial state SyncVar hooks on clients if the …
Browse files Browse the repository at this point in the history
…SyncVar value is different from the default one. (#1414)

* move comment

* add comment

* fix: #1278 - only call initial state SyncVar hooks on clients if the SyncVar value is different from the default one.

* initialState test for an if

* !initialstate

* getting there

* closer

* works but incompatible stack heights message

* better comments

* better

* not needed

* syntax

* rename

* incompatible stack height fixed

* update comment

* remove first todo

* SAVE PROGRESS

* compare go/ni too

* whitespace

* update comments
  • Loading branch information
miwarnec committed Jan 8, 2020
1 parent 32abb70 commit a3ffd12
Showing 1 changed file with 79 additions and 7 deletions.
Expand Up @@ -441,12 +441,6 @@ public static int GetChannelId(CustomAttribute ca)
return 0;
}

/*
Generates code like:
int num = reader.ReadPackedInt32();
OnSetA(num);
Networka = num;
*/
void DeserializeField(FieldDefinition syncVar, ILProcessor serWorker, MethodDefinition deserialize)
{
// check for Hook function
Expand All @@ -456,6 +450,15 @@ void DeserializeField(FieldDefinition syncVar, ILProcessor serWorker, MethodDefi
}

// [SyncVar] GameObject/NetworkIdentity?
/*
Generates code like:
uint num = reader.ReadPackedUInt32();
if (!SyncVarEqual(num, ref q))
{
OnSetQ(GetSyncVarGameObject(num, ref q));
}
___qNetId = num;
*/
if (syncVar.FieldType.FullName == Weaver.gameObjectType.FullName ||
syncVar.FieldType.FullName == Weaver.NetworkIdentityType.FullName)
{
Expand All @@ -478,6 +481,39 @@ void DeserializeField(FieldDefinition syncVar, ILProcessor serWorker, MethodDefi
{
// 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 = serWorker.Create(OpCodes.Nop);

// 'this.' for 'this.SyncVarEqual'
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
// 'tmpValue'
serWorker.Append(serWorker.Create(OpCodes.Ldloc, tmpValue));
// 'ref this.__netId'
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
serWorker.Append(serWorker.Create(OpCodes.Ldflda, netIdField));
// call the function
GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(Weaver.syncVarEqualReference);
syncVarEqualGm.GenericArguments.Add(netIdField.FieldType);
serWorker.Append(serWorker.Create(OpCodes.Call, syncVarEqualGm));
serWorker.Append(serWorker.Create(OpCodes.Brtrue, syncVarEqualLabel));

// call the hook
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0)); // this.
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
serWorker.Append(serWorker.Create(OpCodes.Ldloc, tmpValue));
Expand All @@ -488,13 +524,25 @@ void DeserializeField(FieldDefinition syncVar, ILProcessor serWorker, MethodDefi
else if (syncVar.FieldType.FullName == Weaver.NetworkIdentityType.FullName)
serWorker.Append(serWorker.Create(OpCodes.Callvirt, Weaver.getSyncVarNetworkIdentityReference));
serWorker.Append(serWorker.Create(OpCodes.Call, foundMethod));

// Generates: end if (!SyncVarEqual);
serWorker.Append(syncVarEqualLabel);
}
// set the netid field
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
serWorker.Append(serWorker.Create(OpCodes.Ldloc, tmpValue));
serWorker.Append(serWorker.Create(OpCodes.Stfld, netIdField));
}
// [SyncVar] int/float/struct/etc.?
/*
Generates code like:
int num = reader.ReadPackedInt32();
if (!SyncVarEqual(num, ref a))
{
OnSetA(num);
}
Networka = num;
*/
else
{
MethodReference readFunc = Readers.GetReadFunc(syncVar.FieldType);
Expand All @@ -514,16 +562,40 @@ void DeserializeField(FieldDefinition syncVar, ILProcessor serWorker, MethodDefi
if (foundMethod != 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);

// 'this.' for 'this.SyncVarEqual'
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
// 'tmpValue'
serWorker.Append(serWorker.Create(OpCodes.Ldloc, tmpValue));
// 'ref this.syncVar'
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
serWorker.Append(serWorker.Create(OpCodes.Ldflda, syncVar));
// call the function
GenericInstanceMethod syncVarEqualGm = new GenericInstanceMethod(Weaver.syncVarEqualReference);
syncVarEqualGm.GenericArguments.Add(syncVar.FieldType);
serWorker.Append(serWorker.Create(OpCodes.Call, syncVarEqualGm));
serWorker.Append(serWorker.Create(OpCodes.Brtrue, syncVarEqualLabel));

// call the hook
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
serWorker.Append(serWorker.Create(OpCodes.Ldloc, tmpValue));
serWorker.Append(serWorker.Create(OpCodes.Call, foundMethod));

// Generates: end if (!SyncVarEqual);
serWorker.Append(syncVarEqualLabel);
}
// set the property
serWorker.Append(serWorker.Create(OpCodes.Ldarg_0));
serWorker.Append(serWorker.Create(OpCodes.Ldloc, tmpValue));
serWorker.Append(serWorker.Create(OpCodes.Stfld, syncVar));
}

}

void GenerateDeSerialization()
Expand Down

0 comments on commit a3ffd12

Please sign in to comment.