Skip to content

Commit

Permalink
Na mleko mam alergię
Browse files Browse the repository at this point in the history
  • Loading branch information
RedFoxIV committed Dec 20, 2024
1 parent f7a43e2 commit 6b873bc
Show file tree
Hide file tree
Showing 7 changed files with 220 additions and 68 deletions.
48 changes: 48 additions & 0 deletions Content.Server/_White/Plumbing/PlumbingSystem.Tank.cs
Original file line number Diff line number Diff line change
@@ -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<PlumbingSimpleDemandComponent>();
public void InitializeTank()
{

SubscribeLocalEvent<PlumbingInternalTankComponent, PlumbingGetTank>(OnGetTankInternal);
SubscribeLocalEvent<PlumbingItemSlotTankComponent, PlumbingGetTank>(OnGetTankItemSlot);

//SubscribeLocalEvent<PlumbingSimpleInputComponent, PlumbingRequestOutputEvent>(OnFactoryRequest);
//simpleDemandQuery = GetEntityQuery<PlumbingSimpleDemandComponent>();
}

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;
}

}
129 changes: 83 additions & 46 deletions Content.Server/_White/Plumbing/PlumbingSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -14,102 +17,130 @@

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<PlumbingSimpleDemandComponent>();
public override void Initialize()
{
SubscribeLocalEvent<PlumbingFactoryComponent, PlumbingPollOutputsEvent>(OnFactoryPoll);
SubscribeLocalEvent < PlumbingFactoryComponent, PlumbingRequestOutputEvent>(OnFactoryRequest);

SubscribeLocalEvent<PlumbingSimpleInputComponent, PlumbingPollAvailableInputsEvent>(OnInputsPoll);
InitializeTank();
//SubscribeLocalEvent<PlumbingSimpleInputComponent, PlumbingRequestOutputEvent>(OnFactoryRequest);
//simpleDemandQuery = GetEntityQuery<PlumbingSimpleDemandComponent>();
}

public override void Update(float frameTime)
{
if((_timing.CurTick.Value % _timing.TickRate) == 0)
{
var query = EntityQueryEnumerator<PlumbingSimpleDemandComponent>();
var query = EntityQueryEnumerator<PlumbingSimpleOutputComponent>();
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<NodeContainerComponent>(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<ContainerManagerComponent>(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<SolutionComponent> 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<string>? 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<EntityUid> Valid = new();
public PlumbingPollOutputsEvent(string? filter = null)
public Solution Solution { get; private set; }
public List<(Entity<SolutionComponent>, List<string>?)> 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)
Expand All @@ -118,3 +149,9 @@ public PlumbingRequestOutputEvent(FixedPoint2 quantity, Solution target)
Solution = target;
}
}

[ByRefEvent]
public class PlumbingGetTank : EntityEventArgs
{
public Entity<SolutionComponent>? solutionEnt;
}
33 changes: 31 additions & 2 deletions Content.Shared/_White/Plumbing/PlumbingFactoryComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<string> 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 = "";
}


Empty file.
Loading

0 comments on commit 6b873bc

Please sign in to comment.