Skip to content

Commit

Permalink
replace LocalOnly and UpdateableEntity by SetEntityFlags attribute wi…
Browse files Browse the repository at this point in the history
…th additional features. Added EntityFlags.OnlyForOwner and OnlyForOthers to control full sync of entity
  • Loading branch information
RevenantX committed Sep 9, 2024
1 parent d8d8f7d commit ae5cc78
Show file tree
Hide file tree
Showing 10 changed files with 52 additions and 50 deletions.
8 changes: 5 additions & 3 deletions LiteEntitySystem/ClientEntityManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ protected override unsafe void OnLogicTick()
}
}
}
else if(classData.UpdateOnClient)
else if(classData.Flags.HasFlagFast(EntityFlags.UpdateOnClient))
{
entity.Update();
}
Expand Down Expand Up @@ -755,13 +755,15 @@ public override unsafe void Update()

internal void AddOwned(EntityLogic entity)
{
if (entity.GetClassData().IsUpdateable && !entity.GetClassData().UpdateOnClient)
var flags = entity.GetClassData().Flags;
if (flags.HasFlagFast(EntityFlags.Updateable) && !flags.HasFlagFast(EntityFlags.UpdateOnClient))
AliveEntities.Add(entity);
}

internal void RemoveOwned(EntityLogic entity)
{
if (entity.GetClassData().IsUpdateable && !entity.GetClassData().UpdateOnClient)
var flags = entity.GetClassData().Flags;
if (flags.HasFlagFast(EntityFlags.Updateable) && !flags.HasFlagFast(EntityFlags.UpdateOnClient))
AliveEntities.Remove(entity);
}

