diff --git a/Content.Server/Administration/AdminVerbSystem.cs b/Content.Server/Administration/AdminVerbSystem.cs index 4c975847ae..cf986a7491 100644 --- a/Content.Server/Administration/AdminVerbSystem.cs +++ b/Content.Server/Administration/AdminVerbSystem.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Threading; using Content.Server.Administration.Commands; using Content.Server.Administration.Managers; @@ -10,7 +9,6 @@ using Content.Server.Disposal.Tube.Components; using Content.Server.EUI; using Content.Server.Explosion.EntitySystems; using Content.Server.Ghost.Roles; -using Content.Server.Inventory; using Content.Server.Mind.Commands; using Content.Server.Mind.Components; using Content.Server.Players; @@ -22,17 +20,14 @@ using Content.Shared.Database; using Content.Shared.GameTicking; using Content.Shared.Interaction.Helpers; using Content.Shared.Inventory; -using Content.Shared.Movement.Components; using Content.Shared.Popups; using Content.Shared.Verbs; using Robust.Server.Console; using Robust.Server.GameObjects; using Robust.Server.Player; using Robust.Shared.Console; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Localization; using Robust.Shared.Timing; +using static Content.Shared.Configurable.SharedConfigurationComponent; using Timer = Robust.Shared.Timing.Timer; namespace Content.Server.Administration @@ -50,6 +45,7 @@ namespace Content.Server.Administration [Dependency] private readonly ExplosionSystem _explosions = default!; [Dependency] private readonly GhostRoleSystem _ghostRoleSystem = default!; [Dependency] private readonly ArtifactSystem _artifactSystem = default!; + [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; private readonly Dictionary _openSolutionUis = new(); @@ -289,7 +285,6 @@ namespace Content.Server.Administration args.Verbs.Add(verb); } - // Configuration verb. Is this even used for anything!? if (_groupController.CanAdminMenu(player) && EntityManager.TryGetComponent(args.Target, out var config)) { @@ -297,7 +292,7 @@ namespace Content.Server.Administration verb.Text = Loc.GetString("configure-verb-get-data-text"); verb.IconTexture = "/Textures/Interface/VerbIcons/settings.svg.192dpi.png"; verb.Category = VerbCategory.Debug; - verb.Act = () => config.OpenUserInterface(actor); + verb.Act = () => _uiSystem.TryOpen(args.Target, ConfigurationUiKey.Key, actor.PlayerSession); args.Verbs.Add(verb); } diff --git a/Content.Server/Configurable/ConfigurationComponent.cs b/Content.Server/Configurable/ConfigurationComponent.cs index e905674906..22d7a0dd0f 100644 --- a/Content.Server/Configurable/ConfigurationComponent.cs +++ b/Content.Server/Configurable/ConfigurationComponent.cs @@ -1,136 +1,16 @@ -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Content.Server.Tools.Components; -using Content.Server.UserInterface; using Content.Shared.Configurable; -using Content.Shared.Interaction; using Content.Shared.Tools; -using Content.Shared.Tools.Components; -using Content.Shared.Verbs; -using Robust.Server.Console; -using Robust.Server.GameObjects; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Serialization; -using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.ViewVariables; -namespace Content.Server.Configurable +namespace Content.Server.Configurable; + +[RegisterComponent] +[ComponentReference(typeof(SharedConfigurationComponent))] +public sealed class ConfigurationComponent : SharedConfigurationComponent { - [RegisterComponent] - [ComponentReference(typeof(SharedConfigurationComponent))] - public sealed class ConfigurationComponent : SharedConfigurationComponent, IInteractUsing, ISerializationHooks - { - [Dependency] private readonly IEntityManager _entMan = default!; + [DataField("config")] + public readonly Dictionary Config = new(); - [ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(ConfigurationUiKey.Key); - - [DataField("keys")] private List _keys = new(); - - [ViewVariables] - private readonly Dictionary _config = new(); - - [DataField("validation")] - private readonly Regex _validation = new ("^[a-zA-Z0-9 ]*$", RegexOptions.Compiled); - - [DataField("qualityNeeded", customTypeSerializer:typeof(PrototypeIdSerializer))] - private string _qualityNeeded = "Pulsing"; - - void ISerializationHooks.BeforeSerialization() - { - _keys = _config.Keys.ToList(); - } - - void ISerializationHooks.AfterDeserialization() - { - foreach (var key in _keys) - { - _config.Add(key, string.Empty); - } - } - - protected override void OnAdd() - { - base.OnAdd(); - if (UserInterface != null) - { - UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage; - } - } - - protected override void OnRemove() - { - base.OnRemove(); - if (UserInterface != null) - { - UserInterface.OnReceiveMessage -= UserInterfaceOnReceiveMessage; - } - } - - public string? GetConfig(string name) - { - return _config.GetValueOrDefault(name); - } - - protected override void Startup() - { - base.Startup(); - UpdateUserInterface(); - } - - async Task IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs) - { - if (UserInterface == null || !_entMan.TryGetComponent(eventArgs.User, out ActorComponent? actor)) - return false; - - if (!_entMan.TryGetComponent(eventArgs.Using, out var tool) || !tool.Qualities.Contains(_qualityNeeded)) - return false; - - OpenUserInterface(actor); - return true; - } - - private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage serverMsg) - { - var message = serverMsg.Message; - var config = new Dictionary(_config); - - if (message is ConfigurationUpdatedMessage msg) - { - foreach (var key in config.Keys) - { - var value = msg.Config.GetValueOrDefault(key); - - if (value == null || _validation != null && !_validation.IsMatch(value) && value != string.Empty) - continue; - - _config[key] = value; - } - - // TODO raise event. - } - } - - private void UpdateUserInterface() - { - UserInterface?.SetState(new ConfigurationBoundUserInterfaceState(_config)); - } - - public void OpenUserInterface(ActorComponent actor) - { - UpdateUserInterface(); - UserInterface?.Open(actor.PlayerSession); - UserInterface?.SendMessage(new ValidationUpdateMessage(_validation.ToString()), actor.PlayerSession); - } - - private static void FillConfiguration(List list, Dictionary configuration, T value){ - for (var index = 0; index < list.Count; index++) - { - configuration.Add(list[index], value); - } - } - } + [DataField("qualityNeeded", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string QualityNeeded = "Pulsing"; } diff --git a/Content.Server/Configurable/ConfigurationSystem.cs b/Content.Server/Configurable/ConfigurationSystem.cs new file mode 100644 index 0000000000..ff373c10d8 --- /dev/null +++ b/Content.Server/Configurable/ConfigurationSystem.cs @@ -0,0 +1,64 @@ +using Content.Server.Tools.Components; +using Content.Shared.Interaction; +using Robust.Server.GameObjects; +using static Content.Shared.Configurable.SharedConfigurationComponent; + +namespace Content.Server.Configurable; + +public sealed class ConfigurationSystem : EntitySystem +{ + [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnUpdate); + SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent(OnInteractUsing); + } + + private void OnInteractUsing(EntityUid uid, ConfigurationComponent component, InteractUsingEvent args) + { + if (args.Handled) + return; + + if (!TryComp(args.Used, out ToolComponent? tool) || !tool.Qualities.Contains(component.QualityNeeded)) + return; + + if (!TryComp(args.User, out ActorComponent? actor)) + return; + + args.Handled = _uiSystem.TryOpen(uid, ConfigurationUiKey.Key, actor.PlayerSession); + } + + private void OnStartup(EntityUid uid, ConfigurationComponent component, ComponentStartup args) + { + UpdateUi(uid, component); + } + + private void UpdateUi(EntityUid uid, ConfigurationComponent component) + { + if (_uiSystem.TryGetUi(uid, ConfigurationUiKey.Key, out var ui)) + ui.SetState(new ConfigurationBoundUserInterfaceState(component.Config)); + } + + private void OnUpdate(EntityUid uid, ConfigurationComponent component, ConfigurationUpdatedMessage args) + { + foreach (var key in component.Config.Keys) + { + var value = args.Config.GetValueOrDefault(key); + + if (string.IsNullOrWhiteSpace(value) || component.Validation != null && !component.Validation.IsMatch(value)) + continue; + + component.Config[key] = value; + } + + UpdateUi(uid, component); + + // TODO raise event. + // TODO support float (spinbox) and enum (drop-down) configurations + // TODO support verbs. + } +} diff --git a/Content.Shared/Configurable/SharedConfigurationComponent.cs b/Content.Shared/Configurable/SharedConfigurationComponent.cs index 414f7699ed..965d7a9e5d 100644 --- a/Content.Shared/Configurable/SharedConfigurationComponent.cs +++ b/Content.Shared/Configurable/SharedConfigurationComponent.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using Robust.Shared.GameObjects; +using System.Text.RegularExpressions; using Robust.Shared.Serialization; namespace Content.Shared.Configurable @@ -8,6 +6,9 @@ namespace Content.Shared.Configurable [Virtual] public class SharedConfigurationComponent : Component { + [DataField("validation")] + public readonly Regex Validation = new("^[a-zA-Z0-9 ]*$", RegexOptions.Compiled); + [Serializable, NetSerializable] public sealed class ConfigurationBoundUserInterfaceState : BoundUserInterfaceState {