Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion Packages/src/Editor/Api/McpTools/ReplayInput/InputReplayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ internal static class InputReplayer
// Mouse.current state, so UI interactions must go through ExecuteEvents directly.
private static bool _hasMousePosition;
private static bool _prevLeftButtonHeld;
private static Vector2? _previousReplayMousePosition;
private static bool _suppressIdleUiOverlay;
private static PointerEventData? _pointerData;
private static GameObject? _currentPressTarget;
private static GameObject? _currentDragTarget;
Expand Down Expand Up @@ -452,6 +454,10 @@ private static void ApplyUiEvents()
}

Vector2 screenPos = _replayMousePosition.Value;
bool mouseMoved = !_previousReplayMousePosition.HasValue
|| _previousReplayMousePosition.Value != screenPos;
_previousReplayMousePosition = screenPos;

bool leftHeld = _replayHeldButtons.Contains(MouseButton.Left);
bool justPressed = leftHeld && !_prevLeftButtonHeld;
bool justReleased = !leftHeld && _prevLeftButtonHeld;
Expand All @@ -462,10 +468,12 @@ private static void ApplyUiEvents()

if (justPressed)
{
_suppressIdleUiOverlay = false;
_pressTime = Time.realtimeSinceStartup;
OnUiPointerDown(screenPos, eventSystem);
SimulateMouseUiOverlayState.Update(
MouseAction.Click, inputPos, null, _currentPressTarget?.name, gameViewSize);
SimulateMouseUiOverlayState.RequestExpandAnimation();
}
else if (leftHeld && (_currentPressTarget != null || _currentDragTarget != null))
{
Expand All @@ -488,15 +496,20 @@ private static void ApplyUiEvents()
}
}
}
else
else if (!_suppressIdleUiOverlay || mouseMoved)
{
// Keeping the overlay hidden until the pointer actually moves prevents release fade-out
// from being cancelled by the next idle frame at the same position.
_suppressIdleUiOverlay = false;
SimulateMouseUiOverlayState.Update(
MouseAction.Click, inputPos, null, null, gameViewSize);
}

