decal system & crayons (#5183)
Co-authored-by: Paul <ritter.paul1+git@googlemail.com>
This commit is contained in:
@@ -1,29 +0,0 @@
|
|||||||
using Content.Shared.Crayon;
|
|
||||||
using JetBrains.Annotations;
|
|
||||||
using Robust.Client.GameObjects;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.Maths;
|
|
||||||
|
|
||||||
namespace Content.Client.Crayon
|
|
||||||
{
|
|
||||||
[UsedImplicitly]
|
|
||||||
public class CrayonDecalVisualizer : AppearanceVisualizer
|
|
||||||
{
|
|
||||||
public override void OnChangeData(AppearanceComponent component)
|
|
||||||
{
|
|
||||||
base.OnChangeData(component);
|
|
||||||
|
|
||||||
var sprite = component.Owner.GetComponent<SpriteComponent>();
|
|
||||||
|
|
||||||
if (component.TryGetData(CrayonVisuals.State, out string state))
|
|
||||||
{
|
|
||||||
sprite.LayerSetState(0, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (component.TryGetData(CrayonVisuals.Color, out string color))
|
|
||||||
{
|
|
||||||
sprite.LayerSetColor(0, Color.FromName(color));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Shared.Crayon;
|
using Content.Shared.Crayon;
|
||||||
|
using Content.Shared.Decals;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
@@ -22,9 +23,8 @@ namespace Content.Client.Crayon.UI
|
|||||||
|
|
||||||
_menu.OnClose += Close;
|
_menu.OnClose += Close;
|
||||||
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
|
||||||
var crayonDecals = prototypeManager.EnumeratePrototypes<CrayonDecalPrototype>().FirstOrDefault();
|
var crayonDecals = prototypeManager.EnumeratePrototypes<DecalPrototype>().Where(x => x.Tags.Contains("crayon"));
|
||||||
if (crayonDecals != null)
|
_menu.Populate(crayonDecals);
|
||||||
_menu.Populate(crayonDecals);
|
|
||||||
_menu.OpenCentered();
|
_menu.OpenCentered();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Content.Client.Stylesheets;
|
using Content.Client.Stylesheets;
|
||||||
using Content.Shared.Crayon;
|
using Content.Shared.Crayon;
|
||||||
|
using Content.Shared.Decals;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.Graphics;
|
using Robust.Client.Graphics;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
@@ -89,14 +90,12 @@ namespace Content.Client.Crayon.UI
|
|||||||
RefreshList();
|
RefreshList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Populate(CrayonDecalPrototype proto)
|
public void Populate(IEnumerable<DecalPrototype> prototypes)
|
||||||
{
|
{
|
||||||
var path = new ResourcePath(proto.SpritePath);
|
|
||||||
_decals = new Dictionary<string, Texture>();
|
_decals = new Dictionary<string, Texture>();
|
||||||
foreach (var state in proto.Decals)
|
foreach (var decalPrototype in prototypes)
|
||||||
{
|
{
|
||||||
var rsi = new SpriteSpecifier.Rsi(path, state);
|
_decals.Add(decalPrototype.ID, decalPrototype.Sprite.Frame0());
|
||||||
_decals.Add(state, rsi.Frame0());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RefreshList();
|
RefreshList();
|
||||||
|
|||||||
60
Content.Client/Decals/DecalOverlay.cs
Normal file
60
Content.Client/Decals/DecalOverlay.cs
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Content.Shared.Decals;
|
||||||
|
using Robust.Client.Graphics;
|
||||||
|
using Robust.Client.Utility;
|
||||||
|
using Robust.Shared.Enums;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
|
||||||
|
namespace Content.Client.Decals
|
||||||
|
{
|
||||||
|
public class DecalOverlay : Overlay
|
||||||
|
{
|
||||||
|
private readonly DecalSystem _system;
|
||||||
|
private readonly IMapManager _mapManager;
|
||||||
|
private readonly IPrototypeManager _prototypeManager;
|
||||||
|
|
||||||
|
public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowEntities;
|
||||||
|
|
||||||
|
public DecalOverlay(DecalSystem system, IMapManager mapManager, IPrototypeManager prototypeManager)
|
||||||
|
{
|
||||||
|
_system = system;
|
||||||
|
_mapManager = mapManager;
|
||||||
|
_prototypeManager = prototypeManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Draw(in OverlayDrawArgs args)
|
||||||
|
{
|
||||||
|
var handle = args.WorldHandle;
|
||||||
|
|
||||||
|
Dictionary<string, SpriteSpecifier> cachedTextures = new();
|
||||||
|
|
||||||
|
SpriteSpecifier GetSpriteSpecifier(string id)
|
||||||
|
{
|
||||||
|
if (cachedTextures.TryGetValue(id, out var spriteSpecifier))
|
||||||
|
return spriteSpecifier;
|
||||||
|
|
||||||
|
spriteSpecifier = _prototypeManager.Index<DecalPrototype>(id).Sprite;
|
||||||
|
cachedTextures.Add(id, spriteSpecifier);
|
||||||
|
return spriteSpecifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (gridId, zIndexDictionary) in _system.DecalRenderIndex)
|
||||||
|
{
|
||||||
|
var grid = _mapManager.GetGrid(gridId);
|
||||||
|
handle.SetTransform(grid.WorldMatrix);
|
||||||
|
foreach (var (_, decals) in zIndexDictionary)
|
||||||
|
{
|
||||||
|
foreach (var (_, decal) in decals)
|
||||||
|
{
|
||||||
|
var spriteSpecifier = GetSpriteSpecifier(decal.Id);
|
||||||
|
handle.DrawTexture(spriteSpecifier.Frame0(), decal.Coordinates, decal.Angle, decal.Color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
114
Content.Client/Decals/DecalSystem.cs
Normal file
114
Content.Client/Decals/DecalSystem.cs
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Content.Shared.Decals;
|
||||||
|
using Robust.Client.Graphics;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
|
||||||
|
namespace Content.Client.Decals
|
||||||
|
{
|
||||||
|
public class DecalSystem : SharedDecalSystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IOverlayManager _overlayManager = default!;
|
||||||
|
|
||||||
|
private DecalOverlay _overlay = default!;
|
||||||
|
public Dictionary<GridId, SortedDictionary<int, SortedDictionary<uint, Decal>>> DecalRenderIndex = new();
|
||||||
|
private Dictionary<GridId, Dictionary<uint, int>> DecalZIndexIndex = new();
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
_overlay = new DecalOverlay(this, MapManager, PrototypeManager);
|
||||||
|
_overlayManager.AddOverlay(_overlay);
|
||||||
|
|
||||||
|
SubscribeNetworkEvent<DecalChunkUpdateEvent>(OnChunkUpdate);
|
||||||
|
SubscribeLocalEvent<GridInitializeEvent>(OnGridInitialize);
|
||||||
|
SubscribeLocalEvent<GridRemovalEvent>(OnGridRemoval);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ToggleOverlay()
|
||||||
|
{
|
||||||
|
if (_overlayManager.HasOverlay<DecalOverlay>())
|
||||||
|
{
|
||||||
|
_overlayManager.RemoveOverlay(_overlay);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_overlayManager.AddOverlay(_overlay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGridRemoval(GridRemovalEvent ev)
|
||||||
|
{
|
||||||
|
DecalRenderIndex.Remove(ev.GridId);
|
||||||
|
DecalZIndexIndex.Remove(ev.GridId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGridInitialize(GridInitializeEvent ev)
|
||||||
|
{
|
||||||
|
DecalRenderIndex[ev.GridId] = new();
|
||||||
|
DecalZIndexIndex[ev.GridId] = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Shutdown()
|
||||||
|
{
|
||||||
|
base.Shutdown();
|
||||||
|
_overlayManager.RemoveOverlay(_overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool RemoveDecalHook(GridId gridId, uint uid)
|
||||||
|
{
|
||||||
|
RemoveDecalFromRenderIndex(gridId, uid);
|
||||||
|
|
||||||
|
return base.RemoveDecalHook(gridId, uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveDecalFromRenderIndex(GridId gridId, uint uid)
|
||||||
|
{
|
||||||
|
var zIndex = DecalZIndexIndex[gridId][uid];
|
||||||
|
|
||||||
|
DecalRenderIndex[gridId][zIndex].Remove(uid);
|
||||||
|
if (DecalRenderIndex[gridId][zIndex].Count == 0)
|
||||||
|
DecalRenderIndex[gridId].Remove(zIndex);
|
||||||
|
|
||||||
|
DecalZIndexIndex[gridId].Remove(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnChunkUpdate(DecalChunkUpdateEvent ev)
|
||||||
|
{
|
||||||
|
foreach (var (gridId, gridChunks) in ev.Data)
|
||||||
|
{
|
||||||
|
foreach (var (indices, newChunkData) in gridChunks)
|
||||||
|
{
|
||||||
|
var chunkCollection = ChunkCollection(gridId);
|
||||||
|
if (chunkCollection.TryGetValue(indices, out var chunk))
|
||||||
|
{
|
||||||
|
var removedUids = new HashSet<uint>(chunk.Keys);
|
||||||
|
removedUids.ExceptWith(newChunkData.Keys);
|
||||||
|
foreach (var removedUid in removedUids)
|
||||||
|
{
|
||||||
|
RemoveDecalFromRenderIndex(gridId, removedUid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var (uid, decal) in newChunkData)
|
||||||
|
{
|
||||||
|
if(!DecalRenderIndex[gridId].ContainsKey(decal.ZIndex))
|
||||||
|
DecalRenderIndex[gridId][decal.ZIndex] = new();
|
||||||
|
|
||||||
|
if (DecalZIndexIndex.TryGetValue(gridId, out var values) && values.TryGetValue(uid, out var zIndex))
|
||||||
|
{
|
||||||
|
DecalRenderIndex[gridId][zIndex].Remove(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
DecalRenderIndex[gridId][decal.ZIndex][uid] = decal;
|
||||||
|
DecalZIndexIndex[gridId][uid] = decal.ZIndex;
|
||||||
|
|
||||||
|
ChunkIndex[gridId][uid] = indices;
|
||||||
|
}
|
||||||
|
chunkCollection[indices] = newChunkData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
Content.Client/Decals/ToggleDecalCommand.cs
Normal file
15
Content.Client/Decals/ToggleDecalCommand.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Client.Decals;
|
||||||
|
|
||||||
|
public class ToggleDecalCommand : IConsoleCommand
|
||||||
|
{
|
||||||
|
public string Command => "toggledecals";
|
||||||
|
public string Description => "Toggles decaloverlay";
|
||||||
|
public string Help => $"{Command}";
|
||||||
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
|
{
|
||||||
|
EntitySystem.Get<DecalSystem>().ToggleOverlay();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Cleanable;
|
using Content.Server.Cleanable;
|
||||||
using Content.Server.Coordinates.Helpers;
|
using Content.Server.Coordinates.Helpers;
|
||||||
using Content.Shared.Chemistry;
|
using Content.Server.Decals;
|
||||||
using Content.Shared.Chemistry.Reaction;
|
using Content.Shared.Chemistry.Reaction;
|
||||||
using Content.Shared.Chemistry.Reagent;
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
|
|
||||||
namespace Content.Server.Chemistry.TileReactions
|
namespace Content.Server.Chemistry.TileReactions
|
||||||
@@ -35,6 +37,12 @@ namespace Content.Server.Chemistry.TileReactions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var decalSystem = EntitySystem.Get<DecalSystem>();
|
||||||
|
foreach (var uid in decalSystem.GetDecalsInRange(tile.GridIndex, tile.GridIndices+new Vector2(0.5f, 0.5f), validDelegate: x => x.Cleanable))
|
||||||
|
{
|
||||||
|
decalSystem.RemoveDecal(tile.GridIndex, uid);
|
||||||
|
}
|
||||||
|
|
||||||
return amount;
|
return amount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Server.Administration.Logs;
|
using Content.Server.Administration.Logs;
|
||||||
using Content.Server.UserInterface;
|
using Content.Server.UserInterface;
|
||||||
using Content.Shared.Administration.Logs;
|
|
||||||
using Content.Shared.Audio;
|
using Content.Shared.Audio;
|
||||||
using Content.Shared.Crayon;
|
using Content.Shared.Crayon;
|
||||||
|
using Content.Server.Decals;
|
||||||
|
using Content.Shared.Decals;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Interaction.Helpers;
|
using Content.Shared.Interaction.Helpers;
|
||||||
@@ -60,11 +61,8 @@ namespace Content.Server.Crayon
|
|||||||
Charges = Capacity;
|
Charges = Capacity;
|
||||||
|
|
||||||
// Get the first one from the catalog and set it as default
|
// Get the first one from the catalog and set it as default
|
||||||
var decals = _prototypeManager.EnumeratePrototypes<CrayonDecalPrototype>().FirstOrDefault();
|
var decal = _prototypeManager.EnumeratePrototypes<DecalPrototype>().FirstOrDefault(x => x.Tags.Contains("crayon"));
|
||||||
if (decals != null)
|
SelectedState = decal?.ID ?? string.Empty;
|
||||||
{
|
|
||||||
SelectedState = decals.Decals.First();
|
|
||||||
}
|
|
||||||
Dirty();
|
Dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,14 +72,10 @@ namespace Content.Server.Crayon
|
|||||||
{
|
{
|
||||||
case CrayonSelectMessage msg:
|
case CrayonSelectMessage msg:
|
||||||
// Check if the selected state is valid
|
// Check if the selected state is valid
|
||||||
var crayonDecals = _prototypeManager.EnumeratePrototypes<CrayonDecalPrototype>().FirstOrDefault();
|
if (_prototypeManager.TryIndex<DecalPrototype>(msg.State, out var prototype) && prototype.Tags.Contains("crayon"))
|
||||||
if (crayonDecals != null)
|
|
||||||
{
|
{
|
||||||
if (crayonDecals.Decals.Contains(msg.State))
|
SelectedState = msg.State;
|
||||||
{
|
Dirty();
|
||||||
SelectedState = msg.State;
|
|
||||||
Dirty();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -131,12 +125,8 @@ namespace Content.Server.Crayon
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var entity = Owner.EntityManager.SpawnEntity("CrayonDecal", eventArgs.ClickLocation);
|
if(!EntitySystem.Get<DecalSystem>().TryAddDecal(SelectedState, eventArgs.ClickLocation.Offset(new Vector2(-0.5f,-0.5f)), out _, Color.FromName(_color), cleanable: true))
|
||||||
if (entity.TryGetComponent(out AppearanceComponent? appearance))
|
return false;
|
||||||
{
|
|
||||||
appearance.SetData(CrayonVisuals.State, SelectedState);
|
|
||||||
appearance.SetData(CrayonVisuals.Color, _color);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_useSound != null)
|
if (_useSound != null)
|
||||||
SoundSystem.Play(Filter.Pvs(Owner), _useSound.GetSound(), Owner, AudioHelpers.WithVariation(0.125f));
|
SoundSystem.Play(Filter.Pvs(Owner), _useSound.GetSound(), Owner, AudioHelpers.WithVariation(0.125f));
|
||||||
|
|||||||
118
Content.Server/Decals/Commands/AddDecalCommand.cs
Normal file
118
Content.Server/Decals/Commands/AddDecalCommand.cs
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Content.Server.Administration;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using Content.Shared.Decals;
|
||||||
|
using Content.Shared.Maps;
|
||||||
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Server.Decals.Commands
|
||||||
|
{
|
||||||
|
[AdminCommand(AdminFlags.Mapping)]
|
||||||
|
public sealed class AddDecalCommand : IConsoleCommand
|
||||||
|
{
|
||||||
|
public string Command => "adddecal";
|
||||||
|
public string Description => "Creates a decal on the map";
|
||||||
|
public string Help => $"{Command} <id> <x position> <y position> <gridId> [angle=<angle> zIndex=<zIndex> color=<color>]";
|
||||||
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length < 4 || args.Length > 7)
|
||||||
|
{
|
||||||
|
shell.WriteError($"Received invalid amount of arguments arguments. Expected 4 to 7, got {args.Length}.\nUsage: {Help}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IoCManager.Resolve<IPrototypeManager>().HasIndex<DecalPrototype>(args[0]))
|
||||||
|
{
|
||||||
|
shell.WriteError($"Cannot find decalprototype '{args[0]}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!float.TryParse(args[1], out var x))
|
||||||
|
{
|
||||||
|
shell.WriteError($"Failed parsing x-coordinate '{args[1]}'.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!float.TryParse(args[2], out var y))
|
||||||
|
{
|
||||||
|
shell.WriteError($"Failed parsing y-coordinate'{args[2]}'.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var mapManager = IoCManager.Resolve<IMapManager>();
|
||||||
|
if (!int.TryParse(args[3], out var gridIdRaw) || !mapManager.TryGetGrid(new GridId(gridIdRaw), out var grid))
|
||||||
|
{
|
||||||
|
shell.WriteError($"Failed parsing gridId '{args[3]}'.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var coordinates = new EntityCoordinates(grid.GridEntityId, new Vector2(x, y));
|
||||||
|
if (grid.GetTileRef(coordinates).IsSpace())
|
||||||
|
{
|
||||||
|
shell.WriteError($"Cannot create decal on space tile at {coordinates}.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color? color = null;
|
||||||
|
var zIndex = 0;
|
||||||
|
Angle? rotation = null;
|
||||||
|
if (args.Length > 4)
|
||||||
|
{
|
||||||
|
for (int i = 4; i < args.Length; i++)
|
||||||
|
{
|
||||||
|
var rawValue = args[i].Split('=');
|
||||||
|
if (rawValue.Length != 2)
|
||||||
|
{
|
||||||
|
shell.WriteError($"Failed parsing parameter: '{args[i]}'");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (rawValue[0])
|
||||||
|
{
|
||||||
|
case "angle":
|
||||||
|
if (!double.TryParse(rawValue[1], out var degrees))
|
||||||
|
{
|
||||||
|
shell.WriteError($"Failed parsing angle '{rawValue[1]}'.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
rotation = Angle.FromDegrees(degrees);
|
||||||
|
break;
|
||||||
|
case "zIndex":
|
||||||
|
if (!int.TryParse(rawValue[1], out zIndex))
|
||||||
|
{
|
||||||
|
shell.WriteError($"Failed parsing zIndex '{rawValue[1]}'.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "color":
|
||||||
|
if (!Color.TryFromName(rawValue[1], out var colorRaw))
|
||||||
|
{
|
||||||
|
shell.WriteError($"Failed parsing color '{rawValue[1]}'.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
color = colorRaw;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
shell.WriteError($"Unknown parameter key '{rawValue[0]}'.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(EntitySystem.Get<DecalSystem>().TryAddDecal(args[0], coordinates, out var uid, color, rotation, zIndex))
|
||||||
|
{
|
||||||
|
shell.WriteLine($"Successfully created decal {uid}.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shell.WriteError($"Failed adding decal.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
162
Content.Server/Decals/Commands/EditDecalCommand.cs
Normal file
162
Content.Server/Decals/Commands/EditDecalCommand.cs
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
using Content.Server.Administration;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
|
||||||
|
namespace Content.Server.Decals;
|
||||||
|
|
||||||
|
[AdminCommand(AdminFlags.Mapping)]
|
||||||
|
public class EditDecalCommand : IConsoleCommand
|
||||||
|
{
|
||||||
|
public string Command => "editdecal";
|
||||||
|
public string Description => "Edits a decal.";
|
||||||
|
public string Help => $@"{Command} <gridId> <uid> <mode>\n
|
||||||
|
Possible modes are:\n
|
||||||
|
- position <x position> <y position>\n
|
||||||
|
- color <color>\n
|
||||||
|
- id <id>\n
|
||||||
|
- rotation <degrees>\n
|
||||||
|
- zindex <zIndex>\n
|
||||||
|
- clean <cleanable>
|
||||||
|
";
|
||||||
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length < 4)
|
||||||
|
{
|
||||||
|
shell.WriteError("Expected at least 5 arguments.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!int.TryParse(args[0], out var gridIdRaw))
|
||||||
|
{
|
||||||
|
shell.WriteError($"Failed parsing gridId '{args[3]}'.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!uint.TryParse(args[1], out var uid))
|
||||||
|
{
|
||||||
|
shell.WriteError($"Failed parsing uid '{args[1]}'.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var gridId = new GridId(gridIdRaw);
|
||||||
|
if (!IoCManager.Resolve<IMapManager>().GridExists(gridId))
|
||||||
|
{
|
||||||
|
shell.WriteError($"No grid with gridId {gridId} exists.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var decalSystem = EntitySystem.Get<DecalSystem>();
|
||||||
|
switch (args[2].ToLower())
|
||||||
|
{
|
||||||
|
case "position":
|
||||||
|
if(args.Length != 5)
|
||||||
|
{
|
||||||
|
shell.WriteError("Expected 6 arguments.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!float.TryParse(args[3], out var x) || !float.TryParse(args[4], out var y))
|
||||||
|
{
|
||||||
|
shell.WriteError("Failed parsing position.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!decalSystem.SetDecalPosition(gridId, uid, gridId, new Vector2(x, y)))
|
||||||
|
{
|
||||||
|
shell.WriteError("Failed changing decalposition.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "color":
|
||||||
|
if(args.Length != 4)
|
||||||
|
{
|
||||||
|
shell.WriteError("Expected 5 arguments.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Color.TryFromName(args[3], out var color))
|
||||||
|
{
|
||||||
|
shell.WriteError("Failed parsing color.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!decalSystem.SetDecalColor(gridId, uid, color))
|
||||||
|
{
|
||||||
|
shell.WriteError("Failed changing decal color.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "id":
|
||||||
|
if(args.Length != 4)
|
||||||
|
{
|
||||||
|
shell.WriteError("Expected 5 arguments.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!decalSystem.SetDecalId(gridId, uid, args[3]))
|
||||||
|
{
|
||||||
|
shell.WriteError("Failed changing decal id.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "rotation":
|
||||||
|
if(args.Length != 4)
|
||||||
|
{
|
||||||
|
shell.WriteError("Expected 5 arguments.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!double.TryParse(args[3], out var degrees))
|
||||||
|
{
|
||||||
|
shell.WriteError("Failed parsing degrees.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!decalSystem.SetDecalRotation(gridId, uid, Angle.FromDegrees(degrees)))
|
||||||
|
{
|
||||||
|
shell.WriteError("Failed changing decal rotation.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "zindex":
|
||||||
|
if(args.Length != 4)
|
||||||
|
{
|
||||||
|
shell.WriteError("Expected 5 arguments.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!int.TryParse(args[3], out var zIndex))
|
||||||
|
{
|
||||||
|
shell.WriteError("Failed parsing zIndex.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!decalSystem.SetDecalZIndex(gridId, uid, zIndex))
|
||||||
|
{
|
||||||
|
shell.WriteError("Failed changing decal zIndex.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "clean":
|
||||||
|
if(args.Length != 4)
|
||||||
|
{
|
||||||
|
shell.WriteError("Expected 5 arguments.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bool.TryParse(args[3], out var cleanable))
|
||||||
|
{
|
||||||
|
shell.WriteError("Failed parsing cleanable.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!decalSystem.SetDecalCleanable(gridId, uid, cleanable))
|
||||||
|
{
|
||||||
|
shell.WriteError("Failed changing decal cleanable flag.");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
shell.WriteError("Invalid mode.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
Content.Server/Decals/Commands/RemoveDecalCommand.cs
Normal file
46
Content.Server/Decals/Commands/RemoveDecalCommand.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using Content.Server.Administration;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
|
||||||
|
namespace Content.Server.Decals.Commands
|
||||||
|
{
|
||||||
|
[AdminCommand(AdminFlags.Mapping)]
|
||||||
|
public class RemoveDecalCommand : IConsoleCommand
|
||||||
|
{
|
||||||
|
public string Command => "rmdecal";
|
||||||
|
public string Description => "removes a decal";
|
||||||
|
public string Help => $"{Command} <uid> <gridId>";
|
||||||
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length != 2)
|
||||||
|
{
|
||||||
|
shell.WriteError($"Unexpected number of arguments.\nExpected two: {Help}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!uint.TryParse(args[0], out var uid))
|
||||||
|
{
|
||||||
|
shell.WriteError($"Failed parsing uid.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!int.TryParse(args[1], out var rawGridId) ||
|
||||||
|
!IoCManager.Resolve<IMapManager>().GridExists(new GridId(rawGridId)))
|
||||||
|
{
|
||||||
|
shell.WriteError("Failed parsing gridId.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var decalSystem = EntitySystem.Get<DecalSystem>();
|
||||||
|
if (decalSystem.RemoveDecal(new GridId(rawGridId), uid))
|
||||||
|
{
|
||||||
|
shell.WriteLine($"Successfully removed decal {uid}.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
shell.WriteError($"Failed trying to remove decal {uid}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
326
Content.Server/Decals/DecalSystem.cs
Normal file
326
Content.Server/Decals/DecalSystem.cs
Normal file
@@ -0,0 +1,326 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Content.Shared.Decals;
|
||||||
|
using Content.Shared.Maps;
|
||||||
|
using Robust.Server.Player;
|
||||||
|
using Robust.Shared.Enums;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
|
namespace Content.Server.Decals
|
||||||
|
{
|
||||||
|
public class DecalSystem : SharedDecalSystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
|
|
||||||
|
private readonly Dictionary<GridId, HashSet<Vector2i>> _dirtyChunks = new();
|
||||||
|
private readonly Dictionary<IPlayerSession, Dictionary<GridId, HashSet<Vector2i>>> _previousSentChunks = new();
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
|
||||||
|
MapManager.TileChanged += OnTileChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Shutdown()
|
||||||
|
{
|
||||||
|
base.Shutdown();
|
||||||
|
|
||||||
|
_playerManager.PlayerStatusChanged -= OnPlayerStatusChanged;
|
||||||
|
MapManager.TileChanged -= OnTileChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTileChanged(object? sender, TileChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (!e.NewTile.IsSpace())
|
||||||
|
return;
|
||||||
|
|
||||||
|
var chunkCollection = ChunkCollection(e.NewTile.GridIndex);
|
||||||
|
var indices = GetChunkIndices(e.NewTile.GridIndices);
|
||||||
|
var toDelete = new HashSet<uint>();
|
||||||
|
if (chunkCollection.TryGetValue(indices, out var chunk))
|
||||||
|
{
|
||||||
|
foreach (var (uid, decal) in chunk)
|
||||||
|
{
|
||||||
|
if (new Vector2((int) Math.Floor(decal.Coordinates.X), (int) Math.Floor(decal.Coordinates.Y)) ==
|
||||||
|
e.NewTile.GridIndices)
|
||||||
|
{
|
||||||
|
toDelete.Add(uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toDelete.Count == 0) return;
|
||||||
|
|
||||||
|
foreach (var uid in toDelete)
|
||||||
|
{
|
||||||
|
RemoveDecalInternal(e.NewTile.GridIndex, uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
DirtyChunk(e.NewTile.GridIndex, indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
|
||||||
|
{
|
||||||
|
switch (e.NewStatus)
|
||||||
|
{
|
||||||
|
case SessionStatus.InGame:
|
||||||
|
_previousSentChunks[e.Session] = new();
|
||||||
|
break;
|
||||||
|
case SessionStatus.Disconnected:
|
||||||
|
_previousSentChunks.Remove(e.Session);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DirtyChunk(GridId id, Vector2i chunkIndices)
|
||||||
|
{
|
||||||
|
if(!_dirtyChunks.ContainsKey(id))
|
||||||
|
_dirtyChunks[id] = new HashSet<Vector2i>();
|
||||||
|
_dirtyChunks[id].Add(chunkIndices);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryAddDecal(string id, EntityCoordinates coordinates, [NotNullWhen(true)] out uint? uid, Color? color = null, Angle? rotation = null, int zIndex = 0, bool cleanable = false)
|
||||||
|
{
|
||||||
|
uid = 0;
|
||||||
|
if (!PrototypeManager.HasIndex<DecalPrototype>(id))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var gridId = coordinates.GetGridId(EntityManager);
|
||||||
|
if (MapManager.GetGrid(gridId).GetTileRef(coordinates).IsSpace())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
rotation ??= Angle.Zero;
|
||||||
|
var decal = new Decal(coordinates.Position, id, color, rotation.Value, zIndex, cleanable);
|
||||||
|
var chunkCollection = DecalGridChunkCollection(gridId);
|
||||||
|
uid = chunkCollection.NextUid++;
|
||||||
|
var chunkIndices = GetChunkIndices(decal.Coordinates);
|
||||||
|
if(!chunkCollection.ChunkCollection.ContainsKey(chunkIndices))
|
||||||
|
chunkCollection.ChunkCollection[chunkIndices] = new();
|
||||||
|
chunkCollection.ChunkCollection[chunkIndices][uid.Value] = decal;
|
||||||
|
ChunkIndex[gridId][uid.Value] = chunkIndices;
|
||||||
|
DirtyChunk(gridId, chunkIndices);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool RemoveDecal(GridId gridId, uint uid) => RemoveDecalInternal(gridId, uid);
|
||||||
|
|
||||||
|
public HashSet<uint> GetDecalsInRange(GridId gridId, Vector2 position, float distance = 0.75f, Func<Decal, bool>? validDelegate = null)
|
||||||
|
{
|
||||||
|
var uids = new HashSet<uint>();
|
||||||
|
var chunkCollection = ChunkCollection(gridId);
|
||||||
|
var chunkIndices = GetChunkIndices(position);
|
||||||
|
if (!chunkCollection.TryGetValue(chunkIndices, out var chunk))
|
||||||
|
return uids;
|
||||||
|
|
||||||
|
foreach (var (uid, decal) in chunk)
|
||||||
|
{
|
||||||
|
if ((position - decal.Coordinates-new Vector2(0.5f, 0.5f)).Length > distance)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (validDelegate == null || validDelegate(decal))
|
||||||
|
{
|
||||||
|
uids.Add(uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return uids;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SetDecalPosition(GridId gridId, uint uid, EntityCoordinates coordinates)
|
||||||
|
{
|
||||||
|
return SetDecalPosition(gridId, uid, coordinates.GetGridId(EntityManager), coordinates.Position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SetDecalPosition(GridId gridId, uint uid, GridId newGridId, Vector2 position)
|
||||||
|
{
|
||||||
|
if (!ChunkIndex.TryGetValue(gridId, out var values) || !values.TryGetValue(uid, out var indices))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DirtyChunk(gridId, indices);
|
||||||
|
var chunkCollection = ChunkCollection(gridId);
|
||||||
|
var decal = chunkCollection[indices][uid];
|
||||||
|
if (newGridId == gridId)
|
||||||
|
{
|
||||||
|
chunkCollection[indices][uid] = decal.WithCoordinates(position);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveDecalInternal(gridId, uid);
|
||||||
|
|
||||||
|
var newChunkCollection = ChunkCollection(newGridId);
|
||||||
|
var chunkIndices = GetChunkIndices(position);
|
||||||
|
if(!newChunkCollection.ContainsKey(chunkIndices))
|
||||||
|
newChunkCollection[chunkIndices] = new();
|
||||||
|
newChunkCollection[chunkIndices][uid] = decal.WithCoordinates(position);
|
||||||
|
ChunkIndex[newGridId][uid] = chunkIndices;
|
||||||
|
DirtyChunk(newGridId, chunkIndices);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SetDecalColor(GridId gridId, uint uid, Color? color)
|
||||||
|
{
|
||||||
|
if (!ChunkIndex.TryGetValue(gridId, out var values) || !values.TryGetValue(uid, out var indices))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var chunkCollection = ChunkCollection(gridId);
|
||||||
|
var decal = chunkCollection[indices][uid];
|
||||||
|
chunkCollection[indices][uid] = decal.WithColor(color);
|
||||||
|
DirtyChunk(gridId, indices);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SetDecalId(GridId gridId, uint uid, string id)
|
||||||
|
{
|
||||||
|
if (!ChunkIndex.TryGetValue(gridId, out var values) || !values.TryGetValue(uid, out var indices))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PrototypeManager.HasIndex<DecalPrototype>(id))
|
||||||
|
throw new ArgumentOutOfRangeException($"Tried to set decal id to invalid prototypeid: {id}");
|
||||||
|
|
||||||
|
var chunkCollection = ChunkCollection(gridId);
|
||||||
|
var decal = chunkCollection[indices][uid];
|
||||||
|
chunkCollection[indices][uid] = decal.WithId(id);
|
||||||
|
DirtyChunk(gridId, indices);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SetDecalRotation(GridId gridId, uint uid, Angle angle)
|
||||||
|
{
|
||||||
|
if (!ChunkIndex.TryGetValue(gridId, out var values) || !values.TryGetValue(uid, out var indices))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var chunkCollection = ChunkCollection(gridId);
|
||||||
|
var decal = chunkCollection[indices][uid];
|
||||||
|
chunkCollection[indices][uid] = decal.WithRotation(angle);
|
||||||
|
DirtyChunk(gridId, indices);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SetDecalZIndex(GridId gridId, uint uid, int zIndex)
|
||||||
|
{
|
||||||
|
if (!ChunkIndex.TryGetValue(gridId, out var values) || !values.TryGetValue(uid, out var indices))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var chunkCollection = ChunkCollection(gridId);
|
||||||
|
var decal = chunkCollection[indices][uid];
|
||||||
|
chunkCollection[indices][uid] = decal.WithZIndex(zIndex);
|
||||||
|
DirtyChunk(gridId, indices);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SetDecalCleanable(GridId gridId, uint uid, bool cleanable)
|
||||||
|
{
|
||||||
|
if (!ChunkIndex.TryGetValue(gridId, out var values) || !values.TryGetValue(uid, out var indices))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var chunkCollection = ChunkCollection(gridId);
|
||||||
|
var decal = chunkCollection[indices][uid];
|
||||||
|
chunkCollection[indices][uid] = decal.WithCleanable(cleanable);
|
||||||
|
DirtyChunk(gridId, indices);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
|
||||||
|
|
||||||
|
foreach (var session in Filter.Broadcast().Recipients)
|
||||||
|
{
|
||||||
|
if(session is not IPlayerSession playerSession || playerSession.Status != SessionStatus.InGame)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var chunks = GetChunksForSession(playerSession);
|
||||||
|
var updatedChunks = new Dictionary<GridId, HashSet<Vector2i>>();
|
||||||
|
foreach (var (gridId, gridChunks) in chunks)
|
||||||
|
{
|
||||||
|
var newChunks = new HashSet<Vector2i>(gridChunks);
|
||||||
|
if (_previousSentChunks[playerSession].TryGetValue(gridId, out var previousChunks))
|
||||||
|
{
|
||||||
|
newChunks.ExceptWith(previousChunks);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_dirtyChunks.TryGetValue(gridId, out var dirtyChunks))
|
||||||
|
{
|
||||||
|
gridChunks.IntersectWith(dirtyChunks);
|
||||||
|
newChunks.UnionWith(gridChunks);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newChunks.Count == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
updatedChunks[gridId] = newChunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(updatedChunks.Count == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
_previousSentChunks[playerSession] = chunks;
|
||||||
|
|
||||||
|
//send all gridChunks to client
|
||||||
|
SendChunkUpdates(playerSession, updatedChunks);
|
||||||
|
}
|
||||||
|
|
||||||
|
_dirtyChunks.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SendChunkUpdates(IPlayerSession session, Dictionary<GridId, HashSet<Vector2i>> updatedChunks)
|
||||||
|
{
|
||||||
|
var updatedDecals = new Dictionary<GridId, Dictionary<Vector2i, Dictionary<uint, Decal>>>();
|
||||||
|
foreach (var (gridId, chunks) in updatedChunks)
|
||||||
|
{
|
||||||
|
var gridChunks = new Dictionary<Vector2i, Dictionary<uint, Decal>>();
|
||||||
|
foreach (var indices in chunks)
|
||||||
|
{
|
||||||
|
gridChunks.Add(indices,
|
||||||
|
ChunkCollection(gridId).TryGetValue(indices, out var chunk)
|
||||||
|
? chunk
|
||||||
|
: new Dictionary<uint, Decal>());
|
||||||
|
}
|
||||||
|
updatedDecals[gridId] = gridChunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
RaiseNetworkEvent(new DecalChunkUpdateEvent{Data = updatedDecals}, Filter.SinglePlayer(session));
|
||||||
|
}
|
||||||
|
|
||||||
|
private HashSet<EntityUid> GetSessionViewers(IPlayerSession session)
|
||||||
|
{
|
||||||
|
var viewers = new HashSet<EntityUid>();
|
||||||
|
if (session.Status != SessionStatus.InGame || session.AttachedEntityUid is null)
|
||||||
|
return viewers;
|
||||||
|
|
||||||
|
viewers.Add(session.AttachedEntityUid.Value);
|
||||||
|
|
||||||
|
foreach (var uid in session.ViewSubscriptions)
|
||||||
|
{
|
||||||
|
viewers.Add(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return viewers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<GridId, HashSet<Vector2i>> GetChunksForSession(IPlayerSession session)
|
||||||
|
{
|
||||||
|
return GetChunksForViewers(GetSessionViewers(session));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -72,16 +72,4 @@ namespace Content.Shared.Crayon
|
|||||||
Color = color;
|
Color = color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable, Prototype("crayonDecal")]
|
|
||||||
public class CrayonDecalPrototype : IPrototype
|
|
||||||
{
|
|
||||||
[ViewVariables]
|
|
||||||
[DataField("id", required: true)]
|
|
||||||
public string ID { get; } = default!;
|
|
||||||
|
|
||||||
[DataField("spritePath")] public string SpritePath { get; } = string.Empty;
|
|
||||||
|
|
||||||
[DataField("decals")] public List<string> Decals { get; } = new();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
38
Content.Shared/Decals/Decal.cs
Normal file
38
Content.Shared/Decals/Decal.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
|
|
||||||
|
namespace Content.Shared.Decals
|
||||||
|
{
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
[DataDefinition]
|
||||||
|
public class Decal
|
||||||
|
{
|
||||||
|
[DataField("coordinates")] public readonly Vector2 Coordinates = Vector2.Zero;
|
||||||
|
[DataField("id")] public readonly string Id = string.Empty;
|
||||||
|
[DataField("color")] public readonly Color? Color;
|
||||||
|
[DataField("angle")] public readonly Angle Angle = Angle.Zero;
|
||||||
|
[DataField("zIndex")] public readonly int ZIndex;
|
||||||
|
[DataField("cleanable")] public bool Cleanable;
|
||||||
|
|
||||||
|
public Decal() {}
|
||||||
|
|
||||||
|
public Decal(Vector2 coordinates, string id, Color? color, Angle angle, int zIndex, bool cleanable)
|
||||||
|
{
|
||||||
|
Coordinates = coordinates;
|
||||||
|
Id = id;
|
||||||
|
Color = color;
|
||||||
|
Angle = angle;
|
||||||
|
ZIndex = zIndex;
|
||||||
|
Cleanable = cleanable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Decal WithCoordinates(Vector2 coordinates) => new(coordinates, Id, Color, Angle, ZIndex, Cleanable);
|
||||||
|
public Decal WithId(string id) => new(Coordinates, id, Color, Angle, ZIndex, Cleanable);
|
||||||
|
public Decal WithColor(Color? color) => new(Coordinates, Id, color, Angle, ZIndex, Cleanable);
|
||||||
|
public Decal WithRotation(Angle angle) => new(Coordinates, Id, Color, angle, ZIndex, Cleanable);
|
||||||
|
public Decal WithZIndex(int zIndex) => new(Coordinates, Id, Color, Angle, zIndex, Cleanable);
|
||||||
|
public Decal WithCleanable(bool cleanable) => new(Coordinates, Id, Color, Angle, ZIndex, cleanable);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
Content.Shared/Decals/DecalChunkUpdateEvent.cs
Normal file
15
Content.Shared/Decals/DecalChunkUpdateEvent.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Decals
|
||||||
|
{
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class DecalChunkUpdateEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public Dictionary<GridId, Dictionary<Vector2i, Dictionary<uint, Decal>>> Data = new();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Serialization.Manager;
|
||||||
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
|
using Robust.Shared.Serialization.Manager.Result;
|
||||||
|
using Robust.Shared.Serialization.Markdown;
|
||||||
|
using Robust.Shared.Serialization.Markdown.Mapping;
|
||||||
|
using Robust.Shared.Serialization.Markdown.Validation;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Interfaces;
|
||||||
|
|
||||||
|
namespace Content.Shared.Decals
|
||||||
|
{
|
||||||
|
[TypeSerializer]
|
||||||
|
public class DecalGridChunkCollectionTypeSerializer : ITypeSerializer<DecalGridComponent.DecalGridChunkCollection, MappingDataNode>
|
||||||
|
{
|
||||||
|
public ValidationNode Validate(ISerializationManager serializationManager, MappingDataNode node,
|
||||||
|
IDependencyCollection dependencies, ISerializationContext? context = null)
|
||||||
|
{
|
||||||
|
return serializationManager.ValidateNode<Dictionary<Vector2i, Dictionary<uint, Decal>>>(node, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DeserializationResult Read(ISerializationManager serializationManager, MappingDataNode node,
|
||||||
|
IDependencyCollection dependencies, bool skipHook, ISerializationContext? context = null)
|
||||||
|
{
|
||||||
|
//todo this read method does not support pushing inheritance
|
||||||
|
var dictionary =
|
||||||
|
serializationManager.ReadValueOrThrow<Dictionary<Vector2i, Dictionary<uint, Decal>>>(node, context, skipHook);
|
||||||
|
|
||||||
|
var uids = new SortedSet<uint>();
|
||||||
|
var uidChunkMap = new Dictionary<uint, Vector2i>();
|
||||||
|
foreach (var (indices, decals) in dictionary)
|
||||||
|
{
|
||||||
|
foreach (var (uid, _) in decals)
|
||||||
|
{
|
||||||
|
uids.Add(uid);
|
||||||
|
uidChunkMap[uid] = indices;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var uidMap = new Dictionary<uint, uint>();
|
||||||
|
uint nextIndex = 0;
|
||||||
|
foreach (var uid in uids)
|
||||||
|
{
|
||||||
|
uidMap[uid] = nextIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
var newDict = new Dictionary<Vector2i, Dictionary<uint, Decal>>();
|
||||||
|
foreach (var (oldUid, newUid) in uidMap)
|
||||||
|
{
|
||||||
|
var indices = uidChunkMap[oldUid];
|
||||||
|
if(!newDict.ContainsKey(indices))
|
||||||
|
newDict[indices] = new();
|
||||||
|
newDict[indices][newUid] = dictionary[indices][oldUid];
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DeserializedValue<DecalGridComponent.DecalGridChunkCollection>(
|
||||||
|
new DecalGridComponent.DecalGridChunkCollection(newDict){NextUid = nextIndex});
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataNode Write(ISerializationManager serializationManager, DecalGridComponent.DecalGridChunkCollection value, bool alwaysWrite = false,
|
||||||
|
ISerializationContext? context = null)
|
||||||
|
{
|
||||||
|
return serializationManager.WriteValue(value.ChunkCollection, alwaysWrite, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DecalGridComponent.DecalGridChunkCollection Copy(ISerializationManager serializationManager, DecalGridComponent.DecalGridChunkCollection source,
|
||||||
|
DecalGridComponent.DecalGridChunkCollection target, bool skipHook, ISerializationContext? context = null)
|
||||||
|
{
|
||||||
|
var dict = serializationManager.Copy(source.ChunkCollection, target.ChunkCollection, context, skipHook)!;
|
||||||
|
return new DecalGridComponent.DecalGridChunkCollection(dict) {NextUid = source.NextUid};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
23
Content.Shared/Decals/DecalGridComponent.cs
Normal file
23
Content.Shared/Decals/DecalGridComponent.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Robust.Shared.Analyzers;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
|
|
||||||
|
namespace Content.Shared.Decals
|
||||||
|
{
|
||||||
|
[RegisterComponent]
|
||||||
|
[Friend(typeof(SharedDecalSystem))]
|
||||||
|
public class DecalGridComponent : Component
|
||||||
|
{
|
||||||
|
public override string Name => "DecalGrid";
|
||||||
|
|
||||||
|
[DataField("chunkCollection", serverOnly: true)]
|
||||||
|
public DecalGridChunkCollection ChunkCollection = new(new ());
|
||||||
|
|
||||||
|
public record DecalGridChunkCollection(Dictionary<Vector2i, Dictionary<uint, Decal>> ChunkCollection)
|
||||||
|
{
|
||||||
|
public uint NextUid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
Content.Shared/Decals/DecalPrototype.cs
Normal file
15
Content.Shared/Decals/DecalPrototype.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Shared.Decals
|
||||||
|
{
|
||||||
|
[Prototype("decal")]
|
||||||
|
public class DecalPrototype : IPrototype
|
||||||
|
{
|
||||||
|
[DataField("id")] public string ID { get; } = null!;
|
||||||
|
[DataField("sprite")] public SpriteSpecifier Sprite { get; } = SpriteSpecifier.Invalid;
|
||||||
|
[DataField("tags")] public List<string> Tags = new();
|
||||||
|
}
|
||||||
|
}
|
||||||
153
Content.Shared/Decals/SharedDecalSystem.cs
Normal file
153
Content.Shared/Decals/SharedDecalSystem.cs
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using Robust.Shared;
|
||||||
|
using Robust.Shared.Configuration;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Shared.Decals
|
||||||
|
{
|
||||||
|
public abstract class SharedDecalSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] protected readonly IPrototypeManager PrototypeManager = default!;
|
||||||
|
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||||
|
[Dependency] protected readonly IMapManager MapManager = default!;
|
||||||
|
|
||||||
|
protected readonly Dictionary<GridId, Dictionary<uint, Vector2i>> ChunkIndex = new();
|
||||||
|
|
||||||
|
public const int ChunkSize = 32;
|
||||||
|
public static Vector2i GetChunkIndices(Vector2 coordinates) => new ((int) Math.Floor(coordinates.X / ChunkSize), (int) Math.Floor(coordinates.Y / ChunkSize));
|
||||||
|
|
||||||
|
private float _viewSize;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<GridInitializeEvent>(OnGridInitialize);
|
||||||
|
_configurationManager.OnValueChanged(CVars.NetMaxUpdateRange, OnPvsRangeChanged, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Shutdown()
|
||||||
|
{
|
||||||
|
base.Shutdown();
|
||||||
|
_configurationManager.UnsubValueChanged(CVars.NetMaxUpdateRange, OnPvsRangeChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPvsRangeChanged(float obj)
|
||||||
|
{
|
||||||
|
_viewSize = obj * 2f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGridInitialize(GridInitializeEvent msg)
|
||||||
|
{
|
||||||
|
var comp = EntityManager.EnsureComponent<DecalGridComponent>(MapManager.GetGrid(msg.GridId).GridEntityId);
|
||||||
|
ChunkIndex[msg.GridId] = new();
|
||||||
|
foreach (var (indices, decals) in comp.ChunkCollection.ChunkCollection)
|
||||||
|
{
|
||||||
|
foreach (var uid in decals.Keys)
|
||||||
|
{
|
||||||
|
ChunkIndex[msg.GridId][uid] = indices;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DecalGridComponent.DecalGridChunkCollection DecalGridChunkCollection(GridId gridId) => EntityManager
|
||||||
|
.GetComponent<DecalGridComponent>(MapManager.GetGrid(gridId).GridEntityId).ChunkCollection;
|
||||||
|
protected Dictionary<Vector2i, Dictionary<uint, Decal>> ChunkCollection(GridId gridId) => DecalGridChunkCollection(gridId).ChunkCollection;
|
||||||
|
|
||||||
|
protected virtual void DirtyChunk(GridId id, Vector2i chunkIndices) {}
|
||||||
|
|
||||||
|
protected bool RemoveDecalInternal(GridId gridId, uint uid)
|
||||||
|
{
|
||||||
|
if (!RemoveDecalHook(gridId, uid)) return false;
|
||||||
|
|
||||||
|
if (!ChunkIndex.TryGetValue(gridId, out var values) || !values.TryGetValue(uid, out var indices))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var chunkCollection = ChunkCollection(gridId);
|
||||||
|
if (!chunkCollection.TryGetValue(indices, out var chunk) || !chunk.Remove(uid))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chunkCollection[indices].Count == 0)
|
||||||
|
chunkCollection.Remove(indices);
|
||||||
|
|
||||||
|
ChunkIndex[gridId]?.Remove(uid);
|
||||||
|
DirtyChunk(gridId, indices);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual bool RemoveDecalHook(GridId gridId, uint uid) => true;
|
||||||
|
|
||||||
|
private (Box2 view, MapId mapId) CalcViewBounds(in EntityUid euid)
|
||||||
|
{
|
||||||
|
var xform = EntityManager.GetComponent<TransformComponent>(euid);
|
||||||
|
|
||||||
|
var view = Box2.UnitCentered.Scale(_viewSize).Translated(xform.WorldPosition);
|
||||||
|
var map = xform.MapID;
|
||||||
|
|
||||||
|
return (view, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Dictionary<GridId, HashSet<Vector2i>> GetChunksForViewers(HashSet<EntityUid> viewers)
|
||||||
|
{
|
||||||
|
var chunks = new Dictionary<GridId, HashSet<Vector2i>>();
|
||||||
|
foreach (var viewerUid in viewers)
|
||||||
|
{
|
||||||
|
var (bounds, mapId) = CalcViewBounds(viewerUid);
|
||||||
|
MapManager.FindGridsIntersectingEnumerator(mapId, bounds, out var gridsEnumerator, true);
|
||||||
|
while(gridsEnumerator.MoveNext(out var grid))
|
||||||
|
{
|
||||||
|
if(!chunks.ContainsKey(grid.Index))
|
||||||
|
chunks[grid.Index] = new();
|
||||||
|
var enumerator = new ChunkIndicesEnumerator(grid.InvWorldMatrix.TransformBox(bounds), ChunkSize);
|
||||||
|
while (enumerator.MoveNext(out var indices))
|
||||||
|
{
|
||||||
|
chunks[grid.Index].Add(indices.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return chunks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal struct ChunkIndicesEnumerator
|
||||||
|
{
|
||||||
|
private Vector2i _chunkLB;
|
||||||
|
private Vector2i _chunkRT;
|
||||||
|
|
||||||
|
private int _xIndex;
|
||||||
|
private int _yIndex;
|
||||||
|
|
||||||
|
internal ChunkIndicesEnumerator(Box2 localAABB, int chunkSize)
|
||||||
|
{
|
||||||
|
_chunkLB = new Vector2i((int)Math.Floor(localAABB.Left / chunkSize), (int)Math.Floor(localAABB.Bottom / chunkSize));
|
||||||
|
_chunkRT = new Vector2i((int)Math.Floor(localAABB.Right / chunkSize), (int)Math.Floor(localAABB.Top / chunkSize));
|
||||||
|
|
||||||
|
_xIndex = _chunkLB.X;
|
||||||
|
_yIndex = _chunkLB.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MoveNext([NotNullWhen(true)] out Vector2i? indices)
|
||||||
|
{
|
||||||
|
if (_yIndex > _chunkRT.Y)
|
||||||
|
{
|
||||||
|
_yIndex = _chunkLB.Y;
|
||||||
|
_xIndex += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
indices = new Vector2i(_xIndex, _yIndex);
|
||||||
|
_yIndex += 1;
|
||||||
|
|
||||||
|
return _xIndex <= _chunkRT.X;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
- type: crayonDecal
|
|
||||||
id: BaseDecals
|
|
||||||
spritePath: Effects/crayondecals.rsi
|
|
||||||
decals:
|
|
||||||
- 0
|
|
||||||
- 1
|
|
||||||
- 2
|
|
||||||
- 3
|
|
||||||
- 4
|
|
||||||
- 5
|
|
||||||
- 6
|
|
||||||
- 7
|
|
||||||
- 8
|
|
||||||
- 9
|
|
||||||
- Blasto
|
|
||||||
- Clandestine
|
|
||||||
- Cyber
|
|
||||||
- Diablo
|
|
||||||
- Donk
|
|
||||||
- Gene
|
|
||||||
- Gib
|
|
||||||
- Max
|
|
||||||
- Newton
|
|
||||||
- North
|
|
||||||
- Omni
|
|
||||||
- Osiron
|
|
||||||
- Prima
|
|
||||||
- Psyke
|
|
||||||
- Sirius
|
|
||||||
- Tunnel
|
|
||||||
- Waffle
|
|
||||||
- a
|
|
||||||
- ampersand
|
|
||||||
- amyjon
|
|
||||||
- antilizard
|
|
||||||
- arrow
|
|
||||||
- b
|
|
||||||
- beepsky
|
|
||||||
- biohazard
|
|
||||||
- blueprint
|
|
||||||
- body
|
|
||||||
- bottle
|
|
||||||
- brush
|
|
||||||
- c
|
|
||||||
- carp
|
|
||||||
- cat
|
|
||||||
- chevron
|
|
||||||
- clawprint
|
|
||||||
- clown
|
|
||||||
- comma
|
|
||||||
- corgi
|
|
||||||
- credit
|
|
||||||
- cyka
|
|
||||||
- d
|
|
||||||
- danger
|
|
||||||
- disk
|
|
||||||
- dot
|
|
||||||
- dwarf
|
|
||||||
- e
|
|
||||||
- electricdanger
|
|
||||||
- end
|
|
||||||
- engie
|
|
||||||
- equals
|
|
||||||
- evac
|
|
||||||
- exclamationmark
|
|
||||||
- f
|
|
||||||
- face
|
|
||||||
- fireaxe
|
|
||||||
- firedanger
|
|
||||||
- food
|
|
||||||
- footprint
|
|
||||||
- g
|
|
||||||
- ghost
|
|
||||||
- guy
|
|
||||||
- h
|
|
||||||
- heart
|
|
||||||
- i
|
|
||||||
- j
|
|
||||||
- k
|
|
||||||
- l
|
|
||||||
- largebrush
|
|
||||||
- like
|
|
||||||
- line
|
|
||||||
- m
|
|
||||||
- matt
|
|
||||||
- med
|
|
||||||
- minus
|
|
||||||
- n
|
|
||||||
- nay
|
|
||||||
- o
|
|
||||||
- p
|
|
||||||
- pawprint
|
|
||||||
- peace
|
|
||||||
- percent
|
|
||||||
- plus
|
|
||||||
- pound
|
|
||||||
- prolizard
|
|
||||||
- q
|
|
||||||
- questionmark
|
|
||||||
- r
|
|
||||||
- radiation
|
|
||||||
- revolution
|
|
||||||
- rune1
|
|
||||||
- rune2
|
|
||||||
- rune3
|
|
||||||
- rune4
|
|
||||||
- rune5
|
|
||||||
- rune6
|
|
||||||
- s
|
|
||||||
- safe
|
|
||||||
- scroll
|
|
||||||
- shop
|
|
||||||
- shortline
|
|
||||||
- shotgun
|
|
||||||
- skull
|
|
||||||
- slash
|
|
||||||
- smallbrush
|
|
||||||
- snake
|
|
||||||
- space
|
|
||||||
- splatter
|
|
||||||
- star
|
|
||||||
- stickman
|
|
||||||
- t
|
|
||||||
- taser
|
|
||||||
- thinline
|
|
||||||
- toilet
|
|
||||||
- toolbox
|
|
||||||
- trade
|
|
||||||
- u
|
|
||||||
- uboa
|
|
||||||
- v
|
|
||||||
- w
|
|
||||||
- x
|
|
||||||
- y
|
|
||||||
- z
|
|
||||||
916
Resources/Prototypes/Decals/crayons.yml
Normal file
916
Resources/Prototypes/Decals/crayons.yml
Normal file
@@ -0,0 +1,916 @@
|
|||||||
|
- type: decal
|
||||||
|
id: 0
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: 0
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: 1
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: 1
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: 2
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: 2
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: 3
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: 3
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: 4
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: 4
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: 5
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: 5
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: 6
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: 6
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: 7
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: 7
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: 8
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: 8
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: 9
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: 9
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: Blasto
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: Blasto
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: Clandestine
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: Clandestine
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: Cyber
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: Cyber
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: Diablo
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: Diablo
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: Donk
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: Donk
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: Gene
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: Gene
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: Gib
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: Gib
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: Max
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: Max
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: Newton
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: Newton
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: North
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: North
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: Omni
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: Omni
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: Osiron
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: Osiron
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: Prima
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: Prima
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: Psyke
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: Psyke
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: Sirius
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: Sirius
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: Tunnel
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: Tunnel
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: Waffle
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: Waffle
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: a
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: a
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: ampersand
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: ampersand
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: amyjon
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: amyjon
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: antilizard
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: antilizard
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: arrow
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: arrow
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: b
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: b
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: beepsky
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: beepsky
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: biohazard
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: biohazard
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: blueprint
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: blueprint
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: body
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: body
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: bottle
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: bottle
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: brush
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: brush
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: c
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: c
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: carp
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: carp
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: cat
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: cat
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: chevron
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: chevron
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: clawprint
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: clawprint
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: clown
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: clown
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: comma
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: comma
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: corgi
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: corgi
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: credit
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: credit
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: cyka
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: cyka
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: d
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: d
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: danger
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: danger
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: disk
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: disk
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: dot
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: dot
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: dwarf
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: dwarf
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: e
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: e
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: electricdanger
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: electricdanger
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: end
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: end
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: engie
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: engie
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: equals
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: equals
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: evac
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: evac
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: exclamationmark
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: exclamationmark
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: f
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: f
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: face
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: face
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: fireaxe
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: fireaxe
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: firedanger
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: firedanger
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: food
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: food
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: footprint
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: footprint
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: g
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: g
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: ghost
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: ghost
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: guy
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: guy
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: h
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: h
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: heart
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: heart
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: i
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: i
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: j
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: j
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: k
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: k
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: l
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: l
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: largebrush
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: largebrush
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: like
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: like
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: line
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: line
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: m
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: m
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: matt
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: matt
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: med
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: med
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: minus
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: minus
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: n
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: n
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: nay
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: nay
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: o
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: o
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: p
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: p
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: pawprint
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: pawprint
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: peace
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: peace
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: percent
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: percent
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: plus
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: plus
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: pound
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: pound
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: prolizard
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: prolizard
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: q
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: q
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: questionmark
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: questionmark
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: r
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: r
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: radiation
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: radiation
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: revolution
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: revolution
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: rune1
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: rune1
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: rune2
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: rune2
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: rune3
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: rune3
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: rune4
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: rune4
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: rune5
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: rune5
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: rune6
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: rune6
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: s
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: s
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: safe
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: safe
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: scroll
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: scroll
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: shop
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: shop
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: shortline
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: shortline
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: shotgun
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: shotgun
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: skull
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: skull
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: slash
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: slash
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: smallbrush
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: smallbrush
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: snake
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: snake
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: space
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: space
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: splatter
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: splatter
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: star
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: star
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: stickman
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: stickman
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: t
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: t
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: taser
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: taser
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: thinline
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: thinline
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: toilet
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: toilet
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: toolbox
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: toolbox
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: trade
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: trade
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: u
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: u
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: uboa
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: uboa
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: v
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: v
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: w
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: w
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: x
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: x
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: y
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: y
|
||||||
|
|
||||||
|
- type: decal
|
||||||
|
id: z
|
||||||
|
tags: ["crayon"]
|
||||||
|
sprite:
|
||||||
|
sprite: Effects/crayondecals.rsi
|
||||||
|
state: z
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
- type: entity
|
|
||||||
abstract: true
|
|
||||||
id: CrayonDecal
|
|
||||||
name: crayon drawing
|
|
||||||
description: "Graffiti. Damn kids."
|
|
||||||
components:
|
|
||||||
- type: Clickable
|
|
||||||
- type: InteractionOutline
|
|
||||||
- type: Physics
|
|
||||||
- type: Sprite
|
|
||||||
sprite: Effects/crayondecals.rsi
|
|
||||||
state: corgi
|
|
||||||
- type: Cleanable
|
|
||||||
- type: Appearance
|
|
||||||
visuals:
|
|
||||||
- type: CrayonDecalVisualizer
|
|
||||||
Reference in New Issue
Block a user