diff --git a/CLAUDE.md b/CLAUDE.md index a30caa2..464bc85 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -486,24 +486,32 @@ 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. **`unity run` reserves `-batchmode`, `-nographics`, `-quit`, `-logFile`.** Passing any of them +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. + +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). -6. **`-quit` with `-runTests`** hangs or truncates. Omit it (§3.2). +7. **`-quit` with `-runTests`** hangs or truncates. Omit it (§3.2). -7. **Exit code alone is not a test verdict.** Parse the results XML (§3.2), which is what +8. **Exit code alone is not a test verdict.** Parse the results XML (§3.2), which is what `make test` does. -8. **`which unity` fails** in non-interactive shells even though the CLI is installed. Use the +9. **`which unity` fails** in non-interactive shells even though the CLI is installed. Use the absolute path `/Users/lennart/.unity/bin/unity` (§3.0). -9. **Editor lock** — check before every headless run, filtering out `AssetImportWorker` children. +10. **Editor lock** — check before every headless run, filtering out `AssetImportWorker` children. `make test` and `make build` do this for you (§2b). -10. **Regenerated assets** — hand edits to `Skills/Definitions/*`, `Candidates/Definitions/*` +11. **Regenerated assets** — hand edits to `Skills/Definitions/*`, `Candidates/Definitions/*` and the two `*Database.asset` files are silently discarded (§2.1). -11. **`top_skill` ties** resolve to the first argument. Reordering arguments changes the game. +12. **`top_skill` ties** resolve to the first argument. Reordering arguments changes the game. -12. **`Bootstrap` must stay index 0** in the build settings, and all three scenes must be listed, +13. **`Bootstrap` must stay index 0** in the build settings, and all three scenes must be listed, or `LoadSceneAsync` by name fails at runtime with nothing but a console error. diff --git a/NightclubArcadia/Assets/Editor/ScenePaths.cs b/NightclubArcadia/Assets/Editor/ScenePaths.cs index 0d2975c..5fc7cc1 100644 --- a/NightclubArcadia/Assets/Editor/ScenePaths.cs +++ b/NightclubArcadia/Assets/Editor/ScenePaths.cs @@ -15,7 +15,30 @@ namespace NightclubArcadia.EditorTools /// Persistent systems: dialogue, skills, UI, camera rig, player. public const string Systems = "Assets/Scenes/Systems/Systems.unity"; - /// The scene the setup menus wire into. SC-101's conference hall. + /// + /// The scene the setup menus wire into. SC-101's conference hall. + /// + /// Only for menus that OPEN and MODIFY a scene. A menu that builds a scene from + /// scratch and saves over its target must never point here — see Sandbox. + /// public const string WorkingLevel = "Assets/Scenes/Levels/SC101_ConferenceHall.unity"; + + /// + /// Scratch scene for menus that generate a scene wholesale. + /// + /// This exists because pointing such a menu at WorkingLevel destroyed it once: + /// YarnDemoSetup builds a demo scene and calls SaveScene over its target, so + /// running it replaced SC-101 with a bare Yarn demo. Anything under Scenes/Dev + /// is disposable by definition; nothing outside it is. + /// + public const string Sandbox = "Assets/Scenes/Dev/YarnSandbox.unity"; + + /// + /// Guard for any menu that overwrites a whole scene. Generated scenes belong in + /// Scenes/Dev and nowhere else. + /// + public static bool IsDisposable(string scenePath) => + !string.IsNullOrEmpty(scenePath) && + scenePath.Replace('\\', '/').StartsWith("Assets/Scenes/Dev/", System.StringComparison.Ordinal); } } diff --git a/NightclubArcadia/Assets/Editor/YarnDemoSetup.cs b/NightclubArcadia/Assets/Editor/YarnDemoSetup.cs index 59c0caa..dc71b06 100644 --- a/NightclubArcadia/Assets/Editor/YarnDemoSetup.cs +++ b/NightclubArcadia/Assets/Editor/YarnDemoSetup.cs @@ -9,11 +9,27 @@ using Yarn.Unity.Editor; public static class YarnDemoSetup { const string YarnProjectPath = "Assets/Dialogue/NightclubArcadia.yarnproject"; - const string ScenePath = NightclubArcadia.EditorTools.ScenePaths.WorkingLevel; + const string ScenePath = NightclubArcadia.EditorTools.ScenePaths.Sandbox; - [MenuItem("Tools/Nightclub Arcadia/Set Up Yarn Dialogue Test")] + [MenuItem("Tools/Nightclub Arcadia/Set Up Yarn Sandbox Scene")] public static void SetUpYarnDialogueTest() { + // 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 + // remove it, and do not point ScenePath outside Scenes/Dev. + if (!NightclubArcadia.EditorTools.ScenePaths.IsDisposable(ScenePath)) + { + Debug.LogError($"Refusing to run: '{ScenePath}' is not under Assets/Scenes/Dev/. " + + "This menu overwrites its target scene wholesale."); + return; + } + + if (!AssetDatabase.IsValidFolder("Assets/Scenes/Dev")) + { + AssetDatabase.CreateFolder("Assets/Scenes", "Dev"); + } + if (!AssetDatabase.IsValidFolder("Assets/TextMesh Pro")) { Debug.LogWarning("TextMesh Pro essential resources are missing. Run Window → TextMeshPro → Import TMP Essential Resources."); diff --git a/NightclubArcadia/Assets/Prefabs/UI/DialogueMessageRow.prefab b/NightclubArcadia/Assets/Prefabs/UI/DialogueMessageRow.prefab index 7f26b4f..91d1bbf 100644 --- a/NightclubArcadia/Assets/Prefabs/UI/DialogueMessageRow.prefab +++ b/NightclubArcadia/Assets/Prefabs/UI/DialogueMessageRow.prefab @@ -51,7 +51,7 @@ MonoBehaviour: m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: a7773ea9a6f44798aa98356903037d16, type: 3} m_Name: - m_EditorClassIdentifier: Assembly-CSharp::NightclubArcadia.UI.Dialogue.DialogueMessageRow + m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.UI.Dialogue.DialogueMessageRow speakerText: {fileID: 5900251945930220314} bodyText: {fileID: 1670956017877202442} speakerLabel: {fileID: 5822252844234204748} diff --git a/NightclubArcadia/Assets/Prefabs/UI/DialogueStreamCanvas.prefab b/NightclubArcadia/Assets/Prefabs/UI/DialogueStreamCanvas.prefab index 68f19ce..0fc9d79 100644 --- a/NightclubArcadia/Assets/Prefabs/UI/DialogueStreamCanvas.prefab +++ b/NightclubArcadia/Assets/Prefabs/UI/DialogueStreamCanvas.prefab @@ -542,7 +542,7 @@ MonoBehaviour: m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 88cb6495795a4e13ac7fb72343c132af, type: 3} m_Name: - m_EditorClassIdentifier: Assembly-CSharp::NightclubArcadia.UI.Dialogue.DialogueStreamPresenter + m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.UI.Dialogue.DialogueStreamPresenter messageRowPrefab: {fileID: 5353601244371665078, guid: 90818ef7dc74247ceb348994755cea86, type: 3} messageContainer: {fileID: 4838388606347767229} scrollRect: {fileID: 7105587415705135446} @@ -559,7 +559,7 @@ MonoBehaviour: m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 8d86cc99d5b545c4a3fad9e1482031a2, type: 3} m_Name: - m_EditorClassIdentifier: Assembly-CSharp::NightclubArcadia.UI.Dialogue.DialogueStreamOptionsPresenter + m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.UI.Dialogue.DialogueStreamOptionsPresenter optionViewPrefab: {fileID: 2576261519635394347, guid: e605972137b0b4c1399ffb07beae9a9b, type: 3} optionsContainer: {fileID: 6329947636030823459} canvasGroup: {fileID: 5117926241503925785} diff --git a/NightclubArcadia/Assets/Prefabs/UI/HudCanvas.prefab b/NightclubArcadia/Assets/Prefabs/UI/HudCanvas.prefab index 7d9c455..588f14f 100644 --- a/NightclubArcadia/Assets/Prefabs/UI/HudCanvas.prefab +++ b/NightclubArcadia/Assets/Prefabs/UI/HudCanvas.prefab @@ -252,7 +252,7 @@ MonoBehaviour: m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: fd1354ade14b4b1d80da9acac4aa9e12, type: 3} m_Name: - m_EditorClassIdentifier: Assembly-CSharp::NightclubArcadia.UI.HUD.PortraitHudView + m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.UI.HUD.PortraitHudView panelRoot: {fileID: 4989543578856257477} --- !u!1 &4989543578856257477 GameObject: diff --git a/NightclubArcadia/Assets/Prefabs/UI/PlayerMenuCanvas.prefab b/NightclubArcadia/Assets/Prefabs/UI/PlayerMenuCanvas.prefab index 15575fa..032788c 100644 --- a/NightclubArcadia/Assets/Prefabs/UI/PlayerMenuCanvas.prefab +++ b/NightclubArcadia/Assets/Prefabs/UI/PlayerMenuCanvas.prefab @@ -61,7 +61,7 @@ MonoBehaviour: m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 74efa3bf7a354892a401418d8f56fb2b, type: 3} m_Name: - m_EditorClassIdentifier: Assembly-CSharp::NightclubArcadia.UI.Menu.JournalPanelView + m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.UI.Menu.JournalPanelView placeholderLabel: {fileID: 438358810008138731} --- !u!1 &2044419659697384337 GameObject: @@ -140,7 +140,7 @@ MonoBehaviour: m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: db83a1a74e0e418881880ca808f68160, type: 3} m_Name: - m_EditorClassIdentifier: Assembly-CSharp::NightclubArcadia.UI.Menu.MenuTabBar + m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.UI.Menu.MenuTabBar tabs: - button: {fileID: 1673770274793931208} panel: {fileID: 5076829831943889175} @@ -245,7 +245,7 @@ MonoBehaviour: m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: ef17c93c7dec4af2ae7ce565c8984de3, type: 3} m_Name: - m_EditorClassIdentifier: Assembly-CSharp::NightclubArcadia.UI.Menu.CharacterPanelView + m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.UI.Menu.CharacterPanelView nameLabel: {fileID: 8967222838737055253} aliasLabel: {fileID: 4652515771799086270} inventoryPlaceholder: {fileID: 1990427928476398531} @@ -483,7 +483,7 @@ MonoBehaviour: m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 118cc9783dba4b3cac1646d97ebd3998, type: 3} m_Name: - m_EditorClassIdentifier: Assembly-CSharp::NightclubArcadia.UI.Menu.PlayerMenuController + m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.UI.Menu.PlayerMenuController menuRoot: {fileID: 2249656863633318815} menuInput: {fileID: 0} controlLock: {fileID: 0} @@ -783,6 +783,143 @@ MonoBehaviour: m_hasFontAssetChanged: 0 m_baseMaterial: {fileID: 0} m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &3123656435113957211 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2894368236897154238} + - component: {fileID: 8211184503074210791} + - component: {fileID: 8997850575536806412} + m_Layer: 0 + m_Name: Label + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2894368236897154238 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3123656435113957211} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6001922808625371455} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8211184503074210791 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3123656435113957211} + m_CullTransparentMesh: 1 +--- !u!114 &8997850575536806412 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3123656435113957211} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Skills + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: 0 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 22 + m_fontSizeBase: 22 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 1 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_characterHorizontalScale: 1 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_TextWrappingMode: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 0 + m_ActiveFontFeatures: 6e72656b + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_EmojiFallbackSupport: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} --- !u!1 &3533277334474984255 GameObject: m_ObjectHideFlags: 0 @@ -1388,7 +1525,7 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: - - {fileID: 3528103284151106981} + - {fileID: 1481520485721663919} m_Father: {fileID: 5714344749226447693} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} @@ -1605,7 +1742,7 @@ RectTransform: m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: - - {fileID: 1015917500768946775} + - {fileID: 2894368236897154238} m_Father: {fileID: 5714344749226447693} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0.5, y: 0.5} @@ -1873,7 +2010,7 @@ MonoBehaviour: m_FlexibleWidth: -1 m_FlexibleHeight: -1 m_LayoutPriority: 1 ---- !u!1 &7644334300092530069 +--- !u!1 &7967390318583634950 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -1881,9 +2018,9 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 1015917500768946775} - - component: {fileID: 4696967337599140493} - - component: {fileID: 3131234387202370334} + - component: {fileID: 1481520485721663919} + - component: {fileID: 2759775973399345411} + - component: {fileID: 6167893425112707945} m_Layer: 0 m_Name: Label m_TagString: Untagged @@ -1891,40 +2028,40 @@ GameObject: m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &1015917500768946775 +--- !u!224 &1481520485721663919 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7644334300092530069} + m_GameObject: {fileID: 7967390318583634950} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] - m_Father: {fileID: 6001922808625371455} + m_Father: {fileID: 453386429374550589} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} m_AnchorMax: {x: 1, y: 1} m_AnchoredPosition: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} ---- !u!222 &4696967337599140493 +--- !u!222 &2759775973399345411 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7644334300092530069} + m_GameObject: {fileID: 7967390318583634950} m_CullTransparentMesh: 1 ---- !u!114 &3131234387202370334 +--- !u!114 &6167893425112707945 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 7644334300092530069} + m_GameObject: {fileID: 7967390318583634950} m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} @@ -1938,7 +2075,7 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_text: Skills + m_text: Journal m_isRightToLeft: 0 m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} @@ -2213,143 +2350,6 @@ MonoBehaviour: rowPrefab: {fileID: 1141587833647839303, guid: e14f68d6a57ea4945bd93c44202db910, type: 3} axisHeaderPrefab: {fileID: 5719341463139795832} displayMaxRank: 6 ---- !u!1 &8926189410052142562 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 3528103284151106981} - - component: {fileID: 8980946710928878816} - - component: {fileID: 5867361342524513168} - m_Layer: 0 - m_Name: Label - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &3528103284151106981 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8926189410052142562} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 453386429374550589} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!222 &8980946710928878816 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8926189410052142562} - m_CullTransparentMesh: 1 ---- !u!114 &5867361342524513168 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 8926189410052142562} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} - m_Name: - m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshProUGUI - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_text: Journal - m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_fontSharedMaterials: [] - m_fontMaterial: {fileID: 0} - m_fontMaterials: [] - m_fontColor32: - serializedVersion: 2 - rgba: 4294967295 - m_fontColor: {r: 1, g: 1, b: 1, a: 1} - m_enableVertexGradient: 0 - m_colorMode: 3 - m_fontColorGradient: - topLeft: {r: 1, g: 1, b: 1, a: 1} - topRight: {r: 1, g: 1, b: 1, a: 1} - bottomLeft: {r: 1, g: 1, b: 1, a: 1} - bottomRight: {r: 1, g: 1, b: 1, a: 1} - m_fontColorGradientPreset: {fileID: 0} - m_spriteAsset: {fileID: 0} - m_tintAllSprites: 0 - m_StyleSheet: {fileID: 0} - m_TextStyleHashCode: 0 - m_overrideHtmlColors: 0 - m_faceColor: - serializedVersion: 2 - rgba: 4294967295 - m_fontSize: 22 - m_fontSizeBase: 22 - m_fontWeight: 400 - m_enableAutoSizing: 0 - m_fontSizeMin: 18 - m_fontSizeMax: 72 - m_fontStyle: 1 - m_HorizontalAlignment: 2 - m_VerticalAlignment: 512 - m_textAlignment: 65535 - m_characterSpacing: 0 - m_characterHorizontalScale: 1 - m_wordSpacing: 0 - m_lineSpacing: 0 - m_lineSpacingMax: 0 - m_paragraphSpacing: 0 - m_charWidthMaxAdj: 0 - m_TextWrappingMode: 1 - m_wordWrappingRatios: 0.4 - m_overflowMode: 0 - m_linkedTextComponent: {fileID: 0} - parentLinkedComponent: {fileID: 0} - m_enableKerning: 0 - m_ActiveFontFeatures: 6e72656b - m_enableExtraPadding: 0 - checkPaddingRequired: 0 - m_isRichText: 1 - m_EmojiFallbackSupport: 1 - m_parseCtrlCharacters: 1 - m_isOrthographic: 1 - m_isCullingEnabled: 0 - m_horizontalMapping: 0 - m_verticalMapping: 0 - m_uvLineOffset: 0 - m_geometrySortingOrder: 0 - m_IsTextObjectScaleStatic: 0 - m_VertexBufferAutoSizeReduction: 0 - m_useMaxVisibleDescender: 1 - m_pageToDisplay: 1 - m_margin: {x: 0, y: 0, z: 0, w: 0} - m_isUsingLegacyAnimationComponent: 0 - m_isVolumetricText: 0 - m_hasFontAssetChanged: 0 - m_baseMaterial: {fileID: 0} - m_maskOffset: {x: 0, y: 0, z: 0, w: 0} --- !u!1 &9109014941581283762 GameObject: m_ObjectHideFlags: 0 diff --git a/NightclubArcadia/Assets/Tests/PlayMode/BootstrapTests.cs b/NightclubArcadia/Assets/Tests/PlayMode/BootstrapTests.cs index 653f788..ba05df9 100644 --- a/NightclubArcadia/Assets/Tests/PlayMode/BootstrapTests.cs +++ b/NightclubArcadia/Assets/Tests/PlayMode/BootstrapTests.cs @@ -1,4 +1,5 @@ using System.Collections; +using System.Linq; using NUnit.Framework; using NightclubArcadia.Cinematics; using Unity.Cinemachine; @@ -73,6 +74,31 @@ namespace NightclubArcadia.PlayMode.Tests "No DialogueRunner in any loaded scene"); } + /// + /// Regression: "Can't start dialogue: no Yarn Project has been configured." + /// + /// Asserting the runner merely exists is not enough — it auto-starts on Start(), + /// and a runner with no project throws that at load with nothing else wrong. + /// The project is a serialized asset reference supplied by a prefab override, so + /// it breaks silently if the override is ever dropped. + /// + [Test] + public void TheDialogueRunner_HasItsYarnProject() + { + var runners = Object.FindObjectsByType( + FindObjectsInactive.Include, FindObjectsSortMode.None); + + Assert.AreEqual(1, runners.Length, + "Expected exactly one DialogueRunner across the loaded scenes, found " + + string.Join(", ", runners.Select(r => $"'{r.name}' in {r.gameObject.scene.name}"))); + + var runner = runners[0]; + Assert.IsNotNull(runner.YarnProject, + $"'{runner.name}' in scene '{runner.gameObject.scene.name}' has no Yarn Project. " + + "It auto-starts, so this is the 'no Yarn Project has been configured' error."); + Assert.IsNotEmpty(runner.YarnProject.NodeNames, "The Yarn Project compiled no nodes"); + } + [Test] public void EveryNpc_ResolvedItsDialogueRunner() {