Refactor stacks to not use method events (#4177)

This commit is contained in:
Vera Aguilera Puerto
2021-06-12 11:24:34 +02:00
committed by GitHub
parent ca4e665296
commit 0093a961bc
17 changed files with 79 additions and 248 deletions

View File

@@ -16,14 +16,14 @@ namespace Content.Server.Construction.Completions
[DataDefinition] [DataDefinition]
public class SetStackCount : IGraphAction public class SetStackCount : IGraphAction
{ {
[DataField("amount")] public int Amount { get; private set; } = 1; [DataField("amount")] public int Amount { get; } = 1;
public async Task PerformAction(IEntity entity, IEntity? user) public async Task PerformAction(IEntity entity, IEntity? user)
{ {
if (entity.Deleted) return; if (entity.Deleted) return;
if(!entity.HasComponent<StackComponent>()) return; if(!entity.TryGetComponent<StackComponent>(out var stack)) return;
entity.EntityManager.EventBus.RaiseLocalEvent(entity.Uid, new StackChangeCountEvent(Amount), false); EntitySystem.Get<StackSystem>().SetCount(entity.Uid, stack, Amount);
} }
} }
} }

View File

@@ -29,8 +29,9 @@ namespace Content.Server.Construction.Completions
if (EntityPrototypeHelpers.HasComponent<StackComponent>(Prototype)) if (EntityPrototypeHelpers.HasComponent<StackComponent>(Prototype))
{ {
var stack = entityManager.SpawnEntity(Prototype, coordinates); var stackEnt = entityManager.SpawnEntity(Prototype, coordinates);
stack.EntityManager.EventBus.RaiseLocalEvent(stack.Uid, new StackChangeCountEvent(Amount), false); var stack = stackEnt.GetComponent<StackComponent>();
EntitySystem.Get<StackSystem>().SetCount(stackEnt.Uid, stack, Amount);
} }
else else
{ {

View File

@@ -269,12 +269,11 @@ namespace Content.Server.Construction.Components
if (materialStep.EntityValid(eventArgs.Using, out var stack) if (materialStep.EntityValid(eventArgs.Using, out var stack)
&& await doAfterSystem.DoAfter(doAfterArgs) == DoAfterStatus.Finished) && await doAfterSystem.DoAfter(doAfterArgs) == DoAfterStatus.Finished)
{ {
var splitStack = new StackSplitEvent() {Amount = materialStep.Amount, SpawnPosition = eventArgs.User.Transform.Coordinates}; var splitStack = EntitySystem.Get<StackSystem>().Split(eventArgs.Using.Uid, stack, materialStep.Amount, eventArgs.User.Transform.Coordinates);
Owner.EntityManager.EventBus.RaiseLocalEvent(stack.Owner.Uid, splitStack);
if (splitStack.Result != null) if (splitStack != null)
{ {
entityUsing = splitStack.Result; entityUsing = splitStack;
valid = true; valid = true;
} }
} }

View File

@@ -86,16 +86,12 @@ namespace Content.Server.Construction.Components
foreach (var (stackType, amount) in machineBoard.MaterialRequirements) foreach (var (stackType, amount) in machineBoard.MaterialRequirements)
{ {
var stackSpawn = new StackTypeSpawnEvent() var stack = EntitySystem.Get<StackSystem>().Spawn(amount, stackType, Owner.Transform.Coordinates);
{Amount = amount, StackType = stackType, SpawnPosition = Owner.Transform.Coordinates};
Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, stackSpawn);
var s = stackSpawn.Result; if (stack == null)
if (s == null)
throw new Exception($"Couldn't spawn stack of type {stackType}!"); throw new Exception($"Couldn't spawn stack of type {stackType}!");
if (!partContainer.Insert(s)) if (!partContainer.Insert(stack))
throw new Exception($"Couldn't insert machine material of type {stackType} to machine with prototype {Owner.Prototype?.ID ?? "N/A"}"); throw new Exception($"Couldn't insert machine material of type {stackType} to machine with prototype {Owner.Prototype?.ID ?? "N/A"}");
} }

View File

@@ -313,14 +313,12 @@ namespace Content.Server.Construction.Components
return true; return true;
} }
var splitStack = new StackSplitEvent() var splitStack = EntitySystem.Get<StackSystem>().Split(eventArgs.Using.Uid, stack, needed, Owner.Transform.Coordinates);
{Amount = needed, SpawnPosition = Owner.Transform.Coordinates};
Owner.EntityManager.EventBus.RaiseLocalEvent(stack.Owner.Uid, splitStack);
if (splitStack.Result == null) if (splitStack == null)
return false; return false;
if(!_partContainer.Insert(splitStack.Result)) if(!_partContainer.Insert(splitStack))
return false; return false;
_materialProgress[type] += needed; _materialProgress[type] += needed;

