using Content.Shared.Input; using Content.Shared.Movement.Components; using Robust.Shared.Input; using Robust.Shared.Input.Binding; using Robust.Shared.Players; using Robust.Shared.Serialization; namespace Content.Shared.Movement.Systems; /// /// Lets specific sessions scroll and set their zoom directly. /// public abstract class SharedContentEyeSystem : EntitySystem { private const float ZoomMod = 1.2f; private const byte ZoomMultiple = 10; protected static readonly Vector2 MinZoom = new(MathF.Pow(ZoomMod, -ZoomMultiple), MathF.Pow(ZoomMod, -ZoomMultiple)); protected ISawmill Sawmill = Logger.GetSawmill("ceye"); public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnContentEyeStartup); SubscribeAllEvent(OnContentZoomRequest); CommandBinds.Builder .Bind(ContentKeyFunctions.ZoomIn, new ScrollInputCmdHandler(true, this)) .Bind(ContentKeyFunctions.ZoomOut, new ScrollInputCmdHandler(false, this)) .Bind(ContentKeyFunctions.ResetZoom, new ResetZoomInputCmdHandler(this)) .Register(); Sawmill.Level = LogLevel.Info; } private void OnContentZoomRequest(RequestTargetZoomEvent msg, EntitySessionEventArgs args) { if (!TryComp(args.SenderSession.AttachedEntity, out var content)) return; content.TargetZoom = msg.TargetZoom; Dirty(content); } public override void Shutdown() { base.Shutdown(); CommandBinds.Unregister(); } private void OnContentEyeStartup(EntityUid uid, ContentEyeComponent component, ComponentStartup args) { if (!TryComp(uid, out var eyeComp)) return; component.TargetZoom = eyeComp.Zoom; Dirty(component); } protected void UpdateEye(EntityUid uid, ContentEyeComponent content, SharedEyeComponent eye, float frameTime) { var diff = content.TargetZoom - eye.Zoom; if (diff.LengthSquared < 0.0000001f) { eye.Zoom = content.TargetZoom; Dirty(eye); return; } var change = diff * 8f * frameTime; eye.Zoom += change; Dirty(eye); } private bool CanZoom(EntityUid uid, ContentEyeComponent? component = null) { return Resolve(uid, ref component, false); } private void ResetZoom(EntityUid uid, ContentEyeComponent? component = null) { if (!Resolve(uid, ref component)) return; if (component.TargetZoom.Equals(Vector2.One)) return; component.TargetZoom = Vector2.One; Dirty(component); } private void Zoom(EntityUid uid, bool zoomIn, ContentEyeComponent? component = null) { if (!Resolve(uid, ref component)) return; var actual = component.TargetZoom; if (zoomIn) { actual /= ZoomMod; } else { actual *= ZoomMod; } actual = Vector2.ComponentMax(MinZoom, actual); actual = Vector2.ComponentMin(component.MaxZoom, actual); if (actual.Equals(component.TargetZoom)) return; component.TargetZoom = actual; Dirty(component); Sawmill.Debug($"Set target zoom to {actual}"); } private sealed class ResetZoomInputCmdHandler : InputCmdHandler { private readonly SharedContentEyeSystem _system; public ResetZoomInputCmdHandler(SharedContentEyeSystem system) { _system = system; } public override bool HandleCmdMessage(ICommonSession? session, InputCmdMessage message) { ContentEyeComponent? component = null; if (message is not FullInputCmdMessage full || session?.AttachedEntity == null || full.State != BoundKeyState.Down || !_system.CanZoom(session.AttachedEntity.Value, component)) { return false; } _system.ResetZoom(session.AttachedEntity.Value, component); return false; } } private sealed class ScrollInputCmdHandler : InputCmdHandler { private readonly bool _zoomIn; private readonly SharedContentEyeSystem _system; public ScrollInputCmdHandler(bool zoomIn, SharedContentEyeSystem system) { _zoomIn = zoomIn; _system = system; } public override bool HandleCmdMessage(ICommonSession? session, InputCmdMessage message) { ContentEyeComponent? component = null; if (message is not FullInputCmdMessage full || session?.AttachedEntity == null || full.State != BoundKeyState.Down || !_system.CanZoom(session.AttachedEntity.Value, component)) { return false; } _system.Zoom(session.AttachedEntity.Value, _zoomIn, component); return false; } } /// /// Sendable from client to server to request a target zoom. /// [Serializable, NetSerializable] public sealed class RequestTargetZoomEvent : EntityEventArgs { public Vector2 TargetZoom; } }