VRChat Worlds SDK: Multi-Platform Build & Publish loops forever when the starting platform is last in the list
McDudeMan
Summary
When a Multi-Platform Build & Publish for a world is started from the platform that is last in the SDK's platform order (for example Android, with Windows and Android ticked), it never finishes. It builds and uploads Android, builds and uploads Windows, then switches back to Android and builds and uploads it again, and keeps repeating until the user stops it.
The cause is
VRCMultiPlatformBuild.ShouldContinueMPB
. When the starting platform is also the last in the list, it returns true
on every return to that platform, because that branch assumes the platform has not been built yet (as in the avatar flow). The world builder has already built it at the start, so the end-of-run check in SetUpNextMPBTarget
(MPBBuiltCount + 1 == MPBPlatformsList.Count
) can never become true.Environment
- Unity: 2022.3.22f1
- VRChat Worlds SDK: com.vrchat.worlds 3.10.3
- VRChat Base SDK: com.vrchat.base 3.10.3
- Content type: World (Udon / UdonSharp)
- Platforms ticked: Windows and Android (PC + Quest)
- Editor open on: Android. The loop only happens when the run is started while on Android.
- Files involved: VRCMultiPlatformBuild.cs(com.vrchat.base, Editor/VRCSDK/Dependencies/VRChat) andVRCSdkControlPanelWorldBuilder.cs(com.vrchat.worlds, Editor/VRCSDK/SDK3)
Steps to reproduce
- Open a world project with the Editor's active build target set to Android.
- Open the VRChat SDK Control Panel, Builder tab, and tick both Windows and Android for a multi-platform build.
- Press Build & Publish.
- Wait while the SDK builds and uploads Android, switches to Windows, builds and uploads Windows, and switches back to Android.
Expected:
the run ends when it arrives back on the starting platform, and the "Multi-Platform Upload Finished" notification shows.Actual:
the SDK builds and uploads Android a second time, then Windows again, and so on until the user cancels.Root cause
The platform list is
[Windows, Android]
and MPBInitialPlatform
is Android, so the starting platform is also MPBPlatformsList.Last()
. Tracing the session state through the run:- Android (start), count 0: StartMPBsees initial == last, so it does not enter Building.BuildAndUploadMultiPlatformstill builds and uploads Android because Android is in the list.
- Android, count 1: SetUpNextMPBTargetpicks Windows, increments the count, state = Switching, switches platform.
- Windows, count 2: ShouldContinueMPBreturns true (initial != current). Windows is built and uploaded.SetUpNextMPBTargetpicks Android and increments.
- Android (back at start), count 2: ShouldContinueMPBreachesif (MPBInitialPlatform == MPBPlatformsList.Last()) return true;and returns true instead of finishing. Android is built and uploaded again.
- Android, count 3: the SetUpNextMPBTargetend check needsMPBBuiltCount + 1 == MPBPlatformsList.Count, which is 3 == 2 and false. It switches to Windows and increments again.
From step 5 the count only grows past the list length, so neither exit is ever reached: not the
isMPBFinished = true
path in ShouldContinueMPB
, and not the early return false
in SetUpNextMPBTarget
.The
initial == last
branch in ShouldContinueMPB
and the BuiltCount + 1 == Count
check in SetUpNextMPBTarget
look designed as a pair for a flow where the starting platform is skipped at the beginning and built last (the code comment says this "can happen for Avatar builds"). In VRCSdkControlPanelWorldBuilder.BuildAndUploadMultiPlatform
the only skip condition is !_selectedBuildTargets.Contains(EditorUserBuildSettings.activeBuildTarget)
, so a starting platform that is in the list is built immediately. That leaves the count one ahead of what the end check expects. This pairing is an inference from reading the code, not something confirmed by running the avatar flow.Suggested fix
End the run when it returns to the starting platform and every platform in the list has already been built. In
ShouldContinueMPB
, the initial == last
branch should only return true while the starting platform has not been built yet:```csharp
// If the initial platform is last in the list, only build it again if it has not been built yet
if (MPBInitialPlatform == MPBPlatformsList.Last() && MPBBuiltCount < MPBPlatformsList.Count)
{
return true;
}
```
With
[Windows, Android]
started on Android this gives MPBBuiltCount == 2
on the return trip, so the run falls through to isMPBFinished = true
and ReportMPBDone()
. If the avatar flow counts differently (it may build the starting platform last and reach this point with a count of Count - 1
), the same condition keeps that behaviour, but that is unverified.A second option is to make
BuildAndUploadMultiPlatform
skip the starting platform when it is last in the list and call SetUpNextMPBTarget(cancellationToken, false)
, so the count lines up with the existing end check.Local patch used while waiting for an official fix:
an early exit at the top of StartMultiPlatformBuild
in VRCSdkControlPanelWorldBuilder.cs
. When MPB
is true, the list has more than one platform, the initial platform is the last in the list and is the active target, and MPBBuiltCount >= MPBPlatformsList.Count
, it calls VRCMultiPlatformBuild.ReportMPBDone()
, re-enables the UI, shows the "Multi-Platform Upload Finished" notification and returns. This only touches the world builder, so avatar builds are unaffected. Tested: this patch was run in Unity on a real multi-platform publish started from Android, and worked. The run now finishes normally instead of looping. The one-condition change to ShouldContinueMPB
above has not been run itself; the tested patch applies the same end-of-run rule from the world builder.Workaround and evidence
Workaround without changing the SDK:
start the multi-platform publish while the Editor is on Windows, the first platform in the list. The run then goes Windows, Android, back to Windows, and the existing finish check works. After cancelling a looping run, use VRChat SDK > Utilities > Clear Multi Platform Build State, because the state lives in SessionState
and survives script reloads.Evidence from the Unity Editor.log of an affected run:
- A platform switch to Windows was requested (Requested script compilation because: Switching to platform Windows, Mac, Linux), followed later by a switch to Android (Switching to platform Android).
- Stack traces in the same log pass through VRCSdkControlPanelWorldBuilder.BuildAndUploadMultiPlatform(VRCSdkControlPanelWorldBuilder.cs, line 3312), confirming the build and upload ran from the multi-platform path.
- The log covers a run that the user cancelled, so it shows the switch order but not a final repeat cycle. The repeat was observed directly in the Editor and is described above.
Happy to provide the full Editor.log, the Console output, or a screen recording of the loop if useful.
Log In