View File

@@ -52,15 +52,15 @@ namespace Content.Server.Construction.Components
var resultPosition = Owner.Transform.Coordinates; var resultPosition = Owner.Transform.Coordinates;
Owner.Delete(); Owner.Delete();
// spawn each result afrer refine // spawn each result after refine
foreach (var result in _refineResult!) foreach (var result in _refineResult!)
{ {
var droppedEnt = Owner.EntityManager.SpawnEntity(result, resultPosition); var droppedEnt = Owner.EntityManager.SpawnEntity(result, resultPosition);
// TODO: If something has a stack... Just use a prototype with a single thing in the stack. // TODO: If something has a stack... Just use a prototype with a single thing in the stack.
// This is not a good way to do it. // This is not a good way to do it.
if (droppedEnt.HasComponent<StackComponent>()) if (droppedEnt.TryGetComponent<StackComponent>(out var stack))
Owner.EntityManager.EventBus.RaiseLocalEvent(droppedEnt.Uid, new StackChangeCountEvent(1), false); EntitySystem.Get<StackSystem>().SetCount(droppedEnt.Uid, stack, 1);
} }
return true; return true;

View File

@@ -170,19 +170,17 @@ namespace Content.Server.Construction
if (!materialStep.EntityValid(entity, out var stack)) if (!materialStep.EntityValid(entity, out var stack))
continue; continue;
var splitStack = new StackSplitEvent() var splitStack = Get<StackSystem>().Split(entity.Uid, stack, materialStep.Amount, user.ToCoordinates());
{Amount = materialStep.Amount, SpawnPosition = user.ToCoordinates()};
RaiseLocalEvent(entity.Uid, splitStack);
if (splitStack.Result == null) if (splitStack == null)
continue; continue;
if (string.IsNullOrEmpty(materialStep.Store)) if (string.IsNullOrEmpty(materialStep.Store))
{ {
if (!container.Insert(splitStack.Result)) if (!container.Insert(splitStack))
continue; continue;
} }
else if (!GetContainer(materialStep.Store).Insert(splitStack.Result)) else if (!GetContainer(materialStep.Store).Insert(splitStack))
continue; continue;
handled = true; handled = true;

View File

@@ -33,7 +33,8 @@ namespace Content.Server.Destructible.Thresholds.Behaviors
if (EntityPrototypeHelpers.HasComponent<StackComponent>(entityId)) if (EntityPrototypeHelpers.HasComponent<StackComponent>(entityId))
{ {
var spawned = owner.EntityManager.SpawnEntity(entityId, owner.Transform.MapPosition); var spawned = owner.EntityManager.SpawnEntity(entityId, owner.Transform.MapPosition);
owner.EntityManager.EventBus.RaiseLocalEvent(spawned.Uid, new StackChangeCountEvent(count), false); var stack = spawned.GetComponent<StackComponent>();
EntitySystem.Get<StackSystem>().SetCount(spawned.Uid, stack, count);
spawned.RandomOffset(0.5f); spawned.RandomOffset(0.5f);
} }
else else

View File

