Lathe Refactor and ECS (#11201)
* lathe and material storage refactor * materialStorage ECS it kinda sus tho * beginning the lathe shitcode dive * couple lathe visuals and lathe system * lathe changes and such * dynamic lathe databases * rewrote internal logic on to ui * da newI * material display clientside * misc ui changes * component state handling and various other things * moar * Update Content.Shared/Lathe/LatheComponent.cs Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * first volley of sloth review * more fixes * losin' my mind * all da changes * test fix and other review Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
This commit is contained in:
73
Content.Shared/Lathe/LatheComponent.cs
Normal file
73
Content.Shared/Lathe/LatheComponent.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using Content.Shared.Research.Prototypes;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||
|
||||
namespace Content.Shared.Lathe
|
||||
{
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed class LatheComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// All of the recipes that the lathe has by default
|
||||
/// </summary>
|
||||
[DataField("staticRecipes", customTypeSerializer: typeof(PrototypeIdListSerializer<LatheRecipePrototype>))]
|
||||
public readonly List<string> StaticRecipes = new();
|
||||
|
||||
/// <summary>
|
||||
/// All of the recipes that the lathe is capable of researching
|
||||
/// </summary>
|
||||
[DataField("dynamicRecipes", customTypeSerializer: typeof(PrototypeIdListSerializer<LatheRecipePrototype>))]
|
||||
public readonly List<string>? DynamicRecipes;
|
||||
|
||||
/// <summary>
|
||||
/// The lathe's construction queue
|
||||
/// </summary>
|
||||
[DataField("queue")]
|
||||
public List<LatheRecipePrototype> Queue = new();
|
||||
|
||||
/// <summary>
|
||||
/// How long the inserting animation will play
|
||||
/// </summary>
|
||||
[DataField("insertionTime")]
|
||||
public float InsertionTime = 0.79f; // 0.01 off for animation timing
|
||||
|
||||
/// <summary>
|
||||
/// The sound that plays when the lathe is producing an item, if any
|
||||
/// </summary>
|
||||
[DataField("producingSound")]
|
||||
public SoundSpecifier? ProducingSound;
|
||||
|
||||
#region Visualizer info
|
||||
[DataField("idleState", required: true)]
|
||||
public string IdleState = default!;
|
||||
|
||||
[DataField("runningState", required: true)]
|
||||
public string RunningState = default!;
|
||||
|
||||
[ViewVariables]
|
||||
[DataField("ignoreColor")]
|
||||
public bool IgnoreColor;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// The recipe the lathe is currently producing
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public LatheRecipePrototype? CurrentRecipe;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public sealed class LatheGetRecipesEvent : EntityEventArgs
|
||||
{
|
||||
public readonly EntityUid Lathe;
|
||||
|
||||
public List<string> Recipes = new();
|
||||
|
||||
public LatheGetRecipesEvent(EntityUid lathe)
|
||||
{
|
||||
Lathe = lathe;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,94 +1,60 @@
|
||||
using Content.Shared.Research.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Lathe;
|
||||
|
||||
/// <summary>
|
||||
/// Sent to the server to sync material storage and the recipe queue.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class LatheSyncRequestMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public LatheSyncRequestMessage()
|
||||
{
|
||||
}
|
||||
}
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class LatheUpdateState : BoundUserInterfaceState
|
||||
{
|
||||
public List<string> Recipes;
|
||||
|
||||
/// <summary>
|
||||
/// Sent to the server to sync the lathe's technology database with the research server.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class LatheServerSyncMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public LatheServerSyncMessage()
|
||||
{
|
||||
}
|
||||
}
|
||||
public List<LatheRecipePrototype> Queue;
|
||||
|
||||
/// <summary>
|
||||
/// Sent to the server to open the ResearchClient UI.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class LatheServerSelectionMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public LatheServerSelectionMessage()
|
||||
{
|
||||
}
|
||||
}
|
||||
public LatheRecipePrototype? CurrentlyProducing;
|
||||
|
||||
/// <summary>
|
||||
/// Sent to the client when the lathe is producing a recipe.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class LatheProducingRecipeMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public readonly string ID;
|
||||
public LatheProducingRecipeMessage(string id)
|
||||
{
|
||||
ID = id;
|
||||
}
|
||||
}
|
||||
public LatheUpdateState(List<string> recipes, List<LatheRecipePrototype> queue, LatheRecipePrototype? currentlyProducing = null)
|
||||
{
|
||||
Recipes = recipes;
|
||||
Queue = queue;
|
||||
CurrentlyProducing = currentlyProducing;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sent to the client when the lathe stopped/finished producing a recipe.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class LatheStoppedProducingRecipeMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public LatheStoppedProducingRecipeMessage()
|
||||
{
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Sent to the server to sync material storage and the recipe queue.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class LatheSyncRequestMessage : BoundUserInterfaceMessage { }
|
||||
|
||||
/// <summary>
|
||||
/// Sent to the client to let it know about the recipe queue.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class LatheFullQueueMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public readonly List<string> Recipes;
|
||||
public LatheFullQueueMessage(List<string> recipes)
|
||||
{
|
||||
Recipes = recipes;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Sent to the server to sync the lathe's technology database with the research server.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class LatheServerSyncMessage : BoundUserInterfaceMessage { }
|
||||
|
||||
/// <summary>
|
||||
/// Sent to the server when a client queues a new recipe.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class LatheQueueRecipeMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public readonly string ID;
|
||||
public readonly int Quantity;
|
||||
public LatheQueueRecipeMessage(string id, int quantity)
|
||||
{
|
||||
ID = id;
|
||||
Quantity = quantity;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Sent to the server to open the ResearchClient UI.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class LatheServerSelectionMessage : BoundUserInterfaceMessage { }
|
||||
|
||||
[NetSerializable, Serializable]
|
||||
public enum LatheUiKey
|
||||
{
|
||||
Key,
|
||||
}
|
||||
/// <summary>
|
||||
/// Sent to the server when a client queues a new recipe.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class LatheQueueRecipeMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public readonly string ID;
|
||||
public readonly int Quantity;
|
||||
public LatheQueueRecipeMessage(string id, int quantity)
|
||||
{
|
||||
ID = id;
|
||||
Quantity = quantity;
|
||||
}
|
||||
}
|
||||
|
||||
[NetSerializable, Serializable]
|
||||
public enum LatheUiKey
|
||||
{
|
||||
Key,
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Lathe
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
/// <summary>
|
||||
/// Stores bools for if the machine is on
|
||||
/// and if it's currently running and/or inserting.
|
||||
/// Used for the visualizer
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public enum LatheVisuals : byte
|
||||
{
|
||||
IsRunning,
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
using Content.Shared.Research.Prototypes;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Lathe
|
||||
{
|
||||
[NetworkedComponent()]
|
||||
[Virtual]
|
||||
public class SharedLatheComponent : Component
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||
[Dependency] protected readonly IPrototypeManager PrototypeManager = default!;
|
||||
public bool CanProduce(LatheRecipePrototype recipe, int quantity = 1)
|
||||
{
|
||||
if (!_entMan.TryGetComponent(Owner, out SharedMaterialStorageComponent? storage)
|
||||
|| !_entMan.TryGetComponent(Owner, out SharedLatheDatabaseComponent? database)) return false;
|
||||
|
||||
if (!database.Contains(recipe)) return false;
|
||||
|
||||
foreach (var (material, amount) in recipe.RequiredMaterials)
|
||||
{
|
||||
if (storage[material] < (amount * quantity)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CanProduce(string id, int quantity = 1)
|
||||
{
|
||||
return PrototypeManager.TryIndex(id, out LatheRecipePrototype? recipe) && CanProduce(recipe, quantity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
using System.Collections;
|
||||
using Content.Shared.Research.Prototypes;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||
|
||||
namespace Content.Shared.Lathe
|
||||
{
|
||||
[NetworkedComponent()]
|
||||
public abstract class SharedLatheDatabaseComponent : Component, IEnumerable<LatheRecipePrototype>, ISerializationHooks
|
||||
{
|
||||
[DataField("recipes", customTypeSerializer: typeof(PrototypeIdListSerializer<LatheRecipePrototype>))] private List<string> _recipeIds = new();
|
||||
public readonly List<LatheRecipePrototype> _recipes = new();
|
||||
|
||||
void ISerializationHooks.BeforeSerialization()
|
||||
{
|
||||
var list = new List<string>();
|
||||
|
||||
foreach (var recipe in _recipes)
|
||||
{
|
||||
list.Add(recipe.ID);
|
||||
}
|
||||
|
||||
_recipeIds = list;
|
||||
}
|
||||
|
||||
void ISerializationHooks.AfterDeserialization()
|
||||
{
|
||||
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
||||
|
||||
foreach (var id in _recipeIds)
|
||||
{
|
||||
if (prototypeManager.TryIndex(id, out LatheRecipePrototype? recipe))
|
||||
{
|
||||
_recipes.Add(recipe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all recipes from the database if it's not static.
|
||||
/// </summary>
|
||||
/// <returns>Whether it could clear the database or not.</returns>
|
||||
public virtual void Clear()
|
||||
{
|
||||
_recipes.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a recipe to the database if it's not static.
|
||||
/// </summary>
|
||||
/// <param name="recipe">The recipe to be added.</param>
|
||||
/// <returns>Whether it could be added or not</returns>
|
||||
public virtual void AddRecipe(LatheRecipePrototype recipe)
|
||||
{
|
||||
if (!Contains(recipe))
|
||||
_recipes.Add(recipe);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a recipe from the database if it's not static.
|
||||
/// </summary>
|
||||
/// <param name="recipe">The recipe to be removed.</param>
|
||||
/// <returns>Whether it could be removed or not</returns>
|
||||
public virtual bool RemoveRecipe(LatheRecipePrototype recipe)
|
||||
{
|
||||
return _recipes.Remove(recipe);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the database contains the recipe or not.
|
||||
/// </summary>
|
||||
/// <param name="recipe">The recipe to check</param>
|
||||
/// <returns>Whether the database contained the recipe or not.</returns>
|
||||
public virtual bool Contains(LatheRecipePrototype recipe)
|
||||
{
|
||||
return _recipes.Contains(recipe);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the database contains the recipe or not.
|
||||
/// </summary>
|
||||
/// <param name="id">The recipe id to check</param>
|
||||
/// <returns>Whether the database contained the recipe or not.</returns>
|
||||
public virtual bool Contains(string id)
|
||||
{
|
||||
foreach (var recipe in _recipes)
|
||||
{
|
||||
if (recipe.ID == id) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<string> GetRecipeIdList()
|
||||
{
|
||||
var list = new List<string>();
|
||||
|
||||
foreach (var recipe in this)
|
||||
{
|
||||
list.Add(recipe.ID);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public IEnumerator<LatheRecipePrototype> GetEnumerator()
|
||||
{
|
||||
return _recipes.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
[NetSerializable, Serializable]
|
||||
public sealed class LatheDatabaseState : ComponentState
|
||||
{
|
||||
public readonly List<string> Recipes;
|
||||
public LatheDatabaseState(List<string> recipes)
|
||||
{
|
||||
Recipes = recipes;
|
||||
}
|
||||
}
|
||||
}
|
||||
38
Content.Shared/Lathe/SharedLatheSystem.cs
Normal file
38
Content.Shared/Lathe/SharedLatheSystem.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using Content.Shared.Materials;
|
||||
using Content.Shared.Research.Prototypes;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared.Lathe;
|
||||
|
||||
/// <summary>
|
||||
/// This handles...
|
||||
/// </summary>
|
||||
public abstract class SharedLatheSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly SharedMaterialStorageSystem _materialStorage = default!;
|
||||
|
||||
[PublicAPI]
|
||||
public bool CanProduce(EntityUid uid, string recipe, int amount = 1, LatheComponent? component = null)
|
||||
{
|
||||
return _proto.TryIndex<LatheRecipePrototype>(recipe, out var proto) && CanProduce(uid, proto, amount, component);
|
||||
}
|
||||
|
||||
public bool CanProduce(EntityUid uid, LatheRecipePrototype recipe, int amount = 1, LatheComponent? component = null)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return false;
|
||||
if (!HasRecipe(uid, recipe, component))
|
||||
return false;
|
||||
|
||||
foreach (var (material, needed) in recipe.RequiredMaterials)
|
||||
{
|
||||
if (_materialStorage.GetMaterialAmount(component.Owner, material) < (amount * needed))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract bool HasRecipe(EntityUid uid, LatheRecipePrototype recipe, LatheComponent component);
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
using System.Collections;
|
||||
using Content.Shared.Materials;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Lathe
|
||||
{
|
||||
[NetworkedComponent()]
|
||||
public abstract class SharedMaterialStorageComponent : Component, IEnumerable<KeyValuePair<string, int>>
|
||||
{
|
||||
[ViewVariables]
|
||||
protected virtual Dictionary<string, int> Storage { get; set; } = new();
|
||||
|
||||
public int this[string id]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!Storage.ContainsKey(id))
|
||||
return 0;
|
||||
return Storage[id];
|
||||
}
|
||||
}
|
||||
|
||||
public int this[MaterialPrototype material]
|
||||
{
|
||||
get
|
||||
{
|
||||
var id = material.ID;
|
||||
if (!Storage.ContainsKey(id))
|
||||
return 0;
|
||||
return Storage[id];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The total volume of material stored currently.
|
||||
/// </summary>
|
||||
[ViewVariables] public int CurrentAmount
|
||||
{
|
||||
get
|
||||
{
|
||||
var value = 0;
|
||||
|
||||
foreach (var amount in Storage.Values)
|
||||
{
|
||||
value += amount;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<string, int>> GetEnumerator()
|
||||
{
|
||||
return Storage.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
[NetSerializable, Serializable]
|
||||
public sealed class MaterialStorageState : ComponentState
|
||||
{
|
||||
public readonly Dictionary<string, int> Storage;
|
||||
public MaterialStorageState(Dictionary<string, int> storage)
|
||||
{
|
||||
Storage = storage;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
using Content.Shared.Research.Prototypes;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||
|
||||
namespace Content.Shared.Lathe
|
||||
{
|
||||
[ComponentReference(typeof(SharedLatheDatabaseComponent))]
|
||||
[NetworkedComponent()]
|
||||
public abstract class SharedProtolatheDatabaseComponent : SharedLatheDatabaseComponent, ISerializationHooks
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
[DataField("protolatherecipes", customTypeSerializer:typeof(PrototypeIdListSerializer<LatheRecipePrototype>))]
|
||||
private List<string> _recipeIds = new();
|
||||
|
||||
/// <summary>
|
||||
/// A full list of recipes this protolathe can print.
|
||||
/// </summary>
|
||||
public IEnumerable<LatheRecipePrototype> ProtolatheRecipes
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var id in _recipeIds)
|
||||
{
|
||||
yield return _prototypeManager.Index<LatheRecipePrototype>(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[NetSerializable, Serializable]
|
||||
public sealed class ProtolatheDatabaseState : ComponentState
|
||||
{
|
||||
public readonly List<string> Recipes;
|
||||
public ProtolatheDatabaseState(List<string> recipes)
|
||||
{
|
||||
Recipes = recipes;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user