Skip to content

fix: Explain that hot reload cannot patch a Multiplayer Play Mode Virtual Player - #3191

Merged
hatayama merged 5 commits into
feature/hot-reload-large-project-feedbackfrom
fix/hot-reload-virtual-player-reason
Oct 6, 2026
Merged

hatayama merged 5 commits into
feature/hot-reload-large-project-feedbackfrom
fix/hot-reload-virtual-player-reason

Conversation

@hatayama

@hatayama hatayama commented Oct 6, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Hot reload sent to a Multiplayer Play Mode Virtual Player no longer tells you to "Compile the project first", which never helps there. The file's Failed reason now says the Editor is a Virtual Player, hot reload cannot patch it yet, the edit reaches the player through a compile, and a patch applied to the main Editor does not reach it.
  • The Multiplayer Play Mode and hot-reload references now say the same.

User Impact

  • Before: uloop --project-path <PROJECT_ROOT>/Library/VP/mppm<id> hot-reload --files ... reported the file as Failed with "Compiled assembly not found at '.../Library/ScriptAssemblies/.dll'. Compile the project first." Compiling and retrying gave the same answer.
  • After: the reason explains what is going on in a Virtual Player. Every other project keeps the existing text word for word.

What a large-project trial observed. This project has no Multiplayer Play Mode scenario, so these were not reproduced here:

  1. A patch applied to the main Editor does not reach a Virtual Player, which is a separate Editor process. The player's own hot-reload --status keeps ActivePatchTotal at 0.
  2. A Virtual Player has no Library/ScriptAssemblies under its own project root, because it loads the main project's. Hot reload looks for the compiled assembly under the Editor's own project root, so it cannot find it.
  3. Sent directly to a player, hot reload fails the file. The CLI then falls back to a compile in that player, which brings the edit in (Outcome is ReplacedByCompile).
    • Whether that compile runs follows --compile-on-skip, as for any unapplied edit. auto, the default, holds it while that player is in Play Mode (CompileFallback is HeldForPlayMode), and off never runs it. The docs state this condition.

Changes

  • A new helper in the hot-reload shared assembly:
    • It recognizes a Virtual Player project root (<main project>/Library/VP/<player directory>) from the path string alone. It does not check directories and does not reference the Multiplayer Play Mode package, so projects without that package still compile.
    • Directory names are compared ordinally. Both separators work on Windows, and a trailing separator is tolerated. A root made only of separators is answered false instead of throwing.
    • It words the missing-assembly reason.
  • The patch-target resolver gets its missing-assembly reason from the helper.
  • Docs:
    • A Hot reload section in the Multiplayer Play Mode reference.
    • A Virtual Player row in the Failed table of the hot-reload scope reference.
    • The generated skill copies are regenerated.

Not changed

  • The reason for every project that is not a Virtual Player. An exact-match test pins it.
  • The CLI's compile fallback for a Virtual Player.
  • Two other places print the same "Compiled assembly not found" text:
    • The method matcher runs only after this check has passed, and it does not receive the project root.
    • The pause-point locator belongs to another tool.
  • Not covered: patching a Virtual Player itself. The assembly location, the source snapshots, and the cache directories all assume the Editor's own project root.

Review by eye

  • HotReloadPatchTargetSupport.ResolvePatchTarget now calls HotReloadVirtualPlayerProject.DescribeMissingCompiledAssembly(projectRoot, home.DllPath). No test can pin this line, because Application.dataPath cannot be substituted.

Verification

CI for this PR runs only the Complexity Report, File Length Report, and Dead Code Gate checks, because the PR targets the integration branch. Everything below was run locally.

  • uloop compile: 0 errors, 0 warnings.
  • HotReloadVirtualPlayerProjectTests (10 tests, new):
    • Red against a stub that kept today's behavior: 3 tests failed (the two Virtual Player root cases and the Virtual Player reason).
    • 10/10 pass with the implementation. The Windows-separator case passes trivially on macOS.
  • Mutations: each was applied on top of a commit, run, and reverted.
    • Dropping the VP name check failed only ParentIsNotVP.
    • Dropping the Library name check failed only GrandparentIsNotLibrary.
    • Dropping the trailing-separator trim failed only TrailingSeparator.
  • Separator-only root: before the empty-string guard was added, the new assert in PathTooShortToHaveAGrandparent failed with ArgumentException: Invalid path. It passes with the guard.
  • Regression on the final head: 47/47 across four classes:
    • HotReloadVirtualPlayerProjectTests
    • HotReloadPatchTargetSupportEditorReadTests, HotReloadNewSourceMembershipTests, and HotReloadAssemblyResolutionDiagnosticsTests, which call the resolver directly
  • Skill checks:
    • scripts/sync-tool-docs.sh --check: no drift.
    • check-skill-size: passes.
    • The generated copies match their sources byte for byte (cmp).
  • Repository checks:
    • check-code-complexity.sh, set to fail when a limit is exceeded: 0 issues.
    • check-file-length.sh, set to fail when a limit is exceeded: no file over the limit.
    • Dead code scanner with the CI arguments: exit 0, PublicCandidate 36 (limit 37), no new symbol listed.
  • Not run: the full EditMode suite, and a check against a live Virtual Player.

