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);