-
-
Notifications
You must be signed in to change notification settings - Fork 65
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: SyncVar support arbitrary NetworkBehavior (#514)
Similar to NetworkIdentity and GameObjects, now we can synchronize NetworkBehaviors in a lazy fashion. Meaning even if the target object is spawned at a later time, it will still be found
- Loading branch information
Showing
6 changed files
with
202 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
namespace Mirror | ||
{ | ||
|
||
/// <summary> | ||
/// backing struct for a NetworkIdentity when used as a syncvar | ||
/// the weaver will replace the syncvar with this struct. | ||
/// </summary> | ||
public struct NetworkBehaviorSyncvar | ||
{ | ||
/// <summary> | ||
/// The network client that spawned the parent object | ||
/// used to lookup the identity if it exists | ||
/// </summary> | ||
internal NetworkClient client; | ||
internal uint netId; | ||
internal int componentId; | ||
|
||
internal NetworkBehaviour component; | ||
|
||
internal uint NetId => component != null ? component.NetId : netId; | ||
internal int ComponentId => component != null ? component.ComponentIndex : componentId; | ||
|
||
public NetworkBehaviour Value | ||
{ | ||
get | ||
{ | ||
if (component != null) | ||
return component; | ||
|
||
if (client != null) | ||
{ | ||
client.Spawned.TryGetValue(netId, out NetworkIdentity identity); | ||
if (identity != null) | ||
return identity.NetworkBehaviours[componentId]; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
set | ||
{ | ||
if (value == null) | ||
{ | ||
netId = 0; | ||
componentId = 0; | ||
} | ||
component = value; | ||
} | ||
} | ||
} | ||
|
||
|
||
public static class NetworkBehaviorSerializers | ||
{ | ||
public static void WriteNetworkIdentity(this NetworkWriter writer, NetworkBehaviorSyncvar id) | ||
{ | ||
writer.WritePackedUInt32(id.NetId); | ||
writer.WritePackedInt32(id.ComponentId); | ||
} | ||
|
||
public static NetworkBehaviorSyncvar ReadNetworkIdentity(this NetworkReader reader) | ||
{ | ||
uint netId = reader.ReadPackedUInt32(); | ||
int componentId = reader.ReadPackedInt32(); | ||
|
||
NetworkIdentity identity = null; | ||
if (!(reader.Client is null)) | ||
reader.Client.Spawned.TryGetValue(netId, out identity); | ||
|
||
if (!(reader.Server is null)) | ||
reader.Server.Spawned.TryGetValue(netId, out identity); | ||
|
||
return new NetworkBehaviorSyncvar | ||
{ | ||
client = reader.Client, | ||
netId = netId, | ||
componentId = componentId, | ||
component = identity != null ? identity.NetworkBehaviours[componentId] : null | ||
}; | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
using System.Collections; | ||
using Cysharp.Threading.Tasks; | ||
using NUnit.Framework; | ||
using UnityEngine.TestTools; | ||
|
||
namespace Mirror.Tests | ||
{ | ||
public class SampleBehaviorWithNB : NetworkBehaviour | ||
{ | ||
[SyncVar] | ||
public SampleBehaviorWithNB target; | ||
} | ||
|
||
public class NetworkBehaviorSyncvarTest : ClientServerSetup<SampleBehaviorWithNB> | ||
{ | ||
[Test] | ||
public void IsNullByDefault() | ||
{ | ||
// out of the box, target should be null in the client | ||
|
||
Assert.That(clientComponent.target, Is.Null); | ||
} | ||
|
||
[UnityTest] | ||
public IEnumerator ChangeTarget() => UniTask.ToCoroutine(async () => | ||
{ | ||
serverComponent.target = serverComponent; | ||
await UniTask.WaitUntil(() => clientComponent.target != null); | ||
Assert.That(clientComponent.target, Is.SameAs(clientComponent)); | ||
}); | ||
|
||
[Test] | ||
public void UpdateAfterSpawn() | ||
{ | ||
// this situation can happen when the client does nto see an object | ||
// but the object is assigned in a syncvar. | ||
// this can easily happen during spawn if spawning in an unexpected order | ||
// or if there is AOI in play. | ||
// in this case we would have a valid net id, but we would not | ||
// find the object at spawn time | ||
|
||
var goSyncvar = new NetworkBehaviorSyncvar | ||
{ | ||
client = client, | ||
netId = serverIdentity.NetId, | ||
component = null, | ||
}; | ||
|
||
Assert.That(goSyncvar.Value, Is.SameAs(clientComponent)); | ||
} | ||
|
||
[UnityTest] | ||
public IEnumerator SpawnWithTarget() => UniTask.ToCoroutine(async () => | ||
{ | ||
// create an object, set the target and spawn it | ||
UnityEngine.GameObject newObject = UnityEngine.Object.Instantiate(playerPrefab); | ||
SampleBehaviorWithNB newBehavior = newObject.GetComponent<SampleBehaviorWithNB>(); | ||
newBehavior.target = serverComponent; | ||
serverObjectManager.Spawn(newObject); | ||
// wait until the client spawns it | ||
uint newObjectId = newBehavior.NetId; | ||
await UniTask.WaitUntil(() => client.Spawned.ContainsKey(newObjectId)); | ||
// check if the target was set correctly in the client | ||
NetworkIdentity newClientObject = client.Spawned[newObjectId]; | ||
SampleBehaviorWithNB newClientBehavior = newClientObject.GetComponent<SampleBehaviorWithNB>(); | ||
Assert.That(newClientBehavior.target, Is.SameAs(clientComponent)); | ||
// cleanup | ||
serverObjectManager.Destroy(newObject); | ||
}); | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.