Hot reload tells a Multiplayer Play Mode Virtual Player to compile
first when it cannot find the player's compiled assembly, but a
player has no compiled assemblies under its own root, so compiling
never changes the answer. These tests pin the recognizer and the
reason worded for a player. The helper is a stub that keeps today's
behavior, so the Virtual Player cases fail until it is implemented.
When the compiled assembly is missing and the project root is a
Multiplayer Play Mode Virtual Player (<main project>/Library/VP/<player>),
the (file) reason now says the player loads the main Editor's script
assemblies, so hot reload cannot patch it yet, the edit reaches it
through a compile, and a patch applied to the main Editor does not
reach it. "Compile the project first" never helps there, because a
player has no compiled assemblies under its own root. The player is
recognized from the path alone, so projects without Multiplayer Play
Mode still compile. Every other project keeps the existing text.
The Multiplayer Play Mode reference gains a Hot reload section: a
patch stays in the Editor process it was applied to, so a patch on
the main Editor never reaches a Virtual Player, and a player sent
hot-reload reports the file as Failed before the CLI's compile
fallback brings the edit in. The hot-reload scope reference lists the
Virtual Player as a Failed condition. The generated skill copies are
regenerated from the sources.
@coderabbitai

coderabbitai Bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: hatayama/unity-cli-loop/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: abb8761b-4efd-4894-a0e0-66937e237fbd
📥 Commits

Reviewing files that changed from the base of the PR and between 370b6ee and 6fc544d.

⛔ Files ignored due to path filters (2)
  • Assets/Tests/Editor/HotReload/HotReloadVirtualPlayerProjectTests.cs.meta is excluded by none and included by none
  • Packages/src/Editor/FirstPartyTools/HotReload/Shared/HotReloadVirtualPlayerProject.cs.meta is excluded by none and included by none
📒 Files selected for processing (9)
  • .agents/skills/uloop-control-play-mode/references/multiplayer-play-mode.md
  • .agents/skills/uloop-hot-reload/references/scope-and-limits.md
  • .claude/skills/uloop-control-play-mode/references/multiplayer-play-mode.md
  • .claude/skills/uloop-hot-reload/references/scope-and-limits.md
  • Assets/Tests/Editor/HotReload/HotReloadVirtualPlayerProjectTests.cs
  • Packages/src/Editor/FirstPartyTools/ControlPlayMode/Skill/references/multiplayer-play-mode.md
  • Packages/src/Editor/FirstPartyTools/HotReload/HotReloadPatchTargetSupport.cs
  • Packages/src/Editor/FirstPartyTools/HotReload/Shared/HotReloadVirtualPlayerProject.cs
  • Packages/src/Editor/FirstPartyTools/HotReload/Skill/references/scope-and-limits.md

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

Hot-reload target handling now identifies Multiplayer Play Mode Virtual Player roots and provides a specific missing-assembly message. Tests cover root detection and message content. Reference documentation describes process-local patches and the player-side compile fallback.

Changes

Virtual Player hot-reload support

Layer / File(s) Summary
Virtual Player target handling and documentation
Packages/src/Editor/FirstPartyTools/HotReload/Shared/HotReloadVirtualPlayerProject.cs, Packages/src/Editor/FirstPartyTools/HotReload/HotReloadPatchTargetSupport.cs, Assets/Tests/Editor/HotReload/HotReloadVirtualPlayerProjectTests.cs, Packages/src/Editor/FirstPartyTools/ControlPlayMode/Skill/references/multiplayer-play-mode.md, Packages/src/Editor/FirstPartyTools/HotReload/Skill/references/scope-and-limits.md, .agents/skills/uloop-control-play-mode/references/multiplayer-play-mode.md, .agents/skills/uloop-hot-reload/references/scope-and-limits.md, .claude/skills/uloop-control-play-mode/references/multiplayer-play-mode.md, .claude/skills/uloop-hot-reload/references/scope-and-limits.md
A helper identifies Virtual Player project roots and selects a corresponding message when compiled assemblies are missing. Tests cover path recognition and both message variants. Reference documentation describes patch process scope and compile fallback.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to 6fc54

This change improves the hot-reload failure message for Multiplayer Play Mode Virtual Players and leaves other projects' behavior unchanged. No merge-blocking risk was found. The author did not check the behavior against a live Virtual Player.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 92.31% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 13 functions across 3 files. (6 skipped: 6 …
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely identifies the main change: explaining that hot reload cannot patch a Multiplayer Play Mode Virtual Player.
Description check ✅ Passed The description explains the Virtual Player behavior, the updated failure reason, the documentation changes, and the reported verification. It is directly related to the changeset.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Trimming such a root leaves an empty string, and Path.GetDirectoryName
rejects that with ArgumentException in Unity's Mono. The check runs
while the missing-assembly reason is being built, so throwing there
would end the run instead of reporting the file as Failed. The
too-short-path test now covers a separator-only root as well.
The two new doc sentences said the CLI always compiles in the player
after hot reload fails the file. The fallback follows --compile-on-skip
like any unapplied edit: auto holds the compile while that player is
in Play Mode (CompileFallback is HeldForPlayMode), and off never runs
it, so in those cases the edit has not reached the player. The
generated skill copies are regenerated from the sources.
@hatayama
hatayama merged commit 8bd459d into feature/hot-reload-large-project-feedback Oct 6, 2026
5 checks passed
@hatayama
hatayama deleted the fix/hot-reload-virtual-player-reason branch October 6, 2026 14:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant