From 6b873bcd2e9e6e72f419335dfa193a0be1650d55 Mon Sep 17 00:00:00 2001 From: RedFoxIV <38788538+RedFoxIV@users.noreply.github.com> Date: Fri, 20 Dec 2024 07:28:44 +0300 Subject: [PATCH] =?UTF-8?q?Na=20mleko=20mam=20alergi=C4=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../_White/Plumbing/PlumbingSystem.Tank.cs | 48 +++++++ .../_White/Plumbing/PlumbingSystem.cs | 129 +++++++++++------- .../Plumbing/PlumbingFactoryComponent.cs | 33 ++++- .../_White/Plumbing/PlumbingSystem.cs | 0 .../Machines/Plumbing/base_plumbing.yml | 64 ++++++--- .../Machines/Plumbing/input.rsi/base.png | Bin 0 -> 383 bytes .../Machines/Plumbing/input.rsi/meta.json | 14 ++ 7 files changed, 220 insertions(+), 68 deletions(-) create mode 100644 Content.Server/_White/Plumbing/PlumbingSystem.Tank.cs create mode 100644 Content.Shared/_White/Plumbing/PlumbingSystem.cs create mode 100644 Resources/Textures/_White/Structures/Machines/Plumbing/input.rsi/base.png create mode 100644 Resources/Textures/_White/Structures/Machines/Plumbing/input.rsi/meta.json diff --git a/Content.Server/_White/Plumbing/PlumbingSystem.Tank.cs b/Content.Server/_White/Plumbing/PlumbingSystem.Tank.cs new file mode 100644 index 0000000000..9c8e5fc346 --- /dev/null +++ b/Content.Server/_White/Plumbing/PlumbingSystem.Tank.cs @@ -0,0 +1,48 @@ +using Content.Server.Chemistry.Containers.EntitySystems; +using Content.Server.NodeContainer; +using Content.Shared._White.Plumbing; +using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.Components.SolutionManager; +using Content.Shared.Chemistry.EntitySystems; +using Content.Shared.Chemistry.Reagent; +using Content.Shared.Containers.ItemSlots; +using Content.Shared.FixedPoint; +using Robust.Shared.Containers; +using Robust.Shared.Timing; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Content.Server._White.Plumbing; + +public sealed partial class PlumbingSystem : EntitySystem +{ + + + //var simpleDemandQuery = EntityQueryEnumerator(); + public void InitializeTank() + { + + SubscribeLocalEvent(OnGetTankInternal); + SubscribeLocalEvent(OnGetTankItemSlot); + + //SubscribeLocalEvent(OnFactoryRequest); + //simpleDemandQuery = GetEntityQuery(); + } + + private void OnGetTankInternal(EntityUid uid, PlumbingInternalTankComponent comp, ref PlumbingGetTank args) + { + if (_solution.TryGetSolution(uid, comp.Solution, out var ent)) + args.solutionEnt = ent; + } + private void OnGetTankItemSlot(EntityUid uid, PlumbingItemSlotTankComponent comp, ref PlumbingGetTank args) + { + if (_itemSlot.TryGetSlot(uid, comp.Slot, out var slot) && + slot.HasItem && + _solution.TryGetRefillableSolution(slot.Item!.Value, out var ent, out var _)) // if you can easily refill a container, you should be able to empty it just as easily + args.solutionEnt = ent; + } + +} diff --git a/Content.Server/_White/Plumbing/PlumbingSystem.cs b/Content.Server/_White/Plumbing/PlumbingSystem.cs index bea723e20b..1b0a2ad7ed 100644 --- a/Content.Server/_White/Plumbing/PlumbingSystem.cs +++ b/Content.Server/_White/Plumbing/PlumbingSystem.cs @@ -3,6 +3,9 @@ using Content.Shared._White.Plumbing; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; +using Content.Shared.Chemistry.EntitySystems; +using Content.Shared.Chemistry.Reagent; +using Content.Shared.Containers.ItemSlots; using Content.Shared.FixedPoint; using Robust.Shared.Containers; using Robust.Shared.Timing; @@ -14,18 +17,23 @@ namespace Content.Server._White.Plumbing; -public sealed class PlumbingSystem : EntitySystem +public sealed partial class PlumbingSystem : EntitySystem { - [Dependency] private readonly SolutionContainerSystem _solution = default!; + [Dependency] private readonly SharedSolutionContainerSystem _solution = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly ItemSlotsSystem _itemSlot = default!; + [Dependency] private readonly IGameTiming _timing = default!; //var simpleDemandQuery = EntityQueryEnumerator(); public override void Initialize() { - SubscribeLocalEvent(OnFactoryPoll); - SubscribeLocalEvent < PlumbingFactoryComponent, PlumbingRequestOutputEvent>(OnFactoryRequest); + + SubscribeLocalEvent(OnInputsPoll); + InitializeTank(); + //SubscribeLocalEvent(OnFactoryRequest); //simpleDemandQuery = GetEntityQuery(); } @@ -33,83 +41,106 @@ public override void Update(float frameTime) { if((_timing.CurTick.Value % _timing.TickRate) == 0) { - var query = EntityQueryEnumerator(); + var query = EntityQueryEnumerator(); while(query.MoveNext(out EntityUid uid, out var comp)) { - SimpleDemandTick(uid, comp); + ProcessOutputNode(uid, comp); } } } - - // todo: this is actually stupid - // case in point: 3 tanks connected to one factory will all pull the same perTick of - // chemicals instead of everyone getting a third of the output. - // move polls over to output nodes, so that they check for available inputs and not the other way around - // it just makes more sense if i do not do the whole song and dance ss13 did in order to avoid shit like 10.0000001 water - // i can either do a "faithful recreation", or do something that resembles the original in basic functionality. - // it's easier to do the latter, especially if we're leaning on the whole "different from ss13" idea. - private void SimpleDemandTick(EntityUid uid, PlumbingSimpleDemandComponent comp) + // todo: sync the nodes orientation with the client. Only need to send their direction over. + // A quick&dirty method could be catching MoveEvent and, if the owner rotated, send appearance data to the client. + // Will need PlumbingAppearanceComponent or something like that. + // I think it's mostly ready besides that. Only needs a reaction chamber and/or something to act as a filter. + // Also some minor touchups: proper pipe visuals (copy cablevisualisercomponent for that) and allow the pipes + // to be laid over plating. + // from the gameplay side: plumbing without infinite chemicals is as dull as physically possible. + // Add a factory that supports producing only 1u of a selected chem? It's very low, but it still allows + // for autonomous production of whatever you want. You can, of course, stack a bunch of them, but that + // will take a lot of space. On that note: prevent pipes from being laid under plumbing machinery, and vice versa. + // Current implementation relies too much on PlumbingSimple(Input/Output)Components. If i try to make an + // infinite factory, i'll have to make an PlumbingInfiniteTankComponent that creates a new 1u solution every time + // it catches the event. I dunno, it feels very meh. + // Don't know how to properly fix: processing reagent moving clientside so i don't get shitty prediction + // when a beaker i took out of an input port has 10u removed just a second later. + // This requires either client knowledge of nodes to get the connection data, + // or for the server to keep some PlumbingConnectionsComponent up-to-date every time the node network changes. + // The former will not work as nodes are in Content.Server. + // It is 7:25 AM. Fucking kill me. + private void ProcessOutputNode(EntityUid uid, PlumbingSimpleOutputComponent comp) { if (!TryComp(uid, out var nodecont)) return; - - if (!nodecont.Nodes.TryGetValue("input", out var inputNode)) + + if (!nodecont.Nodes.TryGetValue("output", out var outputNode) || outputNode.NodeGroup is null) return; - if (!TryComp(uid, out var contman) || ! _solution.TryGetSolution(uid, comp.Solution, out var _, out var solution)) + // get the tank we will drain reagents from + // can be either an internal one or in an itemslot + // or whatever the fuck is passed into the event object + var tankev = new PlumbingGetTank(); + RaiseLocalEvent(uid, ref tankev); + if (!tankev.solutionEnt.HasValue) return; - var ev = new PlumbingPollOutputsEvent(); - foreach(var output in ((PlumbingNodeGroup) inputNode.NodeGroup!).OutputNodes) - { - RaiseLocalEvent(output.Owner, ref ev); - } - var reqev = new PlumbingRequestOutputEvent(comp.RequestPerTick / ev.Valid.Count, solution); - foreach (var valid in ev.Valid) + Entity sourceEnt = tankev.solutionEnt.Value; + var senderSolution = sourceEnt.Comp.Solution; + + // check what nodes in the network are ready to receive our shit + var ev = new PlumbingPollAvailableInputsEvent(senderSolution); + foreach (var input in ((PlumbingNodeGroup) outputNode.NodeGroup).InputNodes) { - RaiseLocalEvent(valid, reqev); + RaiseLocalEvent(input.Owner, ref ev); } + // the amount of reagents each of the input nodes in ev.Valid list are gonna get + float fraction = Math.Min(comp.OutputPerSecond.Float(), senderSolution.Volume.Float()) / ev.Valid.Count; - // trycomp nodecontainer - // if present, try get input node - // if present, get nodegroup - // create an instance of an event - // foreach node in nodegroup - // raise event by ref at node - // - // implement tg logic for sucking in shit - // equal parts from all providers; round robin per provider - // or - // fuck it + foreach ((var receiverEnt, List? receiverFilters) in ev.Valid) + { + (var receiverUid, var receiverSolutionComp) = receiverEnt; + Solution receiverSolution = receiverSolutionComp.Solution; + var transferAmount = Math.Min(fraction, receiverSolution.AvailableVolume.Float()); // don't try to transfer more than we can fit + + Solution transfer; + if (receiverFilters is null) + transfer = senderSolution.SplitSolution(FixedPoint2.New(transferAmount)); + else + transfer = senderSolution.SplitSolutionWithOnly(FixedPoint2.New(transferAmount), receiverFilters.ToArray() /*ffs*/ ); + + receiverSolution.AddSolution(transfer, null); + _solution.UpdateChemicals(receiverEnt); + _solution.UpdateChemicals(sourceEnt); + } } - private void OnFactoryPoll(EntityUid uid, PlumbingFactoryComponent comp, ref PlumbingPollOutputsEvent args) + private void OnInputsPoll(EntityUid uid, PlumbingSimpleInputComponent comp, ref PlumbingPollAvailableInputsEvent args) { - args.Valid.Add(uid); + if (_solution.TryGetSolution(uid, comp.Solution, out var ent) && ent.Value.Comp.Solution.AvailableVolume > 0) + args.Valid.Add((ent.Value, comp.UseFilters ? comp.ReagentFilters : null)); } private void OnFactoryRequest(EntityUid uid, PlumbingFactoryComponent comp, PlumbingRequestOutputEvent args) { args.Solution.AddReagent(comp.reagentprototype, comp.perTick); } - } [ByRefEvent] -public class PlumbingPollOutputsEvent : EntityEventArgs +public class PlumbingPollAvailableInputsEvent : EntityEventArgs { - public string? ReagentFilter { get; private set; } - public List Valid = new(); - public PlumbingPollOutputsEvent(string? filter = null) + public Solution Solution { get; private set; } + public List<(Entity, List?)> Valid = new(); + public PlumbingPollAvailableInputsEvent(Solution solution) { - ReagentFilter = filter; + Solution = solution; } } -public class PlumbingRequestOutputEvent : EntityEventArgs { +public class PlumbingRequestOutputEvent : EntityEventArgs +{ public FixedPoint2 Quantity; public Solution Solution; public PlumbingRequestOutputEvent(FixedPoint2 quantity, Solution target) @@ -118,3 +149,9 @@ public PlumbingRequestOutputEvent(FixedPoint2 quantity, Solution target) Solution = target; } } + +[ByRefEvent] +public class PlumbingGetTank : EntityEventArgs +{ + public Entity? solutionEnt; +} diff --git a/Content.Shared/_White/Plumbing/PlumbingFactoryComponent.cs b/Content.Shared/_White/Plumbing/PlumbingFactoryComponent.cs index 8c26eda563..fd9a9e1b77 100644 --- a/Content.Shared/_White/Plumbing/PlumbingFactoryComponent.cs +++ b/Content.Shared/_White/Plumbing/PlumbingFactoryComponent.cs @@ -27,13 +27,42 @@ public partial class PlumbingStorageTankComponent : Component } [RegisterComponent] -public partial class PlumbingSimpleDemandComponent : Component +public partial class PlumbingSimpleInputComponent : Component +{ + [DataField] + public bool UseFilters = false; + [DataField] + public List ReagentFilters = new(); + [DataField] + public string Solution = "plumbing_storage_tank"; + //[DataField] + //public FixedPoint2 InputPerSecond = 10; +} + +[RegisterComponent] +public partial class PlumbingSimpleOutputComponent : Component { [DataField] public string Solution = "plumbing_storage_tank"; [DataField] - public FixedPoint2 RequestPerTick = 10; + public FixedPoint2 OutputPerSecond = 10; +} + + +[RegisterComponent] +public partial class PlumbingInternalTankComponent : Component +{ + [DataField] + public string Solution = "plumbing_storage_tank"; +} + +[RegisterComponent] +public partial class PlumbingItemSlotTankComponent : Component +{ + [DataField(required: true)] + public string Slot = ""; } + diff --git a/Content.Shared/_White/Plumbing/PlumbingSystem.cs b/Content.Shared/_White/Plumbing/PlumbingSystem.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Resources/Prototypes/_White/Entities/Structures/Machines/Plumbing/base_plumbing.yml b/Resources/Prototypes/_White/Entities/Structures/Machines/Plumbing/base_plumbing.yml index 2ea906d2cc..78541b44f8 100644 --- a/Resources/Prototypes/_White/Entities/Structures/Machines/Plumbing/base_plumbing.yml +++ b/Resources/Prototypes/_White/Entities/Structures/Machines/Plumbing/base_plumbing.yml @@ -38,10 +38,10 @@ blockingWireType: HighVoltage # todo copypaste CablePlacer to not interact with wires - type: Appearance - type: Extractable - grindableSolutionName: pipe + grindableSolutionName: grind - type: SolutionContainerManager solutions: - pipe: + grind: reagents: - ReagentId: Iron Quantity: 5 @@ -102,19 +102,25 @@ itemSize: 1 +- type: entity + id: BasePlumbing + parent: BaseMachinePowered + abstract: true + components: + - type: Rotatable + - type: Transform + noRot: true + - type: entity id: BasePlumbingOutput abstract: true - parent: BaseMachinePowered + parent: BasePlumbing name: chemical producer description: ass components: - - type: Transform - noRot: true - type: Sprite sprite: _White/Structures/Machines/Plumbing/factory.rsi state: base - - type: Rotatable - type: NodeContainer nodes: output: @@ -126,23 +132,19 @@ - type: entity id: BasePlumbingInputOutput abstract: true - parent: BaseMachinePowered + parent: BasePlumbing name: chemical producer description: ass components: - - type: Transform - noRot: true - type: Sprite sprite: _White/Structures/Machines/Plumbing/factory.rsi state: base - - type: Rotatable - - type: ExaminableSolution - solution: plumbing_storage_tank - - type: PlumbingSimpleDemand - - type: SolutionContainerManager - solutions: - plumbing_storage_tank: - maxVol: 100 + #- type: PlumbingSimpleInput + #- type: PlumbingSimpleOutput + #- type: SolutionContainerManager + # solutions: + # plumbing_storage_tank: + # maxVol: 100 - type: NodeContainer nodes: input: @@ -174,15 +176,37 @@ - type: Sprite sprite: _White/Structures/Machines/Plumbing/storagetank.rsi state: base - - type: SolutionContainerManager solutions: plumbing_storage_tank: maxVol: 400 - - type: PlumbingStorageTank - + - type: PlumbingInternalTank + solution: plumbing_storage_tank + - type: ExaminableSolution + solution: plumbing_storage_tank + - type: PlumbingSimpleInput + - type: PlumbingSimpleOutput +- type: entity + id: PlumbingInputPort + parent: BasePlumbingOutput + name: chemical input port + description: eats chemicals + components: + - type: Sprite + sprite: _White/Structures/Machines/Plumbing/input.rsi + state: base + - type: ItemSlots + slots: + plumbingInputPort: + ejectOnInteract: true + - type: PlumbingSimpleOutput + solution: plumbingInputPort + - type: PlumbingItemSlotTank + slot: plumbingInputPort + #- type: ExaminableSolution + # solution: plumbingInputPort #- type: NodeContainer #nodes: # inlet: diff --git a/Resources/Textures/_White/Structures/Machines/Plumbing/input.rsi/base.png b/Resources/Textures/_White/Structures/Machines/Plumbing/input.rsi/base.png new file mode 100644 index 0000000000000000000000000000000000000000..b1057bc9bce4bdfdc5d313fc4d918295dea506a3 GIT binary patch literal 383 zcmV-_0f7FAP)>&1502=j7Tt7=@sA%ATcqe7hvQ9Jwl}%p-b9{p&S7AS_(@g+Y>4Z z17J03{`fV}F!+-qD|&wK``M140ywp-PLd?80_?Tw{vQDLw@nNqFRO|tj~|^s0|+B8 zL+{MI2QTNjxHuVG*CHQ57