Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Material Silo #1488

Merged
merged 10 commits into from
Jan 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Content.Client/Materials/MaterialSiloSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using Content.Shared.Materials;

namespace Content.Client.Materials;

public sealed class MaterialSiloSystem : SharedMaterialSiloSystem;
3 changes: 2 additions & 1 deletion Content.Client/Materials/MaterialStorageSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@ public override bool TryInsertMaterialEntity(EntityUid user,
EntityUid toInsert,
EntityUid receiver,
MaterialStorageComponent? storage = null,
MaterialSiloUtilizerComponent? utilizer = null,
MaterialComponent? material = null,
PhysicalCompositionComponent? composition = null)
{
if (!base.TryInsertMaterialEntity(user, toInsert, receiver, storage, material, composition))
if (!base.TryInsertMaterialEntity(user, toInsert, receiver, storage, utilizer, material, composition))
return false;
_transform.DetachParentToNull(toInsert, Transform(toInsert));
return true;
Expand Down
1 change: 1 addition & 0 deletions Content.Client/Materials/UI/MaterialStorageControl.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
HorizontalExpand="True"
VerticalExpand="True">
<BoxContainer Name="MaterialList" Orientation="Vertical">
<Label Name="ConnectToSiloLabel" Text="{Loc 'lathe-menu-connected-to-silo-message'}" Align="Center"/>
<Label Name="NoMatsLabel" Text="{Loc 'lathe-menu-no-materials-message'}" Align="Center"/>
</BoxContainer>
</ScrollContainer>
21 changes: 20 additions & 1 deletion Content.Client/Materials/UI/MaterialStorageControl.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public sealed partial class MaterialStorageControl : ScrollContainer
{
[Dependency] private readonly IEntityManager _entityManager = default!;

private readonly MaterialSiloSystem _materialSilo;

private EntityUid? _owner;

private Dictionary<string, int> _currentMaterials = new();
Expand All @@ -23,6 +25,8 @@ public MaterialStorageControl()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);

_materialSilo = _entityManager.System<MaterialSiloSystem>();
}

public void SetOwner(EntityUid owner)
Expand All @@ -44,7 +48,22 @@ protected override void FrameUpdate(FrameEventArgs args)
}

var canEject = materialStorage.CanEjectStoredMaterials;
var mats = materialStorage.Storage.Select(pair => (pair.Key.Id, pair.Value)).ToDictionary();

Dictionary<string, int> mats;
if (_entityManager.TryGetComponent<MaterialSiloUtilizerComponent>(_owner, out var utilizer) && utilizer.Silo.HasValue)
{
var silo = _materialSilo.GetSiloStorage(_owner.Value);
mats = silo != null
? silo.Value.Comp.Storage.Select(pair => (pair.Key.Id, pair.Value)).ToDictionary()
: materialStorage.Storage.Select(pair => (pair.Key.Id, pair.Value)).ToDictionary();
ConnectToSiloLabel.Visible = silo != null;
}
else
{
mats = materialStorage.Storage.Select(pair => (pair.Key.Id, pair.Value)).ToDictionary();
ConnectToSiloLabel.Visible = false;
}

if (_currentMaterials.Equals(mats))
return;

Expand Down
70 changes: 70 additions & 0 deletions Content.Server/Materials/MaterialSiloSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System.Linq;
using Content.Server.Lathe;
using Content.Server.Station.Components;
using Content.Shared.DeviceLinking;
using Content.Shared.Lathe;
using Content.Shared.Materials;
using Robust.Shared.Timing;

namespace Content.Server.Materials;

public sealed class MaterialSiloSystem : SharedMaterialSiloSystem
{
[Dependency] private readonly LatheSystem _lathe = default!;

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<BecomesStationComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<MaterialSiloComponent, MaterialAmountChangedEvent>(OnMaterialAmountChanged);
}

