From 68ab77d4d4c19815826e1665ccfb90eccc6ff9e2 Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Sat, 18 Jan 2025 14:43:11 +0300 Subject: [PATCH] Knowledge UI (#779) * knowledge button in HUD * ui controller * bugfixes * finish * all-knowing ghosts * Create knowledge-ui.ftl --- Content.Client/Input/ContentContexts.cs | 4 + .../Options/UI/Tabs/KeyRebindTab.xaml.cs | 5 + .../MenuBar/GameTopMenuBarUIController.cs | 3 + .../MenuBar/Widgets/GameTopMenuBar.xaml | 12 ++ .../Knowledge/ClientCP14KnowledgeSystem.cs | 35 ++++ .../Knowledge/CP14KnowledgeUIController.cs | 158 ++++++++++++++++++ .../Windows/CP14KnowledgeWindow.xaml | 13 ++ .../Windows/CP14KnowledgeWindow.xaml.cs | 14 ++ .../_CP14/Knowledge/CP14KnowledgeSystem.cs | 17 +- Content.Shared/Input/ContentKeyFunctions.cs | 4 + .../Knowledge/SharedCP14KnowledgeSystem.cs | 28 ++++ Resources/Locale/en-US/_CP14/HUD/game-hud.ftl | 1 + .../_CP14/escape-menu/ui/options-menu.ftl | 6 + .../en-US/_CP14/knowledge/knowledge-ui.ftl | 1 + Resources/Locale/ru-RU/_CP14/HUD/game-hud.ftl | 1 + .../_CP14/escape-menu/ui/options-menu.ftl | 6 + .../ru-RU/_CP14/knowledge/knowledge-ui.ftl | 1 + 17 files changed, 308 insertions(+), 1 deletion(-) create mode 100644 Content.Client/_CP14/UserInterface/Systems/Knowledge/CP14KnowledgeUIController.cs create mode 100644 Content.Client/_CP14/UserInterface/Systems/Knowledge/Windows/CP14KnowledgeWindow.xaml create mode 100644 Content.Client/_CP14/UserInterface/Systems/Knowledge/Windows/CP14KnowledgeWindow.xaml.cs create mode 100644 Resources/Locale/en-US/_CP14/HUD/game-hud.ftl create mode 100644 Resources/Locale/en-US/_CP14/knowledge/knowledge-ui.ftl create mode 100644 Resources/Locale/ru-RU/_CP14/HUD/game-hud.ftl create mode 100644 Resources/Locale/ru-RU/_CP14/knowledge/knowledge-ui.ftl diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs index 639f326f7f..8ba399fb61 100644 --- a/Content.Client/Input/ContentContexts.cs +++ b/Content.Client/Input/ContentContexts.cs @@ -123,6 +123,10 @@ namespace Content.Client.Input common.AddFunction(ContentKeyFunctions.OpenDecalSpawnWindow); common.AddFunction(ContentKeyFunctions.OpenAdminMenu); common.AddFunction(ContentKeyFunctions.OpenGuidebook); + + //CP14 Keys + human.AddFunction(ContentKeyFunctions.CP14OpenKnowledgeMenu); + //CP14 Keys end } } } diff --git a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs index 24be904e06..30034723b9 100644 --- a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs +++ b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs @@ -265,6 +265,11 @@ namespace Content.Client.Options.UI.Tabs AddButton(EngineKeyFunctions.HideUI); AddButton(ContentKeyFunctions.InspectEntity); + //CP14 + AddHeader("ui-options-header-cp14"); + AddButton(ContentKeyFunctions.CP14OpenKnowledgeMenu); + //CP14 end + foreach (var control in _keyControls.Values) { UpdateKeyControl(control); diff --git a/Content.Client/UserInterface/Systems/MenuBar/GameTopMenuBarUIController.cs b/Content.Client/UserInterface/Systems/MenuBar/GameTopMenuBarUIController.cs index e314310bc0..afb45ec172 100644 --- a/Content.Client/UserInterface/Systems/MenuBar/GameTopMenuBarUIController.cs +++ b/Content.Client/UserInterface/Systems/MenuBar/GameTopMenuBarUIController.cs @@ -24,6 +24,7 @@ public sealed class GameTopMenuBarUIController : UIController [Dependency] private readonly SandboxUIController _sandbox = default!; [Dependency] private readonly GuidebookUIController _guidebook = default!; [Dependency] private readonly EmotesUIController _emotes = default!; + [Dependency] private readonly CP14KnowledgeUIController _knowledge = default!; //CP14 private GameTopMenuBar? GameTopMenuBar => UIManager.GetActiveUIWidgetOrNull(); @@ -47,6 +48,7 @@ public sealed class GameTopMenuBarUIController : UIController _action.UnloadButton(); _sandbox.UnloadButton(); _emotes.UnloadButton(); + _knowledge.UnloadButton(); //CP14 } public void LoadButtons() @@ -60,5 +62,6 @@ public sealed class GameTopMenuBarUIController : UIController _action.LoadButton(); _sandbox.LoadButton(); _emotes.LoadButton(); + _knowledge.LoadButton(); //CP14 } } diff --git a/Content.Client/UserInterface/Systems/MenuBar/Widgets/GameTopMenuBar.xaml b/Content.Client/UserInterface/Systems/MenuBar/Widgets/GameTopMenuBar.xaml index dc8972970a..aaf230d266 100644 --- a/Content.Client/UserInterface/Systems/MenuBar/Widgets/GameTopMenuBar.xaml +++ b/Content.Client/UserInterface/Systems/MenuBar/Widgets/GameTopMenuBar.xaml @@ -33,6 +33,18 @@ HorizontalExpand="True" AppendStyleClass="{x:Static style:StyleBase.ButtonSquare}" /> + + + ? OnKnowledgeUpdate; + + public override void Initialize() + { + base.Initialize(); + + SubscribeNetworkEvent(OnCharacterKnowledgeEvent); + } + + public void RequestKnowledgeInfo() + { + var entity = _players.LocalEntity; + if (entity is null) + return; + + RaiseNetworkEvent(new RequestKnowledgeInfoEvent(GetNetEntity(entity.Value))); + } + + private void OnCharacterKnowledgeEvent(CP14KnowledgeInfoEvent msg, EntitySessionEventArgs args) + { + var entity = GetEntity(msg.NetEntity); + var data = new KnowledgeData(entity, msg.AllKnowledge); + + OnKnowledgeUpdate?.Invoke(data); + } + + public readonly record struct KnowledgeData( + EntityUid Entity, + HashSet> AllKnowledges + ); } diff --git a/Content.Client/_CP14/UserInterface/Systems/Knowledge/CP14KnowledgeUIController.cs b/Content.Client/_CP14/UserInterface/Systems/Knowledge/CP14KnowledgeUIController.cs new file mode 100644 index 0000000000..188a10b666 --- /dev/null +++ b/Content.Client/_CP14/UserInterface/Systems/Knowledge/CP14KnowledgeUIController.cs @@ -0,0 +1,158 @@ +using Content.Client._CP14.Knowledge; +using Content.Client._CP14.UserInterface.Systems.Knowledge.Windows; +using Content.Client.Gameplay; +using Content.Client.UserInterface.Controls; +using Content.Shared.Input; +using JetBrains.Annotations; +using Robust.Client.Player; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controllers; +using Robust.Client.UserInterface.Controls; +using Robust.Shared.Input.Binding; +using Robust.Shared.Prototypes; +using Robust.Shared.Utility; + +namespace Content.Client.UserInterface.Systems.Character; + +[UsedImplicitly] +public sealed class CP14KnowledgeUIController : UIController, IOnStateEntered, IOnStateExited, + IOnSystemChanged +{ + [Dependency] private readonly IPlayerManager _player = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; + [UISystemDependency] private readonly ClientCP14KnowledgeSystem _knowledge = default!; + + private CP14KnowledgeWindow? _window; + + private MenuButton? KnowledgeButton => UIManager.GetActiveUIWidgetOrNull()?.CP14KnowledgeButton; + + public void OnStateEntered(GameplayState state) + { + DebugTools.Assert(_window == null); + + _window = UIManager.CreateWindow(); + LayoutContainer.SetAnchorPreset(_window, LayoutContainer.LayoutPreset.CenterTop); + + CommandBinds.Builder + .Bind(ContentKeyFunctions.CP14OpenKnowledgeMenu, + InputCmdHandler.FromDelegate(_ => ToggleWindow())) + .Register(); + } + + public void OnStateExited(GameplayState state) + { + if (_window != null) + { + _window.Dispose(); + _window = null; + } + + CommandBinds.Unregister(); + } + + public void OnSystemLoaded(ClientCP14KnowledgeSystem system) + { + system.OnKnowledgeUpdate += KnowledgeUpdated; + _player.LocalPlayerDetached += CharacterDetached; + } + + public void OnSystemUnloaded(ClientCP14KnowledgeSystem system) + { + system.OnKnowledgeUpdate -= KnowledgeUpdated; + _player.LocalPlayerDetached -= CharacterDetached; + } + + public void UnloadButton() + { + if (KnowledgeButton is null) + return; + + KnowledgeButton.OnPressed -= KnowledgeButtonPressed; + } + + public void LoadButton() + { + if (KnowledgeButton is null) + return; + + KnowledgeButton.OnPressed += KnowledgeButtonPressed; + + if (_window is null) + return; + + _window.OnClose += DeactivateButton; + _window.OnOpen += ActivateButton; + } + + private void DeactivateButton() + { + KnowledgeButton!.Pressed = false; + } + + private void ActivateButton() + { + KnowledgeButton!.Pressed = true; + } + + private void KnowledgeUpdated(ClientCP14KnowledgeSystem.KnowledgeData data) + { + if (_window is null) + return; + + _window.KnowledgeContent.RemoveAllChildren(); + + var (entity, allKnowledge) = data; + + foreach (var knowledge in allKnowledge) + { + if (!_proto.TryIndex(knowledge, out var indexedKnowledge)) + continue; + + var knowledgeButton = new Button() + { + Access = AccessLevel.Public, + Text = Loc.GetString(indexedKnowledge.Name), + ToolTip = Loc.GetString(indexedKnowledge.Desc), + TextAlign = Label.AlignMode.Center, + }; + + _window.KnowledgeContent.AddChild(knowledgeButton); + } + } + + private void CharacterDetached(EntityUid uid) + { + CloseWindow(); + } + + private void KnowledgeButtonPressed(BaseButton.ButtonEventArgs args) + { + ToggleWindow(); + } + + private void CloseWindow() + { + _window?.Close(); + } + + private void ToggleWindow() + { + if (_window == null) + return; + + if (KnowledgeButton != null) + { + KnowledgeButton.SetClickPressed(!_window.IsOpen); + } + + if (_window.IsOpen) + { + CloseWindow(); + } + else + { + _knowledge.RequestKnowledgeInfo(); + _window.Open(); + } + } +} diff --git a/Content.Client/_CP14/UserInterface/Systems/Knowledge/Windows/CP14KnowledgeWindow.xaml b/Content.Client/_CP14/UserInterface/Systems/Knowledge/Windows/CP14KnowledgeWindow.xaml new file mode 100644 index 0000000000..419d0f56ce --- /dev/null +++ b/Content.Client/_CP14/UserInterface/Systems/Knowledge/Windows/CP14KnowledgeWindow.xaml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/Content.Client/_CP14/UserInterface/Systems/Knowledge/Windows/CP14KnowledgeWindow.xaml.cs b/Content.Client/_CP14/UserInterface/Systems/Knowledge/Windows/CP14KnowledgeWindow.xaml.cs new file mode 100644 index 0000000000..fbd29858c8 --- /dev/null +++ b/Content.Client/_CP14/UserInterface/Systems/Knowledge/Windows/CP14KnowledgeWindow.xaml.cs @@ -0,0 +1,14 @@ +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.CustomControls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client._CP14.UserInterface.Systems.Knowledge.Windows; + +[GenerateTypedNameReferences] +public sealed partial class CP14KnowledgeWindow : DefaultWindow +{ + public CP14KnowledgeWindow() + { + RobustXamlLoader.Load(this); + } +} diff --git a/Content.Server/_CP14/Knowledge/CP14KnowledgeSystem.cs b/Content.Server/_CP14/Knowledge/CP14KnowledgeSystem.cs index 9dc114dec0..4e867f5310 100644 --- a/Content.Server/_CP14/Knowledge/CP14KnowledgeSystem.cs +++ b/Content.Server/_CP14/Knowledge/CP14KnowledgeSystem.cs @@ -38,6 +38,8 @@ public sealed partial class CP14KnowledgeSystem : SharedCP14KnowledgeSystem SubscribeLocalEvent>(AddKnowledgeAdminVerb); SubscribeLocalEvent>(AddKnowledgeLearningVerb); SubscribeLocalEvent(KnowledgeLearnedEvent); + + SubscribeNetworkEvent(OnRequestKnowledgeInfoEvent); } private void KnowledgeLearnedEvent(Entity ent, ref CP14KnowledgeLearnDoAfterEvent args) @@ -120,7 +122,7 @@ public sealed partial class CP14KnowledgeSystem : SharedCP14KnowledgeSystem Category = VerbCategory.CP14KnowledgeAdd, Act = () => { - TryLearnKnowledge(ent, knowledge, false); + TryLearnKnowledge(ent, knowledge, true); }, Impact = LogImpact.High, }); @@ -251,4 +253,17 @@ public sealed partial class CP14KnowledgeSystem : SharedCP14KnowledgeSystem $"{EntityManager.ToPrettyString(uid):player} forgot knowledge: {Loc.GetString(indexedKnowledge.Name)}"); return true; } + + private void OnRequestKnowledgeInfoEvent(RequestKnowledgeInfoEvent msg, EntitySessionEventArgs args) + { + if (!args.SenderSession.AttachedEntity.HasValue || args.SenderSession.AttachedEntity != GetEntity(msg.NetEntity)) + return; + + var entity = args.SenderSession.AttachedEntity.Value; + + if (!TryComp(entity, out var knowledgeComp)) + return; + + RaiseNetworkEvent(new CP14KnowledgeInfoEvent(GetNetEntity(entity),knowledgeComp.Knowledges), args.SenderSession); + } } diff --git a/Content.Shared/Input/ContentKeyFunctions.cs b/Content.Shared/Input/ContentKeyFunctions.cs index 863d9da970..af6a51717a 100644 --- a/Content.Shared/Input/ContentKeyFunctions.cs +++ b/Content.Shared/Input/ContentKeyFunctions.cs @@ -116,5 +116,9 @@ namespace Content.Shared.Input public static readonly BoundKeyFunction MappingRemoveDecal = "MappingRemoveDecal"; public static readonly BoundKeyFunction MappingCancelEraseDecal = "MappingCancelEraseDecal"; public static readonly BoundKeyFunction MappingOpenContextMenu = "MappingOpenContextMenu"; + + //CP14 keys + public static readonly BoundKeyFunction CP14OpenKnowledgeMenu = "CP14OpenKnowledgeMenu"; + //CP14 keys end } } diff --git a/Content.Shared/_CP14/Knowledge/SharedCP14KnowledgeSystem.cs b/Content.Shared/_CP14/Knowledge/SharedCP14KnowledgeSystem.cs index 0541f86fb0..063ee84e84 100644 --- a/Content.Shared/_CP14/Knowledge/SharedCP14KnowledgeSystem.cs +++ b/Content.Shared/_CP14/Knowledge/SharedCP14KnowledgeSystem.cs @@ -2,6 +2,7 @@ using System.Text; using Content.Shared._CP14.Knowledge.Components; using Content.Shared._CP14.Knowledge.Prototypes; using Content.Shared.DoAfter; +using Content.Shared.Ghost; using Content.Shared.MagicMirror; using Content.Shared.Paper; using Robust.Shared.Prototypes; @@ -65,6 +66,9 @@ public abstract partial class SharedCP14KnowledgeSystem : EntitySystem ProtoId knowledge, CP14KnowledgeStorageComponent? knowledgeStorage = null) { + if (HasComp(uid)) //All-knowing ghosts + return true; + if (!Resolve(uid, ref knowledgeStorage, false)) return false; @@ -92,3 +96,27 @@ public sealed partial class CP14KnowledgeLearnDoAfterEvent : DoAfterEvent public ProtoId Knowledge; public override DoAfterEvent Clone() => this; } + +[Serializable, NetSerializable] +public sealed class CP14KnowledgeInfoEvent : EntityEventArgs +{ + public readonly NetEntity NetEntity; + public readonly HashSet> AllKnowledge; + + public CP14KnowledgeInfoEvent(NetEntity netEntity, HashSet> allKnowledge) + { + NetEntity = netEntity; + AllKnowledge = allKnowledge; + } +} + +[Serializable, NetSerializable] +public sealed class RequestKnowledgeInfoEvent : EntityEventArgs +{ + public readonly NetEntity NetEntity; + + public RequestKnowledgeInfoEvent(NetEntity netEntity) + { + NetEntity = netEntity; + } +} diff --git a/Resources/Locale/en-US/_CP14/HUD/game-hud.ftl b/Resources/Locale/en-US/_CP14/HUD/game-hud.ftl new file mode 100644 index 0000000000..527aa5d197 --- /dev/null +++ b/Resources/Locale/en-US/_CP14/HUD/game-hud.ftl @@ -0,0 +1 @@ +cp14-game-hud-open-knowledge-menu-button-tooltip = Open character knowledge menu. \ No newline at end of file diff --git a/Resources/Locale/en-US/_CP14/escape-menu/ui/options-menu.ftl b/Resources/Locale/en-US/_CP14/escape-menu/ui/options-menu.ftl index e0fbdb6096..c0c4375045 100644 --- a/Resources/Locale/en-US/_CP14/escape-menu/ui/options-menu.ftl +++ b/Resources/Locale/en-US/_CP14/escape-menu/ui/options-menu.ftl @@ -14,3 +14,9 @@ cp14-ui-options-postprocess-tooltip = additive lighting will be present. This does not control post-process effects that affect the game or otherwise carry some form of gameplay-related meaning. + + +## Controls menu + +ui-options-header-cp14 = CrystallEdge +ui-options-function-cp14-open-knowledge-menu = Open character knowledge menu. \ No newline at end of file diff --git a/Resources/Locale/en-US/_CP14/knowledge/knowledge-ui.ftl b/Resources/Locale/en-US/_CP14/knowledge/knowledge-ui.ftl new file mode 100644 index 0000000000..74396f70d2 --- /dev/null +++ b/Resources/Locale/en-US/_CP14/knowledge/knowledge-ui.ftl @@ -0,0 +1 @@ +cp14-knowledge-info-title = Character knowledge \ No newline at end of file diff --git a/Resources/Locale/ru-RU/_CP14/HUD/game-hud.ftl b/Resources/Locale/ru-RU/_CP14/HUD/game-hud.ftl new file mode 100644 index 0000000000..720d097d79 --- /dev/null +++ b/Resources/Locale/ru-RU/_CP14/HUD/game-hud.ftl @@ -0,0 +1 @@ +cp14-game-hud-open-knowledge-menu-button-tooltip = Открыть меню знаний персонажа. \ No newline at end of file diff --git a/Resources/Locale/ru-RU/_CP14/escape-menu/ui/options-menu.ftl b/Resources/Locale/ru-RU/_CP14/escape-menu/ui/options-menu.ftl index 42d32f2236..41db14d008 100644 --- a/Resources/Locale/ru-RU/_CP14/escape-menu/ui/options-menu.ftl +++ b/Resources/Locale/ru-RU/_CP14/escape-menu/ui/options-menu.ftl @@ -14,3 +14,9 @@ cp14-ui-options-postprocess-tooltip = такие как аддитивное освещение. Это не управляет эффеками постобработки, которые влияют на игру или иным образом не контролирует эффекты постобработки, которые влияют на игру или имеют какое-то значение для игрового процесса. + + +## Controls menu + +ui-options-header-cp14 = CrystallEdge +ui-options-function-cp14-open-knowledge-menu = Открыть меню знаний персонажа diff --git a/Resources/Locale/ru-RU/_CP14/knowledge/knowledge-ui.ftl b/Resources/Locale/ru-RU/_CP14/knowledge/knowledge-ui.ftl new file mode 100644 index 0000000000..7b4d3ffbf1 --- /dev/null +++ b/Resources/Locale/ru-RU/_CP14/knowledge/knowledge-ui.ftl @@ -0,0 +1 @@ +cp14-knowledge-info-title = Знания персонажа \ No newline at end of file