Implement Navigator cartridge for PDA with station map display (#2984)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: VigersRay <60344369+VigersRay@users.noreply.github.com>
Co-authored-by: Vigers Ray <vigersray@gmail.com>
This commit is contained in:
Copilot 2025-08-24 07:02:54 +03:00 committed by GitHub
parent 6a68898417
commit e23a8d821d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 213 additions and 4 deletions

View file

@ -0,0 +1,32 @@
using Content.Client.UserInterface.Fragments;
using Content.Shared.CartridgeLoader.Cartridges;
using Robust.Client.UserInterface;
namespace Content.Client.CartridgeLoader.Cartridges;
public sealed partial class NavigatorUi : UIFragment
{
private NavigatorUiFragment? _fragment;
private IEntityManager? _entManager;
public override Control GetUIFragmentRoot()
{
return _fragment!;
}
public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner)
{
_entManager = IoCManager.Resolve<IEntityManager>();
_fragment = new NavigatorUiFragment();
_fragment.Setup(fragmentOwner);
}
public override void UpdateState(BoundUserInterfaceState state)
{
if (state is not NavigatorUiState navigatorState || _entManager == null)
return;
var mapUid = _entManager.GetEntity(navigatorState.MapUid);
_fragment?.UpdateState(mapUid, navigatorState.StationName);
}
}

View file

@ -0,0 +1,15 @@
<cartridges:NavigatorUiFragment xmlns:cartridges="clr-namespace:Content.Client.CartridgeLoader.Cartridges"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns="https://spacestation14.io" Margin="1 0 2 0"
Orientation="Vertical">
<PanelContainer StyleClasses="BackgroundDark"></PanelContainer>
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
<controls:StripeBack Name="StationNameContainer">
<PanelContainer>
<Label Name="StationNameLabel" Align="Center" Text="{Loc 'navigator-cartridge-loading'}" StyleClasses="SubText"/>
</PanelContainer>
</controls:StripeBack>
<PanelContainer Name="NavMapContainer" HorizontalExpand="True" VerticalExpand="True" Margin="4">
</PanelContainer>
</BoxContainer>
</cartridges:NavigatorUiFragment>

View file

@ -0,0 +1,38 @@
using Content.Client.Pinpointer.UI;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.CartridgeLoader.Cartridges;
[GenerateTypedNameReferences]
public sealed partial class NavigatorUiFragment : BoxContainer
{
public NavMapControl? NavMap;
public NavigatorUiFragment()
{
RobustXamlLoader.Load(this);
}
public void Setup(EntityUid? owner)
{
NavMap = new NavMapControl();
NavMap.Owner = owner;
NavMap.HorizontalExpand = true;
NavMap.VerticalExpand = true;
NavMapContainer.AddChild(NavMap);
}
public void UpdateState(EntityUid? mapUid, string stationName)
{
StationNameLabel.Text = stationName;
if (NavMap != null && mapUid != null)
{
NavMap.MapUid = mapUid;
}
}
}

View file

@ -135,7 +135,7 @@ public partial class NavMapControl : MapGridControl
},
VerticalExpand = false,
HorizontalExpand = true,
SetWidth = 650f,
//SetWidth = 650f, Sunrise-Edit
Children =
{
new BoxContainer()

View file

@ -13,8 +13,8 @@
</PanelContainer>
</controls:StripeBack>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" VerticalAlignment="Top">
<ui:NavMapControl Name="NavMapScreen"/>
<BoxContainer Orientation="Horizontal" VerticalExpand="True" HorizontalExpand="True" VerticalAlignment="Stretch">
<ui:NavMapControl Name="NavMapScreen" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" HorizontalExpand="True" VerticalExpand="True"/>
<BoxContainer Orientation="Vertical" SetWidth="200">
<!-- Search bar -->

View file

@ -1,4 +1,5 @@
using System.Numerics;
using System.Text.RegularExpressions;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
@ -85,7 +86,7 @@ public partial class MapGridControl : LayoutContainer
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
SetSize = new Vector2(SizeFull, SizeFull);
MinSize = new Vector2(MathF.Round(SizeFull / 2f), MathF.Round(SizeFull / 2f)); // Sunrise-Edit
RectClipContent = true;
MouseFilter = MouseFilterMode.Stop;
ActualRadarRange = WorldRange;

View file

@ -0,0 +1,6 @@
namespace Content.Server.CartridgeLoader.Cartridges;
[RegisterComponent]
public sealed partial class NavigatorCartridgeComponent : Component
{
}

View file

@ -0,0 +1,66 @@
using Content.Server.Station.Systems;
using Content.Shared.CartridgeLoader;
using Content.Shared.CartridgeLoader.Cartridges;
using Content.Shared.Station.Components;
using Robust.Shared.Map;
using System.Linq;
namespace Content.Server.CartridgeLoader.Cartridges;
public sealed class NavigatorCartridgeSystem : EntitySystem
{
[Dependency] private readonly CartridgeLoaderSystem _cartridgeLoader = default!;
[Dependency] private readonly StationSystem _stationSystem = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<NavigatorCartridgeComponent, CartridgeMessageEvent>(OnUiMessage);
SubscribeLocalEvent<NavigatorCartridgeComponent, CartridgeUiReadyEvent>(OnUiReady);
}
/// <summary>
/// The ui messages received here get wrapped by a CartridgeMessageEvent and are relayed from the <see cref="CartridgeLoaderSystem"/>
/// </summary>
/// <remarks>
/// The cartridge specific ui message event needs to inherit from the CartridgeMessageEvent
/// </remarks>
private void OnUiMessage(EntityUid uid, NavigatorCartridgeComponent component, CartridgeMessageEvent args)
{
UpdateUiState(uid, GetEntity(args.LoaderUid), component);
}
/// <summary>
/// This gets called when the ui fragment needs to be updated for the first time after activating
/// </summary>
private void OnUiReady(EntityUid uid, NavigatorCartridgeComponent component, CartridgeUiReadyEvent args)
{
UpdateUiState(uid, args.Loader, component);
}
private void UpdateUiState(EntityUid uid, EntityUid loaderUid, NavigatorCartridgeComponent? component)
{
if (!Resolve(uid, ref component))
return;
var owningStation = _stationSystem.GetOwningStation(loaderUid);
var stationName = "Unknown Station";
NetEntity? mapUid = null;
if (owningStation != null && TryComp<MetaDataComponent>(owningStation.Value, out var metaData))
{
stationName = metaData.EntityName;
// Try to get the station's primary grid for the map
if (TryComp<StationDataComponent>(owningStation.Value, out var stationData) && stationData.Grids.Count > 0)
{
// Get the first grid as the map reference and convert to NetEntity
mapUid = GetNetEntity(stationData.Grids.First());
}
}
var state = new NavigatorUiState(mapUid, stationName);
_cartridgeLoader.UpdateCartridgeUiState(loaderUid, state);
}
}