@@ -5,6 +5,7 @@ using Content.Server.Engineering.Components;
using Content.Server.Stack; using Content.Server.Stack;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Interaction.Helpers; using Content.Shared.Interaction.Helpers;
using Content.Shared.Stacks;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;
@@ -65,20 +66,15 @@ namespace Content.Server.Engineering.EntitySystems
if (component.Deleted || component.Owner.Deleted) if (component.Deleted || component.Owner.Deleted)
return; return;
var hasStack = component.Owner.HasComponent<StackComponent>(); if (component.Owner.TryGetComponent<SharedStackComponent>(out var stackComp)
&& component.RemoveOnInteract && !Get<StackSystem>().Use(uid, stackComp, 1))
if (hasStack && component.RemoveOnInteract)
{ {
var stackUse = new StackUseEvent() {Amount = 1}; return;
RaiseLocalEvent(component.Owner.Uid, stackUse);
if (!stackUse.Result)
return;
} }
EntityManager.SpawnEntity(component.Prototype, args.ClickLocation.SnapToGrid(grid)); EntityManager.SpawnEntity(component.Prototype, args.ClickLocation.SnapToGrid(grid));
if (component.RemoveOnInteract && !hasStack && !component.Owner.Deleted) if (component.RemoveOnInteract && stackComp == null && !component.Owner.Deleted)
component.Owner.Delete(); component.Owner.Delete();
} }
} }

View File

@@ -188,13 +188,12 @@ namespace Content.Server.Hands
} }
else else
{ {
var splitStack = new StackSplitEvent() { Amount = 1, SpawnPosition = playerEnt.Transform.Coordinates }; var splitStack = Get<StackSystem>().Split(throwEnt.Uid, stackComp, 1, playerEnt.Transform.Coordinates);
RaiseLocalEvent(throwEnt.Uid, splitStack);
if (splitStack.Result == null) if (splitStack == null)
return false; return false;
throwEnt = splitStack.Result; throwEnt = splitStack;
} }
var direction = coords.ToMapPos(EntityManager) - playerEnt.Transform.WorldPosition; var direction = coords.ToMapPos(EntityManager) - playerEnt.Transform.WorldPosition;

View File

@@ -6,6 +6,7 @@ using Content.Shared.Damage;
using Content.Shared.Damage.Components; using Content.Shared.Damage.Components;
using Content.Shared.Interaction; using Content.Shared.Interaction;
using Content.Shared.Interaction.Helpers; using Content.Shared.Interaction.Helpers;
using Content.Shared.Stacks;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.Manager.Attributes;
@@ -41,13 +42,9 @@ namespace Content.Server.Medical.Components
return true; return true;
} }
if (Owner.HasComponent<StackComponent>()) if (Owner.TryGetComponent<SharedStackComponent>(out var stack) && !EntitySystem.Get<StackSystem>().Use(Owner.Uid, stack, 1))
{ {
var stackUse = new StackUseEvent() {Amount = 1}; return true;
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, stackUse);
if(!stackUse.Result)
return true;
} }
foreach (var (type, amount) in Heal) foreach (var (type, amount) in Heal)

View File

@@ -25,77 +25,63 @@ namespace Content.Server.Stack
base.Initialize(); base.Initialize();
SubscribeLocalEvent<StackComponent, InteractUsingEvent>(OnStackInteractUsing); SubscribeLocalEvent<StackComponent, InteractUsingEvent>(OnStackInteractUsing);
// The following subscriptions are basically the "method calls" of this entity system.
SubscribeLocalEvent<StackComponent, StackUseEvent>(OnStackUse);
SubscribeLocalEvent<StackComponent, StackSplitEvent>(OnStackSplit);
SubscribeLocalEvent<StackTypeSpawnEvent>(OnStackTypeSpawn);
} }
/// <summary> /// <summary>
/// Try to use an amount of items on this stack. /// Try to use an amount of items on this stack. Returns whether this succeeded.
/// See <see cref="StackUseEvent"/>
/// </summary> /// </summary>
private void OnStackUse(EntityUid uid, StackComponent stack, StackUseEvent args) public bool Use(EntityUid uid, SharedStackComponent stack, int amount)
{ {
// Check if we have enough things in the stack for this... // Check if we have enough things in the stack for this...
if (stack.Count < args.Amount) if (stack.Count <= amount)
{ {
// Not enough things in the stack, so we set the output result to false. // Not enough things in the stack, return false.
args.Result = false; return false;
}
else
{
// We do have enough things in the stack, so remove them and set the output result to true.
RaiseLocalEvent(uid, new StackChangeCountEvent(stack.Count - args.Amount), false);
args.Result = true;
} }
// We do have enough things in the stack, so remove them and change.
SetCount(uid, stack, stack.Count - amount);
return true;
} }
/// <summary> /// <summary>
/// Try to split this stack into two. /// Try to split this stack into two. Returns a non-null <see cref="IEntity"/> if successful.
/// See <see cref="StackSplitEvent"/>
/// </summary> /// </summary>
private void OnStackSplit(EntityUid uid, StackComponent stack, StackSplitEvent args) public IEntity? Split(EntityUid uid, SharedStackComponent stack, int amount, EntityCoordinates spawnPosition)
{ {
// If the stack doesn't have enough things as specified in the parameters, we do nothing.
if (stack.Count < args.Amount)
return;
// Get a prototype ID to spawn the new entity. Null is also valid, although it should rarely be picked... // Get a prototype ID to spawn the new entity. Null is also valid, although it should rarely be picked...
var prototype = _prototypeManager.TryIndex<StackPrototype>(stack.StackTypeId, out var stackType) var prototype = _prototypeManager.TryIndex<StackPrototype>(stack.StackTypeId, out var stackType)
? stackType.Spawn ? stackType.Spawn
: stack.Owner.Prototype?.ID ?? null; : stack.Owner.Prototype?.ID ?? null;
// Remove the amount of things we want to split from the original stack... // Try to remove the amount of things we want to split from the original stack...
RaiseLocalEvent(uid, new StackChangeCountEvent(stack.Count - args.Amount), false); if (!Use(uid, stack, amount))
return null;
// Set the output parameter in the event instance to the newly split stack. // Set the output parameter in the event instance to the newly split stack.
args.Result = EntityManager.SpawnEntity(prototype, args.SpawnPosition); var entity = EntityManager.SpawnEntity(prototype, spawnPosition);
if (args.Result.TryGetComponent(out StackComponent? stackComp)) if (ComponentManager.TryGetComponent(entity.Uid, out SharedStackComponent? stackComp))
{ {
// Set the split stack's count. // Set the split stack's count.
RaiseLocalEvent(args.Result.Uid, new StackChangeCountEvent(args.Amount), false); SetCount(entity.Uid, stackComp, amount);
} }
return entity;
} }
/// <summary> /// <summary>
/// Tries to spawn a stack of a certain type. /// Spawns a stack of a certain stack type. See <see cref="StackPrototype"/>.
/// See <see cref="StackTypeSpawnEvent"/>
/// </summary> /// </summary>
private void OnStackTypeSpawn(StackTypeSpawnEvent args) public IEntity Spawn(int amount, StackPrototype prototype, EntityCoordinates spawnPosition)
{ {
// Can't spawn a stack for an invalid type.
if (args.StackType == null)
return;
// Set the output result parameter to the new stack entity... // Set the output result parameter to the new stack entity...
args.Result = EntityManager.SpawnEntity(args.StackType.Spawn, args.SpawnPosition); var entity = EntityManager.SpawnEntity(prototype.Spawn, spawnPosition);
var stack = args.Result.GetComponent<StackComponent>(); var stack = ComponentManager.GetComponent<StackComponent>(entity.Uid);
// And finally, set the correct amount! // And finally, set the correct amount!
RaiseLocalEvent(args.Result.Uid, new StackChangeCountEvent(args.Amount), false); SetCount(entity.Uid, stack, amount);
return entity;
} }
private void OnStackInteractUsing(EntityUid uid, StackComponent stack, InteractUsingEvent args) private void OnStackInteractUsing(EntityUid uid, StackComponent stack, InteractUsingEvent args)
@@ -107,8 +93,8 @@ namespace Content.Server.Stack
return; return;
var toTransfer = Math.Min(stack.Count, otherStack.AvailableSpace); var toTransfer = Math.Min(stack.Count, otherStack.AvailableSpace);
RaiseLocalEvent(uid, new StackChangeCountEvent(stack.Count - toTransfer), false); SetCount(uid, stack, stack.Count - toTransfer);
RaiseLocalEvent(args.Used.Uid, new StackChangeCountEvent(otherStack.Count + toTransfer), false); SetCount(args.Used.Uid, otherStack, otherStack.Count + toTransfer);
var popupPos = args.ClickLocation; var popupPos = args.ClickLocation;
if (!popupPos.IsValid(EntityManager)) if (!popupPos.IsValid(EntityManager))
@@ -145,110 +131,4 @@ namespace Content.Server.Stack
args.Handled = true; args.Handled = true;
} }
} }
/*
* The following events are actually funny ECS method calls!
*
* Instead of coupling systems together into a ball of spaghetti,
* we raise events that act as method calls.
*
* So for example, instead of having an Use() method in the
* stack component or stack system, we have a StackUseEvent.
* Before raising the event, you would set the Amount property,
* which acts as a parameter or argument, and afterwards the
* entity system in charge of handling this would perform the logic
* and then set the Result on the event instance.
* Then you can access this property to see whether your Use attempt succeeded.
*
* This is very powerful, as it completely removes the coupling
* between entity systems and allows for greater flexibility.
* If you want to intercept this event with another entity system, you can.
* And you don't have to write any bad, hacky code for this!
* You could even use handled events, or cancellable events...
* The possibilities are endless.
*
* Of course, not everything needs to be directed events!
* Broadcast events also work in the same way.
* For example, we use a broadcast event to spawn a stack of a certain type.
*
* Wrapping your head around this may be difficult at first,
* but soon you'll get it, coder. Soon you'll grasp the wisdom.
* Go forth and write some beautiful and robust code!
*/
/// <summary>
/// Uses an amount of things from a stack.
/// Whether this succeeded is stored in <see cref="Result"/>.
/// </summary>
public class StackUseEvent : EntityEventArgs
{
/// <summary>
/// The amount of things to use on the stack.
/// Consider this the equivalent of a parameter for a method call.
/// </summary>
public int Amount { get; init; }
/// <summary>
/// Whether the action succeeded or not.
/// Set by the <see cref="StackSystem"/> after handling this event.
/// Consider this the equivalent of a return value for a method call.
/// </summary>
public bool Result { get; set; } = false;
}
/// <summary>
/// Tries to split a stack into two.
/// If this succeeds, <see cref="Result"/> will be the new stack.
/// </summary>
public class StackSplitEvent : EntityEventArgs
{
/// <summary>
/// The amount of things to take from the original stack.
/// Input parameter.
/// </summary>
public int Amount { get; init; }
/// <summary>
/// The position where to spawn the new stack.
/// Input parameter.
/// </summary>
public EntityCoordinates SpawnPosition { get; init; }
/// <summary>
/// The newly split stack. May be null if the split failed.
/// Output parameter.
/// </summary>
public IEntity? Result { get; set; } = null;
}
/// <summary>
/// Tries to spawn a stack of a certain type.
/// If this succeeds, <see cref="Result"/> will be the new stack.
/// </summary>
public class StackTypeSpawnEvent : EntityEventArgs
{
/// <summary>
/// The amount of things the spawned stack will have.
/// Input parameter.
/// </summary>
public int Amount { get; init; }
/// <summary>
/// The stack type to be spawned.
/// Input parameter.
/// </summary>
public StackPrototype? StackType { get; init; }
/// <summary>
/// The position where the new stack will be spawned.
/// Input parameter.
/// </summary>
public EntityCoordinates SpawnPosition { get; init; }
/// <summary>
/// The newly spawned stack, or null if this failed.
/// Output parameter.
/// </summary>
public IEntity? Result { get; set; } = null;
}
} }

