mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
Session specific state support (#3249)
This commit is contained in:
@@ -567,7 +567,7 @@ namespace Robust.Client.GameStates
|
||||
foreach (var (netId, component) in _entityManager.GetNetComponents(createdEntity))
|
||||
{
|
||||
if (component.NetSyncEnabled)
|
||||
compData.Add(netId, _entityManager.GetComponentState(bus, component));
|
||||
compData.Add(netId, _entityManager.GetComponentState(bus, component, _players.LocalPlayer?.Session));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,76 @@ public sealed class ServerMetaDataSystem : MetaDataSystem
|
||||
{
|
||||
[Dependency] private readonly PVSSystem _pvsSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<MetaDataComponent, PlayerAttachedEvent>(OnActorPlayerAttach);
|
||||
|
||||
EntityManager.ComponentAdded += OnComponentAdded;
|
||||
EntityManager.ComponentRemoved += OnComponentRemoved;
|
||||
}
|
||||
|
||||
public override void Shutdown()
|
||||
{
|
||||
base.Shutdown();
|
||||
|
||||
EntityManager.ComponentAdded -= OnComponentAdded;
|
||||
EntityManager.ComponentRemoved -= OnComponentRemoved;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If a session-specific component gets added, make sure the meta-data flag is set.
|
||||
/// </summary>
|
||||
private void OnComponentAdded(AddedComponentEventArgs obj)
|
||||
{
|
||||
var comp = obj.BaseArgs.Component;
|
||||
if (comp.NetSyncEnabled && (comp.SessionSpecific || comp.SendOnlyToOwner))
|
||||
MetaData(obj.BaseArgs.Owner).Flags |= MetaDataFlags.SessionSpecific;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If a session-specific component gets removed, this will update the meta-data flag.
|
||||
/// </summary>
|
||||
private void OnComponentRemoved(RemovedComponentEventArgs obj)
|
||||
{
|
||||
var removed = obj.BaseArgs.Component;
|
||||
if (!removed.NetSyncEnabled || (!removed.SessionSpecific && !removed.SendOnlyToOwner))
|
||||
return;
|
||||
|
||||
var meta = MetaData(obj.BaseArgs.Owner);
|
||||
if (meta.EntityLifeStage >= EntityLifeStage.Terminating)
|
||||
return;
|
||||
|
||||
foreach (var (_, comp) in EntityManager.GetNetComponents(obj.BaseArgs.Owner))
|
||||
{
|
||||
if (comp.LifeStage >= ComponentLifeStage.Removing)
|
||||
continue;
|
||||
|
||||
if (comp.NetSyncEnabled && (comp.SessionSpecific || comp.SendOnlyToOwner))
|
||||
return; // keep the flag
|
||||
}
|
||||
|
||||
// remove the flag
|
||||
meta.Flags &= ~MetaDataFlags.SessionSpecific;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If a new player gets attached to an entity, this will ensure that the player receives session-restricted
|
||||
/// component states by dirtying any restricted components.
|
||||
/// </summary>
|
||||
private void OnActorPlayerAttach(EntityUid uid, MetaDataComponent meta, PlayerAttachedEvent args)
|
||||
{
|
||||
if ((meta.Flags & MetaDataFlags.SessionSpecific) == 0)
|
||||
return;
|
||||
|
||||
foreach (var (_, comp) in EntityManager.GetNetComponents(uid))
|
||||
{
|
||||
if (comp.SessionSpecific || comp.SendOnlyToOwner)
|
||||
Dirty(comp);
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetVisibilityMask(EntityUid uid, int value, MetaDataComponent? meta = null)
|
||||
{
|
||||
if (!Resolve(uid, ref meta) || meta.VisibilityMask == value)
|
||||
|
||||
@@ -1051,9 +1051,6 @@ internal sealed partial class PVSSystem : EntitySystem
|
||||
var bus = EntityManager.EventBus;
|
||||
var changed = new List<ComponentChange>();
|
||||
|
||||
// Whether this entity has any component states that should only be sent to specific sessions.
|
||||
var entitySpecific = (meta.Flags & MetaDataFlags.EntitySpecific) == MetaDataFlags.EntitySpecific;
|
||||
|
||||
foreach (var (netId, component) in EntityManager.GetNetComponents(entityUid))
|
||||
{
|
||||
if (!component.NetSyncEnabled)
|
||||
@@ -1083,10 +1080,10 @@ internal sealed partial class PVSSystem : EntitySystem
|
||||
if (component.SendOnlyToOwner && player.AttachedEntity != component.Owner)
|
||||
continue;
|
||||
|
||||
if (entitySpecific && !EntityManager.CanGetComponentState(bus, component, player))
|
||||
if (component.SessionSpecific && !EntityManager.CanGetComponentState(bus, component, player))
|
||||
continue;
|
||||
|
||||
var state = changedState ? EntityManager.GetComponentState(bus, component) : null;
|
||||
var state = changedState ? EntityManager.GetComponentState(bus, component, component.SessionSpecific ? player : null) : null;
|
||||
changed.Add(ComponentChange.Added(netId, state, component.LastModifiedTick));
|
||||
}
|
||||
|
||||
@@ -1105,7 +1102,6 @@ internal sealed partial class PVSSystem : EntitySystem
|
||||
{
|
||||
var bus = EntityManager.EventBus;
|
||||
var changed = new List<ComponentChange>();
|
||||
var entitySpecific = (meta.Flags & MetaDataFlags.EntitySpecific) == MetaDataFlags.EntitySpecific;
|
||||
|
||||
foreach (var (netId, component) in EntityManager.GetNetComponents(entityUid))
|
||||
{
|
||||
@@ -1115,10 +1111,10 @@ internal sealed partial class PVSSystem : EntitySystem
|
||||
if (component.SendOnlyToOwner && player.AttachedEntity != component.Owner)
|
||||
continue;
|
||||
|
||||
if (entitySpecific && !EntityManager.CanGetComponentState(bus, component, player))
|
||||
if (component.SessionSpecific && !EntityManager.CanGetComponentState(bus, component, player))
|
||||
continue;
|
||||
|
||||
changed.Add(ComponentChange.Added(netId, EntityManager.GetComponentState(bus, component), component.LastModifiedTick));
|
||||
changed.Add(ComponentChange.Added(netId, EntityManager.GetComponentState(bus, component, component.SessionSpecific ? player : null), component.LastModifiedTick));
|
||||
}
|
||||
|
||||
foreach (var netId in _serverEntManager.GetDeletedComponents(entityUid, GameTick.Zero))
|
||||
|
||||
@@ -23,7 +23,16 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
/// <inheritdoc />
|
||||
[DataField("netsync")]
|
||||
public bool NetSyncEnabled { get; set; } = true;
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool _netSync { get; set; } = true;
|
||||
|
||||
internal bool Networked = true;
|
||||
|
||||
public bool NetSyncEnabled
|
||||
{
|
||||
get => Networked && _netSync;
|
||||
set => _netSync = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[ViewVariables]
|
||||
@@ -35,11 +44,17 @@ namespace Robust.Shared.GameObjects
|
||||
|
||||
/// <summary>
|
||||
/// If true, and if this is a networked component, then component data will only be sent to players if their
|
||||
/// controlled entity is the owner of this component. This is a faster alternative to <see
|
||||
/// cref="MetaDataFlags.EntitySpecific"/>.
|
||||
/// controlled entity is the owner of this component. This is less performance intensive than <see cref="SessionSpecific"/>.
|
||||
/// </summary>
|
||||
public virtual bool SendOnlyToOwner => false;
|
||||
|
||||
/// <summary>
|
||||
/// If true, and if this is a networked component, then this component will cause <see
|
||||
/// cref="ComponentGetStateAttemptEvent"/> events to be raised to check whether a given player should
|
||||
/// receive this component's state.
|
||||
/// </summary>
|
||||
public virtual bool SessionSpecific => false;
|
||||
|
||||
/// <summary>
|
||||
/// Increases the life stage from <see cref="ComponentLifeStage.PreAdd" /> to <see cref="ComponentLifeStage.Added" />,
|
||||
/// after raising a <see cref="ComponentAdd"/> event.
|
||||
|
||||
@@ -205,10 +205,9 @@ namespace Robust.Shared.GameObjects
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Whether the entity has states specific to particular players. This will cause many state-attempt events to
|
||||
/// be raised, and is generally somewhat expensive.
|
||||
/// Whether the entity has any component that has state information specific to particular players.
|
||||
/// </summary>
|
||||
EntitySpecific = 1 << 0,
|
||||
SessionSpecific = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// Whether the entity is currently inside of a container.
|
||||
|
||||
@@ -320,6 +320,10 @@ namespace Robust.Shared.GameObjects
|
||||
// mark the component as dirty for networking
|
||||
Dirty(component);
|
||||
}
|
||||
else
|
||||
{
|
||||
component.Networked = false;
|
||||
}
|
||||
|
||||
var eventArgs = new AddedComponentEventArgs(new ComponentEventArgs(component, uid), reg.Idx);
|
||||
ComponentAdded?.Invoke(eventArgs);
|
||||
@@ -1167,10 +1171,10 @@ namespace Robust.Shared.GameObjects
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ComponentState GetComponentState(IEventBus eventBus, IComponent component)
|
||||
public ComponentState GetComponentState(IEventBus eventBus, IComponent component, ICommonSession? session)
|
||||
{
|
||||
DebugTools.Assert(component.NetSyncEnabled, $"Attempting to get component state for an un-synced component: {component.GetType()}");
|
||||
var getState = new ComponentGetState();
|
||||
var getState = new ComponentGetState(session);
|
||||
eventBus.RaiseComponentEvent(component, ref getState);
|
||||
|
||||
return getState.State ?? component.GetComponentState();
|
||||
|
||||
@@ -365,7 +365,7 @@ namespace Robust.Shared.GameObjects
|
||||
/// <param name="component">Component to generate the state for.</param>
|
||||
/// <returns>The component state of the component.</returns>
|
||||
///
|
||||
ComponentState GetComponentState(IEventBus eventBus, IComponent component);
|
||||
ComponentState GetComponentState(IEventBus eventBus, IComponent component, ICommonSession? player);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a certain player should get a component state.
|
||||
|
||||
@@ -26,6 +26,17 @@ namespace Robust.Shared.GameStates
|
||||
/// Output parameter. Set this to the component's state for the player.
|
||||
/// </summary>
|
||||
public ComponentState? State { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Input parameter. The player the state is being sent to.
|
||||
/// </summary>
|
||||
public readonly ICommonSession? Player;
|
||||
|
||||
public ComponentGetState(ICommonSession? player)
|
||||
{
|
||||
Player = player;
|
||||
State = null;
|
||||
}
|
||||
}
|
||||
|
||||
[ByRefEvent, ComponentEvent]
|
||||
|
||||
Reference in New Issue
Block a user