perf: SyncVar<T> some more inlining

This commit is contained in:
vis2k 2022-02-03 22:12:00 +08:00
parent 0d55ed8448
commit ff1199607e
4 changed files with 47 additions and 5 deletions

View File

@ -16,6 +16,7 @@
//
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;
namespace Mirror
@ -33,6 +34,7 @@ public class SyncVar<T> : SyncObject, IEquatable<T>
// virtual for SyncFieldNetworkIdentity netId trick etc.
public virtual T Value
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => _Value;
set
{
@ -74,6 +76,7 @@ public virtual T Value
// OnCallback is responsible for calling the callback.
// this is necessary for inheriting classes like SyncVarGameObject,
// where the netIds should be converted to GOs and call the GO hook.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected virtual void InvokeCallback(T oldValue, T newValue) =>
Callback?.Invoke(oldValue, newValue);
@ -107,21 +110,31 @@ public SyncVar(T value)
// SyncVar<T>s are readonly and only initialized by 'Value' once.
// implicit conversion: int value = SyncVar<T>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator T(SyncVar<T> field) => field.Value;
// implicit conversion: SyncVar<T> = value
// even if SyncVar<T> is readonly, it's still useful: SyncVar<int> = 1;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator SyncVar<T>(T value) => new SyncVar<T>(value);
// serialization (use .Value instead of _Value so hook is called!)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void OnSerializeAll(NetworkWriter writer) => writer.Write(Value);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void OnSerializeDelta(NetworkWriter writer) => writer.Write(Value);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void OnDeserializeAll(NetworkReader reader) => Value = reader.Read<T>();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void OnDeserializeDelta(NetworkReader reader) => Value = reader.Read<T>();
// IEquatable should compare Value.
// SyncVar<T> should act invisibly like [SyncVar] before.
// this way we can do SyncVar<int> health == 0 etc.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(T other) =>
// from NetworkBehaviour.SyncVarEquals:
// EqualityComparer method avoids allocations.

View File

@ -55,7 +55,9 @@ public class SyncVarGameObject : SyncVar<uint>
// .spawned lookup from netId overwrites base uint .Value
public new GameObject Value
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => GetGameObject(base.Value);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => base.Value = GetNetId(value);
}
@ -64,6 +66,7 @@ public class SyncVarGameObject : SyncVar<uint>
public new event Action<GameObject, GameObject> Callback;
// overwrite CallCallback to use the GameObject version instead
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected override void InvokeCallback(uint oldValue, uint newValue) =>
Callback?.Invoke(GetGameObject(oldValue), GetGameObject(newValue));
@ -76,6 +79,7 @@ public SyncVarGameObject(GameObject value = null)
: base(GetNetId(value)) {}
// helper function to get netId from GameObject (if any)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static uint GetNetId(GameObject go)
{
if (go != null)
@ -87,6 +91,7 @@ static uint GetNetId(GameObject go)
}
// helper function to get GameObject from netId (if spawned)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static GameObject GetGameObject(uint netId)
{
NetworkIdentity spawned = Utils.GetSpawnedInServerOrClient(netId);
@ -94,10 +99,12 @@ static GameObject GetGameObject(uint netId)
}
// implicit conversion: GameObject value = SyncFieldGameObject
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator GameObject(SyncVarGameObject field) => field.Value;
// implicit conversion: SyncFieldGameObject = value
// even if SyncField is readonly, it's still useful: SyncFieldGameObject = target;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator SyncVarGameObject(GameObject value) => new SyncVarGameObject(value);
// == operator for comparisons like Player.target==monster
@ -129,7 +136,10 @@ static GameObject GetGameObject(uint netId)
public static bool operator !=(GameObject a, SyncVarGameObject b) => !(a == b);
// if we overwrite == operators, we also need to overwrite .Equals.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj) => obj is SyncVarGameObject value && this == value;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() => Value.GetHashCode();
}
}

View File

