diff --git a/Content.Server/Atmos/Piping/Unary/Components/GasThermoMachineComponent.cs b/Content.Server/Atmos/Piping/Unary/Components/GasThermoMachineComponent.cs index 0a4ba4a322..b165c8785e 100644 --- a/Content.Server/Atmos/Piping/Unary/Components/GasThermoMachineComponent.cs +++ b/Content.Server/Atmos/Piping/Unary/Components/GasThermoMachineComponent.cs @@ -1,5 +1,7 @@ using Content.Shared.Atmos; using Content.Shared.Atmos.Piping.Unary.Components; +using Content.Shared.Construction.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Server.Atmos.Piping.Unary.Components { @@ -55,7 +57,7 @@ namespace Content.Server.Atmos.Piping.Unary.Components /// [DataField("baseMinTemperature")] [ViewVariables(VVAccess.ReadWrite)] - public float BaseMinTemperature = 96.625f; // Selected so that tier-1 parts can reach 73.15k + public float BaseMinTemperature = 96.625f; // Selected so that tier-1 parts can reach 73.15k /// /// Maximum temperature the device can reach with a 0 total laser quality. Usually the quality will be at @@ -78,5 +80,17 @@ namespace Content.Server.Atmos.Piping.Unary.Components [DataField("maxTemperatureDelta")] [ViewVariables(VVAccess.ReadWrite)] public float MaxTemperatureDelta = 300; + + /// + /// The machine part that affects the heat capacity. + /// + [DataField("machinePartHeatCapacity", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string MachinePartHeatCapacity = "MatterBin"; + + /// + /// The machine part that affects the temperature range. + /// + [DataField("machinePartTemperature", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string MachinePartTemperature = "Laser"; } } diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs index 23bdc776df..aec4376641 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs @@ -15,6 +15,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems [UsedImplicitly] public sealed class GasThermoMachineSystem : EntitySystem { + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!; @@ -33,14 +34,12 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems private void OnThermoMachineUpdated(EntityUid uid, GasThermoMachineComponent thermoMachine, AtmosDeviceUpdateEvent args) { - var appearance = EntityManager.GetComponentOrNull(thermoMachine.Owner); - if (!thermoMachine.Enabled || !EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) || !nodeContainer.TryGetNode(thermoMachine.InletName, out PipeNode? inlet)) { DirtyUI(uid, thermoMachine); - appearance?.SetData(ThermoMachineVisuals.Enabled, false); + _appearance.SetData(uid, ThermoMachineVisuals.Enabled, false); return; } @@ -49,7 +48,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems if (!MathHelper.CloseTo(combinedHeatCapacity, 0, 0.001f)) { - appearance?.SetData(ThermoMachineVisuals.Enabled, true); + _appearance.SetData(uid, ThermoMachineVisuals.Enabled, true); var combinedEnergy = thermoMachine.HeatCapacity * thermoMachine.TargetTemperature + airHeatCapacity * inlet.Air.Temperature; inlet.Air.Temperature = combinedEnergy / combinedHeatCapacity; } @@ -59,38 +58,15 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems private void OnThermoMachineLeaveAtmosphere(EntityUid uid, GasThermoMachineComponent component, AtmosDeviceDisabledEvent args) { - if (EntityManager.TryGetComponent(uid, out AppearanceComponent? appearance)) - { - appearance.SetData(ThermoMachineVisuals.Enabled, false); - } + _appearance.SetData(uid, ThermoMachineVisuals.Enabled, false); DirtyUI(uid, component); } private void OnGasThermoRefreshParts(EntityUid uid, GasThermoMachineComponent component, RefreshPartsEvent args) { - // Here we evaluate the average quality of relevant machine parts. - var nLasers = 0; - var nBins= 0; - var matterBinRating = 0; - var laserRating = 0; - - foreach (var part in args.Parts) - { - switch (part.PartType) - { - case MachinePart.MatterBin: - nBins += 1; - matterBinRating += part.Rating; - break; - case MachinePart.Laser: - nLasers += 1; - laserRating += part.Rating; - break; - } - } - laserRating /= nLasers; - matterBinRating /= nBins; + var matterBinRating = args.PartRatings[component.MachinePartHeatCapacity]; + var laserRating = args.PartRatings[component.MachinePartTemperature]; component.HeatCapacity = 5000 * MathF.Pow(matterBinRating, 2); diff --git a/Content.Server/Construction/Components/MachineBoardComponent.cs b/Content.Server/Construction/Components/MachineBoardComponent.cs index efbf16b470..5f8ff53fb4 100644 --- a/Content.Server/Construction/Components/MachineBoardComponent.cs +++ b/Content.Server/Construction/Components/MachineBoardComponent.cs @@ -1,5 +1,7 @@ +using Content.Shared.Construction.Prototypes; using Content.Shared.Stacks; using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; namespace Content.Server.Construction.Components { @@ -9,8 +11,8 @@ namespace Content.Server.Construction.Components [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [ViewVariables] - [DataField("requirements")] - public readonly Dictionary Requirements = new(); + [DataField("requirements", customTypeSerializer: typeof(PrototypeIdDictionarySerializer))] + public readonly Dictionary Requirements = new(); [ViewVariables] [DataField("materialRequirements")] diff --git a/Content.Server/Construction/Components/MachineFrameComponent.cs b/Content.Server/Construction/Components/MachineFrameComponent.cs index 774e06436e..18121c260a 100644 --- a/Content.Server/Construction/Components/MachineFrameComponent.cs +++ b/Content.Server/Construction/Components/MachineFrameComponent.cs @@ -1,9 +1,11 @@ using System.Threading.Tasks; using Content.Server.Stack; using Content.Shared.Construction; +using Content.Shared.Construction.Prototypes; using Content.Shared.Interaction; using Content.Shared.Tag; using Robust.Shared.Containers; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; namespace Content.Server.Construction.Components { @@ -16,8 +18,8 @@ namespace Content.Server.Construction.Components [ViewVariables] public bool HasBoard => BoardContainer?.ContainedEntities.Count != 0; - [ViewVariables] - public readonly Dictionary Progress = new(); + [DataField("progress", customTypeSerializer: typeof(PrototypeIdDictionarySerializer)), ViewVariables] + public readonly Dictionary Progress = new(); [ViewVariables] public readonly Dictionary MaterialProgress = new(); @@ -28,8 +30,8 @@ namespace Content.Server.Construction.Components [ViewVariables] public readonly Dictionary TagProgress = new(); - [ViewVariables] - public Dictionary Requirements = new(); + [DataField("requirements", customTypeSerializer: typeof(PrototypeIdDictionarySerializer)),ViewVariables] + public Dictionary Requirements = new(); [ViewVariables] public Dictionary MaterialRequirements = new(); diff --git a/Content.Server/Construction/Components/MachinePartComponent.cs b/Content.Server/Construction/Components/MachinePartComponent.cs index dcfed6913c..3d46074403 100644 --- a/Content.Server/Construction/Components/MachinePartComponent.cs +++ b/Content.Server/Construction/Components/MachinePartComponent.cs @@ -1,25 +1,14 @@ +using Content.Shared.Construction.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + namespace Content.Server.Construction.Components { [RegisterComponent] public sealed class MachinePartComponent : Component { - // I'm so sorry for hard-coding this. But trust me, it should make things less painful. - public static IReadOnlyDictionary Prototypes { get; } = new Dictionary() - { - {MachinePart.Capacitor, "CapacitorStockPart"}, - {MachinePart.ScanningModule, "ScanningModuleStockPart"}, - {MachinePart.Manipulator, "MicroManipulatorStockPart"}, - {MachinePart.Laser, "MicroLaserStockPart"}, - {MachinePart.MatterBin, "MatterBinStockPart"}, - {MachinePart.Ansible, "AnsibleSubspaceStockPart"}, - {MachinePart.Filter, "FilterSubspaceStockPart"}, - {MachinePart.Amplifier, "AmplifierSubspaceStockPart"}, - {MachinePart.Treatment, "TreatmentSubspaceStockPart"}, - {MachinePart.Analyzer, "AnalyzerSubspaceStockPart"}, - {MachinePart.Crystal, "CrystalSubspaceStockPart"}, - {MachinePart.Transmitter, "TransmitterSubspaceStockPart"} - }; - [ViewVariables] [DataField("part")] public MachinePart PartType { get; private set; } = MachinePart.Capacitor; + [ViewVariables] + [DataField("part", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] + public string PartType { get; private set; } = default!; [ViewVariables(VVAccess.ReadWrite)] [DataField("rating")] diff --git a/Content.Server/Construction/ConstructionSystem.Machine.cs b/Content.Server/Construction/ConstructionSystem.Machine.cs index bcbc919c0f..8f8cb641da 100644 --- a/Content.Server/Construction/ConstructionSystem.Machine.cs +++ b/Content.Server/Construction/ConstructionSystem.Machine.cs @@ -1,4 +1,6 @@ +using System.Linq; using Content.Server.Construction.Components; +using Content.Shared.Construction.Prototypes; using Robust.Shared.Containers; namespace Content.Server.Construction; @@ -36,11 +38,32 @@ public sealed partial class ConstructionSystem return parts; } + public Dictionary GetPartsRatings(List parts) + { + var output = new Dictionary(); + foreach (var type in _prototypeManager.EnumeratePrototypes()) + { + var amount = 0; + var sumRating = 0; + foreach (var part in parts.Where(part => part.PartType == type.ID)) + { + amount++; + sumRating += part.Rating; + } + var rating = amount != 0 ? sumRating / amount : 0; + output.Add(type.ID, rating); + } + + return output; + } + public void RefreshParts(MachineComponent component) { - EntityManager.EventBus.RaiseLocalEvent(component.Owner, new RefreshPartsEvent() + var parts = GetAllParts(component); + EntityManager.EventBus.RaiseLocalEvent(component.Owner, new RefreshPartsEvent { - Parts = GetAllParts(component), + Parts = parts, + PartRatings = GetPartsRatings(parts), }, true); } @@ -69,14 +92,16 @@ public sealed partial class ConstructionSystem throw new Exception($"Entity with prototype {component.BoardPrototype} doesn't have a {nameof(MachineBoardComponent)}!"); } + var xform = Transform(component.Owner); foreach (var (part, amount) in machineBoard.Requirements) { + var partProto = _prototypeManager.Index(part); for (var i = 0; i < amount; i++) { - var p = EntityManager.SpawnEntity(MachinePartComponent.Prototypes[part], Transform(component.Owner).Coordinates); + var p = EntityManager.SpawnEntity(partProto.StockPartPrototype, xform.Coordinates); if (!partContainer.Insert(p)) - throw new Exception($"Couldn't insert machine part of type {part} to machine with prototype {MetaData(component.Owner).EntityPrototype?.ID ?? "N/A"}!"); + throw new Exception($"Couldn't insert machine part of type {part} to machine with prototype {partProto.StockPartPrototype ?? "N/A"}!"); } } @@ -115,4 +140,6 @@ public sealed partial class ConstructionSystem public sealed class RefreshPartsEvent : EntityEventArgs { public IReadOnlyList Parts = new List(); + + public Dictionary PartRatings = new Dictionary(); } diff --git a/Content.Server/Construction/MachineFrameSystem.cs b/Content.Server/Construction/MachineFrameSystem.cs index 5aa6175e0e..5e3a9ff09e 100644 --- a/Content.Server/Construction/MachineFrameSystem.cs +++ b/Content.Server/Construction/MachineFrameSystem.cs @@ -183,7 +183,7 @@ public sealed class MachineFrameSystem : EntitySystem public void ResetProgressAndRequirements(MachineFrameComponent component, MachineBoardComponent machineBoard) { - component.Requirements = new Dictionary(machineBoard.Requirements); + component.Requirements = new Dictionary(machineBoard.Requirements); component.MaterialRequirements = new Dictionary(machineBoard.MaterialIdRequirements); component.ComponentRequirements = new Dictionary(machineBoard.ComponentRequirements); component.TagRequirements = new Dictionary(machineBoard.TagRequirements); diff --git a/Content.Server/Construction/MachinePart.cs b/Content.Server/Construction/MachinePart.cs deleted file mode 100644 index 1a14701e4c..0000000000 --- a/Content.Server/Construction/MachinePart.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Content.Server.Construction -{ - public enum MachinePart : byte - { - Capacitor, - ScanningModule, - Manipulator, - Laser, - MatterBin, - - // Subspace parts. - Ansible, - Filter, - Amplifier, - Treatment, - Analyzer, - Crystal, - Transmitter, - } -} diff --git a/Content.Shared/Construction/Prototypes/MachinePartPrototype.cs b/Content.Shared/Construction/Prototypes/MachinePartPrototype.cs new file mode 100644 index 0000000000..5a209c9ef2 --- /dev/null +++ b/Content.Shared/Construction/Prototypes/MachinePartPrototype.cs @@ -0,0 +1,22 @@ +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Construction.Prototypes; + +/// +/// This is a prototype for categorizing +/// different types of machine parts. +/// +[Prototype("machinePart")] +public sealed class MachinePartPrototype : IPrototype +{ + /// + [IdDataField] + public string ID { get; } = default!; + + /// + /// A stock part entity based on the machine part. + /// + [DataField("stockPartPrototype", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string? StockPartPrototype { get; } +} diff --git a/Resources/Prototypes/MachineParts/machine_parts.yml b/Resources/Prototypes/MachineParts/machine_parts.yml new file mode 100644 index 0000000000..499a010916 --- /dev/null +++ b/Resources/Prototypes/MachineParts/machine_parts.yml @@ -0,0 +1,47 @@ +- type: machinePart + id: Capacitor + stockPartPrototype: CapacitorStockPart + +- type: machinePart + id: ScanningModule + stockPartPrototype: ScanningModuleStockPart + +- type: machinePart + id: Manipulator + stockPartPrototype: MicroManipulatorStockPart + +- type: machinePart + id: Laser + stockPartPrototype: MicroLaserStockPart + +- type: machinePart + id: MatterBin + stockPartPrototype: MatterBinStockPart + +- type: machinePart + id: Ansible + stockPartPrototype: AnsibleSubspaceStockPart + +- type: machinePart + id: Filter + stockPartPrototype: FilterSubspaceStockPart + +- type: machinePart + id: Amplifier + stockPartPrototype: AmplifierSubspaceStockPart + +- type: machinePart + id: Treatment + stockPartPrototype: TreatmentSubspaceStockPart + +- type: machinePart + id: Analyzer + stockPartPrototype: AnalyzerSubspaceStockPart + +- type: machinePart + id: Crystal + stockPartPrototype: CrystalSubspaceStockPart + +- type: machinePart + id: Transmitter + stockPartPrototype: TransmitterSubspaceStockPart \ No newline at end of file