Adds ComponentGetState ECS event (#1988)

This commit is contained in:
Vera Aguilera Puerto
2021-08-29 17:23:40 +02:00
committed by GitHub
parent b982b94c83
commit 051d47f4ff
9 changed files with 93 additions and 43 deletions

View File

@@ -51,6 +51,7 @@ namespace Robust.Client.GameStates
[Dependency] private readonly IClientGameTiming _timing = default!;
[Dependency] private readonly INetConfigurationManager _config = default!;
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
[Dependency] private readonly IClientEntityManager _entityManager = default!;
[Dependency] private readonly IComponentManager _componentManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
#if EXCEPTION_TOLERANCE
@@ -335,8 +336,6 @@ namespace Robust.Client.GameStates
private void ResetPredictedEntities(GameTick curTick)
{
var bus = (EntityEventBus) _entities.EventBus;
foreach (var entity in _entities.GetEntities())
{
// TODO: 99% there's an off-by-one here.
@@ -366,7 +365,7 @@ namespace Robust.Client.GameStates
Logger.DebugS(CVars.NetPredict.Name, $" And also its component {comp.Name}");
// TODO: Handle interpolation.
var handleState = new ComponentHandleState(compState, null);
bus.RaiseComponentEvent(comp, ref handleState);
_entities.EventBus.RaiseComponentEvent(comp, ref handleState);
comp.HandleComponentState(compState, null);
}
}
@@ -383,6 +382,8 @@ namespace Robust.Client.GameStates
Debug.Assert(_players.LocalPlayer != null, "_players.LocalPlayer != null");
var player = _players.LocalPlayer.Session;
var bus = _entityManager.EventBus;
foreach (var createdEntity in createdEntities)
{
var compData = new Dictionary<uint, ComponentState>();
@@ -390,7 +391,7 @@ namespace Robust.Client.GameStates
foreach (var (netId, component) in _componentManager.GetNetComponents(createdEntity))
{
var state = component.GetComponentState(player);
var state = _componentManager.GetComponentState(bus, component, player);
if(state.GetType() == typeof(ComponentState))
continue;
@@ -474,14 +475,12 @@ namespace Robust.Client.GameStates
}
}
var bus = (EntityEventBus) _entities.EventBus;
// Make sure this is done after all entities have been instantiated.
foreach (var kvStates in toApply)
{
var ent = kvStates.Key;
var entity = (Entity) ent;
HandleEntityState(entity.EntityManager.ComponentManager, entity, bus, kvStates.Value.Item1,
HandleEntityState(entity.EntityManager.ComponentManager, entity, _entities.EventBus, kvStates.Value.Item1,
kvStates.Value.Item2);
}
@@ -549,7 +548,7 @@ namespace Robust.Client.GameStates
return created;
}
private void HandleEntityState(IComponentManager compMan, IEntity entity, EntityEventBus bus, EntityState? curState,
private void HandleEntityState(IComponentManager compMan, IEntity entity, IEventBus bus, EntityState? curState,
EntityState? nextState)
{
var compStateWork = new Dictionary<ushort, (ComponentState? curState, ComponentState? nextState)>();

View File

@@ -254,7 +254,7 @@ namespace Robust.Server.GameStates
if (ent.LastModifiedTick < lastSeenChunk)
continue;
var newState = ServerGameStateManager.GetEntityState(_entMan.ComponentManager, session, anchoredEnt, lastSeenChunk);
var newState = ServerGameStateManager.GetEntityState(_entMan, session, anchoredEnt, lastSeenChunk);
entityStates.Add(newState);
}
@@ -332,7 +332,7 @@ namespace Robust.Server.GameStates
continue;
// only send new changes
var newState = ServerGameStateManager.GetEntityState(_entMan.ComponentManager, session, entityUid, fromTick);
var newState = ServerGameStateManager.GetEntityState(_entMan, session, entityUid, fromTick);
if (!newState.Empty)
entityStates.Add(newState);
@@ -342,7 +342,7 @@ namespace Robust.Server.GameStates
// PVS enter message
// don't assume the client knows anything about us
var newState = ServerGameStateManager.GetEntityState(_entMan.ComponentManager, session, entityUid, GameTick.Zero);
var newState = ServerGameStateManager.GetEntityState(_entMan, session, entityUid, GameTick.Zero);
entityStates.Add(newState);
}
}

