Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0387ec4
Add Unity 6000.5 compile compatibility check
hatayama Jul 19, 2026
f8fb74e
Fix Unity 6000.5 object identifier compatibility
hatayama Jul 19, 2026
1a63e2d
Fix Unity 6000.5 adapter assembly visibility
hatayama Jul 19, 2026
7f1b35e
Handle destroyed Unity objects in identifier adapter
hatayama Jul 19, 2026
0dab8e4
Use raw EntityId value for Unity 6000.5
hatayama Jul 19, 2026
ac0576c
Handle Unity 6000.5 obsolete API diagnostics
hatayama Jul 19, 2026
4adfc24
Use raw EntityId bits for compatibility handles
hatayama Jul 19, 2026
7721cd5
Clear remaining Unity 6000.5 compiler warnings
hatayama Jul 19, 2026
2d9a156
Validate Unity package assemblies when logs are unavailable
hatayama Jul 19, 2026
7517f01
Fail Unity 6000.5 checks without compiler logs
hatayama Jul 19, 2026
82e1506
Preserve Unity compiler log output
hatayama Jul 19, 2026
9596aba
Pass Unity log path as separate arguments
hatayama Jul 19, 2026
5b5469f
Write Unity logs outside build artifacts
hatayama Jul 19, 2026
21fe66e
Capture compiler diagnostics from Unity job logs
hatayama Jul 19, 2026
db5dcbe
Compile Unity 6000.5 directly for diagnostics
hatayama Jul 19, 2026
caac8e1
Separate Unity compile execution modes
hatayama Jul 19, 2026
c496d2e
Use explicit matrix compile mode conditions
hatayama Jul 19, 2026
a69cce5
Reuse matrix unit test leg for editor selection
hatayama Jul 19, 2026
97c8dc7
Match compile steps by Unity version
hatayama Jul 19, 2026
1a3586f
Pass Unity license file explicitly
hatayama Jul 19, 2026
2eb645a
Expose Unity logs when package compilation evidence is missing
hatayama Jul 19, 2026
362623e
Activate Unity 6000.5 with a derived serial
hatayama Jul 19, 2026
d41e666
Use the fixture for Unity license activation
hatayama Jul 19, 2026
5a3d83a
Avoid duplicate zero counts in compiler diagnostics
hatayama Jul 19, 2026
65e62e4
Isolate Unity license activation from fixture compilation
hatayama Jul 19, 2026
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
149 changes: 129 additions & 20 deletions .github/workflows/unity-compile-check-and-test-runner.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Unity Compile Check

# This job is a required status check, so it must report exactly one
# "Compile Check (Linux)" result on every PR. Path filters at the workflow
# These jobs are required status checks, so they must report one result per
# Unity version on every PR. Path filters at the workflow
# level cannot express that: a `paths`/`paths-ignore` pair both fire on a PR
# that mixes C# and non-C# files, producing duplicate required checks. Instead
# the workflow always runs and a change-detection step decides whether to do
Expand All @@ -17,8 +17,21 @@ permissions:

jobs:
compile-check:
name: Compile Check (Linux)
name: Compile Check (${{ matrix.unity-version }})
runs-on: ubuntu-latest
strategy:
matrix:
include:
- unity-version: 2022.3.62f1
project-path: .
library-path: Library
package-warning-scope: false
run-unit-tests: true
- unity-version: 6000.5.4f1
project-path: ci/unity-projects/6000.5
library-path: ci/unity-projects/6000.5/Library
package-warning-scope: true
run-unit-tests: false
# Dependabot PRs cannot access repository secrets (UNITY_LICENSE etc.)
env:
HAS_UNITY_LICENSE: ${{ secrets.UNITY_LICENSE != '' }}
Expand Down Expand Up @@ -47,7 +60,7 @@ jobs:
echo "=== Changed files ==="
echo "$CHANGED"

