Skip to content
Merged
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
47 changes: 47 additions & 0 deletions .agents/skills/uloop-set-game-view-size/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
name: uloop-set-game-view-size
toolName: set-game-view-size
description: "Set or inspect the Unity Game View custom rendering resolution."
---

# uloop set-game-view-size

Set or inspect the Unity Game View custom rendering resolution.

## Usage

```bash
uloop set-game-view-size [--width <width> --height <height>]
```

## Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `--width` | integer | unset | Target Game View rendering width in pixels. Provide with `--height` to change the resolution. |
| `--height` | integer | unset | Target Game View rendering height in pixels. Provide with `--width` to change the resolution. |

## Output

Returns JSON containing:

- `Success`: Whether the request completed.
- `PreviousWidth` / `PreviousHeight`: Resolution before the request.
- `CurrentWidth` / `CurrentHeight`: Resolution after the request.
- `Changed`: Whether the resolution changed.
- `Message`: Human-readable status.

## Examples

```bash
# Read the current custom rendering resolution
uloop set-game-view-size

# Set a Full HD custom rendering resolution
uloop set-game-view-size --width 1920 --height 1080
```

## Notes

- Width and height must be provided together when changing the resolution.
- The tool uses Unity's public `UnityEditor.PlayModeWindow` API and does not require reflection.
47 changes: 47 additions & 0 deletions .claude/skills/uloop-set-game-view-size/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
name: uloop-set-game-view-size
toolName: set-game-view-size
description: "Set or inspect the Unity Game View custom rendering resolution."
---

# uloop set-game-view-size

Set or inspect the Unity Game View custom rendering resolution.

## Usage

```bash
uloop set-game-view-size [--width <width> --height <height>]
```

## Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `--width` | integer | unset | Target Game View rendering width in pixels. Provide with `--height` to change the resolution. |
| `--height` | integer | unset | Target Game View rendering height in pixels. Provide with `--width` to change the resolution. |

## Output

Returns JSON containing:

- `Success`: Whether the request completed.
- `PreviousWidth` / `PreviousHeight`: Resolution before the request.
- `CurrentWidth` / `CurrentHeight`: Resolution after the request.
- `Changed`: Whether the resolution changed.
- `Message`: Human-readable status.

## Examples

```bash
# Read the current custom rendering resolution
uloop set-game-view-size

# Set a Full HD custom rendering resolution
uloop set-game-view-size --width 1920 --height 1080
```

## Notes

