Skip to content

Commit

Permalink
Navmap rework (#26713)
Browse files Browse the repository at this point in the history
* Optimized the drawing of lines and tracked entities

* Optimized nav map updating and added thin wall support

* Added support for thin doors

* Removed floor tile seams, more line drawing optimizations

* Fixed split grids not updating correctly

* Cleaned up NavMapControl code

* Fix nav map header

* Converted nav map updates from system network messages to delta-states

* Addressed review comments

* Fixed timing issue where NavMapSystem would update before AirtightSystem did
  • Loading branch information
chromiumboy authored Apr 17, 2024
1 parent 20b1694 commit 009d06d
Show file tree
Hide file tree
Showing 8 changed files with 891 additions and 584 deletions.
110 changes: 32 additions & 78 deletions Content.Client/Pinpointer/NavMapSystem.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
using System.Numerics;
using Content.Shared.Pinpointer;
using Robust.Client.Graphics;
using Robust.Shared.Enums;
using Robust.Shared.GameStates;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;

namespace Content.Client.Pinpointer;

public sealed class NavMapSystem : SharedNavMapSystem
public sealed partial class NavMapSystem : SharedNavMapSystem
{
public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<NavMapComponent, ComponentHandleState>(OnHandleState);
}

Expand All @@ -21,89 +17,47 @@ private void OnHandleState(EntityUid uid, NavMapComponent component, ref Compone
if (args.Current is not NavMapComponentState state)
return;

component.Chunks.Clear();

foreach (var (origin, data) in state.TileData)
if (!state.FullState)
{
component.Chunks.Add(origin, new NavMapChunk(origin)
foreach (var index in component.Chunks.Keys)
{
TileData = data,
});
}

component.Beacons.Clear();
component.Beacons.AddRange(state.Beacons);

component.Airlocks.Clear();
component.Airlocks.AddRange(state.Airlocks);
}
}

public sealed class NavMapOverlay : Overlay
{
private readonly IEntityManager _entManager;
private readonly IMapManager _mapManager;

public override OverlaySpace Space => OverlaySpace.WorldSpace;

private List<Entity<MapGridComponent>> _grids = new();

public NavMapOverlay(IEntityManager entManager, IMapManager mapManager)
{
_entManager = entManager;
_mapManager = mapManager;
}

protected override void Draw(in OverlayDrawArgs args)
{
var query = _entManager.GetEntityQuery<NavMapComponent>();
var xformQuery = _entManager.GetEntityQuery<TransformComponent>();
var scale = Matrix3.CreateScale(new Vector2(1f, 1f));
if (!state.AllChunks!.Contains(index))
component.Chunks.Remove(index);
}

_grids.Clear();
_mapManager.FindGridsIntersecting(args.MapId, args.WorldBounds, ref _grids);
foreach (var beacon in component.Beacons)
{
if (!state.AllBeacons!.Contains(beacon))
component.Beacons.Remove(beacon);
}
}

foreach (var grid in _grids)
else
{
if (!query.TryGetComponent(grid, out var navMap) || !xformQuery.TryGetComponent(grid.Owner, out var xform))
continue;

// TODO: Faster helper method
var (_, _, matrix, invMatrix) = xform.GetWorldPositionRotationMatrixWithInv();

var localAABB = invMatrix.TransformBox(args.WorldBounds);
Matrix3.Multiply(in scale, in matrix, out var matty);

args.WorldHandle.SetTransform(matty);

for (var x = Math.Floor(localAABB.Left); x <= Math.Ceiling(localAABB.Right); x += SharedNavMapSystem.ChunkSize * grid.Comp.TileSize)
foreach (var index in component.Chunks.Keys)
{
for (var y = Math.Floor(localAABB.Bottom); y <= Math.Ceiling(localAABB.Top); y += SharedNavMapSystem.ChunkSize * grid.Comp.TileSize)
{
var floored = new Vector2i((int) x, (int) y);

var chunkOrigin = SharedMapSystem.GetChunkIndices(floored, SharedNavMapSystem.ChunkSize);

if (!navMap.Chunks.TryGetValue(chunkOrigin, out var chunk))
continue;
if (!state.Chunks.ContainsKey(index))
component.Chunks.Remove(index);
}

// TODO: Okay maybe I should just use ushorts lmao...
for (var i = 0; i < SharedNavMapSystem.ChunkSize * SharedNavMapSystem.ChunkSize; i++)
{
var value = (int) Math.Pow(2, i);
foreach (var beacon in component.Beacons)
{
if (!state.Beacons.Contains(beacon))
component.Beacons.Remove(beacon);
}
}

var mask = chunk.TileData & value;
foreach (var ((category, origin), chunk) in state.Chunks)
{
var newChunk = new NavMapChunk(origin);

if (mask == 0x0)
continue;
foreach (var (atmosDirection, value) in chunk)
newChunk.TileData[atmosDirection] = value;

var tile = chunk.Origin * SharedNavMapSystem.ChunkSize + SharedNavMapSystem.GetTile(mask);
args.WorldHandle.DrawRect(new Box2(tile * grid.Comp.TileSize, (tile + 1) * grid.Comp.TileSize), Color.Aqua, false);
}
}
}
component.Chunks[(category, origin)] = newChunk;
}

args.WorldHandle.SetTransform(Matrix3.Identity);
foreach (var beacon in state.Beacons)
component.Beacons.Add(beacon);
}
}
Loading

0 comments on commit 009d06d

Please sign in to comment.