mirror of
https://github.com/space-wizards/RobustToolbox.git
synced 2026-09-15 14:52:35 +02:00
Improved click detection supporting features: (#1133)
* Improved click detection supporting features: Clickable removed from engine Texture/RSI load hooks for content New sprite layer API * Fix tests.
This commit is contained in:
@@ -44,11 +44,6 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
Register<SpriteComponent>();
|
||||
RegisterReference<SpriteComponent, ISpriteComponent>();
|
||||
RegisterReference<SpriteComponent, IClickTargetComponent>();
|
||||
|
||||
Register<ClickableComponent>();
|
||||
RegisterReference<ClickableComponent, IClientClickableComponent>();
|
||||
RegisterReference<ClickableComponent, IClickableComponent>();
|
||||
|
||||
Register<ClientOccluderComponent>();
|
||||
RegisterReference<ClientOccluderComponent, OccluderComponent>();
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
using Robust.Client.Graphics.Shaders;
|
||||
using Robust.Client.Interfaces.GameObjects;
|
||||
using Robust.Client.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
// Notice: Most actual logic for clicking is done by the game screen.
|
||||
public class ClickableComponent : Component, IClientClickableComponent
|
||||
{
|
||||
private Box2? _localBounds;
|
||||
|
||||
public override string Name => "Clickable";
|
||||
public override uint? NetID => NetIDs.CLICKABLE;
|
||||
|
||||
[ViewVariables]
|
||||
public Box2? LocalBounds
|
||||
{
|
||||
get => _localBounds;
|
||||
set => _localBounds = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
serializer.DataField(ref _localBounds, "bounds", null);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
|
||||
{
|
||||
if (curState is ClickableComponentState state)
|
||||
{
|
||||
_localBounds = state.LocalBounds;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
//TODO: This needs to accept MapPosition, not a Vector2
|
||||
public bool CheckClick(Vector2 worldPos, out int drawdepth)
|
||||
{
|
||||
if (LocalBounds.HasValue)
|
||||
{
|
||||
var worldBounds = LocalBounds.Value.Translated(Owner.Transform.WorldPosition);
|
||||
if (!worldBounds.Contains(worldPos))
|
||||
{
|
||||
drawdepth = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (Owner.TryGetComponent(out ISpriteComponent sprite) && !sprite.Visible)
|
||||
{
|
||||
drawdepth = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
var component = Owner.GetComponent<IClickTargetComponent>();
|
||||
drawdepth = component.DrawDepth;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Robust.Client.GameObjects
|
||||
{
|
||||
public sealed class SpriteComponent : SharedSpriteComponent, ISpriteComponent, IClickTargetComponent,
|
||||
public sealed class SpriteComponent : SharedSpriteComponent, ISpriteComponent,
|
||||
IComponentDebug
|
||||
{
|
||||
private bool _visible = true;
|
||||
@@ -159,8 +159,7 @@ namespace Robust.Client.GameObjects
|
||||
[Dependency] private readonly IPrototypeManager prototypes = default!;
|
||||
[Dependency] private readonly IReflectionManager reflectionManager = default!;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public uint RenderOrder { get; set; }
|
||||
[ViewVariables(VVAccess.ReadWrite)] public uint RenderOrder { get; set; }
|
||||
|
||||
// TODO: this should absolutely not be static.
|
||||
private static ShaderInstance? _defaultShader;
|
||||
@@ -175,8 +174,7 @@ namespace Robust.Client.GameObjects
|
||||
const string LayerSerializationCache = "spritelayer";
|
||||
const string LayerMapSerializationCache = "spritelayermap";
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public bool IsInert { get; private set; }
|
||||
[ViewVariables(VVAccess.ReadWrite)] public bool IsInert { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public void LayerMapSet(object key, int layer)
|
||||
@@ -232,7 +230,7 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
public int AddBlankLayer(int? newIndex = null)
|
||||
{
|
||||
var layer = new Layer {Visible = false};
|
||||
var layer = new Layer(this) {Visible = false};
|
||||
return AddLayer(layer, newIndex);
|
||||
}
|
||||
|
||||
@@ -247,8 +245,11 @@ namespace Robust.Client.GameObjects
|
||||
{
|
||||
if (texturePath.Extension == "rsi")
|
||||
{
|
||||
Logger.ErrorS(LogCategory, "Expected texture but got rsi '{0}', did you mean 'sprite:' instead of 'texture:'?", texturePath);
|
||||
Logger.ErrorS(LogCategory,
|
||||
"Expected texture but got rsi '{0}', did you mean 'sprite:' instead of 'texture:'?",
|
||||
texturePath);
|
||||
}
|
||||
|
||||
Logger.ErrorS(LogCategory, "Unable to load texture '{0}'. Trace:\n{1}", texturePath,
|
||||
Environment.StackTrace);
|
||||
}
|
||||
@@ -258,13 +259,13 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
public int AddLayer(Texture? texture, int? newIndex = null)
|
||||
{
|
||||
var layer = new Layer {Texture = texture};
|
||||
var layer = new Layer(this) {Texture = texture};
|
||||
return AddLayer(layer, newIndex);
|
||||
}
|
||||
|
||||
public int AddLayer(RSI.StateId stateId, int? newIndex = null)
|
||||
{
|
||||
var layer = new Layer {State = stateId};
|
||||
var layer = new Layer(this) {State = stateId};
|
||||
if (BaseRSI != null && BaseRSI.TryGetState(stateId, out var state))
|
||||
{
|
||||
layer.AnimationTimeLeft = state.GetDelay(0);
|
||||
@@ -310,7 +311,7 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
public int AddLayer(RSI.StateId stateId, RSI? rsi, int? newIndex = null)
|
||||
{
|
||||
var layer = new Layer {State = stateId, RSI = rsi};
|
||||
var layer = new Layer(this) {State = stateId, RSI = rsi};
|
||||
if (rsi != null && rsi.TryGetState(stateId, out var state))
|
||||
{
|
||||
layer.AnimationTimeLeft = state.GetDelay(0);
|
||||
@@ -501,10 +502,7 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
|
||||
var theLayer = Layers[layer];
|
||||
theLayer.State = default;
|
||||
theLayer.Texture = texture;
|
||||
|
||||
UpdateIsInert();
|
||||
theLayer.SetTexture(texture);
|
||||
}
|
||||
|
||||
public void LayerSetTexture(object layerKey, Texture texture)
|
||||
@@ -535,8 +533,11 @@ namespace Robust.Client.GameObjects
|
||||
{
|
||||
if (texturePath.Extension == "rsi")
|
||||
{
|
||||
Logger.ErrorS(LogCategory, "Expected texture but got rsi '{0}', did you mean 'sprite:' instead of 'texture:'?", texturePath);
|
||||
Logger.ErrorS(LogCategory,
|
||||
"Expected texture but got rsi '{0}', did you mean 'sprite:' instead of 'texture:'?",
|
||||
texturePath);
|
||||
}
|
||||
|
||||
Logger.ErrorS(LogCategory, "Unable to load texture '{0}'. Trace:\n{1}", texturePath,
|
||||
Environment.StackTrace);
|
||||
}
|
||||
@@ -566,34 +567,7 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
|
||||
var theLayer = Layers[layer];
|
||||
if (theLayer.State == stateId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
theLayer.State = stateId;
|
||||
RSI.State? state;
|
||||
var rsi = theLayer.RSI ?? BaseRSI;
|
||||
if (rsi == null)
|
||||
{
|
||||
state = GetFallbackState();
|
||||
Logger.ErrorS(LogCategory, "No RSI to pull new state from! Trace:\n{0}", Environment.StackTrace);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!rsi.TryGetState(stateId, out state))
|
||||
{
|
||||
state = GetFallbackState();
|
||||
Logger.ErrorS(LogCategory, "State '{0}' does not exist in RSI. Trace:\n{1}", stateId,
|
||||
Environment.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
theLayer.AnimationFrame = 0;
|
||||
theLayer.AnimationTime = 0;
|
||||
theLayer.AnimationTimeLeft = state.GetDelay(0);
|
||||
|
||||
UpdateIsInert();
|
||||
theLayer.SetState(stateId);
|
||||
}
|
||||
|
||||
public void LayerSetState(object layerKey, RSI.StateId stateId)
|
||||
@@ -697,34 +671,7 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
|
||||
var theLayer = Layers[layer];
|
||||
theLayer.RSI = rsi;
|
||||
if (!theLayer.State.IsValid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Gotta do this because somebody might use null as argument (totally valid).
|
||||
var actualRsi = theLayer.RSI ?? BaseRSI;
|
||||
if (actualRsi == null)
|
||||
{
|
||||
Logger.ErrorS(LogCategory, "No RSI to pull new state from! Trace:\n{0}", Environment.StackTrace);
|
||||
theLayer.Texture = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (actualRsi.TryGetState(theLayer.State, out var state))
|
||||
{
|
||||
theLayer.AnimationTimeLeft = state.GetDelay(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.ErrorS(LogCategory, "State '{0}' does not exist in set RSI. Trace:\n{1}", theLayer.State,
|
||||
Environment.StackTrace);
|
||||
theLayer.Texture = null;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateIsInert();
|
||||
theLayer.SetRsi(rsi);
|
||||
}
|
||||
|
||||
public void LayerSetRSI(object layerKey, RSI rsi)
|
||||
@@ -831,10 +778,7 @@ namespace Robust.Client.GameObjects
|
||||
return;
|
||||
}
|
||||
|
||||
var theLayer = Layers[layer];
|
||||
theLayer.Visible = visible;
|
||||
|
||||
UpdateIsInert();
|
||||
Layers[layer].SetVisible(visible);
|
||||
}
|
||||
|
||||
public void LayerSetVisible(object layerKey, bool visible)
|
||||
@@ -903,47 +847,21 @@ namespace Robust.Client.GameObjects
|
||||
{
|
||||
if (Layers.Count <= layer)
|
||||
{
|
||||
Logger.ErrorS(LogCategory, "Layer with index '{0}' does not exist, cannot set animation time! Trace:\n{1}",
|
||||
Logger.ErrorS(LogCategory,
|
||||
"Layer with index '{0}' does not exist, cannot set animation time! Trace:\n{1}",
|
||||
layer, Environment.StackTrace);
|
||||
return;
|
||||
}
|
||||
|
||||
var theLayer = Layers[layer];
|
||||
if (!theLayer.State.IsValid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var theLayerRSI = theLayer.RSI ?? BaseRSI;
|
||||
if (theLayerRSI == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var state = theLayerRSI[theLayer.State];
|
||||
if (animationTime > theLayer.AnimationTime)
|
||||
{
|
||||
// Handle advancing differently from going backwards.
|
||||
theLayer.AnimationTimeLeft -= (animationTime - theLayer.AnimationTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Going backwards we re-calculate from zero.
|
||||
// Definitely possible to optimize this for going backwards but I'm too lazy to figure that out.
|
||||
theLayer.AnimationTimeLeft = -animationTime + state.GetDelay(0);
|
||||
theLayer.AnimationFrame = 0;
|
||||
}
|
||||
|
||||
theLayer.AnimationTime = animationTime;
|
||||
// After setting timing data correctly, run advance to get to the correct frame.
|
||||
_advanceFrameAnimation(theLayer, state);
|
||||
Layers[layer].SetAnimationTime(animationTime);
|
||||
}
|
||||
|
||||
public void LayerSetAnimationTime(object layerKey, float animationTime)
|
||||
{
|
||||
if (!LayerMapTryGet(layerKey, out var layer))
|
||||
{
|
||||
Logger.ErrorS(LogCategory, "Layer with key '{0}' does not exist, cannot set animation time! Trace:\n{1}",
|
||||
Logger.ErrorS(LogCategory,
|
||||
"Layer with key '{0}' does not exist, cannot set animation time! Trace:\n{1}",
|
||||
layerKey, Environment.StackTrace);
|
||||
return;
|
||||
}
|
||||
@@ -955,15 +873,13 @@ namespace Robust.Client.GameObjects
|
||||
{
|
||||
if (Layers.Count <= layer)
|
||||
{
|
||||
Logger.ErrorS(LogCategory, "Layer with index '{0}' does not exist, cannot set auto animated! Trace:\n{1}",
|
||||
Logger.ErrorS(LogCategory,
|
||||
"Layer with index '{0}' does not exist, cannot set auto animated! Trace:\n{1}",
|
||||
layer, Environment.StackTrace);
|
||||
return;
|
||||
}
|
||||
|
||||
var theLayer = Layers[layer];
|
||||
theLayer.AutoAnimated = autoAnimated;
|
||||
|
||||
UpdateIsInert();
|
||||
Layers[layer].SetAutoAnimated(autoAnimated);
|
||||
}
|
||||
|
||||
public void LayerSetAutoAnimated(object layerKey, bool autoAnimated)
|
||||
@@ -994,26 +910,21 @@ namespace Robust.Client.GameObjects
|
||||
|
||||
public RSI? LayerGetActualRSI(int layer)
|
||||
{
|
||||
if (Layers.Count <= layer)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(layer), $"Layer '{layer}' does not exist.");
|
||||
}
|
||||
|
||||
var theLayer = Layers[layer];
|
||||
return BaseRSI ?? theLayer.RSI;
|
||||
return this[layer].ActualRsi;
|
||||
}
|
||||
|
||||
public RSI? LayerGetActualRSI(object layerKey)
|
||||
{
|
||||
if (!LayerMapTryGet(layerKey, out var layer))
|
||||
{
|
||||
throw new KeyNotFoundException($"Layer '{layerKey}' does not exist.");
|
||||
}
|
||||
|
||||
return LayerGetActualRSI(layer);
|
||||
return this[layerKey].ActualRsi;
|
||||
}
|
||||
|
||||
internal void Render(DrawingHandleWorld drawingHandle, in Matrix3 worldTransform, Angle worldRotation, Direction? overrideDirection=null)
|
||||
public ISpriteLayer this[int layer] => Layers[layer];
|
||||
public ISpriteLayer this[Index layer] => Layers[layer];
|
||||
public ISpriteLayer this[object layerKey] => this[LayerMap[layerKey]];
|
||||
public IEnumerable<ISpriteLayer> AllLayers => Layers;
|
||||
|
||||
internal void Render(DrawingHandleWorld drawingHandle, in Matrix3 worldTransform, Angle worldRotation,
|
||||
Direction? overrideDirection = null)
|
||||
{
|
||||
var angle = Rotation;
|
||||
if (Directional)
|
||||
@@ -1052,6 +963,7 @@ namespace Robust.Client.GameObjects
|
||||
}
|
||||
|
||||
// TODO: Implement layer-specific rotation and scale.
|
||||
// Oh and when you do update Layer.LocalToLayer so content doesn't break.
|
||||
|
||||
var texture = layer.Texture;
|
||||
|
||||
@@ -1064,26 +976,7 @@ namespace Robust.Client.GameObjects
|
||||
state = GetFallbackState();
|
||||
}
|
||||
|
||||
RSI.State.Direction layerSpecificDir;
|
||||
if (state.Directions == RSI.State.DirectionType.Dir1)
|
||||
{
|
||||
layerSpecificDir = RSI.State.Direction.South;
|
||||
}
|
||||
else
|
||||
{
|
||||
RSI.State.Direction dir;
|
||||
if (overrideDirection != null)
|
||||
{
|
||||
dir = overrideDirection.Value.Convert(state.Directions);
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = GetDir(state.Directions, worldRotation);
|
||||
}
|
||||
|
||||
layerSpecificDir = OffsetRsiDir(dir, layer.DirOffset);
|
||||
}
|
||||
|
||||
var layerSpecificDir = layer.EffectiveDirection(state, worldRotation, overrideDirection);
|
||||
texture = state.GetFrame(layerSpecificDir, layer.AnimationFrame);
|
||||
}
|
||||
|
||||
@@ -1111,7 +1004,8 @@ namespace Robust.Client.GameObjects
|
||||
serializer.DataFieldCached(ref scale, "scale", Vector2.One);
|
||||
serializer.DataFieldCached(ref rotation, "rotation", Angle.Zero);
|
||||
serializer.DataFieldCached(ref offset, "offset", Vector2.Zero);
|
||||
serializer.DataFieldCached(ref drawDepth, "drawdepth", DrawDepthTag.Default, WithFormat.Constants<DrawDepthTag>());
|
||||
serializer.DataFieldCached(ref drawDepth, "drawdepth", DrawDepthTag.Default,
|
||||
WithFormat.Constants<DrawDepthTag>());
|
||||
serializer.DataFieldCached(ref color, "color", Color.White);
|
||||
serializer.DataFieldCached(ref _directional, "directional", true);
|
||||
serializer.DataFieldCached(ref _visible, "visible", true);
|
||||
@@ -1185,7 +1079,7 @@ namespace Robust.Client.GameObjects
|
||||
foreach (var layerDatum in layerData)
|
||||
{
|
||||
var anyTextureAttempted = false;
|
||||
var layer = new Layer();
|
||||
var layer = new Layer(this);
|
||||
if (!string.IsNullOrWhiteSpace(layerDatum.RsiPath))
|
||||
{
|
||||
var path = TextureRoot / layerDatum.RsiPath;
|
||||
@@ -1380,7 +1274,7 @@ namespace Robust.Client.GameObjects
|
||||
for (var i = 0; i < thestate.Layers.Count; i++)
|
||||
{
|
||||
var netlayer = thestate.Layers[i];
|
||||
var layer = new Layer
|
||||
var layer = new Layer(this)
|
||||
{
|
||||
// These are easy so do them here.
|
||||
Scale = netlayer.Scale,
|
||||
@@ -1467,33 +1361,23 @@ namespace Robust.Client.GameObjects
|
||||
case DirectionOffset.None:
|
||||
return dir;
|
||||
case DirectionOffset.Clockwise:
|
||||
switch (dir)
|
||||
return dir switch
|
||||
{
|
||||
case RSI.State.Direction.North:
|
||||
return RSI.State.Direction.East;
|
||||
case RSI.State.Direction.East:
|
||||
return RSI.State.Direction.South;
|
||||
case RSI.State.Direction.South:
|
||||
return RSI.State.Direction.West;
|
||||
case RSI.State.Direction.West:
|
||||
return RSI.State.Direction.North;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
RSI.State.Direction.North => RSI.State.Direction.East,
|
||||
RSI.State.Direction.East => RSI.State.Direction.South,
|
||||
RSI.State.Direction.South => RSI.State.Direction.West,
|
||||
RSI.State.Direction.West => RSI.State.Direction.North,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
case DirectionOffset.CounterClockwise:
|
||||
switch (dir)
|
||||
return dir switch
|
||||
{
|
||||
case RSI.State.Direction.North:
|
||||
return RSI.State.Direction.West;
|
||||
case RSI.State.Direction.East:
|
||||
return RSI.State.Direction.North;
|
||||
case RSI.State.Direction.South:
|
||||
return RSI.State.Direction.East;
|
||||
case RSI.State.Direction.West:
|
||||
return RSI.State.Direction.South;
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
RSI.State.Direction.North => RSI.State.Direction.West,
|
||||
RSI.State.Direction.East => RSI.State.Direction.North,
|
||||
RSI.State.Direction.South => RSI.State.Direction.East,
|
||||
RSI.State.Direction.West => RSI.State.Direction.South,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
case DirectionOffset.Flip:
|
||||
switch (dir)
|
||||
{
|
||||
@@ -1541,7 +1425,7 @@ namespace Robust.Client.GameObjects
|
||||
/// <summary>
|
||||
/// Enum to "offset" a cardinal direction.
|
||||
/// </summary>
|
||||
public enum DirectionOffset
|
||||
public enum DirectionOffset : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// No offset.
|
||||
@@ -1564,8 +1448,10 @@ namespace Robust.Client.GameObjects
|
||||
Flip = 3,
|
||||
}
|
||||
|
||||
private class Layer
|
||||
private class Layer : ISpriteLayer
|
||||
{
|
||||
private readonly SpriteComponent _parent;
|
||||
|
||||
public ShaderInstance? Shader;
|
||||
public Texture? Texture;
|
||||
|
||||
@@ -1574,23 +1460,22 @@ namespace Robust.Client.GameObjects
|
||||
public float AnimationTimeLeft;
|
||||
public float AnimationTime;
|
||||
public int AnimationFrame;
|
||||
public Vector2 Scale = Vector2.One;
|
||||
public Angle Rotation;
|
||||
public Vector2 Scale { get; set; } = Vector2.One;
|
||||
public Angle Rotation { get; set; }
|
||||
public bool Visible = true;
|
||||
public Color Color = Color.White;
|
||||
public DirectionOffset DirOffset;
|
||||
public Color Color { get; set; } = Color.White;
|
||||
public bool AutoAnimated = true;
|
||||
public DirectionOffset DirOffset { get; set; }
|
||||
public RSI? ActualRsi => RSI ?? _parent.BaseRSI;
|
||||
|
||||
public Layer()
|
||||
public Layer(SpriteComponent parent)
|
||||
{
|
||||
Visible = true;
|
||||
Scale = Vector2.One;
|
||||
Color = Color.White;
|
||||
AutoAnimated = true;
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
public Layer(Layer toClone)
|
||||
{
|
||||
_parent = toClone._parent;
|
||||
Shader = toClone.Shader;
|
||||
Texture = toClone.Texture;
|
||||
RSI = toClone.RSI;
|
||||
@@ -1605,6 +1490,195 @@ namespace Robust.Client.GameObjects
|
||||
DirOffset = toClone.DirOffset;
|
||||
AutoAnimated = toClone.AutoAnimated;
|
||||
}
|
||||
|
||||
RSI? ISpriteLayer.Rsi { get => RSI; set => SetRsi(value); }
|
||||
RSI.StateId ISpriteLayer.RsiState { get => State; set => SetState(value); }
|
||||
Texture? ISpriteLayer.Texture { get => Texture; set => SetTexture(value); }
|
||||
|
||||
bool ISpriteLayer.Visible
|
||||
{
|
||||
get => Visible;
|
||||
set => SetVisible(value);
|
||||
}
|
||||
|
||||
float ISpriteLayer.AnimationTime
|
||||
{
|
||||
get => AnimationTime;
|
||||
set => SetAnimationTime(value);
|
||||
}
|
||||
|
||||
int ISpriteLayer.AnimationFrame => AnimationFrame;
|
||||
|
||||
bool ISpriteLayer.AutoAnimated
|
||||
{
|
||||
get => AutoAnimated;
|
||||
set => SetAutoAnimated(value);
|
||||
}
|
||||
|
||||
public RSI.State.Direction EffectiveDirection(Angle worldRotation)
|
||||
{
|
||||
if (State == default)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
var rsi = ActualRsi;
|
||||
if (rsi == null)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
var state = rsi[State];
|
||||
|
||||
return EffectiveDirection(state, worldRotation, null);
|
||||
}
|
||||
|
||||
public Vector2 LocalToLayer(Vector2 localPos)
|
||||
{
|
||||
// TODO: scale & rotation for layers is currently unimplemented.
|
||||
return localPos;
|
||||
}
|
||||
|
||||
public RSI.State.Direction EffectiveDirection(RSI.State state, Angle worldRotation,
|
||||
Direction? overrideDirection)
|
||||
{
|
||||
if (state.Directions == RSI.State.DirectionType.Dir1)
|
||||
{
|
||||
return RSI.State.Direction.South;
|
||||
}
|
||||
else
|
||||
{
|
||||
RSI.State.Direction dir;
|
||||
if (overrideDirection != null)
|
||||
{
|
||||
dir = overrideDirection.Value.Convert(state.Directions);
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = _parent.GetDir(state.Directions, worldRotation);
|
||||
}
|
||||
|
||||
return OffsetRsiDir(dir, DirOffset);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetAnimationTime(float animationTime)
|
||||
{
|
||||
if (!State.IsValid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var theLayerRSI = ActualRsi;
|
||||
if (theLayerRSI == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var state = theLayerRSI[State];
|
||||
if (animationTime > AnimationTime)
|
||||
{
|
||||
// Handle advancing differently from going backwards.
|
||||
AnimationTimeLeft -= (animationTime - AnimationTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Going backwards we re-calculate from zero.
|
||||
// Definitely possible to optimize this for going backwards but I'm too lazy to figure that out.
|
||||
AnimationTimeLeft = -animationTime + state.GetDelay(0);
|
||||
AnimationFrame = 0;
|
||||
}
|
||||
|
||||
AnimationTime = animationTime;
|
||||
// After setting timing data correctly, run advance to get to the correct frame.
|
||||
_advanceFrameAnimation(this, state);
|
||||
}
|
||||
|
||||
public void SetAutoAnimated(bool value)
|
||||
{
|
||||
AutoAnimated = value;
|
||||
|
||||
_parent.UpdateIsInert();
|
||||
}
|
||||
|
||||
public void SetVisible(bool value)
|
||||
{
|
||||
Visible = value;
|
||||
|
||||
_parent.UpdateIsInert();
|
||||
}
|
||||
|
||||
public void SetRsi(RSI? rsi)
|
||||
{
|
||||
RSI = rsi;
|
||||
if (!State.IsValid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Gotta do this because somebody might use null as argument (totally valid).
|
||||
var actualRsi = ActualRsi;
|
||||
if (actualRsi == null)
|
||||
{
|
||||
Logger.ErrorS(LogCategory, "No RSI to pull new state from! Trace:\n{0}", Environment.StackTrace);
|
||||
Texture = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (actualRsi.TryGetState(State, out var state))
|
||||
{
|
||||
AnimationTimeLeft = state.GetDelay(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.ErrorS(LogCategory, "State '{0}' does not exist in set RSI. Trace:\n{1}", State,
|
||||
Environment.StackTrace);
|
||||
Texture = null;
|
||||
}
|
||||
}
|
||||
|
||||
_parent.UpdateIsInert();
|
||||
}
|
||||
|
||||
public void SetState(RSI.StateId stateId)
|
||||
{
|
||||
if (State == stateId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
State = stateId;
|
||||
RSI.State? state;
|
||||
var rsi = ActualRsi;
|
||||
if (rsi == null)
|
||||
{
|
||||
state = _parent.GetFallbackState();
|
||||
Logger.ErrorS(LogCategory, "No RSI to pull new state from! Trace:\n{0}", Environment.StackTrace);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!rsi.TryGetState(stateId, out state))
|
||||
{
|
||||
state = _parent.GetFallbackState();
|
||||
Logger.ErrorS(LogCategory, "State '{0}' does not exist in RSI. Trace:\n{1}", stateId,
|
||||
Environment.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
AnimationFrame = 0;
|
||||
AnimationTime = 0;
|
||||
AnimationTimeLeft = state.GetDelay(0);
|
||||
|
||||
_parent.UpdateIsInert();
|
||||
}
|
||||
|
||||
public void SetTexture(Texture? texture)
|
||||
{
|
||||
State = default;
|
||||
Texture = texture;
|
||||
|
||||
_parent.UpdateIsInert();
|
||||
}
|
||||
}
|
||||
|
||||
void IAnimationProperties.SetAnimatableProperty(string name, object value)
|
||||
@@ -1618,7 +1692,7 @@ namespace Robust.Client.GameObjects
|
||||
var delimiter = name.IndexOf("/", 6, StringComparison.Ordinal);
|
||||
var indexString = name.Substring(6, delimiter - 6);
|
||||
var index = int.Parse(indexString, CultureInfo.InvariantCulture);
|
||||
var layerProp = name.Substring(delimiter+1);
|
||||
var layerProp = name.Substring(delimiter + 1);
|
||||
|
||||
switch (layerProp)
|
||||
{
|
||||
|
||||
@@ -258,6 +258,15 @@ namespace Robust.Client.Graphics.Clyde
|
||||
TextureId = id;
|
||||
_clyde = clyde;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (_clyde._loadedTextures.TryGetValue(TextureId, out var loaded) && loaded.Name != null)
|
||||
{
|
||||
return $"ClydeTexture: {loaded.Name} ({TextureId})";
|
||||
}
|
||||
return $"ClydeTexture: ({TextureId})";
|
||||
}
|
||||
}
|
||||
|
||||
public Texture GetStockTexture(ClydeStockTexture stockTexture)
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
using Robust.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Maths;
|
||||
|
||||
namespace Robust.Client.Interfaces.GameObjects.Components
|
||||
{
|
||||
public interface IClientClickableComponent : IClickableComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to check whether a click worked.
|
||||
/// </summary>
|
||||
/// <param name="worldPos">The world position that was clicked.</param>
|
||||
/// <param name="drawdepth">
|
||||
/// The draw depth for the sprite that captured the click.
|
||||
/// </param>
|
||||
/// <returns>True if the click worked, false otherwise.</returns>
|
||||
bool CheckClick(Vector2 worldPos, out int drawdepth);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.Graphics.Shaders;
|
||||
using Robust.Shared.Animations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -174,7 +174,9 @@ namespace Robust.Client.Interfaces.GameObjects.Components
|
||||
void LayerSetVisible(int layer, bool visible);
|
||||
void LayerSetVisible(object layerKey, bool visible);
|
||||
void LayerSetColor(int layer, Color color);
|
||||
|
||||
void LayerSetColor(object layerKey, Color color);
|
||||
|
||||
// Yes, I realize how silly it is to reference an enum in the concrete implementation.
|
||||
// I don't care.
|
||||
void LayerSetDirOffset(int layer, SpriteComponent.DirectionOffset offset);
|
||||
@@ -196,5 +198,36 @@ namespace Robust.Client.Interfaces.GameObjects.Components
|
||||
/// Get the RSI used by a layer.
|
||||
/// </summary>
|
||||
RSI? LayerGetActualRSI(object layerKey);
|
||||
|
||||
ISpriteLayer this[int layer] { get; }
|
||||
ISpriteLayer this[Index layer] { get; }
|
||||
ISpriteLayer this[object layerKey] { get; }
|
||||
|
||||
IEnumerable<ISpriteLayer> AllLayers { get; }
|
||||
}
|
||||
|
||||
public interface ISpriteLayer
|
||||
{
|
||||
SpriteComponent.DirectionOffset DirOffset { get; set; }
|
||||
|
||||
RSI? Rsi { get; set; }
|
||||
RSI.StateId RsiState { get; set; }
|
||||
RSI? ActualRsi { get; }
|
||||
|
||||
Texture? Texture { get; set; }
|
||||
|
||||
Angle Rotation { get; set; }
|
||||
Vector2 Scale { get; set; }
|
||||
|
||||
bool Visible { get; set; }
|
||||
Color Color { get; set; }
|
||||
|
||||
float AnimationTime { get; set; }
|
||||
int AnimationFrame { get; }
|
||||
bool AutoAnimated { get; set; }
|
||||
|
||||
RSI.State.Direction EffectiveDirection(Angle worldRotation);
|
||||
|
||||
Vector2 LocalToLayer(Vector2 localPos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Interfaces.GameObjects;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Robust.Client.Interfaces.GameObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// A component that can be clicked on. Handles whether a coordinate is a valid place to click us on.
|
||||
/// </summary>
|
||||
public interface IClickTargetComponent : IComponent
|
||||
{
|
||||
int DrawDepth { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Robust.Client.ResourceManagement;
|
||||
using Robust.Shared.Interfaces.Resources;
|
||||
@@ -36,9 +37,15 @@ namespace Robust.Client.Interfaces.ResourceManagement
|
||||
where T : BaseResource, new();
|
||||
|
||||
IEnumerable<KeyValuePair<ResourcePath, T>> GetAllResources<T>() where T : BaseResource, new();
|
||||
|
||||
// Resource load callbacks so content can hook stuff like click maps.
|
||||
event Action<TextureLoadedEventArgs> OnRawTextureLoaded;
|
||||
event Action<RsiLoadedEventArgs> OnRsiLoaded;
|
||||
}
|
||||
|
||||
internal interface IResourceCacheInternal : IResourceCache, IResourceManagerInternal
|
||||
{
|
||||
void TextureLoaded(TextureLoadedEventArgs eventArgs);
|
||||
void RsiLoaded(RsiLoadedEventArgs eventArgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,6 +151,9 @@ namespace Robust.Client.ResourceManagement
|
||||
return GetTypeDict<T>().Select(p => new KeyValuePair<ResourcePath, T>(p.Key, (T) p.Value));
|
||||
}
|
||||
|
||||
public event Action<TextureLoadedEventArgs>? OnRawTextureLoaded;
|
||||
public event Action<RsiLoadedEventArgs>? OnRsiLoaded;
|
||||
|
||||
#region IDisposable Members
|
||||
|
||||
private bool disposed = false;
|
||||
@@ -197,5 +200,15 @@ namespace Robust.Client.ResourceManagement
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void TextureLoaded(TextureLoadedEventArgs eventArgs)
|
||||
{
|
||||
OnRawTextureLoaded?.Invoke(eventArgs);
|
||||
}
|
||||
|
||||
public void RsiLoaded(RsiLoadedEventArgs eventArgs)
|
||||
{
|
||||
OnRsiLoaded?.Invoke(eventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,12 +70,14 @@ namespace Robust.Client.ResourceManagement
|
||||
// Ok schema validated just fine.
|
||||
var manifestJson = JObject.Parse(manifestContents);
|
||||
|
||||
var toAtlas = new List<(Image<Rgba32> src, Texture[][] output, int[][] indices, int totalFrameCount)>();
|
||||
var toAtlas = new List<(Image<Rgba32> src, Texture[][] output, int[][] indices, Vector2i[][] offsets, int totalFrameCount)>();
|
||||
|
||||
var metaData = ParseMetaData(manifestJson);
|
||||
var frameSize = metaData.Size;
|
||||
var rsi = new RSI(frameSize);
|
||||
|
||||
var callbackOffsets = new Dictionary<RSI.StateId, Vector2i[][]>();
|
||||
|
||||
// Do every state.
|
||||
foreach (var stateObject in metaData.States)
|
||||
{
|
||||
@@ -95,84 +97,92 @@ namespace Robust.Client.ResourceManagement
|
||||
var (foldedDelays, foldedIndices) = FoldDelays(stateObject.Delays);
|
||||
|
||||
var textures = new Texture[foldedIndices.Length][];
|
||||
var callbackOffset = new Vector2i[foldedIndices.Length][];
|
||||
|
||||
for (var i = 0; i < textures.Length; i++)
|
||||
{
|
||||
textures[i] = new Texture[foldedIndices[0].Length];
|
||||
callbackOffset[i] = new Vector2i[foldedIndices[0].Length];
|
||||
}
|
||||
|
||||
var state = new RSI.State(frameSize, stateObject.StateId, stateObject.DirType, foldedDelays, textures);
|
||||
rsi.AddState(state);
|
||||
|
||||
toAtlas.Add((image, textures, foldedIndices, frameCount));
|
||||
toAtlas.Add((image, textures, foldedIndices, callbackOffset, frameCount));
|
||||
callbackOffsets[stateObject.StateId] = callbackOffset;
|
||||
}
|
||||
|
||||
// Poorly hacked in texture atlas support here.
|
||||
var totalFrameCount = toAtlas.Sum(p => p.totalFrameCount);
|
||||
|
||||
// Generate atlas.
|
||||
var dimensionX = (int) MathF.Ceiling(MathF.Sqrt(totalFrameCount));
|
||||
var dimensionY = (int) MathF.Ceiling((float) totalFrameCount / dimensionX);
|
||||
|
||||
using var sheet = new Image<Rgba32>(dimensionX * frameSize.X, dimensionY * frameSize.Y);
|
||||
|
||||
var sheetIndex = 0;
|
||||
foreach (var (src, _, _, _, frameCount) in toAtlas)
|
||||
{
|
||||
var totalFrameCount = toAtlas.Sum(p => p.totalFrameCount);
|
||||
|
||||
// Generate atlas.
|
||||
var dimensionX = (int) MathF.Ceiling(MathF.Sqrt(totalFrameCount));
|
||||
var dimensionY = (int) MathF.Ceiling((float) totalFrameCount / dimensionX);
|
||||
|
||||
using var sheet = new Image<Rgba32>(dimensionX * frameSize.X, dimensionY * frameSize.Y);
|
||||
|
||||
var sheetIndex = 0;
|
||||
foreach (var (src, _, _, frameCount) in toAtlas)
|
||||
// Blit all the frames over.
|
||||
for (var i = 0; i < frameCount; i++)
|
||||
{
|
||||
// Blit all the frames over.
|
||||
for (var i = 0; i < frameCount; i++)
|
||||
{
|
||||
var srcWidth = (src.Width / frameSize.X);
|
||||
var srcColumn = i % srcWidth;
|
||||
var srcRow = i / srcWidth;
|
||||
var srcPos = (srcColumn * frameSize.X, srcRow * frameSize.Y);
|
||||
var srcWidth = (src.Width / frameSize.X);
|
||||
var srcColumn = i % srcWidth;
|
||||
var srcRow = i / srcWidth;
|
||||
var srcPos = (srcColumn * frameSize.X, srcRow * frameSize.Y);
|
||||
|
||||
var sheetColumn = (sheetIndex + i) % dimensionX;
|
||||
var sheetRow = (sheetIndex + i) / dimensionX;
|
||||
var sheetPos = (sheetColumn * frameSize.X, sheetRow * frameSize.Y);
|
||||
var sheetColumn = (sheetIndex + i) % dimensionX;
|
||||
var sheetRow = (sheetIndex + i) / dimensionX;
|
||||
var sheetPos = (sheetColumn * frameSize.X, sheetRow * frameSize.Y);
|
||||
|
||||
var srcBox = UIBox2i.FromDimensions(srcPos, frameSize);
|
||||
var srcBox = UIBox2i.FromDimensions(srcPos, frameSize);
|
||||
|
||||
src.Blit(srcBox, sheet, sheetPos);
|
||||
}
|
||||
|
||||
sheetIndex += frameCount;
|
||||
src.Blit(srcBox, sheet, sheetPos);
|
||||
}
|
||||
|
||||
// Load atlas.
|
||||
var texture = Texture.LoadFromImage(sheet, path.ToString());
|
||||
|
||||
var sheetOffset = 0;
|
||||
foreach (var (src, output, indices, frameCount) in toAtlas)
|
||||
{
|
||||
for (var i = 0; i < indices.Length; i++)
|
||||
{
|
||||
var dirIndices = indices[i];
|
||||
var dirOutput = output[i];
|
||||
|
||||
for (var j = 0; j < dirIndices.Length; j++)
|
||||
{
|
||||
var index = sheetOffset + dirIndices[j];
|
||||
|
||||
var sheetColumn = index % dimensionX;
|
||||
var sheetRow = index / dimensionX;
|
||||
var sheetPos = (sheetColumn * frameSize.X, sheetRow * frameSize.Y);
|
||||
|
||||
dirOutput[j] = new AtlasTexture(texture, UIBox2.FromDimensions(sheetPos, frameSize));
|
||||
}
|
||||
}
|
||||
|
||||
sheetOffset += frameCount;
|
||||
}
|
||||
sheetIndex += frameCount;
|
||||
}
|
||||
|
||||
foreach (var (image, _, _, _) in toAtlas)
|
||||
// Load atlas.
|
||||
var texture = Texture.LoadFromImage(sheet, path.ToString());
|
||||
|
||||
var sheetOffset = 0;
|
||||
foreach (var (_, output, indices, offsets, frameCount) in toAtlas)
|
||||
{
|
||||
for (var i = 0; i < indices.Length; i++)
|
||||
{
|
||||
var dirIndices = indices[i];
|
||||
var dirOutput = output[i];
|
||||
var dirOffsets = offsets[i];
|
||||
|
||||
for (var j = 0; j < dirIndices.Length; j++)
|
||||
{
|
||||
var index = sheetOffset + dirIndices[j];
|
||||
|
||||
var sheetColumn = index % dimensionX;
|
||||
var sheetRow = index / dimensionX;
|
||||
var sheetPos = (sheetColumn * frameSize.X, sheetRow * frameSize.Y);
|
||||
|
||||
dirOffsets[j] = sheetPos;
|
||||
dirOutput[j] = new AtlasTexture(texture, UIBox2.FromDimensions(sheetPos, frameSize));
|
||||
}
|
||||
}
|
||||
|
||||
sheetOffset += frameCount;
|
||||
}
|
||||
|
||||
foreach (var (image, _, _, _, _) in toAtlas)
|
||||
{
|
||||
image.Dispose();
|
||||
}
|
||||
|
||||
RSI = rsi;
|
||||
|
||||
if (cache is IResourceCacheInternal cacheInternal)
|
||||
{
|
||||
cacheInternal.RsiLoaded(new RsiLoadedEventArgs(path, this, sheet, callbackOffsets));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -6,12 +6,16 @@ using Robust.Client.Interfaces.ResourceManagement;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Utility;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.PixelFormats;
|
||||
using YamlDotNet.RepresentationModel;
|
||||
|
||||
namespace Robust.Client.ResourceManagement
|
||||
{
|
||||
public class TextureResource : BaseResource
|
||||
{
|
||||
public const float ClickThreshold = 0.25f;
|
||||
|
||||
public override ResourcePath? Fallback => new ResourcePath("/Textures/noSprite.png");
|
||||
public Texture Texture { get; private set; } = default!;
|
||||
|
||||
@@ -29,7 +33,14 @@ namespace Robust.Client.ResourceManagement
|
||||
|
||||
var manager = IoCManager.Resolve<IClyde>();
|
||||
|
||||
Texture = manager.LoadTextureFromPNGStream(stream, path.ToString(), loadParameters);
|
||||
using var image = Image.Load<Rgba32>(stream);
|
||||
|
||||
Texture = manager.LoadTextureFromImage(image, path.ToString(), loadParameters);
|
||||
|
||||
if (cache is IResourceCacheInternal cacheInternal)
|
||||
{
|
||||
cacheInternal.TextureLoaded(new TextureLoadedEventArgs(path, image, this));
|
||||
}
|
||||
}
|
||||
|
||||
private static TextureLoadParameters? _tryLoadTextureParameters(IResourceCache cache, ResourcePath path)
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Utility;
|
||||
using SixLabors.ImageSharp;
|
||||
|
||||
namespace Robust.Client.ResourceManagement
|
||||
{
|
||||
public readonly struct RsiLoadedEventArgs
|
||||
{
|
||||
internal RsiLoadedEventArgs(ResourcePath path, RSIResource resource, Image atlas, Dictionary<RSI.StateId, Vector2i[][]> atlasOffsets)
|
||||
{
|
||||
Path = path;
|
||||
Resource = resource;
|
||||
Atlas = atlas;
|
||||
AtlasOffsets = atlasOffsets;
|
||||
}
|
||||
|
||||
public ResourcePath Path { get; }
|
||||
public RSIResource Resource { get; }
|
||||
public Image Atlas { get; }
|
||||
public Dictionary<RSI.StateId, Vector2i[][]> AtlasOffsets { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Robust.Shared.Utility;
|
||||
using SixLabors.ImageSharp;
|
||||
|
||||
namespace Robust.Client.ResourceManagement
|
||||
{
|
||||
public readonly struct TextureLoadedEventArgs
|
||||
{
|
||||
internal TextureLoadedEventArgs(ResourcePath path, Image image, TextureResource resource)
|
||||
{
|
||||
Path = path;
|
||||
Image = image;
|
||||
Resource = resource;
|
||||
}
|
||||
|
||||
public ResourcePath Path { get; }
|
||||
public Image Image { get; }
|
||||
public TextureResource Resource { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameObjects.Components;
|
||||
using Robust.Shared.Interfaces.GameObjects.Components;
|
||||
using Robust.Shared.Maths;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Robust.Server.GameObjects
|
||||
{
|
||||
public class ClickableComponent : Component, IClickableComponent
|
||||
{
|
||||
private Box2? _localBounds;
|
||||
|
||||
public Box2? LocalBounds
|
||||
{
|
||||
get => _localBounds;
|
||||
set => _localBounds = value;
|
||||
}
|
||||
|
||||
public override string Name => "Clickable";
|
||||
public override uint? NetID => NetIDs.CLICKABLE;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void ExposeData(ObjectSerializer serializer)
|
||||
{
|
||||
base.ExposeData(serializer);
|
||||
|
||||
serializer.DataField(ref _localBounds, "bounds", null);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ComponentState GetComponentState()
|
||||
{
|
||||
return new ClickableComponentState(_localBounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,9 +45,6 @@ namespace Robust.Server.GameObjects
|
||||
Register<PhysicsComponent>();
|
||||
Register<SpriteComponent>();
|
||||
|
||||
Register<ClickableComponent>();
|
||||
RegisterReference<ClickableComponent, IClickableComponent>();
|
||||
|
||||
Register<ContainerManagerComponent>();
|
||||
RegisterReference<ContainerManagerComponent, IContainerManager>();
|
||||
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
namespace Robust.Shared.Interfaces.GameObjects.Components
|
||||
{
|
||||
public interface IClickableComponent : IComponent { }
|
||||
}
|
||||
@@ -45,7 +45,6 @@ namespace Robust.UnitTesting.Shared.Prototypes
|
||||
Assert.That(prototype.Name, Is.EqualTo("Wall Light"));
|
||||
Assert.That(prototype.ID, Is.EqualTo(id));
|
||||
Assert.That(prototype.Components, Contains.Key("Transform"));
|
||||
Assert.That(prototype.Components, Contains.Key("Clickable"));
|
||||
Assert.That(prototype.Components, Contains.Key("Sprite"));
|
||||
Assert.That(prototype.Components, Contains.Key("PointLight"));
|
||||
});
|
||||
@@ -118,7 +117,6 @@ namespace Robust.UnitTesting.Shared.Prototypes
|
||||
name: Wall Light
|
||||
components:
|
||||
- type: Transform
|
||||
- type: Clickable
|
||||
- type: Sprite
|
||||
- type: PointLight
|
||||
startState: Off
|
||||
|
||||
Reference in New Issue
Block a user