Skip to content

Commit

Permalink
feat: adding generic NetworkBehaviorSyncvar for ease of use
Browse files Browse the repository at this point in the history
can be used in SyncList or other network methods
  • Loading branch information
James-Frowen committed Apr 14, 2024
1 parent 796a010 commit 5caabd9
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 21 deletions.
71 changes: 71 additions & 0 deletions Assets/Mirage/Runtime/NetworkBehaviorSyncvar.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Runtime.CompilerServices;
using Mirage.Serialization;

namespace Mirage
Expand All @@ -19,6 +20,11 @@ public struct NetworkBehaviorSyncvar

internal NetworkBehaviour _component;

public NetworkBehaviorSyncvar(NetworkBehaviour behaviour) : this()
{
_component = behaviour;
}

internal uint NetId => _component != null ? _component.NetId : _netId;
internal int ComponentId => _component != null ? _component.ComponentIndex : _componentId;

Expand Down Expand Up @@ -48,6 +54,58 @@ public NetworkBehaviour Value
_component = value;
}
}

/// <summary>
/// returns Value cast as T
/// </summary>
/// <typeparam name="T"></typeparam>
/// <exception cref="System.InvalidCastException"></exception>
/// /// <returns></returns>
public T GetAs<T>() where T : NetworkBehaviour
{
var value = Value;
if (value is null)
return null;
else
return (T)value;
}

public static implicit operator NetworkBehaviorSyncvar(NetworkBehaviour behaviour) => new NetworkBehaviorSyncvar(behaviour);
}

public struct NetworkBehaviorSyncvar<T> where T : NetworkBehaviour
{
private NetworkBehaviorSyncvar inner;

public NetworkBehaviorSyncvar(T behaviour) : this()
{
inner = new NetworkBehaviorSyncvar(behaviour);
}

internal uint NetId
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => inner.NetId;
}

internal int ComponentId
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => inner.ComponentId;
}

public T Value
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => (T)inner.Value;

[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => inner.Value = value;
}

public static implicit operator NetworkBehaviorSyncvar<T>(T behaviour) => new NetworkBehaviorSyncvar<T>(behaviour);
public static implicit operator NetworkBehaviorSyncvar(NetworkBehaviorSyncvar<T> generic) => generic.inner;
public static explicit operator NetworkBehaviorSyncvar<T>(NetworkBehaviorSyncvar syncvar) => new NetworkBehaviorSyncvar<T>() { inner = syncvar };
}


Expand Down Expand Up @@ -77,5 +135,18 @@ public static NetworkBehaviorSyncvar ReadNetworkBehaviourSyncVar(this NetworkRea
_component = hasValue ? identity.NetworkBehaviours[componentId] : null
};
}

[WeaverSerializeCollection]
public static void WriteGenericNetworkBehaviorSyncVar<T>(this NetworkWriter writer, NetworkBehaviorSyncvar<T> id) where T : NetworkBehaviour
{
WriteNetworkBehaviorSyncVar(writer, id);
}

[WeaverSerializeCollection]
public static NetworkBehaviorSyncvar<T> ReadGenericNetworkBehaviourSyncVar<T>(this NetworkReader reader) where T : NetworkBehaviour
{
var syncvar = ReadNetworkBehaviourSyncVar(reader);
return (NetworkBehaviorSyncvar<T>)syncvar;
}
}
}
109 changes: 88 additions & 21 deletions Assets/Tests/Runtime/ClientServer/NetworkBehaviorSyncvarTest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using System;
using System.Collections;
using Cysharp.Threading.Tasks;
using Mirage.Serialization;
using Mirage.Tests.Runtime.Syncing;
using NUnit.Framework;
using UnityEngine.TestTools;

Expand All @@ -13,6 +16,21 @@ public class SampleBehaviorWithNB : NetworkBehaviour

public class NetworkBehaviorSyncvarTest : ClientServerSetup<SampleBehaviorWithNB>
{
private NetworkWriter writer;
private MirageNetworkReader reader;

protected override UniTask ExtraSetup()
{
writer = new NetworkWriter(1200);
reader = new MirageNetworkReader();
return base.ExtraSetup();
}
public override void ExtraTearDown()
{
reader?.Dispose();
}


[Test]
public void IsNullByDefault()
{
Expand All @@ -31,31 +49,11 @@ public void IsNullByDefault()
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
{
_objectLocator = client.World,
_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 = InstantiateForTest(_characterPrefabGo);
var newObject = InstantiateForTest(_characterPrefabGo);
var newBehavior = newObject.GetComponent<SampleBehaviorWithNB>();
newBehavior.target = serverComponent;
serverObjectManager.Spawn(newObject);
Expand All @@ -71,5 +69,74 @@ public void UpdateAfterSpawn()
// cleanup
serverObjectManager.Destroy(newObject);
});

[Test]
public void NetworkBehaviorSyncvarGetOnClient()
{
var goSyncvar = new NetworkBehaviorSyncvar
{
_objectLocator = client.World,
_netId = serverIdentity.NetId,
_component = null,
};

Assert.That(goSyncvar.Value, Is.SameAs(clientComponent));
}
[Test]
public void NetworkBehaviorSyncvarGetOnClientGeneric()
{
var goSyncvar = (NetworkBehaviorSyncvar<SampleBehaviorWithNB>)new NetworkBehaviorSyncvar
{
_objectLocator = client.World,
_netId = serverIdentity.NetId,
_component = null,
};

Assert.That(goSyncvar.Value, Is.TypeOf<SampleBehaviorWithNB>());
Assert.That(goSyncvar.Value, Is.SameAs(clientComponent));
}
[Test]
public void NetworkBehaviorSyncvarSync()
{
var serverValue = new NetworkBehaviorSyncvar(serverComponent);
writer.Write(serverValue);
reader.ObjectLocator = client.World;
reader.Reset(writer.ToArraySegment());
var clientValue = reader.Read<NetworkBehaviorSyncvar>();

Assert.That(clientValue.Value, Is.SameAs(clientComponent));
}
[Test]
public void NetworkBehaviorSyncvarSyncGeneric()
{
var serverValue = new NetworkBehaviorSyncvar<SampleBehaviorWithNB>(serverComponent);
writer.Write(serverValue);
reader.ObjectLocator = client.World;
reader.Reset(writer.ToArraySegment());
var clientValue = reader.Read<NetworkBehaviorSyncvar<SampleBehaviorWithNB>>();

Assert.That(clientValue.Value, Is.TypeOf<SampleBehaviorWithNB>());
Assert.That(clientValue.Value, Is.SameAs(clientComponent));
}
[Test]
public void GetAs()
{
var serverValue = new NetworkBehaviorSyncvar(serverComponent);
var value = serverValue.GetAs<SampleBehaviorWithNB>();

Assert.That(value, Is.TypeOf<SampleBehaviorWithNB>());
Assert.That(value, Is.SameAs(serverComponent));
}

[Test]
public void GetAsThrow()
{
var serverValue = new NetworkBehaviorSyncvar(serverComponent);

Assert.Throws<InvalidCastException>(() =>
{
var value = serverValue.GetAs<MockPlayer>();
});
}
}
}

0 comments on commit 5caabd9

Please sign in to comment.