Files
nightclub-arcadia/NightclubArcadia/Assets/Editor/YarnDemoSetup.cs
T
lennartandClaude Opus 5 4f48d258b5 disable the pre-split scene builders instead of retargeting them
Fixes the "no Yarn Project has been configured" error coming back after running
the setup menus.

Last commit fixed the wrong layer. Retargeting YarnDemoSetup at a sandbox
stopped it destroying the level, but left the deeper problem: all of these
builders assume the single-scene layout, and after the split there is no target
path that makes them correct.

Two failures, both observed rather than reasoned about. Running the Yarn setup
left a generated scene open whose DialogueRunner had no project and auto-started
— that is the error the user kept seeing, coming from Dev/YarnSandbox.unity, not
from Systems. And retargeting the other three at Systems made PlayerControlSetup
pull navigation in with it; the baked NavMeshData is embedded rather than an
asset, so Systems.unity silently turned binary, 61KB text to 109KB binary. That
is trap 1 recurring on a scene that had just been fixed.

So the three scene builders now return early through LegacySceneSetup.Blocked,
with a message saying what they would have done and what to do instead. They are
not deleted: UILayerSetup alone is 818 lines that still record how the UI layer
is wired, and that record matters until prefabs replace it in Phase 5.

Set Up Skill System keeps its useful half. It regenerates the SkillDefinition
assets from JSON, which touches no scene; only the WireWorkingLevelScene call is
dropped, because those objects already exist in Systems.unity. Set Up Candidate
System was always asset-only and is untouched.

While diagnosing, YarnDemoSetup's own bug was found and fixed even though the
menu is now blocked: it set yarnProject through a SerializedObject on a prefab
instance without recording the override, so the assignment was dropped on save.
It now records the modification and refuses to save a scene whose runner has no
project.

Verified by running all five menus headlessly: the two asset generators run and
produce no diff, the three builders refuse, and no scene or asset changes.
Systems.unity restored to text, the level scene intact at 5 roots.

EditMode 42/42, PlayMode 6/6, YarnCheck 9 files / 35 nodes.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 21:24:24 +02:00

121 lines
4.9 KiB
C#

using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.EventSystems;
using Yarn.Compiler;
using Yarn.Unity;
using Yarn.Unity.Editor;
public static class YarnDemoSetup
{
const string YarnProjectPath = "Assets/Dialogue/NightclubArcadia.yarnproject";
const string ScenePath = NightclubArcadia.EditorTools.ScenePaths.Sandbox;
[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
// 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.");
}
if (!AssetDatabase.IsValidFolder("Assets/Dialogue"))
{
AssetDatabase.CreateFolder("Assets", "Dialogue");
}
if (!AssetDatabase.IsValidFolder("Assets/Scenes"))
{
AssetDatabase.CreateFolder("Assets", "Scenes");
}
var yarnProject = AssetDatabase.LoadAssetAtPath<YarnProject>(YarnProjectPath);
if (yarnProject == null)
{
// YarnProjectUtility.CreateDefaultYarnProject is internal, so
// construct the same default project here.
var project = new Project
{
ExcludeFilePatterns = new[] { "**/*~/*", "./Samples/Yarn Spinner*/*" },
};
YarnEditorUtility.CreateYarnProject(YarnProjectPath, project);
AssetDatabase.Refresh();
yarnProject = AssetDatabase.LoadAssetAtPath<YarnProject>(YarnProjectPath);
}
var scene = EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects, NewSceneMode.Single);
var runner = CreateDialogueRunnerMenuItem.CreateDialogueRunner();
var so = new SerializedObject(runner);
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<EventSystem>(FindObjectsInactive.Include);
#else
var eventSystems = Object.FindObjectsOfType<EventSystem>(true);
#endif
foreach (var eventSystem in eventSystems)
{
if (eventSystem.GetComponent<BaseInputModule>() != null)
{
continue;
}
#if ENABLE_INPUT_SYSTEM
eventSystem.gameObject.AddComponent<UnityEngine.InputSystem.UI.InputSystemUIInputModule>();
#endif
}
EditorSceneManager.SaveScene(scene, ScenePath);
AssetDatabase.SaveAssets();
Debug.Log($"Yarn dialogue test setup complete. Scene saved to {ScenePath}");
}
}