Files
RobustToolbox/Robust.Shared/GameObjects/Systems/SharedGridTraversalSystem.cs
T
e5013d9e3f Add support for struct directed events, add by-ref directed/broadcast events. (#1931)
* Add support for struct directed events.
- Turn transform events into readonly structs

* TransformComponent events have readonly fields.

* Reduce boxing allocations, add DirectedRegistration readonly struct.

* Use typeof in a few places instead of GetType

* Add overloads to allow passing directed events by ref.

* Raise transform events by ref.

* Fix occluder AnchorStateChangedEvent subscription

* Fix broadphase subscriptions

* Fix bug oops

* Fix transform system raising moveevents by value

* Don't reflect the test entity systems.

* Directed EventBus uses ref everywhere, internally
Deduplicates a bunch of code. Whoo!

* Add broadcast by-ref events

* Fix by-ref events bug using Unsafe, add new tests for sorted by-ref events.

* Port broadcast events to by-ref.

* Speed, more correctness, reduce generics bloat.

* Clean up subscription code some.

* Remove bad test.

Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
2021-08-21 11:37:02 +02:00

105 lines
3.4 KiB
C#

using System.Collections.Generic;
using Robust.Shared.Containers;
using Robust.Shared.IoC;
using Robust.Shared.Map;
namespace Robust.Shared.GameObjects
{
/// <summary>
/// Handles moving entities between grids as they move around.
/// </summary>
internal sealed class SharedGridTraversalSystem : EntitySystem
{
[Dependency] private readonly IMapManager _mapManager = default!;
private Stack<MoveEvent> _queuedEvents = new();
private HashSet<EntityUid> _handledThisTick = new();
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<MoveEvent>((ref MoveEvent ev) => _queuedEvents.Push(ev));
}
public override void Update(float frameTime)
{
base.Update(frameTime);
// Need to queue because otherwise calling HandleMove during FrameUpdate will lead to prediction issues.
// TODO: Need to check if that's even still relevant since transform lerping fix?
ProcessChanges();
}
private void ProcessChanges()
{
while (_queuedEvents.TryPop(out var moveEvent))
{
if (!_handledThisTick.Add(moveEvent.Sender.Uid)) continue;
HandleMove(ref moveEvent);
}
_handledThisTick.Clear();
}
private void HandleMove(ref MoveEvent moveEvent)
{
var entity = moveEvent.Sender;
if (entity.Deleted ||
entity.HasComponent<IMapComponent>() ||
entity.HasComponent<IMapGridComponent>() ||
entity.IsInContainer())
{
return;
}
var transform = entity.Transform;
if (float.IsNaN(moveEvent.NewPosition.X) || float.IsNaN(moveEvent.NewPosition.Y))
{
return;
}
var mapPos = moveEvent.NewPosition.ToMapPos(EntityManager);
// Change parent if necessary
if (_mapManager.TryFindGridAt(transform.MapID, mapPos, out var grid) &&
EntityManager.TryGetEntity(grid.GridEntityId, out var gridEnt) &&
grid.GridEntityId != entity.Uid)
{
// Some minor duplication here with AttachParent but only happens when going on/off grid so not a big deal ATM.
if (grid.Index != transform.GridID)
{
transform.AttachParent(gridEnt);
RaiseLocalEvent(entity.Uid, new ChangedGridEvent(entity, transform.GridID, grid.Index));
}
}
else
{
var oldGridId = transform.GridID;
// Attach them to map / they are on an invalid grid
if (oldGridId != GridId.Invalid)
{
transform.AttachParent(_mapManager.GetMapEntity(transform.MapID));
RaiseLocalEvent(entity.Uid, new ChangedGridEvent(entity, oldGridId, GridId.Invalid));
}
}
}
}
public sealed class ChangedGridEvent : EntityEventArgs
{
public IEntity Entity;
public GridId OldGrid;
public GridId NewGrid;
public ChangedGridEvent(IEntity entity, GridId oldGrid, GridId newGrid)
{
Entity = entity;
OldGrid = oldGrid;
NewGrid = newGrid;
}
}
}