diff --git a/LiteEntitySystem/ClientEntityManager.cs b/LiteEntitySystem/ClientEntityManager.cs index ad0db98..43c9432 100644 --- a/LiteEntitySystem/ClientEntityManager.cs +++ b/LiteEntitySystem/ClientEntityManager.cs @@ -157,10 +157,10 @@ private readonly struct SyncCallInfo { public readonly InternalEntity Entity; - private readonly OnSyncCallDelegate _onSync; + private readonly MethodCallDelegate _onSync; private readonly int _prevDataPos; - public SyncCallInfo(OnSyncCallDelegate onSync, InternalEntity entity, int prevDataPos) + public SyncCallInfo(MethodCallDelegate onSync, InternalEntity entity, int prevDataPos) { _onSync = onSync; Entity = entity; diff --git a/LiteEntitySystem/Internal/EntityFieldInfo.cs b/LiteEntitySystem/Internal/EntityFieldInfo.cs index e97798f..d516d5c 100644 --- a/LiteEntitySystem/Internal/EntityFieldInfo.cs +++ b/LiteEntitySystem/Internal/EntityFieldInfo.cs @@ -25,7 +25,7 @@ internal struct EntityFieldInfo public readonly bool IsPredicted; public OnSyncExecutionOrder OnSyncExecutionOrder; - public OnSyncCallDelegate OnSync; + public MethodCallDelegate OnSync; public int FixedOffset; public int PredictedOffset; diff --git a/LiteEntitySystem/Internal/InternalBaseClass.cs b/LiteEntitySystem/Internal/InternalBaseClass.cs index da45d92..3b0d9b0 100644 --- a/LiteEntitySystem/Internal/InternalBaseClass.cs +++ b/LiteEntitySystem/Internal/InternalBaseClass.cs @@ -1,22 +1,7 @@ -using System; -using System.Runtime.CompilerServices; - namespace LiteEntitySystem.Internal { public abstract class InternalBaseClass { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected void ExecuteRPC(in RemoteCall rpc) => rpc.Call(this); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected void ExecuteRPC<T>(in RemoteCall<T> rpc, T value) where T : unmanaged => rpc.Call(this, value); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected void ExecuteRPC<T>(in RemoteCallSpan<T> rpc, ReadOnlySpan<T> value) where T : unmanaged => rpc.Call(this, value); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected void ExecuteRPC<T>(in RemoteCallSerializable<T> rpc, T value) where T : struct, ISpanSerializable => rpc.Call(this, value); - protected internal virtual void OnSyncRequested() { diff --git a/LiteEntitySystem/Internal/InternalEntity.cs b/LiteEntitySystem/Internal/InternalEntity.cs index 1c2b98c..3cc31d4 100644 --- a/LiteEntitySystem/Internal/InternalEntity.cs +++ b/LiteEntitySystem/Internal/InternalEntity.cs @@ -203,7 +203,7 @@ protected internal virtual void OnConstructed() internal void RegisterRpcInternal() { - ref var classData = ref EntityManager.ClassDataDict[ClassId]; + ref var classData = ref EntityManager.ClassDataDict[ClassId]; //setup field ids for BindOnChange and pass on server this for OnChangedEvent to StateSerializer var onChangeTarget = EntityManager.IsServer && !IsLocal ? this : null; @@ -225,7 +225,7 @@ internal void RegisterRpcInternal() if(classData.RemoteCallsClient == null) { rpcCahce = new List<RpcFieldInfo>(); - var rpcRegistrator = new RPCRegistrator(rpcCahce); + var rpcRegistrator = new RPCRegistrator(rpcCahce, classData.Fields); RegisterRPC(ref rpcRegistrator); //Logger.Log($"RegisterRPCs for class: {classData.ClassId}"); } @@ -266,6 +266,59 @@ protected virtual void RegisterRPC(ref RPCRegistrator r) { r.BindOnChange(this, ref _isDestroyed, OnDestroyChange); } + + protected void ExecuteRPC(in RemoteCall rpc) + { + if (IsServer) + { + if (rpc.Flags.HasFlagFast(ExecuteFlags.ExecuteOnServer)) + rpc.CachedAction(this); + ServerManager.AddRemoteCall(this, rpc.Id, rpc.Flags); + } + else if (rpc.Flags.HasFlagFast(ExecuteFlags.ExecuteOnPrediction) && IsLocalControlled) + rpc.CachedAction(this); + } + + protected void ExecuteRPC<T>(in RemoteCall<T> rpc, T value) where T : unmanaged + { + if (IsServer) + { + if (rpc.Flags.HasFlagFast(ExecuteFlags.ExecuteOnServer)) + rpc.CachedAction(this, value); + unsafe + { + ServerManager.AddRemoteCall(this, new ReadOnlySpan<T>(&value, 1), rpc.Id, rpc.Flags); + } + } + else if (rpc.Flags.HasFlagFast(ExecuteFlags.ExecuteOnPrediction) && IsLocalControlled) + rpc.CachedAction(this, value); + } + + protected void ExecuteRPC<T>(in RemoteCallSpan<T> rpc, ReadOnlySpan<T> value) where T : unmanaged + { + if (IsServer) + { + if (rpc.Flags.HasFlagFast(ExecuteFlags.ExecuteOnServer)) + rpc.CachedAction(this, value); + ServerManager.AddRemoteCall(this, value, rpc.Id, rpc.Flags); + } + else if (rpc.Flags.HasFlagFast(ExecuteFlags.ExecuteOnPrediction) && IsLocalControlled) + rpc.CachedAction(this, value); + } + + protected void ExecuteRPC<T>(in RemoteCallSerializable<T> rpc, T value) where T : struct, ISpanSerializable + { + if (IsServer) + { + if (rpc.Flags.HasFlagFast(ExecuteFlags.ExecuteOnServer)) + rpc.CachedAction(this, value); + var writer = new SpanWriter(stackalloc byte[value.MaxSize]); + value.Serialize(ref writer); + ServerManager.AddRemoteCall<byte>(this, writer.RawData.Slice(0, writer.Position), rpc.Id, rpc.Flags); + } + else if (rpc.Flags.HasFlagFast(ExecuteFlags.ExecuteOnPrediction) && IsLocalControlled) + rpc.CachedAction(this, value); + } protected InternalEntity(EntityParams entityParams) { diff --git a/LiteEntitySystem/RPCRegistrator.cs b/LiteEntitySystem/RPCRegistrator.cs index 01dc932..31239cd 100644 --- a/LiteEntitySystem/RPCRegistrator.cs +++ b/LiteEntitySystem/RPCRegistrator.cs @@ -6,45 +6,71 @@ namespace LiteEntitySystem { public delegate void SpanAction<T>(ReadOnlySpan<T> data); - public delegate void SpanAction<TCaller, T>(TCaller caller, ReadOnlySpan<T> data); + public delegate void SpanAction<in TCaller, T>(TCaller caller, ReadOnlySpan<T> data); internal delegate void MethodCallDelegate(object classPtr, ReadOnlySpan<byte> buffer); - internal delegate void OnSyncCallDelegate(object classPtr, ReadOnlySpan<byte> buffer); public readonly struct RemoteCall { - internal readonly Action<InternalBaseClass> CachedAction; - internal RemoteCall(Action<InternalBaseClass> action) => CachedAction = action; - internal void Call(InternalBaseClass self) => CachedAction?.Invoke(self); internal static MethodCallDelegate CreateMCD<TClass>(Action<TClass> methodToCall) => (classPtr, _) => methodToCall((TClass)classPtr); + + internal readonly Action<InternalEntity> CachedAction; + internal readonly ushort Id; + internal readonly ExecuteFlags Flags; + internal readonly bool Initialized; + + internal RemoteCall(Action<InternalEntity> action, ushort rpcId, ExecuteFlags flags) + { + CachedAction = action; + Id = rpcId; + Flags = flags; + Initialized = true; + } } public readonly struct RemoteCall<T> where T : unmanaged { - internal readonly Action<InternalBaseClass, T> CachedAction; - internal RemoteCall(Action<InternalBaseClass, T> action) => CachedAction = action; - internal void Call(InternalBaseClass self, T data) => CachedAction?.Invoke(self, data); internal static unsafe MethodCallDelegate CreateMCD<TClass>(Action<TClass, T> methodToCall) => (classPtr, buffer) => { fixed (byte* data = buffer) methodToCall((TClass)classPtr, *(T*)data); }; + + internal readonly Action<InternalEntity, T> CachedAction; + internal readonly ushort Id; + internal readonly ExecuteFlags Flags; + internal readonly bool Initialized; + + internal RemoteCall(Action<InternalEntity, T> action, ushort rpcId, ExecuteFlags flags) + { + CachedAction = action; + Id = rpcId; + Flags = flags; + Initialized = true; + } } public readonly struct RemoteCallSpan<T> where T : unmanaged { - internal readonly SpanAction<InternalBaseClass, T> CachedAction; - internal RemoteCallSpan(SpanAction<InternalBaseClass, T> action) => CachedAction = action; - internal void Call(InternalBaseClass self, ReadOnlySpan<T> data) => CachedAction?.Invoke(self, data); internal static MethodCallDelegate CreateMCD<TClass>(SpanAction<TClass, T> methodToCall) => (classPtr, buffer) => methodToCall((TClass)classPtr, MemoryMarshal.Cast<byte, T>(buffer)); + + internal readonly SpanAction<InternalEntity, T> CachedAction; + internal readonly ushort Id; + internal readonly ExecuteFlags Flags; + internal readonly bool Initialized; + + internal RemoteCallSpan(SpanAction<InternalEntity, T> action, ushort rpcId, ExecuteFlags flags) + { + CachedAction = action; + Id = rpcId; + Flags = flags; + Initialized = true; + } } public readonly struct RemoteCallSerializable<T> where T : struct, ISpanSerializable { - internal readonly Action<InternalBaseClass, T> CachedAction; - internal RemoteCallSerializable(Action<InternalBaseClass, T> action) => CachedAction = action; - internal void Call(InternalBaseClass self, T data) => CachedAction?.Invoke(self, data); internal static MethodCallDelegate CreateMCD<TClass>(Action<TClass, T> methodToCall) => (classPtr, buffer) => { @@ -53,15 +79,30 @@ internal static MethodCallDelegate CreateMCD<TClass>(Action<TClass, T> methodToC t.Deserialize(ref spanReader); methodToCall((TClass)classPtr, t); }; + + internal readonly Action<InternalEntity, T> CachedAction; + internal readonly ushort Id; + internal readonly ExecuteFlags Flags; + internal readonly bool Initialized; + + internal RemoteCallSerializable(Action<InternalEntity, T> action, ushort rpcId, ExecuteFlags flags) + { + CachedAction = action; + Id = rpcId; + Flags = flags; + Initialized = true; + } } public readonly ref struct RPCRegistrator { private readonly List<RpcFieldInfo> _calls; + private readonly EntityFieldInfo[] _fields; - internal RPCRegistrator(List<RpcFieldInfo> remoteCallsList) + internal RPCRegistrator(List<RpcFieldInfo> remoteCallsList, EntityFieldInfo[] fields) { _calls = remoteCallsList; + _fields = fields; } internal static void CheckTarget(object ent, object target) @@ -69,16 +110,19 @@ internal static void CheckTarget(object ent, object target) if (ent != target) throw new Exception("You can call this only on this class methods"); } - - /// <summary> - /// Bind notification of SyncVar changes to action (OnSync will be called after RPCs and OnConstructs) + + /// <summary> + /// Bind notification of SyncVar changes to action /// </summary> - /// <param name="self">Target entity for binding</param> /// <param name="syncVar">Variable to bind</param> /// <param name="onChangedAction">Action that will be called when variable changes by sync</param> - public void BindOnChange<T, TEntity>(TEntity self, ref SyncVar<T> syncVar, Action<T> onChangedAction) where T : unmanaged where TEntity : InternalEntity + /// <param name="executionOrder">order of execution</param> + public void BindOnChange<T, TEntity>(ref SyncVar<T> syncVar, Action<TEntity, T> onChangedAction, OnSyncExecutionOrder executionOrder = OnSyncExecutionOrder.AfterConstruct) where T : unmanaged where TEntity : InternalEntity { - BindOnChange(self, ref syncVar, onChangedAction, self.ClassData.Fields[syncVar.FieldId].OnSyncExecutionOrder); + ref var field = ref _fields[syncVar.FieldId]; + field.OnSyncExecutionOrder = executionOrder; + var methodToCall = onChangedAction.Method.CreateDelegateHelper<Action<TEntity, T>>(); + field.OnSync = RemoteCall<T>.CreateMCD(methodToCall); } /// <summary> @@ -88,19 +132,15 @@ public void BindOnChange<T, TEntity>(TEntity self, ref SyncVar<T> syncVar, Actio /// <param name="syncVar">Variable to bind</param> /// <param name="onChangedAction">Action that will be called when variable changes by sync</param> /// <param name="executionOrder">order of execution</param> - public unsafe void BindOnChange<T, TEntity>(TEntity self, ref SyncVar<T> syncVar, Action<T> onChangedAction, OnSyncExecutionOrder executionOrder) where T : unmanaged where TEntity : InternalEntity + public void BindOnChange<T, TEntity>(TEntity self, ref SyncVar<T> syncVar, Action<T> onChangedAction, OnSyncExecutionOrder executionOrder = OnSyncExecutionOrder.AfterConstruct) where T : unmanaged where TEntity : InternalEntity { //if (self.EntityManager.IsServer) // return; CheckTarget(self, onChangedAction.Target); - ref var field = ref self.ClassData.Fields[syncVar.FieldId]; + ref var field = ref _fields[syncVar.FieldId]; field.OnSyncExecutionOrder = executionOrder; var methodToCall = onChangedAction.Method.CreateDelegateHelper<Action<TEntity, T>>(); - field.OnSync = (classPtr, buffer) => - { - fixed (byte* data = buffer) - methodToCall((TEntity)classPtr, *(T*)data); - }; + field.OnSync = RemoteCall<T>.CreateMCD(methodToCall); } /// <summary> @@ -165,22 +205,9 @@ public void CreateRPCAction<TEntity, T>(TEntity self, Action<T> methodToCall, re /// <param name="flags">RPC execution flags</param> public void CreateRPCAction<TEntity>(Action<TEntity> methodToCall, ref RemoteCall remoteCallHandle, ExecuteFlags flags) where TEntity : InternalEntity { - ushort rpcId = (ushort)_calls.Count; + if (!remoteCallHandle.Initialized) + remoteCallHandle = new RemoteCall(e => methodToCall((TEntity)e), (ushort)_calls.Count, flags); _calls.Add(new RpcFieldInfo(RemoteCall.CreateMCD(methodToCall))); - if (remoteCallHandle.CachedAction != null) - return; - remoteCallHandle = new RemoteCall(e => - { - var te = (TEntity)e; - if (te.IsServer) - { - if (flags.HasFlagFast(ExecuteFlags.ExecuteOnServer)) - methodToCall(te); - te.ServerManager.AddRemoteCall(te, rpcId, flags); - } - else if (flags.HasFlagFast(ExecuteFlags.ExecuteOnPrediction) && te.IsLocalControlled) - methodToCall(te); - }); } /// <summary> @@ -189,24 +216,11 @@ public void CreateRPCAction<TEntity>(Action<TEntity> methodToCall, ref RemoteCal /// <param name="methodToCall">RPC method to call</param> /// <param name="remoteCallHandle">output handle that should be used to call rpc</param> /// <param name="flags">RPC execution flags</param> - public unsafe void CreateRPCAction<TEntity, T>(Action<TEntity, T> methodToCall, ref RemoteCall<T> remoteCallHandle, ExecuteFlags flags) where T : unmanaged where TEntity : InternalEntity + public void CreateRPCAction<TEntity, T>(Action<TEntity, T> methodToCall, ref RemoteCall<T> remoteCallHandle, ExecuteFlags flags) where T : unmanaged where TEntity : InternalEntity { - ushort rpcId = (ushort)_calls.Count; + if (!remoteCallHandle.Initialized) + remoteCallHandle = new RemoteCall<T>((e, v) => methodToCall((TEntity)e, v), (ushort)_calls.Count, flags); _calls.Add(new RpcFieldInfo(RemoteCall<T>.CreateMCD(methodToCall))); - if (remoteCallHandle.CachedAction != null) - return; - remoteCallHandle = new RemoteCall<T>((e,v) => - { - var te = (TEntity)e; - if (te.IsServer) - { - if (flags.HasFlagFast(ExecuteFlags.ExecuteOnServer)) - methodToCall(te, v); - te.ServerManager.AddRemoteCall(te, new ReadOnlySpan<T>(&v, 1), rpcId, flags); - } - else if (flags.HasFlagFast(ExecuteFlags.ExecuteOnPrediction) && te.IsLocalControlled) - methodToCall(te, v); - }); } /// <summary> @@ -217,22 +231,9 @@ public unsafe void CreateRPCAction<TEntity, T>(Action<TEntity, T> methodToCall, /// <param name="flags">RPC execution flags</param> public void CreateRPCAction<TEntity, T>(SpanAction<TEntity, T> methodToCall, ref RemoteCallSpan<T> remoteCallHandle, ExecuteFlags flags) where T : unmanaged where TEntity : InternalEntity { - ushort rpcId = (ushort)_calls.Count; + if (!remoteCallHandle.Initialized) + remoteCallHandle = new RemoteCallSpan<T>((e,v) => methodToCall((TEntity)e, v), (ushort)_calls.Count, flags); _calls.Add(new RpcFieldInfo(RemoteCallSpan<T>.CreateMCD(methodToCall))); - if (remoteCallHandle.CachedAction != null) - return; - remoteCallHandle = new RemoteCallSpan<T>((e,v) => - { - var te = (TEntity)e; - if (te.IsServer) - { - if (flags.HasFlagFast(ExecuteFlags.ExecuteOnServer)) - methodToCall(te, v); - te.ServerManager.AddRemoteCall(te, v, rpcId, flags); - } - else if (flags.HasFlagFast(ExecuteFlags.ExecuteOnPrediction) && te.IsLocalControlled) - methodToCall(te, v); - }); } /// <summary> @@ -241,28 +242,14 @@ public void CreateRPCAction<TEntity, T>(SpanAction<TEntity, T> methodToCall, ref /// <param name="methodToCall">RPC method to call</param> /// <param name="remoteCallHandle">output handle that should be used to call rpc</param> /// <param name="flags">RPC execution flags</param> - public unsafe void CreateRPCAction<TEntity, T>(Action<TEntity, T> methodToCall, ref RemoteCallSerializable<T> remoteCallHandle, ExecuteFlags flags) + public void CreateRPCAction<TEntity, T>(Action<TEntity, T> methodToCall, ref RemoteCallSerializable<T> remoteCallHandle, ExecuteFlags flags) where T : struct, ISpanSerializable where TEntity : InternalEntity { ushort rpcId = (ushort)_calls.Count; _calls.Add(new RpcFieldInfo(RemoteCallSerializable<T>.CreateMCD(methodToCall))); - if (remoteCallHandle.CachedAction != null) - return; - remoteCallHandle = new RemoteCallSerializable<T>((e,v) => - { - var te = (TEntity)e; - if (te.IsServer) - { - if (flags.HasFlagFast(ExecuteFlags.ExecuteOnServer)) - methodToCall(te, v); - var writer = new SpanWriter(stackalloc byte[v.MaxSize]); - v.Serialize(ref writer); - te.ServerManager.AddRemoteCall<byte>(te, writer.RawData.Slice(0, writer.Position), rpcId, flags); - } - else if (flags.HasFlagFast(ExecuteFlags.ExecuteOnPrediction) && te.IsLocalControlled) - methodToCall(te, v); - }); + if (!remoteCallHandle.Initialized) + remoteCallHandle = new RemoteCallSerializable<T>((e,v) => methodToCall((TEntity)e, v), rpcId, flags); } } @@ -307,60 +294,32 @@ public void CreateClientAction<TSyncField>(Action<TSyncField> methodToCall, ref { ushort rpcId = _internalRpcCounter++; _calls.Add(new RpcFieldInfo(_syncableOffset, RemoteCall.CreateMCD(methodToCall))); - if (remoteCallHandle.CachedAction != null) - return; - remoteCallHandle = new RemoteCall(s => - { - var sf = (SyncableField)s; - if(sf.IsServer) - sf.ParentEntityInternal?.ServerManager.AddRemoteCall(sf.ParentEntityInternal, (ushort)(rpcId + sf.RPCOffset), sf.Flags); - }); + if (!remoteCallHandle.Initialized) + remoteCallHandle = new RemoteCall(null, rpcId, 0); } - public unsafe void CreateClientAction<TSyncField, T>(Action<TSyncField, T> methodToCall, ref RemoteCall<T> remoteCallHandle) where T : unmanaged where TSyncField : SyncableField + public void CreateClientAction<TSyncField, T>(Action<TSyncField, T> methodToCall, ref RemoteCall<T> remoteCallHandle) where T : unmanaged where TSyncField : SyncableField { ushort rpcId = _internalRpcCounter++; _calls.Add(new RpcFieldInfo(_syncableOffset, RemoteCall<T>.CreateMCD(methodToCall))); - if (remoteCallHandle.CachedAction != null) - return; - remoteCallHandle = new RemoteCall<T>((s, value) => - { - var sf = (SyncableField)s; - if(sf.IsServer) - sf.ParentEntityInternal?.ServerManager.AddRemoteCall(sf.ParentEntityInternal, new ReadOnlySpan<T>(&value, 1), (ushort)(rpcId + sf.RPCOffset), sf.Flags); - }); + if (!remoteCallHandle.Initialized) + remoteCallHandle = new RemoteCall<T>(null, rpcId, 0); } public void CreateClientAction<TSyncField, T>(SpanAction<TSyncField, T> methodToCall, ref RemoteCallSpan<T> remoteCallHandle) where T : unmanaged where TSyncField : SyncableField { ushort rpcId = _internalRpcCounter++; _calls.Add(new RpcFieldInfo(_syncableOffset, RemoteCallSpan<T>.CreateMCD(methodToCall))); - if (remoteCallHandle.CachedAction != null) - return; - remoteCallHandle = new RemoteCallSpan<T>((s, value) => - { - var sf = (SyncableField)s; - if(sf.IsServer) - sf.ParentEntityInternal?.ServerManager.AddRemoteCall(sf.ParentEntityInternal, value, (ushort)(rpcId + sf.RPCOffset), sf.Flags); - }); + if (!remoteCallHandle.Initialized) + remoteCallHandle = new RemoteCallSpan<T>(null, rpcId, 0); } - public unsafe void CreateClientAction<TSyncField, T>(Action<TSyncField, T> methodToCall, ref RemoteCallSerializable<T> remoteCallHandle) where T : struct, ISpanSerializable where TSyncField : SyncableField + public void CreateClientAction<TSyncField, T>(Action<TSyncField, T> methodToCall, ref RemoteCallSerializable<T> remoteCallHandle) where T : struct, ISpanSerializable where TSyncField : SyncableField { ushort rpcId = _internalRpcCounter++; _calls.Add(new RpcFieldInfo(_syncableOffset, RemoteCallSerializable<T>.CreateMCD(methodToCall))); - if (remoteCallHandle.CachedAction != null) - return; - remoteCallHandle = new RemoteCallSerializable<T>((s, value) => - { - var sf = (SyncableField)s; - if (sf.IsServer) - { - var writer = new SpanWriter(stackalloc byte[value.MaxSize]); - value.Serialize(ref writer); - sf.ParentEntityInternal?.ServerManager.AddRemoteCall<byte>(sf.ParentEntityInternal, writer.RawData.Slice(0, writer.Position), (ushort)(rpcId + sf.RPCOffset), sf.Flags); - } - }); + if (!remoteCallHandle.Initialized) + remoteCallHandle = new RemoteCallSerializable<T>(null, rpcId, 0); } } } \ No newline at end of file diff --git a/LiteEntitySystem/ServerEntityManager.cs b/LiteEntitySystem/ServerEntityManager.cs index 85ab36e..fc83360 100644 --- a/LiteEntitySystem/ServerEntityManager.cs +++ b/LiteEntitySystem/ServerEntityManager.cs @@ -614,7 +614,7 @@ protected override unsafe void OnLogicTick() } header->PacketType = InternalPackets.DiffSync; //Logger.LogWarning($"P:{pidx} Sending diff part {*partCount}: {_tick}"); - player.Peer.SendUnreliable(new ReadOnlySpan<byte>(_packetBuffer, 0, maxPartSize)); + player.Peer.SendUnreliable(new ReadOnlySpan<byte>(packetBuffer, maxPartSize)); header->Part++; //repeat in next packet diff --git a/LiteEntitySystem/SyncableField.cs b/LiteEntitySystem/SyncableField.cs index 99c596f..b1923f3 100644 --- a/LiteEntitySystem/SyncableField.cs +++ b/LiteEntitySystem/SyncableField.cs @@ -1,3 +1,5 @@ +using System; +using System.Runtime.CompilerServices; using LiteEntitySystem.Internal; namespace LiteEntitySystem @@ -42,5 +44,36 @@ protected internal virtual void RegisterRPC(ref SyncableRPCRegistrator r) { } + + protected void ExecuteRPC(in RemoteCall rpc) + { + if(IsServer) + ParentEntityInternal?.ServerManager.AddRemoteCall(ParentEntityInternal, (ushort)(rpc.Id + RPCOffset), rpc.Flags); + } + + protected void ExecuteRPC<T>(in RemoteCall<T> rpc, T value) where T : unmanaged + { + unsafe + { + if(IsServer) + ParentEntityInternal?.ServerManager.AddRemoteCall(ParentEntityInternal, new ReadOnlySpan<T>(&value, 1), (ushort)(rpc.Id + RPCOffset), Flags); + } + } + + protected void ExecuteRPC<T>(in RemoteCallSpan<T> rpc, ReadOnlySpan<T> value) where T : unmanaged + { + if(IsServer) + ParentEntityInternal?.ServerManager.AddRemoteCall(ParentEntityInternal, value, (ushort)(rpc.Id + RPCOffset), Flags); + } + + protected void ExecuteRPC<T>(in RemoteCallSerializable<T> rpc, T value) where T : struct, ISpanSerializable + { + if (IsServer) + { + var writer = new SpanWriter(stackalloc byte[value.MaxSize]); + value.Serialize(ref writer); + ParentEntityInternal?.ServerManager.AddRemoteCall<byte>(ParentEntityInternal, writer.RawData.Slice(0, writer.Position), (ushort)(rpc.Id + RPCOffset), Flags); + } + } } } \ No newline at end of file