if echo "$CHANGED" | grep -qE '^(Packages/src/Editor/.*\.cs|Packages/src/Runtime/.*\.cs|Assets/.*\.cs|tests/.*\.cs|tests/.*\.csproj|Packages/.*\.asmdef|Assets/.*\.asmdef|Packages/manifest\.json|Packages/packages-lock\.json|\.github/workflows/unity-compile-check-and-test-runner\.yml)$'; then
if echo "$CHANGED" | grep -qE '^(Packages/src/Editor/.*\.cs|Packages/src/Runtime/.*\.cs|Assets/.*\.cs|tests/.*\.cs|tests/.*\.csproj|Packages/.*\.asmdef|Assets/.*\.asmdef|Packages/manifest\.json|Packages/packages-lock\.json|ci/unity-projects/.*|\.github/workflows/unity-compile-check-and-test-runner\.yml)$'; then
echo "csharp=true" >> "$GITHUB_OUTPUT"
else
echo "csharp=false" >> "$GITHUB_OUTPUT"
Expand All @@ -58,13 +71,13 @@ jobs:
run: echo "No C# changes detected; compile check is satisfied without running Unity."

- name: Setup .NET
if: steps.changes.outputs.csharp == 'true'
if: steps.changes.outputs.csharp == 'true' && matrix.run-unit-tests == true
uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7
with:
dotnet-version: 10.0.x

- name: Run concurrency unit tests
if: steps.changes.outputs.csharp == 'true'
if: steps.changes.outputs.csharp == 'true' && matrix.run-unit-tests == true
run: |
dotnet test tests/DynamicCodeExecutionScheduler.UnitTests/DynamicCodeExecutionScheduler.UnitTests.csproj --configuration Release
dotnet test tests/SharedRoslynCompilerWorker.UnitTests/SharedRoslynCompilerWorker.UnitTests.csproj --configuration Release
Expand All @@ -74,13 +87,21 @@ jobs:
if: env.HAS_UNITY_LICENSE == 'true'
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae
with:
path: Library
key: Library-2022.3.62f1-${{ hashFiles('Packages/src/**/*.cs', 'Assets/**/*.cs', 'Packages/manifest.json', 'Packages/packages-lock.json') }}
path: ${{ matrix.library-path }}
key: Library-${{ matrix.unity-version }}-${{ hashFiles('Packages/src/**/*.cs', 'Assets/**/*.cs', 'Packages/manifest.json', 'Packages/packages-lock.json', 'ci/unity-projects/6000.5/**') }}
restore-keys: |
Library-2022.3.62f1-
Library-${{ matrix.unity-version }}-

- name: Compile Unity project
if: steps.changes.outputs.csharp == 'true' && env.HAS_UNITY_LICENSE == 'true'
- name: Purge cached script assemblies
if: ${{ steps.changes.outputs.csharp == 'true' && env.HAS_UNITY_LICENSE == 'true' && matrix['unity-version'] == '6000.5.4f1' }}
run: rm -rf "${{ matrix.project-path }}/Library/ScriptAssemblies"

- name: Prepare Unity log directory
if: env.HAS_UNITY_LICENSE == 'true'
run: mkdir -p artifacts

- name: Compile Unity project (2022.3)
if: ${{ steps.changes.outputs.csharp == 'true' && env.HAS_UNITY_LICENSE == 'true' && matrix['unity-version'] == '2022.3.62f1' }}
id: compile
uses: game-ci/unity-builder@1d4ee0697f193f54668e98961d79907911f4b4f2
timeout-minutes: 30
Expand All @@ -89,12 +110,69 @@ jobs:
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
with:
unityVersion: 2022.3.62f1
projectPath: ${{ matrix.project-path }}
unityVersion: ${{ matrix.unity-version }}
targetPlatform: StandaloneLinux64
buildMethod: ''
allowDirtyBuild: true
continue-on-error: true

- name: Compile Unity project (6000.5)
if: ${{ steps.changes.outputs.csharp == 'true' && env.HAS_UNITY_LICENSE == 'true' && matrix['unity-version'] == '6000.5.4f1' }}
id: compile-6000-5
timeout-minutes: 30
env:
UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }}
UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
run: |
docker run --rm \
--workdir /workspace \
--volume "$GITHUB_WORKSPACE:/workspace" \
--env UNITY_LICENSE \
--env UNITY_EMAIL \
--env UNITY_PASSWORD \
unityci/editor:ubuntu-6000.5.4f1-base-3 \
/bin/bash -c '
set -eu
mkdir -p /BlankProject/Assets
trap '\''unity-editor -batchmode -nographics -quit -returnlicense \
-logFile /dev/stdout \
-username "$UNITY_EMAIL" -password "$UNITY_PASSWORD" \
-projectPath /BlankProject >/dev/null 2>&1 || true'\'' EXIT

