#nullable enable using Content.Server.Interfaces; using Content.Server.Interfaces.GameObjects.Components.Items; using Content.Shared.GameObjects.EntitySystems; using Content.Shared.Interfaces.GameObjects.Components; using Robust.Server.GameObjects.Components.UserInterface; using Robust.Server.GameObjects.EntitySystems; using Robust.Server.Interfaces.GameObjects; using Robust.Shared.Audio; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Maths; using Robust.Shared.ViewVariables; using System; using System.Collections.Generic; using static Content.Shared.GameObjects.Components.Disposal.SharedDisposalRouterComponent; namespace Content.Server.GameObjects.Components.Disposal { [RegisterComponent] [ComponentReference(typeof(IActivate))] [ComponentReference(typeof(IDisposalTubeComponent))] public class DisposalRouterComponent : DisposalJunctionComponent, IActivate { [Dependency] private readonly IServerNotifyManager _notifyManager = default!; public override string Name => "DisposalRouter"; [ViewVariables] private readonly HashSet _tags = new HashSet(); [ViewVariables] public bool Anchored => !Owner.TryGetComponent(out ICollidableComponent? collidable) || collidable.Anchored; [ViewVariables] private BoundUserInterface? UserInterface => Owner.TryGetComponent(out ServerUserInterfaceComponent? ui) && ui.TryGetBoundUserInterface(DisposalRouterUiKey.Key, out var boundUi) ? boundUi : null; public override Direction NextDirection(DisposalHolderComponent holder) { var directions = ConnectableDirections(); if (holder.Tags.Overlaps(_tags)) { return directions[1]; } return Owner.Transform.LocalRotation.GetDir(); } public override void Initialize() { base.Initialize(); if (UserInterface != null) { UserInterface.OnReceiveMessage += OnUiReceiveMessage; } UpdateUserInterface(); } /// /// Handles ui messages from the client. For things such as button presses /// which interact with the world and require server action. /// /// A user interface message from the client. private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj) { if (obj.Session.AttachedEntity == null) { return; } var msg = (UiActionMessage) obj.Message; if (!PlayerCanUseDisposalTagger(obj.Session.AttachedEntity)) return; //Check for correct message and ignore maleformed strings if (msg.Action == UiAction.Ok && TagRegex.IsMatch(msg.Tags)) { _tags.Clear(); foreach (var tag in msg.Tags.Split(',', StringSplitOptions.RemoveEmptyEntries)) { _tags.Add(tag.Trim()); ClickSound(); } } } /// /// Checks whether the player entity is able to use the configuration interface of the pipe tagger. /// /// The player entity. /// Returns true if the entity can use the configuration interface, and false if it cannot. private bool PlayerCanUseDisposalTagger(IEntity playerEntity) { //Need player entity to check if they are still able to use the configuration interface if (playerEntity == null) return false; if (!Anchored) return false; //Check if player can interact in their current state if (!ActionBlockerSystem.CanInteract(playerEntity) || !ActionBlockerSystem.CanUse(playerEntity)) return false; return true; } /// /// Gets component data to be used to update the user interface client-side. /// /// Returns a private DisposalRouterUserInterfaceState GetUserInterfaceState() { if(_tags.Count <= 0) { return new DisposalRouterUserInterfaceState(""); } var taglist = new System.Text.StringBuilder(); foreach (var tag in _tags) { taglist.Append(tag); taglist.Append(", "); } taglist.Remove(taglist.Length - 2, 2); return new DisposalRouterUserInterfaceState(taglist.ToString()); } private void UpdateUserInterface() { var state = GetUserInterfaceState(); UserInterface?.SetState(state); } private void ClickSound() { EntitySystem.Get().PlayFromEntity("/Audio/Machines/machine_switch.ogg", Owner, AudioParams.Default.WithVolume(-2f)); } /// /// Called when you click the owner entity with an empty hand. Opens the UI client-side if possible. /// /// Data relevant to the event such as the actor which triggered it. void IActivate.Activate(ActivateEventArgs args) { if (!args.User.TryGetComponent(out IActorComponent? actor)) { return; } if (!args.User.TryGetComponent(out IHandsComponent? hands)) { _notifyManager.PopupMessage(Owner.Transform.GridPosition, args.User, Loc.GetString("You have no hands.")); return; } var activeHandEntity = hands.GetActiveHand?.Owner; if (activeHandEntity == null) { UpdateUserInterface(); UserInterface?.Open(actor.playerSession); } } public override void OnRemove() { UserInterface?.CloseAll(); base.OnRemove(); } } }