View file

@ -0,0 +1,16 @@
using Robust.Shared.Serialization;
namespace Content.Shared.CartridgeLoader.Cartridges;
[Serializable, NetSerializable]
public sealed class NavigatorUiState : BoundUserInterfaceState
{
public NetEntity? MapUid;
public string StationName;
public NavigatorUiState(NetEntity? mapUid, string stationName)
{
MapUid = mapUid;
StationName = stationName;
}
}

View file

@ -16,3 +16,5 @@ ent-MedTekCartridge = MedTek cartridge
.desc = A program that provides medical diagnostic tools.
ent-AstroNavCartridge = AstroNav cartridge
.desc = A program for navigation that provides GPS coordinates.
ent-NavigatorCartridge = navigator cartridge
.desc = A program for viewing the station map for navigation purposes.

View file

@ -27,6 +27,9 @@ log-probe-printout-entry = #{$number} / {$time} / {$accessor}
astro-nav-program-name = AstroNav
navigator-program-name = Navigator
navigator-cartridge-loading = Loading map...
med-tek-program-name = MedTek
# NanoTask cartridge

View file

@ -16,3 +16,5 @@ ent-MedTekCartridge = картридж МедТек
.desc = Программа, предоставляющая инструменты для медицинской диагностики.
ent-AstroNavCartridge = Картридж АстроНав
.desc = Программа для навигации, предоставляющая GPS-координаты.
ent-NavigatorCartridge = картридж навигатора
.desc = Программа для просмотра карты станции в целях навигации.

View file

@ -21,6 +21,10 @@ log-probe-printout-device = Просканированное устройств
log-probe-printout-header = Последние логи:
log-probe-printout-entry = #{ $number } / { $time } / { $accessor }
astro-nav-program-name = АстроНав
navigator-program-name = Навигатор
navigator-cartridge-loading = Загрузка карты...
med-tek-program-name = МедТек
# Wanted list cartridge
wanted-list-program-name = Список разыскиваемых

View file

@ -173,3 +173,24 @@
sprite: Objects/Devices/gps.rsi
state: icon
- type: AstroNavCartridge
- type: entity
parent: BaseItem
id: NavigatorCartridge
name: navigator cartridge
description: A program for viewing the station map for navigation purposes.
components:
- type: Sprite
sprite: Objects/Devices/cartridge.rsi
state: cart-nav
- type: Icon
sprite: Objects/Devices/cartridge.rsi
state: cart-nav
- type: UIFragment
ui: !type:NavigatorUi
- type: Cartridge
programName: navigator-program-name
icon:
sprite: Structures/Wallmounts/signs.rsi
state: space
- type: NavigatorCartridge

View file

@ -83,6 +83,7 @@
- NotekeeperCartridge
- NanoTaskCartridge
- NewsReaderCartridge
- NavigatorCartridge
cartridgeSlot:
priority: -1
name: device-pda-slot-component-slot-name-cartridge
@ -154,6 +155,7 @@
- NotekeeperCartridge
- NanoTaskCartridge
- NewsReaderCartridge
- NavigatorCartridge
- WantedListCartridge
- type: entity
@ -168,6 +170,7 @@
- NotekeeperCartridge
- NanoTaskCartridge
- NewsReaderCartridge
- NavigatorCartridge
- MedTekCartridge
- type: entity