mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-02-15 03:30:53 +01:00
258 lines
8.1 KiB
C#
258 lines
8.1 KiB
C#
using System;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using Robust.Client.Graphics;
|
|
using Robust.Client.ResourceManagement;
|
|
using Robust.Shared.GameObjects;
|
|
using Robust.Shared.Utility;
|
|
using static Robust.Client.GameObjects.SpriteComponent;
|
|
|
|
namespace Robust.Client.GameObjects;
|
|
|
|
// This partial class contains various public methods for managing a sprite's layers.
|
|
// This setter methods for modifying a layer's properties are in a separate file.
|
|
public sealed partial class SpriteSystem
|
|
{
|
|
public bool LayerExists(Entity<SpriteComponent?> sprite, int index)
|
|
{
|
|
if (!_query.Resolve(sprite.Owner, ref sprite.Comp))
|
|
return false;
|
|
|
|
return index >= 0 && index < sprite.Comp.Layers.Count;
|
|
}
|
|
|
|
public bool TryGetLayer(
|
|
Entity<SpriteComponent?> sprite,
|
|
int index,
|
|
[NotNullWhen(true)] out Layer? layer,
|
|
bool logMissing)
|
|
{
|
|
layer = null;
|
|
|
|
if (!_query.Resolve(sprite.Owner, ref sprite.Comp, logMissing))
|
|
return false;
|
|
|
|
if (index >= 0 && index < sprite.Comp.Layers.Count)
|
|
{
|
|
layer = sprite.Comp.Layers[index];
|
|
DebugTools.AssertEqual(layer.Owner, sprite!);
|
|
DebugTools.AssertEqual(layer.Index, index);
|
|
return true;
|
|
}
|
|
|
|
if (logMissing)
|
|
Log.Error($"Layer index '{index}' on entity {ToPrettyString(sprite)} does not exist! Trace:\n{Environment.StackTrace}");
|
|
|
|
return false;
|
|
}
|
|
|
|
public bool RemoveLayer(Entity<SpriteComponent?> sprite, int index, bool logMissing = true)
|
|
{
|
|
return RemoveLayer(sprite.Owner, index, out _, logMissing);
|
|
}
|
|
|
|
public bool RemoveLayer(
|
|
Entity<SpriteComponent?> sprite,
|
|
int index,
|
|
[NotNullWhen(true)] out Layer? layer,
|
|
bool logMissing = true)
|
|
{
|
|
layer = null;
|
|
if (!_query.Resolve(sprite.Owner, ref sprite.Comp, logMissing))
|
|
return false;
|
|
|
|
if (!TryGetLayer(sprite, index, out layer, logMissing))
|
|
return false;
|
|
|
|
sprite.Comp.Layers.RemoveAt(index);
|
|
|
|
foreach (var otherLayer in sprite.Comp.Layers[index..])
|
|
{
|
|
otherLayer.Index--;
|
|
}
|
|
|
|
// TODO SPRITE track inverse-mapping?
|
|
foreach (var (key, value) in sprite.Comp.LayerMap)
|
|
{
|
|
if (value == index)
|
|
sprite.Comp.LayerMap.Remove(key);
|
|
else if (value > index)
|
|
{
|
|
sprite.Comp.LayerMap[key]--;
|
|
}
|
|
}
|
|
|
|
layer.Owner = default;
|
|
layer.Index = -1;
|
|
|
|
#if DEBUG
|
|
foreach (var otherLayer in sprite.Comp.Layers)
|
|
{
|
|
DebugTools.AssertEqual(otherLayer, sprite.Comp.Layers[otherLayer.Index]);
|
|
}
|
|
#endif
|
|
|
|
sprite.Comp.BoundsDirty = true;
|
|
_tree.QueueTreeUpdate(sprite!);
|
|
QueueUpdateIsInert(sprite!);
|
|
return true;
|
|
}
|
|
|
|
#region AddLayer
|
|
|
|
/// <summary>
|
|
/// Add the given sprite layer. If an index is specified, this will insert the layer with the given index, resulting
|
|
/// in all other layers being reshuffled.
|
|
/// </summary>
|
|
public int AddLayer(Entity<SpriteComponent?> sprite, Layer layer, int? index = null)
|
|
{
|
|
if (!_query.Resolve(sprite.Owner, ref sprite.Comp))
|
|
{
|
|
layer.Index = -1;
|
|
layer.Owner = default;
|
|
return -1;
|
|
}
|
|
|
|
layer.Owner = sprite!;
|
|
|
|
if (index is { } i && i != sprite.Comp.Layers.Count)
|
|
{
|
|
foreach (var otherLayer in sprite.Comp.Layers[i..])
|
|
{
|
|
otherLayer.Index++;
|
|
}
|
|
|
|
// TODO SPRITE track inverse-mapping?
|
|
sprite.Comp.Layers.Insert(i, layer);
|
|
layer.Index = i;
|
|
|
|
foreach (var (key, value) in sprite.Comp.LayerMap)
|
|
{
|
|
if (value >= i)
|
|
sprite.Comp.LayerMap[key]++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
layer.Index = sprite.Comp.Layers.Count;
|
|
sprite.Comp.Layers.Add(layer);
|
|
}
|
|
|
|
#if DEBUG
|
|
foreach (var otherLayer in sprite.Comp.Layers)
|
|
{
|
|
DebugTools.AssertEqual(otherLayer, sprite.Comp.Layers[otherLayer.Index]);
|
|
}
|
|
#endif
|
|
|
|
layer.BoundsDirty = true;
|
|
if (!layer.Blank)
|
|
{
|
|
sprite.Comp.BoundsDirty = true;
|
|
_tree.QueueTreeUpdate(sprite!);
|
|
QueueUpdateIsInert(sprite!);
|
|
}
|
|
return layer.Index;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add a layer corresponding to the given RSI state.
|
|
/// </summary>
|
|
/// <param name="sprite">The sprite</param>
|
|
/// <param name="stateId">The RSI state</param>
|
|
/// <param name="rsi">The RSI to use. If not specified, it will default to using <see cref="SpriteComponent.BaseRSI"/></param>
|
|
/// <param name="index">The layer index to use for the new sprite.</param>
|
|
/// <returns></returns>
|
|
public int AddRsiLayer(Entity<SpriteComponent?> sprite, RSI.StateId stateId, RSI? rsi = null, int? index = null)
|
|
{
|
|
if (!_query.Resolve(sprite.Owner, ref sprite.Comp))
|
|
return -1;
|
|
|
|
var layer = AddBlankLayer(sprite!, index);
|
|
|
|
if (rsi != null)
|
|
LayerSetRsi(layer, rsi, stateId);
|
|
else
|
|
LayerSetRsiState(layer, stateId);
|
|
|
|
return layer.Index;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add a layer corresponding to the given RSI state.
|
|
/// </summary>
|
|
/// <param name="sprite">The sprite</param>
|
|
/// <param name="state">The RSI state</param>
|
|
/// <param name="path">The path to the RSI.</param>
|
|
/// <param name="index">The layer index to use for the new sprite.</param>
|
|
/// <returns></returns>
|
|
public int AddRsiLayer(Entity<SpriteComponent?> sprite, RSI.StateId state, ResPath path, int? index = null)
|
|
{
|
|
if (!_query.Resolve(sprite.Owner, ref sprite.Comp))
|
|
return -1;
|
|
|
|
if (!_resourceCache.TryGetResource<RSIResource>(TextureRoot / path, out var res))
|
|
Log.Error($"Unable to load RSI '{path}'. Trace:\n{Environment.StackTrace}");
|
|
|
|
if (path.Extension != "rsi")
|
|
Log.Error($"Expected rsi path but got '{path}'?");
|
|
|
|
return AddRsiLayer(sprite, state, res?.RSI, index);
|
|
}
|
|
|
|
public int AddTextureLayer(Entity<SpriteComponent?> sprite, ResPath path, int? index = null)
|
|
{
|
|
if (_resourceCache.TryGetResource<TextureResource>(TextureRoot / path, out var texture))
|
|
return AddTextureLayer(sprite, texture?.Texture, index);
|
|
|
|
if (path.Extension == "rsi")
|
|
Log.Error($"Expected texture but got rsi '{path}', did you mean 'sprite:' instead of 'texture:'?");
|
|
|
|
Log.Error($"Unable to load texture '{path}'. Trace:\n{Environment.StackTrace}");
|
|
return AddTextureLayer(sprite, texture?.Texture, index);
|
|
}
|
|
|
|
public int AddTextureLayer(Entity<SpriteComponent?> sprite, Texture? texture, int? index = null)
|
|
{
|
|
if (!_query.Resolve(sprite.Owner, ref sprite.Comp))
|
|
return -1;
|
|
|
|
var layer = new Layer {Texture = texture};
|
|
return AddLayer(sprite, layer, index);
|
|
}
|
|
|
|
public int AddLayer(Entity<SpriteComponent?> sprite, SpriteSpecifier specifier, int? newIndex = null)
|
|
{
|
|
return specifier switch
|
|
{
|
|
SpriteSpecifier.Texture tex => AddTextureLayer(sprite, tex.TexturePath, newIndex),
|
|
SpriteSpecifier.Rsi rsi => AddRsiLayer(sprite, rsi.RsiState, rsi.RsiPath, newIndex),
|
|
_ => throw new NotImplementedException()
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add a new sprite layer and populate it using the provided layer data.
|
|
/// </summary>
|
|
public int AddLayer(Entity<SpriteComponent?> sprite, PrototypeLayerData layerDatum, int? index)
|
|
{
|
|
if (!_query.Resolve(sprite.Owner, ref sprite.Comp))
|
|
return -1;
|
|
|
|
var layer = AddBlankLayer(sprite!, index);
|
|
LayerSetData(layer, layerDatum);
|
|
return layer.Index;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add a blank sprite layer.
|
|
/// </summary>
|
|
public Layer AddBlankLayer(Entity<SpriteComponent> sprite, int? index = null)
|
|
{
|
|
var layer = new Layer();
|
|
AddLayer(sprite!, layer, index);
|
|
return layer;
|
|
}
|
|
|
|
#endregion
|
|
}
|