mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-14 19:29:36 +01:00
Add grid merging (#3627)
* Add grid merging * More preliminary cleanup * Fixes * Fixes * weh * tweaks * Tests * weh * Fix direction test * Release notes
This commit is contained in:
@@ -39,7 +39,7 @@ END TEMPLATE-->
|
||||
|
||||
### New features
|
||||
|
||||
*None yet*
|
||||
* Add the ability to merge grids via GridFixtureSystem.
|
||||
|
||||
### Bugfixes
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ internal sealed class ClientOccluderSystem : OccluderSystem
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<OccluderComponent, AnchorStateChangedEvent>(OnAnchorChanged);
|
||||
SubscribeLocalEvent<OccluderComponent, ReAnchorEvent>(OnReAnchor);
|
||||
SubscribeLocalEvent<OccluderComponent, ComponentShutdown>(OnShutdown);
|
||||
}
|
||||
|
||||
@@ -90,11 +89,6 @@ internal sealed class ClientOccluderSystem : OccluderSystem
|
||||
AnchorStateChanged(uid, comp, args.Transform);
|
||||
}
|
||||
|
||||
private void OnReAnchor(EntityUid uid, OccluderComponent comp, ref ReAnchorEvent args)
|
||||
{
|
||||
AnchorStateChanged(uid, comp, args.Xform);
|
||||
}
|
||||
|
||||
private void QueueOccludedDirectionUpdate(EntityUid sender, OccluderComponent occluder, TransformComponent? xform = null)
|
||||
{
|
||||
if (!Resolve(sender, ref xform))
|
||||
@@ -174,8 +168,9 @@ internal sealed class ClientOccluderSystem : OccluderSystem
|
||||
|
||||
var tile = grid.TileIndicesFor(xform.Coordinates);
|
||||
|
||||
DebugTools.Assert(occluder.LastPosition == null
|
||||
|| occluder.LastPosition.Value.Grid == xform.GridUid && occluder.LastPosition.Value.Tile == tile);
|
||||
// TODO: Sub to parent changes instead or something.
|
||||
// DebugTools.Assert(occluder.LastPosition == null
|
||||
// || occluder.LastPosition.Value.Grid == xform.GridUid && occluder.LastPosition.Value.Tile == tile);
|
||||
occluder.LastPosition = (xform.GridUid.Value, tile);
|
||||
|
||||
// dir starts at the relative effective south direction;
|
||||
|
||||
138
Robust.Server/Physics/GridFixtureSystem.Merging.cs
Normal file
138
Robust.Server/Physics/GridFixtureSystem.Merging.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Robust.Server.Physics;
|
||||
|
||||
public sealed partial class GridFixtureSystem
|
||||
{
|
||||
/*
|
||||
* Something to keep in mind is that they rotate around the origin of a tile (e.g. 0,0), so a rotation of -90 degrees
|
||||
* moves the origin to 0, -1.
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Merges GridB into GridA.
|
||||
/// </summary>
|
||||
/// <param name="offset">Origin of GridB relative to GridA</param>
|
||||
/// <param name="rotation">Rotation to apply to GridB when being merged.
|
||||
/// Note that the rotation is applied before the offset so the offset itself will be rotated.</param>
|
||||
public void Merge(
|
||||
EntityUid gridAUid,
|
||||
EntityUid gridBUid,
|
||||
Vector2i offset,
|
||||
Angle rotation,
|
||||
MapGridComponent? gridA = null,
|
||||
MapGridComponent? gridB = null,
|
||||
TransformComponent? xformA = null,
|
||||
TransformComponent? xformB = null)
|
||||
{
|
||||
var matrix = Matrix3.CreateTransform(offset, rotation);
|
||||
Merge(gridAUid, gridBUid, matrix, gridA, gridB, xformA, xformB);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Merges GridB into GridA.
|
||||
/// </summary>
|
||||
/// <param name="offset">Origin of GridB relative to GridA</param>
|
||||
/// <param name="matrix">Matrix to apply to gridB when being merged.
|
||||
/// Note that rotation is applied first and then offset so the offset itself will be rotated.</param>
|
||||
public void Merge(
|
||||
EntityUid gridAUid,
|
||||
EntityUid gridBUid,
|
||||
Matrix3 matrix,
|
||||
MapGridComponent? gridA = null,
|
||||
MapGridComponent? gridB = null,
|
||||
TransformComponent? xformA = null,
|
||||
TransformComponent? xformB = null)
|
||||
{
|
||||
if (!Resolve(gridAUid, ref gridA, ref xformA))
|
||||
return;
|
||||
|
||||
if (!Resolve(gridBUid, ref gridB, ref xformB))
|
||||
return;
|
||||
|
||||
var sw = new Stopwatch();
|
||||
var tiles = new List<(Vector2i Indices, Tile Tile)>();
|
||||
var enumerator = _maps.GetAllTilesEnumerator(gridBUid, gridB);
|
||||
|
||||
while (enumerator.MoveNext(out var tileRef))
|
||||
{
|
||||
var offsetTile = matrix.Transform(new Vector2(tileRef.Value.GridIndices.X, tileRef.Value.GridIndices.Y) + gridA.TileSizeHalfVector);
|
||||
tiles.Add((offsetTile.Floored(), tileRef.Value.Tile));
|
||||
}
|
||||
|
||||
_maps.SetTiles(gridAUid, gridA, tiles);
|
||||
|
||||
enumerator = _maps.GetAllTilesEnumerator(gridBUid, gridB);
|
||||
var rotationDiff = matrix.Rotation();
|
||||
|
||||
while (enumerator.MoveNext(out var tileRef))
|
||||
{
|
||||
var chunkOrigin = SharedMapSystem.GetChunkIndices(tileRef.Value.GridIndices, gridB.ChunkSize);
|
||||
|
||||
if (!_maps.TryGetChunk(gridBUid, gridB, chunkOrigin, out var chunk))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var chunkLocalTile = SharedMapSystem.GetChunkRelative(tileRef.Value.GridIndices, gridB.ChunkSize);
|
||||
var snapgrid = chunk.GetSnapGrid((ushort) chunkLocalTile.X, (ushort) chunkLocalTile.Y);
|
||||
|
||||
if (snapgrid == null || snapgrid.Count == 0)
|
||||
continue;
|
||||
|
||||
var offsetTile = matrix.Transform(new Vector2(tileRef.Value.GridIndices.X, tileRef.Value.GridIndices.Y) + gridA.TileSizeHalfVector);
|
||||
var tileIndex = offsetTile.Floored();
|
||||
|
||||
for (var j = snapgrid.Count - 1; j >= 0; j--)
|
||||
{
|
||||
var ent = snapgrid[j];
|
||||
var xform = _xformQuery.GetComponent(ent);
|
||||
_xformSystem.ReAnchor(ent, xform,
|
||||
gridB, gridA,
|
||||
tileRef.Value.GridIndices, tileIndex,
|
||||
gridBUid, gridAUid,
|
||||
xformB, xformA,
|
||||
rotationDiff);
|
||||
|
||||
DebugTools.Assert(xform.ParentUid == gridAUid);
|
||||
}
|
||||
|
||||
DebugTools.Assert(snapgrid.Count == 0);
|
||||
}
|
||||
|
||||
enumerator = _maps.GetAllTilesEnumerator(gridBUid, gridB);
|
||||
|
||||
while (enumerator.MoveNext(out var tileRef))
|
||||
{
|
||||
var bounds = _lookup.GetLocalBounds(tileRef.Value.GridIndices, gridB.TileSize);
|
||||
|
||||
_entSet.Clear();
|
||||
_lookup.GetLocalEntitiesIntersecting(gridBUid, bounds, _entSet, LookupFlags.All | ~LookupFlags.Contained | LookupFlags.Approximate);
|
||||
|
||||
foreach (var ent in _entSet)
|
||||
{
|
||||
// Consider centre of entity position maybe?
|
||||
var entXform = _xformQuery.GetComponent(ent);
|
||||
|
||||
if (entXform.ParentUid != gridBUid ||
|
||||
!bounds.Contains(entXform.LocalPosition)) continue;
|
||||
|
||||
var newPos = matrix.Transform(entXform.LocalPosition);
|
||||
|
||||
_xformSystem.SetCoordinates(ent, entXform, new EntityCoordinates(gridAUid, newPos), entXform.LocalRotation + rotationDiff, oldParent: xformB, newParent: xformA);
|
||||
}
|
||||
}
|
||||
|
||||
DebugTools.Assert(xformB.ChildCount == 0);
|
||||
Del(gridBUid);
|
||||
|
||||
Log.Debug($"Merged grids in {sw.Elapsed.TotalMilliseconds}ms");
|
||||
}
|
||||
}
|
||||
@@ -23,16 +23,16 @@ namespace Robust.Server.Physics
|
||||
/// <summary>
|
||||
/// Handles generating fixtures for MapGrids.
|
||||
/// </summary>
|
||||
public sealed class GridFixtureSystem : SharedGridFixtureSystem
|
||||
public sealed partial class GridFixtureSystem : SharedGridFixtureSystem
|
||||
{
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||
[Dependency] private readonly IConGroupController _conGroup = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
[Dependency] private readonly SharedMapSystem _maps = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _xformSystem = default!;
|
||||
|
||||
private ISawmill _logger = default!;
|
||||
private readonly Dictionary<EntityUid, Dictionary<Vector2i, ChunkNodeGroup>> _nodes = new();
|
||||
|
||||
/// <summary>
|
||||
@@ -47,10 +47,19 @@ namespace Robust.Server.Physics
|
||||
|
||||
internal bool SplitAllowed = true;
|
||||
|
||||
private HashSet<EntityUid> _entSet = new();
|
||||
|
||||
private EntityQuery<MapGridComponent> _gridQuery;
|
||||
private EntityQuery<PhysicsComponent> _bodyQuery;
|
||||
private EntityQuery<TransformComponent> _xformQuery;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_logger = Logger.GetSawmill("gsplit");
|
||||
|
||||
_gridQuery = GetEntityQuery<MapGridComponent>();
|
||||
_bodyQuery = GetEntityQuery<PhysicsComponent>();
|
||||
_xformQuery = GetEntityQuery<TransformComponent>();
|
||||
SubscribeLocalEvent<GridRemovalEvent>(OnGridRemoval);
|
||||
SubscribeNetworkEvent<RequestGridNodesMessage>(OnDebugRequest);
|
||||
SubscribeNetworkEvent<StopGridNodesMessage>(OnDebugStopRequest);
|
||||
@@ -197,7 +206,7 @@ namespace Robust.Server.Physics
|
||||
}
|
||||
|
||||
_isSplitting = true;
|
||||
_logger.Debug($"Started split check for {ToPrettyString(uid)}");
|
||||
Log.Debug($"Started split check for {ToPrettyString(uid)}");
|
||||
var splitFrontier = new Queue<ChunkSplitNode>(4);
|
||||
var grids = new List<HashSet<ChunkSplitNode>>(1);
|
||||
|
||||
@@ -234,7 +243,7 @@ namespace Robust.Server.Physics
|
||||
// Split time
|
||||
if (grids.Count > 1)
|
||||
{
|
||||
_logger.Info($"Splitting {ToPrettyString(uid)} into {grids.Count} grids.");
|
||||
Log.Info($"Splitting {ToPrettyString(uid)} into {grids.Count} grids.");
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
|
||||
@@ -244,13 +253,10 @@ namespace Robust.Server.Physics
|
||||
x.Sum(o => o.Indices.Count)
|
||||
.CompareTo(y.Sum(o => o.Indices.Count)));
|
||||
|
||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||
var bodyQuery = GetEntityQuery<PhysicsComponent>();
|
||||
var gridQuery = GetEntityQuery<MapGridComponent>();
|
||||
var oldGridXform = xformQuery.GetComponent(oldGridUid);
|
||||
var (gridPos, gridRot) = _xformSystem.GetWorldPositionRotation(oldGridXform, xformQuery);
|
||||
var mapBody = bodyQuery.GetComponent(oldGridUid);
|
||||
var oldGridComp = gridQuery.GetComponent(oldGridUid);
|
||||
var oldGridXform = _xformQuery.GetComponent(oldGridUid);
|
||||
var (gridPos, gridRot) = _xformSystem.GetWorldPositionRotation(oldGridXform);
|
||||
var mapBody = _bodyQuery.GetComponent(oldGridUid);
|
||||
var oldGridComp = _gridQuery.GetComponent(oldGridUid);
|
||||
var newGrids = new EntityUid[grids.Count - 1];
|
||||
var mapId = oldGridXform.MapID;
|
||||
|
||||
@@ -259,17 +265,17 @@ namespace Robust.Server.Physics
|
||||
var group = grids[i];
|
||||
var newGrid = _mapManager.CreateGridEntity(mapId);
|
||||
var newGridUid = newGrid.Owner;
|
||||
var newGridXform = xformQuery.GetComponent(newGridUid);
|
||||
var newGridXform = _xformQuery.GetComponent(newGridUid);
|
||||
newGrids[i] = newGridUid;
|
||||
|
||||
// Keep same origin / velocity etc; this makes updating a lot faster and easier.
|
||||
_xformSystem.SetWorldPosition(newGridXform, gridPos);
|
||||
_xformSystem.SetWorldPositionRotation(newGridXform, gridPos, gridRot);
|
||||
var splitBody = bodyQuery.GetComponent(newGridUid);
|
||||
_xformSystem.SetWorldPositionRotation(newGridUid, gridPos, gridRot, newGridXform);
|
||||
var splitBody = _bodyQuery.GetComponent(newGridUid);
|
||||
_physics.SetLinearVelocity(newGridUid, mapBody.LinearVelocity, body: splitBody);
|
||||
_physics.SetAngularVelocity(newGridUid, mapBody.AngularVelocity, body: splitBody);
|
||||
|
||||
var gridComp = gridQuery.GetComponent(newGridUid);
|
||||
var gridComp = _gridQuery.GetComponent(newGridUid);
|
||||
var tileData = new List<(Vector2i GridIndices, Tile Tile)>(group.Sum(o => o.Indices.Count));
|
||||
|
||||
// Gather all tiles up front and set once to minimise fixture change events
|
||||
@@ -284,7 +290,7 @@ namespace Robust.Server.Physics
|
||||
}
|
||||
}
|
||||
|
||||
newGrid.Comp.SetTiles(tileData);
|
||||
_maps.SetTiles(newGrid.Owner, newGrid.Comp, tileData);
|
||||
DebugTools.Assert(_mapManager.IsGrid(newGridUid), "A split grid had no tiles?");
|
||||
|
||||
// Set tiles on new grid + update anchored entities
|
||||
@@ -303,8 +309,13 @@ namespace Robust.Server.Physics
|
||||
for (var j = snapgrid.Count - 1; j >= 0; j--)
|
||||
{
|
||||
var ent = snapgrid[j];
|
||||
var xform = xformQuery.GetComponent(ent);
|
||||
_xformSystem.ReAnchor(ent, xform, oldGridComp, gridComp, tilePos, oldGridUid, newGridUid, oldGridXform, newGridXform, xformQuery);
|
||||
var xform = _xformQuery.GetComponent(ent);
|
||||
_xformSystem.ReAnchor(ent, xform,
|
||||
oldGridComp, gridComp,
|
||||
tilePos, tilePos,
|
||||
oldGridUid, newGridUid,
|
||||
oldGridXform, newGridXform,
|
||||
Angle.Zero);
|
||||
DebugTools.Assert(xform.Anchored);
|
||||
}
|
||||
}
|
||||
@@ -317,15 +328,18 @@ namespace Robust.Server.Physics
|
||||
var tilePos = offset + tile;
|
||||
var bounds = _lookup.GetLocalBounds(tilePos, oldGrid.TileSize);
|
||||
|
||||
foreach (var ent in _lookup.GetLocalEntitiesIntersecting(oldGridUid, tilePos, 0f, LookupFlags.Dynamic | LookupFlags.Sundries))
|
||||
_entSet.Clear();
|
||||
_lookup.GetLocalEntitiesIntersecting(oldGridUid, tilePos, _entSet, 0f, LookupFlags.All | ~LookupFlags.Uncontained | LookupFlags.Approximate);
|
||||
|
||||
foreach (var ent in _entSet)
|
||||
{
|
||||
// Consider centre of entity position maybe?
|
||||
var entXform = xformQuery.GetComponent(ent);
|
||||
var entXform = _xformQuery.GetComponent(ent);
|
||||
|
||||
if (entXform.ParentUid != oldGridUid ||
|
||||
!bounds.Contains(entXform.LocalPosition)) continue;
|
||||
|
||||
_xformSystem.SetParent(ent, entXform, newGridUid, xformQuery, newGridXform);
|
||||
_xformSystem.SetParent(ent, entXform, newGridUid, _xformQuery, newGridXform);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,10 +379,10 @@ namespace Robust.Server.Physics
|
||||
var ev = new GridSplitEvent(newGrids, oldGridUid);
|
||||
RaiseLocalEvent(uid, ref ev, true);
|
||||
|
||||
_logger.Debug($"Split {grids.Count} grids in {sw.Elapsed}");
|
||||
Log.Debug($"Split {grids.Count} grids in {sw.Elapsed}");
|
||||
}
|
||||
|
||||
_logger.Debug($"Stopped split check for {ToPrettyString(uid)}");
|
||||
Log.Debug($"Stopped split check for {ToPrettyString(uid)}");
|
||||
_isSplitting = false;
|
||||
SendNodeDebug(oldGridUid);
|
||||
}
|
||||
|
||||
55
Robust.Server/Physics/MergeGridsCommand.cs
Normal file
55
Robust.Server/Physics/MergeGridsCommand.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using Robust.Shared.Console;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Server.Physics;
|
||||
|
||||
public sealed class MergeGridsCommand : IConsoleCommand
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
|
||||
public string Command => "merge_grids";
|
||||
public string Description => $"Combines 2 grids into 1 grid";
|
||||
public string Help => $"{Command} <gridUid1> <gridUid2> <offsetX> <offsetY> [rotation]";
|
||||
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (args.Length < 4)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!NetEntity.TryParse(args[0], out var gridANet) ||
|
||||
!NetEntity.TryParse(args[1], out var gridBNet))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var gridAUid = _entManager.GetEntity(gridANet);
|
||||
var gridBUid = _entManager.GetEntity(gridBNet);
|
||||
|
||||
if (!_entManager.TryGetComponent<MapGridComponent>(gridAUid, out var gridA) ||
|
||||
!_entManager.TryGetComponent<MapGridComponent>(gridBUid, out var gridB))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!int.TryParse(args[2], out var x) ||
|
||||
!int.TryParse(args[3], out var y))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Angle rotation = Angle.Zero;
|
||||
|
||||
if (args.Length >= 5 && int.TryParse(args[4], out var rotationInt))
|
||||
{
|
||||
rotation = Angle.FromDegrees(rotationInt);
|
||||
}
|
||||
|
||||
var offset = new Vector2i(x, y);
|
||||
var fixtureSystem = _entManager.System<GridFixtureSystem>();
|
||||
fixtureSystem.Merge(gridAUid, gridBUid, offset, rotation, gridA: gridA, gridB: gridB);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -258,7 +259,24 @@ namespace Robust.Shared.Maths
|
||||
/// <param name="degrees">The angle in degrees.</param>
|
||||
public static Angle FromDegrees(double degrees)
|
||||
{
|
||||
return new(MathHelper.DegreesToRadians(degrees));
|
||||
// Avoid rounding issues with common use cases.
|
||||
switch (degrees)
|
||||
{
|
||||
case -270:
|
||||
return new Angle(Math.PI * -1.5);
|
||||
case 90:
|
||||
return new Angle(Math.PI / 2);
|
||||
case -180:
|
||||
return new Angle(-Math.PI);
|
||||
case 180:
|
||||
return new Angle(Math.PI);
|
||||
case 270.0:
|
||||
return new Angle(Math.PI * 1.5);
|
||||
case -90:
|
||||
return new Angle(Math.PI / -2);
|
||||
default:
|
||||
return new(MathHelper.DegreesToRadians(degrees));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -109,6 +109,11 @@ namespace Robust.Shared.Maths
|
||||
}
|
||||
}
|
||||
|
||||
public Vector2i Rotate(Angle angle)
|
||||
{
|
||||
return (Vector2i) angle.RotateVec(this);
|
||||
}
|
||||
|
||||
public static Vector2i operator -(Vector2i a, Vector2i b)
|
||||
{
|
||||
return new(a.X - b.X, a.Y - b.Y);
|
||||
|
||||
@@ -722,6 +722,21 @@ public abstract partial class SharedMapSystem
|
||||
return new GridTileEnumerator(uid, grid.Chunks.GetEnumerator(), grid.ChunkSize, ignoreEmpty);
|
||||
}
|
||||
|
||||
public void SetTile(Entity<MapGridComponent> grid, EntityCoordinates coordinates, Tile tile)
|
||||
{
|
||||
SetTile(grid.Owner, grid.Comp, coordinates, tile);
|
||||
}
|
||||
|
||||
public void SetTile(Entity<MapGridComponent> grid, Vector2i gridIndices, Tile tile)
|
||||
{
|
||||
SetTile(grid.Owner, grid.Comp, gridIndices, tile);
|
||||
}
|
||||
|
||||
public void SetTiles(Entity<MapGridComponent> grid, List<(Vector2i GridIndices, Tile Tile)> tiles)
|
||||
{
|
||||
SetTiles(grid.Owner, grid.Comp, tiles);
|
||||
}
|
||||
|
||||
public void SetTile(EntityUid uid, MapGridComponent grid, EntityCoordinates coords, Tile tile)
|
||||
{
|
||||
var localTile = CoordinatesToTile(uid, grid, coords);
|
||||
|
||||
@@ -23,15 +23,16 @@ public abstract partial class SharedTransformSystem
|
||||
TransformComponent xform,
|
||||
MapGridComponent oldGrid,
|
||||
MapGridComponent newGrid,
|
||||
Vector2i oldTilePos,
|
||||
Vector2i tilePos,
|
||||
EntityUid oldGridUid,
|
||||
EntityUid newGridUid,
|
||||
TransformComponent oldGridXform,
|
||||
TransformComponent newGridXform,
|
||||
EntityQuery<TransformComponent> xformQuery)
|
||||
Angle rotation)
|
||||
{
|
||||
// Bypass some of the expensive stuff in unanchoring / anchoring.
|
||||
_map.RemoveFromSnapGridCell(oldGridUid, oldGrid, tilePos, uid);
|
||||
_map.RemoveFromSnapGridCell(oldGridUid, oldGrid, oldTilePos, uid);
|
||||
_map.AddToSnapGridCell(newGridUid, newGrid, tilePos, uid);
|
||||
// TODO: Could do this re-parent way better.
|
||||
// Unfortunately we don't want any anchoring events to go out hence... this.
|
||||
@@ -40,21 +41,25 @@ public abstract partial class SharedTransformSystem
|
||||
newGridXform._children.Add(uid);
|
||||
xform._parent = newGridUid;
|
||||
xform._anchored = true;
|
||||
var oldPos = xform._localPosition;
|
||||
var oldRot = xform._localRotation;
|
||||
xform._localPosition = tilePos + newGrid.TileSizeHalfVector;
|
||||
xform._localRotation += rotation;
|
||||
|
||||
SetGridId(uid, xform, newGridUid, xformQuery);
|
||||
SetGridId(uid, xform, newGridUid, XformQuery);
|
||||
var reParent = new EntParentChangedMessage(uid, oldGridUid, xform.MapID, xform);
|
||||
RaiseLocalEvent(uid, ref reParent, true);
|
||||
var meta = MetaData(uid);
|
||||
var movEevee = new MoveEvent((uid, xform, meta),
|
||||
new EntityCoordinates(oldGridUid, xform._localPosition),
|
||||
new EntityCoordinates(oldGridUid, oldPos),
|
||||
new EntityCoordinates(newGridUid, xform._localPosition),
|
||||
xform.LocalRotation,
|
||||
oldRot,
|
||||
xform.LocalRotation,
|
||||
_gameTiming.ApplyingState);
|
||||
RaiseLocalEvent(uid, ref movEevee);
|
||||
InvokeGlobalMoveEvent(ref movEevee);
|
||||
|
||||
DebugTools.Assert(xformQuery.GetComponent(oldGridUid).MapID == xformQuery.GetComponent(newGridUid).MapID);
|
||||
DebugTools.Assert(XformQuery.GetComponent(oldGridUid).MapID == XformQuery.GetComponent(newGridUid).MapID);
|
||||
DebugTools.Assert(xform._anchored);
|
||||
|
||||
Dirty(uid, xform, meta);
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace Robust.UnitTesting.Shared.Map
|
||||
/// <summary>
|
||||
/// Tests whether grid fixtures are being generated correctly.
|
||||
/// </summary>
|
||||
[Parallelizable(ParallelScope.All)]
|
||||
[TestFixture]
|
||||
public sealed class GridFixtures_Tests : RobustIntegrationTest
|
||||
{
|
||||
|
||||
69
Robust.UnitTesting/Shared/Map/GridMerge_Tests.cs
Normal file
69
Robust.UnitTesting/Shared/Map/GridMerge_Tests.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using Robust.Server.Physics;
|
||||
using Robust.Shared;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.UnitTesting.Server;
|
||||
|
||||
namespace Robust.UnitTesting.Shared.Map;
|
||||
|
||||
[Parallelizable(ParallelScope.All | ParallelScope.Fixtures)]
|
||||
[TestFixture]
|
||||
public sealed class GridMerge_Tests
|
||||
{
|
||||
private ISimulation GetSim()
|
||||
{
|
||||
var sim = RobustServerSimulation.NewSimulation().InitializeInstance();
|
||||
|
||||
var config = sim.Resolve<IConfigurationManager>();
|
||||
config.SetCVar(CVars.GridSplitting, true);
|
||||
|
||||
return sim;
|
||||
}
|
||||
|
||||
private static readonly TestCaseData[] MergeCases = new[]
|
||||
{
|
||||
new TestCaseData(new Vector2i(-1, 0), Angle.Zero, new Box2(-1f, 0f, 1f, 3f)),
|
||||
new TestCaseData(new Vector2i(0, 3), Angle.Zero, new Box2(0f, 0f, 1f, 6f)),
|
||||
new TestCaseData(new Vector2i(0, 1), Angle.FromDegrees(90), new Box2(-3f, 0f, 1f, 3f)),
|
||||
new TestCaseData(new Vector2i(1, 3), Angle.FromDegrees(-90), new Box2(0f, 0f, 4f, 3f)),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Checks 2 grids merge properly.
|
||||
/// </summary>
|
||||
[Test, TestCaseSource(nameof(MergeCases))]
|
||||
public void Merge(Vector2i offset, Angle angle, Box2 bounds)
|
||||
{
|
||||
var sim = GetSim();
|
||||
var mapManager = sim.Resolve<IMapManager>();
|
||||
var entMan = sim.Resolve<IEntityManager>();
|
||||
var mapSystem = entMan.System<SharedMapSystem>();
|
||||
var gridFixtures = entMan.System<GridFixtureSystem>();
|
||||
|
||||
var mapId = mapManager.CreateMap();
|
||||
var grid1 = mapManager.CreateGridEntity(mapId);
|
||||
var grid2 = mapManager.CreateGridEntity(mapId);
|
||||
var tiles = new List<(Vector2i, Tile)>();
|
||||
|
||||
for (var y = 0; y < 3; y++)
|
||||
{
|
||||
tiles.Add((new Vector2i(0, y), new Tile(1)));
|
||||
}
|
||||
|
||||
mapSystem.SetTiles(grid1, tiles);
|
||||
mapSystem.SetTiles(grid2, tiles);
|
||||
|
||||
Assert.That(mapManager.GetAllGrids(mapId).Count(), Is.EqualTo(2));
|
||||
|
||||
gridFixtures.Merge(grid1.Owner, grid2.Owner, offset, angle, grid1.Comp, grid2.Comp);
|
||||
|
||||
Assert.That(mapManager.GetAllGrids(mapId).Count(), Is.EqualTo(1));
|
||||
|
||||
Assert.That(grid1.Comp.LocalAABB, Is.EqualTo(bounds));
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ using Robust.UnitTesting.Server;
|
||||
|
||||
namespace Robust.UnitTesting.Shared.Map;
|
||||
|
||||
[Parallelizable(ParallelScope.All | ParallelScope.Fixtures)]
|
||||
[TestFixture]
|
||||
public sealed class GridSplit_Tests
|
||||
{
|
||||
@@ -31,6 +32,8 @@ public sealed class GridSplit_Tests
|
||||
{
|
||||
var sim = GetSim();
|
||||
var mapManager = sim.Resolve<IMapManager>();
|
||||
var mapSystem = sim.Resolve<IEntityManager>().System<SharedMapSystem>();
|
||||
|
||||
var mapId = mapManager.CreateMap();
|
||||
var gridEnt = mapManager.CreateGridEntity(mapId);
|
||||
var grid = gridEnt.Comp;
|
||||
@@ -38,16 +41,16 @@ public sealed class GridSplit_Tests
|
||||
|
||||
for (var x = 0; x < 5; x++)
|
||||
{
|
||||
grid.SetTile(new Vector2i(x, 0), new Tile(1));
|
||||
mapSystem.SetTile(gridEnt, new Vector2i(x, 0), new Tile(1));
|
||||
}
|
||||
|
||||
Assert.That(mapManager.GetAllGrids(mapId).Count(), Is.EqualTo(1));
|
||||
|
||||
grid.SetTile(new Vector2i(1, 0), Tile.Empty);
|
||||
mapSystem.SetTile(gridEnt, new Vector2i(1, 0), Tile.Empty);
|
||||
Assert.That(mapManager.GetAllGrids(mapId).Count(), Is.EqualTo(1));
|
||||
|
||||
grid.CanSplit = true;
|
||||
grid.SetTile(new Vector2i(2, 0), Tile.Empty);
|
||||
mapSystem.SetTile(gridEnt, new Vector2i(2, 0), Tile.Empty);
|
||||
Assert.That(mapManager.GetAllGrids(mapId).Count(), Is.EqualTo(2));
|
||||
|
||||
mapManager.DeleteMap(mapId);
|
||||
@@ -58,18 +61,18 @@ public sealed class GridSplit_Tests
|
||||
{
|
||||
var sim = GetSim();
|
||||
var mapManager = sim.Resolve<IMapManager>();
|
||||
var mapSystem = sim.Resolve<IEntityManager>().System<SharedMapSystem>();
|
||||
var mapId = mapManager.CreateMap();
|
||||
var gridEnt = mapManager.CreateGridEntity(mapId);
|
||||
var grid = gridEnt.Comp;
|
||||
|
||||
for (var x = 0; x < 3; x++)
|
||||
{
|
||||
grid.SetTile(new Vector2i(x, 0), new Tile(1));
|
||||
mapSystem.SetTile(gridEnt, new Vector2i(x, 0), new Tile(1));
|
||||
}
|
||||
|
||||
Assert.That(mapManager.GetAllGrids(mapId).Count(), Is.EqualTo(1));
|
||||
|
||||
grid.SetTile(new Vector2i(1, 0), Tile.Empty);
|
||||
mapSystem.SetTile(gridEnt, new Vector2i(1, 0), Tile.Empty);
|
||||
Assert.That(mapManager.GetAllGrids(mapId).Count(), Is.EqualTo(2));
|
||||
|
||||
mapManager.DeleteMap(mapId);
|
||||
@@ -80,27 +83,27 @@ public sealed class GridSplit_Tests
|
||||
{
|
||||
var sim = GetSim();
|
||||
var mapManager = sim.Resolve<IMapManager>();
|
||||
var mapSystem = sim.Resolve<IEntityManager>().System<SharedMapSystem>();
|
||||
var mapId = mapManager.CreateMap();
|
||||
var gridEnt = mapManager.CreateGridEntity(mapId);
|
||||
var grid = gridEnt.Comp;
|
||||
|
||||
for (var x = 0; x < 3; x++)
|
||||
{
|
||||
for (var y = 0; y < 3; y++)
|
||||
{
|
||||
grid.SetTile(new Vector2i(x, y), new Tile(1));
|
||||
mapSystem.SetTile(gridEnt, new Vector2i(x, y), new Tile(1));
|
||||
}
|
||||
}
|
||||
|
||||
Assert.That(mapManager.GetAllGrids(mapId).Count(), Is.EqualTo(1));
|
||||
|
||||
grid.SetTile(Vector2i.One, Tile.Empty);
|
||||
mapSystem.SetTile(gridEnt, Vector2i.One, Tile.Empty);
|
||||
Assert.That(mapManager.GetAllGrids(mapId).Count(), Is.EqualTo(1));
|
||||
|
||||
grid.SetTile(new Vector2i(1, 2), Tile.Empty);
|
||||
mapSystem.SetTile(gridEnt, new Vector2i(1, 2), Tile.Empty);
|
||||
Assert.That(mapManager.GetAllGrids(mapId).Count(), Is.EqualTo(1));
|
||||
|
||||
grid.SetTile(new Vector2i(1, 0), Tile.Empty);
|
||||
mapSystem.SetTile(gridEnt, new Vector2i(1, 0), Tile.Empty);
|
||||
Assert.That(mapManager.GetAllGrids(mapId).Count(), Is.EqualTo(2));
|
||||
|
||||
mapManager.DeleteMap(mapId);
|
||||
@@ -111,20 +114,21 @@ public sealed class GridSplit_Tests
|
||||
{
|
||||
var sim = GetSim();
|
||||
var mapManager = sim.Resolve<IMapManager>();
|
||||
var mapSystem = sim.Resolve<IEntityManager>().System<SharedMapSystem>();
|
||||
var mapId = mapManager.CreateMap();
|
||||
var gridEnt = mapManager.CreateGridEntity(mapId);
|
||||
var grid = gridEnt.Comp;
|
||||
|
||||
for (var x = 0; x < 3; x++)
|
||||
{
|
||||
grid.SetTile(new Vector2i(x, 0), new Tile(1));
|
||||
mapSystem.SetTile(gridEnt , new Vector2i(x, 0), new Tile(1));
|
||||
}
|
||||
|
||||
grid.SetTile(Vector2i.One, new Tile(1));
|
||||
mapSystem.SetTile(gridEnt, Vector2i.One, new Tile(1));
|
||||
|
||||
Assert.That(mapManager.GetAllGrids(mapId).Count(), Is.EqualTo(1));
|
||||
|
||||
grid.SetTile(new Vector2i(1, 0), Tile.Empty);
|
||||
mapSystem.SetTile(gridEnt, new Vector2i(1, 0), Tile.Empty);
|
||||
Assert.That(mapManager.GetAllGrids(mapId).Count(), Is.EqualTo(3));
|
||||
|
||||
mapManager.DeleteMap(mapId);
|
||||
@@ -139,13 +143,14 @@ public sealed class GridSplit_Tests
|
||||
var sim = GetSim();
|
||||
var entManager = sim.Resolve<IEntityManager>();
|
||||
var mapManager = sim.Resolve<IMapManager>();
|
||||
var mapSystem = sim.Resolve<IEntityManager>().System<SharedMapSystem>();
|
||||
var mapId = mapManager.CreateMap();
|
||||
var gridEnt = mapManager.CreateGridEntity(mapId);
|
||||
var grid = gridEnt.Comp;
|
||||
|
||||
for (var x = 0; x < 4; x++)
|
||||
{
|
||||
grid.SetTile(new Vector2i(x, 0), new Tile(1));
|
||||
mapSystem.SetTile(gridEnt, new Vector2i(x, 0), new Tile(1));
|
||||
}
|
||||
|
||||
Assert.That(mapManager.GetAllGrids(mapId).Count(), Is.EqualTo(1));
|
||||
@@ -157,7 +162,7 @@ public sealed class GridSplit_Tests
|
||||
anchoredXform.Anchored = true;
|
||||
Assert.That(anchoredXform.Anchored);
|
||||
|
||||
grid.SetTile(new Vector2i(2, 0), Tile.Empty);
|
||||
mapSystem.SetTile(gridEnt, new Vector2i(2, 0), Tile.Empty);
|
||||
Assert.That(mapManager.GetAllGrids(mapId).Count(), Is.EqualTo(2));
|
||||
|
||||
var newGrid = mapManager.GetAllMapGrids(mapId).First(x => x != grid);
|
||||
|
||||
Reference in New Issue
Block a user