component.Beacons.Clear();
component.Beacons.AddRange(state.Beacons);
+
+ component.Airlocks.Clear();
+ component.Airlocks.AddRange(state.Airlocks);
}
}
public partial class NavMapControl : MapGridControl
{
[Dependency] private readonly IEntityManager _entManager = default!;
- private readonly SharedTransformSystem _transformSystem = default!;
+ private readonly SharedTransformSystem _transformSystem;
public EntityUid? Owner;
public EntityUid? MapUid;
// Tracked data
public Dictionary<EntityCoordinates, (bool Visible, Color Color)> TrackedCoordinates = new();
public Dictionary<NetEntity, NavMapBlip> TrackedEntities = new();
- public Dictionary<Vector2i, List<NavMapLine>> TileGrid = default!;
+ public Dictionary<Vector2i, List<NavMapLine>>? TileGrid = default!;
// Default colors
public Color WallColor = new(102, 217, 102);
// Find closest tracked entity in range
var closestEntity = NetEntity.Invalid;
- var closestCoords = new EntityCoordinates();
var closestDistance = float.PositiveInfinity;
foreach ((var currentEntity, var blip) in TrackedEntities)
continue;
closestEntity = currentEntity;
- closestCoords = blip.Coordinates;
closestDistance = currentDistance;
}
else if (args.Function == EngineKeyFunctions.UIRightClick)
{
// Clear current selection with right click
- if (TrackedEntitySelectedAction != null)
- TrackedEntitySelectedAction.Invoke(null);
+ TrackedEntitySelectedAction?.Invoke(null);
}
}
{
base.Draw(handle);
- // Get the components necessary for drawing the navmap
+ // Get the components necessary for drawing the navmap
_entManager.TryGetComponent(MapUid, out _navMap);
_entManager.TryGetComponent(MapUid, out _grid);
_entManager.TryGetComponent(MapUid, out _xform);
var area = new Box2(-WorldRange, -WorldRange, WorldRange + 1f, WorldRange + 1f).Translated(offset);
- // Drawing lines can be rather expensive due to the number of neighbors that need to be checked in order
+ // Drawing lines can be rather expensive due to the number of neighbors that need to be checked in order
// to figure out where they should be drawn. However, we don't *need* to do check these every frame.
// Instead, lets periodically update where to draw each line and then store these points in a list.
// Then we can just run through the list each frame and draw the lines without any extra computation.
}
}
+ var airlockBuffer = Vector2.One * (MinimapScale / 2.25f) * 0.75f;
+ var airlockLines = new ValueList<Vector2>();
+ var foobarVec = new Vector2(1, -1);
+
+ foreach (var airlock in _navMap.Airlocks)
+ {
+ var position = airlock.Position - offset;
+ position = Scale(position with { Y = -position.Y });
+ airlockLines.Add(position + airlockBuffer);
+ airlockLines.Add(position - airlockBuffer * foobarVec);
+
+ airlockLines.Add(position + airlockBuffer);
+ airlockLines.Add(position + airlockBuffer * foobarVec);
+
+ airlockLines.Add(position - airlockBuffer);
+ airlockLines.Add(position + airlockBuffer * foobarVec);
+
+ airlockLines.Add(position - airlockBuffer);
+ airlockLines.Add(position - airlockBuffer * foobarVec);
+
+ airlockLines.Add(position + airlockBuffer * -Vector2.UnitY);
+ airlockLines.Add(position - airlockBuffer * -Vector2.UnitY);
+ }
+
+ if (airlockLines.Count > 0)
+ {
+ if (!_sRGBLookUp.TryGetValue(WallColor, out var sRGB))
+ {
+ sRGB = Color.ToSrgb(WallColor);
+ _sRGBLookUp[WallColor] = sRGB;
+ }
+
+ handle.DrawPrimitives(DrawPrimitiveTopology.LineList, airlockLines.Span, sRGB);
+ }
+
if (PostWallDrawingAction != null)
PostWallDrawingAction.Invoke(handle);
using Content.Shared.Examine;
using Content.Shared.Pinpointer;
using Content.Shared.Tag;
+using Robust.Server.GameObjects;
using Robust.Shared.GameStates;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics;
[Dependency] private readonly IAdminLogManager _adminLog = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly TagSystem _tags = default!;
+ [Dependency] private readonly MapSystem _map = default!;
private EntityQuery<PhysicsComponent> _physicsQuery;
private EntityQuery<TagComponent> _tagQuery;
SubscribeLocalEvent<NavMapBeaconComponent, ComponentStartup>(OnNavMapBeaconStartup);
SubscribeLocalEvent<NavMapBeaconComponent, AnchorStateChangedEvent>(OnNavMapBeaconAnchor);
+ SubscribeLocalEvent<NavMapDoorComponent, ComponentStartup>(OnNavMapDoorStartup);
+ SubscribeLocalEvent<NavMapDoorComponent, AnchorStateChangedEvent>(OnNavMapDoorAnchor);
+
SubscribeLocalEvent<ConfigurableNavMapBeaconComponent, NavMapBeaconConfigureBuiMessage>(OnConfigureMessage);
SubscribeLocalEvent<ConfigurableNavMapBeaconComponent, MapInitEvent>(OnConfigurableMapInit);
SubscribeLocalEvent<ConfigurableNavMapBeaconComponent, ExaminedEvent>(OnConfigurableExamined);
RefreshNavGrid(uid);
}
+ private void OnNavMapDoorStartup(Entity<NavMapDoorComponent> ent, ref ComponentStartup args)
+ {
+ RefreshNavGrid(ent);
+ }
+
+ private void OnNavMapDoorAnchor(Entity<NavMapDoorComponent> ent, ref AnchorStateChangedEvent args)
+ {
+ RefreshNavGrid(ent);
+ }
+
private void OnConfigureMessage(Entity<ConfigurableNavMapBeaconComponent> ent, ref NavMapBeaconConfigureBuiMessage args)
{
if (args.Session.AttachedEntity is not { } user)
private void OnGetState(EntityUid uid, NavMapComponent component, ref ComponentGetState args)
{
+ if (!TryComp<MapGridComponent>(uid, out var mapGrid))
+ return;
+
var data = new Dictionary<Vector2i, int>(component.Chunks.Count);
foreach (var (index, chunk) in component.Chunks)
{
beacons.Add(new NavMapBeacon(beacon.Color, name, xform.LocalPosition));
}
+ var airlockQuery = EntityQueryEnumerator<NavMapDoorComponent, TransformComponent>();
+ var airlocks = new List<NavMapAirlock>();
+ while (airlockQuery.MoveNext(out _, out _, out var xform))
+ {
+ if (xform.GridUid != uid || !xform.Anchored)
+ continue;
+
+ var pos = _map.TileIndicesFor(uid, mapGrid, xform.Coordinates);
+ var enumerator = _map.GetAnchoredEntitiesEnumerator(uid, mapGrid, pos);
+
+ var wallPresent = false;
+ while (enumerator.MoveNext(out var ent))
+ {
+ if (!_physicsQuery.TryGetComponent(ent, out var body) ||
+ !body.CanCollide ||
+ !body.Hard ||
+ body.BodyType != BodyType.Static ||
+ !_tags.HasTag(ent.Value, "Wall", _tagQuery) &&
+ !_tags.HasTag(ent.Value, "Window", _tagQuery))
+ {
+ continue;
+ }
+
+ wallPresent = true;
+ break;
+ }
+
+ if (wallPresent)
+ continue;
+
+ airlocks.Add(new NavMapAirlock(xform.LocalPosition));
+ }
+
// TODO: Diffs
args.State = new NavMapComponentState()
{
TileData = data,
Beacons = beacons,
+ Airlocks = airlocks
};
}
!body.CanCollide ||
!body.Hard ||
body.BodyType != BodyType.Static ||
- (!_tags.HasTag(ent.Value, "Wall", _tagQuery) &&
- !_tags.HasTag(ent.Value, "Window", _tagQuery)))
+ !_tags.HasTag(ent.Value, "Wall", _tagQuery) &&
+ !_tags.HasTag(ent.Value, "Window", _tagQuery))
{
continue;
}
public readonly Dictionary<Vector2i, NavMapChunk> Chunks = new();
[ViewVariables] public readonly List<SharedNavMapSystem.NavMapBeacon> Beacons = new();
+
+ [ViewVariables] public readonly List<SharedNavMapSystem.NavMapAirlock> Airlocks = new();
}
public sealed class NavMapChunk
--- /dev/null
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Pinpointer;
+
+/// <summary>
+/// This is used for objects which appear as doors on the navmap.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+[Access(typeof(SharedNavMapSystem))]
+public sealed partial class NavMapDoorComponent : Component
+{
+
+}
public Dictionary<Vector2i, int> TileData = new();
public List<NavMapBeacon> Beacons = new();
+
+ public List<NavMapAirlock> Airlocks = new();
}
[Serializable, NetSerializable]
public readonly record struct NavMapBeacon(Color Color, string Text, Vector2 Position);
+
+ [Serializable, NetSerializable]
+ public readonly record struct NavMapAirlock(Vector2 Position);
}
- type: Weldable
time: 3
- type: Airlock
+ - type: NavMapDoor
- type: DoorBolt
- type: Appearance
- type: WiresVisuals
- type: Weldable\r
time: 10\r
- type: Airlock\r
+ - type: NavMapDoor\r
- type: DoorBolt\r
- type: AccessReader\r
- type: Appearance\r
mode: NoSprite
- type: Occluder
+- type: entity
+ parent: BaseMaterialDoor
+ id: BaseMaterialDoorNavMap
+ abstract: true
+ components:
+ - type: NavMapDoor
+
- type: entity
id: MetalDoor
name: metal door
- parent: BaseMaterialDoor
+ parent: BaseMaterialDoorNavMap
components:
- type: Construction
graph: DoorGraph
- type: entity
id: WoodDoor
name: wooden door
- parent: BaseMaterialDoor
+ parent: BaseMaterialDoorNavMap
description: A door, where will it lead?
components:
- type: Sprite
- type: entity
id: PaperDoor
name: paper door
- parent: WoodDoor
+ parent: BaseMaterialDoorNavMap
description: A door, where will it lead?
components:
- type: Sprite
- type: entity
id: PlasmaDoor
name: plasma door
- parent: BaseMaterialDoor
+ parent: BaseMaterialDoorNavMap
description: A door, where will it lead?
components:
- type: Sprite
- type: entity
id: GoldDoor
name: gold door
- parent: BaseMaterialDoor
+ parent: BaseMaterialDoorNavMap
description: A door, where will it lead?
components:
- type: Sprite
- type: entity
id: SilverDoor
name: silver door
- parent: BaseMaterialDoor
+ parent: BaseMaterialDoorNavMap
description: A door, where will it lead?
components:
- type: Sprite
- type: entity
id: BananiumDoor
name: bananium door
- parent: BaseMaterialDoor
+ parent: BaseMaterialDoorNavMap
description: A door, where will it lead?
components:
- type: Sprite
- type: entity
id: WebDoor
name: web door
- parent: BaseMaterialDoor
+ parent: BaseMaterialDoorNavMap
description: A door, leading to the lands of the spiders... or a spaced room.
components:
- type: Sprite
- type: ContainerFill
containers:
battery-container: [ PowerCellMedium ]
+ - type: Tag
+ tags:
+ - Structure
+ - Wall
- type: ContainerContainer
containers:
battery-container: !type:Container
- type: ContainerContainer
containers:
board: !type:Container
+ - type: NavMapDoor
- type: Door
openDrawDepth: BlastDoors
closedDrawDepth: BlastDoors
openUnlitVisible: true
# needed so that windoors will close regardless of whether there are people in it; it doesn't crush after all
safety: false
+ - type: NavMapDoor
- type: DoorBolt
- type: Electrified
enabled: false