Added mapped storage for things like crayon belts and tools (#4201)
* Added mapped storage for things like crayon belts and tools * Attempt to get StorageFillEvent to work * Managed to get it working with Visualizer logi * Improved PR and did some light refactoring of components * Update Content.Client/Storage/Visualizers/MappedItemVisualizer.cs Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * Removed event, went with stateful ApperanceData * Removed ids in favor of whitelist * Refactor YAML, Moved functionality to Shared and renamed it. * Changed so insert/remove always send full state. * Move logic to component * Fix some issues on MappedVisualizer and few nitpicks - Fix mapped visualizer only doing init or update layers - Fixed naming of systems - Fixed sort of crayons * Forgot to apply Vera's suggestion * Fix the data to be more strict and to avoid unnecessary clearing Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
This commit is contained in:
71
Content.Client/Storage/Visualizers/MappedItemVisualizer.cs
Normal file
71
Content.Client/Storage/Visualizers/MappedItemVisualizer.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Shared.Storage.ItemCounter;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.Storage.Visualizers
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class MappedItemVisualizer : AppearanceVisualizer
|
||||
{
|
||||
[DataField("sprite")] private ResourcePath? _rsiPath;
|
||||
private List<string> _spriteLayers = new();
|
||||
|
||||
public override void InitializeEntity(IEntity entity)
|
||||
{
|
||||
base.InitializeEntity(entity);
|
||||
|
||||
if (entity.TryGetComponent<ISpriteComponent>(out var spriteComponent))
|
||||
{
|
||||
_rsiPath ??= spriteComponent.BaseRSI!.Path!;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void OnChangeData(AppearanceComponent component)
|
||||
{
|
||||
base.OnChangeData(component);
|
||||
if (component.Owner.TryGetComponent<ISpriteComponent>(out var spriteComponent))
|
||||
{
|
||||
if (_spriteLayers.Count == 0)
|
||||
{
|
||||
InitLayers(spriteComponent, component);
|
||||
}
|
||||
EnableLayers(spriteComponent, component);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void InitLayers(ISpriteComponent spriteComponent, AppearanceComponent component)
|
||||
{
|
||||
if (!component.TryGetData<ShowLayerData>(StorageMapVisuals.InitLayers, out var wrapper))
|
||||
return;
|
||||
|
||||
_spriteLayers.AddRange(wrapper.QueuedEntities);
|
||||
|
||||
foreach (var sprite in _spriteLayers)
|
||||
{
|
||||
spriteComponent.LayerMapReserveBlank(sprite);
|
||||
spriteComponent.LayerSetSprite(sprite, new SpriteSpecifier.Rsi(_rsiPath!, sprite));
|
||||
spriteComponent.LayerSetVisible(sprite, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnableLayers(ISpriteComponent spriteComponent, AppearanceComponent component)
|
||||
{
|
||||
if (!component.TryGetData<ShowLayerData>(StorageMapVisuals.LayerChanged, out var wrapper))
|
||||
return;
|
||||
|
||||
|
||||
foreach (var layerName in _spriteLayers)
|
||||
{
|
||||
var show = wrapper.QueuedEntities.Contains(layerName);
|
||||
spriteComponent.LayerSetVisible(layerName, show);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Stacks;
|
||||
using Content.Shared.Tag;
|
||||
@@ -21,6 +22,7 @@ namespace Content.Server.Storage.Components
|
||||
/// amount: 6 # Note: this field can be omitted
|
||||
/// countTag: Cigarette # Note: field doesn't point to entity Id, but its tag
|
||||
/// </code>
|
||||
[Obsolete("Should be deprecated in favor of SharedItemCounterSystem")]
|
||||
[RegisterComponent]
|
||||
public class StorageCounterComponent : Component, ISerializationHooks
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Storage;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
@@ -16,8 +17,7 @@ namespace Content.Server.Storage.Components
|
||||
{
|
||||
public override string Name => "StorageFill";
|
||||
|
||||
[DataField("contents")]
|
||||
private List<StorageFillEntry> _contents = new();
|
||||
[DataField("contents")] private List<StorageFillEntry> _contents = new();
|
||||
|
||||
public IReadOnlyList<StorageFillEntry> Contents => _contents;
|
||||
|
||||
@@ -40,7 +40,8 @@ namespace Content.Server.Storage.Components
|
||||
foreach (var storageItem in _contents)
|
||||
{
|
||||
if (string.IsNullOrEmpty(storageItem.PrototypeId)) continue;
|
||||
if (!string.IsNullOrEmpty(storageItem.GroupId) && alreadySpawnedGroups.Contains(storageItem.GroupId)) continue;
|
||||
if (!string.IsNullOrEmpty(storageItem.GroupId) &&
|
||||
alreadySpawnedGroups.Contains(storageItem.GroupId)) continue;
|
||||
|
||||
if (storageItem.SpawnProbability != 1f &&
|
||||
!random.Prob(storageItem.SpawnProbability))
|
||||
@@ -50,8 +51,10 @@ namespace Content.Server.Storage.Components
|
||||
|
||||
for (var i = 0; i < storageItem.Amount; i++)
|
||||
{
|
||||
storage.Insert(Owner.EntityManager.SpawnEntity(storageItem.PrototypeId, Owner.Transform.Coordinates));
|
||||
storage.Insert(
|
||||
Owner.EntityManager.SpawnEntity(storageItem.PrototypeId, Owner.Transform.Coordinates));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(storageItem.GroupId)) alreadySpawnedGroups.Add(storageItem.GroupId);
|
||||
}
|
||||
}
|
||||
@@ -63,13 +66,13 @@ namespace Content.Server.Storage.Components
|
||||
[DataField("id", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
public string? PrototypeId;
|
||||
|
||||
[DataField("prob")]
|
||||
public float SpawnProbability;
|
||||
[DataField("prob")] public float SpawnProbability;
|
||||
|
||||
/// <summary>
|
||||
/// The probability that an item will spawn. Takes decimal form so 0.05 is 5%, 0.50 is 50% etc.
|
||||
/// </summary>
|
||||
[DataField("orGroup")]
|
||||
public string GroupId;
|
||||
[DataField("orGroup")] public string GroupId;
|
||||
|
||||
/// <summary>
|
||||
/// orGroup signifies to pick between entities designated with an ID.
|
||||
///
|
||||
@@ -92,8 +95,7 @@ namespace Content.Server.Storage.Components
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// </summary>
|
||||
[DataField("amount")]
|
||||
public int Amount;
|
||||
[DataField("amount")] public int Amount;
|
||||
|
||||
public void PopulateDefaultValues()
|
||||
{
|
||||
|
||||
41
Content.Server/Storage/ItemCounterSystem.cs
Normal file
41
Content.Server/Storage/ItemCounterSystem.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Server.Storage.Components;
|
||||
using Content.Shared.Storage.ItemCounter;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.Storage
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class ItemCounterSystem : SharedItemCounterSystem
|
||||
{
|
||||
protected override bool TryGetContainer(ContainerModifiedMessage msg,
|
||||
ItemCounterComponent itemCounter,
|
||||
out IReadOnlyList<string> showLayers)
|
||||
{
|
||||
if (msg.Container.Owner.TryGetComponent(out ServerStorageComponent? component))
|
||||
{
|
||||
var containedLayers = component.StoredEntities ?? new List<IEntity>();
|
||||
var list = new List<string>();
|
||||
foreach (var mapLayerData in itemCounter.MapLayers.Values)
|
||||
{
|
||||
foreach (var entity in containedLayers)
|
||||
{
|
||||
if (mapLayerData.Whitelist.IsValid(entity))
|
||||
{
|
||||
list.Add(mapLayerData.Layer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
showLayers = list;
|
||||
return true;
|
||||
}
|
||||
|
||||
showLayers = new List<string>();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
24
Content.Shared/Storage/ItemCounter/ItemCounterComponent.cs
Normal file
24
Content.Shared/Storage/ItemCounter/ItemCounterComponent.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Shared.Storage.ItemCounter
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class ItemCounterComponent : Component, ISerializationHooks
|
||||
{
|
||||
public override string Name => "ItemCounter";
|
||||
|
||||
[DataField("mapLayers")] public readonly Dictionary<string, SharedMapLayerData> MapLayers = new();
|
||||
|
||||
void ISerializationHooks.AfterDeserialization()
|
||||
{
|
||||
foreach (var (layerName, val) in MapLayers)
|
||||
{
|
||||
val.Layer = layerName;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System.Collections.Generic;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Shared.Storage.ItemCounter
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public abstract class SharedItemCounterSystem : EntitySystem
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
SubscribeLocalEvent<ItemCounterComponent, ComponentInit>(InitLayers);
|
||||
SubscribeLocalEvent<ItemCounterComponent, EntInsertedIntoContainerMessage>(HandleEntityInsert);
|
||||
SubscribeLocalEvent<ItemCounterComponent, EntRemovedFromContainerMessage>(HandleEntityRemoved);
|
||||
}
|
||||
|
||||
private void InitLayers(EntityUid uid, ItemCounterComponent component, ComponentInit args)
|
||||
{
|
||||
if (component.Owner.TryGetComponent(out SharedAppearanceComponent? appearanceComponent))
|
||||
{
|
||||
var list = new List<string>(component.MapLayers.Keys);
|
||||
appearanceComponent.SetData(StorageMapVisuals.InitLayers, new ShowLayerData(list));
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleEntityRemoved(EntityUid uid, ItemCounterComponent itemCounter,
|
||||
EntRemovedFromContainerMessage args)
|
||||
{
|
||||
if (itemCounter.Owner.TryGetComponent(out SharedAppearanceComponent? appearanceComponent)
|
||||
&& TryGetContainer(args, itemCounter, out var containedLayers))
|
||||
{
|
||||
appearanceComponent.SetData(StorageMapVisuals.LayerChanged, new ShowLayerData(containedLayers));
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleEntityInsert(EntityUid uid, ItemCounterComponent itemCounter,
|
||||
EntInsertedIntoContainerMessage args)
|
||||
{
|
||||
if (itemCounter.Owner.TryGetComponent(out SharedAppearanceComponent? appearanceComponent)
|
||||
&& TryGetContainer(args, itemCounter, out var containedLayers))
|
||||
{
|
||||
appearanceComponent.SetData(StorageMapVisuals.LayerChanged, new ShowLayerData(containedLayers));
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract bool TryGetContainer(ContainerModifiedMessage msg,
|
||||
ItemCounterComponent itemCounter,
|
||||
out IReadOnlyList<string> containedLayers);
|
||||
}
|
||||
}
|
||||
46
Content.Shared/Storage/ItemCounter/SharedMapLayerData.cs
Normal file
46
Content.Shared/Storage/ItemCounter/SharedMapLayerData.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Shared.Storage.ItemCounter
|
||||
{
|
||||
[Serializable, NetSerializable]
|
||||
public enum StorageMapVisuals : sbyte
|
||||
{
|
||||
InitLayers,
|
||||
LayerChanged,
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
[DataDefinition]
|
||||
public class SharedMapLayerData
|
||||
{
|
||||
public string Layer = string.Empty;
|
||||
|
||||
[DataField("whitelist", required: true)]
|
||||
public EntityWhitelist Whitelist { get; set; } = new();
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public class ShowLayerData
|
||||
{
|
||||
public IReadOnlyList<string> QueuedEntities { get; internal set; }
|
||||
|
||||
public ShowLayerData()
|
||||
{
|
||||
QueuedEntities = new List<string>();
|
||||
}
|
||||
|
||||
public ShowLayerData(IReadOnlyList<string> other)
|
||||
{
|
||||
QueuedEntities = other;
|
||||
}
|
||||
|
||||
public ShowLayerData(ShowLayerData other)
|
||||
{
|
||||
QueuedEntities = other.QueuedEntities;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,30 @@
|
||||
- type: Tag
|
||||
id: Crayon
|
||||
|
||||
- type: Tag
|
||||
id: CrayonBlack
|
||||
|
||||
- type: Tag
|
||||
id: CrayonBlue
|
||||
|
||||
- type: Tag
|
||||
id: CrayonGreen
|
||||
|
||||
- type: Tag
|
||||
id: CrayonOrange
|
||||
|
||||
- type: Tag
|
||||
id: CrayonPurple
|
||||
|
||||
- type: Tag
|
||||
id: CrayonRed
|
||||
|
||||
- type: Tag
|
||||
id: CrayonWhite
|
||||
|
||||
- type: Tag
|
||||
id: CrayonYellow
|
||||
|
||||
- type: entity
|
||||
abstract: true
|
||||
parent: BaseItem
|
||||
@@ -30,6 +54,9 @@
|
||||
- type: Crayon
|
||||
color: white
|
||||
capacity: 5
|
||||
- type: Tag
|
||||
tags:
|
||||
- CrayonWhite
|
||||
|
||||
- type: entity
|
||||
parent: Crayon
|
||||
@@ -42,6 +69,9 @@
|
||||
- type: Crayon
|
||||
color: white
|
||||
capacity: 5
|
||||
- type: Tag
|
||||
tags:
|
||||
- CrayonWhite
|
||||
|
||||
- type: entity
|
||||
parent: Crayon
|
||||
@@ -54,6 +84,9 @@
|
||||
- type: Crayon
|
||||
color: black
|
||||
capacity: 5
|
||||
- type: Tag
|
||||
tags:
|
||||
- CrayonBlack
|
||||
|
||||
- type: entity
|
||||
parent: Crayon
|
||||
@@ -66,6 +99,9 @@
|
||||
- type: Crayon
|
||||
color: red
|
||||
capacity: 5
|
||||
- type: Tag
|
||||
tags:
|
||||
- CrayonRed
|
||||
|
||||
- type: entity
|
||||
parent: Crayon
|
||||
@@ -78,6 +114,9 @@
|
||||
- type: Crayon
|
||||
color: orange
|
||||
capacity: 5
|
||||
- type: Tag
|
||||
tags:
|
||||
- CrayonOrange
|
||||
|
||||
- type: entity
|
||||
parent: Crayon
|
||||
@@ -90,6 +129,9 @@
|
||||
- type: Crayon
|
||||
color: yellow
|
||||
capacity: 5
|
||||
- type: Tag
|
||||
tags:
|
||||
- CrayonYellow
|
||||
|
||||
- type: entity
|
||||
parent: Crayon
|
||||
@@ -102,6 +144,9 @@
|
||||
- type: Crayon
|
||||
color: green
|
||||
capacity: 5
|
||||
- type: Tag
|
||||
tags:
|
||||
- CrayonGreen
|
||||
|
||||
- type: entity
|
||||
parent: Crayon
|
||||
@@ -114,6 +159,9 @@
|
||||
- type: Crayon
|
||||
color: lightblue
|
||||
capacity: 5
|
||||
- type: Tag
|
||||
tags:
|
||||
- CrayonBlue
|
||||
|
||||
- type: entity
|
||||
parent: Crayon
|
||||
@@ -126,6 +174,9 @@
|
||||
- type: Crayon
|
||||
color: purple
|
||||
capacity: 5
|
||||
- type: Tag
|
||||
tags:
|
||||
- CrayonPurple
|
||||
|
||||
- type: entity
|
||||
parent: BaseItem
|
||||
@@ -152,15 +203,38 @@
|
||||
- id: CrayonBlue
|
||||
- id: CrayonPurple
|
||||
- id: CrayonBlack
|
||||
- type: ItemCounter
|
||||
mapLayers:
|
||||
black_box:
|
||||
whitelist:
|
||||
tags:
|
||||
- CrayonBlack
|
||||
blue_box:
|
||||
whitelist:
|
||||
tags:
|
||||
- CrayonBlue
|
||||
green_box:
|
||||
whitelist:
|
||||
tags:
|
||||
- CrayonGreen
|
||||
orange_box:
|
||||
whitelist:
|
||||
tags:
|
||||
- CrayonOrange
|
||||
purple_box:
|
||||
whitelist:
|
||||
tags:
|
||||
- CrayonPurple
|
||||
red_box:
|
||||
whitelist:
|
||||
tags:
|
||||
- CrayonRed
|
||||
yellow_box:
|
||||
whitelist:
|
||||
tags:
|
||||
- CrayonYellow
|
||||
|
||||
- type: Appearance
|
||||
visuals:
|
||||
- type: StackVisualizer
|
||||
composite: true
|
||||
stackLayers:
|
||||
- red_box
|
||||
- orange_box
|
||||
- yellow_box
|
||||
- green_box
|
||||
- blue_box
|
||||
- purple_box
|
||||
- black_box
|
||||
- type: MappedItemVisualizer
|
||||
|
||||
|
||||
Reference in New Issue
Block a user