From f5f3e65e1d6f0c4c64b8b5b3dd3dcb7b72096128 Mon Sep 17 00:00:00 2001 From: Moony Date: Thu, 10 Mar 2022 23:37:35 -0600 Subject: [PATCH] Implement Intrinsic UIs (#6926) * Implement Intrinsic UIs, allowing the admin ghost to double as a computer. * ignore moment * remove debug statement, sort the actions. * ffs * didn't ever use this and don't need to, removed. * rm dead code * lil bit of commenting. --- Content.Client/Entry/IgnoredComponents.cs | 1 + .../UserInterface/ActivatableUIComponent.cs | 12 +- .../UserInterface/IntrinsicUIComponent.cs | 56 ++++++++ .../UserInterface/IntrinsicUISystem.cs | 89 ++++++++++++ .../Locale/en-US/robotics/ai-actions.ftl | 10 ++ .../Entities/Mobs/Player/admin_ghost.yml | 130 ++++++++++++++++++ 6 files changed, 287 insertions(+), 11 deletions(-) create mode 100644 Content.Server/UserInterface/IntrinsicUIComponent.cs create mode 100644 Content.Server/UserInterface/IntrinsicUISystem.cs create mode 100644 Resources/Locale/en-US/robotics/ai-actions.ftl diff --git a/Content.Client/Entry/IgnoredComponents.cs b/Content.Client/Entry/IgnoredComponents.cs index 3667507aa0..c201aed9d1 100644 --- a/Content.Client/Entry/IgnoredComponents.cs +++ b/Content.Client/Entry/IgnoredComponents.cs @@ -110,6 +110,7 @@ namespace Content.Client.Entry "Lung", "BatteryDischarger", "Apc", + "IntrinsicUI", "PowerProvider", "ApcPowerReceiver", "Cable", diff --git a/Content.Server/UserInterface/ActivatableUIComponent.cs b/Content.Server/UserInterface/ActivatableUIComponent.cs index f55626884b..5f29aaa023 100644 --- a/Content.Server/UserInterface/ActivatableUIComponent.cs +++ b/Content.Server/UserInterface/ActivatableUIComponent.cs @@ -1,18 +1,8 @@ -using System; -using Content.Shared.Instruments; -using Content.Shared.Interaction; using Robust.Server.GameObjects; using Robust.Server.Player; using Robust.Shared.Reflection; -using Robust.Shared.GameObjects; -using Robust.Shared.Enums; -using Robust.Shared.Player; -using Robust.Shared.Network; -using Robust.Shared.IoC; -using Robust.Shared.Utility; using Robust.Shared.Serialization; -using Robust.Shared.Serialization.Manager.Attributes; -using Robust.Shared.ViewVariables; + namespace Content.Server.UserInterface { diff --git a/Content.Server/UserInterface/IntrinsicUIComponent.cs b/Content.Server/UserInterface/IntrinsicUIComponent.cs new file mode 100644 index 0000000000..02bfa6db40 --- /dev/null +++ b/Content.Server/UserInterface/IntrinsicUIComponent.cs @@ -0,0 +1,56 @@ +using Content.Shared.Actions.ActionTypes; +using JetBrains.Annotations; +using Robust.Server.GameObjects; +using Robust.Shared.Reflection; +using Robust.Shared.Serialization; + +namespace Content.Server.UserInterface; + +[RegisterComponent] +public sealed class IntrinsicUIComponent : Component, ISerializationHooks +{ + /// + /// List of UIs and their actions that this entity has. + /// + [ViewVariables, DataField("uis", required: true)] + public List UIs = new(); + + void ISerializationHooks.AfterDeserialization() + { + foreach (var ui in UIs) + { + ui.AfterDeserialization(); + } + } +} + +[DataDefinition] +public struct IntrinsicUIEntry +{ + [ViewVariables] + public Enum? Key { get; set; } + + /// + /// The BUI key that this intrinsic UI should open. + /// + [DataField("key", readOnly: true, required: true)] + private string _keyRaw = default!; + + /// + /// The action used for this BUI. + /// + [DataField("toggleAction", required: true)] + public InstantAction ToggleAction = new(); + + public void AfterDeserialization() + { + var reflectionManager = IoCManager.Resolve(); + if (reflectionManager.TryParseEnumReference(_keyRaw, out var key)) + Key = key; + + if (ToggleAction.Event is ToggleIntrinsicUIEvent ev) + { + ev.Key = Key; + } + } +} diff --git a/Content.Server/UserInterface/IntrinsicUISystem.cs b/Content.Server/UserInterface/IntrinsicUISystem.cs new file mode 100644 index 0000000000..bf9a0a6264 --- /dev/null +++ b/Content.Server/UserInterface/IntrinsicUISystem.cs @@ -0,0 +1,89 @@ +using Content.Server.Actions; +using Content.Shared.Actions; +using Content.Shared.Toggleable; +using JetBrains.Annotations; +using Robust.Server.GameObjects; +using Robust.Shared.Reflection; +using Robust.Shared.Serialization; + +namespace Content.Server.UserInterface; + +public sealed class IntrinsicUISystem : EntitySystem +{ + [Dependency] private readonly ActionsSystem _actionsSystem = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnGetActions); + SubscribeLocalEvent(OnActionToggle); + } + + private void OnActionToggle(EntityUid uid, IntrinsicUIComponent component, ToggleIntrinsicUIEvent args) + { + args.Handled = InteractUI(uid, args.Key, component); + } + + private void OnGetActions(EntityUid uid, IntrinsicUIComponent component, ComponentStartup args) + { + if (!TryComp(uid, out var actions)) + return; + + foreach (var entry in component.UIs) + { + _actionsSystem.AddAction(uid, entry.ToggleAction, null, actions); + } + } + + public bool InteractUI(EntityUid uid, Enum? key, IntrinsicUIComponent? iui = null, ActorComponent? actor = null) + { + if (!Resolve(uid, ref iui, ref actor)) + return false; + + if (key is null) + { + Logger.ErrorS("bui", $"Entity {ToPrettyString(uid)} has an invalid intrinsic UI."); + } + + var ui = GetUIOrNull(uid, key, iui); + + if (ui is null) + { + Logger.ErrorS("bui", $"Couldn't get UI {key} on {ToPrettyString(uid)}"); + return false; + } + + var attempt = new IntrinsicUIOpenAttemptEvent(uid, key); + RaiseLocalEvent(uid, attempt, false); + if (attempt.Cancelled) return false; + + ui.Toggle(actor.PlayerSession); + return true; + } + + private BoundUserInterface? GetUIOrNull(EntityUid uid, Enum? key, IntrinsicUIComponent? component = null) + { + if (!Resolve(uid, ref component)) + return null; + + return key is null ? null : uid.GetUIOrNull(key); + } +} + +[UsedImplicitly] +public sealed class ToggleIntrinsicUIEvent : PerformActionEvent +{ + [ViewVariables] + public Enum? Key { get; set; } +} + +// Competing with ActivatableUI for horrible event names. +public sealed class IntrinsicUIOpenAttemptEvent : CancellableEntityEventArgs +{ + public EntityUid User { get; } + public Enum? Key { get; } + public IntrinsicUIOpenAttemptEvent(EntityUid who, Enum? key) + { + User = who; + Key = key; + } +} diff --git a/Resources/Locale/en-US/robotics/ai-actions.ftl b/Resources/Locale/en-US/robotics/ai-actions.ftl new file mode 100644 index 0000000000..940f574679 --- /dev/null +++ b/Resources/Locale/en-US/robotics/ai-actions.ftl @@ -0,0 +1,10 @@ +action-name-show-solar-console = Solar Control Interface +action-description-show-solar-console = View a solar control interface. +action-name-show-communications-console = Communications Interface +action-description-show-communications-console = View a communications interface. +action-name-show-radar-console = Mass Scanner Interface +action-description-show-radar-console = View a mass scanner interface. +action-name-show-cargo-console = Cargo Ordering Interface +action-description-show-cargo-console = View a cargo ordering interface. +action-name-show-crew-monitoring-console = Crew Monitoring Interface. +action-description-crew-monitoring-console = View a crew monitoring interface. diff --git a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml index ae326af4cc..dd8267a7b9 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml @@ -35,3 +35,133 @@ - type: Access groups: - AllAccess + - type: UserInterface + interfaces: + - key: enum.SolarControlConsoleUiKey.Key + type: SolarControlConsoleBoundUserInterface + - key: enum.CommunicationsConsoleUiKey.Key + type: CommunicationsConsoleBoundUserInterface + - key: enum.RadarConsoleUiKey.Key + type: RadarConsoleBoundUserInterface + - key: enum.CargoConsoleUiKey.Key + type: CargoConsoleBoundUserInterface + - key: enum.CrewMonitoringUIKey.Key + type: CrewMonitoringBoundUserInterface + - type: IntrinsicUI + uis: + - key: enum.SolarControlConsoleUiKey.Key + toggleAction: + name: action-name-show-solar-console + description: action-description-show-solar-console + icon: Structures/Machines/parts.rsi/box_0.png + iconOn: Structures/Machines/parts.rsi/box_2.png + keywords: [ "AI", "console", "interface" ] + priority: -10 + event: !type:ToggleIntrinsicUIEvent + - key: enum.CommunicationsConsoleUiKey.Key + toggleAction: + name: action-name-show-communications-console + description: action-description-show-communications-console + icon: Structures/Machines/parts.rsi/box_0.png + iconOn: Structures/Machines/parts.rsi/box_2.png + keywords: [ "AI", "console", "interface" ] + priority: -10 + event: !type:ToggleIntrinsicUIEvent + - key: enum.RadarConsoleUiKey.Key + toggleAction: + name: action-name-show-radar-console + description: action-description-show-radar-console + icon: Structures/Machines/parts.rsi/box_0.png + iconOn: Structures/Machines/parts.rsi/box_2.png + keywords: [ "AI", "console", "interface" ] + priority: -10 + event: !type:ToggleIntrinsicUIEvent + - key: enum.CargoConsoleUiKey.Key + toggleAction: + name: action-name-show-cargo-console + description: action-description-show-cargo-console + icon: Structures/Machines/parts.rsi/box_0.png + iconOn: Structures/Machines/parts.rsi/box_2.png + keywords: [ "AI", "console", "interface" ] + priority: -10 + event: !type:ToggleIntrinsicUIEvent + - key: enum.CrewMonitoringUIKey.Key + toggleAction: + name: action-name-show-crew-monitoring-console + description: action-description-crew-monitoring-console + icon: Structures/Machines/parts.rsi/box_0.png + iconOn: Structures/Machines/parts.rsi/box_2.png + keywords: [ "AI", "console", "interface" ] + priority: -10 + event: !type:ToggleIntrinsicUIEvent + - type: SolarControlConsole # look ma i AM the computer! + - type: CommunicationsConsole + - type: RadarConsole + - type: CargoConsole + - type: CargoOrderDatabase + - type: GalacticMarket # wow this kinda sucks. + products: + - MedicalSupplies + - MedicalChemistrySupplies + - EmergencyExplosive + - EmergencyFire + - EmergencyInternals + - EmergencyRadiation + - EmergencyInflatablewall + - ArmorySmg + - ArmoryShotgun + - SecurityArmor + - SecurityRiot + - SecurityLaser + - SecurityHelmet + - SecuritySupplies + - SecurityNonLethal + - SecurityRestraints + - HydroponicsTools + - HydroponicsSeeds + - HydroponicsSeedsExotic + - LivestockMonkeyCube + - LivestockCow + - LivestockChicken + - LivestockDuck + - LivestockGoat + - FoodPizza + - ServiceJanitorial + - ServiceLightsReplacement + - ServiceSmokeables + - ServiceCustomSmokable + - ServiceBureaucracy + - ServicePersonnel + - EngineeringCableLv + - EngineeringCableMv + - EngineeringCableHv + - EngineeringCableBulk + - EngineAmeShielding + - EngineAmeJar + - EngineAmeControl + - EngineSolar + - FunPlushies + - FunArtSupplies + - FunInstruments + - FunBoardGames + - MaterialSteel + - MaterialGlass + - MaterialPlastic + - MaterialPlasteel + - MaterialPlasma + - EngineSingularityEmitter + - EngineSingularityCollector + - EngineSingularityGenerator + - EngineSingularityContainment + - EngineParticleAccelerator + - ShuttleThruster + - ShuttleGyroscope + - AtmosphericsAir + - AtmosphericsOxygen + - AtmosphericsNitrogen + - AtmosphericsCarbonDioxide + - type: CrewMonitoringConsole + - type: DeviceNetworkComponent + deviceNetId: Wireless + - type: WirelessNetworkConnection + range: 500