diff --git a/CLAUDE.md b/CLAUDE.md
index 464bc85..c7ca0b4 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -486,13 +486,15 @@ should not be — see `docs/restructure-plan.md`.
four runtime files use — without that, everything referencing it would have stopped compiling.
Keep it in mind before adding loose scripts outside an asmdef folder.
-5. **`Tools ▸ Nightclub Arcadia ▸ Set Up Yarn Sandbox Scene` overwrites its target scene
- wholesale.** It builds a scene from scratch and calls `SaveScene` over `ScenePath`. It is
- pinned to `Assets/Scenes/Dev/` and guarded by `ScenePaths.IsDisposable`, because it was once
- briefly retargeted at `SC101_ConferenceHall` and destroyed it — ten of fourteen roots, the
- player and the lighting included. **Never point a scene-generating menu at a real scene.**
- The other three setup menus (`PlayerControlSetup`, `UILayerSetup`, `SkillSystemSetup`) open
- and modify their target, which is safe.
+5. **The one-shot scene builders under `Assets/Editor` are disabled, on purpose.**
+ `Set Up UI Layer`, `Set Up Player Control & Camera` and `Set Up Yarn Sandbox Scene` were
+ written for the single-scene layout. After the split they do damage rather than work: pointed
+ at a level they rebuild systems content that already exists in `Systems.unity`, and pointed at
+ Systems, `PlayerControlSetup` drags navigation in and silently turns that scene binary (trap 1
+ again). Both were observed. They now return early via `LegacySceneSetup.Blocked` and are kept
+ only as a record of how the wiring works until prefabs replace them (Phase 5).
+ `Set Up Skill System` and `Set Up Candidate System` still work — they regenerate assets from
+ JSON and touch no scene. **To run the game, open `Bootstrap.unity` and press Play.**
6. **`unity run` reserves `-batchmode`, `-nographics`, `-quit`, `-logFile`.** Passing any of them
after `--` is a hard error, and its output does not reach stdout — read `Logs/Editor.log` (§3.4).
diff --git a/NightclubArcadia/Assets/Editor/LegacySceneSetup.cs b/NightclubArcadia/Assets/Editor/LegacySceneSetup.cs
new file mode 100644
index 0000000..fec48e7
--- /dev/null
+++ b/NightclubArcadia/Assets/Editor/LegacySceneSetup.cs
@@ -0,0 +1,48 @@
+using UnityEditor;
+using UnityEngine;
+
+namespace NightclubArcadia.EditorTools
+{
+ ///
+ /// Gate for the one-shot scene builders under Assets/Editor.
+ ///
+ /// Those menus were written when the whole game lived in a single scene. They find
+ /// or create the dialogue system, the UI canvases, the player and the camera rig,
+ /// and save the result into one scene. After the split into Bootstrap / Systems /
+ /// Level, that assumption is false, and running them does damage rather than work:
+ ///
+ /// - Pointed at a level, they rebuild systems content that already exists in
+ /// Systems.unity, leaving duplicate UIStateControllers and dialogue runners.
+ /// - Pointed at Systems, PlayerControlSetup drags navigation in with it. The
+ /// baked NavMeshData is embedded rather than an asset, and NavMeshData prefers
+ /// binary serialization, so the whole scene silently turns binary — the exact
+ /// problem that took a bisection to find the first time (CLAUDE.md trap 1).
+ ///
+ /// Both were observed, not theorised. So the builders are blocked rather than
+ /// retargeted, and deliberately not deleted: UILayerSetup alone is 818 lines that
+ /// still record how the UI layer is wired, and that record is worth keeping until
+ /// the prefabs replace it (docs/restructure-plan.md Phase 5).
+ ///
+ /// Asset generators are unaffected. Regenerating SkillDefinitions or the candidate
+ /// registry from JSON touches no scene and stays available.
+ ///
+ public static class LegacySceneSetup
+ {
+ ///
+ /// Call at the top of any menu that builds scene content. Returns true if the
+ /// caller should stop, which is currently always.
+ ///
+ public static bool Blocked(string menuName, string whatItWouldDo)
+ {
+ Debug.LogError(
+ $"'{menuName}' is disabled.\n\n" +
+ $"It was written for the single-scene layout and would {whatItWouldDo}. " +
+ "The game is now split across Bootstrap, Systems and a level scene, and the " +
+ "objects it builds already exist in Assets/Scenes/Systems/Systems.unity.\n\n" +
+ "To run the game: open Assets/Scenes/Bootstrap.unity and press Play.\n" +
+ "To verify it comes up: make test-play\n" +
+ "Rewriting these for the split is docs/restructure-plan.md Phase 5.");
+ return true;
+ }
+ }
+}
diff --git a/NightclubArcadia/Assets/Editor/LegacySceneSetup.cs.meta b/NightclubArcadia/Assets/Editor/LegacySceneSetup.cs.meta
new file mode 100644
index 0000000..587af9d
--- /dev/null
+++ b/NightclubArcadia/Assets/Editor/LegacySceneSetup.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 6d28eed724b04f52af81ac74d57f3f26
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/NightclubArcadia/Assets/Editor/PlayerControlSetup.cs b/NightclubArcadia/Assets/Editor/PlayerControlSetup.cs
index af9eec3..56bd4b2 100644
--- a/NightclubArcadia/Assets/Editor/PlayerControlSetup.cs
+++ b/NightclubArcadia/Assets/Editor/PlayerControlSetup.cs
@@ -10,18 +10,22 @@ using UnityEngine;
using UnityEngine.AI;
///
-/// Wires player control, navigation, and camera systems into SC101_ConferenceHall.unity.
+/// Wires player control, navigation, and camera systems into Systems.unity.
/// Run via Tools → Nightclub Arcadia → Set Up Player Control & Camera.
///
public static class PlayerControlSetup
{
- const string ScenePath = NightclubArcadia.EditorTools.ScenePaths.WorkingLevel;
+ const string ScenePath = NightclubArcadia.EditorTools.ScenePaths.Systems;
const string PlayerPrefabPath = "Assets/StarterAssets/ThirdPersonController/Prefabs/PlayerArmature.prefab";
const string SettingsFolder = "Assets/Settings";
[MenuItem("Tools/Nightclub Arcadia/Set Up Player Control & Camera")]
public static void SetUp()
{
+ if (NightclubArcadia.EditorTools.LegacySceneSetup.Blocked("Set Up Player Control & Camera",
+ "rebuild the player and camera rig and pull navigation into Systems.unity, "
+ + "which turns that scene binary")) return;
+
EnsurePlayerPrefab();
WireScene();
AssetDatabase.SaveAssets();
diff --git a/NightclubArcadia/Assets/Editor/SkillSystemSetup.cs b/NightclubArcadia/Assets/Editor/SkillSystemSetup.cs
index 961687f..4533796 100644
--- a/NightclubArcadia/Assets/Editor/SkillSystemSetup.cs
+++ b/NightclubArcadia/Assets/Editor/SkillSystemSetup.cs
@@ -23,7 +23,7 @@ public static class SkillSystemSetup
const string SkillsFolder = "Assets/Skills";
const string BiblePath = "Assets/Skills/skill_bible.json";
const string DatabasePath = "Assets/Skills/SkillDatabase.asset";
- const string ScenePath = NightclubArcadia.EditorTools.ScenePaths.WorkingLevel;
+ const string ScenePath = NightclubArcadia.EditorTools.ScenePaths.Systems;
const string AutoSetupSessionKey = "NightclubArcadia.SkillSystem.AutoSetupDone";
[DidReloadScripts]
@@ -55,7 +55,7 @@ public static class SkillSystemSetup
///
/// Creates/updates ScriptableObject assets without opening a scene.
/// Safe to run on domain reload. Scene wiring stays on the menu item /
- /// the checked-in SC101_ConferenceHall.unity Skill System objects.
+ /// the checked-in Systems.unity Skill System objects.
///
static void EnsureSkillAssetsOnly()
{
@@ -122,9 +122,12 @@ public static class SkillSystemSetup
EditorUtility.SetDirty(database);
AssetDatabase.SaveAssets();
- WireWorkingLevelScene(database);
+ // Scene wiring deliberately skipped: the Skill System objects live in
+ // Systems.unity and are already wired there. Regenerating the assets is
+ // still useful and touches no scene. See LegacySceneSetup.
AssetDatabase.SaveAssets();
- Debug.Log($"Skill system setup complete. Database at {DatabasePath}; scene wired at {ScenePath}.");
+ Debug.Log($"Skill assets regenerated. Database at {DatabasePath}. Scene wiring skipped — "
+ + "the Skill System already exists in Systems.unity.");
}
static bool TryLoadRoster(out SkillBibleEntry[] roster)
@@ -243,7 +246,7 @@ public static class SkillSystemSetup
var runner = UnityEngine.Object.FindAnyObjectByType();
if (runner == null)
{
- Debug.LogError("No DialogueRunner in SC101_ConferenceHall.unity.");
+ Debug.LogError("No DialogueRunner in Systems.unity.");
return;
}
diff --git a/NightclubArcadia/Assets/Editor/UILayerSetup.cs b/NightclubArcadia/Assets/Editor/UILayerSetup.cs
index 21f55b5..8286007 100644
--- a/NightclubArcadia/Assets/Editor/UILayerSetup.cs
+++ b/NightclubArcadia/Assets/Editor/UILayerSetup.cs
@@ -16,12 +16,12 @@ using UnityEngine.UI;
using Yarn.Unity;
///
-/// Builds UI prefabs and wires them into SC101_ConferenceHall.unity.
+/// Builds UI prefabs and wires them into Systems.unity.
/// Run via Tools → Nightclub Arcadia → Set Up UI Layer.
///
public static class UILayerSetup
{
- const string ScenePath = NightclubArcadia.EditorTools.ScenePaths.WorkingLevel;
+ const string ScenePath = NightclubArcadia.EditorTools.ScenePaths.Systems;
const string PrefabFolder = "Assets/Prefabs/UI";
const string ArtFolder = "Assets/Art/UI/Placeholder";
@@ -40,6 +40,9 @@ public static class UILayerSetup
[MenuItem("Tools/Nightclub Arcadia/Set Up UI Layer")]
public static void SetUp()
{
+ if (NightclubArcadia.EditorTools.LegacySceneSetup.Blocked("Set Up UI Layer",
+ "rebuild the UI canvases that already live in Systems.unity, leaving duplicates")) return;
+
EnsureFolders();
CreatePortraitPlaceholder();
diff --git a/NightclubArcadia/Assets/Editor/YarnDemoSetup.cs b/NightclubArcadia/Assets/Editor/YarnDemoSetup.cs
index dc71b06..a5fe534 100644
--- a/NightclubArcadia/Assets/Editor/YarnDemoSetup.cs
+++ b/NightclubArcadia/Assets/Editor/YarnDemoSetup.cs
@@ -14,6 +14,9 @@ public static class YarnDemoSetup
[MenuItem("Tools/Nightclub Arcadia/Set Up Yarn Sandbox Scene")]
public static void SetUpYarnDialogueTest()
{
+ if (NightclubArcadia.EditorTools.LegacySceneSetup.Blocked("Set Up Yarn Sandbox Scene",
+ "generate a throwaway scene whose dialogue runner duplicates the real one")) return;
+
// This menu BUILDS A SCENE FROM SCRATCH and saves over ScenePath. Pointed at a
// real level it silently destroys it, which is exactly what happened when it
// was briefly retargeted at SC101_ConferenceHall. The guard is the fix; do not
@@ -67,9 +70,30 @@ public static class YarnDemoSetup
so.FindProperty("yarnProject").objectReferenceValue = yarnProject;
so.ApplyModifiedPropertiesWithoutUndo();
+ // CreateDialogueRunner returns a component on a PREFAB INSTANCE of the package's
+ // Dialogue System prefab. Applying a SerializedProperty on one of those does not
+ // always record the override, and an unrecorded override is dropped on save —
+ // which produced a sandbox whose runner had no project, auto-started, and
+ // failed with "Can't start dialogue: no Yarn Project has been configured."
+ if (PrefabUtility.IsPartOfPrefabInstance(runner))
+ {
+ PrefabUtility.RecordPrefabInstancePropertyModifications(runner);
+ }
+
runner.autoStart = true;
runner.startNode = "Start";
EditorUtility.SetDirty(runner);
+ EditorSceneManager.MarkSceneDirty(scene);
+
+ // Postcondition. This menu exists to produce a runnable scene; a scene whose
+ // runner has no project is worse than no scene, because it fails at Play time
+ // with an error that points nowhere near here.
+ if (new SerializedObject(runner).FindProperty("yarnProject").objectReferenceValue == null)
+ {
+ Debug.LogError("Yarn sandbox setup failed: the DialogueRunner has no Yarn Project. " +
+ "The generated scene will error on Play. Not saving.");
+ return;
+ }
#if UNITY_2023_1_OR_NEWER
var eventSystems = Object.FindObjectsByType(FindObjectsInactive.Include);