if (justReleased)
{
OnUiPointerUp(screenPos, eventSystem);
_suppressIdleUiOverlay = true;
SimulateMouseUiOverlayState.RequestDissipateAnimation();
SimulateMouseUiOverlayState.Clear();
}
}
Expand Down Expand Up @@ -642,7 +655,9 @@ private static bool DetectMousePositionEvents(InputRecordingData data)
private static void ResetUiReplayState()
{
_replayMousePosition = null;
_previousReplayMousePosition = null;
_prevLeftButtonHeld = false;
_suppressIdleUiOverlay = false;
_pointerData = null;
_currentPressTarget = null;
_currentDragTarget = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ public class SimulateMouseUiTool : AbstractUnityTool<SimulateMouseUiSchema, Simu
{
public override string ToolName => "simulate-mouse-ui";

private const float EXPAND_DURATION = 0.1f;
private const float EXPAND_START_SCALE = 1.5f;
private const float DISSIPATE_DURATION = 0.1f;
private const float EXPAND_DURATION = SimulateMouseUiAnimationConstants.EXPAND_DURATION;
private const float EXPAND_START_SCALE = SimulateMouseUiAnimationConstants.EXPAND_START_SCALE;
private const float DISSIPATE_DURATION = SimulateMouseUiAnimationConstants.DISSIPATE_DURATION;

protected override async Task<SimulateMouseUiResponse> ExecuteAsync(
SimulateMouseUiSchema parameters,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace io.github.hatayama.uLoopMCP
{
public static class SimulateMouseUiAnimationConstants
{
public const float EXPAND_DURATION = 0.1f;
public const float EXPAND_START_SCALE = 1.5f;
public const float DISSIPATE_DURATION = 0.1f;
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 56 additions & 0 deletions Packages/src/Runtime/SimulateMouseUi/SimulateMouseUiOverlay.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ public class SimulateMouseUiOverlay : MonoBehaviour
private readonly List<Image> _pathSegments = new List<Image>();
private readonly List<Image> _waypointMarkers = new List<Image>();

private const float SELF_EXPAND_DURATION = SimulateMouseUiAnimationConstants.EXPAND_DURATION;
private const float SELF_EXPAND_START_SCALE = SimulateMouseUiAnimationConstants.EXPAND_START_SCALE;
private const float SELF_DISSIPATE_DURATION = SimulateMouseUiAnimationConstants.DISSIPATE_DURATION;

private enum SelfAnimState { None, Expanding, Dissipating }
private SelfAnimState _selfAnimState = SelfAnimState.None;
private float _selfAnimStartTime;

private void Awake()
{
Debug.Assert(_canvasGroup != null, "_canvasGroup must be assigned in prefab");
Expand All @@ -43,6 +51,23 @@ private void Awake()

private void LateUpdate()
{
ConsumePendingAnimationRequests();

// Dissipate runs independently of overlay state (state is already cleared on release)
if (_selfAnimState == SelfAnimState.Dissipating)
{
float elapsed = Time.realtimeSinceStartup - _selfAnimStartTime;
float t = Mathf.Clamp01(elapsed / SELF_DISSIPATE_DURATION);
_cursorGroup.localScale = Vector3.one * Mathf.Lerp(1f, 0f, t);
_canvasGroup.alpha = Mathf.Lerp(1f, 0f, t);
if (t >= 1f)
{
_selfAnimState = SelfAnimState.None;
_canvasGroup.alpha = 0f;
}
return;
}

if (!SimulateMouseUiOverlayState.IsActive)
{
_canvasGroup.alpha = 0;
Expand All @@ -57,19 +82,50 @@ private void LateUpdate()
_cursorGroup.localScale = Vector3.one;
}

if (_selfAnimState == SelfAnimState.Expanding)
{
float elapsed = Time.realtimeSinceStartup - _selfAnimStartTime;
float t = Mathf.Clamp01(elapsed / SELF_EXPAND_DURATION);
_cursorGroup.localScale = Vector3.one * Mathf.Lerp(SELF_EXPAND_START_SCALE, 1f, t);
if (t >= 1f)
{
_selfAnimState = SelfAnimState.None;
}
}

UpdateCursorPosition();
UpdateCursorMode();
UpdateDragPath();
}

private void ConsumePendingAnimationRequests()
{
if (SimulateMouseUiOverlayState.ConsumePendingExpandAnimation())
{
_canvasGroup.alpha = 1f;
_cursorGroup.localScale = Vector3.one * SELF_EXPAND_START_SCALE;
_selfAnimState = SelfAnimState.Expanding;
_selfAnimStartTime = Time.realtimeSinceStartup;
}

if (SimulateMouseUiOverlayState.ConsumePendingDissipateAnimation())
{
_selfAnimState = SelfAnimState.Dissipating;
_selfAnimStartTime = Time.realtimeSinceStartup;
}
}

public void SetCursorScale(float scale)
{
_cursorGroup.localScale = Vector3.one * scale;
// SimulateMouseUiTool drives animation externally; cancel any self-driven animation
_selfAnimState = SelfAnimState.None;
}

public void SetAlpha(float alpha)
{
_canvasGroup.alpha = alpha;
_selfAnimState = SelfAnimState.None;
}

// sim coordinate: simX = screen pixel X, simY = EditorScreen.height - canvasY (top-left origin)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ public static class SimulateMouseUiOverlayState

public static float LongPressElapsed { get; private set; }

// Animation request flags survive Clear() — they are consumed by the overlay in LateUpdate
private static bool _pendingExpandAnimation;
private static bool _pendingDissipateAnimation;

private const int MAX_DRAG_WAYPOINTS = 4;

private static readonly List<Vector2> _dragWaypoints = new List<Vector2>();
Expand Down Expand Up @@ -67,6 +71,38 @@ public static void AddWaypoint(Vector2 position)
_dragWaypoints.Add(position);
}

public static void RequestExpandAnimation()
{
_pendingExpandAnimation = true;
}

public static void RequestDissipateAnimation()
{
_pendingDissipateAnimation = true;
}

public static bool ConsumePendingExpandAnimation()
{
if (!_pendingExpandAnimation)
{
return false;
}

_pendingExpandAnimation = false;
return true;
}

public static bool ConsumePendingDissipateAnimation()
{
if (!_pendingDissipateAnimation)
{
return false;
}

_pendingDissipateAnimation = false;
return true;
}

public static void Clear()
{
IsActive = false;
Expand Down
Loading