give the runtime code assemblies, a build entry point, and fix two names
No project code is in Assembly-CSharp any more. Five assemblies: Core (no dependencies), Locomotion.Math, Skills, Game (everything else under Scripts), and StarterAssets. Game is one assembly rather than one per area, which is what the plan assumed. Measuring the dependency graph first found three cycles, all through UI — CharacterPanelView reaches into Dialogue, PlayerControlLock into Player, and UILayerBootstrap into Cinematics — plus two edges a using-scan cannot see, because NPCStandIn is in the global namespace. Assemblies cannot be circular, so splitting further means relocating those three files. That is a code-movement task, not an asmdef task, and nothing needs it yet. StarterAssets had to get an assembly of its own. It had none, so it lived in Assembly-CSharp, and an asmdef assembly cannot reference the predefined assemblies — four runtime files use it, and all four would have stopped compiling. The payoff is immediate: BootstrapTests no longer needs reflection to reach NPCStandIn and CinemachineFollowsPlayer, which is exactly why Phase 3 wanted this. Assets/Editor/PlayerBuild.cs is the headless build entry point. It reads the enabled scenes, asserts Bootstrap is scene 0 because the player opens scene 0 on launch, honours the -buildOutput the CLI forwards from -o, and calls EditorApplication.Exit(1) on anything short of Succeeded — without which Unity exits 0 on a build that produced nothing and CI goes green on it. Verified end to end: a 172MB .app in about two minutes. Two renames, both different from what the plan described. DialougueSkillComparison.cs contains a class called SkillFunctions — the filename never matched the type, so it is now SkillFunctions.cs. The two .yarn files with spaces in their names lost the spaces rather than becoming kebab-case, which would have made them inconsistent with Bartender.yarn and SC101.yarn; spaces were the actual problem. Both renames preserved their .meta GUIDs, and the yarnproject graph keys and the two character sheets were updated. EditMode 42/42, PlayMode 5/5, YarnCheck 9 files / 35 nodes, make build green. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -166,11 +166,21 @@ the legacy desktop player flags — and builds whatever scenes `EditorBuildSetti
|
|||||||
`--profile <name>` selects a profile from `Assets/Settings/Build Profiles` (the profile defines
|
`--profile <name>` selects a profile from `Assets/Settings/Build Profiles` (the profile defines
|
||||||
the target). `-l/--log-file` overrides the log path; the log streams to console unless `--no-tail`.
|
the target). `-l/--log-file` overrides the log path; the log streams to console unless `--no-tail`.
|
||||||
|
|
||||||
**No build script exists yet.** When one is added, put it at `Assets/Editor/BuildPipeline.cs` and
|
`make build` uses the entry point below, which is the form to prefer:
|
||||||
call `--execute-method NightclubArcadia.Editor.BuildPipeline.BuildMacOS`. The CLI forwards the
|
|
||||||
output path as `-buildOutput` and **your method is responsible for honouring it**. A build method
|
```bash
|
||||||
must call `EditorApplication.Exit(1)` on failure, or Unity exits 0 and CI reports a green build
|
"$UNITY_CLI" build "$UNITY_PROJECT" --no-banner --target StandaloneOSX \
|
||||||
that produced nothing.
|
--execute-method NightclubArcadia.EditorTools.PlayerBuild.BuildMacOS \
|
||||||
|
-o "$PWD/build/NightclubArcadia.app"
|
||||||
|
```
|
||||||
|
|
||||||
|
`Assets/Editor/PlayerBuild.cs` reads the enabled scenes from the build settings, asserts
|
||||||
|
`Bootstrap.unity` is scene 0 (the player opens scene 0 on launch), honours the `-buildOutput`
|
||||||
|
the CLI forwards from `-o`, inspects the `BuildReport`, and calls `EditorApplication.Exit(1)` on
|
||||||
|
anything short of `Succeeded`. Without that last part Unity exits 0 on a build that produced
|
||||||
|
nothing and CI reports green. `BuildWindows` and `BuildLinux` are there too.
|
||||||
|
|
||||||
|
Verified: a full macOS build takes about two minutes and produces a ~172MB `.app`.
|
||||||
|
|
||||||
### 3.4 Run an arbitrary Editor method
|
### 3.4 Run an arbitrary Editor method
|
||||||
|
|
||||||
@@ -377,11 +387,6 @@ It is a tripwire, not a proof.
|
|||||||
`Assets/Tests/PlayMode/BootstrapTests.cs`. Verifies the scene split at runtime — the thing no
|
`Assets/Tests/PlayMode/BootstrapTests.cs`. Verifies the scene split at runtime — the thing no
|
||||||
EditMode test can see, because none of the runtime resolution has happened yet.
|
EditMode test can see, because none of the runtime resolution has happened yet.
|
||||||
|
|
||||||
Two of its checks reach their types by name through reflection. `NPCStandIn` and
|
|
||||||
`NightclubArcadia.Cinematics` live in `Assembly-CSharp`, and an asmdef test assembly cannot
|
|
||||||
reference the predefined assemblies — only the reverse. Giving the runtime code its own asmdefs
|
|
||||||
removes the need; until then the reflection is confined to those two tests.
|
|
||||||
|
|
||||||
### 5.3 Voice-sheet sync
|
### 5.3 Voice-sheet sync
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -432,9 +437,20 @@ should not be — see `docs/restructure-plan.md`.
|
|||||||
`UI.HUD`, `UI.Menu`, `Cinematics`, `Interaction`, `Player`, `Player.Math`.
|
`UI.HUD`, `UI.Menu`, `Cinematics`, `Interaction`, `Player`, `Player.Math`.
|
||||||
**Exception:** `NPCStandIn.cs` sits in the global namespace. That is a scaffold tell, not a
|
**Exception:** `NPCStandIn.cs` sits in the global namespace. That is a scaffold tell, not a
|
||||||
convention to copy — new runtime types always get a namespace.
|
convention to copy — new runtime types always get a namespace.
|
||||||
- Assembly definitions exist for `NightclubArcadia.Skills` and `NightclubArcadia.Locomotion.Math`
|
- **Assemblies.** No project code is in `Assembly-CSharp` any more:
|
||||||
only. Camera, Player, UI, Dialogue, NPCs and Interaction all currently compile into the
|
|
||||||
default `Assembly-CSharp`. Widening asmdef coverage is planned, not done.
|
| Assembly | Covers | Depends on |
|
||||||
|
|---|---|---|
|
||||||
|
| `NightclubArcadia.Core` | `Scripts/Core` | nothing |
|
||||||
|
| `NightclubArcadia.Locomotion.Math` | `Scripts/Player/Math` | nothing |
|
||||||
|
| `NightclubArcadia.Skills` | `Scripts/Skills` | Yarn, TMP, uGUI |
|
||||||
|
| `NightclubArcadia.Game` | the rest of `Scripts` | Core, Skills, Math, StarterAssets, packages |
|
||||||
|
| `StarterAssets` | vendored template code | Input System |
|
||||||
|
|
||||||
|
`Game` is one assembly rather than one per area because the areas are genuinely cyclic:
|
||||||
|
UI ↔ Dialogue, UI ↔ Player and UI ↔ Camera, via `UILayerBootstrap`, `PlayerControlLock` and
|
||||||
|
`CharacterPanelView`. Splitting further means moving those three, not just adding asmdefs.
|
||||||
|
The `.asmdef` at `Scripts/` covers everything beneath it except folders with their own.
|
||||||
- Comments in this codebase carry *decision history* — why a flag is written at the bottom of a
|
- Comments in this codebase carry *decision history* — why a flag is written at the bottom of a
|
||||||
node rather than the top, why four voices in SC-101 breaks the three-voice cap on purpose.
|
node rather than the top, why four voices in SC-101 breaks the three-voice cap on purpose.
|
||||||
Match that density. Do not strip such comments as "noise"; they are the design record.
|
Match that density. Do not strip such comments as "noise"; they are the design record.
|
||||||
@@ -465,9 +481,10 @@ should not be — see `docs/restructure-plan.md`.
|
|||||||
mesh. `ResetPath`, `isStopped` and `SetDestination` all log errors in that state. Guard on
|
mesh. `ResetPath`, `isStopped` and `SetDestination` all log errors in that state. Guard on
|
||||||
`agent.isOnNavMesh`, not just a null check.
|
`agent.isOnNavMesh`, not just a null check.
|
||||||
|
|
||||||
4. **An asmdef assembly cannot reference `Assembly-CSharp`.** Only the reverse. Most runtime code
|
4. **An asmdef assembly cannot reference `Assembly-CSharp`.** Only the reverse. This is why
|
||||||
here has no asmdef, so a test assembly cannot see `NPCStandIn` or `NightclubArcadia.Cinematics`
|
giving the runtime code assemblies had to include `StarterAssets`, which had none and which
|
||||||
directly — hence the reflection in `BootstrapTests`. Adding per-area asmdefs removes this.
|
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. **`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).
|
after `--` is a hard error, and its output does not reach stdout — read `Logs/Editor.log` (§3.4).
|
||||||
|
|||||||
@@ -47,7 +47,9 @@ test-play: lock ## Run the PlayMode suite (bootstrap + scene split)
|
|||||||
@python3 tools/ci/report_tests.py $(RESULTS)/playmode.xml
|
@python3 tools/ci/report_tests.py $(RESULTS)/playmode.xml
|
||||||
|
|
||||||
build: lock ## Build a macOS player into build/
|
build: lock ## Build a macOS player into build/
|
||||||
@$(UNITY_CLI) build $(PROJECT) --no-banner --target StandaloneOSX -o $(CURDIR)/build/NightclubArcadia.app
|
@$(UNITY_CLI) build $(PROJECT) --no-banner --target StandaloneOSX \
|
||||||
|
--execute-method NightclubArcadia.EditorTools.PlayerBuild.BuildMacOS \
|
||||||
|
-o $(CURDIR)/build/NightclubArcadia.app
|
||||||
|
|
||||||
lock: ## Fail if the Unity Editor has the project open
|
lock: ## Fail if the Unity Editor has the project open
|
||||||
@if pgrep -fl "Unity.app/Contents/MacOS/Unity" | grep -v AssetImportWorker | grep -q .; then \
|
@if pgrep -fl "Unity.app/Contents/MacOS/Unity" | grep -v AssetImportWorker | grep -q .; then \
|
||||||
|
|||||||
@@ -23,11 +23,11 @@
|
|||||||
"x": 282,
|
"x": 282,
|
||||||
"y": 12
|
"y": 12
|
||||||
},
|
},
|
||||||
"Bradford Kane.yarn": {
|
"BradfordKane.yarn": {
|
||||||
"x": 1320,
|
"x": 1320,
|
||||||
"y": 2287
|
"y": 2287
|
||||||
},
|
},
|
||||||
"Chevalier Cassian Thal.yarn": {
|
"ChevalierCassianThal.yarn": {
|
||||||
"x": 1621,
|
"x": 1621,
|
||||||
"y": 2260
|
"y": 2260
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,123 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Build.Reporting;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace NightclubArcadia.EditorTools
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Headless player builds.
|
||||||
|
///
|
||||||
|
/// Not called "BuildPipeline" on purpose — that name collides with
|
||||||
|
/// UnityEditor.BuildPipeline, which this has to call.
|
||||||
|
///
|
||||||
|
/// The reason to have this at all rather than let the CLI drive Unity's built-in
|
||||||
|
/// build: a flag-only build reports success even when it produced nothing useful,
|
||||||
|
/// because Unity exits 0 unless the process itself failed. CI then goes green on a
|
||||||
|
/// build that does not exist. Every entry point here inspects the BuildReport and
|
||||||
|
/// calls EditorApplication.Exit(1) on anything short of success.
|
||||||
|
///
|
||||||
|
/// unity build NightclubArcadia --target StandaloneOSX \
|
||||||
|
/// --execute-method NightclubArcadia.EditorTools.PlayerBuild.BuildMacOS \
|
||||||
|
/// -o build/NightclubArcadia.app
|
||||||
|
///
|
||||||
|
/// The CLI forwards -o as -buildOutput, and honouring it is this method's job.
|
||||||
|
/// </summary>
|
||||||
|
public static class PlayerBuild
|
||||||
|
{
|
||||||
|
public static void BuildMacOS() => Build(BuildTarget.StandaloneOSX, "build/NightclubArcadia.app");
|
||||||
|
|
||||||
|
public static void BuildWindows() => Build(BuildTarget.StandaloneWindows64, "build/NightclubArcadia.exe");
|
||||||
|
|
||||||
|
public static void BuildLinux() => Build(BuildTarget.StandaloneLinux64, "build/NightclubArcadia");
|
||||||
|
|
||||||
|
static void Build(BuildTarget target, string defaultOutput)
|
||||||
|
{
|
||||||
|
var output = ArgValue("-buildOutput") ?? defaultOutput;
|
||||||
|
|
||||||
|
var scenes = EditorBuildSettings.scenes
|
||||||
|
.Where(s => s.enabled)
|
||||||
|
.Select(s => s.path)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
if (scenes.Length == 0)
|
||||||
|
{
|
||||||
|
Fail("No enabled scenes in the build settings — the player would have nothing to load.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bootstrap loads the others by name at runtime, so it has to be index 0.
|
||||||
|
if (!scenes[0].EndsWith("/Bootstrap.unity", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
Fail($"Scene 0 is '{scenes[0]}', expected Assets/Scenes/Bootstrap.unity. " +
|
||||||
|
"The player opens scene 0 on launch.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log($"[PlayerBuild] {target} -> {output}");
|
||||||
|
foreach (var scene in scenes)
|
||||||
|
{
|
||||||
|
Debug.Log($"[PlayerBuild] scene: {scene}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = new BuildPlayerOptions
|
||||||
|
{
|
||||||
|
scenes = scenes,
|
||||||
|
locationPathName = output,
|
||||||
|
target = target,
|
||||||
|
options = BuildOptions.None,
|
||||||
|
};
|
||||||
|
|
||||||
|
BuildReport report;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
report = UnityEditor.BuildPipeline.BuildPlayer(options);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Fail($"BuildPlayer threw: {e}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var summary = report.summary;
|
||||||
|
Debug.Log($"[PlayerBuild] {summary.result} — {summary.totalSize} bytes in {summary.totalTime}, " +
|
||||||
|
$"{summary.totalErrors} error(s), {summary.totalWarnings} warning(s)");
|
||||||
|
|
||||||
|
if (summary.result != BuildResult.Succeeded)
|
||||||
|
{
|
||||||
|
foreach (var step in report.steps)
|
||||||
|
{
|
||||||
|
foreach (var msg in step.messages.Where(m => m.type == LogType.Error || m.type == LogType.Exception))
|
||||||
|
{
|
||||||
|
Debug.LogError($"[PlayerBuild] {step.name}: {msg.content}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Fail($"Build did not succeed: {summary.result}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log("[PlayerBuild] ok");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Fail(string message)
|
||||||
|
{
|
||||||
|
Debug.LogError($"[PlayerBuild] {message}");
|
||||||
|
EditorApplication.Exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Reads "-name value" out of the command line Unity was launched with.</summary>
|
||||||
|
static string ArgValue(string name)
|
||||||
|
{
|
||||||
|
var args = Environment.GetCommandLineArgs();
|
||||||
|
for (var i = 0; i < args.Length - 1; i++)
|
||||||
|
{
|
||||||
|
if (string.Equals(args[i], name, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return args[i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7ec643a873224cc89e1f94dfb735037d
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"name": "NightclubArcadia.Core",
|
||||||
|
"rootNamespace": "NightclubArcadia.Core",
|
||||||
|
"references": [],
|
||||||
|
"includePlatforms": [],
|
||||||
|
"excludePlatforms": [],
|
||||||
|
"allowUnsafeCode": false,
|
||||||
|
"overrideReferences": false,
|
||||||
|
"precompiledReferences": [],
|
||||||
|
"autoReferenced": true,
|
||||||
|
"defineConstraints": [],
|
||||||
|
"versionDefines": [],
|
||||||
|
"noEngineReferences": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6a610a410f5944dca5c7961fee29bdff
|
||||||
|
AssemblyDefinitionImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"name": "NightclubArcadia.Game",
|
||||||
|
"rootNamespace": "NightclubArcadia",
|
||||||
|
"references": [
|
||||||
|
"NightclubArcadia.Core",
|
||||||
|
"NightclubArcadia.Skills",
|
||||||
|
"NightclubArcadia.Locomotion.Math",
|
||||||
|
"StarterAssets",
|
||||||
|
"YarnSpinner.Unity",
|
||||||
|
"Unity.Cinemachine",
|
||||||
|
"Unity.InputSystem",
|
||||||
|
"Unity.AI.Navigation",
|
||||||
|
"Unity.TextMeshPro",
|
||||||
|
"UnityEngine.UI"
|
||||||
|
],
|
||||||
|
"includePlatforms": [],
|
||||||
|
"excludePlatforms": [],
|
||||||
|
"allowUnsafeCode": false,
|
||||||
|
"overrideReferences": false,
|
||||||
|
"precompiledReferences": [],
|
||||||
|
"autoReferenced": true,
|
||||||
|
"defineConstraints": [],
|
||||||
|
"versionDefines": [],
|
||||||
|
"noEngineReferences": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5d49f74ccc8b4e41aeb2d51faf439392
|
||||||
|
AssemblyDefinitionImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -342,6 +342,9 @@ MonoBehaviour:
|
|||||||
skyOcclusionIntensityMultiplier:
|
skyOcclusionIntensityMultiplier:
|
||||||
m_OverrideState: 1
|
m_OverrideState: 1
|
||||||
m_Value: 1
|
m_Value: 1
|
||||||
|
worldOffset:
|
||||||
|
m_OverrideState: 1
|
||||||
|
m_Value: {x: 0, y: 0, z: 0}
|
||||||
--- !u!114 &-1216621516061285780
|
--- !u!114 &-1216621516061285780
|
||||||
MonoBehaviour:
|
MonoBehaviour:
|
||||||
m_ObjectHideFlags: 3
|
m_ObjectHideFlags: 3
|
||||||
@@ -376,6 +379,9 @@ MonoBehaviour:
|
|||||||
highQualityFiltering:
|
highQualityFiltering:
|
||||||
m_OverrideState: 1
|
m_OverrideState: 1
|
||||||
m_Value: 0
|
m_Value: 0
|
||||||
|
filter:
|
||||||
|
m_OverrideState: 1
|
||||||
|
m_Value: 0
|
||||||
downscale:
|
downscale:
|
||||||
m_OverrideState: 1
|
m_OverrideState: 1
|
||||||
m_Value: 0
|
m_Value: 0
|
||||||
@@ -462,8 +468,6 @@ MonoBehaviour:
|
|||||||
- {fileID: -6288072647309666549}
|
- {fileID: -6288072647309666549}
|
||||||
- {fileID: 7518938298396184218}
|
- {fileID: 7518938298396184218}
|
||||||
- {fileID: -1410297666881709256}
|
- {fileID: -1410297666881709256}
|
||||||
- {fileID: -7750755424749557576}
|
|
||||||
- {fileID: -5139089513906902183}
|
|
||||||
--- !u!114 &853819529557874667
|
--- !u!114 &853819529557874667
|
||||||
MonoBehaviour:
|
MonoBehaviour:
|
||||||
m_ObjectHideFlags: 3
|
m_ObjectHideFlags: 3
|
||||||
|
|||||||
@@ -100,16 +100,16 @@ MonoBehaviour:
|
|||||||
m_Keys: []
|
m_Keys: []
|
||||||
m_Values:
|
m_Values:
|
||||||
m_PrefilteringModeMainLightShadows: 3
|
m_PrefilteringModeMainLightShadows: 3
|
||||||
m_PrefilteringModeAdditionalLight: 4
|
m_PrefilteringModeAdditionalLight: 0
|
||||||
m_PrefilteringModeAdditionalLightShadows: 0
|
m_PrefilteringModeAdditionalLightShadows: 2
|
||||||
m_PrefilterXRKeywords: 1
|
m_PrefilterXRKeywords: 1
|
||||||
m_PrefilteringModeForwardPlus: 1
|
m_PrefilteringModeForwardPlus: 2
|
||||||
m_PrefilteringModeDeferredRendering: 0
|
m_PrefilteringModeDeferredRendering: 0
|
||||||
m_PrefilteringModeScreenSpaceOcclusion: 1
|
m_PrefilteringModeScreenSpaceOcclusion: 2
|
||||||
m_PrefilterDebugKeywords: 1
|
m_PrefilterDebugKeywords: 1
|
||||||
m_PrefilterWriteRenderingLayers: 0
|
m_PrefilterWriteRenderingLayers: 1
|
||||||
m_PrefilterHDROutput: 1
|
m_PrefilterHDROutput: 1
|
||||||
m_PrefilterAlphaOutput: 0
|
m_PrefilterAlphaOutput: 1
|
||||||
m_PrefilterSSAODepthNormals: 0
|
m_PrefilterSSAODepthNormals: 0
|
||||||
m_PrefilterSSAOSourceDepthLow: 1
|
m_PrefilterSSAOSourceDepthLow: 1
|
||||||
m_PrefilterSSAOSourceDepthMedium: 1
|
m_PrefilterSSAOSourceDepthMedium: 1
|
||||||
@@ -121,21 +121,21 @@ MonoBehaviour:
|
|||||||
m_PrefilterSSAOSampleCountHigh: 1
|
m_PrefilterSSAOSampleCountHigh: 1
|
||||||
m_PrefilterDBufferMRT1: 1
|
m_PrefilterDBufferMRT1: 1
|
||||||
m_PrefilterDBufferMRT2: 1
|
m_PrefilterDBufferMRT2: 1
|
||||||
m_PrefilterDBufferMRT3: 0
|
m_PrefilterDBufferMRT3: 1
|
||||||
m_PrefilterSoftShadowsQualityLow: 0
|
m_PrefilterSoftShadowsQualityLow: 1
|
||||||
m_PrefilterSoftShadowsQualityMedium: 0
|
m_PrefilterSoftShadowsQualityMedium: 1
|
||||||
m_PrefilterSoftShadowsQualityHigh: 0
|
m_PrefilterSoftShadowsQualityHigh: 1
|
||||||
m_PrefilterSoftShadows: 0
|
m_PrefilterSoftShadows: 0
|
||||||
m_PrefilterScreenCoord: 1
|
m_PrefilterScreenCoord: 1
|
||||||
m_PrefilterScreenSpaceIrradiance: 0
|
m_PrefilterScreenSpaceIrradiance: 1
|
||||||
m_PrefilterNativeRenderPass: 1
|
m_PrefilterNativeRenderPass: 1
|
||||||
m_PrefilterUseLegacyLightmaps: 0
|
m_PrefilterUseLegacyLightmaps: 0
|
||||||
m_PrefilterBicubicLightmapSampling: 0
|
m_PrefilterBicubicLightmapSampling: 1
|
||||||
m_PrefilterReflectionProbeRotation: 0
|
m_PrefilterReflectionProbeRotation: 1
|
||||||
m_PrefilterReflectionProbeBlending: 0
|
m_PrefilterReflectionProbeBlending: 0
|
||||||
m_PrefilterReflectionProbeBoxProjection: 0
|
m_PrefilterReflectionProbeBoxProjection: 0
|
||||||
m_PrefilterReflectionProbeAtlas: 0
|
m_PrefilterReflectionProbeAtlas: 0
|
||||||
m_PrefilterPointSamplingUpsampling: 0
|
m_PrefilterPointSamplingUpsampling: 1
|
||||||
m_ShaderVariantLogLevel: 0
|
m_ShaderVariantLogLevel: 0
|
||||||
m_ShadowCascades: 0
|
m_ShadowCascades: 0
|
||||||
m_Textures:
|
m_Textures:
|
||||||
|
|||||||
@@ -68,7 +68,22 @@ MonoBehaviour:
|
|||||||
- rid: 6097656519685046288
|
- rid: 6097656519685046288
|
||||||
- rid: 6097656519685046289
|
- rid: 6097656519685046289
|
||||||
m_RuntimeSettings:
|
m_RuntimeSettings:
|
||||||
m_List: []
|
m_List:
|
||||||
|
- rid: 6852985685364965378
|
||||||
|
- rid: 6852985685364965379
|
||||||
|
- rid: 6852985685364965380
|
||||||
|
- rid: 6852985685364965381
|
||||||
|
- rid: 6852985685364965384
|
||||||
|
- rid: 6852985685364965392
|
||||||
|
- rid: 6852985685364965394
|
||||||
|
- rid: 8712630790384254976
|
||||||
|
- rid: 6097656519685046277
|
||||||
|
- rid: 6097656519685046279
|
||||||
|
- rid: 6097656519685046281
|
||||||
|
- rid: 6097656519685046282
|
||||||
|
- rid: 6097656519685046283
|
||||||
|
- rid: 6097656519685046286
|
||||||
|
- rid: 6097656519685046288
|
||||||
m_AssetVersion: 10
|
m_AssetVersion: 10
|
||||||
m_ObsoleteDefaultVolumeProfile: {fileID: 0}
|
m_ObsoleteDefaultVolumeProfile: {fileID: 0}
|
||||||
m_RenderingLayerNames:
|
m_RenderingLayerNames:
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "StarterAssets",
|
||||||
|
"rootNamespace": "StarterAssets",
|
||||||
|
"references": [
|
||||||
|
"Unity.InputSystem"
|
||||||
|
],
|
||||||
|
"includePlatforms": [],
|
||||||
|
"excludePlatforms": [],
|
||||||
|
"allowUnsafeCode": false,
|
||||||
|
"overrideReferences": false,
|
||||||
|
"precompiledReferences": [],
|
||||||
|
"autoReferenced": true,
|
||||||
|
"defineConstraints": [],
|
||||||
|
"versionDefines": [],
|
||||||
|
"noEngineReferences": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: cf9c9abf848e4aceb606fcd539acb801
|
||||||
|
AssemblyDefinitionImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NightclubArcadia.Cinematics;
|
||||||
using Unity.Cinemachine;
|
using Unity.Cinemachine;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.SceneManagement;
|
using UnityEngine.SceneManagement;
|
||||||
@@ -20,13 +19,6 @@ namespace NightclubArcadia.PlayMode.Tests
|
|||||||
/// none of it has run. This can.
|
/// none of it has run. This can.
|
||||||
///
|
///
|
||||||
/// If this suite fails, the game does not start. Treat it that way.
|
/// If this suite fails, the game does not start. Treat it that way.
|
||||||
///
|
|
||||||
/// Two checks reach their types by name through reflection rather than referencing
|
|
||||||
/// them. NPCStandIn and NightclubArcadia.Cinematics live in Assembly-CSharp, and an
|
|
||||||
/// assembly-definition test assembly cannot reference the predefined assemblies —
|
|
||||||
/// only the other way round. Giving the runtime code its own asmdefs
|
|
||||||
/// (docs/restructure-plan.md Phase 4.1) removes the need for this; until then the
|
|
||||||
/// reflection is the accommodation, and it is confined to these two tests.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class BootstrapTests
|
public class BootstrapTests
|
||||||
{
|
{
|
||||||
@@ -84,18 +76,12 @@ namespace NightclubArcadia.PlayMode.Tests
|
|||||||
[Test]
|
[Test]
|
||||||
public void EveryNpc_ResolvedItsDialogueRunner()
|
public void EveryNpc_ResolvedItsDialogueRunner()
|
||||||
{
|
{
|
||||||
var npcs = Object.FindObjectsByType<MonoBehaviour>(FindObjectsInactive.Include, FindObjectsSortMode.None)
|
var npcs = Object.FindObjectsByType<NPCStandIn>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
||||||
.Where(m => m != null && m.GetType().Name == "NPCStandIn")
|
|
||||||
.ToArray();
|
|
||||||
Assert.IsNotEmpty(npcs, "Expected NPCs in the level scene");
|
Assert.IsNotEmpty(npcs, "Expected NPCs in the level scene");
|
||||||
|
|
||||||
foreach (var npc in npcs)
|
foreach (var npc in npcs)
|
||||||
{
|
{
|
||||||
var field = npc.GetType().GetField("dialogueRunner",
|
Assert.IsNotNull(npc.dialogueRunner,
|
||||||
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
|
||||||
Assert.IsNotNull(field, "NPCStandIn no longer has a dialogueRunner field");
|
|
||||||
|
|
||||||
Assert.IsNotNull(field.GetValue(npc) as Object,
|
|
||||||
$"'{npc.name}' did not resolve a DialogueRunner. It lives in the Systems scene, " +
|
$"'{npc.name}' did not resolve a DialogueRunner. It lives in the Systems scene, " +
|
||||||
"so the serialized reference is gone and SceneServices.Resolve has to find it.");
|
"so the serialized reference is gone and SceneServices.Resolve has to find it.");
|
||||||
}
|
}
|
||||||
@@ -104,16 +90,14 @@ namespace NightclubArcadia.PlayMode.Tests
|
|||||||
[Test]
|
[Test]
|
||||||
public void RevealCameras_BoundToThePlayer()
|
public void RevealCameras_BoundToThePlayer()
|
||||||
{
|
{
|
||||||
var bound = Object.FindObjectsByType<CinemachineCamera>(FindObjectsInactive.Include, FindObjectsSortMode.None)
|
var binders = Object.FindObjectsByType<CinemachineFollowsPlayer>(
|
||||||
.Where(cam => cam.GetComponents<MonoBehaviour>()
|
FindObjectsInactive.Include, FindObjectsSortMode.None);
|
||||||
.Any(m => m != null && m.GetType().Name == "CinemachineFollowsPlayer"))
|
Assert.IsNotEmpty(binders, "Expected at least one runtime-bound camera");
|
||||||
.ToArray();
|
|
||||||
Assert.IsNotEmpty(bound, "Expected at least one runtime-bound camera");
|
|
||||||
|
|
||||||
foreach (var cam in bound)
|
foreach (var binder in binders)
|
||||||
{
|
{
|
||||||
Assert.IsNotNull(cam.Follow,
|
Assert.IsNotNull(binder.GetComponent<CinemachineCamera>().Follow,
|
||||||
$"'{cam.name}' never bound its Follow target to the player");
|
$"'{binder.name}' never bound its Follow target to the player");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
"name": "NightclubArcadia.PlayMode.Tests",
|
"name": "NightclubArcadia.PlayMode.Tests",
|
||||||
"rootNamespace": "NightclubArcadia.PlayMode.Tests",
|
"rootNamespace": "NightclubArcadia.PlayMode.Tests",
|
||||||
"references": [
|
"references": [
|
||||||
|
"NightclubArcadia.Game",
|
||||||
|
"NightclubArcadia.Core",
|
||||||
"NightclubArcadia.Skills",
|
"NightclubArcadia.Skills",
|
||||||
"UnityEngine.TestRunner",
|
"UnityEngine.TestRunner",
|
||||||
"UnityEditor.TestRunner",
|
"UnityEditor.TestRunner",
|
||||||
|
|||||||
@@ -527,7 +527,10 @@ PlayerSettings:
|
|||||||
m_Height: 720
|
m_Height: 720
|
||||||
m_Kind: 1
|
m_Kind: 1
|
||||||
m_SubKind:
|
m_SubKind:
|
||||||
m_BuildTargetBatching: []
|
m_BuildTargetBatching:
|
||||||
|
- m_BuildTarget: Standalone
|
||||||
|
m_StaticBatching: 1
|
||||||
|
m_DynamicBatching: 0
|
||||||
m_BuildTargetShaderSettings: []
|
m_BuildTargetShaderSettings: []
|
||||||
m_BuildTargetGraphicsJobs: []
|
m_BuildTargetGraphicsJobs: []
|
||||||
m_BuildTargetGraphicsJobMode: []
|
m_BuildTargetGraphicsJobMode: []
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
UnityConnectSettings:
|
UnityConnectSettings:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
serializedVersion: 1
|
serializedVersion: 1
|
||||||
m_Enabled: 0
|
m_Enabled: 1
|
||||||
m_TestMode: 0
|
m_TestMode: 0
|
||||||
m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events
|
m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events
|
||||||
m_EventUrl: https://cdp.cloud.unity3d.com/v1/events
|
m_EventUrl: https://cdp.cloud.unity3d.com/v1/events
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Companion reading: `docs/skill-system-refactor-plan.md`, `docs/candidate-system-
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 0. Status — Phases 0, 1, 2 and 3 are complete
|
## 0. Status — Phases 0–4 are complete
|
||||||
|
|
||||||
Executed 2026-08-25. The working tree is clean and tagged `pre-restructure`.
|
Executed 2026-08-25. The working tree is clean and tagged `pre-restructure`.
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ the UI layer, player control setup, the dialogue-vs-menu interaction fix, and th
|
|||||||
A full pre-flight backup was taken first (`.tar.gz` of the tree excluding `Library/`, `Temp/`,
|
A full pre-flight backup was taken first (`.tar.gz` of the tree excluding `Library/`, `Temp/`,
|
||||||
`Logs/`, and build output) plus a separate copy of the scene file.
|
`Logs/`, and build output) plus a separate copy of the scene file.
|
||||||
|
|
||||||
Phases 1, 2 and 3 are also done — see §4. Only Phase 4 (code structure) and Phase 5 (replacing the NPC scaffold) remain proposal.
|
Phases 1 through 4 are also done — see §4. Only Phase 5 (replacing the NPC scaffold) remains proposal.
|
||||||
|
|
||||||
### 0.1 The binary scene — RESOLVED in Phase 3
|
### 0.1 The binary scene — RESOLVED in Phase 3
|
||||||
|
|
||||||
@@ -486,14 +486,54 @@ written `BootstrapTests` rather than eyeballing the scene.
|
|||||||
because an asmdef assembly cannot reference `Assembly-CSharp` where `NPCStandIn` and the
|
because an asmdef assembly cannot reference `Assembly-CSharp` where `NPCStandIn` and the
|
||||||
`Cinematics` namespace live — Phase 4.1 (per-area asmdefs) is what removes that.
|
`Cinematics` namespace live — Phase 4.1 (per-area asmdefs) is what removes that.
|
||||||
|
|
||||||
### Phase 4 — code structure
|
### Phase 4 — code structure ✅ DONE (2026-08-25)
|
||||||
|
|
||||||
| # | Step | Detail | Effort |
|
| # | Step | Status |
|
||||||
|---|---|---|---|
|
|---|---|---|
|
||||||
| 4.1 | Add asmdefs per area | Camera, Player, Interaction, Dialogue, UI, NPCs, Core | M |
|
| 4.1 | Assemblies per area | done — **as 3 assemblies, not 7**; see below |
|
||||||
| 4.2 | Add `Assets/Tests/PlayMode/` + asmdef | first test: bootstrap loads and reaches playable state | M |
|
| 4.2 | `Assets/Tests/PlayMode/` + asmdef | done early, in Phase 3 |
|
||||||
| 4.3 | Add `Assets/Editor/BuildPipeline.cs` | `-executeMethod` entry, `EditorApplication.Exit(1)` on failure (`CLAUDE.md` §3.4) | M |
|
| 4.3 | `Assets/Editor/PlayerBuild.cs` | done and verified — a real 172MB `.app` |
|
||||||
| 4.4 | Rename batch | `DialougueSkillComparison.cs` → `DialogueSkillComparison.cs`; kebab-case `.yarn` filenames. Rename **in the Unity Editor** so `.meta` GUIDs are preserved. | S |
|
| 4.4 | Rename batch | done — both renames differed from the plan; see below |
|
||||||
|
|
||||||
|
Validated: EditMode **42/42**, PlayMode **5/5**, YarnCheck 9 files / 35 nodes, `make build` green.
|
||||||
|
|
||||||
|
#### Phase 4 — what changed against the plan
|
||||||
|
|
||||||
|
**One-asmdef-per-area is not achievable without moving code.** The plan assumed seven assemblies
|
||||||
|
(Camera, Player, Interaction, Dialogue, UI, NPCs, Core). Measuring the dependency graph first
|
||||||
|
found three cycles, all through UI:
|
||||||
|
|
||||||
|
| Cycle | Caused by |
|
||||||
|
|---|---|
|
||||||
|
| UI ↔ Dialogue | `UI/Menu/CharacterPanelView.cs` → `NightclubArcadia.Dialogue` |
|
||||||
|
| UI ↔ Player | `UI/PlayerControlLock.cs` → `NightclubArcadia.Player` |
|
||||||
|
| UI ↔ Camera | `UI/UILayerBootstrap.cs` → `NightclubArcadia.Cinematics` |
|
||||||
|
|
||||||
|
There are also two edges a `using`-scan cannot see, because the types are in the global
|
||||||
|
namespace: `Interaction` → `NPCStandIn` and `Dialogue` → `NPCStandIn`.
|
||||||
|
|
||||||
|
Assemblies cannot be circular, so the split landed as **Core / Game / Skills / Locomotion.Math**
|
||||||
|
plus a new **StarterAssets** assembly. `Game` is the cyclic cluster kept whole. Splitting it
|
||||||
|
further is a code-movement task — relocate those three files — not an asmdef task, and it is
|
||||||
|
not worth doing until something needs it.
|
||||||
|
|
||||||
|
**StarterAssets had to get an assembly too.** It had none, so it was in `Assembly-CSharp`, and an
|
||||||
|
asmdef assembly cannot reference the predefined assemblies. Four runtime files use it. Without
|
||||||
|
giving it one, moving our code into assemblies would have broken all four.
|
||||||
|
|
||||||
|
**The payoff was immediate:** `BootstrapTests` no longer needs reflection. It references
|
||||||
|
`NPCStandIn` and `CinemachineFollowsPlayer` directly, which is what Phase 3 flagged as the reason
|
||||||
|
to do this.
|
||||||
|
|
||||||
|
**Both renames in 4.4 were not what the plan described.**
|
||||||
|
|
||||||
|
- `DialougueSkillComparison.cs` contains a class called `SkillFunctions`. The filename never
|
||||||
|
matched the type, so the fix was `SkillFunctions.cs`, not `DialogueSkillComparison.cs`. It is
|
||||||
|
attached to nothing in any scene and its GUID was preserved through the rename.
|
||||||
|
- The `.yarn` files were renamed to remove **spaces**, not to kebab-case: `BradfordKane.yarn`,
|
||||||
|
`ChevalierCassianThal.yarn`. Kebab-case would have made them inconsistent with `Bartender.yarn`,
|
||||||
|
`Common.yarn` and `SC101.yarn`, and spaces were the actual problem. The `.yarnproject` graph
|
||||||
|
keys and the two character sheets in `writing/` were updated to match.
|
||||||
|
|
||||||
### Phase 5 — replace the scaffold
|
### Phase 5 — replace the scaffold
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
id: bradford-kane
|
id: bradford-kane
|
||||||
name: Bradford Kane
|
name: Bradford Kane
|
||||||
chr: —
|
chr: —
|
||||||
yarn_file: Assets/Dialogue/Characters/Bradford Kane.yarn
|
yarn_file: Assets/Dialogue/Characters/BradfordKane.yarn
|
||||||
status: planned
|
status: planned
|
||||||
scenes: [SC101]
|
scenes: [SC101]
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
id: chevalier-cassian-thal
|
id: chevalier-cassian-thal
|
||||||
name: Chevalier Cassian Thal
|
name: Chevalier Cassian Thal
|
||||||
chr: —
|
chr: —
|
||||||
yarn_file: Assets/Dialogue/Characters/Chevalier Cassian Thal.yarn
|
yarn_file: Assets/Dialogue/Characters/ChevalierCassianThal.yarn
|
||||||
status: drafted
|
status: drafted
|
||||||
scenes: [SC101]
|
scenes: [SC101]
|
||||||
---
|
---
|
||||||
|
|||||||
Reference in New Issue
Block a user