Expand Down
5 changes: 3 additions & 2 deletions LiteEntitySystem/ControllerLogic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace LiteEntitySystem
/// <summary>
/// Base class for Controller entities
/// </summary>
[SetEntityFlags(EntityFlags.OnlyForOwner)]
public abstract class ControllerLogic : InternalEntity
{
[SyncVarFlags(SyncFlags.NeverRollBack)]
Expand Down Expand Up @@ -58,7 +59,7 @@ protected ControllerLogic(EntityParams entityParams) : base(entityParams) { }
/// <summary>
/// Base class for AI Controller entities
/// </summary>
[LocalOnly, UpdateableEntity]
[SetEntityFlags(EntityFlags.LocalOnly | EntityFlags.Updateable)]
public abstract class AiControllerLogic : ControllerLogic
{
public override bool IsBot => true;
Expand All @@ -69,7 +70,7 @@ protected AiControllerLogic(EntityParams entityParams) : base(entityParams) { }
/// <summary>
/// Base class for AI Controller entities with typed ControlledEntity field
/// </summary>
[LocalOnly, UpdateableEntity]
[SetEntityFlags(EntityFlags.LocalOnly | EntityFlags.Updateable)]
public abstract class AiControllerLogic<T> : AiControllerLogic where T : PawnLogic
{
public T ControlledEntity => GetControlledEntity<T>();
Expand Down
29 changes: 14 additions & 15 deletions LiteEntitySystem/EntityLogic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,27 @@

namespace LiteEntitySystem
{
/// <summary>
/// Entity has update method
/// </summary>
[Flags]
public enum EntityFlags
{
UpdateOnClient = Updateable | (1 << 0), //Update entity on client even when entity isn't owned
Updateable = 1 << 1, //Entity has update method
LocalOnly = 1 << 2, //Entity is local only (only on server or client no difference)
OnlyForOwner = 1 << 3, //Sync entity only for owner player
OnlyForOthers = 1 << 4 //Sync entity only for other players
}

[AttributeUsage(AttributeTargets.Class)]
public class UpdateableEntity : Attribute
public class SetEntityFlags : Attribute
{
public readonly bool UpdateOnClient;

public UpdateableEntity() { }
public readonly EntityFlags Flags;

public UpdateableEntity(bool updateOnClient)
public SetEntityFlags(EntityFlags flags)
{
UpdateOnClient = updateOnClient;
Flags = flags;
}
}

/// <summary>
/// Entity is local only (only on server or client no difference)
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class LocalOnly : Attribute { }

/// <summary>
/// Base class for simple (not controlled by controller) entity
/// </summary>
Expand Down
4 changes: 2 additions & 2 deletions LiteEntitySystem/EntityManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ private static bool IsEntityLagCompensated(InternalEntity e)
=> !e.IsLocal && e is EntityLogic { HasLagCompensation: true };

private bool IsEntityAlive(EntityClassData classData, InternalEntity entity)
=> classData.IsUpdateable && (IsServer || entity.IsLocal || (IsClient && classData.UpdateOnClient));
=> classData.Flags.HasFlagFast(EntityFlags.Updateable) && (IsServer || entity.IsLocal || (IsClient && classData.Flags.HasFlagFast(EntityFlags.UpdateOnClient)));

internal virtual void RemoveEntity(InternalEntity e)
{
Expand All @@ -522,7 +522,7 @@ internal virtual void RemoveEntity(InternalEntity e)
AliveEntities.Remove(e);
if(IsEntityLagCompensated(e))
LagCompensatedEntities.Remove((EntityLogic)e);
if (classData.IsLocalOnly)
if (classData.Flags.HasFlagFast(EntityFlags.LocalOnly))
_localIdQueue.ReuseId(e.Id);
EntitiesDict[e.Id] = null;
EntitiesCount--;
Expand Down
6 changes: 5 additions & 1 deletion LiteEntitySystem/EntityTypesMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ public ulong EvaluateEntityClassDataHash()
//don't hash localonly types
foreach (var (entType, _) in RegisteredTypes
.OrderBy(kv => kv.Value.ClassId)
.Where(kv => kv.Key.GetCustomAttribute<LocalOnly>(true) == null))
.Where(kv =>
{
var attr = kv.Key.GetCustomAttribute<SetEntityFlags>(true);
return attr == null || !attr.Flags.HasFlagFast(EntityFlags.LocalOnly);
}))
{
var allTypesStack = Utils.GetBaseTypes(entType, typeof(InternalEntity), true);
while(allTypesStack.Count > 0)
Expand Down
2 changes: 1 addition & 1 deletion LiteEntitySystem/HumanControllerLogic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace LiteEntitySystem
/// <summary>
/// Base class for human Controller entities
/// </summary>
[UpdateableEntity(true)]
[SetEntityFlags(EntityFlags.UpdateOnClient)]
public abstract class HumanControllerLogic<TInput> : ControllerLogic where TInput : unmanaged
{
private struct ServerResponse
Expand Down
24 changes: 7 additions & 17 deletions LiteEntitySystem/Internal/EntityClassData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,7 @@ internal struct EntityClassData
public readonly EntityFieldInfo[] LagCompensatedFields;
public readonly int LagCompensatedSize;
public readonly int LagCompensatedCount;
public readonly bool UpdateOnClient;
public readonly bool IsUpdateable;
public readonly bool IsLocalOnly;
public readonly EntityFlags Flags;
public readonly EntityConstructor<InternalEntity> EntityConstructor;
public RpcFieldInfo[] RemoteCallsClient;

Expand All @@ -81,20 +79,8 @@ public EntityClassData(ushort filterId, Type entType, RegisteredTypeInfo typeInf
RemoteCallsClient = null;

ClassId = typeInfo.ClassId;

var updateAttribute = entType.GetCustomAttribute<UpdateableEntity>();
if (updateAttribute != null)
{
IsUpdateable = true;
UpdateOnClient = updateAttribute.UpdateOnClient;
}
else
{
IsUpdateable = false;
UpdateOnClient = false;
}

IsLocalOnly = entType.GetCustomAttribute<LocalOnly>() != null;
Flags = 0;

EntityConstructor = typeInfo.Constructor;
IsSingleton = entType.IsSubclassOf(SingletonEntityType);
FilterId = filterId;
Expand All @@ -110,6 +96,10 @@ public EntityClassData(ushort filterId, Type entType, RegisteredTypeInfo typeInf
while(allTypesStack.Count > 0)
{
var baseType = allTypesStack.Pop();

var setFlagsAttribute = baseType.GetCustomAttribute<SetEntityFlags>();
Flags |= setFlagsAttribute != null ? setFlagsAttribute.Flags : 0;

//cache fields
foreach (var field in Utils.GetProcessedFields(baseType))
{
Expand Down
20 changes: 13 additions & 7 deletions LiteEntitySystem/Internal/StateSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ private enum RPCMode
private EntityFieldInfo[] _fields;
private int _fieldsCount;
private int _fieldsFlagsSize;
private EntityFlags _flags;

private InternalEntity _entity;
private byte[] _latestEntityData;
Expand All @@ -44,7 +45,6 @@ private enum RPCMode
private RemoteCallPacket _rpcTail;
private RemoteCallPacket _syncRpcHead;
private RemoteCallPacket _syncRpcTail;
private bool _isController;
private uint _fullDataSize;
private int _syncFrame;
private RPCMode _rpcMode;
Expand Down Expand Up @@ -104,6 +104,7 @@ public void AllocateMemory(ref EntityClassData classData)
_fieldsCount = classData.FieldsCount;
_fieldsFlagsSize = classData.FieldsFlagsSize;
_fullDataSize = (uint)(HeaderSize + classData.FixedFieldsSize);
_flags = classData.Flags;

//resize or clean prev data
if (_latestEntityData == null || _latestEntityData.Length < _fullDataSize)
Expand All @@ -121,7 +122,6 @@ public unsafe void Init(InternalEntity e, ushort tick)
_state = SerializerState.Active;
_syncFrame = -1;
_rpcMode = RPCMode.Normal;
_isController = e is ControllerLogic;
_versionChangedTick = tick;
LastChangedTick = tick;

Expand Down Expand Up @@ -242,10 +242,13 @@ private unsafe void WriteInitialState(bool isOwned, ushort serverTick, byte* res
public unsafe void MakeBaseline(byte playerId, ushort serverTick, byte* resultData, ref int position)
{
//skip inactive and other controlled controllers
if (_state != SerializerState.Active || (_isController && playerId != _entity.InternalOwnerId.Value))
bool isOwned = _entity.InternalOwnerId.Value == playerId;
if (_state != SerializerState.Active ||
(_flags.HasFlagFast(EntityFlags.OnlyForOwner) && !isOwned) ||
(_flags.HasFlagFast(EntityFlags.OnlyForOthers) && isOwned))
return;
//don't write total size in full sync and fields
WriteInitialState(_entity.InternalOwnerId.Value == playerId, serverTick, resultData, ref position);
WriteInitialState(isOwned, serverTick, resultData, ref position);
//Logger.Log($"[SEM] SendBaseline for entity: {_entity.Id}, pos: {position}, posAfterData: {position + _fullDataSize}");
}

Expand All @@ -267,11 +270,14 @@ public unsafe DiffResult MakeDiff(byte playerId, ushort serverTick, ushort minim
}

//make diff
int startPos = position;
bool isOwned = _entity.InternalOwnerId.Value == playerId;
if (_isController && !isOwned)
if ((_flags.HasFlagFast(EntityFlags.OnlyForOwner) && !isOwned) ||
(_flags.HasFlagFast(EntityFlags.OnlyForOthers) && isOwned))
{
return DiffResult.Skip;

}

int startPos = position;
//at 0 ushort
ushort* fieldFlagAndSize = (ushort*)(resultData + startPos);
position += sizeof(ushort);
Expand Down
2 changes: 1 addition & 1 deletion LiteEntitySystem/PawnLogic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/// <summary>
/// Base class for entites that can be controlled by Controller
/// </summary>
[UpdateableEntity]
[SetEntityFlags(EntityFlags.Updateable)]
public abstract class PawnLogic : EntityLogic
{
[SyncVarFlags(SyncFlags.OnlyForOwner)]
Expand Down
2 changes: 1 addition & 1 deletion LiteEntitySystem/ServerEntityManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ private T Add<T>(Action<T> initMethod) where T : InternalEntity
ref var classData = ref ClassDataDict[EntityClassInfo<T>.ClassId];
T entity;

if (classData.IsLocalOnly)
if (classData.Flags.HasFlagFast(EntityFlags.LocalOnly))
{
entity = AddLocalEntity(initMethod);
}
Expand Down

0 comments on commit ae5cc78

Please sign in to comment.