Material generators from Afterlight (#18387)
This commit is contained in:
@@ -27,4 +27,10 @@ public sealed class UpgradePowerSupplierComponent : Component
|
||||
/// </summary>
|
||||
[DataField("scaling", required: true), ViewVariables(VVAccess.ReadWrite)]
|
||||
public MachineUpgradeScalingType Scaling;
|
||||
|
||||
/// <summary>
|
||||
/// The current value that the power supply is being scaled by,
|
||||
/// </summary>
|
||||
[DataField("actualScalar"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public float ActualScalar = 1f;
|
||||
}
|
||||
|
||||
@@ -76,8 +76,12 @@ internal sealed class PowerMonitoringConsoleSystem : EntitySystem
|
||||
}
|
||||
foreach (PowerSupplierComponent pcc in netQ.Suppliers)
|
||||
{
|
||||
sources.Add(LoadOrSource(pcc, pcc.MaxSupply, false));
|
||||
totalSources += pcc.MaxSupply;
|
||||
var supply = pcc.Enabled
|
||||
? pcc.MaxSupply
|
||||
: 0f;
|
||||
|
||||
sources.Add(LoadOrSource(pcc, supply, false));
|
||||
totalSources += supply;
|
||||
}
|
||||
foreach (BatteryDischargerComponent pcc in netQ.Dischargers)
|
||||
{
|
||||
|
||||
@@ -43,7 +43,7 @@ public sealed class UpgradePowerSystem : EntitySystem
|
||||
load *= MathF.Pow(component.PowerDrawMultiplier, rating - 1);
|
||||
break;
|
||||
default:
|
||||
Logger.Error($"invalid power scaling type for {ToPrettyString(uid)}.");
|
||||
Log.Error($"invalid power scaling type for {ToPrettyString(uid)}.");
|
||||
load = 0;
|
||||
break;
|
||||
}
|
||||
@@ -82,19 +82,19 @@ public sealed class UpgradePowerSystem : EntitySystem
|
||||
supply *= MathF.Pow(component.PowerSupplyMultiplier, rating - 1);
|
||||
break;
|
||||
default:
|
||||
Logger.Error($"invalid power scaling type for {ToPrettyString(uid)}.");
|
||||
Log.Error($"invalid power scaling type for {ToPrettyString(uid)}.");
|
||||
supply = component.BaseSupplyRate;
|
||||
break;
|
||||
}
|
||||
|
||||
component.ActualScalar = supply / component.BaseSupplyRate;
|
||||
|
||||
if (TryComp<PowerSupplierComponent>(uid, out var powa))
|
||||
powa.MaxSupply = supply;
|
||||
}
|
||||
|
||||
private void OnSupplierUpgradeExamine(EntityUid uid, UpgradePowerSupplierComponent component, UpgradeExamineEvent args)
|
||||
{
|
||||
// UpgradePowerSupplierComponent.PowerSupplyMultiplier is not the actual multiplier, so we have to do this.
|
||||
if (TryComp<PowerSupplierComponent>(uid, out var powa))
|
||||
args.AddPercentageUpgrade("upgrade-power-supply", powa.MaxSupply / component.BaseSupplyRate);
|
||||
args.AddPercentageUpgrade("upgrade-power-supply", component.ActualScalar);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
|
||||
|
||||
namespace Content.Server.Power.Generator;
|
||||
|
||||
/// <summary>
|
||||
/// This is used for chemical fuel input into generators.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(GeneratorSystem))]
|
||||
public sealed class ChemicalFuelGeneratorAdapterComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The acceptable list of input entities.
|
||||
/// </summary>
|
||||
[DataField("whitelist")]
|
||||
public EntityWhitelist? Whitelist;
|
||||
|
||||
/// <summary>
|
||||
/// The conversion factor for different chems you can put in.
|
||||
/// </summary>
|
||||
[DataField("chemConversionFactors", required: true, customTypeSerializer:typeof(PrototypeIdDictionarySerializer<float, ReagentPrototype>))]
|
||||
public Dictionary<string, float> ChemConversionFactors = default!;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Content.Server.Power.Generator;
|
||||
|
||||
/// <summary>
|
||||
/// This is used for stuff that can directly be shoved into a generator.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(GeneratorSystem))]
|
||||
public sealed class ChemicalFuelGeneratorDirectSourceComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The solution to pull fuel material from.
|
||||
/// </summary>
|
||||
[DataField("solution", required: true), ViewVariables(VVAccess.ReadWrite)]
|
||||
public string Solution = default!;
|
||||
}
|
||||
47
Content.Server/Power/Generator/GasPowerReceiverComponent.cs
Normal file
47
Content.Server/Power/Generator/GasPowerReceiverComponent.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
|
||||
namespace Content.Server.Power.Generator;
|
||||
|
||||
/// <summary>
|
||||
/// This is used for providing gas power to machinery.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(GasPowerReceiverSystem))]
|
||||
public sealed class GasPowerReceiverComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Past this temperature we assume we're in reaction mass mode and not magic mode.
|
||||
/// </summary>
|
||||
[DataField("maxTemperature"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public float MaxTemperature = 1000.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The gas that fuels this generator
|
||||
/// </summary>
|
||||
[DataField("targetGas", required: true), ViewVariables(VVAccess.ReadWrite)]
|
||||
public Gas TargetGas;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of gas consumed for operation in magic mode.
|
||||
/// </summary>
|
||||
[DataField("molesConsumedSec"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public float MolesConsumedSec = 1.55975875833f / 4;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of kPA "consumed" for operation in pressure mode.
|
||||
/// </summary>
|
||||
[DataField("pressureConsumedSec"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public float PressureConsumedSec = 100f;
|
||||
|
||||
/// <summary>
|
||||
/// Whether the consumed gas should then be ejected directly into the atmosphere.
|
||||
/// </summary>
|
||||
[DataField("offVentGas"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool OffVentGas;
|
||||
|
||||
[DataField("lastProcess", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)]
|
||||
public TimeSpan LastProcess = TimeSpan.Zero;
|
||||
|
||||
[DataField("powered"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool Powered = true;
|
||||
}
|
||||
92
Content.Server/Power/Generator/GasPowerReceiverSystem.cs
Normal file
92
Content.Server/Power/Generator/GasPowerReceiverSystem.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using Content.Server.Atmos.EntitySystems;
|
||||
using Content.Server.Atmos.Piping.Components;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.NodeContainer.EntitySystems;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Shared.Atmos;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server.Power.Generator;
|
||||
|
||||
/// <summary>
|
||||
/// This handles gas power receivers, allowing devices to accept power in the form of a gas.
|
||||
/// </summary>
|
||||
public sealed class GasPowerReceiverSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
|
||||
[Dependency] private readonly NodeContainerSystem _nodeContainer = default!;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<GasPowerReceiverComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<GasPowerReceiverComponent, AtmosDeviceUpdateEvent>(OnDeviceUpdated);
|
||||
}
|
||||
|
||||
private void OnMapInit(EntityUid uid, GasPowerReceiverComponent component, MapInitEvent args)
|
||||
{
|
||||
component.LastProcess = _gameTiming.CurTime;
|
||||
}
|
||||
|
||||
private void OnDeviceUpdated(EntityUid uid, GasPowerReceiverComponent component, AtmosDeviceUpdateEvent args)
|
||||
{
|
||||
var timeDelta = (float)(_gameTiming.CurTime - component.LastProcess).TotalSeconds;
|
||||
component.LastProcess = _gameTiming.CurTime;
|
||||
|
||||
if (!HasComp<AtmosDeviceComponent>(uid)
|
||||
|| !TryComp<NodeContainerComponent>(uid, out var nodeContainer)
|
||||
|| !_nodeContainer.TryGetNode<PipeNode>(nodeContainer, "pipe", out var pipe))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// if we're below the max temperature, then we are simply consuming our target gas
|
||||
if (pipe.Air.Temperature <= component.MaxTemperature)
|
||||
{
|
||||
// we have enough gas, so we consume it and are powered
|
||||
if (pipe.Air.Moles[(int) component.TargetGas] > component.MolesConsumedSec * timeDelta)
|
||||
{
|
||||
pipe.Air.AdjustMoles(component.TargetGas, -component.MolesConsumedSec * timeDelta);
|
||||
SetPowered(uid, component, true);
|
||||
}
|
||||
else // we do not have enough gas, so we power off
|
||||
{
|
||||
SetPowered(uid, component, false);
|
||||
}
|
||||
}
|
||||
else // we are exceeding the max temp and are now operating in pressure mode
|
||||
{
|
||||
var pres = component.PressureConsumedSec * timeDelta;
|
||||
if (pipe.Air.Pressure >= pres)
|
||||
{
|
||||
// remove gas from the pipe
|
||||
var res = pipe.Air.Remove(pres * 100.0f / (Atmospherics.R * pipe.Air.Temperature));
|
||||
if (component.OffVentGas)
|
||||
{
|
||||
// eject the gas into the atmosphere
|
||||
var mix = _atmosphereSystem.GetContainingMixture(uid, false, true);
|
||||
if (mix is not null)
|
||||
_atmosphereSystem.Merge(res, mix);
|
||||
}
|
||||
|
||||
SetPowered(uid, component, true);
|
||||
}
|
||||
else // if we do not have high enough pressure to operate, power off
|
||||
{
|
||||
SetPowered(uid, component, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SetPowered(EntityUid uid, GasPowerReceiverComponent comp, bool state)
|
||||
{
|
||||
if (state != comp.Powered)
|
||||
{
|
||||
comp.Powered = state;
|
||||
var ev = new PowerChangedEvent(state, 0);
|
||||
RaiseLocalEvent(uid, ref ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
123
Content.Server/Power/Generator/GeneratorSystem.cs
Normal file
123
Content.Server/Power/Generator/GeneratorSystem.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
using Content.Server.Chemistry.Components.SolutionManager;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Materials;
|
||||
using Content.Shared.Power.Generator;
|
||||
using Content.Shared.Stacks;
|
||||
using Robust.Server.GameObjects;
|
||||
|
||||
namespace Content.Server.Power.Generator;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public sealed class GeneratorSystem : SharedGeneratorSystem
|
||||
{
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
[Dependency] private readonly SharedStackSystem _stack = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
|
||||
|
||||
|
||||
private EntityQuery<UpgradePowerSupplierComponent> _upgradeQuery;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
_upgradeQuery = GetEntityQuery<UpgradePowerSupplierComponent>();
|
||||
|
||||
SubscribeLocalEvent<SolidFuelGeneratorAdapterComponent, InteractUsingEvent>(OnSolidFuelAdapterInteractUsing);
|
||||
SubscribeLocalEvent<ChemicalFuelGeneratorAdapterComponent, InteractUsingEvent>(OnChemicalFuelAdapterInteractUsing);
|
||||
SubscribeLocalEvent<FuelGeneratorComponent, SetTargetPowerMessage>(OnTargetPowerSet);
|
||||
}
|
||||
|
||||
private void OnChemicalFuelAdapterInteractUsing(EntityUid uid, ChemicalFuelGeneratorAdapterComponent component, InteractUsingEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (!TryComp<SolutionContainerManagerComponent>(args.Used, out var solutions) ||
|
||||
!TryComp<FuelGeneratorComponent>(uid, out var generator))
|
||||
return;
|
||||
|
||||
if (!(component.Whitelist?.IsValid(args.Used) ?? true))
|
||||
return;
|
||||
|
||||
if (TryComp<ChemicalFuelGeneratorDirectSourceComponent>(args.Used, out var source))
|
||||
{
|
||||
if (!solutions.Solutions.ContainsKey(source.Solution))
|
||||
{
|
||||
Log.Error($"Couldn't get solution {source.Solution} on {ToPrettyString(args.Used)}");
|
||||
return;
|
||||
}
|
||||
|
||||
var solution = solutions.Solutions[source.Solution];
|
||||
generator.RemainingFuel += ReagentsToFuel(component, solution);
|
||||
solution.RemoveAllSolution();
|
||||
QueueDel(args.Used);
|
||||
}
|
||||
}
|
||||
|
||||
private float ReagentsToFuel(ChemicalFuelGeneratorAdapterComponent component, Solution solution)
|
||||
{
|
||||
var total = 0.0f;
|
||||
foreach (var reagent in solution.Contents)
|
||||
{
|
||||
if (!component.ChemConversionFactors.ContainsKey(reagent.ReagentId))
|
||||
continue;
|
||||
|
||||
total += reagent.Quantity.Float() * component.ChemConversionFactors[reagent.ReagentId];
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
private void OnTargetPowerSet(EntityUid uid, FuelGeneratorComponent component, SetTargetPowerMessage args)
|
||||
{
|
||||
component.TargetPower = Math.Clamp(args.TargetPower, 0, component.MaxTargetPower / 1000) * 1000;
|
||||
}
|
||||
|
||||
private void OnSolidFuelAdapterInteractUsing(EntityUid uid, SolidFuelGeneratorAdapterComponent component, InteractUsingEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (!TryComp<PhysicalCompositionComponent>(args.Used, out var mat) ||
|
||||
!HasComp<MaterialComponent>(args.Used) ||
|
||||
!TryComp<FuelGeneratorComponent>(uid, out var generator))
|
||||
return;
|
||||
|
||||
if (!mat.MaterialComposition.ContainsKey(component.FuelMaterial))
|
||||
return;
|
||||
|
||||
_popup.PopupEntity(Loc.GetString("generator-insert-material", ("item", args.Used), ("generator", uid)), uid);
|
||||
generator.RemainingFuel += _stack.GetCount(args.Used) * component.Multiplier;
|
||||
QueueDel(args.Used);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
var query = EntityQueryEnumerator<FuelGeneratorComponent, PowerSupplierComponent, TransformComponent>();
|
||||
|
||||
while (query.MoveNext(out var uid, out var gen, out var supplier, out var xform))
|
||||
{
|
||||
supplier.Enabled = gen.RemainingFuel > 0.0f && xform.Anchored;
|
||||
|
||||
var upgradeMultiplier = _upgradeQuery.CompOrNull(uid)?.ActualScalar ?? 1f;
|
||||
|
||||
supplier.MaxSupply = gen.TargetPower * upgradeMultiplier;
|
||||
|
||||
var eff = 1 / CalcFuelEfficiency(gen.TargetPower, gen.OptimalPower, gen);
|
||||
|
||||
gen.RemainingFuel = MathF.Max(gen.RemainingFuel - (gen.OptimalBurnRate * frameTime * eff), 0.0f);
|
||||
UpdateUi(uid, gen);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateUi(EntityUid uid, FuelGeneratorComponent comp)
|
||||
{
|
||||
if (!_uiSystem.IsUiOpen(uid, GeneratorComponentUiKey.Key))
|
||||
return;
|
||||
|
||||
_uiSystem.TrySetUiState(uid, GeneratorComponentUiKey.Key, new SolidFuelGeneratorComponentBuiState(comp));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Content.Shared.Materials;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server.Power.Generator;
|
||||
|
||||
/// <summary>
|
||||
/// This is used for allowing you to insert fuel into gens.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(GeneratorSystem))]
|
||||
public sealed class SolidFuelGeneratorAdapterComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The material to accept as fuel.
|
||||
/// </summary>
|
||||
[DataField("fuelMaterial", customTypeSerializer: typeof(PrototypeIdSerializer<MaterialPrototype>)), ViewVariables(VVAccess.ReadWrite)]
|
||||
public string FuelMaterial = "Plasma";
|
||||
|
||||
/// <summary>
|
||||
/// How much fuel that material should count for.
|
||||
/// </summary>
|
||||
[DataField("multiplier"), ViewVariables(VVAccess.ReadWrite)]
|
||||
public float Multiplier = 1.0f;
|
||||
}
|
||||
Reference in New Issue
Block a user