View File

@@ -268,13 +268,15 @@ namespace Robust.Server.GameStates
/// <summary>
/// Generates a network entity state for the given entity.
/// </summary>
/// <param name="compMan">ComponentManager that contains the components for the entity.</param>
/// <param name="entMan">EntityManager that contains the entity.</param>
/// <param name="player">The player to generate this state for.</param>
/// <param name="entityUid">Uid of the entity to generate the state from.</param>
/// <param name="fromTick">Only provide delta changes from this tick.</param>
/// <returns>New entity State for the given entity.</returns>
internal static EntityState GetEntityState(IComponentManager compMan, ICommonSession player, EntityUid entityUid, GameTick fromTick)
internal static EntityState GetEntityState(IEntityManager entMan, ICommonSession player, EntityUid entityUid, GameTick fromTick)
{
var bus = entMan.EventBus;
var compMan = entMan.ComponentManager;
var changed = new List<ComponentChange>();
foreach (var (netId, component) in compMan.GetNetComponents(entityUid))
@@ -294,7 +296,7 @@ namespace Robust.Server.GameStates
{
ComponentState? state = null;
if (component.NetSyncEnabled && component.LastModifiedTick != GameTick.Zero && component.LastModifiedTick >= fromTick)
state = component.GetComponentState(player);
state = compMan.GetComponentState(bus, component, player);
// Can't be null since it's returned by GetNetComponents
// ReSharper disable once PossibleInvalidOperationException
@@ -302,7 +304,7 @@ namespace Robust.Server.GameStates
}
else if (component.NetSyncEnabled && component.LastModifiedTick != GameTick.Zero && component.LastModifiedTick >= fromTick)
{
changed.Add(ComponentChange.Changed(netId, component.GetComponentState(player)));
changed.Add(ComponentChange.Changed(netId, compMan.GetComponentState(bus, component, player)));
}
else if (component.Deleted && component.LastModifiedTick >= fromTick)
{
@@ -331,7 +333,7 @@ namespace Robust.Server.GameStates
DebugTools.Assert(entity.Initialized);
if (entity.LastModifiedTick >= fromTick)
stateEntities.Add(GetEntityState(entityMan.ComponentManager, player, entity.Uid, fromTick));
stateEntities.Add(GetEntityState(entityMan, player, entity.Uid, fromTick));
}
// no point sending an empty collection

View File

@@ -137,14 +137,14 @@ namespace Robust.Shared.GameObjects
private static readonly ComponentShutdown CompShutdownInstance = new();
private static readonly ComponentRemove CompRemoveInstance = new();
private EntityEventBus GetBus()
private IEventBus GetBus()
{
// Apparently components are being created outside of the ComponentManager,
// and the Owner is not being set correctly.
// ReSharper disable once RedundantAssertionStatement
DebugTools.AssertNotNull(Owner);
return (EntityEventBus) Owner.EntityManager.EventBus;
return Owner.EntityManager.EventBus;
}
/// <summary>

View File

@@ -6,7 +6,9 @@ using System.Linq;
using System.Runtime.CompilerServices;
using Internal.TypeSystem;
using Robust.Shared.Exceptions;
using Robust.Shared.GameStates;
using Robust.Shared.Physics;
using Robust.Shared.Players;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using DependencyAttribute = Robust.Shared.IoC.DependencyAttribute;
@@ -588,6 +590,15 @@ namespace Robust.Shared.GameObjects
}
}
/// <inheritdoc />
public ComponentState GetComponentState(IEventBus eventBus, IComponent component, ICommonSession player)
{
var getState = new ComponentGetState(player);
eventBus.RaiseComponentEvent(component, ref getState);
return getState.State ?? component.GetComponentState(player);
}
#endregion
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@@ -48,6 +48,32 @@ namespace Robust.Shared.GameObjects
void UnsubscribeLocalEvent<TComp, TEvent>()
where TComp : IComponent
where TEvent : notnull;
/// <summary>
/// Dispatches an event directly to a specific component.
/// </summary>
/// <remarks>
/// This has a very specific purpose, and has massive potential to be abused.
/// DO NOT EXPOSE THIS TO CONTENT.
/// </remarks>
/// <typeparam name="TEvent">Event to dispatch.</typeparam>
/// <param name="component">Component receiving the event.</param>
/// <param name="args">Event arguments for the event.</param>
internal void RaiseComponentEvent<TEvent>(IComponent component, TEvent args)
where TEvent : notnull;
/// <summary>
/// Dispatches an event directly to a specific component, by-ref.
/// </summary>
/// <remarks>
/// This has a very specific purpose, and has massive potential to be abused.
/// DO NOT EXPOSE THIS TO CONTENT.
/// </remarks>
/// <typeparam name="TEvent">Event to dispatch.</typeparam>
/// <param name="component">Component receiving the event.</param>
/// <param name="args">Event arguments for the event.</param>
internal void RaiseComponentEvent<TEvent>(IComponent component, ref TEvent args)
where TEvent : notnull;
}
internal partial class EntityEventBus : IDirectedEventBus, IEventBus, IDisposable
@@ -70,36 +96,16 @@ namespace Robust.Shared.GameObjects
_eventTables = new EventTables(_entMan);
}
/// <summary>
/// Dispatches an event directly to a specific component.
/// </summary>
/// <remarks>
/// This has a very specific purpose, and has massive potential to be abused.
/// DO NOT EXPOSE THIS TO CONTENT.
/// </remarks>
/// <typeparam name="TEvent">Event to dispatch.</typeparam>
/// <param name="component">Component receiving the event.</param>
/// <param name="args">Event arguments for the event.</param>
internal void RaiseComponentEvent<TEvent>(IComponent component, TEvent args)
where TEvent : notnull
/// <inheritdoc />
void IDirectedEventBus.RaiseComponentEvent<TEvent>(IComponent component, TEvent args)
{
ref var unitRef = ref Unsafe.As<TEvent, Unit>(ref args);
_eventTables.DispatchComponent<TEvent>(component.Owner.Uid, component, ref unitRef, false);
}
/// <summary>
/// Dispatches an event directly to a specific component, by-ref.
/// </summary>
/// <remarks>
/// This has a very specific purpose, and has massive potential to be abused.
/// DO NOT EXPOSE THIS TO CONTENT.
/// </remarks>
/// <typeparam name="TEvent">Event to dispatch.</typeparam>
/// <param name="component">Component receiving the event.</param>
/// <param name="args">Event arguments for the event.</param>
internal void RaiseComponentEvent<TEvent>(IComponent component, ref TEvent args)
where TEvent : notnull
/// <inheritdoc />
void IDirectedEventBus.RaiseComponentEvent<TEvent>(IComponent component, ref TEvent args)
{
ref var unitRef = ref Unsafe.As<TEvent, Unit>(ref args);

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using JetBrains.Annotations;
using Robust.Shared.Players;
namespace Robust.Shared.GameObjects
{
@@ -197,6 +198,15 @@ namespace Robust.Shared.GameObjects
/// <returns>All components that have a network ID.</returns>
NetComponentEnumerable GetNetComponents(EntityUid uid);
/// <summary>
/// Gets a component state for a certain player.
/// </summary>
/// <param name="eventBus">A reference to the event bus instance.</param>
/// <param name="component">Component to generate the state for.</param>
/// <param name="player">The player to generate the state for.</param>
/// <returns>The component state of the component, for the player.</returns>
ComponentState GetComponentState(IEventBus eventBus, IComponent component, ICommonSession player);
/// <summary>
/// Returns ALL component instances of a specified type.
/// </summary>

View File

@@ -14,4 +14,26 @@ namespace Robust.Shared.GameStates
Next = next;
}
}
/// <summary>
/// Component event for getting the component state for a specific player.
/// </summary>
public struct ComponentGetState
{
/// <summary>
/// Input parameter. The player the state is being generated for.
/// </summary>
public readonly ICommonSession Player;
/// <summary>
/// Output parameter. Set this to the component's state for the player.
/// </summary>
public ComponentState? State { get; set; }
public ComponentGetState(ICommonSession player)
{
Player = player;
State = null;
}
}
}

View File

@@ -156,7 +156,7 @@ namespace Robust.UnitTesting.Shared.GameObjects
compManMock.Raise(m => m.ComponentAdded += null, new AddedComponentEventArgs(compInstance, entUid));
// Raise
bus.RaiseComponentEvent(compInstance, new ComponentInit());
((IEventBus)bus).RaiseComponentEvent(compInstance, new ComponentInit());
// Assert
Assert.That(calledCount, Is.EqualTo(1));