Skip to content
Open
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
77 changes: 66 additions & 11 deletions MCPForUnity/Editor/Tools/Build/BuildTargetMapping.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
using System;
using UnityEditor;
using UnityEditor.Build;

namespace MCPForUnity.Editor.Tools.Build
{
public static class BuildTargetMapping
{
private const string VisionOSName = "VisionOS";

public static bool TryResolveBuildTarget(string name, out BuildTarget target)
{
if (string.IsNullOrEmpty(name))
Expand All @@ -24,13 +27,12 @@ public static bool TryResolveBuildTarget(string name, out BuildTarget target)
case "webgl": target = BuildTarget.WebGL; return true;
case "uwp": target = BuildTarget.WSAPlayer; return true;
case "tvos": target = BuildTarget.tvOS; return true;
// BuildTarget.VisionOS exists only in Unity 2023.2+ and late 2022.3 patches
#if UNITY_2023_2_OR_NEWER
case "visionos": target = BuildTarget.VisionOS; return true;
#endif
default:
if (System.Enum.TryParse(name, true, out target))
if (TryParseDefinedBuildTarget(name, out target))
{
return true;
}

target = default;
return false;
}
Expand All @@ -50,10 +52,14 @@ public static BuildTargetGroup GetTargetGroup(BuildTarget target)
case BuildTarget.WebGL: return BuildTargetGroup.WebGL;
case BuildTarget.WSAPlayer: return BuildTargetGroup.WSA;
case BuildTarget.tvOS: return BuildTargetGroup.tvOS;
#if UNITY_2023_2_OR_NEWER
case BuildTarget.VisionOS: return BuildTargetGroup.VisionOS;
#endif
default: return BuildTargetGroup.Unknown;
default:
if (IsVisionOSTarget(target)
&& Enum.TryParse(VisionOSName, true, out BuildTargetGroup visionOSGroup))
{
return visionOSGroup;
}

return BuildTargetGroup.Unknown;
}
}

Expand All @@ -67,12 +73,61 @@ public static string TryResolveNamedBuildTarget(string name, out NamedBuildTarge
if (!TryResolveBuildTarget(name, out var buildTarget))
{
namedTarget = default;
return $"Unknown build target: '{name}'. Valid targets: windows64, osx, linux64, android, ios, webgl, uwp, tvos, visionos";
return GetUnknownBuildTargetMessage(name);
}

var targetGroup = GetTargetGroup(buildTarget);
if (targetGroup == BuildTargetGroup.Unknown)
{
namedTarget = default;
return IsVisionOSTarget(buildTarget)
? "VisionOS build target is available, but its BuildTargetGroup is not exposed by this Unity editor installation."
: $"Build target group could not be resolved for target '{buildTarget}'.";
}
namedTarget = GetNamedBuildTarget(buildTarget);

namedTarget = NamedBuildTarget.FromBuildTargetGroup(targetGroup);
return null;
}

public static string GetUnknownBuildTargetMessage(string name)
{
if (string.Equals(name, "visionos", StringComparison.OrdinalIgnoreCase))
{
return "VisionOS build target is not available in this Unity editor installation. "
+ "Install the visionOS build support module or use a Unity version/configuration that exposes BuildTarget.VisionOS.";
}

return $"Unknown build target: '{name}'. Valid targets: {GetValidTargetsList()}.";
}

private static string GetValidTargetsList()
{
string validTargets = "windows64, osx, linux64, android, ios, webgl, uwp, tvos";
if (TryParseDefinedBuildTarget(VisionOSName, out _))
{
validTargets += ", visionos";
}

return validTargets;
}

private static bool IsVisionOSTarget(BuildTarget target)
{
return string.Equals(target.ToString(), VisionOSName, StringComparison.OrdinalIgnoreCase);
}

private static bool TryParseDefinedBuildTarget(string name, out BuildTarget target)
{
target = default;
if (int.TryParse(name, out _))
{
return false;
}

return Enum.TryParse(name, true, out target)
&& Enum.IsDefined(typeof(BuildTarget), target);
}

public static string GetDefaultOutputPath(BuildTarget target, string productName)
{
string basePath = $"Builds/{target}";
Expand Down
6 changes: 3 additions & 3 deletions MCPForUnity/Editor/Tools/ManageBuild.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ private static object HandleBuild(ToolParams p)

string targetName = p.Get("target");
if (!BuildTargetMapping.TryResolveBuildTarget(targetName, out var target))
return new ErrorResponse($"Unknown target '{targetName}'.");
return new ErrorResponse(BuildTargetMapping.GetUnknownBuildTargetMessage(targetName));

var group = BuildTargetMapping.GetTargetGroup(target);
if (!BuildPipeline.IsBuildTargetSupported(group, target))
Expand Down Expand Up @@ -221,7 +221,7 @@ private static object HandlePlatform(ToolParams p)

// Switch platform
if (!BuildTargetMapping.TryResolveBuildTarget(targetName, out var target))
return new ErrorResponse($"Unknown target '{targetName}'.");
return new ErrorResponse(BuildTargetMapping.GetUnknownBuildTargetMessage(targetName));

var group = BuildTargetMapping.GetTargetGroup(target);
if (!BuildPipeline.IsBuildTargetSupported(group, target))
Expand Down Expand Up @@ -442,7 +442,7 @@ private static object HandleBatch(ToolParams p)
foreach (var t in targets)
{
if (!BuildTargetMapping.TryResolveBuildTarget(t, out var bt))
return new ErrorResponse($"Unknown target '{t}' in batch.");
return new ErrorResponse(BuildTargetMapping.GetUnknownBuildTargetMessage(t));
var btGroup = BuildTargetMapping.GetTargetGroup(bt);
if (!BuildPipeline.IsBuildTargetSupported(btGroup, bt))
return new ErrorResponse(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;
using MCPForUnity.Editor.Tools.Build;
using NUnit.Framework;
using UnityEditor;

namespace MCPForUnity.Tests.EditMode.Tools
{
[TestFixture]
public class BuildTargetMappingTests
{
[TestCase("windows64", BuildTarget.StandaloneWindows64)]
[TestCase("macos", BuildTarget.StandaloneOSX)]
[TestCase("linux", BuildTarget.StandaloneLinux64)]
[TestCase("tvos", BuildTarget.tvOS)]
public void TryResolveBuildTarget_KnownAliasesResolve(string name, BuildTarget expected)
{
Assert.IsTrue(BuildTargetMapping.TryResolveBuildTarget(name, out var target));
Assert.AreEqual(expected, target);
}

[Test]
public void TryResolveBuildTarget_NumericInputDoesNotResolve()
{
Assert.IsFalse(BuildTargetMapping.TryResolveBuildTarget("5", out _));
}

[Test]
public void TryResolveNamedBuildTarget_UnknownTargetListsOnlyAvailableTargets()
{
string error = BuildTargetMapping.TryResolveNamedBuildTarget("not-a-target", out _);

Assert.IsNotNull(error);
StringAssert.Contains("windows64", error);

bool visionOSAvailable = Enum.TryParse("VisionOS", true, out BuildTarget _);
if (visionOSAvailable)
{
StringAssert.Contains("visionos", error);
}
else
{
Assert.IsFalse(error.Contains("visionos"));
}
}

[Test]
public void TryResolveNamedBuildTarget_VisionOSUnavailableReturnsHelpfulError()
{
bool visionOSAvailable = Enum.TryParse("VisionOS", true, out BuildTarget _);
string error = BuildTargetMapping.TryResolveNamedBuildTarget("visionos", out _);

if (visionOSAvailable)
{
Assert.IsTrue(BuildTargetMapping.TryResolveBuildTarget("visionos", out _));
Assert.IsTrue(
error == null || error.Contains("VisionOS"),
$"Expected no error or a VisionOS-specific error, got: {error}");
}
else
{
Assert.IsFalse(BuildTargetMapping.TryResolveBuildTarget("visionos", out _));
Assert.IsNotNull(error);
StringAssert.Contains("VisionOS build target is not available", error);
}
}
}
}

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