590 lines
27 KiB
C#
590 lines
27 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Newtonsoft.Json.Linq;
|
|
using UnityEditor;
|
|
using UnityEditor.Build;
|
|
using UnityEditor.Build.Reporting;
|
|
using MCPForUnity.Editor.Helpers;
|
|
using MCPForUnity.Editor.Tools.Build;
|
|
|
|
namespace MCPForUnity.Editor.Tools
|
|
{
|
|
[McpForUnityTool("manage_build", AutoRegister = false, Group = "core",
|
|
RequiresPolling = true, PollAction = "status", MaxPollSeconds = 1800)]
|
|
public static class ManageBuild
|
|
{
|
|
private static readonly string[] ValidActions =
|
|
{ "build", "status", "platform", "settings", "scenes", "profiles", "batch", "cancel" };
|
|
|
|
public static object HandleCommand(JObject @params)
|
|
{
|
|
if (@params == null)
|
|
return new ErrorResponse("Parameters cannot be null.");
|
|
|
|
var p = new ToolParams(@params);
|
|
var actionResult = p.GetRequired("action");
|
|
if (!actionResult.IsSuccess)
|
|
return new ErrorResponse(actionResult.ErrorMessage);
|
|
|
|
string action = actionResult.Value.ToLowerInvariant();
|
|
|
|
if (!ValidActions.Contains(action))
|
|
return new ErrorResponse(
|
|
$"Unknown action '{action}'. Valid actions: {string.Join(", ", ValidActions)}");
|
|
|
|
try
|
|
{
|
|
switch (action)
|
|
{
|
|
case "build": return HandleBuild(p);
|
|
case "status": return HandleStatus(p);
|
|
case "platform": return HandlePlatform(p);
|
|
case "settings": return HandleSettings(p);
|
|
case "scenes": return HandleScenes(p);
|
|
case "profiles": return HandleProfiles(p);
|
|
case "batch": return HandleBatch(p);
|
|
case "cancel": return HandleCancel(p);
|
|
default:
|
|
return new ErrorResponse($"Unknown action: '{action}'");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return new ErrorResponse(ex.Message, new { stackTrace = ex.StackTrace });
|
|
}
|
|
}
|
|
|
|
// ── build ──────────────────────────────────────────────────────
|
|
|
|
private static object HandleBuild(ToolParams p)
|
|
{
|
|
if (BuildPipeline.isBuildingPlayer)
|
|
return new ErrorResponse("A build is already in progress.");
|
|
|
|
string targetName = p.Get("target");
|
|
if (!BuildTargetMapping.TryResolveBuildTarget(targetName, out var target))
|
|
return new ErrorResponse(BuildTargetMapping.GetUnknownBuildTargetMessage(targetName));
|
|
|
|
var group = BuildTargetMapping.GetTargetGroup(target);
|
|
if (!BuildPipeline.IsBuildTargetSupported(group, target))
|
|
return new ErrorResponse(
|
|
$"Platform '{target}' is not installed. Install it via Unity Hub.");
|
|
|
|
string outputPath = p.Get("output_path")
|
|
?? BuildTargetMapping.GetDefaultOutputPath(target, PlayerSettings.productName);
|
|
string[] scenes = p.GetStringArray("scenes");
|
|
bool development = p.GetBool("development");
|
|
string[] optionNames = p.GetStringArray("options");
|
|
string subtargetStr = p.Get("subtarget");
|
|
string scriptingBackend = p.Get("scripting_backend");
|
|
|
|
// Apply scripting backend if specified (persistent change)
|
|
if (!string.IsNullOrEmpty(scriptingBackend))
|
|
{
|
|
string backendLower = scriptingBackend.ToLowerInvariant();
|
|
if (backendLower != "il2cpp" && backendLower != "mono")
|
|
return new ErrorResponse(
|
|
$"Unknown scripting_backend '{scriptingBackend}'. Valid: mono, il2cpp");
|
|
var namedTarget = BuildTargetMapping.GetNamedBuildTarget(target);
|
|
var impl = backendLower == "il2cpp"
|
|
? ScriptingImplementation.IL2CPP
|
|
: ScriptingImplementation.Mono2x;
|
|
PlayerSettings.SetScriptingBackend(namedTarget, impl);
|
|
}
|
|
|
|
#if UNITY_6000_0_OR_NEWER
|
|
string profilePath = p.Get("profile");
|
|
if (!string.IsNullOrEmpty(profilePath))
|
|
return HandleProfileBuild(p, profilePath, outputPath, development, optionNames);
|
|
#else
|
|
string profilePath = p.Get("profile");
|
|
if (!string.IsNullOrEmpty(profilePath))
|
|
McpLog.Warn($"Build Profile param ignored — requires Unity 6+. Current: {UnityEngine.Application.unityVersion}");
|
|
#endif
|
|
|
|
var buildOptions = BuildRunner.ParseBuildOptions(optionNames, development);
|
|
int subtarget = BuildTargetMapping.ResolveSubtarget(subtargetStr);
|
|
var options = BuildRunner.CreateBuildOptions(target, outputPath, scenes, buildOptions, subtarget);
|
|
|
|
string jobId = BuildJobStore.CreateJobId();
|
|
var job = new BuildJob(jobId, target, outputPath);
|
|
return BuildRunner.ScheduleBuild(job, options);
|
|
}
|
|
|
|
#if UNITY_6000_0_OR_NEWER
|
|
private static object HandleProfileBuild(ToolParams p, string profilePath, string outputPath,
|
|
bool development, string[] optionNames)
|
|
{
|
|
var profile = UnityEditor.AssetDatabase.LoadAssetAtPath<
|
|
UnityEditor.Build.Profile.BuildProfile>(profilePath);
|
|
if (profile == null)
|
|
return new ErrorResponse($"Build profile not found at: {profilePath}");
|
|
|
|
var buildOptions = BuildRunner.ParseBuildOptions(optionNames, development);
|
|
var options = new BuildPlayerWithProfileOptions
|
|
{
|
|
buildProfile = profile,
|
|
locationPathName = outputPath,
|
|
options = buildOptions
|
|
};
|
|
|
|
// BuildPlayerWithProfileOptions derives the actual target from the profile,
|
|
// but we use activeBuildTarget for job metadata/status display
|
|
var target = EditorUserBuildSettings.activeBuildTarget;
|
|
string jobId = BuildJobStore.CreateJobId();
|
|
var job = new BuildJob(jobId, target, outputPath);
|
|
return BuildRunner.ScheduleProfileBuild(job, options);
|
|
}
|
|
#endif
|
|
|
|
// ── status ─────────────────────────────────────────────────────
|
|
|
|
private static object HandleStatus(ToolParams p)
|
|
{
|
|
string jobId = p.Get("job_id");
|
|
|
|
if (string.IsNullOrEmpty(jobId))
|
|
{
|
|
// Prefer active (pending/building) job — needed for polling middleware
|
|
var last = BuildJobStore.LastCompletedJob;
|
|
if (last != null && (last.State == BuildJobState.Building || last.State == BuildJobState.Pending))
|
|
{
|
|
return new PendingResponse(
|
|
$"Build {last.State.ToString().ToLowerInvariant()}...",
|
|
pollIntervalSeconds: 5.0,
|
|
data: last.ToStatusResponse()
|
|
);
|
|
}
|
|
|
|
if (last != null)
|
|
return new SuccessResponse("Last completed build.", last.ToStatusResponse());
|
|
|
|
#if UNITY_6000_0_OR_NEWER
|
|
var latestReport = BuildReport.GetLatestReport();
|
|
if (latestReport != null)
|
|
{
|
|
var s = latestReport.summary;
|
|
return new SuccessResponse("Last build report from Unity.", new
|
|
{
|
|
result = s.result.ToString().ToLowerInvariant(),
|
|
platform = s.platform.ToString(),
|
|
output_path = s.outputPath,
|
|
total_size_mb = Math.Round(s.totalSize / (1024.0 * 1024.0), 2),
|
|
duration_seconds = s.totalTime.TotalSeconds,
|
|
errors = s.totalErrors,
|
|
warnings = s.totalWarnings
|
|
});
|
|
}
|
|
#endif
|
|
return new ErrorResponse("No build jobs found.");
|
|
}
|
|
|
|
// Check batch jobs first
|
|
var batchJob = BuildJobStore.GetBatchJob(jobId);
|
|
if (batchJob != null)
|
|
return new SuccessResponse($"Batch {batchJob.State}.", batchJob.ToStatusResponse());
|
|
|
|
var buildJob = BuildJobStore.GetBuildJob(jobId);
|
|
if (buildJob == null)
|
|
return new ErrorResponse($"No job found with ID: {jobId}");
|
|
|
|
if (buildJob.State == BuildJobState.Building || buildJob.State == BuildJobState.Pending)
|
|
{
|
|
return new PendingResponse(
|
|
$"Build {buildJob.State.ToString().ToLowerInvariant()}...",
|
|
pollIntervalSeconds: 5.0,
|
|
data: buildJob.ToStatusResponse()
|
|
);
|
|
}
|
|
|
|
return new SuccessResponse($"Build {buildJob.State}.", buildJob.ToStatusResponse());
|
|
}
|
|
|
|
// ── platform ───────────────────────────────────────────────────
|
|
|
|
private static object HandlePlatform(ToolParams p)
|
|
{
|
|
string targetName = p.Get("target");
|
|
|
|
if (string.IsNullOrEmpty(targetName))
|
|
{
|
|
// Read current platform
|
|
return new SuccessResponse("Current platform.", new
|
|
{
|
|
target = EditorUserBuildSettings.activeBuildTarget.ToString(),
|
|
target_group = BuildTargetMapping.GetTargetGroup(
|
|
EditorUserBuildSettings.activeBuildTarget).ToString(),
|
|
subtarget = EditorUserBuildSettings.standaloneBuildSubtarget.ToString()
|
|
});
|
|
}
|
|
|
|
// Switch platform
|
|
if (!BuildTargetMapping.TryResolveBuildTarget(targetName, out var target))
|
|
return new ErrorResponse(BuildTargetMapping.GetUnknownBuildTargetMessage(targetName));
|
|
|
|
var group = BuildTargetMapping.GetTargetGroup(target);
|
|
if (!BuildPipeline.IsBuildTargetSupported(group, target))
|
|
return new ErrorResponse(
|
|
$"Platform '{target}' is not installed. Install it via Unity Hub.");
|
|
|
|
if (EditorUserBuildSettings.activeBuildTarget == target)
|
|
return new SuccessResponse("Already on this platform.", new
|
|
{
|
|
target = target.ToString()
|
|
});
|
|
|
|
// Capture previous target before switching
|
|
string previousTarget = EditorUserBuildSettings.activeBuildTarget.ToString();
|
|
|
|
string subtargetStr = p.Get("subtarget");
|
|
if (!string.IsNullOrEmpty(subtargetStr))
|
|
{
|
|
string subtargetLower = subtargetStr.ToLowerInvariant();
|
|
if (subtargetLower == "server")
|
|
EditorUserBuildSettings.standaloneBuildSubtarget = StandaloneBuildSubtarget.Server;
|
|
else if (subtargetLower == "player")
|
|
EditorUserBuildSettings.standaloneBuildSubtarget = StandaloneBuildSubtarget.Player;
|
|
}
|
|
|
|
// SwitchActiveBuildTarget is synchronous — blocks until reimport completes
|
|
EditorUserBuildSettings.SwitchActiveBuildTarget(group, target);
|
|
|
|
return new SuccessResponse(
|
|
$"Switched to {target}. Assets reimported for new platform.",
|
|
new { target = target.ToString(), previous = previousTarget }
|
|
);
|
|
}
|
|
|
|
// ── settings ───────────────────────────────────────────────────
|
|
|
|
private static object HandleSettings(ToolParams p)
|
|
{
|
|
var propertyResult = p.GetRequired("property");
|
|
if (!propertyResult.IsSuccess)
|
|
return new ErrorResponse(propertyResult.ErrorMessage);
|
|
|
|
string property = propertyResult.Value.ToLowerInvariant();
|
|
string targetName = p.Get("target");
|
|
string value = p.Get("value");
|
|
|
|
// Resolve target
|
|
string err = BuildTargetMapping.TryResolveNamedBuildTarget(targetName, out var namedTarget);
|
|
if (err != null)
|
|
return new ErrorResponse(err);
|
|
|
|
if (string.IsNullOrEmpty(value))
|
|
{
|
|
// Read
|
|
var result = BuildSettingsHelper.ReadProperty(property, namedTarget);
|
|
if (result == null)
|
|
return new ErrorResponse(
|
|
$"Unknown property '{property}'. Valid: {string.Join(", ", BuildSettingsHelper.ValidProperties)}");
|
|
return new SuccessResponse($"Read {property}.", result);
|
|
}
|
|
|
|
// Write
|
|
string writeErr = BuildSettingsHelper.WriteProperty(property, value, namedTarget);
|
|
if (writeErr != null)
|
|
return new ErrorResponse(writeErr);
|
|
return new SuccessResponse($"Set {property} = {value}.",
|
|
BuildSettingsHelper.ReadProperty(property, namedTarget));
|
|
}
|
|
|
|
// ── scenes ─────────────────────────────────────────────────────
|
|
|
|
private static object HandleScenes(ToolParams p)
|
|
{
|
|
var scenesRaw = p.GetRaw("scenes");
|
|
|
|
if (scenesRaw == null || scenesRaw.Type == JTokenType.Null)
|
|
{
|
|
// Read current scene list
|
|
var scenes = EditorBuildSettings.scenes.Select(s => new
|
|
{
|
|
path = s.path,
|
|
enabled = s.enabled,
|
|
guid = s.guid.ToString()
|
|
}).ToArray();
|
|
|
|
return new SuccessResponse($"Build scenes ({scenes.Length}).", new { scenes });
|
|
}
|
|
|
|
// Handle string input: try JSON parse, then comma-separated
|
|
if (scenesRaw.Type == JTokenType.String)
|
|
{
|
|
string scenesStr = scenesRaw.ToString();
|
|
try { scenesRaw = JArray.Parse(scenesStr); }
|
|
catch
|
|
{
|
|
// Treat as comma-separated paths
|
|
var paths = scenesStr.Split(',')
|
|
.Select(s => s.Trim())
|
|
.Where(s => !string.IsNullOrEmpty(s))
|
|
.ToArray();
|
|
if (paths.Length == 0)
|
|
return new ErrorResponse("'scenes' string contained no valid paths.");
|
|
var fromStr = paths.Select(sp => new EditorBuildSettingsScene(sp, true)).ToArray();
|
|
EditorBuildSettings.scenes = fromStr;
|
|
return new SuccessResponse($"Updated build scenes ({fromStr.Length}).", new
|
|
{
|
|
scenes = fromStr.Select(s => new { path = s.path, enabled = s.enabled }).ToArray()
|
|
});
|
|
}
|
|
}
|
|
|
|
// Write scene list — accepts array of strings or array of {path, enabled} objects
|
|
var sceneArray = scenesRaw as JArray;
|
|
if (sceneArray == null)
|
|
return new ErrorResponse("'scenes' must be an array of scene paths or {path, enabled} objects.");
|
|
|
|
var newScenes = new List<EditorBuildSettingsScene>();
|
|
foreach (var item in sceneArray)
|
|
{
|
|
if (item.Type == JTokenType.String)
|
|
{
|
|
newScenes.Add(new EditorBuildSettingsScene(item.ToString(), true));
|
|
continue;
|
|
}
|
|
string path = item["path"]?.ToString();
|
|
if (string.IsNullOrEmpty(path))
|
|
return new ErrorResponse("Each scene must have a 'path' field.");
|
|
bool enabled = item["enabled"]?.Value<bool>() ?? true;
|
|
newScenes.Add(new EditorBuildSettingsScene(path, enabled));
|
|
}
|
|
|
|
EditorBuildSettings.scenes = newScenes.ToArray();
|
|
return new SuccessResponse($"Updated build scenes ({newScenes.Count}).", new
|
|
{
|
|
scenes = newScenes.Select(s => new { path = s.path, enabled = s.enabled }).ToArray()
|
|
});
|
|
}
|
|
|
|
// ── profiles ───────────────────────────────────────────────────
|
|
|
|
private static object HandleProfiles(ToolParams p)
|
|
{
|
|
#if UNITY_6000_0_OR_NEWER
|
|
string profilePath = p.Get("profile");
|
|
bool activate = p.GetBool("activate");
|
|
|
|
if (string.IsNullOrEmpty(profilePath))
|
|
{
|
|
// List all profiles
|
|
var guids = AssetDatabase.FindAssets("t:BuildProfile");
|
|
var profiles = guids.Select(guid =>
|
|
{
|
|
string path = AssetDatabase.GUIDToAssetPath(guid);
|
|
return new { path, name = System.IO.Path.GetFileNameWithoutExtension(path) };
|
|
}).ToArray();
|
|
|
|
var active = UnityEditor.Build.Profile.BuildProfile.GetActiveBuildProfile();
|
|
return new SuccessResponse($"Found {profiles.Length} build profiles.", new
|
|
{
|
|
profiles,
|
|
active_profile = active != null ? AssetDatabase.GetAssetPath(active) : null
|
|
});
|
|
}
|
|
|
|
var loadedProfile = AssetDatabase.LoadAssetAtPath<
|
|
UnityEditor.Build.Profile.BuildProfile>(profilePath);
|
|
if (loadedProfile == null)
|
|
return new ErrorResponse($"Build profile not found at: {profilePath}");
|
|
|
|
if (activate)
|
|
{
|
|
UnityEditor.Build.Profile.BuildProfile.SetActiveBuildProfile(loadedProfile);
|
|
return new SuccessResponse($"Activated build profile: {profilePath}", new
|
|
{
|
|
profile = profilePath,
|
|
activated = true
|
|
});
|
|
}
|
|
|
|
// Get profile details — use .scenes (available since Unity 6000.0.0)
|
|
// instead of .GetScenesForBuild() which was added in 6000.0.36
|
|
var profileScenes = loadedProfile.scenes
|
|
.Select(s => s.path).ToArray();
|
|
return new SuccessResponse($"Profile: {profilePath}", new
|
|
{
|
|
profile = profilePath,
|
|
scenes = profileScenes
|
|
});
|
|
#else
|
|
string version = UnityEngine.Application.unityVersion;
|
|
return new ErrorResponse(
|
|
$"Build Profiles require Unity 6 (6000.0+). Current version: {version}");
|
|
#endif
|
|
}
|
|
|
|
// ── batch ──────────────────────────────────────────────────────
|
|
|
|
private static object HandleBatch(ToolParams p)
|
|
{
|
|
if (BuildPipeline.isBuildingPlayer)
|
|
return new ErrorResponse("A build is already in progress.");
|
|
|
|
string[] targets = p.GetStringArray("targets");
|
|
string[] profiles = p.GetStringArray("profiles");
|
|
string outputDir = p.Get("output_dir") ?? "Builds";
|
|
bool development = p.GetBool("development");
|
|
string[] optionNames = p.GetStringArray("options");
|
|
|
|
if ((targets == null || targets.Length == 0) && (profiles == null || profiles.Length == 0))
|
|
return new ErrorResponse("'targets' or 'profiles' is required for batch builds.");
|
|
if (targets != null && targets.Length > 0 && profiles != null && profiles.Length > 0)
|
|
return new ErrorResponse("Provide 'targets' or 'profiles', not both.");
|
|
|
|
// Validate all targets/profiles upfront before creating store entries
|
|
if (targets != null && targets.Length > 0)
|
|
{
|
|
var resolvedTargets = new List<(BuildTarget bt, string path)>();
|
|
foreach (var t in targets)
|
|
{
|
|
if (!BuildTargetMapping.TryResolveBuildTarget(t, out var bt))
|
|
return new ErrorResponse(BuildTargetMapping.GetUnknownBuildTargetMessage(t));
|
|
var btGroup = BuildTargetMapping.GetTargetGroup(bt);
|
|
if (!BuildPipeline.IsBuildTargetSupported(btGroup, bt))
|
|
return new ErrorResponse(
|
|
$"Platform '{bt}' is not installed. Install it via Unity Hub.");
|
|
string defaultPath = BuildTargetMapping.GetDefaultOutputPath(bt, PlayerSettings.productName);
|
|
string path = defaultPath.StartsWith("Builds/")
|
|
? $"{outputDir}/{defaultPath.Substring(7)}"
|
|
: $"{outputDir}/{defaultPath}";
|
|
resolvedTargets.Add((bt, path));
|
|
}
|
|
|
|
string batchId = BuildJobStore.CreateBatchId();
|
|
var batch = new BatchJob(batchId);
|
|
batch.State = BuildJobState.Building;
|
|
BuildJobStore.AddBatchJob(batch);
|
|
|
|
foreach (var (bt, path) in resolvedTargets)
|
|
{
|
|
var child = new BuildJob(BuildJobStore.CreateJobId(), bt, path);
|
|
batch.Children.Add(child);
|
|
}
|
|
|
|
var buildOpts = BuildRunner.ParseBuildOptions(optionNames, development);
|
|
|
|
BuildRunner.ScheduleNextBatchBuild(batch, index =>
|
|
{
|
|
var child = batch.Children[index];
|
|
var group = BuildTargetMapping.GetTargetGroup(child.Target);
|
|
|
|
// Platform switch is required — ensures correct shader variants,
|
|
// asset import settings, and scripting defines for the target
|
|
if (EditorUserBuildSettings.activeBuildTarget != child.Target)
|
|
EditorUserBuildSettings.SwitchActiveBuildTarget(group, child.Target);
|
|
|
|
int subtarget = (int)StandaloneBuildSubtarget.Player;
|
|
var options = BuildRunner.CreateBuildOptions(
|
|
child.Target, child.OutputPath, null, buildOpts, subtarget);
|
|
BuildRunner.ScheduleBuild(child, options);
|
|
return child;
|
|
});
|
|
|
|
return new PendingResponse(
|
|
$"Batch build started ({batch.Children.Count} builds).",
|
|
pollIntervalSeconds: 10.0,
|
|
data: new { job_id = batchId, total = batch.Children.Count }
|
|
);
|
|
}
|
|
#if UNITY_6000_0_OR_NEWER
|
|
if (profiles != null && profiles.Length > 0)
|
|
{
|
|
// Validate all profiles exist before creating any store entries
|
|
var loadedProfiles = new List<UnityEditor.Build.Profile.BuildProfile>();
|
|
foreach (var profilePath in profiles)
|
|
{
|
|
var profile = AssetDatabase.LoadAssetAtPath<
|
|
UnityEditor.Build.Profile.BuildProfile>(profilePath);
|
|
if (profile == null)
|
|
return new ErrorResponse($"Profile not found: {profilePath}");
|
|
loadedProfiles.Add(profile);
|
|
}
|
|
|
|
string batchId = BuildJobStore.CreateBatchId();
|
|
var batch = new BatchJob(batchId);
|
|
batch.State = BuildJobState.Building;
|
|
BuildJobStore.AddBatchJob(batch);
|
|
|
|
for (int i = 0; i < profiles.Length; i++)
|
|
{
|
|
var target = EditorUserBuildSettings.activeBuildTarget;
|
|
string name = System.IO.Path.GetFileNameWithoutExtension(profiles[i]);
|
|
string path = $"{outputDir}/{name}/{PlayerSettings.productName}";
|
|
var child = new BuildJob(BuildJobStore.CreateJobId(), target, path);
|
|
batch.Children.Add(child);
|
|
}
|
|
|
|
var buildOpts = BuildRunner.ParseBuildOptions(optionNames, development);
|
|
|
|
BuildRunner.ScheduleNextBatchBuild(batch, index =>
|
|
{
|
|
var child = batch.Children[index];
|
|
var opts = new BuildPlayerWithProfileOptions
|
|
{
|
|
buildProfile = loadedProfiles[index],
|
|
locationPathName = child.OutputPath,
|
|
options = buildOpts
|
|
};
|
|
BuildRunner.ScheduleProfileBuild(child, opts);
|
|
return child;
|
|
});
|
|
|
|
return new PendingResponse(
|
|
$"Batch build started ({batch.Children.Count} builds).",
|
|
pollIntervalSeconds: 10.0,
|
|
data: new { job_id = batchId, total = batch.Children.Count }
|
|
);
|
|
}
|
|
#else
|
|
if (profiles != null && profiles.Length > 0)
|
|
{
|
|
return new ErrorResponse(
|
|
$"Profile-based batch requires Unity 6+. Current: {UnityEngine.Application.unityVersion}");
|
|
}
|
|
#endif
|
|
|
|
return new ErrorResponse("'targets' or 'profiles' is required for batch builds.");
|
|
}
|
|
|
|
// ── cancel ─────────────────────────────────────────────────────
|
|
|
|
private static object HandleCancel(ToolParams p)
|
|
{
|
|
var jobIdResult = p.GetRequired("job_id");
|
|
if (!jobIdResult.IsSuccess)
|
|
return new ErrorResponse(jobIdResult.ErrorMessage);
|
|
|
|
string jobId = jobIdResult.Value;
|
|
|
|
var batchJob = BuildJobStore.GetBatchJob(jobId);
|
|
if (batchJob != null)
|
|
{
|
|
if (batchJob.State == BuildJobState.Building)
|
|
{
|
|
batchJob.State = BuildJobState.Cancelled;
|
|
return new SuccessResponse(
|
|
"Batch cancelled. The current build will finish but no more builds will start.",
|
|
new { job_id = jobId, state = "cancelled" });
|
|
}
|
|
return new ErrorResponse($"Batch is already {batchJob.State}.");
|
|
}
|
|
|
|
var buildJob = BuildJobStore.GetBuildJob(jobId);
|
|
if (buildJob != null)
|
|
{
|
|
if (buildJob.State == BuildJobState.Building)
|
|
return new ErrorResponse(
|
|
"Cannot cancel a single build in progress. BuildPipeline.BuildPlayer is " +
|
|
"synchronous and blocks the editor until completion.");
|
|
return new ErrorResponse($"Build is already {buildJob.State}.");
|
|
}
|
|
|
|
return new ErrorResponse($"No job found with ID: {jobId}");
|
|
}
|
|
}
|
|
}
|