using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace LocalMcp.UnityServer
{
#if UNITY_EDITOR
/// <summary>
/// Controls Unity Editor Play Mode (Start/Stop game)
/// </summary>
public static class EditorPlayModeControl
{
/// <summary>
/// Starts Play Mode
/// </summary>
public static string Play(object id)
{
try
{
if (EditorApplication.isPlaying)
{
var result = new PlayModeResult
{
success = false,
message = "Already in Play Mode",
isPlaying = true,
isPaused = EditorApplication.isPaused
};
var response = JsonRpcResponse.Success(result, id);
return response.ToJson();
}
EditorApplication.isPlaying = true;
var successResult = new PlayModeResult
{
success = true,
message = "Play Mode started",
isPlaying = true,
isPaused = false
};
var successResponse = JsonRpcResponse.Success(successResult, id);
return successResponse.ToJson();
}
catch (Exception e)
{
Debug.LogError($"[MCP] Play error: {e.Message}\n{e.StackTrace}");
return JsonRpcResponseHelper.ErrorMessage($"Failed to start Play Mode: {e.Message}", id);
}
}
/// <summary>
/// Stops Play Mode
/// </summary>
public static string Stop(object id)
{
try
{
if (!EditorApplication.isPlaying)
{
var result = new PlayModeResult
{
success = false,
message = "Not in Play Mode",
isPlaying = false,
isPaused = false
};
var response = JsonRpcResponse.Success(result, id);
return response.ToJson();
}
EditorApplication.isPlaying = false;
var successResult = new PlayModeResult
{
success = true,
message = "Play Mode stopped",
isPlaying = false,
isPaused = false
};
var successResponse = JsonRpcResponse.Success(successResult, id);
return successResponse.ToJson();
}
catch (Exception e)
{
Debug.LogError($"[MCP] Stop error: {e.Message}\n{e.StackTrace}");
return JsonRpcResponseHelper.ErrorMessage($"Failed to stop Play Mode: {e.Message}", id);
}
}
/// <summary>
/// Pauses Play Mode
/// </summary>
public static string Pause(object id)
{
try
{
if (!EditorApplication.isPlaying)
{
return JsonRpcResponseHelper.ErrorMessage("Not in Play Mode", id);
}
EditorApplication.isPaused = true;
var result = new PlayModeResult
{
success = true,
message = "Play Mode paused",
isPlaying = true,
isPaused = true
};
var response = JsonRpcResponse.Success(result, id);
return response.ToJson();
}
catch (Exception e)
{
Debug.LogError($"[MCP] Pause error: {e.Message}\n{e.StackTrace}");
return JsonRpcResponseHelper.ErrorMessage($"Failed to pause Play Mode: {e.Message}", id);
}
}
/// <summary>
/// Resumes Play Mode from pause
/// </summary>
public static string Resume(object id)
{
try
{
if (!EditorApplication.isPlaying)
{
return JsonRpcResponseHelper.ErrorMessage("Not in Play Mode", id);
}
if (!EditorApplication.isPaused)
{
var result = new PlayModeResult
{
success = false,
message = "Play Mode is not paused",
isPlaying = true,
isPaused = false
};
var response = JsonRpcResponse.Success(result, id);
return response.ToJson();
}
EditorApplication.isPaused = false;
var successResult = new PlayModeResult
{
success = true,
message = "Play Mode resumed",
isPlaying = true,
isPaused = false
};
var successResponse = JsonRpcResponse.Success(successResult, id);
return successResponse.ToJson();
}
catch (Exception e)
{
Debug.LogError($"[MCP] Resume error: {e.Message}\n{e.StackTrace}");
return JsonRpcResponseHelper.ErrorMessage($"Failed to resume Play Mode: {e.Message}", id);
}
}
/// <summary>
/// Steps one frame forward in paused Play Mode
/// </summary>
public static string Step(object id)
{
try
{
if (!EditorApplication.isPlaying)
{
return JsonRpcResponseHelper.ErrorMessage("Not in Play Mode", id);
}
if (!EditorApplication.isPaused)
{
return JsonRpcResponseHelper.ErrorMessage("Play Mode is not paused. Pause first to step.", id);
}
EditorApplication.Step();
var result = new PlayModeResult
{
success = true,
message = "Stepped one frame",
isPlaying = true,
isPaused = true
};
var response = JsonRpcResponse.Success(result, id);
return response.ToJson();
}
catch (Exception e)
{
Debug.LogError($"[MCP] Step error: {e.Message}\n{e.StackTrace}");
return JsonRpcResponseHelper.ErrorMessage($"Failed to step frame: {e.Message}", id);
}
}
/// <summary>
/// Gets the current Play Mode status
/// </summary>
public static string GetStatus(object id)
{
try
{
var result = new PlayModeStatusResult
{
isPlaying = EditorApplication.isPlaying,
isPaused = EditorApplication.isPaused,
isCompiling = EditorApplication.isCompiling,
isPlayingOrWillChangePlaymode = EditorApplication.isPlayingOrWillChangePlaymode
};
var response = JsonRpcResponse.Success(result, id);
return response.ToJson();
}
catch (Exception e)
{
Debug.LogError($"[MCP] GetStatus error: {e.Message}\n{e.StackTrace}");
return JsonRpcResponseHelper.ErrorMessage($"Failed to get Play Mode status: {e.Message}", id);
}
}
/// <summary>
/// Plays for a specified duration and captures logs
/// </summary>
public static string PlayAndCaptureLogs(string paramsJson, object id)
{
try
{
var parameters = JsonUtility.FromJson<PlayAndCaptureLogsParams>(paramsJson);
if (EditorApplication.isPlaying)
{
return JsonRpcResponseHelper.ErrorMessage("Already in Play Mode. Stop first before using this command.", id);
}
float duration = parameters.duration > 0 ? parameters.duration : 5.0f;
int logLimit = parameters.logLimit > 0 ? parameters.logLimit : 100;
string logLevel = string.IsNullOrEmpty(parameters.logLevel) ? "all" : parameters.logLevel;
// Start Play Mode
EditorApplication.isPlaying = true;
// Schedule stop after duration
double startTime = EditorApplication.timeSinceStartup;
EditorApplication.update += CheckStopTime;
void CheckStopTime()
{
if (EditorApplication.timeSinceStartup - startTime >= duration)
{
EditorApplication.update -= CheckStopTime;
if (EditorApplication.isPlaying)
{
EditorApplication.isPlaying = false;
}
Debug.Log($"[MCP] PlayAndCaptureLogs: Stopped after {duration} seconds");
}
}
var result = new PlayAndCaptureLogsResult
{
success = true,
message = $"Play Mode started for {duration} seconds. Will stop automatically.",
duration = duration,
logLimit = logLimit,
logLevel = logLevel,
instruction = $"Use unity.log.history with limit={logLimit} and level={logLevel} after {duration} seconds to retrieve logs"
};
var response = JsonRpcResponse.Success(result, id);
return response.ToJson();
}
catch (Exception e)
{
Debug.LogError($"[MCP] PlayAndCaptureLogs error: {e.Message}\n{e.StackTrace}");
return JsonRpcResponseHelper.ErrorMessage($"Failed to play and capture logs: {e.Message}", id);
}
}
}
#region Data Structures
[Serializable]
public class PlayModeResult
{
public bool success;
public string message;
public bool isPlaying;
public bool isPaused;
}
[Serializable]
public class PlayModeStatusResult
{
public bool isPlaying;
public bool isPaused;
public bool isCompiling;
public bool isPlayingOrWillChangePlaymode;
}
[Serializable]
public class PlayAndCaptureLogsParams
{
public float duration; // Duration in seconds to play (default: 5.0)
public int logLimit; // Number of logs to capture (default: 100)
public string logLevel; // Log level filter: "all", "error", "warning", "log" (default: "all")
}
[Serializable]
public class PlayAndCaptureLogsResult
{
public bool success;
public string message;
public float duration;
public int logLimit;
public string logLevel;
public string instruction;
}
#endregion
#endif
}