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; /// 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> _clientLookup = new(); private readonly HashSet<(NetEntity, string, string)> _clientInformation = new(); private readonly HashSet _silosToAdd = new(); private readonly HashSet _silosToRemove = new(); protected override void UpdateOreSiloUi(Entity 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; // Don't show clients on the screen if we can't link them. if (!CanTransmitMaterials((ent, ent, xform), client)) 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, xform), 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(); while (actorQuery.MoveNext(out _, out var actorComp, out var actorXform)) { _silosToAdd.Clear(); _silosToRemove.Clear(); var clientQuery = EntityQueryEnumerator(); 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); } } } }