ItemMapper ECS (#9867)
This commit is contained in:
65
Content.Client/Storage/Systems/ItemMapperSystem.cs
Normal file
65
Content.Client/Storage/Systems/ItemMapperSystem.cs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using Content.Shared.Storage.Components;
|
||||||
|
using Content.Shared.Storage.EntitySystems;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Client.Storage.Systems;
|
||||||
|
|
||||||
|
public sealed class ItemMapperSystem : SharedItemMapperSystem
|
||||||
|
{
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
SubscribeLocalEvent<ItemMapperComponent, ComponentStartup>(OnStartup);
|
||||||
|
SubscribeLocalEvent<ItemMapperComponent, AppearanceChangeEvent>(OnAppearance);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnStartup(EntityUid uid, ItemMapperComponent component, ComponentStartup args)
|
||||||
|
{
|
||||||
|
if (TryComp<SpriteComponent>(uid, out var sprite))
|
||||||
|
{
|
||||||
|
component.RSIPath ??= sprite.BaseRSI!.Path!;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAppearance(EntityUid uid, ItemMapperComponent component, ref AppearanceChangeEvent args)
|
||||||
|
{
|
||||||
|
if (TryComp<SpriteComponent>(component.Owner, out var spriteComponent))
|
||||||
|
{
|
||||||
|
if (component.SpriteLayers.Count == 0)
|
||||||
|
{
|
||||||
|
InitLayers(component, spriteComponent, args.Component);
|
||||||
|
}
|
||||||
|
|
||||||
|
EnableLayers(component, spriteComponent, args.Component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitLayers(ItemMapperComponent component, SpriteComponent spriteComponent, AppearanceComponent appearance)
|
||||||
|
{
|
||||||
|
if (!appearance.TryGetData<ShowLayerData>(StorageMapVisuals.InitLayers, out var wrapper))
|
||||||
|
return;
|
||||||
|
|
||||||
|
component.SpriteLayers.AddRange(wrapper.QueuedEntities);
|
||||||
|
|
||||||
|
foreach (var sprite in component.SpriteLayers)
|
||||||
|
{
|
||||||
|
spriteComponent.LayerMapReserveBlank(sprite);
|
||||||
|
spriteComponent.LayerSetSprite(sprite, new SpriteSpecifier.Rsi(component.RSIPath!, sprite));
|
||||||
|
spriteComponent.LayerSetVisible(sprite, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnableLayers(ItemMapperComponent component, SpriteComponent spriteComponent, AppearanceComponent appearance)
|
||||||
|
{
|
||||||
|
if (!appearance.TryGetData<ShowLayerData>(StorageMapVisuals.LayerChanged, out var wrapper))
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var layerName in component.SpriteLayers)
|
||||||
|
{
|
||||||
|
var show = wrapper.QueuedEntities.Contains(layerName);
|
||||||
|
spriteComponent.LayerSetVisible(layerName, show);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using Content.Shared.Storage;
|
using Content.Client.Animations;
|
||||||
using Content.Client.Animations;
|
using Content.Shared.Storage;
|
||||||
|
|
||||||
namespace Content.Client.Storage;
|
namespace Content.Client.Storage.Systems;
|
||||||
|
|
||||||
// TODO kill this is all horrid.
|
// TODO kill this is all horrid.
|
||||||
public sealed class StorageSystem : EntitySystem
|
public sealed class StorageSystem : EntitySystem
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Content.Shared.Storage.Components;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
|
||||||
using Robust.Shared.Utility;
|
|
||||||
|
|
||||||
namespace Content.Client.Storage.Visualizers
|
|
||||||
{
|
|
||||||
[UsedImplicitly]
|
|
||||||
public sealed class MappedItemVisualizer : AppearanceVisualizer
|
|
||||||
{
|
|
||||||
[DataField("sprite")] private ResourcePath? _rsiPath;
|
|
||||||
private List<string> _spriteLayers = new();
|
|
||||||
|
|
||||||
public override void InitializeEntity(EntityUid entity)
|
|
||||||
{
|
|
||||||
base.InitializeEntity(entity);
|
|
||||||
|
|
||||||
if (IoCManager.Resolve<IEntityManager>().TryGetComponent<ISpriteComponent?>(entity, out var spriteComponent))
|
|
||||||
{
|
|
||||||
_rsiPath ??= spriteComponent.BaseRSI!.Path!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override void OnChangeData(AppearanceComponent component)
|
|
||||||
{
|
|
||||||
base.OnChangeData(component);
|
|
||||||
|
|
||||||
var entities = IoCManager.Resolve<IEntityManager>();
|
|
||||||
if (entities.TryGetComponent(component.Owner, out ISpriteComponent? 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,36 +1,9 @@
|
|||||||
using System.Linq;
|
using Content.Shared.Storage.EntitySystems;
|
||||||
using Content.Shared.Storage.Components;
|
|
||||||
using Content.Shared.Storage.EntitySystems;
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.Containers;
|
|
||||||
|
|
||||||
namespace Content.Server.Storage.EntitySystems
|
namespace Content.Server.Storage.EntitySystems
|
||||||
{
|
{
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public sealed class ItemMapperSystem : SharedItemMapperSystem
|
public sealed class ItemMapperSystem : SharedItemMapperSystem {}
|
||||||
{
|
|
||||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
|
||||||
|
|
||||||
protected override bool TryGetLayers(ContainerModifiedMessage msg,
|
|
||||||
ItemMapperComponent itemMapper,
|
|
||||||
out IReadOnlyList<string> showLayers)
|
|
||||||
{
|
|
||||||
var containedLayers = _containerSystem.GetAllContainers(msg.Container.Owner)
|
|
||||||
.SelectMany(cont => cont.ContainedEntities).ToArray();
|
|
||||||
|
|
||||||
var list = new List<string>();
|
|
||||||
foreach (var mapLayerData in itemMapper.MapLayers.Values)
|
|
||||||
{
|
|
||||||
var count = containedLayers.Count(uid => mapLayerData.ServerWhitelist.IsValid(uid));
|
|
||||||
if (count >= mapLayerData.MinCount && count <= mapLayerData.MaxCount)
|
|
||||||
{
|
|
||||||
list.Add(mapLayerData.Layer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
showLayers = list;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using Content.Shared.Audio;
|
using Content.Shared.Audio;
|
||||||
using Content.Shared.Buckle.Components;
|
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Damage.Prototypes;
|
using Content.Shared.Damage.Prototypes;
|
||||||
using Content.Shared.Hands.EntitySystems;
|
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
@@ -12,7 +10,6 @@ namespace Content.Shared.Blocking;
|
|||||||
|
|
||||||
public sealed class BlockingUserSystem : EntitySystem
|
public sealed class BlockingUserSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
|
||||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||||
[Dependency] private readonly BlockingSystem _blockingSystem = default!;
|
[Dependency] private readonly BlockingSystem _blockingSystem = default!;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using Content.Shared.Storage.EntitySystems;
|
using Content.Shared.Storage.EntitySystems;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Shared.Storage.Components
|
namespace Content.Shared.Storage.Components
|
||||||
{
|
{
|
||||||
@@ -54,17 +54,12 @@ namespace Content.Shared.Storage.Components
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
[Access(typeof(SharedItemMapperSystem))]
|
[Access(typeof(SharedItemMapperSystem))]
|
||||||
public sealed class ItemMapperComponent : Component, ISerializationHooks
|
public sealed class ItemMapperComponent : Component
|
||||||
{
|
{
|
||||||
[DataField("mapLayers")] public readonly Dictionary<string, SharedMapLayerData> MapLayers = new();
|
[DataField("mapLayers")] public readonly Dictionary<string, SharedMapLayerData> MapLayers = new();
|
||||||
|
|
||||||
void ISerializationHooks.AfterDeserialization()
|
[DataField("sprite")] public ResourcePath? RSIPath;
|
||||||
{
|
|
||||||
foreach (var (layerName, val) in MapLayers)
|
|
||||||
{
|
|
||||||
val.Layer = layerName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public readonly List<string> SpriteLayers = new();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Shared.Storage.Components;
|
using System.Linq;
|
||||||
|
using Content.Shared.Storage.Components;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.Containers;
|
using Robust.Shared.Containers;
|
||||||
|
|
||||||
@@ -12,6 +13,8 @@ namespace Content.Shared.Storage.EntitySystems
|
|||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public abstract class SharedItemMapperSystem : EntitySystem
|
public abstract class SharedItemMapperSystem : EntitySystem
|
||||||
{
|
{
|
||||||
|
[Dependency] private readonly SharedContainerSystem _container = default!;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Initialize()
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
@@ -23,6 +26,11 @@ namespace Content.Shared.Storage.EntitySystems
|
|||||||
|
|
||||||
private void InitLayers(EntityUid uid, ItemMapperComponent component, ComponentInit args)
|
private void InitLayers(EntityUid uid, ItemMapperComponent component, ComponentInit args)
|
||||||
{
|
{
|
||||||
|
foreach (var (layerName, val) in component.MapLayers)
|
||||||
|
{
|
||||||
|
val.Layer = layerName;
|
||||||
|
}
|
||||||
|
|
||||||
if (EntityManager.TryGetComponent(component.Owner, out AppearanceComponent? appearanceComponent))
|
if (EntityManager.TryGetComponent(component.Owner, out AppearanceComponent? appearanceComponent))
|
||||||
{
|
{
|
||||||
var list = new List<string>(component.MapLayers.Keys);
|
var list = new List<string>(component.MapLayers.Keys);
|
||||||
@@ -61,8 +69,25 @@ namespace Content.Shared.Storage.EntitySystems
|
|||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="containedLayers">list of <paramref name="itemMapper"/> layers that should be visible</param>
|
/// <param name="containedLayers">list of <paramref name="itemMapper"/> layers that should be visible</param>
|
||||||
/// <returns>false if <c>msg.Container.Owner</c> is not a storage, true otherwise.</returns>
|
/// <returns>false if <c>msg.Container.Owner</c> is not a storage, true otherwise.</returns>
|
||||||
protected abstract bool TryGetLayers(ContainerModifiedMessage msg,
|
private bool TryGetLayers(ContainerModifiedMessage msg,
|
||||||
ItemMapperComponent itemMapper,
|
ItemMapperComponent itemMapper,
|
||||||
out IReadOnlyList<string> containedLayers);
|
out IReadOnlyList<string> showLayers)
|
||||||
|
{
|
||||||
|
var containedLayers = _container.GetAllContainers(msg.Container.Owner)
|
||||||
|
.SelectMany(cont => cont.ContainedEntities).ToArray();
|
||||||
|
|
||||||
|
var list = new List<string>();
|
||||||
|
foreach (var mapLayerData in itemMapper.MapLayers.Values)
|
||||||
|
{
|
||||||
|
var count = containedLayers.Count(uid => mapLayerData.ServerWhitelist.IsValid(uid));
|
||||||
|
if (count >= mapLayerData.MinCount && count <= mapLayerData.MaxCount)
|
||||||
|
{
|
||||||
|
list.Add(mapLayerData.Layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showLayers = list;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototy
|
|||||||
namespace Content.Shared.Tag
|
namespace Content.Shared.Tag
|
||||||
{
|
{
|
||||||
[RegisterComponent, Access(typeof(TagSystem))]
|
[RegisterComponent, Access(typeof(TagSystem))]
|
||||||
public sealed class TagComponent : Component, ISerializationHooks
|
public sealed class TagComponent : Component
|
||||||
{
|
{
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
[DataField("tags", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<TagPrototype>))]
|
[DataField("tags", customTypeSerializer: typeof(PrototypeIdHashSetSerializer<TagPrototype>))]
|
||||||
|
|||||||
@@ -57,10 +57,8 @@
|
|||||||
whitelist:
|
whitelist:
|
||||||
components:
|
components:
|
||||||
- SignalLinker
|
- SignalLinker
|
||||||
- type: Appearance
|
|
||||||
visuals:
|
|
||||||
- type: MappedItemVisualizer
|
|
||||||
sprite: Clothing/Belt/belt_overlay.rsi
|
sprite: Clothing/Belt/belt_overlay.rsi
|
||||||
|
- type: Appearance
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingBeltStorageBase
|
parent: ClothingBeltStorageBase
|
||||||
@@ -132,10 +130,8 @@
|
|||||||
whitelist:
|
whitelist:
|
||||||
tags:
|
tags:
|
||||||
- Wrench
|
- Wrench
|
||||||
- type: Appearance
|
|
||||||
visuals:
|
|
||||||
- type: MappedItemVisualizer
|
|
||||||
sprite: Clothing/Belt/belt_overlay.rsi
|
sprite: Clothing/Belt/belt_overlay.rsi
|
||||||
|
- type: Appearance
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingBeltStorageBase
|
parent: ClothingBeltStorageBase
|
||||||
@@ -169,10 +165,8 @@
|
|||||||
whitelist:
|
whitelist:
|
||||||
components:
|
components:
|
||||||
- Stunbaton
|
- Stunbaton
|
||||||
- type: Appearance
|
|
||||||
visuals:
|
|
||||||
- type: MappedItemVisualizer
|
|
||||||
sprite: Clothing/Belt/belt_overlay.rsi
|
sprite: Clothing/Belt/belt_overlay.rsi
|
||||||
|
- type: Appearance
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingBeltStorageBase
|
parent: ClothingBeltStorageBase
|
||||||
@@ -210,10 +204,8 @@
|
|||||||
whitelist:
|
whitelist:
|
||||||
tags:
|
tags:
|
||||||
- Wrench
|
- Wrench
|
||||||
- type: Appearance
|
|
||||||
visuals:
|
|
||||||
- type: MappedItemVisualizer
|
|
||||||
sprite: Clothing/Belt/belt_overlay.rsi
|
sprite: Clothing/Belt/belt_overlay.rsi
|
||||||
|
- type: Appearance
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingBeltStorageBase
|
parent: ClothingBeltStorageBase
|
||||||
@@ -272,10 +264,8 @@
|
|||||||
whitelist:
|
whitelist:
|
||||||
tags:
|
tags:
|
||||||
- Wrench
|
- Wrench
|
||||||
- type: Appearance
|
|
||||||
visuals:
|
|
||||||
- type: MappedItemVisualizer
|
|
||||||
sprite: Clothing/Belt/belt_overlay.rsi
|
sprite: Clothing/Belt/belt_overlay.rsi
|
||||||
|
- type: Appearance
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingBeltStorageBase
|
parent: ClothingBeltStorageBase
|
||||||
@@ -329,10 +319,8 @@
|
|||||||
whitelist:
|
whitelist:
|
||||||
tags:
|
tags:
|
||||||
- Bottle
|
- Bottle
|
||||||
- type: Appearance
|
|
||||||
visuals:
|
|
||||||
- type: MappedItemVisualizer
|
|
||||||
sprite: Clothing/Belt/belt_overlay.rsi
|
sprite: Clothing/Belt/belt_overlay.rsi
|
||||||
|
- type: Appearance
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingBeltStorageBase
|
parent: ClothingBeltStorageBase
|
||||||
@@ -364,10 +352,8 @@
|
|||||||
whitelist:
|
whitelist:
|
||||||
components:
|
components:
|
||||||
- Stunbaton
|
- Stunbaton
|
||||||
- type: Appearance
|
|
||||||
visuals:
|
|
||||||
- type: MappedItemVisualizer
|
|
||||||
sprite: Clothing/Belt/belt_overlay.rsi
|
sprite: Clothing/Belt/belt_overlay.rsi
|
||||||
|
- type: Appearance
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingBeltStorageBase
|
parent: ClothingBeltStorageBase
|
||||||
@@ -392,8 +378,6 @@
|
|||||||
tags:
|
tags:
|
||||||
- CaptainSabre
|
- CaptainSabre
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
|
||||||
- type: MappedItemVisualizer
|
|
||||||
|
|
||||||
# Belts without visualizers
|
# Belts without visualizers
|
||||||
|
|
||||||
|
|||||||
@@ -313,7 +313,4 @@
|
|||||||
whitelist:
|
whitelist:
|
||||||
tags:
|
tags:
|
||||||
- CrayonYellow
|
- CrayonYellow
|
||||||
|
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
|
||||||
- type: MappedItemVisualizer
|
|
||||||
|
|||||||
@@ -164,8 +164,6 @@
|
|||||||
tags:
|
tags:
|
||||||
- Document
|
- Document
|
||||||
- type: Appearance
|
- type: Appearance
|
||||||
visuals:
|
|
||||||
- type: MappedItemVisualizer
|
|
||||||
- type: Tag
|
- type: Tag
|
||||||
tags:
|
tags:
|
||||||
- Folder
|
- Folder
|
||||||
|
|||||||
@@ -207,10 +207,8 @@
|
|||||||
whitelist:
|
whitelist:
|
||||||
tags:
|
tags:
|
||||||
- WetFloorSign
|
- WetFloorSign
|
||||||
- type: Appearance
|
|
||||||
visuals:
|
|
||||||
- type: MappedItemVisualizer
|
|
||||||
sprite: Objects/Specific/Janitorial/janitorial_cart.rsi
|
sprite: Objects/Specific/Janitorial/janitorial_cart.rsi
|
||||||
|
- type: Appearance
|
||||||
- type: SolutionContainerVisuals
|
- type: SolutionContainerVisuals
|
||||||
maxFillLevels: 3
|
maxFillLevels: 3
|
||||||
fillBaseName: cart_water-
|
fillBaseName: cart_water-
|
||||||
|
|||||||
@@ -148,10 +148,8 @@
|
|||||||
whitelist:
|
whitelist:
|
||||||
tags:
|
tags:
|
||||||
- TrashBag
|
- TrashBag
|
||||||
- type: Appearance
|
|
||||||
visuals:
|
|
||||||
- type: MappedItemVisualizer
|
|
||||||
sprite: Objects/Vehicles/pussywagon.rsi
|
sprite: Objects/Vehicles/pussywagon.rsi
|
||||||
|
- type: Appearance
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: VehiclePussyWagonDestroyed
|
id: VehiclePussyWagonDestroyed
|
||||||
|
|||||||
Reference in New Issue
Block a user