- Width and height must be provided together when changing the resolution.
- The tool uses Unity's public `UnityEditor.PlayModeWindow` API and does not require reflection.
10 changes: 5 additions & 5 deletions Assets/Tests/Demo/scripts/verify-replay-via-cli.sh
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ run_uloop_json() {
printf '%s\n' "$output" >&2
fail "uloop $* failed"
}
if printf '%s\n' "$output" | grep -Eq '"success"[[:space:]]*:[[:space:]]*false'; then
if printf '%s\n' "$output" | grep -Eq '"Success"[[:space:]]*:[[:space:]]*false'; then
printf '%s\n' "$output" >&2
fail "uloop $* returned success=false"
fi
Expand All @@ -79,7 +79,7 @@ assert_json_result() {
expected=$2
context=$3

actual=$(printf '%s\n' "$json" | sed -n 's/.*"result"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
actual=$(printf '%s\n' "$json" | sed -n 's/.*"Result"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
[ "$actual" = "$expected" ] || fail "$context: expected '$expected', got '$actual'"
}

Expand Down Expand Up @@ -208,7 +208,7 @@ fi
echo "[5/9] Stopping recording via CLI..."
RECORD_STOP_RESULT=$(run_uloop_json record-input --action Stop)
echo " $RECORD_STOP_RESULT"
RECORDING_INPUT_PATH=$(printf '%s\n' "$RECORD_STOP_RESULT" | sed -n 's/.*"outputPath"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
RECORDING_INPUT_PATH=$(printf '%s\n' "$RECORD_STOP_RESULT" | sed -n 's/.*"OutputPath"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')

echo "[6/9] Saving recording event log..."
save_log "$RECORDING_LOG"
Expand Down Expand Up @@ -239,13 +239,13 @@ sleep 2
waited=0
while [ $waited -lt 60 ]; do
STATUS_RESULT=$(run_uloop replay-input --action Status 2>&1) || true
playing=$(echo "$STATUS_RESULT" | grep -o '"isReplaying": *[a-z]*' | sed 's/.*: *//')
playing=$(echo "$STATUS_RESULT" | grep -o '"IsReplaying": *[a-z]*' | sed 's/.*: *//')
if [ "$playing" = "false" ]; then
echo " Replay completed."
break
fi
if [ $((waited % 5)) -eq 0 ]; then
progress=$(echo "$STATUS_RESULT" | grep -o '"progress": *[0-9.]*' | sed 's/.*: *//')
progress=$(echo "$STATUS_RESULT" | grep -o '"Progress": *[0-9.]*' | sed 's/.*: *//')
echo " Progress: ${progress:-...}"
fi
sleep 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ public async Task CompileAsync_WhenSharedWorkerBuildFails_ShouldFallbackToOneSho
dllPath,
references,
externalCompilerPaths,
new RoslynCompilerOptions(Array.Empty<string>(), false),
compileCancellationTokenSource.Token,
() => buildStarted = true,
() => buildFinished = true,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System;
using NUnit.Framework;

using io.github.hatayama.UnityCliLoop.FirstPartyTools;

namespace io.github.hatayama.UnityCliLoop.Tests.Editor.DynamicCodeToolTests
{
/// <summary>
/// Verifies the immutable compiler-settings snapshot used by dynamic compilation.
/// </summary>
[TestFixture]
public sealed class RoslynCompilerOptionsTests
{
/// <summary>
/// Verifies empty and whitespace-only define symbols are excluded while valid symbols are copied.
/// </summary>
[Test]
public void Constructor_FiltersWhitespaceAndCopiesDefineSymbols()
{
string[] defineSymbols =
{
"UNITY_EDITOR",
null,
"",
" ",
"CUSTOM_DEFINE"
};

RoslynCompilerOptions options = new(defineSymbols, true);
defineSymbols[0] = "MUTATED_AFTER_CAPTURE";

Assert.That(
options.DefineSymbols,
Is.EqualTo(new[] { "UNITY_EDITOR", "CUSTOM_DEFINE" }));
Assert.That(options.AllowUnsafeCode, Is.True);
}

/// <summary>
/// Verifies an empty define-symbol collection produces an empty immutable snapshot.
/// </summary>
[Test]
public void Constructor_WithEmptyDefineSymbols_CapturesEmptySnapshot()
{
RoslynCompilerOptions options = new(Array.Empty<string>(), false);

Assert.That(options.DefineSymbols, Is.Empty);
Assert.That(options.AllowUnsafeCode, Is.False);
}

}
}

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

Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public interface ICompiledAssemblyBuilder
{
Task<CompiledAssemblyBuildResult> BuildAsync(
DynamicCompilationPlan plan,
RoslynCompilerOptions compilerOptions,
CancellationToken ct = default);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,11 @@ public CompiledAssemblyBuilder(

public async Task<CompiledAssemblyBuildResult> BuildAsync(
DynamicCompilationPlan plan,
RoslynCompilerOptions compilerOptions,
CancellationToken ct = default)
{
Debug.Assert(plan != null, "plan must not be null");
Debug.Assert(compilerOptions != null, "compilerOptions must not be null");

ct.ThrowIfCancellationRequested();

Expand Down Expand Up @@ -98,6 +100,7 @@ async Task<CompilerMessage[]> BuildFunc(
resolvedDllPath,
resolvedReferences,
externalCompilerPaths,
compilerOptions,
cancellationToken,
() => canDeleteTempFiles = false,
() => canDeleteTempFiles = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using UnityEditor;
using Debug = UnityEngine.Debug;
using Stopwatch = System.Diagnostics.Stopwatch;

Expand Down Expand Up @@ -61,6 +62,11 @@ public async Task<CompilationResult> CompileAsync(CompilationRequest request, Ca
Debug.Assert(!string.IsNullOrWhiteSpace(request.Code), "request.Code must not be empty");

ct.ThrowIfCancellationRequested();
await MainThreadSwitcher.SwitchToMainThread(ct);
string[] activeDefineSymbols = EditorUserBuildSettings.activeScriptCompilationDefines ?? Array.Empty<string>();
RoslynCompilerOptions compilerOptions = new(
activeDefineSymbols,
PlayerSettings.allowUnsafeCode);
LastBuildCount = 0;
Stopwatch compilerTotalStopwatch = Stopwatch.StartNew();
Stopwatch planStopwatch = Stopwatch.StartNew();
Expand Down Expand Up @@ -95,7 +101,10 @@ public async Task<CompilationResult> CompileAsync(CompilationRequest request, Ca
}

Stopwatch builderTotalStopwatch = Stopwatch.StartNew();
CompiledAssemblyBuildResult buildResult = await _assemblyBuilder.BuildAsync(plan, ct).ConfigureAwait(false);
CompiledAssemblyBuildResult buildResult = await _assemblyBuilder.BuildAsync(
plan,
compilerOptions,
ct).ConfigureAwait(false);
builderTotalStopwatch.Stop();
LastBuildCount = buildResult.BuildCount;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public Task<DynamicCompilationBackendResult> CompileAsync(
string dllPath,
List<string> references,
ExternalCompilerPaths externalCompilerPaths,
RoslynCompilerOptions compilerOptions,
CancellationToken ct,
Action markBuildStarted,
Action markBuildFinished,
Expand All @@ -46,6 +47,7 @@ public Task<DynamicCompilationBackendResult> CompileAsync(
dllPath,
references,
externalCompilerPaths,
compilerOptions,
ct,
markBuildStarted,
markBuildFinished,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using UnityEditor;
using UnityEditor.Compilation;
using UnityEngine;

Expand Down Expand Up @@ -52,14 +51,15 @@ public static async Task<DynamicCompilationBackendResult> CompileAsync(
string dllPath,
List<string> references,
ExternalCompilerPaths externalCompilerPaths,
RoslynCompilerOptions compilerOptions,
CancellationToken ct,
Action markBuildStarted,
Action markBuildFinished,
Action incrementBuildCount)
{
string workerRequestFilePath = Path.ChangeExtension(sourcePath, ".worker");
string[] defineSymbols = GetActiveDefineSymbols();
bool allowUnsafeCode = PlayerSettings.allowUnsafeCode;
IReadOnlyCollection<string> defineSymbols = compilerOptions.DefineSymbols;
bool allowUnsafeCode = compilerOptions.AllowUnsafeCode;

try
{
Expand Down Expand Up @@ -271,26 +271,6 @@ internal static void WriteWorkerRequestFile(
File.WriteAllLines(Path.GetFullPath(requestFilePath), lines);
}

private static string[] GetActiveDefineSymbols()
{
string[] activeDefines = EditorUserBuildSettings.activeScriptCompilationDefines;
if (activeDefines == null || activeDefines.Length == 0)
{
return Array.Empty<string>();
}

List<string> filteredDefines = new(activeDefines.Length);
foreach (string define in activeDefines)
{
if (!string.IsNullOrWhiteSpace(define))
{
filteredDefines.Add(define);
}
}

return filteredDefines.ToArray();
}

private static string BuildDefineOption(IReadOnlyCollection<string> defineSymbols)
{
string serializedDefines = SerializeDefineSymbols(defineSymbols);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Collections.Generic;
using UnityEngine;

namespace io.github.hatayama.UnityCliLoop.FirstPartyTools
{
/// <summary>
/// Captures the Unity compiler settings required by the asynchronous Roslyn pipeline.
/// </summary>
public sealed class RoslynCompilerOptions
{
public IReadOnlyList<string> DefineSymbols { get; }

public bool AllowUnsafeCode { get; }

/// <summary>
/// Creates an immutable compiler-settings snapshot for one compilation request.
/// </summary>
public RoslynCompilerOptions(
IReadOnlyCollection<string> defineSymbols,
bool allowUnsafeCode)
{
Debug.Assert(defineSymbols != null, "defineSymbols must not be null");

List<string> filteredDefineSymbols = new(defineSymbols.Count);
foreach (string defineSymbol in defineSymbols)
{
if (!string.IsNullOrWhiteSpace(defineSymbol))
{
filteredDefineSymbols.Add(defineSymbol);
}
}

DefineSymbols = filteredDefineSymbols.AsReadOnly();
AllowUnsafeCode = allowUnsafeCode;
}
}
}

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

8 changes: 8 additions & 0 deletions Packages/src/Editor/FirstPartyTools/SetGameViewSize.meta

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using io.github.hatayama.UnityCliLoop.ToolContracts;

namespace io.github.hatayama.UnityCliLoop.FirstPartyTools
{
/// <summary>
/// Carries the resolution before and after a Set Game View Size request.
/// </summary>
public sealed class SetGameViewSizeResponse : UnityCliLoopToolResponse
{
public uint PreviousWidth { get; set; }
public uint PreviousHeight { get; set; }
public uint CurrentWidth { get; set; }
public uint CurrentHeight { get; set; }
public bool Changed { get; set; }
public string Message { get; set; } = "";
}
}
Loading
Loading