View File

@@ -80,10 +80,7 @@ namespace Content.Server.Tiles
if (HasBaseTurf(currentTileDefinition, baseTurf.Name)) if (HasBaseTurf(currentTileDefinition, baseTurf.Name))
{ {
var stackUse = new StackUseEvent() {Amount = 1}; if (!EntitySystem.Get<StackSystem>().Use(Owner.Uid, stack, 1))
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, stackUse);
if (!stackUse.Result)
continue; continue;
PlaceAt(mapGrid, location, currentTileDefinition.TileId); PlaceAt(mapGrid, location, currentTileDefinition.TileId);

View File

@@ -44,8 +44,8 @@ namespace Content.Server.Wires.Components
var droppedEnt = Owner.EntityManager.SpawnEntity(_wireDroppedOnCutPrototype, eventArgs.ClickLocation); var droppedEnt = Owner.EntityManager.SpawnEntity(_wireDroppedOnCutPrototype, eventArgs.ClickLocation);
// TODO: Literally just use a prototype that has a single thing in the stack, it's not that complicated... // TODO: Literally just use a prototype that has a single thing in the stack, it's not that complicated...
if (droppedEnt.HasComponent<StackComponent>()) if (droppedEnt.TryGetComponent<StackComponent>(out var stack))
Owner.EntityManager.EventBus.RaiseLocalEvent(droppedEnt.Uid, new StackChangeCountEvent(1), false); EntitySystem.Get<StackSystem>().SetCount(droppedEnt.Uid, stack, 1);
return true; return true;
} }

