Local Material Silo (#36492)

* Material Silo

* fix board, fix copyright

* a bit of review.... for the vibe....

* a tiny bit of review

* 4 spaced

* sloths no good very tiny nitpick

* fix ui flickers

* oops

* slightly lower range

* Sloth Review

---------

Co-authored-by: ScarKy0 <scarky0@onet.eu>
This commit is contained in:
Nemanja
2025-04-18 19:43:17 -04:00
committed by GitHub
parent 667bda28df
commit f8ff7aee92
28 changed files with 842 additions and 46 deletions

View File

@@ -102,14 +102,18 @@ public sealed class MaterialStorageSystem : SharedMaterialStorageSystem
if (!base.TryInsertMaterialEntity(user, toInsert, receiver, storage, material, composition))
return false;
_audio.PlayPvs(storage.InsertingSound, receiver);
_popup.PopupEntity(Loc.GetString("machine-insert-item", ("user", user), ("machine", receiver),
("item", toInsert)), receiver);
_popup.PopupEntity(Loc.GetString("machine-insert-item",
("user", user),
("machine", receiver),
("item", toInsert)),
receiver);
QueueDel(toInsert);
// Logging
TryComp<StackComponent>(toInsert, out var stack);
var count = stack?.Count ?? 1;
_adminLogger.Add(LogType.Action, LogImpact.Low,
_adminLogger.Add(LogType.Action,
LogImpact.Low,
$"{ToPrettyString(user):player} inserted {count} {ToPrettyString(toInsert):inserted} into {ToPrettyString(receiver):receiver}");
return true;
}

View File

@@ -0,0 +1,119 @@
using Content.Server.Pinpointer;
using Content.Shared.IdentityManagement;
using Content.Shared.Materials.OreSilo;
using Robust.Server.GameStates;
using Robust.Shared.Player;
namespace Content.Server.Materials;
/// <inheritdoc/>
public sealed class OreSiloSystem : SharedOreSiloSystem
{
[Dependency] private readonly EntityLookupSystem _entityLookup = default!;
[Dependency] private readonly NavMapSystem _navMap = default!;
[Dependency] private readonly PvsOverrideSystem _pvsOverride = default!;
[Dependency] private readonly SharedUserInterfaceSystem _userInterface = default!;
private const float OreSiloPreloadRangeSquared = 225f; // ~1 screen
private readonly HashSet<Entity<OreSiloClientComponent>> _clientLookup = new();
private readonly HashSet<(NetEntity, string, string)> _clientInformation = new();
private readonly HashSet<EntityUid> _silosToAdd = new();
private readonly HashSet<EntityUid> _silosToRemove = new();
protected override void UpdateOreSiloUi(Entity<OreSiloComponent> ent)
{
if (!_userInterface.IsUiOpen(ent.Owner, OreSiloUiKey.Key))
return;
_clientLookup.Clear();
_clientInformation.Clear();
var xform = Transform(ent);
// Sneakily uses override with TComponent parameter
_entityLookup.GetEntitiesInRange(xform.Coordinates, ent.Comp.Range, _clientLookup);
foreach (var client in _clientLookup)
{
// don't show already-linked clients.
if (client.Comp.Silo is not null)
continue;
var netEnt = GetNetEntity(client);
var name = Identity.Name(client, EntityManager);
var beacon = _navMap.GetNearestBeaconString(client.Owner, onlyName: true);
var txt = Loc.GetString("ore-silo-ui-itemlist-entry",
("name", name),
("beacon", beacon),
("linked", ent.Comp.Clients.Contains(client)),
("inRange", true));
_clientInformation.Add((netEnt, txt, beacon));
}
// Get all clients of this silo, including those out of range.
foreach (var client in ent.Comp.Clients)
{
var netEnt = GetNetEntity(client);
var name = Identity.Name(client, EntityManager);
var beacon = _navMap.GetNearestBeaconString(client, onlyName: true);
var inRange = CanTransmitMaterials((ent, ent), client);
var txt = Loc.GetString("ore-silo-ui-itemlist-entry",
("name", name),
("beacon", beacon),
("linked", ent.Comp.Clients.Contains(client)),
("inRange", inRange));
_clientInformation.Add((netEnt, txt, beacon));
}
_userInterface.SetUiState(ent.Owner, OreSiloUiKey.Key, new OreSiloBuiState(_clientInformation));
}
public override void Update(float frameTime)
{
base.Update(frameTime);
// Solving an annoying problem: we need to send the silo to people who are near the silo so that
// Things don't start wildly mispredicting. We do this as cheaply as possible via grid-based local-pos checks.
// Sloth okay-ed this in the interim until a better solution comes around.
var actorQuery = EntityQueryEnumerator<ActorComponent, TransformComponent>();
while (actorQuery.MoveNext(out _, out var actorComp, out var actorXform))
{
_silosToAdd.Clear();
_silosToRemove.Clear();
var clientQuery = EntityQueryEnumerator<OreSiloClientComponent, TransformComponent>();
while (clientQuery.MoveNext(out _, out var clientComp, out var clientXform))
{
if (clientComp.Silo == null)
continue;
// We limit it to same-grid checks only for peak perf
if (actorXform.GridUid != clientXform.GridUid)
continue;
if ((actorXform.LocalPosition - clientXform.LocalPosition).LengthSquared() <= OreSiloPreloadRangeSquared)
{
_silosToAdd.Add(clientComp.Silo.Value);
}
else
{
_silosToRemove.Add(clientComp.Silo.Value);
}
}
foreach (var toRemove in _silosToRemove)
{
_pvsOverride.RemoveSessionOverride(toRemove, actorComp.PlayerSession);
}
foreach (var toAdd in _silosToAdd)
{
_pvsOverride.AddSessionOverride(toAdd, actorComp.PlayerSession);
}
}
}
}

View File

@@ -436,12 +436,12 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
/// to the position of <paramref name="ent"/> from the nearest beacon.
/// </summary>
[PublicAPI]
public string GetNearestBeaconString(Entity<TransformComponent?> ent)
public string GetNearestBeaconString(Entity<TransformComponent?> ent, bool onlyName = false)
{
if (!Resolve(ent, ref ent.Comp))
return Loc.GetString("nav-beacon-pos-no-beacons");
return GetNearestBeaconString(_transformSystem.GetMapCoordinates(ent, ent.Comp));
return GetNearestBeaconString(_transformSystem.GetMapCoordinates(ent, ent.Comp), onlyName);
}
/// <summary>
@@ -449,11 +449,14 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
/// to <paramref name="coordinates"/> from the nearest beacon.
/// </summary>
public string GetNearestBeaconString(MapCoordinates coordinates)
public string GetNearestBeaconString(MapCoordinates coordinates, bool onlyName = false)
{
if (!TryGetNearestBeacon(coordinates, out var beacon, out var pos))
return Loc.GetString("nav-beacon-pos-no-beacons");
if (onlyName)
return beacon.Value.Comp.Text!;
var gridOffset = Angle.Zero;
if (_mapManager.TryFindGridAt(pos.Value, out var grid, out _))
gridOffset = Transform(grid).LocalRotation;