LICENSE_VALUE=$(printf "%s" "$UNITY_LICENSE" | tr "\\n" " " | sed -n '\''s/.*<DeveloperData Value="\([^"]*\)"\/>.*/\1/p'\'')
test -n "$LICENSE_VALUE"
printf "%s" "$LICENSE_VALUE" | base64 -d > /tmp/developer-data.bin
SERIAL=$(tail -c +5 /tmp/developer-data.bin | tr -d "\\r\\n")
test "${#SERIAL}" -eq 27
if [[ "$SERIAL" == F* ]]; then
dbus-uuidgen > /etc/machine-id
mkdir -p /var/lib/dbus
ln -sf /etc/machine-id /var/lib/dbus/machine-id
fi

ACTIVATED=false
for ATTEMPT in 1 2 3; do
if unity-editor -batchmode -nographics -quit \
-logFile /dev/stdout \
-serial "$SERIAL" \
-username "$UNITY_EMAIL" \
-password "$UNITY_PASSWORD" \
-projectPath /BlankProject; then
ACTIVATED=true
break
fi
sleep $((ATTEMPT * 5))
done
test "$ACTIVATED" = true

unity-editor -batchmode -nographics -quit \
-projectPath /workspace/ci/unity-projects/6000.5 \
-logFile /workspace/artifacts/unity-build.log
'
continue-on-error: true

- name: Check for compile errors and warnings
if: steps.changes.outputs.csharp == 'true' && env.HAS_UNITY_LICENSE == 'true'
run: |
Expand All @@ -110,14 +188,45 @@ jobs:
ERROR_COUNT=0
WARNING_COUNT=0

if [ "${{ matrix.package-warning-scope }}" == "true" ]; then
PACKAGE_ASSEMBLY_COUNT=$(find "${{ matrix.project-path }}/Library/ScriptAssemblies" -maxdepth 1 -type f -name 'UnityCLILoop*.dll' 2>/dev/null | wc -l | tr -d ' ')
if [ "$PACKAGE_ASSEMBLY_COUNT" -eq 0 ]; then
echo "::error::Unity did not resolve or compile the io.github.hatayama.uloopmcp package"
if [ -f "$LOG_FILE" ]; then
echo "=== Unity log tail ==="
tail -100 "$LOG_FILE"
else
echo "::error::Unity log file is missing: $LOG_FILE"
fi
exit 1
fi
echo "Package assembly evidence found: $PACKAGE_ASSEMBLY_COUNT assembly(s)."
fi

if [ -f "$LOG_FILE" ]; then
echo "Analyzing log file: $LOG_FILE"

# Count errors (CS errors from compiler)
ERROR_COUNT=$(grep -c "error CS[0-9]*:" "$LOG_FILE" 2>/dev/null || echo "0")
if [ "${{ matrix.package-warning-scope }}" == "true" ]; then
PACKAGE_EVIDENCE_PATTERN='io\.github\.hatayama\.uloopmcp|UnityCLILoop\.Runtime'
if ! grep -Eq "$PACKAGE_EVIDENCE_PATTERN" "$LOG_FILE"; then
echo "::error::Unity did not resolve or compile the io.github.hatayama.uloopmcp package"
exit 1
fi
echo "Package compilation evidence found in Unity log."
fi

if [ "${{ matrix.package-warning-scope }}" == "true" ]; then
# Unity 6000.5 can emit compiler noise from other packages. Only
# package source diagnostics determine this compatibility check.
ERROR_PATTERN='(Packages/src/|io\.github\.hatayama\.uloopmcp).*error CS[0-9]*:|error CS[0-9]*:.*(Packages/src/|io\.github\.hatayama\.uloopmcp)'
WARNING_PATTERN='(Packages/src/|io\.github\.hatayama\.uloopmcp).*warning CS[0-9]*:|warning CS[0-9]*:.*(Packages/src/|io\.github\.hatayama\.uloopmcp)'
else
ERROR_PATTERN='error CS[0-9]*:'
WARNING_PATTERN='warning CS[0-9]*:'
fi

