Initial commit: AIGame Unity client with URP, HybridCLR, YooAsset and tooling.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
udx
2026-09-21 14:21:07 +08:00
co-authored by Cursor
commit f3f66ab063
931 changed files with 112366 additions and 0 deletions
@@ -0,0 +1,208 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Unity.Pipeline.Models
{
/// <summary>
/// Response model for /api/exec endpoint.
/// Contains execution result and metadata for remote command execution.
/// </summary>
[Serializable]
public class CommandExecutionResponse : BaseResponse
{
/// <summary>
/// Whether the command executed successfully.
/// </summary>
[JsonProperty("success")]
public bool Success { get; set; }
/// <summary>
/// Name of the command that was executed.
/// </summary>
[JsonProperty("command")]
public string Command { get; set; }
/// <summary>
/// Result returned by the command (if any).
/// </summary>
[JsonProperty("result")]
public object Result { get; set; }
/// <summary>
/// Execution duration in milliseconds.
/// </summary>
/// <remarks>
/// Like <c>command</c> and <c>executedAt</c>, emitted on the /api/exec wire only in verbose
/// mode — the gating lives in <c>ExecResponseSerializer</c>, not on this model. (AUTHAPI-21)
/// </remarks>
[JsonProperty("executionTimeMs")]
public long? ExecutionTimeMs { get; set; }
/// <summary>
/// Coarse machine-readable server state marker. Set to "busy" when the command was not
/// executed because the server's host cannot service it yet (e.g. the Editor is still
/// settling after a cold start). Omitted from the JSON on ordinary success/failure
/// responses, so existing envelopes are unchanged.
/// </summary>
[JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)]
public string Status { get; set; }
/// <summary>
/// True when the failure is transient and the same request is expected to succeed after a
/// short wait (poll /api/status until it reports "ready"). Omitted from the JSON on
/// ordinary success/failure responses.
/// </summary>
[JsonProperty("retryable", NullValueHandling = NullValueHandling.Ignore)]
public bool? Retryable { get; set; }
/// <summary>
/// Stable, machine-readable failure discriminator (e.g. <c>INVALID_COMMAND_ARGS</c>).
///
/// HTTP status cannot serve as the discriminator here: every /api/exec failure is 400, so
/// status alone cannot separate "your arguments are wrong" from "the command threw".
/// Spelled to match the <c>unity</c> CLI's own InvalidArgsCode literal, so neither side
/// needs a translation table.
/// </summary>
[JsonProperty("errorCode", NullValueHandling = NullValueHandling.Ignore)]
public string ErrorCode { get; set; }
/// <summary>
/// Every argument-binding defect found, one entry each — the binder accumulates rather
/// than bailing, so a user fixing a command line sees all of its problems at once.
/// Machine-readable rather than prose, because the <c>unity</c> CLI renders and localizes
/// these itself; <see cref="BaseResponse.ErrorDetails"/> carries the English fallback for
/// clients that do not.
/// </summary>
[JsonProperty("argProblems", NullValueHandling = NullValueHandling.Ignore)]
public List<ArgProblem> ArgProblems { get; set; }
/// <summary>
/// The resolved command's catalog entry, shaped like a /api/commands <c>commands[]</c>
/// element. Sent with an argument error so a client can render usage without a separate
/// schema request. Free to produce - the command is already resolved at that point.
/// </summary>
[JsonProperty("commandSchema", NullValueHandling = NullValueHandling.Ignore)]
public JObject CommandSchema { get; set; }
/// <summary>
/// What the server bound from a raw command line. Set ONLY for argv/commandLine requests,
/// leaving the structured path's envelope unchanged. A client that does not bind locally
/// has no other way to report what the command actually received.
/// </summary>
[JsonProperty("parameters", NullValueHandling = NullValueHandling.Ignore)]
public JObject BoundParameters { get; set; }
/// <summary>
/// Create the argument-binding failure response (sent with HTTP 400): the command was
/// resolved but its arguments could not be bound, so nothing executed.
/// </summary>
internal static CommandExecutionResponse CmdInvalidArgs(string cmd, string details,
List<ArgProblem> problems, JObject commandSchema)
{
return new CommandExecutionResponse
{
Command = cmd,
Success = false,
ExecutedAt = DateTime.UtcNow,
Error = "Invalid Command Arguments",
ErrorDetails = details,
ErrorCode = "INVALID_COMMAND_ARGS",
ArgProblems = problems,
CommandSchema = commandSchema
};
}
/// <summary>
/// The specific cause of a "busy" response, matching /api/status's own "status" values for
/// the same conditions ("settling", "blocked_by_dialog") — a caller can branch on this
/// directly instead of inferring the cause from whether "dialogs" happens to be populated.
/// Omitted from the JSON on ordinary success/failure responses.
/// </summary>
[JsonProperty("busyReason", NullValueHandling = NullValueHandling.Ignore)]
public string BusyReason { get; set; }
/// <summary>
/// Dialogs (see EditorDialogEvents) that opened at or after this call started. Omitted
/// when none occurred, so existing envelopes are unchanged. Lets a caller learn "this
/// call took 40s because a dialog was shown" even without polling /api/dialog
/// concurrently.
/// </summary>
[JsonProperty("dialogsDuringExecution", NullValueHandling = NullValueHandling.Ignore)]
public List<object> DialogsDuringExecution { get; set; }
/// <summary>
/// Currently-open dialog(s) (see EditorDialogEvents), attached to a busy response when a
/// MainThreadRequired command was rejected because a modal dialog is blocking the main
/// thread. Omitted otherwise.
/// </summary>
[JsonProperty("dialogs", NullValueHandling = NullValueHandling.Ignore)]
public List<object> Dialogs { get; set; }
/// <summary>
/// Create a successful execution response.
/// </summary>
/// <param name="command">Name of the executed command.</param>
/// <param name="result">The command's result payload.</param>
/// <param name="executionTimeMs">How long the command took to execute, in milliseconds.</param>
/// <returns>A successful response wrapping <paramref name="result"/>.</returns>
public static CommandExecutionResponse CmdSuccess(string command, object result = null, long? executionTimeMs = null)
{
return new CommandExecutionResponse
{
Success = true,
Command = command,
ExecutedAt = DateTime.UtcNow,
Result = result,
ExecutionTimeMs = executionTimeMs
};
}
/// <summary>
/// Create a failed execution response.
/// </summary>
/// <param name="cmd">Name of the executed command.</param>
/// <param name="error">Error message.</param>
/// <param name="errorDetails">Additional error details for debugging.</param>
/// <returns>A failed response with <see cref="BaseResponse.Error"/>/<see cref="BaseResponse.ErrorDetails"/> set.</returns>
public static CommandExecutionResponse CmdFailure(string cmd, string error, string errorDetails)
{
return new CommandExecutionResponse
{
Command = cmd,
Success = false,
ExecutedAt = DateTime.UtcNow,
Error = error,
ErrorDetails = errorDetails
};
}
/// <summary>
/// Create the retryable "server busy" response (sent with HTTP 503): the command was not
/// executed because the host cannot service it yet — distinguishable from a genuine
/// command failure via status/retryable so callers know to retry shortly instead of
/// guessing (AUTHAPI-35). <paramref name="busyReason"/> is the specific cause ("settling",
/// "blocked_by_dialog", ...); omit it only for a generic/legacy busy state.
/// </summary>
/// <param name="cmd">Name of the command that could not be serviced yet.</param>
/// <param name="details">Human-readable reason the host is busy.</param>
/// <param name="busyReason">The specific cause of the busy state, or null for a generic/legacy busy state.</param>
/// <returns>A retryable "server busy" response.</returns>
public static CommandExecutionResponse CmdBusy(string cmd, string details, string busyReason = null)
{
return new CommandExecutionResponse
{
Command = cmd,
Success = false,
ExecutedAt = DateTime.UtcNow,
Error = "Server Busy",
ErrorDetails = details,
Status = "busy",
Retryable = true,
BusyReason = busyReason
};
}
}
}