fish-station/Content.Server/PDA/PdaSystem.cs

337 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Content.Server.AlertLevel;
using Content.Server.CartridgeLoader;
using Content.Server.Chat.Managers;
using Content.Server.DeviceNetwork.Components;
using Content.Server.Instruments;
using Content.Server.Light.EntitySystems;
using Content.Server.PDA.Ringer;
using Content.Server.RoundEnd;
using Content.Server.Shuttles.Components;
using Content.Server.Shuttles.Systems;
using Content.Server.Station.Systems;
using Content.Server.Store.Components;
using Content.Server.Store.Systems;
using Content.Server.Traitor.Uplink;
using Content.Shared.Access.Components;
using Content.Shared.CartridgeLoader;
using Content.Shared.Chat;
using Content.Shared.Light;
using Content.Shared.Light.Components;
using Content.Shared.Light.EntitySystems;
using Content.Shared.PDA;
using Content.Shared.Store.Components;
using Robust.Server.Containers;
using Robust.Server.GameObjects;
using Robust.Shared.Configuration;
using Robust.Shared.Containers;
using Robust.Shared.Player;
using Robust.Shared.Utility;
using Content.Shared.CCVar;
using Robust.Shared.Timing;
namespace Content.Server.PDA
{
public sealed class PdaSystem : SharedPdaSystem
{
[Dependency] private readonly CartridgeLoaderSystem _cartridgeLoader = default!;
[Dependency] private readonly InstrumentSystem _instrument = default!;
[Dependency] private readonly RingerSystem _ringer = default!;
[Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly StoreSystem _store = default!;
[Dependency] private readonly IChatManager _chatManager = default!;
[Dependency] private readonly UserInterfaceSystem _ui = default!;
[Dependency] private readonly UnpoweredFlashlightSystem _unpoweredFlashlight = default!;
[Dependency] private readonly ContainerSystem _containerSystem = default!;
[Dependency] private readonly RoundEndSystem _roundEndSystem = default!;
[Dependency] private readonly EmergencyShuttleSystem _emergencyShuttleSystem = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<PdaComponent, LightToggleEvent>(OnLightToggle);
// UI Events:
SubscribeLocalEvent<PdaComponent, BoundUIOpenedEvent>(OnPdaOpen);
SubscribeLocalEvent<PdaComponent, PdaRequestUpdateInterfaceMessage>(OnUiMessage);
SubscribeLocalEvent<PdaComponent, PdaToggleFlashlightMessage>(OnUiMessage);
SubscribeLocalEvent<PdaComponent, PdaShowRingtoneMessage>(OnUiMessage);
SubscribeLocalEvent<PdaComponent, PdaShowMusicMessage>(OnUiMessage);
SubscribeLocalEvent<PdaComponent, PdaShowUplinkMessage>(OnUiMessage);
SubscribeLocalEvent<PdaComponent, PdaLockUplinkMessage>(OnUiMessage);
SubscribeLocalEvent<PdaComponent, CartridgeLoaderNotificationSentEvent>(OnNotification);
SubscribeLocalEvent<StationRenamedEvent>(OnStationRenamed);
SubscribeLocalEvent<AlertLevelChangedEvent>(OnAlertLevelChanged);
}
protected override void OnComponentInit(EntityUid uid, PdaComponent pda, ComponentInit args)
{
base.OnComponentInit(uid, pda, args);
if (!HasComp<UserInterfaceComponent>(uid))
return;
UpdateAlertLevel(uid, pda);
UpdateStationName(uid, pda);
UpdateEvacShuttle(uid, pda); // Sunrise-edit
}
protected override void OnItemInserted(EntityUid uid, PdaComponent pda, EntInsertedIntoContainerMessage args)
{
base.OnItemInserted(uid, pda, args);
UpdatePdaUi(uid, pda);
}
protected override void OnItemRemoved(EntityUid uid, PdaComponent pda, EntRemovedFromContainerMessage args)
{
if (args.Container.ID != pda.IdSlot.ID && args.Container.ID != pda.PenSlot.ID && args.Container.ID != pda.PaiSlot.ID)
return;
// TODO: This is super cursed just use compstates please.
if (MetaData(uid).EntityLifeStage >= EntityLifeStage.Terminating)
return;
base.OnItemRemoved(uid, pda, args);
UpdatePdaUi(uid, pda);
}
private void OnLightToggle(EntityUid uid, PdaComponent pda, LightToggleEvent args)
{
pda.FlashlightOn = args.IsOn;
UpdatePdaUi(uid, pda);
}
public void SetOwner(EntityUid uid, PdaComponent pda, string ownerName)
{
pda.OwnerName = ownerName;
UpdatePdaUi(uid, pda);
}
private void OnStationRenamed(StationRenamedEvent ev)
{
UpdateAllPdaUisOnStation();
}
private void OnAlertLevelChanged(AlertLevelChangedEvent args)
{
UpdateAllPdaUisOnStation();
}
private void UpdateAllPdaUisOnStation()
{
var query = EntityQueryEnumerator<PdaComponent>();
while (query.MoveNext(out var ent, out var comp))
{
UpdatePdaUi(ent, comp);
}
}
private void OnNotification(Entity<PdaComponent> ent, ref CartridgeLoaderNotificationSentEvent args)
{
_ringer.RingerPlayRingtone(ent.Owner);
if (!_containerSystem.TryGetContainingContainer(ent, out var container)
|| !TryComp<ActorComponent>(container.Owner, out var actor))
return;
var message = FormattedMessage.EscapeText(args.Message);
var wrappedMessage = Loc.GetString("pda-notification-message",
("header", args.Header),
("message", message));
_chatManager.ChatMessageToOne(
ChatChannel.Notifications,
message,
wrappedMessage,
EntityUid.Invalid,
false,
actor.PlayerSession.Channel);
}
/// <summary>
/// Send new UI state to clients, call if you modify something like uplink.
/// </summary>
public void UpdatePdaUi(EntityUid uid, PdaComponent? pda = null)
{
if (!Resolve(uid, ref pda, false))
return;
if (!_ui.HasUi(uid, PdaUiKey.Key))
return;
var address = GetDeviceNetAddress(uid);
var hasInstrument = HasComp<InstrumentComponent>(uid);
var showUplink = HasComp<UplinkComponent>(uid) && IsUnlocked(uid);
UpdateStationName(uid, pda);
UpdateAlertLevel(uid, pda);
UpdateEvacShuttle(uid, pda); // Sunrise-edit
// TODO: Update the level and name of the station with each call to UpdatePdaUi is only needed for latejoin players.
// TODO: If someone can implement changing the level and name of the station when changing the PDA grid, this can be removed.
// TODO don't make this depend on cartridge loader!?!?
if (!TryComp(uid, out CartridgeLoaderComponent? loader))
return;
var programs = _cartridgeLoader.GetAvailablePrograms(uid, loader);
var id = CompOrNull<IdCardComponent>(pda.ContainedId);
var state = new PdaUpdateState(
programs,
GetNetEntity(loader.ActiveProgram),
pda.FlashlightOn,
pda.PenSlot.HasItem,
pda.PaiSlot.HasItem,
new PdaIdInfoText
{
ActualOwnerName = pda.OwnerName,
IdOwner = id?.FullName,
JobTitle = id?.JobTitle,
StationAlertLevel = pda.StationAlertLevel,
StationAlertColor = pda.StationAlertColor,
EvacShuttleStatus = pda.ShuttleStatus, // Sunrise-edit
EvacShuttleTime = pda.ShuttleTime // Sunrise-edit
},
pda.StationName,
showUplink,
hasInstrument,
address);
_ui.SetUiState(uid, PdaUiKey.Key, state);
}
private void OnPdaOpen(Entity<PdaComponent> ent, ref BoundUIOpenedEvent args)
{
if (!PdaUiKey.Key.Equals(args.UiKey))
return;
UpdatePdaUi(ent.Owner, ent.Comp);
}
private void OnUiMessage(EntityUid uid, PdaComponent pda, PdaRequestUpdateInterfaceMessage msg)
{
if (!PdaUiKey.Key.Equals(msg.UiKey))
return;
UpdatePdaUi(uid, pda);
}
private void OnUiMessage(EntityUid uid, PdaComponent pda, PdaToggleFlashlightMessage msg)
{
if (!PdaUiKey.Key.Equals(msg.UiKey))
return;
// TODO PREDICTION
// When moving this to shared, fill in the user field
_unpoweredFlashlight.TryToggleLight(uid, user: null);
}
private void OnUiMessage(EntityUid uid, PdaComponent pda, PdaShowRingtoneMessage msg)
{
if (!PdaUiKey.Key.Equals(msg.UiKey))
return;
if (HasComp<RingerComponent>(uid))
_ringer.ToggleRingerUI(uid, msg.Actor);
}
private void OnUiMessage(EntityUid uid, PdaComponent pda, PdaShowMusicMessage msg)
{
if (!PdaUiKey.Key.Equals(msg.UiKey))
return;
if (TryComp<InstrumentComponent>(uid, out var instrument))
_instrument.ToggleInstrumentUi(uid, msg.Actor, instrument);
}
private void OnUiMessage(EntityUid uid, PdaComponent pda, PdaShowUplinkMessage msg)
{
if (!PdaUiKey.Key.Equals(msg.UiKey))
return;
// check if its locked again to prevent malicious clients opening locked uplinks
if (HasComp<UplinkComponent>(uid) && IsUnlocked(uid))
_store.ToggleUi(msg.Actor, uid);
}
private void OnUiMessage(EntityUid uid, PdaComponent pda, PdaLockUplinkMessage msg)
{
if (!PdaUiKey.Key.Equals(msg.UiKey))
return;
if (TryComp<RingerUplinkComponent>(uid, out var uplink))
{
_ringer.LockUplink(uid, uplink);
UpdatePdaUi(uid, pda);
}
}
private bool IsUnlocked(EntityUid uid)
{
return !TryComp<RingerUplinkComponent>(uid, out var uplink) || uplink.Unlocked;
}
private void UpdateStationName(EntityUid uid, PdaComponent pda)
{
var station = _station.GetOwningStation(uid);
pda.StationName = station is null ? null : Name(station.Value);
}
// Sunrise-start
private void UpdateEvacShuttle(EntityUid uid, PdaComponent pda)
{
TimeSpan? shuttleTime;
EvacShuttleStatus shuttleStatus;
if (_emergencyShuttleSystem.EmergencyShuttleArrived)
{
shuttleTime = _gameTiming.CurTime + TimeSpan.FromSeconds(_emergencyShuttleSystem.СonsoleAccumulator);
shuttleStatus = EvacShuttleStatus.WaitingToLaunch;
}
else
{
if (_roundEndSystem.ExpectedCountdownEnd != null)
{
shuttleTime = _roundEndSystem.ExpectedCountdownEnd;
shuttleStatus = EvacShuttleStatus.WaitingToArrival;
}
else
{
shuttleTime = _roundEndSystem.TimeToCallShuttle();
shuttleStatus = EvacShuttleStatus.WaitingToCall;
}
}
var station = _station.GetOwningStation(uid);
if (!TryComp<StationEmergencyShuttleComponent>(station, out var stationEmergencyShuttleComponent))
return;
pda.ShuttleStatus = shuttleStatus;
pda.ShuttleTime = shuttleTime;
}
// Sunrise-end
private void UpdateAlertLevel(EntityUid uid, PdaComponent pda)
{
var station = _station.GetOwningStation(uid);
if (!TryComp(station, out AlertLevelComponent? alertComp) ||
alertComp.AlertLevels == null)
return;
pda.StationAlertLevel = alertComp.CurrentLevel;
if (alertComp.AlertLevels.Levels.TryGetValue(alertComp.CurrentLevel, out var details))
pda.StationAlertColor = details.Color;
}
private string? GetDeviceNetAddress(EntityUid uid)
{
string? address = null;
if (TryComp(uid, out DeviceNetworkComponent? deviceNetworkComponent))
{
address = deviceNetworkComponent?.Address;
}
return address;
}
}
}