@ -25,7 +25,9 @@ public class SyncVarNetworkBehaviour<T> : SyncVar<ulong>
// .spawned lookup from netId overwrites base uint .Value
public new T Value
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ULongToNetworkBehaviour(base.Value);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => base.Value = NetworkBehaviourToULong(value);
}
@ -34,6 +36,7 @@ public class SyncVarNetworkBehaviour<T> : SyncVar<ulong>
public new event Action<T, T> Callback;
// overwrite CallCallback to use the NetworkIdentity version instead
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected override void InvokeCallback(ulong oldValue, ulong newValue) =>
Callback?.Invoke(ULongToNetworkBehaviour(oldValue), ULongToNetworkBehaviour(newValue));
@ -46,10 +49,12 @@ public SyncVarNetworkBehaviour(T value = null)
: base(NetworkBehaviourToULong(value)) {}
// implicit conversion: NetworkBehaviour value = SyncFieldNetworkBehaviour
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator T(SyncVarNetworkBehaviour<T> field) => field.Value;
// implicit conversion: SyncFieldNetworkBehaviour = value
// even if SyncField is readonly, it's still useful: SyncFieldNetworkBehaviour = target;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator SyncVarNetworkBehaviour<T>(T value) => new SyncVarNetworkBehaviour<T>(value);
// NOTE: overloading all == operators blocks '== null' checks with an
@ -97,16 +102,18 @@ public SyncVarNetworkBehaviour(T value = null)
public static bool operator !=(T a, SyncVarNetworkBehaviour<T> b) => !(a == b);
// if we overwrite == operators, we also need to overwrite .Equals.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj) => obj is SyncVarNetworkBehaviour<T> value && this == value;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() => Value.GetHashCode();
// helper functions to get/set netId, componentIndex from ulong
internal static ulong Pack(uint netId, byte componentIndex)
{
// netId on the 4 left bytes. compIndex on the right most byte.
return (ulong)netId << 32 | componentIndex;
}
// netId on the 4 left bytes. compIndex on the right most byte.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static ulong Pack(uint netId, byte componentIndex) =>
(ulong)netId << 32 | componentIndex;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void Unpack(ulong value, out uint netId, out byte componentIndex)
{
netId = (uint)(value >> 32);
@ -133,6 +140,7 @@ static ulong NetworkBehaviourToULong(T value)
}
// Serialize should only write 4+1 bytes, not 8 bytes ulong
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void OnSerializeAll(NetworkWriter writer)
{
Unpack(base.Value, out uint netId, out byte componentIndex);
@ -140,10 +148,12 @@ public override void OnSerializeAll(NetworkWriter writer)
writer.WriteByte(componentIndex);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void OnSerializeDelta(NetworkWriter writer) =>
OnSerializeAll(writer);
// Deserialize should only write 4+1 bytes, not 8 bytes ulong
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void OnDeserializeAll(NetworkReader reader)
{
uint netId = reader.ReadUInt();
@ -151,6 +161,7 @@ public override void OnDeserializeAll(NetworkReader reader)
base.Value = Pack(netId, componentIndex);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void OnDeserializeDelta(NetworkReader reader) =>
OnDeserializeAll(reader);
}

View File

@ -48,7 +48,9 @@ public class SyncVarNetworkIdentity : SyncVar<uint>
// .spawned lookup from netId overwrites base uint .Value
public new NetworkIdentity Value
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => Utils.GetSpawnedInServerOrClient(base.Value);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => base.Value = value != null ? value.netId : 0;
}
@ -57,6 +59,7 @@ public class SyncVarNetworkIdentity : SyncVar<uint>
public new event Action<NetworkIdentity, NetworkIdentity> Callback;
// overwrite CallCallback to use the NetworkIdentity version instead
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected override void InvokeCallback(uint oldValue, uint newValue) =>
Callback?.Invoke(Utils.GetSpawnedInServerOrClient(oldValue), Utils.GetSpawnedInServerOrClient(newValue));
@ -69,10 +72,12 @@ public SyncVarNetworkIdentity(NetworkIdentity value = null)
: base(value != null ? value.netId : 0) {}
// implicit conversion: NetworkIdentity value = SyncFieldNetworkIdentity
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator NetworkIdentity(SyncVarNetworkIdentity field) => field.Value;
// implicit conversion: SyncFieldNetworkIdentity = value
// even if SyncField is readonly, it's still useful: SyncFieldNetworkIdentity = target;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator SyncVarNetworkIdentity(NetworkIdentity value) => new SyncVarNetworkIdentity(value);
// NOTE: overloading all == operators blocks '== null' checks with an
@ -104,7 +109,10 @@ public SyncVarNetworkIdentity(NetworkIdentity value = null)
public static bool operator !=(NetworkIdentity a, SyncVarNetworkIdentity b) => !(a == b);
// if we overwrite == operators, we also need to overwrite .Equals.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj) => obj is SyncVarNetworkIdentity value && this == value;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() => Value.GetHashCode();
}
}