SnapGridComponent Removal (#1720)

* Removed SnapGridOffset, there is only center now.

* SnapGridComponent methods are now static.

* Removed SnapGridComponent.OnPositionChanged.

* Refactored static functions off SnapGridComponent to MapGrid.
Refactored away usages of SnapGridComponent.Position.

* Added Transform.Anchored for checking if an entity is a tile entity.
More refactoring for static MapGrid functions.

* Static snapgrid methods on MapGrid are no longer static.

* Removed IMapGrid.SnapSize, it is now always equal to the IMapGrid.TileSize.

* Add setter to ITransformComponent.Anchored.
Removed direct references to SnapGridComponent from content.

* Grid functions now deal with EntityUids instead of SnapGridComponents.
Began renaming public API functions from SnapGrid to Anchor.

* Add some unit tests.

* SnapGridComponent now anchors itself in startup, instead of Initialize (sending directed events in init is an error).
This commit is contained in:
Acruid
2021-04-28 10:24:11 -07:00
committed by GitHub
parent 32dea84196
commit 122acc5fd5
27 changed files with 514 additions and 522 deletions

View File

@@ -280,12 +280,12 @@ namespace Robust.Client.Console.Commands
internal class SnapGridGetCell : IConsoleCommand
{
public string Command => "sggcell";
public string Help => "sggcell <gridID> <vector2i> [offset]\nThat vector2i param is in the form x<int>,y<int>.";
public string Help => "sggcell <gridID> <vector2i>\nThat vector2i param is in the form x<int>,y<int>.";
public string Description => "Lists entities on a snap grid cell.";
public void Execute(IConsoleShell shell, string argStr, string[] args)
{
if (args.Length != 2 && args.Length != 3)
if (args.Length != 2)
{
shell.WriteLine(Help);
return;
@@ -293,7 +293,6 @@ namespace Robust.Client.Console.Commands
string gridId = args[0];
string indices = args[1];
string offset = args.Length == 3 ? args[2] : "Center";
if (!int.TryParse(args[0], out var id))
{
@@ -307,29 +306,17 @@ namespace Robust.Client.Console.Commands
return;
}
SnapGridOffset selectedOffset;
if (Enum.IsDefined(typeof(SnapGridOffset), offset))
{
selectedOffset = (SnapGridOffset)Enum.Parse(typeof(SnapGridOffset), offset);
}
else
{
shell.WriteError("given offset type is not defined");
return;
}
var mapMan = IoCManager.Resolve<IMapManager>();
if (mapMan.GridExists(new GridId(int.Parse(gridId, CultureInfo.InvariantCulture))))
{
foreach (var entity in
mapMan.GetGrid(new GridId(int.Parse(gridId, CultureInfo.InvariantCulture))).GetSnapGridCell(
mapMan.GetGrid(new GridId(int.Parse(gridId, CultureInfo.InvariantCulture))).GetAnchoredEntities(
new Vector2i(
int.Parse(indices.Split(',')[0], CultureInfo.InvariantCulture),
int.Parse(indices.Split(',')[1], CultureInfo.InvariantCulture)),
selectedOffset))
int.Parse(indices.Split(',')[1], CultureInfo.InvariantCulture))))
{
shell.WriteLine(entity.Owner.Uid.ToString());
shell.WriteLine(entity.ToString());
}
}
else

View File

@@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.ViewVariables;
@@ -8,8 +10,8 @@ namespace Robust.Client.GameObjects
{
internal sealed class ClientOccluderComponent : OccluderComponent
{
internal SnapGridComponent? SnapGrid { get; private set; }
[Dependency] private readonly IMapManager _mapManager = default!;
[ViewVariables] private (GridId, Vector2i) _lastPosition;
[ViewVariables] internal OccluderDir Occluding { get; private set; }
[ViewVariables] internal uint UpdateGeneration { get; set; }
@@ -29,39 +31,36 @@ namespace Robust.Client.GameObjects
{
base.Startup();
if (Owner.TryGetComponent(out SnapGridComponent? snap))
if (Owner.Transform.Anchored)
{
SnapGrid = snap;
SnapGrid.OnPositionChanged += SnapGridOnPositionChanged;
SnapGridOnPositionChanged();
}
}
private void SnapGridOnPositionChanged()
public void SnapGridOnPositionChanged()
{
SendDirty();
_lastPosition = (Owner.Transform.GridID, SnapGrid!.Position);
if(!Owner.Transform.Anchored)
return;
var grid = _mapManager.GetGrid(Owner.Transform.GridID);
_lastPosition = (Owner.Transform.GridID, grid.TileIndicesFor(Owner.Transform.Coordinates));
}
protected override void Shutdown()
{
base.Shutdown();
if (SnapGrid != null)
{
SnapGrid.OnPositionChanged -= SnapGridOnPositionChanged;
}
SendDirty();
}
private void SendDirty()
{
if (SnapGrid != null)
if (Owner.Transform.Anchored)
{
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local,
new OccluderDirtyEvent(Owner, _lastPosition, SnapGrid.Offset));
new OccluderDirtyEvent(Owner, _lastPosition));
}
}
@@ -69,16 +68,18 @@ namespace Robust.Client.GameObjects
{
Occluding = OccluderDir.None;
if (Deleted || SnapGrid == null)
if (Deleted || !Owner.Transform.Anchored)
{
return;
}
void CheckDir(Direction dir, OccluderDir oclDir)
{
foreach (var neighbor in SnapGrid.GetInDir(dir))
var grid = _mapManager.GetGrid(Owner.Transform.GridID);
var position = Owner.Transform.Coordinates;
foreach (var neighbor in grid.GetInDir(position, dir))
{
if (neighbor.TryGetComponent(out ClientOccluderComponent? comp) && comp.Enabled)
if (Owner.EntityManager.ComponentManager.TryGetComponent(neighbor, out ClientOccluderComponent? comp) && comp.Enabled)
{
Occluding |= oclDir;
break;

View File

@@ -6,6 +6,7 @@ using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
namespace Robust.Client.GameObjects
{
@@ -20,10 +21,11 @@ namespace Robust.Client.GameObjects
{
[Dependency] private readonly IMapManager _mapManager = default!;
private readonly Queue<IEntity> _dirtyEntities = new();
private readonly Queue<EntityUid> _dirtyEntities = new();
private uint _updateGeneration;
/// <inheritdoc />
public override void Initialize()
{
base.Initialize();
@@ -32,6 +34,18 @@ namespace Robust.Client.GameObjects
UpdatesAfter.Add(typeof(PhysicsSystem));
SubscribeLocalEvent<OccluderDirtyEvent>(HandleDirtyEvent);
SubscribeLocalEvent<ClientOccluderComponent, SnapGridPositionChangedEvent>(HandleSnapGridMove);
}
/// <inheritdoc />
public override void Shutdown()
{
UnsubscribeLocalEvent<OccluderDirtyEvent>();
UnsubscribeLocalEvent<ClientOccluderComponent, SnapGridPositionChangedEvent>(HandleSnapGridMove);
base.Shutdown();
}
public override void FrameUpdate(float frameTime)
@@ -47,8 +61,8 @@ namespace Robust.Client.GameObjects
while (_dirtyEntities.TryDequeue(out var entity))
{
if (!entity.Deleted
&& entity.TryGetComponent(out ClientOccluderComponent? occluder)
if (EntityManager.EntityExists(entity)
&& ComponentManager.TryGetComponent(entity, out ClientOccluderComponent? occluder)
&& occluder.UpdateGeneration != _updateGeneration)
{
occluder.Update();
@@ -58,6 +72,11 @@ namespace Robust.Client.GameObjects
}
}
private static void HandleSnapGridMove(EntityUid uid, ClientOccluderComponent component, SnapGridPositionChangedEvent args)
{
component.SnapGridOnPositionChanged();
}
private void HandleDirtyEvent(OccluderDirtyEvent ev)
{
var sender = ev.Sender;
@@ -65,13 +84,14 @@ namespace Robust.Client.GameObjects
sender.TryGetComponent(out ClientOccluderComponent? iconSmooth)
&& iconSmooth.Running)
{
var snapGrid = sender.GetComponent<SnapGridComponent>();
var grid1 = _mapManager.GetGrid(sender.Transform.GridID);
var coords = sender.Transform.Coordinates;
_dirtyEntities.Enqueue(sender);
AddValidEntities(snapGrid.GetInDir(Direction.North));
AddValidEntities(snapGrid.GetInDir(Direction.South));
AddValidEntities(snapGrid.GetInDir(Direction.East));
AddValidEntities(snapGrid.GetInDir(Direction.West));
_dirtyEntities.Enqueue(sender.Uid);
AddValidEntities(grid1.GetInDir(coords, Direction.North));
AddValidEntities(grid1.GetInDir(coords, Direction.South));
AddValidEntities(grid1.GetInDir(coords, Direction.East));
AddValidEntities(grid1.GetInDir(coords, Direction.West));
}
// Entity is no longer valid, update around the last position it was at.
@@ -79,28 +99,23 @@ namespace Robust.Client.GameObjects
{
var pos = ev.LastPosition.Value.pos;
AddValidEntities(grid.GetSnapGridCell(pos + new Vector2i(1, 0), ev.Offset));
AddValidEntities(grid.GetSnapGridCell(pos + new Vector2i(-1, 0), ev.Offset));
AddValidEntities(grid.GetSnapGridCell(pos + new Vector2i(0, 1), ev.Offset));
AddValidEntities(grid.GetSnapGridCell(pos + new Vector2i(0, -1), ev.Offset));
AddValidEntities(grid.GetAnchoredEntities(pos + new Vector2i(1, 0)));
AddValidEntities(grid.GetAnchoredEntities(pos + new Vector2i(-1, 0)));
AddValidEntities(grid.GetAnchoredEntities(pos + new Vector2i(0, 1)));
AddValidEntities(grid.GetAnchoredEntities(pos + new Vector2i(0, -1)));
}
}
private void AddValidEntities(IEnumerable<IEntity> candidates)
private void AddValidEntities(IEnumerable<EntityUid> candidates)
{
foreach (var entity in candidates)
{
if (entity.HasComponent<ClientOccluderComponent>())
if (ComponentManager.HasComponent<ClientOccluderComponent>(entity))
{
_dirtyEntities.Enqueue(entity);
}
}
}
private void AddValidEntities(IEnumerable<IComponent> candidates)
{
AddValidEntities(candidates.Select(c => c.Owner));
}
}
/// <summary>
@@ -108,15 +123,13 @@ namespace Robust.Client.GameObjects
/// </summary>
internal sealed class OccluderDirtyEvent : EntityEventArgs
{
public OccluderDirtyEvent(IEntity sender, (GridId grid, Vector2i pos)? lastPosition, SnapGridOffset offset)
public OccluderDirtyEvent(IEntity sender, (GridId grid, Vector2i pos)? lastPosition)
{
LastPosition = lastPosition;
Offset = offset;
Sender = sender;
}
public (GridId grid, Vector2i pos)? LastPosition { get; }
public SnapGridOffset Offset { get; }
public IEntity Sender { get; }
}
}

View File

@@ -56,8 +56,7 @@ namespace Robust.Client.Map
continue;
}
CreateGrid(gridData![gridId].Coordinates.MapId, gridId, creationDatum.ChunkSize,
creationDatum.SnapSize);
CreateGrid(gridData![gridId].Coordinates.MapId, gridId, creationDatum.ChunkSize);
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using Robust.Client.Graphics;
using Robust.Shared.Map;
using Robust.Shared.Maths;
@@ -62,7 +62,7 @@ namespace Robust.Client.Placement.Modes
var gridId = MouseCoords.GetGridId(pManager.EntityManager);
if (gridId.IsValid())
{
snapSize = pManager.MapManager.GetGrid(gridId).SnapSize; //Find snap size for the grid.
snapSize = pManager.MapManager.GetGrid(gridId).TileSize; //Find snap size for the grid.
onGrid = true;
}
else

View File

@@ -1,4 +1,4 @@
using System;
using System;
using Robust.Client.Graphics;
using Robust.Shared.Map;
using Robust.Shared.Maths;
@@ -52,7 +52,7 @@ namespace Robust.Client.Placement.Modes
snapSize = 1f;
if (gridId.IsValid())
{
snapSize = pManager.MapManager.GetGrid(gridId).SnapSize; //Find snap size for the grid.
snapSize = pManager.MapManager.GetGrid(gridId).TileSize; //Find snap size for the grid.
onGrid = true;
}
else

View File

@@ -193,13 +193,14 @@ namespace Robust.Server.GameStates
if (!_entMan.EntityExists(entityUid))
continue;
var xform = _compMan.GetComponent<ITransformComponent>(entityUid);
// Anchored entities don't ever leave
if (_compMan.HasComponent<SnapGridComponent>(entityUid))
if (xform.Anchored)
continue;
// PVS leave message
//TODO: Remove NaN as the signal to leave PVS
var xform = _compMan.GetComponent<ITransformComponent>(entityUid);
var oldState = (TransformComponent.TransformComponentState) xform.GetComponentState(session);
entityStates.Add(new EntityState(entityUid,
@@ -232,7 +233,8 @@ namespace Robust.Server.GameStates
// PVS enter message
// skip sending anchored entities (walls)
if (_compMan.HasComponent<SnapGridComponent>(entityUid) && _entMan.GetEntity(entityUid).LastModifiedTick <= lastMapUpdate)
var xform = _compMan.GetComponent<ITransformComponent>(entityUid);
if (xform.Anchored && _entMan.GetEntity(entityUid).LastModifiedTick <= lastMapUpdate)
continue;
// don't assume the client knows anything about us

View File

@@ -73,7 +73,7 @@ namespace Robust.Server.Map
var mapCreations = _mapCreationTick.Where(kv => kv.Value >= fromTick && kv.Key != MapId.Nullspace)
.Select(kv => kv.Key).ToArray();
var gridCreations = _grids.Values.Where(g => g.CreatedTick >= fromTick && g.ParentMapId != MapId.Nullspace).ToDictionary(g => g.Index,
grid => new GameStateMapData.GridCreationDatum(grid.ChunkSize, grid.SnapSize));
grid => new GameStateMapData.GridCreationDatum(grid.ChunkSize));
// no point sending empty collections
if (gridDatums.Count == 0) gridDatums = default;

View File

@@ -25,7 +25,6 @@ namespace Robust.Server.Maps
info.Add("chunksize", grid.ChunkSize.ToString(CultureInfo.InvariantCulture));
info.Add("tilesize", grid.TileSize.ToString(CultureInfo.InvariantCulture));
info.Add("snapsize", grid.SnapSize.ToString(CultureInfo.InvariantCulture));
var chunks = grid.GetMapChunks();
foreach (var chunk in chunks)

View File

@@ -125,6 +125,12 @@ namespace Robust.Shared.GameObjects
IEnumerable<ITransformComponent> Children { get; }
int ChildCount { get; }
IEnumerable<EntityUid> ChildEntityUids { get; }
/// <summary>
/// Is this transform anchored to a grid tile?
/// </summary>
bool Anchored { get; set; }
Matrix3 GetLocalMatrix();
Matrix3 GetLocalMatrixInv();
void DetachParentToNull();

View File

@@ -1,229 +1,24 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
namespace Robust.Shared.GameObjects
{
/// <summary>
/// Makes it possible to look this entity up with the snap grid.
/// Makes it possible to look this entity up with the snap grid.
/// </summary>
public class SnapGridComponent : Component, IComponentDebug
internal class SnapGridComponent : Component
{
public const string LogCategory = "go.comp.snapgrid";
/// <inheritdoc />
public sealed override string Name => "SnapGrid";
private bool IsSet;
[DataField("offset")]
private SnapGridOffset _offset = SnapGridOffset.Center;
[Dependency] private readonly IMapManager _mapManager = default!;
[Obsolete]
public event Action? OnPositionChanged;
private GridId _lastGrid;
public Vector2i Position { get; private set; }
public SnapGridOffset Offset => _offset;
/// <inheritdoc />
public override void Initialize()
{
base.Initialize();
UpdatePosition();
}
/// <inheritdoc />
protected override void Shutdown()
{
base.Shutdown();
if (IsSet)
{
if (_mapManager.TryGetGrid(_lastGrid, out var grid))
{
grid.RemoveFromSnapGridCell(Position, Offset, this);
return;
}
IsSet = false;
}
}
/// <summary>
/// GridId the last time this component was moved.
/// </summary>
internal GridId LastGrid = GridId.Invalid;
/// <summary>
/// Returns an enumerable over all the entities which are one tile over in a certain direction.
/// TileIndices the last time this component was moved.
/// </summary>
public IEnumerable<IEntity> GetInDir(Direction dir)
{
if (!_mapManager.TryGetGrid(Owner.Transform.GridID, out var grid))
return Enumerable.Empty<IEntity>();
var pos = SnapGridPosAt(dir);
return grid.GetSnapGridCell(pos, Offset).Select(s => s.Owner);
}
[Pure]
public IEnumerable<IEntity> GetOffset(Vector2i offset)
{
if (!_mapManager.TryGetGrid(Owner.Transform.GridID, out var grid))
return Enumerable.Empty<IEntity>();
var pos = Position + offset;
return grid.GetSnapGridCell(pos, Offset).Select(s => s.Owner);
}
public IEnumerable<IEntity> GetLocal()
{
if (!_mapManager.TryGetGrid(Owner.Transform.GridID, out var grid))
return Enumerable.Empty<IEntity>();
return grid.GetSnapGridCell(Position, Offset).Select(s => s.Owner);
}
public string GetDebugString()
{
return $"ofs/pos: {Offset}/{Position}";
}
public EntityCoordinates DirectionToGrid(Direction direction)
{
if (!_mapManager.TryGetGrid(Owner.Transform.GridID, out var grid))
return Owner.Transform.Coordinates.Offset(direction.ToVec());
var coords = grid.GridTileToLocal(SnapGridPosAt(direction));
return coords;
}
Vector2i SnapGridPosAt(Direction dir, int dist = 1)
{
switch (dir)
{
case Direction.East:
return Position + new Vector2i(dist, 0);
case Direction.SouthEast:
return Position + new Vector2i(dist, -dist);
case Direction.South:
return Position + new Vector2i(0, -dist);
case Direction.SouthWest:
return Position + new Vector2i(-dist, -dist);
case Direction.West:
return Position + new Vector2i(-dist, 0);
case Direction.NorthWest:
return Position + new Vector2i(-dist, dist);
case Direction.North:
return Position + new Vector2i(0, dist);
case Direction.NorthEast:
return Position + new Vector2i(dist, dist);
default:
throw new NotImplementedException();
}
}
public IEnumerable<SnapGridComponent> GetCardinalNeighborCells()
{
if (!_mapManager.TryGetGrid(Owner.Transform.GridID, out var grid))
yield break;
foreach (var cell in grid.GetSnapGridCell(Position, Offset))
yield return cell;
foreach (var cell in grid.GetSnapGridCell(Position + new Vector2i(0, 1), Offset))
yield return cell;
foreach (var cell in grid.GetSnapGridCell(Position + new Vector2i(0, -1), Offset))
yield return cell;
foreach (var cell in grid.GetSnapGridCell(Position + new Vector2i(1, 0), Offset))
yield return cell;
foreach (var cell in grid.GetSnapGridCell(Position + new Vector2i(-1, 0), Offset))
yield return cell;
}
public IEnumerable<SnapGridComponent> GetCellsInSquareArea(int n = 1)
{
if (!_mapManager.TryGetGrid(Owner.Transform.GridID, out var grid))
yield break;
for (var y = -n; y <= n; ++y)
for (var x = -n; x <= n; ++x)
{
foreach (var cell in grid.GetSnapGridCell(Position + new Vector2i(x, y), Offset))
yield return cell;
}
}
internal void UpdatePosition()
{
if (IsSet)
{
if (!_mapManager.TryGetGrid(_lastGrid, out var lastGrid))
{
Logger.WarningS(LogCategory, "Entity {0} snapgrid didn't find grid {1}. Race condition?", Owner.Uid, Owner.Transform.GridID);
return;
}
lastGrid.RemoveFromSnapGridCell(Position, Offset, this);
}
if (!_mapManager.TryGetGrid(Owner.Transform.GridID, out var grid))
{
// Either a race condition, or we're not on any grids.
return;
}
IsSet = true;
var oldPos = Position;
Position = grid.SnapGridCellFor(Owner.Transform.Coordinates, Offset);
var oldGrid = _lastGrid;
_lastGrid = Owner.Transform.GridID;
grid.AddToSnapGridCell(Position, Offset, this);
if (oldPos != Position)
{
OnPositionChanged?.Invoke();
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid,
new SnapGridPositionChangedEvent(Position, oldPos, _lastGrid, oldGrid));
}
}
}
public enum SnapGridOffset: byte
{
/// <summary>
/// Center snap grid (wires, pipes, ...).
/// </summary>
Center,
/// <summary>
/// Edge snap grid (walls, ...).
/// </summary>
Edge,
}
public class SnapGridPositionChangedEvent : EntityEventArgs
{
public GridId OldGrid { get; }
public GridId NewGrid { get; }
public bool SameGrid => OldGrid == NewGrid;
public Vector2i OldPosition { get; }
public Vector2i Position { get; }
public SnapGridPositionChangedEvent(Vector2i position, Vector2i oldPosition, GridId newGrid, GridId oldGrid)
{
Position = position;
OldPosition = oldPosition;
NewGrid = newGrid;
OldGrid = oldGrid;
}
internal Vector2i LastTileIndices;
}
}

View File

@@ -321,6 +321,21 @@ namespace Robust.Shared.GameObjects
}
}
/// <inheritdoc />
[ViewVariables]
public bool Anchored
{
get => Owner.HasComponent<SnapGridComponent>();
set
{
if(value && !Owner.HasComponent<SnapGridComponent>())
Owner.AddComponent<SnapGridComponent>();
else if(!value && Owner.HasComponent<SnapGridComponent>())
Owner.RemoveComponent<SnapGridComponent>();
}
}
[ViewVariables]
public IEnumerable<ITransformComponent> Children =>
_children.Select(u => Owner.EntityManager.GetEntity(u).Transform);

View File

@@ -114,7 +114,7 @@ namespace Robust.Shared.GameObjects
/// <inheritdoc />
public bool IsValid()
{
return !Deleted;
return EntityManager.EntityExists(Uid);
}
/// <summary>
@@ -235,7 +235,7 @@ namespace Robust.Shared.GameObjects
/// <inheritdoc />
public bool HasComponent<T>()
{
return EntityManager.ComponentManager.HasComponent(Uid, typeof(T));
return EntityManager.ComponentManager.HasComponent<T>(Uid);
}
/// <inheritdoc />

View File

@@ -297,7 +297,13 @@ namespace Robust.Shared.GameObjects
public bool EntityExists(EntityUid uid)
{
return TryGetEntity(uid, out var _);
if (!TryGetEntity(uid, out var ent))
return false;
if (ent.Deleted)
return false;
return true;
}
/// <summary>
@@ -349,17 +355,20 @@ namespace Robust.Shared.GameObjects
var entity = new Entity(this, uid.Value);
// we want this called before adding components
EntityAdded?.Invoke(this, entity.Uid);
// We do this after the event, so if the event throws we have not committed
Entities[entity.Uid] = entity;
AllEntities.Add(entity);
// allocate the required MetaDataComponent
_componentManager.AddComponent<MetaDataComponent>(entity);
// allocate the required TransformComponent
_componentManager.AddComponent<TransformComponent>(entity);
Entities[entity.Uid] = entity;
AllEntities.Add(entity);
return entity;
}

View File

@@ -1,27 +1,119 @@
using JetBrains.Annotations;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Map;
using Robust.Shared.Maths;
namespace Robust.Shared.GameObjects
{
[UsedImplicitly]
public class SnapGridSystem : EntitySystem
internal class SnapGridSystem : EntitySystem
{
[Dependency] private readonly IMapManager _mapManager = default!;
/// <inheritdoc />
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SnapGridComponent, MoveEvent>(OnMoveEvent);
SubscribeLocalEvent<SnapGridComponent, ComponentStartup>(HandleComponentStartup);
SubscribeLocalEvent<SnapGridComponent, ComponentShutdown>(HandleComponentShutdown);
SubscribeLocalEvent<SnapGridComponent, MoveEvent>(HandleMoveEvent);
}
/// <inheritdoc />
public override void Shutdown()
{
base.Shutdown();
UnsubscribeLocalEvent<SnapGridComponent, MoveEvent>(OnMoveEvent);
UnsubscribeLocalEvent<SnapGridComponent, ComponentStartup>(HandleComponentStartup);
UnsubscribeLocalEvent<SnapGridComponent, ComponentShutdown>(HandleComponentShutdown);
UnsubscribeLocalEvent<SnapGridComponent, MoveEvent>(HandleMoveEvent);
}
private void OnMoveEvent(EntityUid uid, SnapGridComponent snapGrid, MoveEvent args)
private void HandleComponentStartup(EntityUid uid, SnapGridComponent component, ComponentStartup args)
{
snapGrid.UpdatePosition();
var transform = ComponentManager.GetComponent<ITransformComponent>(uid);
UpdatePosition(uid, transform, component);
}
private void HandleComponentShutdown(EntityUid uid, SnapGridComponent component, ComponentShutdown args)
{
if (component.LastGrid == GridId.Invalid)
return;
var transform = ComponentManager.GetComponent<ITransformComponent>(uid);
if (_mapManager.TryGetGrid(component.LastGrid, out var grid))
{
var indices = grid.TileIndicesFor(transform.WorldPosition);
grid.RemoveFromSnapGridCell(indices, uid);
return;
}
component.LastGrid = GridId.Invalid;
}
private void HandleMoveEvent(EntityUid uid, SnapGridComponent component, MoveEvent args)
{
var transform = ComponentManager.GetComponent<ITransformComponent>(uid);
UpdatePosition(uid, transform, component);
}
private void UpdatePosition(EntityUid euid, ITransformComponent transform, SnapGridComponent snapComp)
{
if (snapComp.LastGrid != GridId.Invalid)
{
if (!_mapManager.TryGetGrid(snapComp.LastGrid, out var lastGrid))
{
Logger.WarningS("go.comp.snapgrid", "Entity {0} snapgrid didn't find grid {1}. Race condition?", euid, transform.GridID);
return;
}
lastGrid.RemoveFromSnapGridCell(snapComp.LastTileIndices, euid);
}
if (!_mapManager.TryGetGrid(transform.GridID, out var grid))
{
// Either a race condition, or we're not on any grids.
return;
}
var oldPos = snapComp.LastTileIndices;
var oldGrid = snapComp.LastGrid;
var newPos = grid.TileIndicesFor(transform.MapPosition);
var newGrid = transform.GridID;
grid.AddToSnapGridCell(newPos, euid);
if (oldPos != newPos || oldGrid != newGrid)
{
RaiseLocalEvent(euid, new SnapGridPositionChangedEvent(newPos, oldPos, newGrid, oldGrid));
}
snapComp.LastTileIndices = newPos;
snapComp.LastGrid = newGrid;
}
}
public class SnapGridPositionChangedEvent : EntityEventArgs
{
public GridId OldGrid { get; }
public GridId NewGrid { get; }
public bool SameGrid => OldGrid == NewGrid;
public Vector2i OldPosition { get; }
public Vector2i Position { get; }
public SnapGridPositionChangedEvent(Vector2i position, Vector2i oldPosition, GridId newGrid, GridId oldGrid)
{
Position = position;
OldPosition = oldPosition;
NewGrid = newGrid;
OldGrid = oldGrid;
}
}
}

View File

@@ -29,12 +29,10 @@ namespace Robust.Shared.GameStates
public struct GridCreationDatum
{
public readonly ushort ChunkSize;
public readonly float SnapSize;
public GridCreationDatum(ushort chunkSize, float snapSize)
public GridCreationDatum(ushort chunkSize)
{
ChunkSize = chunkSize;
SnapSize = snapSize;
}
}

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Robust.Shared.GameObjects;
using Robust.Shared.Maths;
@@ -7,7 +7,7 @@ namespace Robust.Shared.Map
/// <summary>
/// A square section of a <see cref="IMapGrid"/>.
/// </summary>
public interface IMapChunk : IEnumerable<TileRef>
internal interface IMapChunk : IEnumerable<TileRef>
{
/// <summary>
/// The number of tiles per side of the square chunk.
@@ -76,10 +76,10 @@ namespace Robust.Shared.Map
/// <returns>The indices relative to the grid origin.</returns>
Vector2i ChunkTileToGridTile(Vector2i chunkTile);
IEnumerable<SnapGridComponent> GetSnapGridCell(ushort xCell, ushort yCell, SnapGridOffset offset);
IEnumerable<EntityUid> GetSnapGridCell(ushort xCell, ushort yCell);
void AddToSnapGridCell(ushort xCell, ushort yCell, SnapGridOffset offset, SnapGridComponent snap);
void RemoveFromSnapGridCell(ushort xCell, ushort yCell, SnapGridOffset offset, SnapGridComponent snap);
void AddToSnapGridCell(ushort xCell, ushort yCell, EntityUid euid);
void RemoveFromSnapGridCell(ushort xCell, ushort yCell, EntityUid euid);
Box2i CalcLocalBounds();

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
@@ -17,6 +17,9 @@ namespace Robust.Shared.Map
/// </summary>
MapId ParentMapId { get; set; }
/// <summary>
/// The entity this grid is represented by in the ECS system.
/// </summary>
EntityUid GridEntityId { get; }
/// <summary>
@@ -39,11 +42,6 @@ namespace Robust.Shared.Map
/// </summary>
ushort ChunkSize { get; }
/// <summary>
/// The distance between the snap grid, between each center snap and between each offset snap grid location
/// </summary>
float SnapSize { get; }
/// <summary>
/// The origin of the grid in world coordinates. Make sure to set this!
/// </summary>
@@ -54,16 +52,6 @@ namespace Robust.Shared.Map
/// </summary>
bool HasGravity { get; set; }
/// <summary>
/// Is this located at a position on the center grid of snap positions, accepts local coordinates
/// </summary>
bool OnSnapCenter(Vector2 position);
/// <summary>
/// Is this located at a position on the border grid of snap positions, accepts local coordinates
/// </summary>
bool OnSnapBorder(Vector2 position);
#region TileAccess
/// <summary>
@@ -115,17 +103,27 @@ namespace Robust.Shared.Map
#region SnapGridAccess
IEnumerable<SnapGridComponent> GetSnapGridCell(EntityCoordinates coords, SnapGridOffset offset);
IEnumerable<SnapGridComponent> GetSnapGridCell(Vector2i pos, SnapGridOffset offset);
IEnumerable<EntityUid> GetAnchoredEntities(EntityCoordinates coords);
IEnumerable<EntityUid> GetAnchoredEntities(Vector2i pos);
Vector2i SnapGridCellFor(EntityCoordinates coords, SnapGridOffset offset);
Vector2i SnapGridCellFor(MapCoordinates worldPos, SnapGridOffset offset);
Vector2i SnapGridCellFor(Vector2 localPos, SnapGridOffset offset);
Vector2i TileIndicesFor(EntityCoordinates coords) => CoordinatesToTile(coords);
Vector2i TileIndicesFor(MapCoordinates worldPos) => CoordinatesToTile(MapToGrid(worldPos));
Vector2i TileIndicesFor(Vector2 worldPos) => WorldToTile(worldPos);
void AddToSnapGridCell(Vector2i pos, SnapGridOffset offset, SnapGridComponent snap);
void AddToSnapGridCell(EntityCoordinates coords, SnapGridOffset offset, SnapGridComponent snap);
void RemoveFromSnapGridCell(Vector2i pos, SnapGridOffset offset, SnapGridComponent snap);
void RemoveFromSnapGridCell(EntityCoordinates coords, SnapGridOffset offset, SnapGridComponent snap);
void AddToSnapGridCell(Vector2i pos, EntityUid euid);
void AddToSnapGridCell(EntityCoordinates coords, EntityUid euid);
void RemoveFromSnapGridCell(Vector2i pos, EntityUid euid);
void RemoveFromSnapGridCell(EntityCoordinates coords, EntityUid euid);
/// <summary>
/// Returns an enumerable over all the entities which are one tile over in a certain direction.
/// </summary>
IEnumerable<EntityUid> GetInDir(EntityCoordinates position, Direction dir);
IEnumerable<EntityUid> GetOffset(EntityCoordinates coords, Vector2i offset);
IEnumerable<EntityUid> GetLocal(EntityCoordinates coords);
EntityCoordinates DirectionToGrid(EntityCoordinates coords, Direction direction);
IEnumerable<EntityUid> GetCardinalNeighborCells(EntityCoordinates coords);
IEnumerable<EntityUid> GetCellsInSquareArea(EntityCoordinates coords, int n);
#endregion SnapGridAccess

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Robust.Shared.GameObjects;
@@ -80,7 +80,7 @@ namespace Robust.Shared.Map
void DeleteMap(MapId mapID);
IMapGrid CreateGrid(MapId currentMapID, GridId? gridID = null, ushort chunkSize = 16, float snapSize = 1);
IMapGrid CreateGrid(MapId currentMapID, GridId? gridID = null, ushort chunkSize = 16);
IMapGrid GetGrid(GridId gridID);
bool TryGetGrid(GridId gridId, [NotNullWhen(true)] out IMapGrid? grid);
bool GridExists(GridId gridID);

View File

@@ -1,4 +1,4 @@
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Timing;
namespace Robust.Shared.Map
@@ -16,6 +16,6 @@ namespace Robust.Shared.Map
/// <param name="oldTile">The old tile that got replaced.</param>
void RaiseOnTileChanged(TileRef tileRef, Tile oldTile);
IMapGridInternal CreateGridNoEntity(MapId currentMapID, GridId? gridID = null, ushort chunkSize = 16, float snapSize = 1);
IMapGridInternal CreateGridNoEntity(MapId currentMapID, GridId? gridID = null, ushort chunkSize = 16);
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using Robust.Shared.GameObjects;
@@ -10,6 +10,11 @@ namespace Robust.Shared.Map
/// <inheritdoc />
internal class MapChunk : IMapChunkInternal
{
/// <summary>
/// New SnapGrid cells are allocated with this capacity.
/// </summary>
private const int SnapCellStartingCapacity = 1;
private readonly IMapGridInternal _grid;
private readonly Vector2i _gridIndices;
@@ -174,7 +179,7 @@ namespace Robust.Shared.Map
}
/// <inheritdoc />
public IEnumerable<SnapGridComponent> GetSnapGridCell(ushort xCell, ushort yCell, SnapGridOffset offset)
public IEnumerable<EntityUid> GetSnapGridCell(ushort xCell, ushort yCell)
{
if (xCell >= ChunkSize)
throw new ArgumentOutOfRangeException(nameof(xCell), "Tile indices out of bounds.");
@@ -183,18 +188,18 @@ namespace Robust.Shared.Map
throw new ArgumentOutOfRangeException(nameof(yCell), "Tile indices out of bounds.");
var cell = _snapGrid[xCell, yCell];
var list = offset == SnapGridOffset.Center ? cell.Center : cell.Edge;
var list = cell.Center;
if (list == null)
{
return Array.Empty<SnapGridComponent>();
return Array.Empty<EntityUid>();
}
return list;
}
/// <inheritdoc />
public void AddToSnapGridCell(ushort xCell, ushort yCell, SnapGridOffset offset, SnapGridComponent snap)
public void AddToSnapGridCell(ushort xCell, ushort yCell, EntityUid euid)
{
if (xCell >= ChunkSize)
throw new ArgumentOutOfRangeException(nameof(xCell), "Tile indices out of bounds.");
@@ -203,26 +208,12 @@ namespace Robust.Shared.Map
throw new ArgumentOutOfRangeException(nameof(yCell), "Tile indices out of bounds.");
ref var cell = ref _snapGrid[xCell, yCell];
if (offset == SnapGridOffset.Center)
{
if (cell.Center == null)
{
cell.Center = new List<SnapGridComponent>(1);
}
cell.Center.Add(snap);
}
else
{
if (cell.Edge == null)
{
cell.Edge = new List<SnapGridComponent>(1);
}
cell.Edge.Add(snap);
}
cell.Center ??= new List<EntityUid>(SnapCellStartingCapacity);
cell.Center.Add(euid);
}
/// <inheritdoc />
public void RemoveFromSnapGridCell(ushort xCell, ushort yCell, SnapGridOffset offset, SnapGridComponent snap)
public void RemoveFromSnapGridCell(ushort xCell, ushort yCell, EntityUid euid)
{
if (xCell >= ChunkSize)
throw new ArgumentOutOfRangeException(nameof(xCell), "Tile indices out of bounds.");
@@ -231,14 +222,7 @@ namespace Robust.Shared.Map
throw new ArgumentOutOfRangeException(nameof(yCell), "Tile indices out of bounds.");
ref var cell = ref _snapGrid[xCell, yCell];
if (offset == SnapGridOffset.Center)
{
cell.Center?.Remove(snap);
}
else
{
cell.Edge?.Remove(snap);
}
cell.Center?.Remove(euid);
}
public bool SuppressCollisionRegeneration { get; set; }
@@ -258,7 +242,7 @@ namespace Robust.Shared.Map
public Box2 CalcWorldBounds()
{
var worldPos = _grid.WorldPosition + (Vector2i)Indices * _grid.TileSize * ChunkSize;
var worldPos = _grid.WorldPosition + Indices * _grid.TileSize * ChunkSize;
var localBounds = CalcLocalBounds();
var ts = _grid.TileSize;
@@ -291,8 +275,7 @@ namespace Robust.Shared.Map
private struct SnapGridCell
{
public List<SnapGridComponent> Center;
public List<SnapGridComponent> Edge;
public List<EntityUid>? Center;
}
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using Robust.Shared.GameObjects;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
@@ -62,18 +63,17 @@ namespace Robust.Shared.Map
/// Initializes a new instance of the <see cref="MapGrid"/> class.
/// </summary>
/// <param name="mapManager">Reference to the <see cref="MapManager"/> that will manage this grid.</param>
/// <param name="entityManager"></param>
/// <param name="gridIndex">Index identifier of this grid.</param>
/// <param name="chunkSize">The dimension of this square chunk.</param>
/// <param name="snapSize">Distance in world units between the lines on the conceptual snap grid.</param>
/// <param name="parentMapId">Parent map identifier.</param>
internal MapGrid(IMapManagerInternal mapManager, IEntityManager entityManager, GridId gridIndex, ushort chunkSize, float snapSize,
MapId parentMapId)
internal MapGrid(IMapManagerInternal mapManager, IEntityManager entityManager, GridId gridIndex, ushort chunkSize, MapId parentMapId)
{
_mapManager = mapManager;
_entityManager = entityManager;
Index = gridIndex;
ChunkSize = chunkSize;
SnapSize = snapSize;
ParentMapId = parentMapId;
LastModifiedTick = CreatedTick = _mapManager.GameTiming.CurTick;
HasGravity = false;
@@ -101,10 +101,6 @@ namespace Robust.Shared.Map
[ViewVariables]
public ushort ChunkSize { get; }
/// <inheritdoc />
[ViewVariables]
public float SnapSize { get; }
/// <inheritdoc />
[ViewVariables]
public GridId Index { get; }
@@ -173,18 +169,6 @@ namespace Robust.Shared.Map
UpdateAABB();
}
/// <inheritdoc />
public bool OnSnapCenter(Vector2 position)
{
return (MathHelper.CloseTo(position.X % SnapSize, 0) && MathHelper.CloseTo(position.Y % SnapSize, 0));
}
/// <inheritdoc />
public bool OnSnapBorder(Vector2 position)
{
return (MathHelper.CloseTo(position.X % SnapSize, SnapSize / 2) && MathHelper.CloseTo(position.Y % SnapSize, SnapSize / 2));
}
#region TileAccess
/// <inheritdoc />
@@ -349,72 +333,67 @@ namespace Robust.Shared.Map
#region SnapGridAccess
/// <inheritdoc />
public IEnumerable<SnapGridComponent> GetSnapGridCell(EntityCoordinates coords, SnapGridOffset offset)
public IEnumerable<EntityUid> GetAnchoredEntities(EntityCoordinates coords)
{
return GetSnapGridCell(SnapGridCellFor(coords, offset), offset);
return GetAnchoredEntities(TileIndicesFor(coords));
}
/// <inheritdoc />
public IEnumerable<SnapGridComponent> GetSnapGridCell(Vector2i pos, SnapGridOffset offset)
public IEnumerable<EntityUid> GetAnchoredEntities(Vector2i pos)
{
var (chunk, chunkTile) = ChunkAndOffsetForTile(pos);
return chunk.GetSnapGridCell((ushort)chunkTile.X, (ushort)chunkTile.Y, offset);
return chunk.GetSnapGridCell((ushort)chunkTile.X, (ushort)chunkTile.Y);
}
/// <inheritdoc />
public Vector2i SnapGridCellFor(EntityCoordinates coords, SnapGridOffset offset)
public Vector2i TileIndicesFor(EntityCoordinates coords)
{
DebugTools.Assert(ParentMapId == coords.GetMapId(_entityManager));
var local = WorldToLocal(coords.ToMapPos(_entityManager));
return SnapGridCellFor(local, offset);
return SnapGridLocalCellFor(local);
}
/// <inheritdoc />
public Vector2i SnapGridCellFor(MapCoordinates worldPos, SnapGridOffset offset)
public Vector2i TileIndicesFor(MapCoordinates worldPos)
{
DebugTools.Assert(ParentMapId == worldPos.MapId);
var localPos = WorldToLocal(worldPos.Position);
return SnapGridCellFor(localPos, offset);
return SnapGridLocalCellFor(localPos);
}
/// <inheritdoc />
public Vector2i SnapGridCellFor(Vector2 localPos, SnapGridOffset offset)
private Vector2i SnapGridLocalCellFor(Vector2 localPos)
{
if (offset == SnapGridOffset.Edge)
{
localPos += new Vector2(TileSize / 2f, TileSize / 2f);
}
var x = (int)Math.Floor(localPos.X / TileSize);
var y = (int)Math.Floor(localPos.Y / TileSize);
return new Vector2i(x, y);
}
/// <inheritdoc />
public void AddToSnapGridCell(Vector2i pos, SnapGridOffset offset, SnapGridComponent snap)
public void AddToSnapGridCell(Vector2i pos, EntityUid euid)
{
var (chunk, chunkTile) = ChunkAndOffsetForTile(pos);
chunk.AddToSnapGridCell((ushort)chunkTile.X, (ushort)chunkTile.Y, offset, snap);
chunk.AddToSnapGridCell((ushort)chunkTile.X, (ushort)chunkTile.Y, euid);
}
/// <inheritdoc />
public void AddToSnapGridCell(EntityCoordinates coords, SnapGridOffset offset, SnapGridComponent snap)
public void AddToSnapGridCell(EntityCoordinates coords, EntityUid euid)
{
AddToSnapGridCell(SnapGridCellFor(coords, offset), offset, snap);
AddToSnapGridCell(TileIndicesFor(coords), euid);
}
/// <inheritdoc />
public void RemoveFromSnapGridCell(Vector2i pos, SnapGridOffset offset, SnapGridComponent snap)
public void RemoveFromSnapGridCell(Vector2i pos, EntityUid euid)
{
var (chunk, chunkTile) = ChunkAndOffsetForTile(pos);
chunk.RemoveFromSnapGridCell((ushort)chunkTile.X, (ushort)chunkTile.Y, offset, snap);
chunk.RemoveFromSnapGridCell((ushort)chunkTile.X, (ushort) chunkTile.Y, euid);
}
/// <inheritdoc />
public void RemoveFromSnapGridCell(EntityCoordinates coords, SnapGridOffset offset, SnapGridComponent snap)
public void RemoveFromSnapGridCell(EntityCoordinates coords, EntityUid euid)
{
RemoveFromSnapGridCell(SnapGridCellFor(coords, offset), offset, snap);
RemoveFromSnapGridCell(TileIndicesFor(coords), euid);
}
private (IMapChunk, Vector2i) ChunkAndOffsetForTile(Vector2i pos)
@@ -425,6 +404,88 @@ namespace Robust.Shared.Map
return (chunk, chunkTile);
}
private static Vector2i SnapGridPosAt(Vector2i position, Direction dir, int dist = 1)
{
switch (dir)
{
case Direction.East:
return position + new Vector2i(dist, 0);
case Direction.SouthEast:
return position + new Vector2i(dist, -dist);
case Direction.South:
return position + new Vector2i(0, -dist);
case Direction.SouthWest:
return position + new Vector2i(-dist, -dist);
case Direction.West:
return position + new Vector2i(-dist, 0);
case Direction.NorthWest:
return position + new Vector2i(-dist, dist);
case Direction.North:
return position + new Vector2i(0, dist);
case Direction.NorthEast:
return position + new Vector2i(dist, dist);
default:
throw new NotImplementedException();
}
}
/// <inheritdoc />
public IEnumerable<EntityUid> GetInDir(EntityCoordinates position, Direction dir)
{
var pos = SnapGridPosAt(TileIndicesFor(position), dir);
return GetAnchoredEntities(pos);
}
/// <inheritdoc />
public IEnumerable<EntityUid> GetOffset(EntityCoordinates coords, Vector2i offset)
{
var pos = TileIndicesFor(coords) + offset;
return GetAnchoredEntities(pos);
}
/// <inheritdoc />
public IEnumerable<EntityUid> GetLocal(EntityCoordinates coords)
{
return GetAnchoredEntities(TileIndicesFor(coords));
}
/// <inheritdoc />
public EntityCoordinates DirectionToGrid(EntityCoordinates coords, Direction direction)
{
return GridTileToLocal(SnapGridPosAt(TileIndicesFor(coords), direction));
}
/// <inheritdoc />
public IEnumerable<EntityUid> GetCardinalNeighborCells(EntityCoordinates coords)
{
var position = TileIndicesFor(coords);
foreach (var cell in GetAnchoredEntities(position))
yield return cell;
foreach (var cell in GetAnchoredEntities(position + new Vector2i(0, 1)))
yield return cell;
foreach (var cell in GetAnchoredEntities(position + new Vector2i(0, -1)))
yield return cell;
foreach (var cell in GetAnchoredEntities(position + new Vector2i(1, 0)))
yield return cell;
foreach (var cell in GetAnchoredEntities(position + new Vector2i(-1, 0)))
yield return cell;
}
/// <inheritdoc />
public IEnumerable<EntityUid> GetCellsInSquareArea(EntityCoordinates coords, int n)
{
var position = TileIndicesFor(coords);
for (var y = -n; y <= n; ++y)
for (var x = -n; x <= n; ++x)
{
foreach (var cell in GetAnchoredEntities(position + new Vector2i(x, y)))
{
yield return cell;
}
}
}
#endregion
#region Transforms
@@ -468,6 +529,8 @@ namespace Robust.Shared.Map
/// </summary>
public Vector2i CoordinatesToTile(EntityCoordinates coords)
{
DebugTools.Assert(ParentMapId == coords.GetMapId(_entityManager));
var local = WorldToLocal(coords.ToMapPos(_entityManager));
var x = (int)Math.Floor(local.X / TileSize);
var y = (int)Math.Floor(local.Y / TileSize);

View File

@@ -398,13 +398,12 @@ namespace Robust.Shared.Map
return _grids.Values;
}
public IMapGrid CreateGrid(MapId currentMapID, GridId? gridID = null, ushort chunkSize = 16, float snapSize = 1)
public IMapGrid CreateGrid(MapId currentMapID, GridId? gridID = null, ushort chunkSize = 16)
{
return CreateGridImpl(currentMapID, gridID, chunkSize, snapSize, true);
return CreateGridImpl(currentMapID, gridID, chunkSize, true);
}
private IMapGridInternal CreateGridImpl(MapId currentMapID, GridId? gridID, ushort chunkSize, float snapSize,
bool createEntity)
private IMapGridInternal CreateGridImpl(MapId currentMapID, GridId? gridID, ushort chunkSize, bool createEntity)
{
#if DEBUG
DebugTools.Assert(_dbgGuardRunning);
@@ -432,7 +431,7 @@ namespace Robust.Shared.Map
HighestGridID = actualID;
}
var grid = new MapGrid(this, _entityManager, actualID, chunkSize, snapSize, currentMapID);
var grid = new MapGrid(this, _entityManager, actualID, chunkSize, currentMapID);
_grids.Add(actualID, grid);
Logger.InfoS("map", $"Creating new grid {actualID}");
@@ -481,10 +480,9 @@ namespace Robust.Shared.Map
return grid;
}
public IMapGridInternal CreateGridNoEntity(MapId currentMapID, GridId? gridID = null, ushort chunkSize = 16,
float snapSize = 1)
public IMapGridInternal CreateGridNoEntity(MapId currentMapID, GridId? gridID = null, ushort chunkSize = 16)
{
return CreateGridImpl(currentMapID, gridID, chunkSize, snapSize, false);
return CreateGridImpl(currentMapID, gridID, chunkSize, false);
}
public IMapGrid GetGrid(GridId gridID)

View File

@@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.UnitTesting.Server;
namespace Robust.UnitTesting.Shared.GameObjects.Systems
{
[TestFixture, Parallelizable]
public class AnchoredSystemTests
{
private static readonly MapId TestMapId = new(1);
private static readonly GridId TestGridId = new(1);
private class Subscriber : IEntityEventSubscriber { }
private static ISimulation SimulationFactory()
{
var sim = RobustServerSimulation
.NewSimulation()
.InitializeInstance();
var mapManager = sim.Resolve<IMapManager>();
// Adds the map with id 1, and spawns entity 1 as the map entity.
mapManager.CreateMap(TestMapId);
// Add grid 1, as the default grid to anchor things to.
mapManager.CreateGrid(TestMapId, TestGridId);
return sim;
}
/// <summary>
/// When an entity is anchored to a grid tile, it's world position is unchanged.
/// </summary>
[Test]
public void Anchored_WorldPosition_Unchanged()
{
var sim = SimulationFactory();
var entMan = sim.Resolve<IEntityManager>();
var mapMan = sim.Resolve<IMapManager>();
var grid = mapMan.GetGrid(TestGridId);
var subscriber = new Subscriber();
int calledCount = 0;
entMan.EventBus.SubscribeEvent<MoveEvent>(EventSource.Local, subscriber, MoveEventHandler);
var ent1 = entMan.SpawnEntity(null, new MapCoordinates(Vector2.Zero, TestMapId));
// Act
var tileIndices = grid.TileIndicesFor(ent1.Transform.Coordinates);
grid.AddToSnapGridCell(tileIndices, ent1.Uid);
Assert.That(calledCount, Is.EqualTo(0));
void MoveEventHandler(MoveEvent ev)
{
Assert.Fail("MoveEvent raised when anchoring entity.");
calledCount++;
}
}
// Anchored entities have their world position locked where it is, their rotation locked and rounded to one of the 4 cardinal directions,
// and their parent changed to the grid they are anchored to. None of these 3 properties can be changed while anchored. Trying to write to these
// properties will silently fail.
// Because of these restrictions, they will never raise move or parent events while anchored.
// Anchored entities are registered as a tile entity to the grid tile they are above to when the flag is set. They are not moved when
// anchored. Content is free to place and orient the entity where it wants before anchoring.
// Entities cannot be anchored to space tiles. If a tile is changed to a space tile, all ents anchored to that tile are unanchored.
// An anchored entity is defined as an entity with the ITransformComponent.Anchored flag set. PhysicsComponent.Anchored is obsolete,
// And PhysicsComponent.BodyType is not able to be changed by content. PhysicsComponent.BodyType is synchronized with ITransformComponent.Anchored
// through anchored messages. SnapGridComponent is obsolete.
// Trying to anchor an entity to a space tile is a no-op.
// Adding an anchored entity to a container un-anchors it.
// Adding and removing a physics component should poll ITransformComponent.Anchored for the correct body type. Ents without a physics component can be anchored.
}
}

View File

@@ -0,0 +1,51 @@
using NUnit.Framework;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.UnitTesting.Server;
namespace Robust.UnitTesting.Shared.GameObjects.Systems
{
[TestFixture, Parallelizable]
class TransformSystemTests
{
private static ISimulation SimulationFactory()
{
var sim = RobustServerSimulation
.NewSimulation()
.InitializeInstance();
// Adds the map with id 1, and spawns entity 1 as the map entity.
sim.AddMap(1);
return sim;
}
/// <summary>
/// When the local position of the transform changes, a MoveEvent is raised.
/// </summary>
[Test]
public void OnMove_LocalPosChanged_RaiseMoveEvent()
{
var sim = SimulationFactory();
var entMan = sim.Resolve<IEntityManager>();
var subscriber = new Subscriber();
int calledCount = 0;
entMan.EventBus.SubscribeEvent<MoveEvent>(EventSource.Local, subscriber, MoveEventHandler);
var ent1 = entMan.SpawnEntity(null, new MapCoordinates(Vector2.Zero, new MapId(1)));
ent1.Transform.LocalPosition = Vector2.One;
Assert.That(calledCount, Is.EqualTo(1));
void MoveEventHandler(MoveEvent ev)
{
calledCount++;
Assert.That(ev.OldPosition, Is.EqualTo(new EntityCoordinates(new EntityUid(1), Vector2.Zero)));
Assert.That(ev.NewPosition, Is.EqualTo(new EntityCoordinates(new EntityUid(1), Vector2.One)));
}
}
private class Subscriber : IEntityEventSubscriber { }
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using Moq;
@@ -284,112 +284,6 @@ namespace Robust.UnitTesting.Shared.Map
Assert.That(result, Is.EqualTo("Chunk (7, 9)"));
}
[Test]
public void GetEmptySnapGrid()
{
var chunk = MapChunkFactory(7, 9);
Assert.That(chunk.GetSnapGridCell(0,0, SnapGridOffset.Center).ToList().Count, Is.EqualTo(0));
Assert.That(chunk.GetSnapGridCell(0, 0, SnapGridOffset.Edge).ToList().Count, Is.EqualTo(0));
}
[Test]
public void GetSnapGridThrowsOutOfRange()
{
var chunk = MapChunkFactory(7, 9);
Assert.Throws<ArgumentOutOfRangeException>((() => chunk.GetSnapGridCell(8,0, SnapGridOffset.Center).ToList()));
Assert.Throws<ArgumentOutOfRangeException>((() => chunk.GetSnapGridCell(0, 8, SnapGridOffset.Center).ToList()));
Assert.Throws<ArgumentOutOfRangeException>((() => chunk.GetSnapGridCell(8,0,SnapGridOffset.Edge).ToList()));
Assert.Throws<ArgumentOutOfRangeException>((() => chunk.GetSnapGridCell(0, 8, SnapGridOffset.Edge).ToList()));
}
[Test]
public void AddSnapGridCellCenter()
{
var chunk = MapChunkFactory(7, 9);
var snapGridComponent = new SnapGridComponent();
chunk.AddToSnapGridCell(3, 5, SnapGridOffset.Center, snapGridComponent);
chunk.AddToSnapGridCell(3, 5, SnapGridOffset.Edge, new SnapGridComponent());
chunk.AddToSnapGridCell(3, 6, SnapGridOffset.Center, new SnapGridComponent());
var result = chunk.GetSnapGridCell(3, 5, SnapGridOffset.Center).ToList();
Assert.That(result.Count, Is.EqualTo(1));
Assert.That(result[0], Is.EqualTo(snapGridComponent));
}
[Test]
public void AddSnapGridCellEdge()
{
var chunk = MapChunkFactory(7, 9);
var snapGridComponent = new SnapGridComponent();
chunk.AddToSnapGridCell(3, 5, SnapGridOffset.Edge, snapGridComponent);
chunk.AddToSnapGridCell(3, 5, SnapGridOffset.Center, new SnapGridComponent());
chunk.AddToSnapGridCell(3, 6, SnapGridOffset.Edge, new SnapGridComponent());
var result = chunk.GetSnapGridCell(3, 5, SnapGridOffset.Edge).ToList();
Assert.That(result.Count, Is.EqualTo(1));
Assert.That(result[0], Is.EqualTo(snapGridComponent));
}
[Test]
public void AddSnapGridThrowsOutOfRange()
{
var chunk = MapChunkFactory(7, 9);
Assert.Throws<ArgumentOutOfRangeException>((() => chunk.AddToSnapGridCell(8, 0, SnapGridOffset.Center, new SnapGridComponent())));
Assert.Throws<ArgumentOutOfRangeException>((() => chunk.AddToSnapGridCell(0, 8, SnapGridOffset.Center, new SnapGridComponent())));
Assert.Throws<ArgumentOutOfRangeException>((() => chunk.AddToSnapGridCell(8, 0, SnapGridOffset.Edge, new SnapGridComponent())));
Assert.Throws<ArgumentOutOfRangeException>((() => chunk.AddToSnapGridCell(0, 8, SnapGridOffset.Edge, new SnapGridComponent())));
}
[Test]
public void RemoveSnapGridCellCenter()
{
var chunk = MapChunkFactory(7, 9);
var snapGridComponent = new SnapGridComponent();
chunk.AddToSnapGridCell(3, 5, SnapGridOffset.Center, snapGridComponent);
chunk.AddToSnapGridCell(3, 5, SnapGridOffset.Edge, new SnapGridComponent());
chunk.AddToSnapGridCell(3, 6, SnapGridOffset.Center, new SnapGridComponent());
chunk.RemoveFromSnapGridCell(3, 5, SnapGridOffset.Center, snapGridComponent);
var result = chunk.GetSnapGridCell(3, 5, SnapGridOffset.Center).ToList();
Assert.That(result.Count, Is.EqualTo(0));
}
[Test]
public void RemoveSnapGridCellEdge()
{
var chunk = MapChunkFactory(7, 9);
var snapGridComponent = new SnapGridComponent();
chunk.AddToSnapGridCell(3, 5, SnapGridOffset.Edge, snapGridComponent);
chunk.AddToSnapGridCell(3, 5, SnapGridOffset.Center, new SnapGridComponent());
chunk.AddToSnapGridCell(3, 6, SnapGridOffset.Edge, new SnapGridComponent());
chunk.RemoveFromSnapGridCell(3, 5, SnapGridOffset.Edge, snapGridComponent);
var result = chunk.GetSnapGridCell(3, 5, SnapGridOffset.Edge).ToList();
Assert.That(result.Count, Is.EqualTo(0));
}
[Test]
public void RemoveSnapGridThrowsOutOfRange()
{
var chunk = MapChunkFactory(7, 9);
Assert.Throws<ArgumentOutOfRangeException>((() => chunk.RemoveFromSnapGridCell(8, 0, SnapGridOffset.Center, new SnapGridComponent())));
Assert.Throws<ArgumentOutOfRangeException>((() => chunk.RemoveFromSnapGridCell(0, 8, SnapGridOffset.Center, new SnapGridComponent())));
Assert.Throws<ArgumentOutOfRangeException>((() => chunk.RemoveFromSnapGridCell(8, 0, SnapGridOffset.Edge, new SnapGridComponent())));
Assert.Throws<ArgumentOutOfRangeException>((() => chunk.RemoveFromSnapGridCell(0, 8, SnapGridOffset.Edge, new SnapGridComponent())));
}
[Test]
public void BoundsExpandWhenTileAdded()
{

View File

@@ -170,7 +170,7 @@ namespace Robust.UnitTesting.Shared.Map
if(mapMan.GridExists(id))
mapMan.DeleteGrid(id);
var newGrid = mapMan.CreateGrid(mapId, id, 8, 1);
var newGrid = mapMan.CreateGrid(mapId, id, 8);
newGrid.WorldPosition = new Vector2(3, 5);
return (IMapGridInternal)newGrid;