private void OnMaterialAmountChanged(Entity<MaterialSiloComponent> ent, ref MaterialAmountChangedEvent args)
{
// Spawning a timer because SetUiState in UpdateUserInterfaceState is being networked before
// silo's MaterialStorageComponent state gets handled.
// That causes lathe ui recipe list to not update properly.
Timer.Spawn(20,
() =>
{
if (!TryComp(ent, out DeviceLinkSourceComponent? source))
return;

foreach (var utilizerSet in source.Outputs.Where(x => x.Key == SourcePort).Select(x => x.Value))
{
foreach (var utilizer in utilizerSet)
{
if (TryComp(utilizer, out LatheComponent? lathe))
_lathe.UpdateUserInterfaceState(utilizer, lathe);
}
}
});
}

private void OnMapInit(Entity<BecomesStationComponent> ent, ref MapInitEvent args)
{
Entity<DeviceLinkSourceComponent>? silo = null;
var siloQuery = AllEntityQuery<MaterialSiloComponent, MaterialStorageComponent, TransformComponent, DeviceLinkSourceComponent>();
while (siloQuery.MoveNext(out var siloEnt, out _, out _, out var siloXform, out var source))
{
if (siloXform.GridUid != ent)
continue;

silo = (siloEnt, source);
break;
}

if (silo == null)
return;

var utilizerQuery = AllEntityQuery<MaterialSiloUtilizerComponent, MaterialStorageComponent, TransformComponent, DeviceLinkSinkComponent>();
while (utilizerQuery.MoveNext(out var utilizer, out _, out var storage, out var utilizerXform, out var sink))
{
if (utilizerXform.GridUid != ent)
continue;

DeviceLink.LinkDefaults(null, silo.Value, utilizer, silo.Value.Comp, sink);
}
}
}
17 changes: 11 additions & 6 deletions Content.Server/Materials/MaterialStorageSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,15 @@ public override bool TryInsertMaterialEntity(EntityUid user,
EntityUid toInsert,
EntityUid receiver,
MaterialStorageComponent? storage = null,
MaterialSiloUtilizerComponent? utilizer = null,
MaterialComponent? material = null,
PhysicalCompositionComponent? composition = null)
{
if (!Resolve(receiver, ref storage) || !Resolve(toInsert, ref material, ref composition, false))
return false;
if (TryComp<ApcPowerReceiverComponent>(receiver, out var power) && !power.Powered)
return false;
if (!base.TryInsertMaterialEntity(user, toInsert, receiver, storage, material, composition))
if (!base.TryInsertMaterialEntity(user, toInsert, receiver, storage, utilizer, material, composition))
return false;
_audio.PlayPvs(storage.InsertingSound, receiver);
_popup.PopupEntity(Loc.GetString("machine-insert-item", ("user", user), ("machine", receiver),
Expand Down Expand Up @@ -187,26 +188,28 @@ public List<EntityUid> SpawnMultipleFromMaterial(int amount, MaterialPrototype m
/// <param name="maxAmount">The maximum amount to eject. If not given, as much as possible is ejected.</param>
/// <param name="coordinates">The position where to spawn the created sheets. If not given, they're spawned next to the entity.</param>
/// <param name="component">The storage component on <paramref name="entity"/>. Resolved automatically if not given.</param>
/// <param name="utilizer">The material silo utilizer component on <paramref name="uid"/>.</param>
/// <returns>The stack entities that were spawned.</returns>
public List<EntityUid> EjectMaterial(
EntityUid entity,
string material,
int? maxAmount = null,
EntityCoordinates? coordinates = null,
MaterialStorageComponent? component = null)
MaterialStorageComponent? component = null,
MaterialSiloUtilizerComponent? utilizer = null)
{
if (!Resolve(entity, ref component))
return new List<EntityUid>();

coordinates ??= Transform(entity).Coordinates;

var amount = GetMaterialAmount(entity, material, component);
var amount = GetMaterialAmount(entity, material, component, utilizer);
if (maxAmount != null)
amount = Math.Min(maxAmount.Value, amount);

var spawned = SpawnMultipleFromMaterial(amount, material, coordinates.Value, out var overflow);

TryChangeMaterialAmount(entity, material, -(amount - overflow), component);
TryChangeMaterialAmount(entity, material, -(amount - overflow), component, utilizer);
return spawned;
}

Expand All @@ -216,11 +219,13 @@ public List<EntityUid> EjectMaterial(
/// <param name="entity">The entity with storage to eject from.</param>
/// <param name="coordinates">The position where to spawn the created sheets. If not given, they're spawned next to the entity.</param>
/// <param name="component">The storage component on <paramref name="entity"/>. Resolved automatically if not given.</param>
/// <param name="utilizer">The material silo utilizer component on <paramref name="uid"/>.</param>
/// <returns>The stack entities that were spawned.</returns>
public List<EntityUid> EjectAllMaterial(
EntityUid entity,
EntityCoordinates? coordinates = null,
MaterialStorageComponent? component = null)
MaterialStorageComponent? component = null,
MaterialSiloUtilizerComponent? utilizer = null)
{
if (!Resolve(entity, ref component))
return new List<EntityUid>();
Expand All @@ -230,7 +235,7 @@ public List<EntityUid> EjectAllMaterial(
var allSpawned = new List<EntityUid>();
foreach (var material in component.Storage.Keys.ToArray())
{
var spawned = EjectMaterial(entity, material, null, coordinates, component);
var spawned = EjectMaterial(entity, material, null, coordinates, component, utilizer);
allSpawned.AddRange(spawned);
}

Expand Down
11 changes: 11 additions & 0 deletions Content.Shared/CCVar/CCVars.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2980,6 +2980,17 @@ public static readonly CVarDef<float>
CVarDef.Create("reclaimer.allow_gibbing", true, CVar.SERVER);

#endregion

#region Material Silo

/// <summary>
/// Is ore material enabled.
/// </summary>
public static readonly CVarDef<bool> SiloEnabled =
CVarDef.Create("silo.silo_enabled", true, CVar.SERVER | CVar.REPLICATED);

#endregion

#region Jetpack System
/*
* Jetpack System
Expand Down
6 changes: 6 additions & 0 deletions Content.Shared/Materials/MaterialSiloComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
using Robust.Shared.GameStates;

namespace Content.Shared.Materials;

[RegisterComponent, NetworkedComponent]
public sealed partial class MaterialSiloComponent : Component;
10 changes: 10 additions & 0 deletions Content.Shared/Materials/MaterialSiloUtilizerComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Robust.Shared.GameStates;

namespace Content.Shared.Materials;

[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class MaterialSiloUtilizerComponent : Component
{
[DataField, AutoNetworkedField]
public EntityUid? Silo;
}
1 change: 0 additions & 1 deletion Content.Shared/Materials/MaterialStorageComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
namespace Content.Shared.Materials;

[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
[Access(typeof(SharedMaterialStorageSystem))]
public sealed partial class MaterialStorageComponent : Component
{
[DataField, AutoNetworkedField]
Expand Down
120 changes: 120 additions & 0 deletions Content.Shared/Materials/SharedMaterialSiloSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
using System.Linq;
using Content.Shared.CCVar;
using Content.Shared.DeviceLinking;
using Content.Shared.DeviceLinking.Events;
using Content.Shared.Power;
using Content.Shared.Power.EntitySystems;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;

namespace Content.Shared.Materials;

public abstract class SharedMaterialSiloSystem : EntitySystem
{
[Dependency] protected readonly SharedDeviceLinkSystem DeviceLink = default!;

[Dependency] private readonly SharedPowerReceiverSystem _powerReceiver = default!;
[Dependency] private readonly SharedMaterialStorageSystem _materialStorage = default!;

[Dependency] private readonly IConfigurationManager _cfg = default!;

private bool _siloEnabled;

protected ProtoId<SourcePortPrototype> SourcePort = "MaterialSilo";
protected ProtoId<SinkPortPrototype> SinkPort = "MaterialSiloUtilizer";

public override void Initialize()
{
base.Initialize();

_cfg.OnValueChanged(CCVars.SiloEnabled, enabled => _siloEnabled = enabled, true);

SubscribeLocalEvent<MaterialSiloComponent, NewLinkEvent>(OnNewLink);
SubscribeLocalEvent<MaterialSiloComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<MaterialSiloUtilizerComponent, PortDisconnectedEvent>(OnPortDisconnected);
}

private void OnPortDisconnected(Entity<MaterialSiloUtilizerComponent> ent, ref PortDisconnectedEvent args)
{
if (args.Port != SinkPort)
return;

ent.Comp.Silo = null;
Dirty(ent);
}

private void OnNewLink(Entity<MaterialSiloComponent> ent, ref NewLinkEvent args)
{
if (args.SinkPort != SinkPort || args.SourcePort != SourcePort
|| !TryComp(args.Sink, out MaterialSiloUtilizerComponent? utilizer))
return;

if (utilizer.Silo != null)
DeviceLink.RemoveSinkFromSource(utilizer.Silo.Value, args.Sink);

if (TryComp(args.Sink, out MaterialStorageComponent? utilizerStorage)
&& utilizerStorage.Storage.Count != 0
&& TryComp(ent, out MaterialStorageComponent? siloStorage))
{
foreach (var material in utilizerStorage.Storage.Keys.ToArray())
{
var materialAmount = utilizerStorage.Storage.GetValueOrDefault(material, 0);
if (_materialStorage.TryChangeMaterialAmount(ent, material, materialAmount, siloStorage))
_materialStorage.TryChangeMaterialAmount(args.Sink, material, -materialAmount, utilizerStorage);
}
}

utilizer.Silo = ent;
Dirty(args.Sink, utilizer);
}

private void OnPowerChanged(Entity<MaterialSiloComponent> ent, ref PowerChangedEvent args)
{
if (!TryComp(ent, out MaterialStorageComponent? siloStorage))
return;

var siloUtilizerQuery = AllEntityQuery<MaterialSiloUtilizerComponent, MaterialStorageComponent>();

while (siloUtilizerQuery.MoveNext(out var utilizerUid, out var utilizer, out var utilizerStorage))
{
if (utilizer.Silo != ent)
continue;

foreach (var material in utilizerStorage.Storage.Keys.ToArray())
{
var materialAmount = utilizerStorage.Storage.GetValueOrDefault(material, 0);
if (!_materialStorage.TryChangeMaterialAmount(ent, material, materialAmount, siloStorage))
continue;

utilizerStorage.Storage[material] -= materialAmount;

var ev = new MaterialAmountChangedEvent();
RaiseLocalEvent(utilizerUid, ref ev);

Dirty(utilizerUid, utilizerStorage);
}
}
}

public int GetSiloMaterialAmount(EntityUid machine, string material, MaterialSiloUtilizerComponent? utilizer = null)
{
var silo = GetSiloStorage(machine, utilizer);
return silo == null ? 0 : silo.Value.Comp.Storage.GetValueOrDefault(material, 0);
}

public int GetSiloTotalMaterialAmount(EntityUid machine, MaterialSiloUtilizerComponent? utilizer = null)
{
var silo = GetSiloStorage(machine, utilizer);
return silo == null ? 0 : silo.Value.Comp.Storage.Values.Sum();
}

public Entity<MaterialStorageComponent>? GetSiloStorage(EntityUid machine, MaterialSiloUtilizerComponent? utilizer = null)
{
if (!_siloEnabled || !Resolve(machine, ref utilizer)
|| !TryComp(utilizer.Silo, out MaterialStorageComponent? storage)
|| !_powerReceiver.IsPowered(utilizer.Silo.Value))
return null;

return (utilizer.Silo.Value, storage);
}
}
Loading
Loading