VRCSceneTemplateInitializer
does not create the default sample scene when the
UDON
preprocessor symbol is already defined on the first launch.
Steps to reproduce
  1. Prepare a VRChat Worlds template with the
    UDON
    preprocessor symbol already defined.
The original report used a project template generated by ALCOM 1.1.5 or earlier. (We added a workaround in 1.1.6.)
However, the issue can also be reproduced by modifying a VCC template to include the
UDON
preprocessor symbol in
ProjectSettings.asset
.
For reference, ALCOM's Worlds template included the
UDON
preprocessor symbol to reduce the initial Unity launch time by avoiding recompilation of most assemblies.
  1. Launch Unity.
  2. VRCSceneTemplateInitializer
    should create the default scene, but it does not.
Cause of the bug
This bug is triggered by the combination of the following conditions:
  1. UdonSharpDataLocator
    does not exist in the project. This causes
    Assets/UdonSharp/UtilityScripts
    to be generated during the first assembly load.
  2. The
    UDON
    preprocessor symbol is already defined before the first compilation. This causes
    [InitializeOnLoad]
    in
    VRCSceneTemplateInitializer
    to run during the first assembly load.
The sequence of events is as follows:
  1. Unity compiles scripts normally.
  2. Unity calls the static constructor of
    VRCSceneTemplateInitializer
    because of
    [InitializeOnLoad]
    .
VRCSceneTemplateInitializer
checks
SessionState.GetBool(HasRunStateKey, false)
, which is
false
, so it sets
HasRunStateKey
to
true
and registers an
EditorApplication.delayCall
to generate
VRCDefaultWorldScene
.
  1. Unity calls some
    [InitializeOnLoad]
    methods from UdonSharp, and UdonSharp generates
    Assets/UdonSharp/UtilityScripts
    .
  2. Unity recompiles
    Assembly-CSharp
    and reloads the domain.
Note that the registered
delayCall
is never executed before this reload.
  1. Unity calls the static constructor of
    VRCSceneTemplateInitializer
    again because of
    [InitializeOnLoad]
    .
This time,
SessionState.GetBool(HasRunStateKey, false)
returns
true
, so nothing happens.
As a result, the logic that generates
VRCDefaultWorldScene
is never executed.
(The order of steps 2 and 3 may differ, but the result is the same.)
For comparison, the following sequence does
not
cause the bug when the
UDON
symbol is not initially defined:
  1. Unity compiles scripts normally, but the
    VRC.SDK3.Editor
    assembly containing
    VRCSceneTemplateInitializer
    is not compiled because of
    "defineConstraints": ["UDON"]
    .
  2. Unity calls some
    [InitializeOnLoad]
    methods from UdonSharp, and UdonSharp generates
    Assets/UdonSharp/UtilityScripts
    .
  3. EnvConfig.cs
    checks for
    VRC.Udon.UdonBehaviour
    and adds the
    UDON
    preprocessor symbol.
  4. Unity recompiles all assemblies and reloads the domain.
  5. Unity calls the static constructor of
    VRCSceneTemplateInitializer
    because of
    [InitializeOnLoad]
    .
SessionState.GetBool(HasRunStateKey, false)
returns
false
, so it sets
HasRunStateKey
to
true
and registers an
EditorApplication.delayCall
that generates
VRCDefaultWorldScene
.
  1. Unity executes the
    EditorApplication.delayCall
    , and
    VRCDefaultWorldScene
    is generated correctly.
Suggested fix
The issue is that
HasRunStateKey
is set to
true
before the
EditorApplication.delayCall
is actually executed.
I believe moving the
HasRunStateKey
assignment into the
EditorApplication.delayCall
lambda would fix the issue.