Refactors stacks to be fully ECS. (#4046)

This commit is contained in:
Vera Aguilera Puerto
2021-05-26 10:20:57 +02:00
committed by GitHub
parent 0f8e330a3d
commit 33fa208214
18 changed files with 494 additions and 249 deletions

View File

@@ -30,7 +30,6 @@
<ItemGroup>
<Folder Include="GameObjects\Components\Trigger\" />
<EmbeddedResource Include="Text\Names\*.txt" />
<Folder Include="GameObjects\Components\Visualizers" />
</ItemGroup>
<Import Project="..\RobustToolbox\MSBuild\Robust.Analyzers.targets" />

View File

@@ -1,46 +1,34 @@
using System;
using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Stacks;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Players;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.ViewVariables;
namespace Content.Shared.GameObjects.Components
{
public abstract class SharedStackComponent : Component, ISerializationHooks
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private const string SerializationCache = "stack";
public sealed override string Name => "Stack";
public sealed override uint? NetID => ContentNetIDs.STACK;
[DataField("count")]
private int _count = 30;
[DataField("max")]
private int _maxCount = 30;
[ViewVariables(VVAccess.ReadWrite)]
public virtual int Count
{
get => _count;
set
{
_count = value;
if (_count <= 0)
{
Owner.Delete();
}
[DataField("stackType", required:true, customTypeSerializer:typeof(PrototypeIdSerializer<StackPrototype>))]
public string StackTypeId { get; private set; } = string.Empty;
Dirty();
}
}
/// <summary>
/// Current stack count.
/// Do NOT set this directly, raise the <see cref="StackChangeCountEvent"/> event instead.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("count")]
public int Count { get; set; } = 30;
[ViewVariables]
public int MaxCount
@@ -48,28 +36,16 @@ namespace Content.Shared.GameObjects.Components
get => _maxCount;
private set
{
if (_maxCount == value)
return;
_maxCount = value;
Dirty();
}
}
[ViewVariables] public int AvailableSpace => MaxCount - Count;
[ViewVariables]
[DataField("stackType")]
public string StackTypeId { get; } = string.Empty;
public StackPrototype StackType => _prototypeManager.Index<StackPrototype>(StackTypeId);
protected override void Startup()
{
base.Startup();
if (StackTypeId != string.Empty && !_prototypeManager.HasIndex<StackPrototype>(StackTypeId))
{
Logger.Error($"No {nameof(StackPrototype)} found with id {StackTypeId} for {Owner.Prototype?.ID ?? Owner.Name}");
}
}
public int AvailableSpace => MaxCount - Count;
public override ComponentState GetComponentState(ICommonSession player)
{
@@ -79,11 +55,10 @@ namespace Content.Shared.GameObjects.Components
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
{
if (curState is not StackComponentState cast)
{
return;
}
Count = cast.Count;
// This will change the count and call events.
Owner.EntityManager.EventBus.RaiseLocalEvent(Owner.Uid, new StackChangeCountEvent(cast.Count));
MaxCount = cast.MaxCount;
}

View File

@@ -0,0 +1,108 @@
using Content.Shared.GameObjects.Components;
using JetBrains.Annotations;
using Robust.Shared.GameObjects;
namespace Content.Shared.GameObjects.EntitySystems
{
[UsedImplicitly]
public abstract class SharedStackSystem : EntitySystem
{
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SharedStackComponent, ComponentStartup>(OnStackStarted);
SubscribeLocalEvent<SharedStackComponent, StackChangeCountEvent>(OnStackCountChange);
}
private void OnStackStarted(EntityUid uid, SharedStackComponent component, ComponentStartup args)
{
if (!ComponentManager.TryGetComponent(uid, out SharedAppearanceComponent? appearance))
return;
appearance.SetData(StackVisuals.MaxCount, component.MaxCount);
appearance.SetData(StackVisuals.Hide, false);
}
protected void OnStackCountChange(EntityUid uid, SharedStackComponent component, StackChangeCountEvent args)
{
if (args.Amount == component.Count)
return;
var old = component.Count;
if (args.Amount > component.MaxCount)
{
args.Amount = component.MaxCount;
args.Clamped = true;
}
if (args.Amount < 0)
{
args.Amount = 0;
args.Clamped = true;
}
component.Count = args.Amount;
component.Dirty();
// Queue delete stack if count reaches zero.
if(component.Count <= 0)
EntityManager.QueueDeleteEntity(uid);
// Change appearance data.
if (ComponentManager.TryGetComponent(uid, out SharedAppearanceComponent? appearance))
appearance.SetData(StackVisuals.Actual, component.Count);
RaiseLocalEvent(uid, new StackCountChangedEvent(old, component.Count));
}
}
/// <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>
/// Event raised when a stack's count has changed.
/// </summary>
public class StackCountChangedEvent : EntityEventArgs
{
/// <summary>
/// The old stack count.
/// </summary>
public int OldCount { get; }
/// <summary>
/// The new stack count.
/// </summary>
public int NewCount { get; }
public StackCountChangedEvent(int oldCount, int newCount)
{
OldCount = oldCount;
NewCount = newCount;
}
}
}

View File

@@ -17,12 +17,12 @@ namespace Content.Shared.Stacks
public string Name { get; } = string.Empty;
[DataField("icon")]
public SpriteSpecifier? Icon { get; }
public SpriteSpecifier? Icon { get; } = null;
/// <summary>
/// The entity id that will be spawned by default from this stack.
/// </summary>
[DataField("spawn")]
public string? Spawn { get; }
[DataField("spawn", required: true)]
public string Spawn { get; } = string.Empty;
}
}