View File

@@ -47,14 +47,9 @@ namespace Content.Server.Wires.Components
} }
} }
if (Owner.HasComponent<StackComponent>()) if (Owner.TryGetComponent<StackComponent>(out var stack)
{ && !EntitySystem.Get<StackSystem>().Use(Owner.Uid, stack, 1))
var stackUse = new StackUseEvent(){Amount = 1}; return true;
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, stackUse);
if(!stackUse.Result)
return true;
}
Owner.EntityManager.SpawnEntity(_wirePrototypeID, grid.GridTileToLocal(snapPos)); Owner.EntityManager.SpawnEntity(_wirePrototypeID, grid.GridTileToLocal(snapPos));
return true; return true;

View File

@@ -57,7 +57,7 @@ namespace Content.Shared.Stacks
return; return;
// This will change the count and call events. // This will change the count and call events.
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new StackChangeCountEvent(cast.Count)); EntitySystem.Get<SharedStackSystem>().SetCount(Owner.Uid, this, cast.Count);
MaxCount = cast.MaxCount; MaxCount = cast.MaxCount;
} }

View File

@@ -12,7 +12,6 @@ namespace Content.Shared.Stacks
base.Initialize(); base.Initialize();
SubscribeLocalEvent<SharedStackComponent, ComponentStartup>(OnStackStarted); SubscribeLocalEvent<SharedStackComponent, ComponentStartup>(OnStackStarted);
SubscribeLocalEvent<SharedStackComponent, StackChangeCountEvent>(OnStackCountChange);
SubscribeLocalEvent<SharedStackComponent, ExaminedEvent>(OnStackExamined); SubscribeLocalEvent<SharedStackComponent, ExaminedEvent>(OnStackExamined);
} }
@@ -26,26 +25,27 @@ namespace Content.Shared.Stacks
appearance.SetData(StackVisuals.Hide, false); appearance.SetData(StackVisuals.Hide, false);
} }
protected void OnStackCountChange(EntityUid uid, SharedStackComponent component, StackChangeCountEvent args) public void SetCount(EntityUid uid, SharedStackComponent component, int amount)
{ {
if (args.Amount == component.Count) // Do nothing if amount is already the same.
if (amount == component.Count)
return; return;
// Store old value for event-raising purposes...
var old = component.Count; var old = component.Count;
if (args.Amount > component.MaxCount) // Clamp the value.
if (amount > component.MaxCount)
{ {
args.Amount = component.MaxCount; amount = component.MaxCount;
args.Clamped = true;
} }
if (args.Amount < 0) if (amount < 0)
{ {
args.Amount = 0; amount = 0;
args.Clamped = true;
} }
component.Count = args.Amount; component.Count = amount;
component.Dirty(); component.Dirty();
// Queue delete stack if count reaches zero. // Queue delete stack if count reaches zero.
@@ -74,32 +74,6 @@ namespace Content.Shared.Stacks
} }
} }
/// <summary>
/// Attempts to change the amount of things in a stack to a specific number.
/// If the amount had to be clamped to zero or the max amount, <see cref="Clamped"/> will be true
/// and the amount will be changed to match the value set.
/// Does nothing if the amount is the same as the stack count already.
/// </summary>
public class StackChangeCountEvent : EntityEventArgs
{
/// <summary>
/// Amount to set the stack to.
/// Input/Output parameter.
/// </summary>
public int Amount { get; set; }
/// <summary>
/// Whether the <see cref="Amount"/> had to be clamped.
/// Output parameter.
/// </summary>
public bool Clamped { get; set; }
public StackChangeCountEvent(int amount)
{
Amount = amount;
}
}
/// <summary> /// <summary>
/// Event raised when a stack's count has changed. /// Event raised when a stack's count has changed.
/// </summary> /// </summary>