# Count warnings (CS warnings from compiler, excluding specific noise)
WARNING_COUNT=$(grep -c "warning CS[0-9]*:" "$LOG_FILE" 2>/dev/null || echo "0")
ERROR_COUNT=$(grep -Ec "$ERROR_PATTERN" "$LOG_FILE" 2>/dev/null || true)
WARNING_COUNT=$(grep -Ec "$WARNING_PATTERN" "$LOG_FILE" 2>/dev/null || true)

echo ""
echo "=== Compilation Results ==="
Expand All @@ -129,23 +238,23 @@ jobs:
echo "::error::Found $ERROR_COUNT compile error(s)"
echo ""
echo "=== Errors ==="
grep "error CS[0-9]*:" "$LOG_FILE" | head -20
grep -E "$ERROR_PATTERN" "$LOG_FILE" | head -20
exit 1
fi

if [ "$WARNING_COUNT" -gt 0 ]; then
echo "::warning::Found $WARNING_COUNT compile warning(s)"
echo ""
echo "=== Warnings ==="
grep "warning CS[0-9]*:" "$LOG_FILE" | head -20
grep -E "$WARNING_PATTERN" "$LOG_FILE" | head -20
exit 1
fi

echo "✅ No compile errors or warnings found!"
else
echo "::warning::Could not find Unity log file for analysis"
# Fall back to checking if build step failed
if [ "${{ steps.compile.outcome }}" == "failure" ]; then
# Unity 6000.5's builder reports an untitled-scene build failure after successful script compilation.
if [ "${{ matrix.package-warning-scope }}" == "true" ] || [ "${{ steps.compile.outcome }}" == "failure" ]; then
echo "::error::Unity compilation failed"
exit 1
fi
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@ internal static class UiRaycastHelper

private static List<CanvasRaycastSource> CollectCanvasRaycastSources()
{
#if UNITY_6000_4_OR_NEWER
Canvas[] canvases = Object.FindObjectsByType<Canvas>();
#else
Canvas[] canvases = Object.FindObjectsByType<Canvas>(FindObjectsSortMode.None);
#endif
List<CanvasRaycastSource> canvasRaycastSources = new List<CanvasRaycastSource>();

foreach (Canvas canvas in canvases)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,12 @@ public void EnsureExists()
}

// Domain Reload resets _instance but DontDestroyOnLoad objects survive; reclaim one and destroy duplicates
#if UNITY_6000_4_OR_NEWER
InputVisualizationCanvas[] existing = Object.FindObjectsByType<InputVisualizationCanvas>();
#else
InputVisualizationCanvas[] existing =
Object.FindObjectsByType<InputVisualizationCanvas>(FindObjectsSortMode.None);
#endif
for (int i = 0; i < existing.Length; i++)
{
if (_instance == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ public static async Task<DynamicCompilationBackendResult> CompileAsync(
? DynamicReferenceSetBuilder.MergeReferencesByAssemblyName(Array.Empty<string>(), references)
: Array.Empty<string>();

#pragma warning disable 618 // Unity's fallback compiler API has no supported replacement on older editor versions.
AssemblyBuilder builder = new(dllPath, sourcePath)
{
referencesOptions = ReferencesOptions.UseEngineModules,
additionalReferences = referenceArray
};
#pragma warning restore 618

builder.buildFinished += (string assemblyPath, CompilerMessage[] compilerMessages) =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using UnityEngine;

using io.github.hatayama.UnityCliLoop.Runtime;
using io.github.hatayama.UnityCliLoop.ToolContracts;

namespace io.github.hatayama.UnityCliLoop.FirstPartyTools
{
Expand Down Expand Up @@ -43,9 +44,9 @@ public static Classification Classify(Object unityObject)
string assetPath = AssetDatabase.GetAssetPath(unityObject);
return string.IsNullOrEmpty(assetPath)
? new Classification(
UloopCapturedVariableUnityObjectKind.RuntimeInstance, unityObject.name, unityObject.GetInstanceID())
UloopCapturedVariableUnityObjectKind.RuntimeInstance, unityObject.name, UnityObjectIdentifier.GetInstanceId(unityObject))
: new Classification(
UloopCapturedVariableUnityObjectKind.Asset, assetPath, unityObject.GetInstanceID());
UloopCapturedVariableUnityObjectKind.Asset, assetPath, UnityObjectIdentifier.GetInstanceId(unityObject));
}

private static Classification ClassifyGameObjectOrComponent(GameObject gameObject, Object handleSource)
Expand All @@ -55,13 +56,13 @@ private static Classification ClassifyGameObjectOrComponent(GameObject gameObjec
return new Classification(
UloopCapturedVariableUnityObjectKind.SceneObject,
$"{gameObject.scene.name}:{BuildHierarchyPath(gameObject.transform)}",
handleSource.GetInstanceID());
UnityObjectIdentifier.GetInstanceId(handleSource));
}

return new Classification(
UloopCapturedVariableUnityObjectKind.PrefabAsset,
AssetDatabase.GetAssetPath(handleSource),
handleSource.GetInstanceID());
UnityObjectIdentifier.GetInstanceId(handleSource));
}

private static string BuildHierarchyPath(Transform transform)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ private static UloopCapturedVariable FormatUnityObjectVariable(
{
return new UloopCapturedVariable(
name, scope, typeName, DestroyedValue,
UloopCapturedVariableUnityObjectKind.Destroyed, string.Empty, unityObjectCandidate.GetInstanceID());
UloopCapturedVariableUnityObjectKind.Destroyed, string.Empty, UnityObjectIdentifier.GetInstanceId(unityObjectCandidate));
}

SourcePausePointUnityObjectClassifier.Classification classification =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ internal static int CreateClusterKey(Collider collider)
// The 4-connected component split in CollectPhysicsColliderElements re-derives one annotation per
// visually closed region so a single GameObject can produce multiple entries when UI occlusion
// splits its reachable samples.
return collider!.gameObject.GetInstanceID();
return UnityObjectIdentifier.GetInstanceId(collider!.gameObject);
}

private static RaycastClusterSample CreateClusterSample(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,11 @@ private static void CollectEventHandlers(
HashSet<GameObject> processedObjects,
UiRaycastHelper.RaycastContext? raycastContext)
{
#if UNITY_6000_4_OR_NEWER
MonoBehaviour[] allBehaviours = Object.FindObjectsByType<MonoBehaviour>();
#else
MonoBehaviour[] allBehaviours = Object.FindObjectsOfType<MonoBehaviour>();
#endif
Comment thread
coderabbitai[bot] marked this conversation as resolved.
foreach (MonoBehaviour behaviour in allBehaviours)
{
if (!behaviour.isActiveAndEnabled)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,11 @@ private static TargetPathLookupResult FindActiveGameObjectByPath(string targetPa
return new TargetPathLookupResult(null, 0);
}

#if UNITY_6000_4_OR_NEWER
GameObject[] gameObjects = UnityEngine.Object.FindObjectsByType<GameObject>();
#else
GameObject[] gameObjects = UnityEngine.Object.FindObjectsByType<GameObject>(FindObjectsSortMode.None);
#endif
GameObject? matchedTarget = null;
int matchCount = 0;

Expand Down
25 changes: 25 additions & 0 deletions Packages/src/Editor/ToolContracts/UnityObjectIdentifier.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using UnityEngine;

namespace io.github.hatayama.UnityCliLoop.ToolContracts
{
/// <summary>
/// Provides the integer object handle required by the current pause-point response contract.
/// </summary>
internal static class UnityObjectIdentifier
{
/// <summary>
/// Gets an object handle while keeping the existing integer response contract compatible with older Unity versions.
/// </summary>
public static int GetInstanceId(Object unityObject)
{
Debug.Assert(unityObject is not null, "unityObject must not be null.");
#if UNITY_6000_4_OR_NEWER
// The wire contract remains int, so extract the same lower 32 bits as Unity's obsolete int cast.
// Unity 6000.5 stores a version marker in the upper 32 bits; future IDs may collide in this int shape.
return unchecked((int)EntityId.ToULong(unityObject.GetEntityId()));
#else
return unityObject.GetInstanceID();
#endif
}
}
}

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

Empty file.
5 changes: 5 additions & 0 deletions ci/unity-projects/6000.5/Packages/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"dependencies": {
"io.github.hatayama.uloopmcp": "file:../../../../Packages/src"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
m_EditorVersion: 6000.5.4f1
Loading