Local Material Silo (#36492)
* Material Silo * fix board, fix copyright * a bit of review.... for the vibe.... * a tiny bit of review * 4 spaced * sloths no good very tiny nitpick * fix ui flickers * oops * slightly lower range * Sloth Review --------- Co-authored-by: ScarKy0 <scarky0@onet.eu>
This commit is contained in:
@@ -75,6 +75,24 @@ public enum MaterialStorageVisuals : byte
|
||||
Inserting
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collects all the materials stored on a <see cref="MaterialStorageComponent"/>
|
||||
/// </summary>
|
||||
/// <param name="Entity">The entity holding all these materials</param>
|
||||
/// <param name="Materials">A dictionary of all materials held</param>
|
||||
/// <param name="LocalOnly">An optional specifier. Non-local sources (silo, etc.) should not add materials when this is false.</param>
|
||||
[ByRefEvent]
|
||||
public readonly record struct GetStoredMaterialsEvent(Entity<MaterialStorageComponent> Entity, Dictionary<ProtoId<MaterialPrototype>, int> Materials, bool LocalOnly);
|
||||
|
||||
/// <summary>
|
||||
/// After using materials, removes them from storage.
|
||||
/// </summary>
|
||||
/// <param name="Entity">The entity that held the materials and is being used up</param>
|
||||
/// <param name="Materials">A dictionary of the difference of materials left.</param>
|
||||
/// <param name="LocalOnly">An optional specifier. Non-local sources (silo, etc.) should not consume materials when this is false.</param>
|
||||
[ByRefEvent]
|
||||
public readonly record struct ConsumeStoredMaterialsEvent(Entity<MaterialStorageComponent> Entity, Dictionary<ProtoId<MaterialPrototype>, int> Materials, bool LocalOnly);
|
||||
|
||||
/// <summary>
|
||||
/// event raised on the materialStorage when a material entity is inserted into it.
|
||||
/// </summary>
|
||||
|
||||
18
Content.Shared/Materials/OreSilo/OreSiloClientComponent.cs
Normal file
18
Content.Shared/Materials/OreSilo/OreSiloClientComponent.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Materials.OreSilo;
|
||||
|
||||
/// <summary>
|
||||
/// An entity with <see cref="MaterialStorageComponent"/> that interfaces with an <see cref="OreSiloComponent"/>.
|
||||
/// Used for tracking the connected silo.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
[Access(typeof(SharedOreSiloSystem))]
|
||||
public sealed partial class OreSiloClientComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The silo that this client pulls materials from.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public EntityUid? Silo;
|
||||
}
|
||||
55
Content.Shared/Materials/OreSilo/OreSiloComponent.cs
Normal file
55
Content.Shared/Materials/OreSilo/OreSiloComponent.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Materials.OreSilo;
|
||||
|
||||
/// <summary>
|
||||
/// Provides additional materials to linked clients across long distances.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
[Access(typeof(SharedOreSiloSystem))]
|
||||
public sealed partial class OreSiloComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="OreSiloClientComponent"/> that are connected to this silo.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public HashSet<EntityUid> Clients = new();
|
||||
|
||||
/// <summary>
|
||||
/// The maximum distance you can be to the silo and still receive transmission.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Default value should be big enough to span a single large department.
|
||||
/// </remarks>
|
||||
[DataField, AutoNetworkedField]
|
||||
public float Range = 20f;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class OreSiloBuiState : BoundUserInterfaceState
|
||||
{
|
||||
public readonly HashSet<(NetEntity, string, string)> Clients;
|
||||
|
||||
public OreSiloBuiState(HashSet<(NetEntity, string, string)> clients)
|
||||
{
|
||||
Clients = clients;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class ToggleOreSiloClientMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public readonly NetEntity Client;
|
||||
|
||||
public ToggleOreSiloClientMessage(NetEntity client)
|
||||
{
|
||||
Client = client;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum OreSiloUiKey : byte
|
||||
{
|
||||
Key
|
||||
}
|
||||
168
Content.Shared/Materials/OreSilo/SharedOreSiloSystem.cs
Normal file
168
Content.Shared/Materials/OreSilo/SharedOreSiloSystem.cs
Normal file
@@ -0,0 +1,168 @@
|
||||
using Content.Shared.Power.EntitySystems;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Materials.OreSilo;
|
||||
|
||||
public abstract class SharedOreSiloSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedMaterialStorageSystem _materialStorage = default!;
|
||||
[Dependency] private readonly SharedPowerReceiverSystem _powerReceiver = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
|
||||
private EntityQuery<OreSiloClientComponent> _clientQuery;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<OreSiloComponent, ToggleOreSiloClientMessage>(OnToggleOreSiloClient);
|
||||
SubscribeLocalEvent<OreSiloComponent, ComponentShutdown>(OnSiloShutdown);
|
||||
Subs.BuiEvents<OreSiloComponent>(OreSiloUiKey.Key,
|
||||
subs =>
|
||||
{
|
||||
subs.Event<BoundUIOpenedEvent>(OnBoundUIOpened);
|
||||
});
|
||||
|
||||
|
||||
SubscribeLocalEvent<OreSiloClientComponent, GetStoredMaterialsEvent>(OnGetStoredMaterials);
|
||||
SubscribeLocalEvent<OreSiloClientComponent, ConsumeStoredMaterialsEvent>(OnConsumeStoredMaterials);
|
||||
SubscribeLocalEvent<OreSiloClientComponent, ComponentShutdown>(OnClientShutdown);
|
||||
|
||||
_clientQuery = GetEntityQuery<OreSiloClientComponent>();
|
||||
}
|
||||
|
||||
private void OnToggleOreSiloClient(Entity<OreSiloComponent> ent, ref ToggleOreSiloClientMessage args)
|
||||
{
|
||||
var client = GetEntity(args.Client);
|
||||
|
||||
if (!_clientQuery.TryComp(client, out var clientComp))
|
||||
return;
|
||||
|
||||
if (ent.Comp.Clients.Contains(client)) // remove client
|
||||
{
|
||||
clientComp.Silo = null;
|
||||
Dirty(client, clientComp);
|
||||
ent.Comp.Clients.Remove(client);
|
||||
Dirty(ent);
|
||||
|
||||
UpdateOreSiloUi(ent);
|
||||
}
|
||||
else // add client
|
||||
{
|
||||
if (!CanTransmitMaterials((ent, ent), client))
|
||||
return;
|
||||
|
||||
var clientMats = _materialStorage.GetStoredMaterials(client, true);
|
||||
var inverseMats = new Dictionary<string, int>();
|
||||
foreach (var (mat, amount) in clientMats)
|
||||
{
|
||||
inverseMats.Add(mat, -amount);
|
||||
}
|
||||
_materialStorage.TryChangeMaterialAmount(client, inverseMats, localOnly: true);
|
||||
_materialStorage.TryChangeMaterialAmount(ent.Owner, clientMats);
|
||||
|
||||
ent.Comp.Clients.Add(client);
|
||||
Dirty(ent);
|
||||
clientComp.Silo = ent;
|
||||
Dirty(client, clientComp);
|
||||
|
||||
UpdateOreSiloUi(ent);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBoundUIOpened(Entity<OreSiloComponent> ent, ref BoundUIOpenedEvent args)
|
||||
{
|
||||
UpdateOreSiloUi(ent);
|
||||
}
|
||||
|
||||
private void OnSiloShutdown(Entity<OreSiloComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
foreach (var client in ent.Comp.Clients)
|
||||
{
|
||||
if (!_clientQuery.TryComp(client, out var comp))
|
||||
continue;
|
||||
|
||||
comp.Silo = null;
|
||||
Dirty(client, comp);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void UpdateOreSiloUi(Entity<OreSiloComponent> ent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void OnGetStoredMaterials(Entity<OreSiloClientComponent> ent, ref GetStoredMaterialsEvent args)
|
||||
{
|
||||
if (args.LocalOnly)
|
||||
return;
|
||||
|
||||
if (ent.Comp.Silo is not { } silo)
|
||||
return;
|
||||
|
||||
if (!CanTransmitMaterials(silo, ent))
|
||||
return;
|
||||
|
||||
var materials = _materialStorage.GetStoredMaterials(silo);
|
||||
|
||||
foreach (var (mat, amount) in materials)
|
||||
{
|
||||
// Don't supply materials that they don't usually have access to.
|
||||
if (!_materialStorage.IsMaterialWhitelisted((args.Entity, args.Entity), mat))
|
||||
continue;
|
||||
|
||||
var existing = args.Materials.GetOrNew(mat);
|
||||
args.Materials[mat] = existing + amount;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnConsumeStoredMaterials(Entity<OreSiloClientComponent> ent, ref ConsumeStoredMaterialsEvent args)
|
||||
{
|
||||
if (args.LocalOnly)
|
||||
return;
|
||||
|
||||
if (ent.Comp.Silo is not { } silo || !TryComp<MaterialStorageComponent>(silo, out var materialStorage))
|
||||
return;
|
||||
|
||||
if (!CanTransmitMaterials(silo, ent))
|
||||
return;
|
||||
|
||||
foreach (var (mat, amount) in args.Materials)
|
||||
{
|
||||
if (!_materialStorage.TryChangeMaterialAmount(silo, mat, amount, materialStorage))
|
||||
continue;
|
||||
args.Materials[mat] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnClientShutdown(Entity<OreSiloClientComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
if (!TryComp<OreSiloComponent>(ent.Comp.Silo, out var silo))
|
||||
return;
|
||||
|
||||
silo.Clients.Remove(ent);
|
||||
Dirty(ent.Comp.Silo.Value, silo);
|
||||
UpdateOreSiloUi((ent.Comp.Silo.Value, silo));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a given client fulfills the criteria to link/receive materials from an ore silo.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool CanTransmitMaterials(Entity<OreSiloComponent?> silo, EntityUid client)
|
||||
{
|
||||
if (!Resolve(silo, ref silo.Comp))
|
||||
return false;
|
||||
|
||||
if (!_powerReceiver.IsPowered(silo.Owner))
|
||||
return false;
|
||||
|
||||
if (_transform.GetGrid(client) != _transform.GetGrid(silo.Owner))
|
||||
return false;
|
||||
|
||||
if (!_transform.InRange(silo.Owner, client, silo.Comp.Range))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Components;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Stacks;
|
||||
using Content.Shared.Whitelist;
|
||||
using JetBrains.Annotations;
|
||||
@@ -58,16 +57,22 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the volume of a specified material contained in this storage.
|
||||
/// Gets all the materials stored on this entity
|
||||
/// </summary>
|
||||
/// <param name="uid"></param>
|
||||
/// <param name="material"></param>
|
||||
/// <param name="component"></param>
|
||||
/// <returns>The volume of the material</returns>
|
||||
[PublicAPI]
|
||||
public int GetMaterialAmount(EntityUid uid, MaterialPrototype material, MaterialStorageComponent? component = null)
|
||||
/// <param name="ent"></param>
|
||||
/// <param name="localOnly">Include only materials held "locally", as determined by event subscribers</param>
|
||||
/// <returns></returns>
|
||||
public Dictionary<ProtoId<MaterialPrototype>, int> GetStoredMaterials(Entity<MaterialStorageComponent?> ent, bool localOnly = false)
|
||||
{
|
||||
return GetMaterialAmount(uid, material.ID, component);
|
||||
if (!Resolve(ent, ref ent.Comp, false))
|
||||
return new();
|
||||
|
||||
// clone so we don't modify by accident.
|
||||
var mats = new Dictionary<ProtoId<MaterialPrototype>, int>(ent.Comp.Storage);
|
||||
var ev = new GetStoredMaterialsEvent((ent, ent.Comp), mats, localOnly);
|
||||
RaiseLocalEvent(ent, ref ev, true);
|
||||
|
||||
return ev.Materials;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -76,12 +81,27 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
|
||||
/// <param name="uid"></param>
|
||||
/// <param name="material"></param>
|
||||
/// <param name="component"></param>
|
||||
/// <param name="localOnly"></param>
|
||||
/// <returns>The volume of the material</returns>
|
||||
public int GetMaterialAmount(EntityUid uid, string material, MaterialStorageComponent? component = null)
|
||||
[PublicAPI]
|
||||
public int GetMaterialAmount(EntityUid uid, MaterialPrototype material, MaterialStorageComponent? component = null, bool localOnly = false)
|
||||
{
|
||||
return GetMaterialAmount(uid, material.ID, component, localOnly);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the volume of a specified material contained in this storage.
|
||||
/// </summary>
|
||||
/// <param name="uid"></param>
|
||||
/// <param name="material"></param>
|
||||
/// <param name="component"></param>
|
||||
/// <param name="localOnly"></param>
|
||||
/// <returns>The volume of the material</returns>
|
||||
public int GetMaterialAmount(EntityUid uid, string material, MaterialStorageComponent? component = null, bool localOnly = false)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return 0; //you have nothing
|
||||
return component.Storage.GetValueOrDefault(material, 0);
|
||||
return GetStoredMaterials((uid, component), localOnly).GetValueOrDefault(material, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -89,26 +109,43 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
|
||||
/// </summary>
|
||||
/// <param name="uid"></param>
|
||||
/// <param name="component"></param>
|
||||
/// <param name="localOnly"></param>
|
||||
/// <returns>The volume of all materials in the storage</returns>
|
||||
public int GetTotalMaterialAmount(EntityUid uid, MaterialStorageComponent? component = null)
|
||||
public int GetTotalMaterialAmount(EntityUid uid, MaterialStorageComponent? component = null, bool localOnly = false)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return 0;
|
||||
return component.Storage.Values.Sum();
|
||||
return GetStoredMaterials((uid, component), localOnly).Values.Sum();
|
||||
}
|
||||
|
||||
// TODO: Revisit this if we ever decide to do things with storage limits. As it stands, the feature is unused.
|
||||
/// <summary>
|
||||
/// Tests if a specific amount of volume will fit in the storage.
|
||||
/// </summary>
|
||||
/// <param name="uid"></param>
|
||||
/// <param name="volume"></param>
|
||||
/// <param name="component"></param>
|
||||
/// <param name="localOnly"></param>
|
||||
/// <returns>If the specified volume will fit</returns>
|
||||
public bool CanTakeVolume(EntityUid uid, int volume, MaterialStorageComponent? component = null)
|
||||
public bool CanTakeVolume(EntityUid uid, int volume, MaterialStorageComponent? component = null, bool localOnly = false)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return false;
|
||||
return component.StorageLimit == null || GetTotalMaterialAmount(uid, component) + volume <= component.StorageLimit;
|
||||
return component.StorageLimit == null || GetTotalMaterialAmount(uid, component, true) + volume <= component.StorageLimit;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a certain material prototype is supported by this entity.
|
||||
/// </summary>
|
||||
public bool IsMaterialWhitelisted(Entity<MaterialStorageComponent?> ent, ProtoId<MaterialPrototype> material)
|
||||
{
|
||||
if (!Resolve(ent, ref ent.Comp))
|
||||
return false;
|
||||
|
||||
if (ent.Comp.MaterialWhiteList == null)
|
||||
return true;
|
||||
|
||||
return ent.Comp.MaterialWhiteList.Contains(material);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -118,8 +155,9 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
|
||||
/// <param name="materialId"></param>
|
||||
/// <param name="volume"></param>
|
||||
/// <param name="component"></param>
|
||||
/// <param name="localOnly"></param>
|
||||
/// <returns>If the amount can be changed</returns>
|
||||
public bool CanChangeMaterialAmount(EntityUid uid, string materialId, int volume, MaterialStorageComponent? component = null)
|
||||
public bool CanChangeMaterialAmount(EntityUid uid, string materialId, int volume, MaterialStorageComponent? component = null, bool localOnly = false)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return false;
|
||||
@@ -127,10 +165,10 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
|
||||
if (!CanTakeVolume(uid, volume, component))
|
||||
return false;
|
||||
|
||||
if (component.MaterialWhiteList == null ? false : !component.MaterialWhiteList.Contains(materialId))
|
||||
if (!IsMaterialWhitelisted((uid, component), materialId))
|
||||
return false;
|
||||
|
||||
var amount = component.Storage.GetValueOrDefault(materialId);
|
||||
var amount = GetMaterialAmount(uid, materialId, component, localOnly);
|
||||
return amount + volume >= 0;
|
||||
}
|
||||
|
||||
@@ -140,14 +178,24 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="materials"></param>
|
||||
/// <returns>If the amount can be changed</returns>
|
||||
public bool CanChangeMaterialAmount(Entity<MaterialStorageComponent?> entity, Dictionary<string,int> materials)
|
||||
/// <param name="localOnly"></param>
|
||||
public bool CanChangeMaterialAmount(Entity<MaterialStorageComponent?> entity, Dictionary<string,int> materials, bool localOnly = false)
|
||||
{
|
||||
if (!Resolve(entity, ref entity.Comp))
|
||||
return false;
|
||||
|
||||
var inVolume = materials.Values.Sum();
|
||||
var stored = GetStoredMaterials((entity, entity.Comp), localOnly);
|
||||
|
||||
if (!CanTakeVolume(entity, inVolume, entity.Comp))
|
||||
return false;
|
||||
|
||||
foreach (var (material, amount) in materials)
|
||||
{
|
||||
if (!CanChangeMaterialAmount(entity, material, amount, entity.Comp))
|
||||
if (!IsMaterialWhitelisted(entity, material))
|
||||
return false;
|
||||
|
||||
if (stored.GetValueOrDefault(material) + amount < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -163,16 +211,27 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
|
||||
/// <param name="volume"></param>
|
||||
/// <param name="component"></param>
|
||||
/// <param name="dirty"></param>
|
||||
/// <param name="localOnly"></param>
|
||||
/// <returns>If it was successful</returns>
|
||||
public bool TryChangeMaterialAmount(EntityUid uid, string materialId, int volume, MaterialStorageComponent? component = null, bool dirty = true)
|
||||
public bool TryChangeMaterialAmount(EntityUid uid, string materialId, int volume, MaterialStorageComponent? component = null, bool dirty = true, bool localOnly = false)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return false;
|
||||
if (!CanChangeMaterialAmount(uid, materialId, volume, component))
|
||||
|
||||
if (!CanChangeMaterialAmount(uid, materialId, volume, component, localOnly))
|
||||
return false;
|
||||
|
||||
var changeEv = new ConsumeStoredMaterialsEvent((uid, component), new() {{materialId, volume}}, localOnly);
|
||||
RaiseLocalEvent(uid, ref changeEv);
|
||||
var remaining = changeEv.Materials.Values.First();
|
||||
|
||||
var existing = component.Storage.GetOrNew(materialId);
|
||||
existing += volume;
|
||||
|
||||
var localUpperLimit = component.StorageLimit == null ? int.MaxValue : component.StorageLimit.Value - existing;
|
||||
var localLowerLimit = -existing;
|
||||
var localChange = Math.Clamp(remaining, localLowerLimit, localUpperLimit);
|
||||
|
||||
existing += localChange;
|
||||
|
||||
if (existing == 0)
|
||||
component.Storage.Remove(materialId);
|
||||
@@ -191,23 +250,54 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
|
||||
/// Changes the amount of a specific material in the storage.
|
||||
/// Still respects the filters in place.
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="materials"></param>
|
||||
/// <returns>If the amount can be changed</returns>
|
||||
public bool TryChangeMaterialAmount(Entity<MaterialStorageComponent?> entity, Dictionary<string,int> materials)
|
||||
public bool TryChangeMaterialAmount(Entity<MaterialStorageComponent?> entity, Dictionary<string, int> materials, bool localOnly = false)
|
||||
{
|
||||
return TryChangeMaterialAmount(entity, materials.Select(p => (new ProtoId<MaterialPrototype>(p.Key), p.Value)).ToDictionary(), localOnly);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the amount of a specific material in the storage.
|
||||
/// Still respects the filters in place.
|
||||
/// </summary>
|
||||
/// <returns>If the amount can be changed</returns>
|
||||
public bool TryChangeMaterialAmount(
|
||||
Entity<MaterialStorageComponent?> entity,
|
||||
Dictionary<ProtoId<MaterialPrototype>, int> materials,
|
||||
bool localOnly = false)
|
||||
{
|
||||
if (!Resolve(entity, ref entity.Comp))
|
||||
return false;
|
||||
|
||||
if (!CanChangeMaterialAmount(entity, materials))
|
||||
return false;
|
||||
|
||||
foreach (var (material, amount) in materials)
|
||||
{
|
||||
if (!TryChangeMaterialAmount(entity, material, amount, entity.Comp, false))
|
||||
if (!CanChangeMaterialAmount(entity, material, amount, entity))
|
||||
return false;
|
||||
}
|
||||
|
||||
var changeEv = new ConsumeStoredMaterialsEvent((entity, entity.Comp), materials, localOnly);
|
||||
RaiseLocalEvent(entity, ref changeEv);
|
||||
|
||||
foreach (var (material, remaining) in changeEv.Materials)
|
||||
{
|
||||
var existing = entity.Comp.Storage.GetOrNew(material);
|
||||
|
||||
var localUpperLimit = entity.Comp.StorageLimit == null ? int.MaxValue : entity.Comp.StorageLimit.Value - existing;
|
||||
var localLowerLimit = -existing;
|
||||
var localChange = Math.Clamp(remaining, localLowerLimit, localUpperLimit);
|
||||
|
||||
existing += localChange;
|
||||
|
||||
if (existing == 0)
|
||||
entity.Comp.Storage.Remove(material);
|
||||
else
|
||||
entity.Comp.Storage[material] = existing;
|
||||
|
||||
}
|
||||
|
||||
var ev = new MaterialAmountChangedEvent();
|
||||
RaiseLocalEvent(entity, ref ev);
|
||||
|
||||
Dirty(entity, entity.Comp);
|
||||
return true;
|
||||
}
|
||||
@@ -221,6 +311,7 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
|
||||
/// <param name="volume">The stored material volume to set the storage to.</param>
|
||||
/// <param name="component">The storage component on <paramref name="uid"/>. Resolved automatically if not given.</param>
|
||||
/// <returns>True if it was successful (enough space etc).</returns>
|
||||
[PublicAPI]
|
||||
public bool TrySetMaterialAmount(
|
||||
EntityUid uid,
|
||||
string materialId,
|
||||
@@ -268,7 +359,7 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
|
||||
totalVolume += vol * multiplier;
|
||||
}
|
||||
|
||||
if (!CanTakeVolume(receiver, totalVolume, storage))
|
||||
if (!CanTakeVolume(receiver, totalVolume, storage, localOnly: true))
|
||||
return false;
|
||||
|
||||
foreach (var (mat, vol) in composition.MaterialComposition)
|
||||
|
||||
Reference in New Issue
Block a user