diff --git a/Content.Client/Sprite/ScaleVisualsSystem.cs b/Content.Client/Sprite/ScaleVisualsSystem.cs new file mode 100644 index 0000000000..06d25e0a1d --- /dev/null +++ b/Content.Client/Sprite/ScaleVisualsSystem.cs @@ -0,0 +1,38 @@ +using System.Numerics; +using Content.Shared.Sprite; +using Robust.Client.GameObjects; + +namespace Content.Client.Sprite; + +public sealed class ScaleVisualsSystem : SharedScaleVisualsSystem +{ + [Dependency] private readonly SpriteSystem _sprite = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnChangeData); + } + + private void OnChangeData(Entity ent, ref AppearanceChangeEvent args) + { + if (!args.AppearanceData.TryGetValue(ScaleVisuals.Scale, out var scale) || + args.Sprite == null) return; + + // save the original scale + ent.Comp.OriginalScale ??= args.Sprite.Scale; + + var vecScale = (Vector2)scale; + _sprite.SetScale((ent.Owner, args.Sprite), vecScale); + } + + // revert to the original scale + protected override void ResetScale(Entity ent) + { + base.ResetScale(ent); + + if (ent.Comp.OriginalScale != null) + _sprite.SetScale(ent.Owner, ent.Comp.OriginalScale.Value); + } +} diff --git a/Content.Server/Sprite/ScaleVisualsSystem.cs b/Content.Server/Sprite/ScaleVisualsSystem.cs new file mode 100644 index 0000000000..53e9233e60 --- /dev/null +++ b/Content.Server/Sprite/ScaleVisualsSystem.cs @@ -0,0 +1,5 @@ +using Content.Shared.Sprite; + +namespace Content.Server.Sprite; + +public sealed class ScaleVisualsSystem : SharedScaleVisualsSystem; diff --git a/Content.Server/Toolshed/Commands/Misc/ScaleCommand.cs b/Content.Server/Toolshed/Commands/Misc/ScaleCommand.cs new file mode 100644 index 0000000000..ab8cdf7ed9 --- /dev/null +++ b/Content.Server/Toolshed/Commands/Misc/ScaleCommand.cs @@ -0,0 +1,69 @@ +using System.Numerics; +using Content.Server.Administration; +using Content.Shared.Administration; +using Content.Shared.Sprite; +using Robust.Shared.Physics.Systems; +using Robust.Shared.Toolshed; + +namespace Content.Server.Toolshed.Commands.Misc; + +/// +/// Used to change an entity's sprite scale. +/// +[ToolshedCommand, AdminCommand(AdminFlags.VarEdit)] +public sealed class ScaleCommand : ToolshedCommand +{ + private SharedScaleVisualsSystem? _scaleVisuals; + private SharedPhysicsSystem? _physics; + + [CommandImplementation("set")] + public IEnumerable Set([PipedArgument] IEnumerable input, Vector2 scale) + { + _scaleVisuals ??= GetSys(); + + foreach (var ent in input) + { + _scaleVisuals.SetSpriteScale(ent, scale); + yield return ent; + } + } + + [CommandImplementation("multiply")] + public IEnumerable Multiply([PipedArgument] IEnumerable input, float factor) + { + _scaleVisuals ??= GetSys(); + + foreach (var ent in input) + { + var scale = _scaleVisuals.GetSpriteScale(ent) * factor; + _scaleVisuals.SetSpriteScale(ent, scale); + yield return ent; + } + } + + [CommandImplementation("multiplywithfixture")] + public IEnumerable MultiplyWithFixture([PipedArgument] IEnumerable input, float factor) + { + _scaleVisuals ??= GetSys(); + _physics ??= GetSys(); + + foreach (var ent in input) + { + var scale = _scaleVisuals.GetSpriteScale(ent) * factor; + _scaleVisuals.SetSpriteScale(ent, scale); + _physics.ScaleFixtures(ent, factor); + yield return ent; + } + } + + [CommandImplementation("get")] + public IEnumerable Get([PipedArgument] IEnumerable input) + { + _scaleVisuals ??= GetSys(); + + foreach (var ent in input) + { + yield return _scaleVisuals.GetSpriteScale(ent); + } + } +} diff --git a/Content.Shared/Sprite/ScaleVisualsComponent.cs b/Content.Shared/Sprite/ScaleVisualsComponent.cs new file mode 100644 index 0000000000..a9c1fcb39c --- /dev/null +++ b/Content.Shared/Sprite/ScaleVisualsComponent.cs @@ -0,0 +1,27 @@ +using System.Numerics; +using Robust.Shared.GameStates; + +namespace Content.Shared.Sprite; + +/// +/// Used to set the datafield to a certain value from the server. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedScaleVisualsSystem))] +public sealed partial class ScaleVisualsComponent : Component +{ + /// + /// The current sprite scale. + /// + [DataField, AutoNetworkedField] + [ViewVariables] + public Vector2 Scale = Vector2.One; + + /// + /// The original sprite scale, which we revert to if this component is removed. + /// Only set on the client. + /// + [DataField] + [ViewVariables] + public Vector2? OriginalScale; +} diff --git a/Content.Shared/Sprite/SharedScaleVisualsSystem.cs b/Content.Shared/Sprite/SharedScaleVisualsSystem.cs new file mode 100644 index 0000000000..fd2a522cd0 --- /dev/null +++ b/Content.Shared/Sprite/SharedScaleVisualsSystem.cs @@ -0,0 +1,77 @@ +using System.Numerics; +using Robust.Shared.Serialization; + +namespace Content.Shared.Sprite; + +public abstract class SharedScaleVisualsSystem : EntitySystem +{ + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnComponentShutdown); + } + + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + SetSpriteScale(ent.Owner, ent.Comp.Scale); + } + + private void OnComponentShutdown(Entity ent, ref ComponentShutdown args) + { + ResetScale(ent); + } + + protected virtual void ResetScale(Entity ent) + { + var ev = new ScaleEntityEvent(ent.Owner, Vector2.One); + RaiseLocalEvent(ent.Owner, ref ev); + } + + /// + /// Used to set the datafield to a certain value from the server. + /// + public void SetSpriteScale(EntityUid uid, Vector2 scale) + { + var comp = EnsureComp(uid); + comp.Scale = scale; + Dirty(uid, comp); + + var appearanceComponent = EnsureComp(uid); + _appearance.SetData(uid, ScaleVisuals.Scale, scale, appearanceComponent); + + // Raise an event for content use. + var ev = new ScaleEntityEvent(uid, scale); + RaiseLocalEvent(uid, ref ev); + } + + /// + /// Gets the current scale set by . + /// This does not include any direct changes made to the SpriteComponent. + /// + public Vector2 GetSpriteScale(EntityUid uid) + { + if (!TryComp(uid, out var appearanceComponent)) + return Vector2.One; + + if (!_appearance.TryGetData(uid, ScaleVisuals.Scale, out var scale, appearanceComponent)) + scale = Vector2.One; + + return scale; + } +} + +/// +/// Raised when a sprite scale is changed. +/// +[ByRefEvent] +public readonly record struct ScaleEntityEvent(EntityUid Uid, Vector2 Scale); + +[Serializable, NetSerializable] +public enum ScaleVisuals : byte +{ + Scale, +} diff --git a/Resources/Locale/en-US/commands/toolshed-commands.ftl b/Resources/Locale/en-US/commands/toolshed-commands.ftl index 90c0226ecc..08732fabac 100644 --- a/Resources/Locale/en-US/commands/toolshed-commands.ftl +++ b/Resources/Locale/en-US/commands/toolshed-commands.ftl @@ -96,3 +96,11 @@ command-description-xenoartifact-unlockAllNodes = Unlocks all nodes of artifact. command-description-jobboard-completeJob = Completes a given salvage job board job for the station. +command-description-scale-set = + Sets an entity's sprite size to a certain scale (without changing its fixture). +command-description-scale-get = + Get an entity's sprite scale as set by ScaleVisualsComponent. Does not include any changes directly made in the SpriteComponent. +command-description-scale-multiply = + Multiply an entity's sprite size with a certain factor (without changing its fixture). +command-description-scale-multiplywithfixture = + Multiply an entity's sprite size with a certain factor (including its fixture). diff --git a/Resources/engineCommandPerms.yml b/Resources/engineCommandPerms.yml index a41e945615..5af33603f9 100644 --- a/Resources/engineCommandPerms.yml +++ b/Resources/engineCommandPerms.yml @@ -8,7 +8,6 @@ - vvread - vvwrite - vvinvoke - - scale - spin - Flags: DEBUG