From bbd648242040844917e3eb6d1bff4182ac93c4d2 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Thu, 4 Aug 2022 12:38:56 +1200 Subject: [PATCH] Fix lathe unanchor interaction & general cleanup (#10156) --- .../Lathe/Components/LatheComponent.cs | 17 +- .../Components/LatheInsertingComponent.cs | 8 +- .../Components/LatheProducingComponent.cs | 17 +- Content.Server/Lathe/LatheSystem.cs | 252 ++++++++---------- Content.Shared/Lathe/LatheMessages.cs | 4 +- 5 files changed, 144 insertions(+), 154 deletions(-) diff --git a/Content.Server/Lathe/Components/LatheComponent.cs b/Content.Server/Lathe/Components/LatheComponent.cs index 5902c31d28..b3ac8d1f21 100644 --- a/Content.Server/Lathe/Components/LatheComponent.cs +++ b/Content.Server/Lathe/Components/LatheComponent.cs @@ -29,13 +29,10 @@ namespace Content.Server.Lathe.Components /// /// The lathe's construction queue /// - [ViewVariables] - public Queue Queue { get; } = new(); - /// - /// The recipe the lathe is currently producing - /// - [ViewVariables] - public LatheRecipePrototype? ProducingRecipe; + [DataField("queue", customTypeSerializer: typeof(PrototypeIdListSerializer))] + public List Queue { get; } = new(); + // TODO queue serializer. + /// /// How long the inserting animation will play /// @@ -46,12 +43,6 @@ namespace Content.Server.Lathe.Components /// [DataField("insertionAccumulator")] public float InsertionAccumulator = 0f; - /// - /// Production accumulator for the production time. - /// - [ViewVariables] - [DataField("producingAccumulator")] - public float ProducingAccumulator = 0f; /// /// The sound that plays when the lathe is producing an item, if any diff --git a/Content.Server/Lathe/Components/LatheInsertingComponent.cs b/Content.Server/Lathe/Components/LatheInsertingComponent.cs index e808c4d26d..f56ef45976 100644 --- a/Content.Server/Lathe/Components/LatheInsertingComponent.cs +++ b/Content.Server/Lathe/Components/LatheInsertingComponent.cs @@ -5,5 +5,11 @@ namespace Content.Server.Lathe.Components /// [RegisterComponent] public sealed class LatheInsertingComponent : Component - {} + { + /// + /// Remaining insertion time, in seconds. + /// + [DataField("timeRemaining", required: true)] + public float TimeRemaining; + } } diff --git a/Content.Server/Lathe/Components/LatheProducingComponent.cs b/Content.Server/Lathe/Components/LatheProducingComponent.cs index 55ff79d625..89a7c96e06 100644 --- a/Content.Server/Lathe/Components/LatheProducingComponent.cs +++ b/Content.Server/Lathe/Components/LatheProducingComponent.cs @@ -1,3 +1,6 @@ +using Content.Shared.Research.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + namespace Content.Server.Lathe.Components { /// @@ -5,5 +8,17 @@ namespace Content.Server.Lathe.Components /// [RegisterComponent] public sealed class LatheProducingComponent : Component - {} + { + /// + /// The recipe the lathe is currently producing + /// + [DataField("recipe", required:true, customTypeSerializer:typeof(PrototypeIdSerializer))] + public string? Recipe; + + /// + /// Remaining production time, in seconds. + /// + [DataField("timeRemaining", required: true)] + public float TimeRemaining; + } } diff --git a/Content.Server/Lathe/LatheSystem.cs b/Content.Server/Lathe/LatheSystem.cs index 9d16f9c6c9..6ca7b5855a 100644 --- a/Content.Server/Lathe/LatheSystem.cs +++ b/Content.Server/Lathe/LatheSystem.cs @@ -6,18 +6,16 @@ using Content.Server.Research.Components; using Content.Shared.Interaction; using Content.Server.Materials; using Content.Server.Popups; -using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Server.Research; using Content.Server.Stack; -using Content.Server.UserInterface; using Content.Shared.Research.Components; using Robust.Server.GameObjects; using Robust.Shared.Prototypes; using Robust.Shared.Player; -using Robust.Shared.Audio; using JetBrains.Annotations; using System.Linq; +using Robust.Server.Player; namespace Content.Server.Lathe { @@ -26,59 +24,40 @@ namespace Content.Server.Lathe { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; - + [Dependency] private readonly SharedAudioSystem _audioSys = default!; + [Dependency] private readonly UserInterfaceSystem _uiSys = default!; + [Dependency] private readonly ResearchSystem _researchSys = default!; + public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnInteractUsing); SubscribeLocalEvent(OnComponentInit); + SubscribeLocalEvent(OnLatheQueueRecipeMessage); + SubscribeLocalEvent(OnLatheSyncRequestMessage); + SubscribeLocalEvent(OnLatheServerSelectionMessage); + SubscribeLocalEvent(OnLatheServerSyncMessage); } - // These queues are to add/remove COMPONENTS to the lathes - private Queue ProducingAddQueue = new(); - private Queue ProducingRemoveQueue = new(); - private Queue InsertingAddQueue = new(); - private Queue InsertingRemoveQueue = new(); - public override void Update(float frameTime) { - foreach (var uid in ProducingAddQueue) - EnsureComp(uid); - ProducingAddQueue.Clear(); - foreach (var uid in ProducingRemoveQueue) - RemComp(uid); - ProducingRemoveQueue.Clear(); - foreach (var uid in InsertingAddQueue) - EnsureComp(uid); - InsertingAddQueue.Clear(); - foreach (var uid in InsertingRemoveQueue) - RemComp(uid); - InsertingRemoveQueue.Clear(); - - foreach (var (insertingComp, lathe) in EntityQuery(false)) + foreach (var comp in EntityQuery()) { - if (lathe.InsertionAccumulator < lathe.InsertionTime) - { - lathe.InsertionAccumulator += frameTime; + comp.TimeRemaining -= frameTime; + + if (comp.TimeRemaining > 0) continue; - } - lathe.InsertionAccumulator = 0; - UpdateInsertingAppearance(lathe.Owner, false); - InsertingRemoveQueue.Enqueue(lathe.Owner); + + UpdateInsertingAppearance(comp.Owner, false); + RemCompDeferred(comp.Owner, comp); } - foreach (var (producingComp, lathe) in EntityQuery(false)) + foreach (var comp in EntityQuery()) { - if (lathe.ProducingRecipe == null) - continue; - if (lathe.ProducingAccumulator < lathe.ProducingRecipe.CompleteTime.TotalSeconds) - { - lathe.ProducingAccumulator += frameTime; - continue; - } - lathe.ProducingAccumulator = 0; + comp.TimeRemaining -= frameTime; - FinishProducing(lathe.ProducingRecipe, lathe, true); + if (comp.TimeRemaining <= 0) + FinishProducing(comp.Owner, comp); } } @@ -88,12 +67,6 @@ namespace Content.Server.Lathe /// private void OnComponentInit(EntityUid uid, LatheComponent component, ComponentInit args) { - component.UserInterface = uid.GetUIOrNull(LatheUiKey.Key); - if (component.UserInterface != null) - { - component.UserInterface.OnReceiveMessage += msg => UserInterfaceOnOnReceiveMessage(uid, component, msg); - } - if (TryComp(uid, out var appearance)) { appearance.SetData(LatheVisuals.IsInserting, false); @@ -111,9 +84,13 @@ namespace Content.Server.Lathe return; foreach (var recipe in recipes) + { foreach (var mat in recipe.RequiredMaterials) + { if (!component.MaterialWhiteList.Contains(mat.Key)) component.MaterialWhiteList.Add(mat.Key); + } + } } /// @@ -124,13 +101,14 @@ namespace Content.Server.Lathe { if (args.Handled) return; - args.Handled = true; if (!TryComp(uid, out var storage) || !TryComp(args.Used, out var material) || component.LatheWhitelist?.IsValid(args.Used) == false) return; + args.Handled = true; + var matUsed = false; foreach (var mat in material.Materials) if (component.MaterialWhiteList.Contains(mat.ID)) @@ -160,6 +138,7 @@ namespace Content.Server.Lathe // Check if it can take ALL of the material's volume. if (storage.StorageLimit > 0 && !storage.CanTakeAmount(totalAmount)) return; + var lastMat = string.Empty; foreach (var (mat, vol) in material._materials) { @@ -169,17 +148,18 @@ namespace Content.Server.Lathe // Play a sound when inserting, if any if (component.InsertingSound != null) - { - SoundSystem.Play(component.InsertingSound.GetSound(), Filter.Pvs(component.Owner, entityManager: EntityManager), component.Owner); - } + _audioSys.PlayPvs(component.InsertingSound, uid); // We need the prototype to get the color _prototypeManager.TryIndex(lastMat, out MaterialPrototype? matProto); EntityManager.QueueDeleteEntity(args.Used); - InsertingAddQueue.Enqueue(uid); + + EnsureComp(uid).TimeRemaining = component.InsertionTime; + _popupSystem.PopupEntity(Loc.GetString("machine-insert-item", ("machine", uid), ("item", args.Used)), uid, Filter.Entities(args.User)); + if (matProto != null) { UpdateInsertingAppearance(uid, true, matProto.Color); @@ -191,30 +171,34 @@ namespace Content.Server.Lathe /// This handles the checks to start producing an item, and /// starts up the sound and visuals /// - private void Produce(LatheComponent component, LatheRecipePrototype recipe, bool SkipCheck = false) + private bool TryStartProducing(EntityUid uid, LatheProducingComponent? prodComp = null, LatheComponent? component = null) { - if (!component.CanProduce(recipe) - || !TryComp(component.Owner, out MaterialStorageComponent? storage)) + if (!Resolve(uid, ref component) || component.Queue.Count == 0) + return false; + + if (!this.IsPowered(uid, EntityManager)) + return false; + + var recipeId = component.Queue[0]; + + if (!_prototypeManager.TryIndex(recipeId, out var recipe)) { - FinishProducing(recipe, component, false); - return; + // recipie does not exist. Remove and try produce the next item. + component.Queue.RemoveAt(0); + return TryStartProducing(uid, prodComp, component); } + + if (!component.CanProduce(recipe) || !TryComp(uid, out MaterialStorageComponent? storage)) + return false; - if (!SkipCheck && HasComp(component.Owner)) - { - FinishProducing(recipe, component, false); - return; - } + prodComp ??= EnsureComp(uid); - if (!this.IsPowered(component.Owner, EntityManager)) - { - FinishProducing(recipe, component, false); - return; - } + if (prodComp.Recipe != null) + return false; - component.UserInterface?.SendMessage(new LatheFullQueueMessage(GetIdQueue(component))); - - component.ProducingRecipe = recipe; + component.Queue.RemoveAt(0); + prodComp.Recipe = recipeId; + prodComp.TimeRemaining = (float)recipe.CompleteTime.TotalSeconds; foreach (var (material, amount) in recipe.RequiredMaterials) { @@ -222,33 +206,42 @@ namespace Content.Server.Lathe storage.RemoveMaterial(material, amount); } - component.UserInterface?.SendMessage(new LatheProducingRecipeMessage(recipe.ID)); + // Again, this should really just be a bui state instead of two separate messages. + _uiSys.TrySendUiMessage(uid, LatheUiKey.Key, new LatheProducingRecipeMessage(recipe.ID)); + _uiSys.TrySendUiMessage(uid, LatheUiKey.Key, new LatheFullQueueMessage(component.Queue)); + if (component.ProducingSound != null) - { - SoundSystem.Play(component.ProducingSound.GetSound(), Filter.Pvs(component.Owner), component.Owner); - } - UpdateRunningAppearance(component.Owner, true); - ProducingAddQueue.Enqueue(component.Owner); + _audioSys.PlayPvs(component.ProducingSound, component.Owner); + + UpdateRunningAppearance(uid, true); + return true; } /// /// If we were able to produce the recipe, /// spawn it and cleanup. If we weren't, just do cleanup. /// - private void FinishProducing(LatheRecipePrototype recipe, LatheComponent component, bool productionSucceeded = true) + private void FinishProducing(EntityUid uid, LatheProducingComponent prodComp) { - component.ProducingRecipe = null; - if (productionSucceeded) - EntityManager.SpawnEntity(recipe.Result, Comp(component.Owner).Coordinates); - component.UserInterface?.SendMessage(new LatheStoppedProducingRecipeMessage()); - // Continue to next in queue if there are items left - if (component.Queue.Count > 0) + if (prodComp.Recipe == null || !_prototypeManager.TryIndex(prodComp.Recipe, out var recipe)) { - Produce(component, component.Queue.Dequeue(), true); + RemCompDeferred(prodComp.Owner, prodComp); + UpdateRunningAppearance(uid, false); return; } - ProducingRemoveQueue.Enqueue(component.Owner); - UpdateRunningAppearance(component.Owner, false); + + Spawn(recipe.Result, Transform(uid).Coordinates); + prodComp.Recipe = null; + + // TODO this should probably just be a BUI state, not a special message. + _uiSys.TrySendUiMessage(uid, LatheUiKey.Key, new LatheStoppedProducingRecipeMessage()); + + // Continue to next in queue if there are items left + if (TryStartProducing(uid, prodComp)) + return; + + RemComp(prodComp.Owner, prodComp); + UpdateRunningAppearance(uid, false); } /// @@ -277,64 +270,49 @@ namespace Content.Server.Lathe appearance.SetData(LatheVisuals.InsertingColor, color); } - /// - /// Handles all the button presses in the lathe UI - /// - private void UserInterfaceOnOnReceiveMessage(EntityUid uid, LatheComponent component, ServerBoundUserInterfaceMessage message) + #region UI Messages + + private void OnLatheQueueRecipeMessage(EntityUid uid, LatheComponent component, LatheQueueRecipeMessage args) { - if (!this.IsPowered(uid, EntityManager)) - return; - - switch (message.Message) + if (_prototypeManager.TryIndex(args.ID, out LatheRecipePrototype? recipe)) { - case LatheQueueRecipeMessage msg: - _prototypeManager.TryIndex(msg.ID, out LatheRecipePrototype? recipe); - if (recipe != null!) - for (var i = 0; i < msg.Quantity; i++) - { - component.Queue.Enqueue(recipe); - component.UserInterface?.SendMessage(new LatheFullQueueMessage(GetIdQueue(component))); - } - if (!HasComp(component.Owner) && component.Queue.Count > 0) - Produce(component, component.Queue.Dequeue()); + for (var i = 0; i < args.Quantity; i++) + { + component.Queue.Add(recipe.ID); + } - break; - case LatheSyncRequestMessage _: - if (!HasComp(uid)) return; - component.UserInterface?.SendMessage(new LatheFullQueueMessage(GetIdQueue(component))); - if (component.ProducingRecipe != null) - component.UserInterface?.SendMessage(new LatheProducingRecipeMessage(component.ProducingRecipe.ID)); - break; - - case LatheServerSelectionMessage _: - if (!TryComp(uid, out ResearchClientComponent? researchClient)) return; - IoCManager.Resolve() - .GetEntitySystem() - .TryOpen(uid, ResearchClientUiKey.Key, message.Session); - break; - - case LatheServerSyncMessage _: - if (!TryComp(uid, out TechnologyDatabaseComponent? database) - || !TryComp(uid, out ProtolatheDatabaseComponent? protoDatabase)) return; - - if (IoCManager.Resolve().GetEntitySystem().SyncWithServer(database)) - protoDatabase.Sync(); - - break; + // Again: TODO this should be handled by BUI states + _uiSys.TrySendUiMessage(uid, LatheUiKey.Key, new LatheFullQueueMessage(component.Queue)); } + + TryStartProducing(component.Owner, null, component); } - /// - /// Gets all the prototypes in the lathe's construction queue - /// - private Queue GetIdQueue(LatheComponent lathe) + private void OnLatheSyncRequestMessage(EntityUid uid, LatheComponent component, LatheSyncRequestMessage args) { - var queue = new Queue(); - foreach (var recipePrototype in lathe.Queue) - { - queue.Enqueue(recipePrototype.ID); - } - return queue; + if (!HasComp(uid)) return; + + // Again: TODO BUI states. Why TF was this was this ever two separate messages!?!? + _uiSys.TrySendUiMessage(uid, LatheUiKey.Key, new LatheFullQueueMessage(component.Queue)); + if (TryComp(uid, out LatheProducingComponent? prodComp) && prodComp.Recipe != null) + _uiSys.TrySendUiMessage(uid, LatheUiKey.Key, new LatheProducingRecipeMessage(prodComp.Recipe)); } + + private void OnLatheServerSelectionMessage(EntityUid uid, LatheComponent component, LatheServerSelectionMessage args) + { + // TODO W.. b.. why? + // the client can just open the ui itself. why tf is it asking the server to open it for it. + _uiSys.TryOpen(uid, ResearchClientUiKey.Key, (IPlayerSession) args.Session); + } + + private void OnLatheServerSyncMessage(EntityUid uid, TechnologyDatabaseComponent component, LatheServerSyncMessage args) + { + _researchSys.SyncWithServer(component); + + if (TryComp(uid, out ProtolatheDatabaseComponent? protoDatabase)) + protoDatabase.Sync(); + } + + #endregion } } diff --git a/Content.Shared/Lathe/LatheMessages.cs b/Content.Shared/Lathe/LatheMessages.cs index 0ffffb1306..e23bea0ca7 100644 --- a/Content.Shared/Lathe/LatheMessages.cs +++ b/Content.Shared/Lathe/LatheMessages.cs @@ -65,8 +65,8 @@ namespace Content.Shared.Lathe; [Serializable, NetSerializable] public sealed class LatheFullQueueMessage : BoundUserInterfaceMessage { - public readonly Queue Recipes; - public LatheFullQueueMessage(Queue recipes) + public readonly List Recipes; + public LatheFullQueueMessage(List recipes) { Recipes = recipes; }