15 Commits
Author SHA1 Message Date
lennartandClaude Opus 5 9a0618fd31 replace the NPC scaffold with data-driven prefabs, and retire the builders
NPCStandIn was written to be dropped on a sphere and carried its identity in
per-instance public fields. The cost of that showed up in the scene itself: of
the two spheres, one was the Bartender and the other was named "Bartender (1)"
in the hierarchy while being configured as the Chair — data changed, name never
was. Nothing outside the scene could see what existed, and two copies could
disagree.

Identity now lives in an InteractableDefinition asset and the scene only places
a prefab. The migration matched the old objects by yarn node rather than by
name, which is the only reason the chair ended up as the chair.

InteractableDefinition rather than the planned "character definition": it covers
a character and a talkable object equally, so Bartender.prefab sits under
Prefabs/Characters and Chair.prefab under Prefabs/Interactables.

Three components collapse into one. DialogueInteractable was in no scene at all
— a dead trigger-zone variant of the same idea. ClickInteractableBridge existed
only to adapt NPCStandIn without modifying it, a constraint that died with
NPCStandIn; DialogueInteractor implements IClickInteractable itself. The parts
worth keeping were lifted out rather than discarded: WorldSpaceLabel and
InteractionPrompt are now normal components on prefab children, so a label can
be seen and positioned in the Editor instead of existing only at runtime.
InputDeviceTracker moved into NightclubArcadia.Core and gained a namespace,
leaving no global-namespace runtime types.

Characters get the same pipeline as Skills and Candidates:
Assets/Characters/characters.json is the source of truth, CharacterSetup
regenerates the definition assets on script reload and removes orphans. Adding
an NPC is a JSON entry plus a prefab — no code, and no Unity for the data half.

Phase 5.4 deletes the one-shot builders rather than disabling them. UILayerSetup,
PlayerControlSetup, UILayerSetupAutoRun and YarnDemoSetup assumed the
single-scene layout, had already destroyed a level scene and turned Systems
binary once each, and after NPCStandIn went they no longer compiled. The prefabs
they used to generate are authored and committed; the wiring knowledge is in
those prefabs and in git history. The asset generators — Skill, Candidate,
Character — are untouched and still work.

EditMode 42/42, PlayMode 7/7, YarnCheck 9 files / 35 nodes. All three scenes
still text.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 21:53:06 +02:00
lennartandClaude Opus 5 ec4619d9dc resolve cross-scene dependencies at the point of use, not in Awake
Fixes "[SceneServices] Bartender: could not resolve dialogueRunner".

Resolving a cross-scene dependency in Awake is a race by construction. The
dialogue runner lives in Systems; an NPC lives in the level. Open the level on
its own, or let the scenes load in the other order, and the NPC wakes with no
Systems scene in sight. Worse, the failed lookup was cached into the serialized
field, so it stayed broken for the rest of the session rather than recovering
once Systems appeared.

NPCStandIn and DialogueInteractable now resolve lazily through a property and
cache only a successful result, so any load order works. Awake still does a
silent best-effort pass, which keeps the common case free.

SceneServices splits in two accordingly. TryResolve is silent and is what
speculative callers use; Resolve logs an error and belongs only where the
dependency is genuinely required. Both now include inactive objects — a system
parked inactive is still the object we mean, and excluding it reported "not
found" for something sitting in the hierarchy. The error text now says where the
runner lives and how to open the scenes, instead of asking a question.

BootstrapTests only ever covered the happy order, which is why it stayed green
while this was broken. SceneOrderTests loads the level BEFORE Systems and holds
that NPCs still reach the runner. It also asserts it is reproducing the race —
it counts the NPCs whose Awake-time resolution failed and fails if that is zero,
so the test cannot quietly start passing for the wrong reason. It currently
reports 2 of 2, which is the bug this commit fixes.

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

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 21:42:54 +02:00
lennartandClaude Opus 5 2a20bd68fe add an Open Game Scenes menu, and fix the Editor-lock check
The scenes were never destroyed. Pressing Play with only Bootstrap open means
GameBootstrap loads Systems and the level at runtime, and Unity discards
runtime-loaded scenes when Play ends, restoring whatever the Editor had open —
Bootstrap alone. The Hierarchy comes back nearly empty. Every scene file was
byte-identical to HEAD throughout, still text.

Tools > Nightclub Arcadia > Open Game Scenes opens all three with the level
active, which is the authoring setup. With them already open, GameBootstrap's
LoadIfNeeded skips them and they survive Play. GameSceneWorkflow also captures
the scene setup before Play and restores it afterwards as a safety net, skipping
the restore when Unity already got it right and ignoring scenes deleted meanwhile
— an exception in that callback would leave the Editor in a worse state than the
problem it fixes. Toggleable under the same menu.

Also fixes `make lock`, which had a self-matching bug since Phase 1: `pgrep -f`
on the full binary path matched the very shell running the check, because the
pattern appears in its own command line. It reported the Editor as running when
nothing was, and would have blocked every make test/build once anything else
matched. Now `pgrep -x Unity`, which matches the process name and cannot match
the shell.

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

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 21:35:36 +02:00
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
lennartandClaude Opus 5 46160d86dc stop the Yarn setup menu from overwriting a real scene
Fixes "Can't start dialogue: no Yarn Project has been configured."

Cause, and it was mine. Phase 3.7 said "retarget YarnDemoSetup.cs or retire it";
I retargeted it. But that menu does not modify a scene — it builds one from
scratch and calls SaveScene over its target. Pointing it at
SC101_ConferenceHall.unity armed it at the real level, and running it replaced
the scene with a bare Yarn demo: ten of fourteen roots gone, including the
player, the lighting and the navmesh. The leftover Dialogue System prefab
instance it left behind had no yarnProject override, auto-started, and produced
the error.

The scene was committed, so nothing was lost; it is restored from HEAD at 14
roots with its sun reference intact.

The menu now targets Assets/Scenes/Dev/YarnSandbox.unity and refuses to run if
its target is not under Scenes/Dev, via ScenePaths.IsDisposable. It is renamed
to "Set Up Yarn Sandbox Scene" so the menu says what it does. The other three
setup menus open and modify their target rather than regenerating it, so they
were never affected and are unchanged.

The test suite could not have caught this, because it asserted only that a
DialogueRunner existed. TheDialogueRunner_HasItsYarnProject now asserts there is
exactly one runner across the loaded scenes and that its project is set and
compiled — which reproduces the failure exactly when the scene is broken.

Also here: four UI prefabs pick up m_EditorClassIdentifier changes from
Assembly-CSharp to NightclubArcadia.Game, written by Unity after the assembly
split in the previous commit. Expected and correct.

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

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 21:14:13 +02:00
lennartandClaude Opus 5 ad598143f8 turn Unity Services back off
The macOS build in the previous commit flipped UnityConnectSettings.m_Enabled
from 0 to 1 as a side effect of running through the authenticated CLI. Nothing
asked for that, and it was off before. The sub-settings — Insights, crash
reporting — were already 0 and stayed 0, so nothing was actually being sent.

It may well flip again on the next build. If it does, that is why.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 21:02:07 +02:00
lennartandClaude Opus 5 bb0f2b760c 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]>
2026-08-25 21:01:27 +02:00
lennartandClaude Opus 5 40b4547c71 split the scene into Bootstrap, Systems and Level
The game now starts from Bootstrap.unity, which additively loads Systems (the
dialogue runner, skills, UI layer, camera rig and the player) and then a level
(geometry, light, navmesh, reveal cameras). The level becomes the active scene so
new objects and lighting land there.

The player moved into Systems. It had been parented under Room_101 — under level
geometry — and it is persistent content, not level content. Moving it also
removes most of the cross-scene breakage on its own.

Unity nulls any serialized reference that crosses a scene boundary. Measured
rather than guessed: the pre-split scene was pulled from git and its null
references diffed against the split result. Exactly seven were lost — both NPCs'
dialogueRunner, dialogueUI and player, plus the reveal camera's tracking target.
A first naive audit reported 210, which turned out to be pre-existing Unity
defaults like Image.m_Material; the baseline diff is what separated the two.

Each of the seven now resolves at runtime. SceneServices.Resolve fills in a null
Inspector reference by searching the loaded scenes, keeping an assigned value if
there is one; CinemachineFollowsPlayer binds the reveal camera once the player
exists. Both follow the pattern already used by CameraFramingVolume and by
NPCStandIn's player lookup, rather than introducing a new one.

Assets/Tests/PlayMode is new, and it immediately paid for itself. BootstrapTests
loads Bootstrap and asserts the whole game comes up; on its first run it caught a
real bug the split had introduced. The player's NavMeshAgent lives in Systems
while the NavMesh is baked into the level, so during load the agent exists
off-mesh and ResetPath logs an error. ClickToMoveController now guards on
agent.isOnNavMesh rather than a bare null check. No EditMode test could have seen
that, because none of it has run yet.

Two of those checks reach their types by name through reflection: NPCStandIn and
the Cinematics namespace live in Assembly-CSharp, and an asmdef test assembly
cannot reference the predefined assemblies. Per-area asmdefs remove the need.

Build settings list all three scenes with Bootstrap at index 0, which
LoadSceneAsync by name requires.

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

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 20:50:25 +02:00
lennartandClaude Opus 5 1c1e50809a convert the working scene to text and move it to Scenes/Levels
The scene is now Assets/Scenes/Levels/SC101_ConferenceHall.unity, serialized as
TEXT: 101KB of YAML, diffable and mergeable for the first time.

Root cause of the binary problem, which four earlier approaches had failed to
fix: the NavMeshSurface on the Navigation root held its baked NavMeshData
*embedded in the scene* rather than as an asset. NavMeshData prefers binary
serialization, and one such object forces the whole scene file to binary
regardless of the project's Force Text setting — which is why toggling that
setting, re-saving, and saving to a new path all did nothing.

Bisecting the roots one at a time found it: thirteen roots each saved as text on
their own, Navigation did not. Extracting the data to
Scenes/Levels/SC101_ConferenceHall/NavMesh-Navigation.asset — which is what
baking from the NavMeshSurface inspector produces anyway — lets the scene
serialize as text. The embedded copy was the anomaly.

The scene was rebuilt rather than copied, because saving the binary scene to a
new path reproduces binary. All 14 roots were moved into a fresh scene and
verified: roots 14 -> 14, cross-root references 25 -> 25, zero missing scripts.
Render settings were carried across by hand, since they do not travel with
GameObjects.

Nothing is split yet — every object is still in one scene, so no reference
crosses a scene boundary. That split is the next step.

Also here: the four Editor setup menus no longer each hardcode the scene path;
they share NightclubArcadia.EditorTools.ScenePaths, which is what made renaming
the scene a four-file edit. Build settings point at the new scene, the URP
template leftovers (SampleScene, Readme.asset, TutorialInfo) are deleted, and
.gitattributes drops the binary exception that existed only for the old file.

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

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 20:39:24 +02:00
lennartandClaude Opus 5 f5b302b3e3 add a Makefile for the common commands, and a test reporter
The invocations in CLAUDE.md were correct but long, and retyping them is how
flags get dropped. `make check` is the gate a change should pass: Yarn compiles,
voice sheets are in sync, EditMode is green.

`make test` and `make build` depend on a `lock` target that fails if the Editor
has the project open, which removes the most common confusing failure. It
filters out AssetImportWorker children, which are not a second Editor.

tools/ci/report_tests.py parses the NUnit results and exits non-zero on failure,
because Unity documents no common exit-code definition across the components
under test — the XML is the authority, not $?.

`make merge-driver` configures UnityYAMLMerge for the .gitattributes rules added
earlier. Note the binary lives in the Editor bundle under Contents/Helpers, not
Contents/Tools as most guides say; there is no Tools directory in Unity 6 on
macOS.

Also ignores the local .test-results/ and build/ output.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 20:29:39 +02:00
lennartandClaude Opus 5 2b35d3f754 renormalize line endings to LF
Mechanical consequence of the .gitattributes in the previous commit, done in one
deliberate pass rather than left to trickle out as surprise diffs whenever
someone next touches a vendored file.

74 files, all CRLF -> LF, 71 of them in StarterAssets. `git diff -w` over this
commit is empty: nothing but line endings changed. DialogueTest.unity is
correctly untouched, being marked binary.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 20:28:07 +02:00
lennartandClaude Opus 5 382f6c7f63 add .gitattributes: Unity YAML merge driver and line-ending policy
Scenes, prefabs and assets are now marked for UnityYAMLMerge, which is what
makes them mergeable at all — without it a scene conflict is resolved by a
line-oriented text merge that produces a file Unity may still load and that is
quietly wrong. The driver needs a one-time git config per machine; CLAUDE.md
carries the command.

Line endings are pinned to LF for every text type rather than left to
`text=auto`, so the 71 CRLF files vendored in StarterAssets stop being a source
of phantom diffs.

One exception, and it matters: DialogueTest.unity is marked `binary`. It is a
Unity binary SerializedFile rather than YAML, and it contains 128 lone CR bytes
— under `*.unity text eol=lf` git would rewrite those as line endings and
corrupt the scene. The rule carries the verification command and comes out as
soon as the file is genuinely text.

LFS is deliberately not enabled: the remote is self-hosted and its LFS support
is unverified, and enabling the filter against a server without it breaks
pushing. The rules to add later, and the migration step that has to accompany
them, are recorded in the file.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 20:28:06 +02:00
lennartandClaude Opus 5 ed28763017 document the writing pipeline and record Phase 2
CLAUDE.md gains the writing/ layout, the voice-sheet pipeline and its direction
of truth, the sync commands, and a pointer that Ground Truth must never be
copied into this repo. The writer-owned/code-owned table now covers writing/.

The restructure plan records Phase 2 as executed, and closes its first open
question: the writing handbook does exist, in the Obsidian vault, so STYLE.md
became a digest with pointers rather than the reconstruction the plan assumed.

Also noted there: the vault's opening-scene spec records SC-101's tone check as
BLOCKED on a one-page Voice Sheet that was never written. STYLE.md now holds
that sheet with four fields explicitly unset.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 20:23:42 +02:00
lennartandClaude Opus 5 f1fadf7909 add a writer-facing content pipeline under writing/
Dialogue was already plain text, so the gap was never the .yarn files. It was
that the character material a writing session needs was either missing or stored
somewhere a writer could not comfortably work.

Three things were wrong. The writing handbook was not in the repo and was cited
by SC101.yarn as though it were. The best voice material — register, verbal tics,
success/failure/passive samples — was a \n-escaped string inside a JSON field.
The named NPCs had no sheets at all, existing only as their Yarn lines.

writing/ now holds the dialogue-facing layer, at the repo root so it gets no
.meta files and is not a Unity asset:

  STYLE.md          register, the five tone moves, the ban list, branching
                    shapes, the Wrong Truth rule, flag families, candidate rules
  YARN-PRIMER.md    the one page of syntax needed to write a scene
  GLOSSARY.md       in-world and project vocabulary
  voices/           the eleven skill voices, one readable sheet each
  characters/       Bartender, Chevalier Cassian Thal, Bradford Kane
  scenes/           SC-101's brief: intent, beats, checks, constraints
  lore/             the three identity readings and the rules that bind them

STYLE.md is a digest of the Mystery Writing Handbook in the Obsidian vault, with
pointers rather than copies. The vault stays the authoring home for design work,
and Ground Truth — the solution document — deliberately stays out of this repo.

The voice sheets are generated from skill_bible.json but are the source of truth
for the prose. tools/writing/sync_voices.py folds edits back; voicelib.py
guarantees notes -> dict -> notes is identity for all eleven, so --to-json on
unchanged sheets is byte-identical. VoiceSheetSyncTests fails the build on drift
in either direction, and was verified to fail on real drift rather than merely
to pass.

SC101.yarn's header is trimmed from prose rationale to the six rules that bind
while editing that file, with the reasoning moved to the scene brief.

EditMode 42/42. YarnCheck compiles 9 files / 35 nodes.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 20:23:42 +02:00
lennartandClaude Opus 5 b915ad78c7 record Phase 0 completion in the restructure plan
Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-25 19:50:39 +02:00
221 changed files with 23734 additions and 17266 deletions
+102
View File
@@ -0,0 +1,102 @@
# Nightclub Arcadia — git attributes
#
# Two jobs: make Unity's YAML files mergeable, and keep line endings from
# becoming a source of phantom diffs.
# ---------------------------------------------------------------------------
# Unity YAML — text, LF, and merged with UnityYAMLMerge
# ---------------------------------------------------------------------------
# The merge driver needs a one-time setup per machine; see §"Merge driver" in
# CLAUDE.md. Without it git falls back to a normal text merge, which for scenes
# and prefabs means conflicts that are painful but not silently wrong.
*.unity text eol=lf merge=unityyamlmerge
*.prefab text eol=lf merge=unityyamlmerge
*.asset text eol=lf merge=unityyamlmerge
*.mat text eol=lf merge=unityyamlmerge
*.anim text eol=lf merge=unityyamlmerge
*.controller text eol=lf merge=unityyamlmerge
*.overrideController text eol=lf merge=unityyamlmerge
*.physicMaterial text eol=lf merge=unityyamlmerge
*.physicsMaterial2D text eol=lf merge=unityyamlmerge
*.playable text eol=lf merge=unityyamlmerge
*.mask text eol=lf merge=unityyamlmerge
*.brush text eol=lf merge=unityyamlmerge
*.flare text eol=lf merge=unityyamlmerge
*.lighting text eol=lf merge=unityyamlmerge
*.terrainlayer text eol=lf merge=unityyamlmerge
*.signal text eol=lf merge=unityyamlmerge
*.guiskin text eol=lf merge=unityyamlmerge
*.fontsettings text eol=lf merge=unityyamlmerge
*.meta text eol=lf
# ---------------------------------------------------------------------------
# Source, config and prose
# ---------------------------------------------------------------------------
*.cs text eol=lf diff=csharp
*.yarn text eol=lf
*.yarnproject text eol=lf
*.asmdef text eol=lf
*.asmref text eol=lf
*.inputactions text eol=lf
*.shader text eol=lf
*.compute text eol=lf
*.cginc text eol=lf
*.hlsl text eol=lf
*.shadergraph text eol=lf
*.json text eol=lf
*.md text eol=lf
*.txt text eol=lf
*.py text eol=lf
*.sh text eol=lf
*.csproj text eol=lf
*.xml text eol=lf
*.gitattributes text eol=lf
*.gitignore text eol=lf
# ---------------------------------------------------------------------------
# Binary — never diffed, never line-ending converted
# ---------------------------------------------------------------------------
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.tga binary
*.tif binary
*.tiff binary
*.psd binary
*.exr binary
*.hdr binary
*.fbx binary
*.obj binary
*.blend binary
*.wav binary
*.mp3 binary
*.ogg binary
*.aif binary
*.ttf binary
*.otf binary
*.pdf binary
*.dll binary
*.pdb binary
*.so binary
*.dylib binary
*.bundle binary
*.a binary
*.unitypackage binary
*.cubemap binary
# ---------------------------------------------------------------------------
# Git LFS — deliberately NOT enabled yet
# ---------------------------------------------------------------------------
# git-lfs is installed locally, but this repo pushes to a self-hosted server
# whose LFS support has not been verified, and enabling LFS against a server
# that lacks it breaks pushing. There is also almost nothing to store yet: one
# placeholder PNG plus the StarterAssets meshes.
#
# When real art lands, verify the server first, then add:
# *.png filter=lfs diff=lfs merge=lfs -text
# *.fbx filter=lfs diff=lfs merge=lfs -text
# *.wav filter=lfs diff=lfs merge=lfs -text
# and migrate existing blobs with `git lfs migrate import --include=...`.
# Adding the filter without migrating leaves old blobs outside LFS, which is
# confusing rather than broken.
+6
View File
@@ -127,3 +127,9 @@ tools/**/obj/
*.tar.gz *.tar.gz
*.7z *.7z
*.rar *.rar
# ---------------------------------------------------------------------------
# Local build and test output (Makefile targets)
# ---------------------------------------------------------------------------
/.test-results/
/build/
+233 -50
View File
@@ -17,7 +17,9 @@ to fix — it is the checkout path). The Unity project is a **subdirectory**:
/Users/lennart/Dev/nightlcub-arcadia/ # git root /Users/lennart/Dev/nightlcub-arcadia/ # git root
├── CLAUDE.md, AGENTS.md # this reference ├── CLAUDE.md, AGENTS.md # this reference
├── docs/ # design + plan docs (markdown) ├── docs/ # design + plan docs (markdown)
├── writing/ # writer-facing context — see §4
├── tools/YarnCheck/ # .NET 9 Yarn compiler/player, no Unity needed ├── tools/YarnCheck/ # .NET 9 Yarn compiler/player, no Unity needed
├── tools/writing/ # voice-sheet sync (md <-> skill_bible.json)
├── .gitignore # macOS / IDE / toolchain rules ├── .gitignore # macOS / IDE / toolchain rules
└── NightclubArcadia/ # ← the Unity project (-projectPath) └── NightclubArcadia/ # ← the Unity project (-projectPath)
├── .gitignore # Unity rules (anchored, must stay here) ├── .gitignore # Unity rules (anchored, must stay here)
@@ -45,17 +47,47 @@ AI Navigation 2.0.14, ProBuilder 6.1.2, Test Framework 1.7.0. Yarn Spinner is an
overwritten by the Editor setup scripts. Edit the JSON. overwritten by the Editor setup scripts. Edit the JSON.
2. **Never hand-edit scene or prefab YAML unless you have read the surrounding block.** 2. **Never hand-edit scene or prefab YAML unless you have read the surrounding block.**
GUID/fileID surgery in `.unity` / `.prefab` files silently detaches components. GUID/fileID surgery in `.unity` / `.prefab` files silently detaches components.
3. **One Unity instance per project path.** Unity refuses to open a project in batch 5. **One Unity instance per project path.** Unity refuses to open a project in batch
mode while the Editor has it open — a single instance at a time. Always check before mode while the Editor has it open — a single instance at a time. Always check before
any `-batchmode` invocation (§3.1). any `-batchmode` invocation (§3.1).
4. **Prefer YarnCheck over Unity for dialogue validation.** It is seconds, not minutes, 6. **Prefer YarnCheck over Unity for dialogue validation.** It is seconds, not minutes,
and needs no Editor lock (§5.3). and needs no Editor lock (§5.5).
5. **Do not commit on the user's behalf** unless asked. Unity writes to tracked files 7. **Do not commit on the user's behalf** unless asked. Unity writes to tracked files
(`ProjectSettings/*`, `.meta`, scenes) as a side effect of simply being open, so (`ProjectSettings/*`, `.meta`, scenes) as a side effect of simply being open, so
`git status` noise is expected and is not always yours. `git status` noise is expected and is not always yours.
--- ---
## 2b. Everyday commands
A `Makefile` at the repo root wraps everything in this document. Prefer it — the exact
invocations live there instead of being retyped.
```bash
make # list targets
make check # yarn + voice sheets + EditMode — run this before committing
make test # EditMode suite, with a readable summary
make yarn # compile every Yarn script (seconds, no Unity)
make build # macOS player into build/
make lock # fail if the Editor has the project open
```
`make test` and `make build` refuse to run while the Editor is open, which removes the most
common way these commands fail confusingly.
### Merge driver — one-time per machine
`.gitattributes` marks Unity YAML for `unityyamlmerge`. Git needs to be told what that is, or
it falls back to a line-oriented text merge that can produce a scene Unity still loads and that
is quietly wrong:
```bash
make merge-driver
```
That points git at `UnityYAMLMerge` inside the Editor bundle (`Contents/Helpers/`, not
`Contents/Tools/` — the path in most online guides is wrong for Unity 6 on macOS).
## 3. Unity from the command line ## 3. Unity from the command line
### 3.0 Two different tools, both present ### 3.0 Two different tools, both present
@@ -101,10 +133,11 @@ misread the check. `Temp/UnityLockfile` and `unity status` are the other two sig
Useful flags: `--filter <pattern>`, `--retries <0-10>` (reports tests that pass on retry as Useful flags: `--filter <pattern>`, `--retries <0-10>` (reports tests that pass on retry as
flaky), `--rerun-failed`, `--shard N/M` for parallel CI, `--coverage`, `--timeout <seconds>`. flaky), `--rerun-failed`, `--shard N/M` for parallel CI, `--coverage`, `--timeout <seconds>`.
`--mode PlayMode` runs the PlayMode suite. **There are none yet** — `Assets/Tests/` is EditMode `--mode PlayMode` runs `Assets/Tests/PlayMode` — currently `BootstrapTests`, which loads
only, so that command reports zero tests. A PlayMode suite needs a new `Bootstrap.unity` and asserts the whole game comes up: both scenes loaded, the player present
`Assets/Tests/PlayMode/*.asmdef` referencing `UnityEngine.TestRunner` with `includePlatforms` and tagged, the dialogue runner found, both NPCs having resolved their runner across the scene
left empty. boundary, and the reveal camera bound to the player. **If that suite fails, the game does not
start.**
Raw-Editor equivalent, if you need a flag the CLI does not expose: Raw-Editor equivalent, if you need a flag the CLI does not expose:
@@ -133,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
@@ -174,6 +217,49 @@ NightclubArcadia/Assets/Dialogue/
└── Objects/ Chair └── Objects/ Chair
``` ```
The writer-facing context sits at the repo root, outside `Assets/` so it gets no `.meta` files:
The scenes are split three ways, loaded additively from `Bootstrap`:
```
Assets/Scenes/
├── Bootstrap.unity entry point; GameBootstrap loads the rest
├── Systems/Systems.unity dialogue, skills, UI, camera rig, and the PLAYER
└── Levels/
├── SC101_ConferenceHall.unity geometry, light, navmesh, reveal cameras
└── SC101_ConferenceHall/ baked data for that scene (NavMesh asset)
```
`Bootstrap` must stay index 0 in the build settings. The level is made the active scene after
load, so new objects and lighting land there rather than in Bootstrap.
**Working in the Editor.** `Tools ▸ Nightclub Arcadia ▸ Open Game Scenes` opens all three at
once, with the level active. Do that before pressing Play.
If you press Play with only `Bootstrap` open, `GameBootstrap` loads the other two *at runtime*,
and Unity discards runtime-loaded scenes when Play ends — the Hierarchy comes back with Bootstrap
alone and it looks as though the scenes were destroyed. **Nothing is written to disk**; it is the
Hierarchy, not the files. With all three already open, `GameBootstrap` skips loading them
(`LoadIfNeeded`) and they are still there afterwards. `GameSceneWorkflow` also captures and
restores the scene setup around Play as a safety net; toggle it under the same menu.
```
writing/
├── README.md session entry point
├── STYLE.md register, tone moves, ban list, branching rules ← read first
├── YARN-PRIMER.md the one page of syntax a writer needs
├── GLOSSARY.md in-world and project vocabulary
├── voices/ the eleven skill voices, one sheet each (generated — see §4.7)
├── characters/ named NPCs, dialogue-facing
├── scenes/ per-scene briefs: intent, beats, checks, constraints
└── lore/ candidates.md — the three identity readings and their hard rules
```
Design material deeper than this lives in Obsidian, not the repo:
`~/Obsidian-Vaults/obsidian-vault/Projects/Active/NightclubArcadia/`. **`Ground Truth.md` there
is the solution document — never copy, quote, or summarise it into this repo**, including into
commit messages. The game's premise is that the protagonist's identity never resolves.
**Dialogue is already plain text in the repo.** It is authored in `.yarn` files, not inside **Dialogue is already plain text in the repo.** It is authored in `.yarn` files, not inside
the Unity Editor, and any new `.yarn` file dropped anywhere under `Assets/Dialogue/` is picked the Unity Editor, and any new `.yarn` file dropped anywhere under `Assets/Dialogue/` is picked
up automatically by the `**/*.yarn` glob in the `.yarnproject`. Adding a scene or a character up automatically by the `**/*.yarn` glob in the `.yarnproject`. Adding a scene or a character
@@ -242,20 +328,52 @@ There is **no manual sync step** for dialogue. The chain is:
The only things that need a human/Editor step are the *data* files, not the dialogue: The only things that need a human/Editor step are the *data* files, not the dialogue:
``` ```
skill_bible.json → Tools ▸ Nightclub Arcadia ▸ (SkillSystemSetup) → Skills/Definitions/*.asset + SkillDatabase.asset skill_bible.json → Tools ▸ Nightclub Arcadia ▸ Set Up Skill System → Skills/Definitions/*.asset + SkillDatabase.asset
candidates.json → Tools ▸ Nightclub Arcadia ▸ (CandidateSystemSetup) → Candidates/Definitions/*.asset + CandidateDatabase.asset candidates.json → Tools ▸ Nightclub Arcadia ▸ Set Up Candidate System → Candidates/Definitions/*.asset + CandidateDatabase.asset
characters.json → Tools ▸ Nightclub Arcadia ▸ Set Up Characters → Characters/Definitions/*.asset
``` ```
`characters.json` is where an NPC or a talkable object gets its display name, its Yarn node and
its interaction range. Adding one is a JSON entry plus a prefab; it needs no code.
Those setup scripts also register a `[DidReloadScripts]` callback, so in practice the assets Those setup scripts also register a `[DidReloadScripts]` callback, so in practice the assets
regenerate on script reload too. The JSON is the source of truth either way. regenerate on script reload too. The JSON is the source of truth either way.
### 4.6 Code-owned vs writer-owned ### 4.6 The voice-sheet pipeline
The Skill Bible prose used to live as a `\n`-escaped string inside `skill_bible.json`, which no
writer could comfortably read or revise. It now lives in `writing/voices/*.md`, and truth flows
in opposite directions for the two halves of each sheet:
```
PROSE writing/voices/<id>.md -> skill_bible.json -> Skills/Definitions/*.asset
MACHINE skill_bible.json -> the "Machine fields" table in the .md
```
```bash
python3 tools/writing/sync_voices.py --check # verify; exit 1 on drift
python3 tools/writing/sync_voices.py --to-json # fold edited prose into the bible
python3 tools/writing/sync_voices.py --to-md # refresh the machine table from the bible
```
`tools/writing/voicelib.py` does the parsing and guarantees `notes -> dict -> notes` is identity
for all eleven skills. `--to-json` on unchanged sheets is byte-identical, so it is safe to run
at any time.
`VoiceSheetSyncTests` (EditMode) enforces the same invariant, so drift fails the build instead
of silently shipping a voice that no longer matches the sheet the next scene is written against.
It deliberately does not reimplement the markdown parser in C# — it asserts the shipped prose
appears verbatim in the sheet, which catches drift in either direction with no second parser to
keep in step.
### 4.7 Code-owned vs writer-owned
| Writer-owned (edit freely, no Unity) | Code-owned (needs an engineer) | | Writer-owned (edit freely, no Unity) | Code-owned (needs an engineer) |
|---|---| |---|---|
| `Assets/Dialogue/**/*.yarn` | `Assets/Scripts/**/*.cs` | | `writing/**` | `Assets/Scripts/**/*.cs` |
| `<<declare>>` lines in `Common.yarn` | `Assets/Editor/**/*.cs` | | `Assets/Dialogue/**/*.yarn` | `Assets/Editor/**/*.cs` |
| `Assets/Skills/skill_bible.json` (prose fields) | Yarn command/function *implementations* | | `<<declare>>` lines in `Common.yarn` | Yarn command/function *implementations* |
| `writing/voices/*.md` (prose → the bible, §4.6) | `Assets/Skills/skill_bible.json` (machine fields) |
| `Assets/Candidates/candidates.json` (`status`, `sceneId`, `notes`, `unlockFlag`) | `.asset`, `.prefab`, `.unity`, `.meta` | | `Assets/Candidates/candidates.json` (`status`, `sceneId`, `notes`, `unlockFlag`) | `.asset`, `.prefab`, `.unity`, `.meta` |
| `docs/` writing docs | `ProjectSettings/**` | | `docs/` writing docs | `ProjectSettings/**` |
@@ -278,11 +396,24 @@ or a branch.** If a writing task requires either, that is a pipeline bug — fil
`$self_lean_*` / `$found_*` in any `.yarn` file resolves to a real id in `CandidateDatabase`. `$self_lean_*` / `$found_*` in any `.yarn` file resolves to a real id in `CandidateDatabase`.
It is a tripwire, not a proof. It is a tripwire, not a proof.
### 5.2 One-click in-Editor run ### 5.2 PlayMode suite
`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.
### 5.3 Voice-sheet sync
```bash
python3 tools/writing/sync_voices.py --check
```
Seconds, no Unity. Run it after touching `writing/voices/*.md` or `skill_bible.json` (§4.6).
### 5.4 One-click in-Editor run
`Tools ▸ Nightclub Arcadia ▸ Run Skill EditMode Tests` (`Assets/Editor/SkillSystemTestRunner.cs`). `Tools ▸ Nightclub Arcadia ▸ Run Skill EditMode Tests` (`Assets/Editor/SkillSystemTestRunner.cs`).
### 5.3 YarnCheck — validate dialogue without Unity ⭐ ### 5.5 YarnCheck — validate dialogue without Unity ⭐
`tools/YarnCheck` is a .NET 9 console app that compiles **and plays** the Yarn scripts using `tools/YarnCheck` is a .NET 9 console app that compiles **and plays** the Yarn scripts using
the exact Yarn Spinner DLLs shipped in `Packages/dev.yarnspinner.unity/Runtime/DLLs`, so it the exact Yarn Spinner DLLs shipped in `Packages/dev.yarnspinner.unity/Runtime/DLLs`, so it
@@ -318,11 +449,26 @@ should not be — see `docs/restructure-plan.md`.
- Namespaces: `NightclubArcadia.<Area>` — `Skills`, `Dialogue`, `UI`, `UI.Dialogue`, - Namespaces: `NightclubArcadia.<Area>` — `Skills`, `Dialogue`, `UI`, `UI.Dialogue`,
`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 There are no global-namespace runtime types left; the last one, `NPCStandIn`, went with the
convention to copy — new runtime types always get a namespace. scaffold, and `InputDeviceTracker` moved into `NightclubArcadia.Core`.
- 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 |
`Scripts/Interaction` holds the interaction layer: `InteractableDefinition` (the asset that
says what a thing is called and which node it starts), `DialogueInteractor` (the component
that places one in the world), plus `WorldSpaceLabel` and `InteractionPrompt`.
`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.
@@ -333,29 +479,66 @@ should not be — see `docs/restructure-plan.md`.
## 7. Traps ## 7. Traps
1. **`Assets/Scenes/DialogueTest.unity` is serialized as binary**, and Unity will not convert it 1. **A scene silently turns binary if it holds an object that prefers binary serialization.**
from a headless run. The project is set to Force Text (`m_SerializationMode: 2`) and the API This one cost real time. `DialogueTest.unity` was binary for weeks despite the project being
agrees — `EditorSettings.serializationMode` reads `ForceText` — but Force Text governs set to Force Text, because the `NavMeshSurface` held its baked `NavMeshData` *embedded in the
conversion **at the moment the setting changes**, not on every save. A file that entered the scene* rather than as an asset. One such object forces the whole file to binary, and no amount
project as binary stays binary. Four approaches were tried and all failed silently: of re-saving or toggling the setting fixes it — Force Text only converts at the moment the
`AssetDatabase.ForceReserializeAssets` does not rewrite scene files; `OpenScene` + setting changes. The fix is to extract the data to its own asset, which is what baking from
`MarkSceneDirty` + `SaveScene` to the same path returns `true` and writes nothing, because the NavMeshSurface inspector produces anyway. If a scene goes binary again, bisect: move the
`MarkSceneDirty` does not take in batch mode; `SaveScene` to a *new* path writes a fresh file roots one at a time into a fresh scene and see which one yields a binary file.
that is also binary; and re-assigning `serializationMode` (Mixed → ForceText) from script
does not trigger a reserialize pass. **The fix is Editor-UI only:** Project Settings ▸ Editor 2. **Serialized references cannot cross a scene boundary.** Unity nulls them. The split cost
▸ Asset Serialization, switch the mode and switch it back, which reserializes on apply. exactly seven: both NPCs' `dialogueRunner`, `dialogueUI` and `player`, plus the reveal
Until then the scene is not diffable or mergeable. It is committed and intact (14 roots). camera's tracking target. All are resolved at runtime now — `SceneServices` for the first,
2. **`unity run` reserves `-batchmode`, `-nographics`, `-quit`, `-logFile`.** Passing any of them `CinemachineFollowsPlayer` for the last.
**Resolve at the point of use, never in `Awake`.** A level object can wake up before the
scene holding its dependency exists — open the level on its own, or in the wrong order, and
`Awake` runs with no Systems scene in sight. That produced
`[SceneServices] Bartender: could not resolve dialogueRunner`, and because the result was
cached once, it stayed broken for the whole session. `SceneServices.TryResolve` is the silent
lookup for speculative calls; `SceneServices.Resolve` logs and belongs only where the
dependency is genuinely needed. `NPCStandIn.ResolvedDialogueRunner` is the pattern to copy.
`SceneOrderTests` holds the property, and asserts it is actually reproducing the race rather
than passing for free.
3. **The player's NavMeshAgent outlives the NavMesh.** The player is in Systems, the NavMesh is
baked into the level, so there is a window during load where the agent exists and is not on a
mesh. `ResetPath`, `isStopped` and `SetDestination` all log errors in that state. Guard on
`agent.isOnNavMesh`, not just a null check.
4. **An asmdef assembly cannot reference `Assembly-CSharp`.** Only the reverse. This is why
giving the runtime code assemblies had to include `StarterAssets`, which had none and which
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. **The one-shot scene builders are gone.** `UILayerSetup`, `PlayerControlSetup`,
`UILayerSetupAutoRun` and `YarnDemoSetup` built scenes from scratch and assumed the
single-scene layout; after the split they produced duplicates, and one of them destroyed a
level. The prefabs they used to generate are authored and committed now, so they were deleted
rather than fixed. They are in git history if the wiring ever needs consulting.
`Set Up Skill System`, `Set Up Candidate System` and `Set Up Characters` remain — they
regenerate assets from JSON and touch no scene. **To run the game, open `Bootstrap.unity`.**
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). after `--` is a hard error, and its output does not reach stdout — read `Logs/Editor.log` (§3.4).
3. **`-quit` with `-runTests`** hangs or truncates. Omit it (§3.2).
4. **Exit code alone is not a test verdict.** Parse the results XML (§3.2). 7. **`-quit` with `-runTests`** hangs or truncates. Omit it (§3.2).
5. **`which unity` fails** in non-interactive shells even though the CLI is installed. Use the
8. **Exit code alone is not a test verdict.** Parse the results XML (§3.2), which is what
`make test` does.
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). absolute path `/Users/lennart/.unity/bin/unity` (§3.0).
6. **Editor lock** — check before every headless run, filtering out `AssetImportWorker` children (§3.1).
7. **Regenerated assets** — hand edits to `Skills/Definitions/*`, `Candidates/Definitions/*` 10. **Editor lock** — check before every headless run, filtering out `AssetImportWorker` children.
and the two `*Database.asset` files are silently discarded (§2.1). `make test` and `make build` do this for you (§2b).
8. **`top_skill` ties** resolve to the first argument. Reordering arguments changes the game.
9. **No `.gitattributes`** — no Unity YAML merge driver, no LFS rule for `Assets/Art/`. 11. **Regenerated assets** — hand edits to `Skills/Definitions/*`, `Candidates/Definitions/*`
Scene and prefab merges will conflict destructively under branching. and the two `*Database.asset` files are silently discarded (§2.1).
10. **Template leftovers still present**: `Assets/Scenes/SampleScene.unity`, `Assets/Readme.asset`,
`Assets/TutorialInfo/`. `SampleScene` is in the build scene list. Not load-bearing. 12. **`top_skill` ties** resolve to the first argument. Reordering arguments changes the game.
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.
+73
View File
@@ -0,0 +1,73 @@
# Nightclub Arcadia — common commands.
#
# Everything here is documented in CLAUDE.md; this file exists so the exact
# invocations live in one place instead of being retyped from memory.
UNITY_CLI ?= /Users/lennart/.unity/bin/unity
UNITY ?= /Applications/Unity/Hub/Editor/6000.5.8f1/Unity.app/Contents/MacOS/Unity
PROJECT ?= $(CURDIR)/NightclubArcadia
RESULTS ?= $(CURDIR)/.test-results
SMARTMERGE ?= /Applications/Unity/Hub/Editor/6000.5.8f1/Unity.app/Contents/Helpers/UnityYAMLMerge
.DEFAULT_GOAL := help
.PHONY: help check yarn yarn-play voices voices-sync test test-play build lock clean-results merge-driver
help: ## Show this help
@grep -hE '^[a-z-]+:.*?## ' $(MAKEFILE_LIST) \
| awk 'BEGIN {FS = ":.*?## "} {printf " \033[36m%-14s\033[0m %s\n", $$1, $$2}'
@echo ""
@echo " Unity must be CLOSED for test/build — run 'make lock' to check."
check: yarn voices test test-play ## Everything a change should pass before commit
yarn: ## Compile every Yarn script (seconds, no Unity)
@cd tools/YarnCheck && DOTNET_CLI_TELEMETRY_OPTOUT=1 dotnet run -- ../../NightclubArcadia/Assets/Dialogue
yarn-play: ## Play a node: make yarn-play NODE=Bartender_Talk PICKS="2 2 0 0"
@cd tools/YarnCheck && DOTNET_CLI_TELEMETRY_OPTOUT=1 \
dotnet run -- ../../NightclubArcadia/Assets/Dialogue $(NODE) $(PICKS)
voices: ## Check writing/voices/*.md against skill_bible.json
@python3 tools/writing/sync_voices.py --check
voices-sync: ## Fold edited voice prose into skill_bible.json
@python3 tools/writing/sync_voices.py --to-json
test: lock ## Run the EditMode suite
@mkdir -p $(RESULTS)
@$(UNITY_CLI) test $(PROJECT) --no-banner --mode EditMode \
--output $(RESULTS)/editmode.xml --timeout 900 || true
@python3 tools/ci/report_tests.py $(RESULTS)/editmode.xml
test-play: lock ## Run the PlayMode suite (bootstrap + scene split)
@mkdir -p $(RESULTS)
@$(UNITY_CLI) test $(PROJECT) --no-banner --mode PlayMode \
--output $(RESULTS)/playmode.xml --timeout 900 || true
@python3 tools/ci/report_tests.py $(RESULTS)/playmode.xml
build: lock ## Build a macOS player into build/
@$(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
# pgrep -x matches the process NAME only. The previous `pgrep -f` on the full
# binary path matched this very shell, because the pattern appears in its own
# command line — the check reported the Editor running when nothing was.
# AssetImportWorkers share the name but only exist alongside an Editor, so
# matching them is correct rather than a false positive.
@if pgrep -x Unity > /dev/null 2>&1; then \
echo "The Unity Editor is running — close it first (only one instance per project)."; \
exit 1; \
fi
merge-driver: ## One-time: teach git to merge Unity YAML with UnityYAMLMerge
@test -x "$(SMARTMERGE)" || { echo "UnityYAMLMerge not found at $(SMARTMERGE)"; exit 1; }
@git config merge.unityyamlmerge.name "Unity SmartMerge"
@git config merge.unityyamlmerge.driver "'$(SMARTMERGE)' merge -p --force --fallback none %O %B %A %A"
@git config merge.unityyamlmerge.recursive binary
@echo "configured: $$(git config merge.unityyamlmerge.name)"
clean-results: ## Remove local test results
@rm -rf $(RESULTS)
@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: ba062aa6c92b140379dbc06b43dd3b9b guid: fd96ed0121314a93aff9d3ef7845fd1d
folderAsset: yes folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}
@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 2216657f3a0224501bcfa09add14f689 guid: 642dac0a511114afa9f701fb8a59378c
folderAsset: yes folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}
@@ -0,0 +1,19 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 8f4df63859ea4e39910d900aa7a5510a, type: 3}
m_Name: bartender
m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.Interaction.InteractableDefinition
id: bartender
displayName: Bartender
yarnNode: Bartender_Talk
interactionRange: 3
showLabel: 1
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8ccb543c858f74a969cb025cb3e1f0ea
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,19 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 8f4df63859ea4e39910d900aa7a5510a, type: 3}
m_Name: chair
m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.Interaction.InteractableDefinition
id: chair
displayName: Chair
yarnNode: Chair_Interaction
interactionRange: 3
showLabel: 1
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 403e142c457b0412a8c8604a2a9807ed
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,18 @@
{
"interactables": [
{
"id": "bartender",
"displayName": "Bartender",
"yarnNode": "Bartender_Talk",
"interactionRange": 3.0,
"showLabel": true
},
{
"id": "chair",
"displayName": "Chair",
"yarnNode": "Chair_Interaction",
"interactionRange": 3.0,
"showLabel": true
}
]
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b4673507aac641739818bc04a57a8930
TextScriptImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -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
}, },
@@ -1,28 +1,24 @@
// SC-101 — The Card at the Desk. Opening candidate hooks. // SC-101 — The Card at the Desk. Opening candidate hooks.
// //
// Scene files stay thin: set the stage, <<detour>> into hook nodes, return. // Brief, beats, checks and the reasoning behind every rule below:
// writing/scenes/sc101-the-card-at-the-desk.md
// //
// Evidence rule: each candidate gets exactly one of each evidence type — // Rules that bind while editing THIS file — all six are deliberate, none is a
// object, testimony, document, intuition. Preserve that balance; do not // leftover. The brief says why; this is the short form so you do not have to
// stack types so trust becomes an artifact of imbalance. // leave the file to avoid breaking it.
// See Assets/Candidates/candidates.json.
// //
// Beat order: hooks fire in sequence from SC101_Desk (STANDING ORDER → // 1. Scene files stay thin: set the stage, <<detour>> into hook nodes, return.
// HOUSE POUR → FACEWORK → CONFLUENCE). Each remains an independently authored // 2. Evidence balance — one object / testimony / document / intuition per
// node. Never <<if>>-guard a hook on another hook having fired, on any // candidate. Never stack types. See Assets/Candidates/candidates.json.
// $self_lean_*, or on skill_rank(...). // 3. Beat order is fixed: STANDING ORDER -> HOUSE POUR -> FACEWORK ->
// // CONFLUENCE. Never <<if>>-guard a hook on another hook having fired, on any
// Passive pattern (clue-bearing): // $self_lean_*, or on skill_rank(...).
// one voice per hook, from the candidate's attached pair; // 4. Passive pattern for a clue-bearing hook: one voice, from the candidate's
// the line is that character's argument, never a report; // attached pair; the line is that voice's argument, never a report; exactly
// exactly one $self_lean_* write; set $found_<clue_id> alongside it. // one $self_lean_* write, with $found_<clue_id> set alongside it.
// // 5. Four voice introductions, against the handbook cap of three. Deliberate,
// Four-voice exception: this opening uses four voice introductions (one per // SC-101 only — one voice per pair. Do not correct it down, do not copy it.
// pair) against the writing handbook's "cap introductions at three voices" // 6. The body stays neutral: no lean, no candidate attachment outside the hooks.
// rule. Deliberate and for SC-101 only — do not "correct" it down to three,
// and do not copy it as a new precedent elsewhere.
//
// Body stays neutral on purpose: no lean, no candidate attachment.
title: Start title: Start
position: -17,-276 position: -17,-276
@@ -0,0 +1,144 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NightclubArcadia.Interaction;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEngine;
namespace NightclubArcadia.EditorTools
{
/// <summary>
/// Regenerates InteractableDefinition assets from Assets/Characters/characters.json.
///
/// The JSON is the source of truth and the .asset files are build output; hand edits
/// to them are overwritten. Same contract as Skills and Candidates, deliberately —
/// a writer adding a character edits one JSON file and never opens Unity.
///
/// This exists because the identity of an NPC used to live in public fields on a
/// scene object, where nothing outside that scene could see it and two copies could
/// disagree. They did: the scene's second "Bartender" was the chair.
/// </summary>
public static class CharacterSetup
{
const string JsonPath = "Assets/Characters/characters.json";
const string DefinitionsFolder = "Assets/Characters/Definitions";
[Serializable]
class Dto
{
public string id;
public string displayName;
public string yarnNode;
public float interactionRange = 3f;
public bool showLabel = true;
}
[Serializable]
class DtoList
{
public Dto[] interactables;
}
[MenuItem("Tools/Nightclub Arcadia/Set Up Characters")]
public static void SetUpCharacters() => Regenerate(verbose: true);
[DidReloadScripts]
static void OnScriptsReloaded() => Regenerate(verbose: false);
static void Regenerate(bool verbose)
{
if (!File.Exists(JsonPath))
{
if (verbose)
{
Debug.LogError($"[Characters] Missing {JsonPath}");
}
return;
}
DtoList parsed;
try
{
parsed = JsonUtility.FromJson<DtoList>(File.ReadAllText(JsonPath));
}
catch (Exception e)
{
Debug.LogError($"[Characters] {JsonPath} is not valid JSON: {e.Message}");
return;
}
if (parsed?.interactables == null || parsed.interactables.Length == 0)
{
Debug.LogError($"[Characters] {JsonPath} defines no interactables.");
return;
}
var duplicates = parsed.interactables.GroupBy(i => i.id).Where(g => g.Count() > 1).ToList();
if (duplicates.Count > 0)
{
Debug.LogError("[Characters] Duplicate ids: " +
string.Join(", ", duplicates.Select(g => g.Key)));
return;
}
if (!AssetDatabase.IsValidFolder(DefinitionsFolder))
{
AssetDatabase.CreateFolder("Assets/Characters", "Definitions");
}
var live = new HashSet<string>(StringComparer.Ordinal);
var changed = new List<string>();
foreach (var dto in parsed.interactables)
{
if (string.IsNullOrWhiteSpace(dto.id))
{
Debug.LogError("[Characters] An entry has no id; skipped.");
continue;
}
live.Add(dto.id);
var path = $"{DefinitionsFolder}/{dto.id}.asset";
var asset = AssetDatabase.LoadAssetAtPath<InteractableDefinition>(path);
if (asset == null)
{
asset = ScriptableObject.CreateInstance<InteractableDefinition>();
AssetDatabase.CreateAsset(asset, path);
changed.Add(dto.id);
}
else if (asset.DisplayName != dto.displayName || asset.YarnNode != dto.yarnNode ||
!Mathf.Approximately(asset.InteractionRange, dto.interactionRange) ||
asset.ShowLabel != dto.showLabel)
{
changed.Add(dto.id);
}
asset.EditorSet(dto.id, dto.displayName, dto.yarnNode, dto.interactionRange, dto.showLabel);
EditorUtility.SetDirty(asset);
}
// An id removed from the JSON should not leave an orphan asset behind that a
// prefab could still be pointing at.
foreach (var guid in AssetDatabase.FindAssets("t:InteractableDefinition", new[] { DefinitionsFolder }))
{
var path = AssetDatabase.GUIDToAssetPath(guid);
var name = Path.GetFileNameWithoutExtension(path);
if (!live.Contains(name))
{
Debug.LogWarning($"[Characters] Removing orphan definition '{name}' — no longer in the JSON.");
AssetDatabase.DeleteAsset(path);
}
}
AssetDatabase.SaveAssets();
if (verbose || changed.Count > 0)
{
Debug.Log($"[Characters] {parsed.interactables.Length} definition(s) in {DefinitionsFolder}" +
(changed.Count > 0 ? $"; updated: {string.Join(", ", changed)}" : "; no changes"));
}
}
}
}
@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 6c0e3c886ff143d3b26b7f55d7f22410 guid: 9cbb2b742dcc4031a4e0cfc0c0544faf
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2
@@ -0,0 +1,129 @@
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
namespace NightclubArcadia.EditorTools
{
/// <summary>
/// Makes the split-scene layout usable in the Editor.
///
/// The game runs from Bootstrap, which loads Systems and a level additively AT
/// RUNTIME. Unity discards runtime-loaded scenes when Play ends and restores
/// whatever the Editor had open, which for someone who pressed Play in Bootstrap is
/// Bootstrap alone. The Hierarchy comes back nearly empty and it looks as though the
/// scenes were destroyed. They are not — nothing is written to disk — but it is an
/// unpleasant way to work.
///
/// Two fixes, both opt-outable:
/// - Open Game Scenes puts all three in the Hierarchy for authoring.
/// - The Editor's scene setup is captured before Play and restored after, so what
/// you had open is what you get back.
///
/// GameBootstrap skips any scene that is already loaded, so having all three open
/// and pressing Play does the right thing rather than loading anything twice.
/// </summary>
[InitializeOnLoad]
public static class GameSceneWorkflow
{
const string RestorePrefKey = "NightclubArcadia.RestoreSceneSetup";
const string RestoreMenu = "Tools/Nightclub Arcadia/Restore Scene Setup After Play";
static SceneSetup[] setupBeforePlay;
static GameSceneWorkflow()
{
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
}
[MenuItem("Tools/Nightclub Arcadia/Open Game Scenes")]
public static void OpenGameScenes()
{
// The prompt cannot be shown in batch mode, where it returns false and would
// make this menu a silent no-op.
if (!Application.isBatchMode && !EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
{
return;
}
foreach (var path in new[] { ScenePaths.Bootstrap, ScenePaths.Systems, ScenePaths.WorkingLevel })
{
if (!File.Exists(path))
{
Debug.LogError($"[Scenes] Missing: {path}");
return;
}
}
EditorSceneManager.OpenScene(ScenePaths.Bootstrap, OpenSceneMode.Single);
EditorSceneManager.OpenScene(ScenePaths.Systems, OpenSceneMode.Additive);
var level = EditorSceneManager.OpenScene(ScenePaths.WorkingLevel, OpenSceneMode.Additive);
// The level owns the lighting and is where new objects should land.
EditorSceneManager.SetActiveScene(level);
Debug.Log("[Scenes] Bootstrap + Systems + SC101_ConferenceHall open. Level is active.");
}
[MenuItem(RestoreMenu)]
static void ToggleRestore()
{
var on = !EditorPrefs.GetBool(RestorePrefKey, true);
EditorPrefs.SetBool(RestorePrefKey, on);
Debug.Log($"[Scenes] Restore scene setup after Play: {(on ? "on" : "off")}");
}
[MenuItem(RestoreMenu, true)]
static bool ToggleRestoreValidate()
{
Menu.SetChecked(RestoreMenu, EditorPrefs.GetBool(RestorePrefKey, true));
return true;
}
static void OnPlayModeStateChanged(PlayModeStateChange state)
{
if (!EditorPrefs.GetBool(RestorePrefKey, true))
{
return;
}
if (state == PlayModeStateChange.ExitingEditMode)
{
setupBeforePlay = EditorSceneManager.GetSceneManagerSetup();
return;
}
if (state != PlayModeStateChange.EnteredEditMode || setupBeforePlay == null)
{
return;
}
var setup = setupBeforePlay;
setupBeforePlay = null;
// A scene deleted or renamed while Play was running would throw here, and
// an exception in this callback leaves the Editor in a confusing state.
var usable = setup.Where(s => File.Exists(s.path)).ToArray();
if (usable.Length == 0)
{
return;
}
var current = EditorSceneManager.GetSceneManagerSetup();
if (current.Length == usable.Length &&
current.Select(s => s.path).SequenceEqual(usable.Select(s => s.path)))
{
return; // already what we wanted; do not disturb it
}
try
{
EditorSceneManager.RestoreSceneManagerSetup(usable);
}
catch (System.Exception e)
{
Debug.LogWarning($"[Scenes] Could not restore the pre-Play scene setup: {e.Message}");
}
}
}
}
@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 5bdf044f1ab04312b76895dac1740b37 guid: 0e05a1f05ef74ff7a53f6e24ab37e51e
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2
@@ -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:
@@ -1,316 +0,0 @@
using NightclubArcadia.Cinematics;
using NightclubArcadia.Interaction;
using NightclubArcadia.Player;
using StarterAssets;
using Unity.AI.Navigation;
using Unity.Cinemachine;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.AI;
/// <summary>
/// Wires player control, navigation, and camera systems into DialogueTest.unity.
/// Run via Tools → Nightclub Arcadia → Set Up Player Control &amp; Camera.
/// </summary>
public static class PlayerControlSetup
{
const string ScenePath = "Assets/Scenes/DialogueTest.unity";
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()
{
EnsurePlayerPrefab();
WireScene();
AssetDatabase.SaveAssets();
Debug.Log("[PlayerControlSetup] Player control and camera setup complete.");
}
static void EnsurePlayerPrefab()
{
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(PlayerPrefabPath);
if (prefab == null)
{
Debug.LogError($"[PlayerControlSetup] Missing prefab at {PlayerPrefabPath}");
return;
}
var root = PrefabUtility.LoadPrefabContents(PlayerPrefabPath);
EnsureComponent<PlayerPointerInput>(root);
EnsureComponent<PlayerMotionArbiter>(root);
EnsureComponent<ClickToMoveController>(root);
EnsureComponent<PointerNavigationInput>(root);
EnsureComponent<NavMeshAgent>(root);
var inputs = root.GetComponent<StarterAssetsInputs>();
if (inputs != null)
{
inputs.analogMovement = true;
inputs.cursorLocked = false;
}
var controller = root.GetComponent<ThirdPersonController>();
if (controller != null)
{
controller.LockCameraPosition = true;
}
var clickToMove = root.GetComponent<ClickToMoveController>();
var pointerNav = root.GetComponent<PointerNavigationInput>();
var pointerInput = root.GetComponent<PlayerPointerInput>();
var arbiter = root.GetComponent<PlayerMotionArbiter>();
WireSerializedReference(clickToMove, "brainCamera", null);
WireSerializedReference(pointerNav, "pointerInput", pointerInput);
WireSerializedReference(pointerNav, "clickToMove", clickToMove);
WireSerializedReference(pointerNav, "motionArbiter", arbiter);
PrefabUtility.SaveAsPrefabAsset(root, PlayerPrefabPath);
PrefabUtility.UnloadPrefabContents(root);
}
static void WireScene()
{
var scene = EditorSceneManager.OpenScene(ScenePath, OpenSceneMode.Single);
var player = GameObject.FindGameObjectWithTag("Player");
if (player == null)
{
Debug.LogError("[PlayerControlSetup] No Player-tagged object found in scene.");
return;
}
EnsureComponent<PlayerPointerInput>(player);
EnsureComponent<PlayerMotionArbiter>(player);
EnsureComponent<ClickToMoveController>(player);
EnsureComponent<PointerNavigationInput>(player);
EnsureComponent<NavMeshAgent>(player);
var inputs = player.GetComponent<StarterAssetsInputs>();
if (inputs != null)
{
inputs.analogMovement = true;
inputs.cursorLocked = false;
}
var controller = player.GetComponent<ThirdPersonController>();
if (controller != null)
{
controller.LockCameraPosition = true;
}
var brainCamera = Camera.main;
var pointerInput = player.GetComponent<PlayerPointerInput>();
var clickToMove = player.GetComponent<ClickToMoveController>();
var pointerNav = player.GetComponent<PointerNavigationInput>();
var arbiter = player.GetComponent<PlayerMotionArbiter>();
WireSerializedReference(clickToMove, "brainCamera", brainCamera);
WireSerializedReference(pointerNav, "brainCamera", brainCamera);
WireSerializedReference(pointerNav, "pointerInput", pointerInput);
WireSerializedReference(pointerNav, "clickToMove", clickToMove);
WireSerializedReference(pointerNav, "motionArbiter", arbiter);
var groundLayer = LayerMask.NameToLayer("Ground");
var interactableLayer = LayerMask.NameToLayer("Interactable");
SetLayerIfExists("Floor", groundLayer);
SetLayerIfExists("Room_101", groundLayer);
SetLayerIfExists("Wall_Back", groundLayer);
SetLayerIfExists("Wall_Front", groundLayer);
SetLayerIfExists("Table", groundLayer);
WireBartender("Bartender", interactableLayer);
WireBartender("Bartender (1)", interactableLayer);
EnsureNavigation(player.transform.position);
EnsureCameraAnchor(player.transform, brainCamera);
EditorSceneManager.MarkSceneDirty(scene);
EditorSceneManager.SaveScene(scene);
}
static void WireBartender(string objectName, int interactableLayer)
{
var bartender = GameObject.Find(objectName);
if (bartender == null)
{
return;
}
if (interactableLayer >= 0)
{
bartender.layer = interactableLayer;
}
EnsureComponent<ClickInteractableBridge>(bartender);
EnsureComponent<CameraPointOfInterest>(bartender);
}
static void EnsureNavigation(Vector3 sampleOrigin)
{
var navigation = GameObject.Find("Navigation");
if (navigation == null)
{
navigation = new GameObject("Navigation");
}
var surface = EnsureComponent<NavMeshSurface>(navigation);
surface.agentTypeID = 0;
surface.collectObjects = CollectObjects.All;
surface.useGeometry = NavMeshCollectGeometry.RenderMeshes;
var included = 0;
var defaultLayer = LayerMask.NameToLayer("Default");
var groundLayer = LayerMask.NameToLayer("Ground");
if (defaultLayer >= 0)
{
included |= 1 << defaultLayer;
}
if (groundLayer >= 0)
{
included |= 1 << groundLayer;
}
surface.layerMask = included;
var table = GameObject.Find("Table");
if (table != null)
{
var modifier = EnsureComponent<NavMeshModifier>(table);
modifier.overrideArea = true;
modifier.area = NavMesh.GetAreaFromName("Not Walkable");
}
surface.BuildNavMesh();
if (!NavMesh.SamplePosition(sampleOrigin, out _, 2f, NavMesh.AllAreas))
{
Debug.LogWarning("[PlayerControlSetup] NavMesh bake did not cover the player start position.");
}
}
static void EnsureCameraAnchor(Transform followTarget, Camera brainCamera)
{
var vcamObject = GameObject.Find("CinemachineCamera");
if (vcamObject == null)
{
Debug.LogError("[PlayerControlSetup] CinemachineCamera not found.");
return;
}
var vcam = vcamObject.GetComponent<CinemachineCamera>();
var composer = vcamObject.GetComponent<CinemachinePositionComposer>();
var anchorObject = GameObject.Find("CameraAnchor");
if (anchorObject == null)
{
anchorObject = new GameObject("CameraAnchor");
}
anchorObject.transform.position = followTarget.position;
var anchor = EnsureComponent<CameraRigAnchor>(anchorObject);
EnsureComponent<CameraPanInput>(anchorObject);
EnsureComponent<CameraPointOfInterestDirector>(anchorObject);
EnsureComponent<CameraStateDirector>(anchorObject);
WireSerializedReference(anchor, "followTarget", followTarget);
WireSerializedReference(anchor, "composer", composer);
if (vcam != null)
{
vcam.Target.TrackingTarget = anchorObject.transform;
vcam.Priority.Value = 10;
}
var pan = anchorObject.GetComponent<CameraPanInput>();
WireSerializedReference(pan, "brainCamera", brainCamera);
WireSerializedReference(pan, "anchor", anchor);
WireSerializedReference(pan, "stateDirector", anchorObject.GetComponent<CameraStateDirector>());
var poiDirector = anchorObject.GetComponent<CameraPointOfInterestDirector>();
WireSerializedReference(poiDirector, "anchor", anchor);
WireSerializedReference(poiDirector, "stateDirector", anchorObject.GetComponent<CameraStateDirector>());
var stateDirector = anchorObject.GetComponent<CameraStateDirector>();
WireSerializedReference(stateDirector, "anchor", anchor);
EnsureRevealCamera(vcamObject, followTarget);
}
static void EnsureRevealCamera(GameObject followVcam, Transform followTarget)
{
var revealName = "CM_Reveal_Room101";
var revealObject = GameObject.Find(revealName);
if (revealObject == null)
{
revealObject = new GameObject(revealName);
revealObject.transform.SetPositionAndRotation(
followVcam.transform.position + new Vector3(-4f, 2f, -2f),
followVcam.transform.rotation);
}
var revealCam = EnsureComponent<CinemachineCamera>(revealObject);
revealCam.Target.TrackingTarget = followTarget;
revealCam.Priority.Value = 0;
revealCam.Lens.FieldOfView = followVcam.GetComponent<CinemachineCamera>().Lens.FieldOfView;
var volumeObject = GameObject.Find("RevealVolume_Room101");
if (volumeObject == null)
{
volumeObject = new GameObject("RevealVolume_Room101");
volumeObject.transform.position = followTarget.position + new Vector3(0f, 1f, 2f);
}
var box = EnsureComponent<BoxCollider>(volumeObject);
box.isTrigger = true;
box.size = new Vector3(6f, 3f, 4f);
var volume = EnsureComponent<CameraFramingVolume>(volumeObject);
WireSerializedReference(volume, "revealCamera", revealCam);
}
static T EnsureComponent<T>(GameObject target) where T : Component
{
var component = target.GetComponent<T>();
if (component == null)
{
component = target.AddComponent<T>();
}
return component;
}
static void SetLayerIfExists(string objectName, int layer)
{
if (layer < 0)
{
return;
}
var obj = GameObject.Find(objectName);
if (obj != null)
{
obj.layer = layer;
}
}
static void WireSerializedReference(Object target, string propertyName, Object value)
{
if (target == null)
{
return;
}
var so = new SerializedObject(target);
var property = so.FindProperty(propertyName);
if (property != null)
{
property.objectReferenceValue = value;
so.ApplyModifiedPropertiesWithoutUndo();
}
}
}
@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: eedfabcda58c94099b2ad3e19f141b09
@@ -0,0 +1,22 @@
namespace NightclubArcadia.EditorTools
{
/// <summary>
/// The scene paths the one-shot setup menus operate on.
///
/// These used to be a literal "Assets/Scenes/DialogueTest.unity" repeated in four
/// Editor scripts, which is why renaming the scene meant finding all four. One
/// place now.
/// </summary>
public static class ScenePaths
{
/// <summary>Entry point. Loads Systems, then a level.</summary>
public const string Bootstrap = "Assets/Scenes/Bootstrap.unity";
/// <summary>Persistent systems: dialogue, skills, UI, camera rig, player.</summary>
public const string Systems = "Assets/Scenes/Systems/Systems.unity";
/// <summary>The level scene. SC-101's conference hall.</summary>
public const string WorkingLevel = "Assets/Scenes/Levels/SC101_ConferenceHall.unity";
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3a3f10ec1f9042358ed09c1cdcc345d8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -23,7 +23,7 @@ public static class SkillSystemSetup
const string SkillsFolder = "Assets/Skills"; const string SkillsFolder = "Assets/Skills";
const string BiblePath = "Assets/Skills/skill_bible.json"; const string BiblePath = "Assets/Skills/skill_bible.json";
const string DatabasePath = "Assets/Skills/SkillDatabase.asset"; const string DatabasePath = "Assets/Skills/SkillDatabase.asset";
const string ScenePath = "Assets/Scenes/DialogueTest.unity"; const string ScenePath = NightclubArcadia.EditorTools.ScenePaths.Systems;
const string AutoSetupSessionKey = "NightclubArcadia.SkillSystem.AutoSetupDone"; const string AutoSetupSessionKey = "NightclubArcadia.SkillSystem.AutoSetupDone";
[DidReloadScripts] [DidReloadScripts]
@@ -55,7 +55,7 @@ public static class SkillSystemSetup
/// <summary> /// <summary>
/// Creates/updates ScriptableObject assets without opening a scene. /// Creates/updates ScriptableObject assets without opening a scene.
/// Safe to run on domain reload. Scene wiring stays on the menu item / /// Safe to run on domain reload. Scene wiring stays on the menu item /
/// the checked-in DialogueTest.unity Skill System objects. /// the checked-in Systems.unity Skill System objects.
/// </summary> /// </summary>
static void EnsureSkillAssetsOnly() static void EnsureSkillAssetsOnly()
{ {
@@ -122,9 +122,12 @@ public static class SkillSystemSetup
EditorUtility.SetDirty(database); EditorUtility.SetDirty(database);
AssetDatabase.SaveAssets(); AssetDatabase.SaveAssets();
WireDialogueTestScene(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(); 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) static bool TryLoadRoster(out SkillBibleEntry[] roster)
@@ -230,7 +233,7 @@ public static class SkillSystemSetup
} }
} }
static void WireDialogueTestScene(SkillDatabase database) static void WireWorkingLevelScene(SkillDatabase database)
{ {
if (!File.Exists(ScenePath)) if (!File.Exists(ScenePath))
{ {
@@ -243,7 +246,7 @@ public static class SkillSystemSetup
var runner = UnityEngine.Object.FindAnyObjectByType<DialogueRunner>(); var runner = UnityEngine.Object.FindAnyObjectByType<DialogueRunner>();
if (runner == null) if (runner == null)
{ {
Debug.LogError("No DialogueRunner in DialogueTest.unity."); Debug.LogError("No DialogueRunner in Systems.unity.");
return; return;
} }
@@ -1,818 +0,0 @@
using System.IO;
using NightclubArcadia.Cinematics;
using NightclubArcadia.Dialogue;
using NightclubArcadia.Skills;
using NightclubArcadia.UI;
using NightclubArcadia.UI.Dialogue;
using NightclubArcadia.UI.HUD;
using NightclubArcadia.UI.Menu;
using StarterAssets;
using TMPro;
using Unity.Cinemachine;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.UI;
using Yarn.Unity;
/// <summary>
/// Builds UI prefabs and wires them into DialogueTest.unity.
/// Run via Tools → Nightclub Arcadia → Set Up UI Layer.
/// </summary>
public static class UILayerSetup
{
const string ScenePath = "Assets/Scenes/DialogueTest.unity";
const string PrefabFolder = "Assets/Prefabs/UI";
const string ArtFolder = "Assets/Art/UI/Placeholder";
// Nested Resources folder: UILayerBootstrap builds the HUD at runtime and
// can only reach the sprite through Resources.Load. Keeping it under
// Art/UI/Placeholder preserves the organisation while making it
// build-safe — an AssetDatabase-only path is null outside the editor.
const string PortraitFolder = ArtFolder + "/Resources";
const string PortraitPath = PortraitFolder + "/portrait_placeholder.png";
const string MessageRowPrefabPath = PrefabFolder + "/DialogueMessageRow.prefab";
const string StreamCanvasPrefabPath = PrefabFolder + "/DialogueStreamCanvas.prefab";
const string HudCanvasPrefabPath = PrefabFolder + "/HudCanvas.prefab";
const string SkillRowPrefabPath = PrefabFolder + "/SkillRow.prefab";
const string MenuCanvasPrefabPath = PrefabFolder + "/PlayerMenuCanvas.prefab";
[MenuItem("Tools/Nightclub Arcadia/Set Up UI Layer")]
public static void SetUp()
{
EnsureFolders();
CreatePortraitPlaceholder();
var messageRow = CreateMessageRowPrefab();
var skillRow = CreateSkillRowPrefab();
var streamCanvas = CreateDialogueStreamCanvasPrefab(messageRow);
var hudCanvas = CreateHudCanvasPrefab();
var menuCanvas = CreatePlayerMenuCanvasPrefab(skillRow);
WireScene(streamCanvas, hudCanvas, menuCanvas);
AssetDatabase.SaveAssets();
Debug.Log("[UILayerSetup] UI layer setup complete.");
}
static void EnsureFolders()
{
EnsureFolder("Assets/Prefabs");
EnsureFolder(PrefabFolder);
EnsureFolder("Assets/Art");
EnsureFolder("Assets/Art/UI");
EnsureFolder(ArtFolder);
EnsureFolder(PortraitFolder);
}
static void EnsureFolder(string path)
{
if (AssetDatabase.IsValidFolder(path))
{
return;
}
var parent = Path.GetDirectoryName(path)?.Replace('\\', '/');
var name = Path.GetFileName(path);
if (!string.IsNullOrEmpty(parent) && !string.IsNullOrEmpty(name))
{
AssetDatabase.CreateFolder(parent, name);
}
}
static void CreatePortraitPlaceholder()
{
if (File.Exists(PortraitPath))
{
return;
}
var tex = new Texture2D(512, 512, TextureFormat.RGBA32, false);
var dark = new Color(0.12f, 0.12f, 0.14f, 1f);
var mid = new Color(0.35f, 0.35f, 0.4f, 1f);
for (var y = 0; y < 512; y++)
{
for (var x = 0; x < 512; x++)
{
var dx = (x - 256) / 256f;
var dy = (y - 280) / 256f;
var inHead = dx * dx + dy * dy < 0.12f;
var inBody = Mathf.Abs(dx) < 0.22f && y < 220 && y > 40;
tex.SetPixel(x, y, inHead || inBody ? mid : dark);
}
}
tex.Apply();
File.WriteAllBytes(PortraitPath, tex.EncodeToPNG());
Object.DestroyImmediate(tex);
AssetDatabase.Refresh();
var importer = AssetImporter.GetAtPath(PortraitPath) as TextureImporter;
if (importer != null)
{
importer.textureType = TextureImporterType.Sprite;
importer.spritePixelsPerUnit = 100;
importer.SaveAndReimport();
}
}
static GameObject CreateMessageRowPrefab()
{
var root = new GameObject("DialogueMessageRow", typeof(RectTransform), typeof(DialogueMessageRow));
var rootRt = root.GetComponent<RectTransform>();
rootRt.sizeDelta = new Vector2(0f, 80f);
var layout = root.AddComponent<VerticalLayoutGroup>();
layout.padding = new RectOffset(12, 12, 8, 8);
layout.spacing = 4f;
layout.childControlHeight = true;
layout.childControlWidth = true;
layout.childForceExpandHeight = false;
layout.childForceExpandWidth = true;
var fitter = root.AddComponent<ContentSizeFitter>();
fitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
fitter.horizontalFit = ContentSizeFitter.FitMode.Unconstrained;
var speakerGo = CreateTmp("Speaker", root.transform, 22f, FontStyles.Bold, TextAlignmentOptions.Left);
var bodyGo = CreateTmp("Body", root.transform, 28f, FontStyles.Normal, TextAlignmentOptions.TopLeft);
var row = root.GetComponent<DialogueMessageRow>();
var so = new SerializedObject(row);
so.FindProperty("speakerText").objectReferenceValue = speakerGo.GetComponent<TMP_Text>();
so.FindProperty("bodyText").objectReferenceValue = bodyGo.GetComponent<TMP_Text>();
so.FindProperty("speakerLabel").objectReferenceValue = speakerGo;
so.ApplyModifiedPropertiesWithoutUndo();
var prefab = PrefabUtility.SaveAsPrefabAsset(root, MessageRowPrefabPath);
Object.DestroyImmediate(root);
return prefab;
}
static GameObject CreateSkillRowPrefab()
{
var root = new GameObject("SkillRow", typeof(RectTransform), typeof(SkillRowView));
var rootRt = root.GetComponent<RectTransform>();
rootRt.sizeDelta = new Vector2(0f, 48f);
var hlg = root.AddComponent<HorizontalLayoutGroup>();
hlg.padding = new RectOffset(8, 8, 4, 4);
hlg.spacing = 12f;
hlg.childAlignment = TextAnchor.MiddleLeft;
hlg.childControlHeight = true;
hlg.childControlWidth = true;
hlg.childForceExpandHeight = true;
hlg.childForceExpandWidth = false;
var stripe = CreateUiImage("Accent", root.transform, new Color(1f, 1f, 1f, 1f));
stripe.GetComponent<LayoutElement>().preferredWidth = 6f;
stripe.GetComponent<LayoutElement>().flexibleWidth = 0f;
var nameGo = CreateTmp("Name", root.transform, 24f, FontStyles.Bold, TextAlignmentOptions.Left);
nameGo.GetComponent<LayoutElement>().flexibleWidth = 1f;
var barGo = new GameObject("Bar", typeof(RectTransform), typeof(Image), typeof(LayoutElement));
barGo.transform.SetParent(root.transform, false);
barGo.GetComponent<Image>().color = new Color(0.2f, 0.2f, 0.22f, 1f);
barGo.GetComponent<LayoutElement>().preferredWidth = 160f;
barGo.GetComponent<LayoutElement>().flexibleWidth = 0f;
barGo.GetComponent<LayoutElement>().preferredHeight = 16f;
var fillGo = CreateUiImage("Fill", barGo.transform, Color.white);
var fillRt = fillGo.GetComponent<RectTransform>();
fillRt.anchorMin = Vector2.zero;
fillRt.anchorMax = Vector2.one;
fillRt.offsetMin = Vector2.zero;
fillRt.offsetMax = Vector2.zero;
var fillImage = fillGo.GetComponent<Image>();
fillImage.type = Image.Type.Filled;
fillImage.fillMethod = Image.FillMethod.Horizontal;
fillImage.fillAmount = 0.2f;
Object.DestroyImmediate(fillGo.GetComponent<LayoutElement>());
var rankGo = CreateTmp("Rank", root.transform, 24f, FontStyles.Normal, TextAlignmentOptions.Right);
rankGo.GetComponent<LayoutElement>().preferredWidth = 40f;
rankGo.GetComponent<LayoutElement>().flexibleWidth = 0f;
var view = root.GetComponent<SkillRowView>();
var so = new SerializedObject(view);
so.FindProperty("nameLabel").objectReferenceValue = nameGo.GetComponent<TMP_Text>();
so.FindProperty("rankLabel").objectReferenceValue = rankGo.GetComponent<TMP_Text>();
so.FindProperty("barFill").objectReferenceValue = fillImage;
so.FindProperty("accentStripe").objectReferenceValue = stripe.GetComponent<Image>();
so.ApplyModifiedPropertiesWithoutUndo();
var prefab = PrefabUtility.SaveAsPrefabAsset(root, SkillRowPrefabPath);
Object.DestroyImmediate(root);
return prefab;
}
static GameObject CreateDialogueStreamCanvasPrefab(GameObject messageRowPrefab)
{
var canvasGo = CreateCanvas("DialogueStreamCanvas", 5);
var canvasGroup = canvasGo.AddComponent<CanvasGroup>();
var panel = new GameObject("Panel", typeof(RectTransform), typeof(Image));
panel.transform.SetParent(canvasGo.transform, false);
var panelRt = panel.GetComponent<RectTransform>();
panelRt.anchorMin = new Vector2(0.66f, 0f);
panelRt.anchorMax = new Vector2(1f, 1f);
panelRt.offsetMin = Vector2.zero;
panelRt.offsetMax = Vector2.zero;
panel.GetComponent<Image>().color = new Color(0.05f, 0.05f, 0.08f, 0.92f);
var scrollGo = new GameObject("Scroll", typeof(RectTransform), typeof(ScrollRect), typeof(Image));
scrollGo.transform.SetParent(panel.transform, false);
Stretch(scrollGo.GetComponent<RectTransform>(), 8f);
scrollGo.GetComponent<Image>().color = new Color(0f, 0f, 0f, 0.01f);
var viewport = new GameObject("Viewport", typeof(RectTransform), typeof(RectMask2D), typeof(Image));
viewport.transform.SetParent(scrollGo.transform, false);
Stretch(viewport.GetComponent<RectTransform>());
viewport.GetComponent<Image>().color = new Color(1f, 1f, 1f, 0.01f);
var content = new GameObject("Content", typeof(RectTransform), typeof(VerticalLayoutGroup), typeof(ContentSizeFitter));
content.transform.SetParent(viewport.transform, false);
var contentRt = content.GetComponent<RectTransform>();
contentRt.anchorMin = new Vector2(0f, 0f);
contentRt.anchorMax = new Vector2(1f, 0f);
contentRt.pivot = new Vector2(0.5f, 0f);
contentRt.sizeDelta = new Vector2(0f, 0f);
var vlg = content.GetComponent<VerticalLayoutGroup>();
vlg.childAlignment = TextAnchor.LowerCenter;
vlg.childControlHeight = true;
vlg.childControlWidth = true;
vlg.childForceExpandHeight = false;
vlg.childForceExpandWidth = true;
vlg.spacing = 6f;
vlg.padding = new RectOffset(4, 4, 8, 8);
var csf = content.GetComponent<ContentSizeFitter>();
csf.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
var messages = new GameObject("Messages", typeof(RectTransform), typeof(VerticalLayoutGroup), typeof(ContentSizeFitter));
messages.transform.SetParent(content.transform, false);
ConfigureVerticalContent(messages);
var options = new GameObject("Options", typeof(RectTransform), typeof(VerticalLayoutGroup), typeof(ContentSizeFitter), typeof(CanvasGroup));
options.transform.SetParent(content.transform, false);
ConfigureVerticalContent(options);
var optionsGroup = options.GetComponent<CanvasGroup>();
optionsGroup.alpha = 0f;
optionsGroup.interactable = false;
optionsGroup.blocksRaycasts = false;
var scroll = scrollGo.GetComponent<ScrollRect>();
scroll.content = contentRt;
scroll.viewport = viewport.GetComponent<RectTransform>();
scroll.horizontal = false;
scroll.vertical = true;
scroll.movementType = ScrollRect.MovementType.Clamped;
var streamPresenter = canvasGo.AddComponent<DialogueStreamPresenter>();
var streamSo = new SerializedObject(streamPresenter);
streamSo.FindProperty("messageRowPrefab").objectReferenceValue = messageRowPrefab.GetComponent<DialogueMessageRow>();
streamSo.FindProperty("messageContainer").objectReferenceValue = messages.GetComponent<RectTransform>();
streamSo.FindProperty("scrollRect").objectReferenceValue = scroll;
streamSo.ApplyModifiedPropertiesWithoutUndo();
var optionPrefab = AssetDatabase.LoadAssetAtPath<GameObject>(
"Packages/dev.yarnspinner.unity/Prefabs/Option Item.prefab");
var optionsPresenter = canvasGo.AddComponent<DialogueStreamOptionsPresenter>();
var optSo = new SerializedObject(optionsPresenter);
if (optionPrefab != null)
{
optSo.FindProperty("optionViewPrefab").objectReferenceValue = optionPrefab.GetComponent<OptionItem>();
}
optSo.FindProperty("optionsContainer").objectReferenceValue = options.transform;
optSo.FindProperty("canvasGroup").objectReferenceValue = optionsGroup;
optSo.ApplyModifiedPropertiesWithoutUndo();
// Start hidden — DialogueTransitionController shows it.
canvasGroup.alpha = 0f;
canvasGroup.interactable = false;
canvasGroup.blocksRaycasts = false;
var prefab = PrefabUtility.SaveAsPrefabAsset(canvasGo, StreamCanvasPrefabPath);
Object.DestroyImmediate(canvasGo);
return prefab;
}
static GameObject CreateHudCanvasPrefab()
{
var canvasGo = CreateCanvas("HudCanvas", 10);
var portraitSprite = AssetDatabase.LoadAssetAtPath<Sprite>(PortraitPath);
var panel = new GameObject("PortraitPanel", typeof(RectTransform), typeof(CanvasGroup), typeof(Image), typeof(Button));
panel.transform.SetParent(canvasGo.transform, false);
var panelRt = panel.GetComponent<RectTransform>();
panelRt.anchorMin = new Vector2(1f, 0f);
panelRt.anchorMax = new Vector2(1f, 0f);
panelRt.pivot = new Vector2(1f, 0f);
panelRt.sizeDelta = new Vector2(220f, 280f);
panelRt.anchoredPosition = new Vector2(-24f, 24f);
panel.GetComponent<Image>().color = new Color(0.15f, 0.15f, 0.18f, 0.95f);
if (portraitSprite != null)
{
panel.GetComponent<Image>().sprite = portraitSprite;
panel.GetComponent<Image>().preserveAspect = true;
}
var hint = CreateTmp("TabHint", panel.transform, 18f, FontStyles.Normal, TextAlignmentOptions.Center);
var hintRt = hint.GetComponent<RectTransform>();
hintRt.anchorMin = new Vector2(0f, 0f);
hintRt.anchorMax = new Vector2(1f, 0f);
hintRt.pivot = new Vector2(0.5f, 0f);
hintRt.sizeDelta = new Vector2(0f, 28f);
hintRt.anchoredPosition = new Vector2(0f, 4f);
hint.GetComponent<TMP_Text>().text = "Tab";
Object.DestroyImmediate(hint.GetComponent<LayoutElement>());
var view = canvasGo.AddComponent<PortraitHudView>();
var so = new SerializedObject(view);
so.FindProperty("panelRoot").objectReferenceValue = panel;
so.ApplyModifiedPropertiesWithoutUndo();
var prefab = PrefabUtility.SaveAsPrefabAsset(canvasGo, HudCanvasPrefabPath);
Object.DestroyImmediate(canvasGo);
return prefab;
}
static GameObject CreatePlayerMenuCanvasPrefab(GameObject skillRowPrefab)
{
var canvasGo = CreateCanvas("PlayerMenuCanvas", 20);
var rootGroup = canvasGo.AddComponent<CanvasGroup>();
var dimmer = CreateUiImage("Dimmer", canvasGo.transform, new Color(0f, 0f, 0f, 0.6f));
Stretch(dimmer.GetComponent<RectTransform>());
Object.DestroyImmediate(dimmer.GetComponent<LayoutElement>());
var body = new GameObject("MenuBody", typeof(RectTransform), typeof(Image));
body.transform.SetParent(canvasGo.transform, false);
var bodyRt = body.GetComponent<RectTransform>();
bodyRt.anchorMin = new Vector2(0.15f, 0.1f);
bodyRt.anchorMax = new Vector2(0.85f, 0.9f);
bodyRt.offsetMin = Vector2.zero;
bodyRt.offsetMax = Vector2.zero;
body.GetComponent<Image>().color = new Color(0.08f, 0.08f, 0.1f, 0.98f);
var tabBarGo = new GameObject("TabBar", typeof(RectTransform), typeof(HorizontalLayoutGroup), typeof(MenuTabBar));
tabBarGo.transform.SetParent(body.transform, false);
var tabBarRt = tabBarGo.GetComponent<RectTransform>();
tabBarRt.anchorMin = new Vector2(0f, 1f);
tabBarRt.anchorMax = new Vector2(1f, 1f);
tabBarRt.pivot = new Vector2(0.5f, 1f);
tabBarRt.sizeDelta = new Vector2(0f, 56f);
tabBarRt.anchoredPosition = Vector2.zero;
var tabHlg = tabBarGo.GetComponent<HorizontalLayoutGroup>();
tabHlg.spacing = 8f;
tabHlg.padding = new RectOffset(12, 12, 8, 8);
// childControl* default to FALSE on a script-added layout group. Left
// false, each tab button keeps its own 100px sizeDelta ("Character"
// clips to "Charact") and childForceExpandWidth dumps all the leftover
// room between them as a gap instead of widening them.
tabHlg.childControlWidth = true;
tabHlg.childControlHeight = true;
tabHlg.childForceExpandWidth = true;
tabHlg.childForceExpandHeight = true;
var contentArea = new GameObject("ContentArea", typeof(RectTransform));
contentArea.transform.SetParent(body.transform, false);
var contentRt = contentArea.GetComponent<RectTransform>();
contentRt.anchorMin = new Vector2(0f, 0f);
contentRt.anchorMax = new Vector2(1f, 1f);
contentRt.offsetMin = new Vector2(16f, 16f);
contentRt.offsetMax = new Vector2(-16f, -64f);
var characterPanel = CreateTabPanel("CharacterPanel", contentArea.transform);
var skillsPanel = CreateTabPanel("SkillsPanel", contentArea.transform);
var journalPanel = CreateTabPanel("JournalPanel", contentArea.transform);
// Character content
var charView = characterPanel.AddComponent<CharacterPanelView>();
var nameLabel = CreateTmp("Name", characterPanel.transform, 36f, FontStyles.Bold, TextAlignmentOptions.Left);
var aliasLabel = CreateTmp("Alias", characterPanel.transform, 28f, FontStyles.Italic, TextAlignmentOptions.Left);
var invLabel = CreateTmp("Inventory", characterPanel.transform, 24f, FontStyles.Normal, TextAlignmentOptions.Left);
var charVlg = characterPanel.AddComponent<VerticalLayoutGroup>();
charVlg.spacing = 12f;
charVlg.padding = new RectOffset(8, 8, 8, 8);
charVlg.childControlWidth = true;
charVlg.childControlHeight = true;
charVlg.childForceExpandWidth = true;
charVlg.childForceExpandHeight = false;
var charSo = new SerializedObject(charView);
charSo.FindProperty("nameLabel").objectReferenceValue = nameLabel.GetComponent<TMP_Text>();
charSo.FindProperty("aliasLabel").objectReferenceValue = aliasLabel.GetComponent<TMP_Text>();
charSo.FindProperty("inventoryPlaceholder").objectReferenceValue = invLabel.GetComponent<TMP_Text>();
charSo.ApplyModifiedPropertiesWithoutUndo();
// Skills content
var skillsScroll = new GameObject("SkillsScroll", typeof(RectTransform), typeof(ScrollRect));
skillsScroll.transform.SetParent(skillsPanel.transform, false);
Stretch(skillsScroll.GetComponent<RectTransform>());
var skillsViewport = new GameObject("Viewport", typeof(RectTransform), typeof(RectMask2D), typeof(Image));
skillsViewport.transform.SetParent(skillsScroll.transform, false);
Stretch(skillsViewport.GetComponent<RectTransform>());
skillsViewport.GetComponent<Image>().color = new Color(1f, 1f, 1f, 0.01f);
var skillsContent = new GameObject("Content", typeof(RectTransform), typeof(VerticalLayoutGroup), typeof(ContentSizeFitter));
skillsContent.transform.SetParent(skillsViewport.transform, false);
ConfigureVerticalContent(skillsContent);
var skillsContentRt = skillsContent.GetComponent<RectTransform>();
skillsContentRt.anchorMin = new Vector2(0f, 1f);
skillsContentRt.anchorMax = new Vector2(1f, 1f);
skillsContentRt.pivot = new Vector2(0.5f, 1f);
var skillsScrollRect = skillsScroll.GetComponent<ScrollRect>();
skillsScrollRect.content = skillsContentRt;
skillsScrollRect.viewport = skillsViewport.GetComponent<RectTransform>();
skillsScrollRect.horizontal = false;
var axisHeaderTemplate = CreateTmp("AxisHeaderTemplate", skillsContent.transform, 20f, FontStyles.Bold, TextAlignmentOptions.Left);
axisHeaderTemplate.SetActive(false);
var skillsView = skillsPanel.AddComponent<SkillsPanelView>();
var skillsSo = new SerializedObject(skillsView);
skillsSo.FindProperty("contentRoot").objectReferenceValue = skillsContentRt;
skillsSo.FindProperty("rowPrefab").objectReferenceValue = skillRowPrefab.GetComponent<SkillRowView>();
skillsSo.FindProperty("axisHeaderPrefab").objectReferenceValue = axisHeaderTemplate.GetComponent<TMP_Text>();
skillsSo.FindProperty("displayMaxRank").intValue = 6;
skillsSo.ApplyModifiedPropertiesWithoutUndo();
// Journal content
var journalView = journalPanel.AddComponent<JournalPanelView>();
var journalLabel = CreateTmp("Placeholder", journalPanel.transform, 28f, FontStyles.Italic, TextAlignmentOptions.Center);
Stretch(journalLabel.GetComponent<RectTransform>());
Object.DestroyImmediate(journalLabel.GetComponent<LayoutElement>());
var journalSo = new SerializedObject(journalView);
journalSo.FindProperty("placeholderLabel").objectReferenceValue = journalLabel.GetComponent<TMP_Text>();
journalSo.ApplyModifiedPropertiesWithoutUndo();
var charBtn = CreateTabButton("Character", tabBarGo.transform);
var skillsBtn = CreateTabButton("Skills", tabBarGo.transform);
var journalBtn = CreateTabButton("Journal", tabBarGo.transform);
var tabBar = tabBarGo.GetComponent<MenuTabBar>();
var tabSo = new SerializedObject(tabBar);
var tabsProp = tabSo.FindProperty("tabs");
tabsProp.arraySize = 3;
// Character tab must refresh on show for the same reason as Skills:
// panels toggle via CanvasGroup, so OnEnable never fires again.
SetTabEntry(tabsProp.GetArrayElementAtIndex(0), charBtn.GetComponent<Button>(), characterPanel.GetComponent<CanvasGroup>(), charView, "Refresh");
SetTabEntry(tabsProp.GetArrayElementAtIndex(1), skillsBtn.GetComponent<Button>(), skillsPanel.GetComponent<CanvasGroup>(), skillsView, "Refresh");
SetTabEntry(tabsProp.GetArrayElementAtIndex(2), journalBtn.GetComponent<Button>(), journalPanel.GetComponent<CanvasGroup>(), null);
tabSo.ApplyModifiedPropertiesWithoutUndo();
var menuController = canvasGo.AddComponent<PlayerMenuController>();
var menuSo = new SerializedObject(menuController);
menuSo.FindProperty("menuRoot").objectReferenceValue = canvasGo;
menuSo.FindProperty("tabBar").objectReferenceValue = tabBar;
menuSo.ApplyModifiedPropertiesWithoutUndo();
rootGroup.alpha = 0f;
rootGroup.interactable = false;
rootGroup.blocksRaycasts = false;
var prefab = PrefabUtility.SaveAsPrefabAsset(canvasGo, MenuCanvasPrefabPath);
Object.DestroyImmediate(canvasGo);
return prefab;
}
static void SetTabEntry(SerializedProperty entry, Button button, CanvasGroup panel, Object target, string method = null)
{
entry.FindPropertyRelative("button").objectReferenceValue = button;
entry.FindPropertyRelative("panel").objectReferenceValue = panel;
if (target != null && method != null)
{
var onShown = entry.FindPropertyRelative("onShown");
onShown.FindPropertyRelative("m_PersistentCalls.m_Calls").arraySize = 1;
var call = onShown.FindPropertyRelative("m_PersistentCalls.m_Calls").GetArrayElementAtIndex(0);
call.FindPropertyRelative("m_Target").objectReferenceValue = target;
call.FindPropertyRelative("m_MethodName").stringValue = method;
call.FindPropertyRelative("m_Mode").enumValueIndex = 1; // Void
call.FindPropertyRelative("m_CallState").enumValueIndex = 2; // RuntimeOnly
}
}
static void WireScene(GameObject streamCanvasPrefab, GameObject hudCanvasPrefab, GameObject menuCanvasPrefab)
{
var scene = EditorSceneManager.OpenScene(ScenePath, OpenSceneMode.Single);
// UI System root
var uiSystem = GameObject.Find("UI System");
if (uiSystem == null)
{
uiSystem = new GameObject("UI System");
}
if (uiSystem.GetComponent<UIStateController>() == null)
{
uiSystem.AddComponent<UIStateController>();
}
// Player components
var player = GameObject.Find("PlayerArmature");
if (player == null)
{
Debug.LogError("[UILayerSetup] PlayerArmature not found in scene.");
return;
}
var controlLock = player.GetComponent<PlayerControlLock>();
if (controlLock == null)
{
controlLock = player.AddComponent<PlayerControlLock>();
}
var menuInput = player.GetComponent<PlayerMenuInput>();
if (menuInput == null)
{
menuInput = player.AddComponent<PlayerMenuInput>();
}
var inputs = player.GetComponent<StarterAssetsInputs>();
if (inputs != null)
{
inputs.cursorLocked = false;
EditorUtility.SetDirty(inputs);
}
// DialogueTransitionController
var transition = Object.FindFirstObjectByType<DialogueTransitionController>();
if (transition != null)
{
var tSo = new SerializedObject(transition);
tSo.FindProperty("controlLock").objectReferenceValue = controlLock;
tSo.ApplyModifiedPropertiesWithoutUndo();
}
// Instantiate / refresh UI prefab instances
var streamInstance = EnsurePrefabInstance(streamCanvasPrefab, "DialogueStreamCanvas");
var hudInstance = EnsurePrefabInstance(hudCanvasPrefab, "HudCanvas");
var menuInstance = EnsurePrefabInstance(menuCanvasPrefab, "PlayerMenuCanvas");
// Wire menu controller refs
var menuController = menuInstance.GetComponent<PlayerMenuController>();
if (menuController != null)
{
var mSo = new SerializedObject(menuController);
mSo.FindProperty("menuInput").objectReferenceValue = menuInput;
mSo.FindProperty("controlLock").objectReferenceValue = controlLock;
mSo.ApplyModifiedPropertiesWithoutUndo();
}
// Portrait → Open menu
var portraitButton = hudInstance.GetComponentInChildren<Button>(true);
if (portraitButton != null && menuController != null)
{
while (portraitButton.onClick.GetPersistentEventCount() > 0)
{
UnityEditor.Events.UnityEventTools.RemovePersistentListener(portraitButton.onClick, 0);
}
UnityEditor.Events.UnityEventTools.AddPersistentListener(portraitButton.onClick, menuController.Open);
EditorUtility.SetDirty(portraitButton);
}
// Camera framing
var vcam = GameObject.Find("CinemachineCamera");
if (vcam != null)
{
var framing = vcam.GetComponent<DialogueCameraFraming>();
if (framing == null)
{
framing = vcam.AddComponent<DialogueCameraFraming>();
}
var composer = vcam.GetComponent<CinemachinePositionComposer>();
var fSo = new SerializedObject(framing);
fSo.FindProperty("composer").objectReferenceValue = composer;
fSo.FindProperty("dialogueScreenX").floatValue = -0.17f;
fSo.ApplyModifiedPropertiesWithoutUndo();
}
// Re-point DialogueRunner presenters
var runner = Object.FindFirstObjectByType<DialogueRunner>();
var streamPresenter = streamInstance.GetComponent<DialogueStreamPresenter>();
var optionsPresenter = streamInstance.GetComponent<DialogueStreamOptionsPresenter>();
var lineAdvancer = Object.FindFirstObjectByType<LineAdvancer>();
if (runner != null && streamPresenter != null && optionsPresenter != null)
{
var rSo = new SerializedObject(runner);
var presenters = rSo.FindProperty("dialoguePresenters");
if (presenters != null)
{
presenters.arraySize = lineAdvancer != null ? 3 : 2;
presenters.GetArrayElementAtIndex(0).objectReferenceValue = streamPresenter;
presenters.GetArrayElementAtIndex(1).objectReferenceValue = optionsPresenter;
if (lineAdvancer != null)
{
presenters.GetArrayElementAtIndex(2).objectReferenceValue = lineAdvancer;
}
rSo.ApplyModifiedPropertiesWithoutUndo();
}
}
if (lineAdvancer != null && streamPresenter != null)
{
var aSo = new SerializedObject(lineAdvancer);
aSo.FindProperty("presenter").objectReferenceValue = streamPresenter;
aSo.ApplyModifiedPropertiesWithoutUndo();
}
// Point DialogueTransitionController.dialogueUI at the new canvas
if (transition != null && streamInstance != null)
{
var tSo = new SerializedObject(transition);
tSo.FindProperty("dialogueUI").objectReferenceValue = streamInstance;
tSo.FindProperty("controlLock").objectReferenceValue = controlLock;
tSo.ApplyModifiedPropertiesWithoutUndo();
}
// Deactivate the package Dialogue System Canvas (keep EventSystem alive)
var dialogueSystem = GameObject.Find("Dialogue System");
if (dialogueSystem != null)
{
var packageCanvas = dialogueSystem.transform.Find("Canvas");
if (packageCanvas != null)
{
// Rescue the Skill Check Banner onto the scene-owned Skill Check
// Canvas — NOT into streamInstance. EnsurePrefabInstance
// DestroyImmediates the stream canvas on every re-run, so
// anything parented under it dies with it; that is what left
// SkillRuntime.resultView null after the second setup run.
// Skill Check Canvas is scene-owned, survives re-runs, and its
// sortingOrder 100 already draws above the dialogue canvas.
var banner = packageCanvas.Find("Skill Check Banner");
if (banner != null)
{
var bannerHost = GameObject.Find("Skill Check Canvas");
if (bannerHost != null)
{
banner.SetParent(bannerHost.transform, false);
}
}
packageCanvas.gameObject.SetActive(false);
}
}
// Repair SkillRuntime.resultView. It can be left dangling by an earlier
// run of this menu item, and a null here silently disables every roll
// banner ("SkillCheckResultView is not assigned; skipping roll banner").
// Prefer an active view if more than one survives.
SkillCheckResultView resultView = null;
foreach (var candidate in Object.FindObjectsByType<SkillCheckResultView>(
FindObjectsInactive.Include, FindObjectsSortMode.None))
{
if (resultView == null
|| (!resultView.gameObject.activeInHierarchy && candidate.gameObject.activeInHierarchy))
{
resultView = candidate;
}
}
var skillRuntime = Object.FindFirstObjectByType<SkillRuntime>();
if (skillRuntime != null && resultView != null)
{
var skillSo = new SerializedObject(skillRuntime);
skillSo.FindProperty("resultView").objectReferenceValue = resultView;
skillSo.ApplyModifiedPropertiesWithoutUndo();
}
else if (skillRuntime != null)
{
Debug.LogWarning("[UILayerSetup] No SkillCheckResultView found in the scene; roll banners will not display.", skillRuntime);
}
// Update NPCStandIn dialogueUI refs to the new canvas
foreach (var npc in Object.FindObjectsByType<NPCStandIn>(FindObjectsInactive.Include, FindObjectsSortMode.None))
{
var so = new SerializedObject(npc);
var uiProp = so.FindProperty("dialogueUI");
if (uiProp != null)
{
uiProp.objectReferenceValue = streamInstance;
so.ApplyModifiedPropertiesWithoutUndo();
}
}
EditorSceneManager.MarkSceneDirty(scene);
EditorSceneManager.SaveScene(scene);
}
static GameObject EnsurePrefabInstance(GameObject prefab, string name)
{
var existing = GameObject.Find(name);
if (existing != null)
{
Object.DestroyImmediate(existing);
}
var instance = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
instance.name = name;
return instance;
}
static GameObject CreateCanvas(string name, int sortingOrder)
{
var go = new GameObject(name, typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster));
var canvas = go.GetComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
canvas.sortingOrder = sortingOrder;
var scaler = go.GetComponent<CanvasScaler>();
scaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
scaler.referenceResolution = new Vector2(1920f, 1080f);
scaler.matchWidthOrHeight = 0.5f;
return go;
}
static GameObject CreateTabPanel(string name, Transform parent)
{
var go = new GameObject(name, typeof(RectTransform), typeof(CanvasGroup));
go.transform.SetParent(parent, false);
Stretch(go.GetComponent<RectTransform>());
var group = go.GetComponent<CanvasGroup>();
group.alpha = 0f;
group.interactable = false;
group.blocksRaycasts = false;
return go;
}
static GameObject CreateTabButton(string label, Transform parent)
{
var go = new GameObject(label, typeof(RectTransform), typeof(Image), typeof(Button), typeof(LayoutElement));
go.transform.SetParent(parent, false);
go.GetComponent<Image>().color = new Color(0.2f, 0.2f, 0.25f, 1f);
var text = CreateTmp("Label", go.transform, 22f, FontStyles.Bold, TextAlignmentOptions.Center);
Stretch(text.GetComponent<RectTransform>());
Object.DestroyImmediate(text.GetComponent<LayoutElement>());
text.GetComponent<TMP_Text>().text = label;
return go;
}
static GameObject CreateTmp(string name, Transform parent, float size, FontStyles style, TextAlignmentOptions align)
{
var go = new GameObject(name, typeof(RectTransform), typeof(TextMeshProUGUI), typeof(LayoutElement));
go.transform.SetParent(parent, false);
var tmp = go.GetComponent<TextMeshProUGUI>();
tmp.fontSize = size;
tmp.fontStyle = style;
tmp.alignment = align;
tmp.color = Color.white;
tmp.text = name;
tmp.textWrappingMode = TextWrappingModes.Normal;
// Deliberately no LayoutElement.preferredHeight. A fixed height here is
// one line's worth, and LayoutElement outranks TMP's own ILayoutElement
// report — so a wrapped 4-line body would be allocated ~40px while
// rendering ~150px, and consecutive rows draw on top of each other.
// Leaving it at the -1 default lets TMP measure the wrapped text.
// The component stays so callers can still set preferredWidth /
// flexibleWidth (see the skill row).
return go;
}
static GameObject CreateUiImage(string name, Transform parent, Color color)
{
var go = new GameObject(name, typeof(RectTransform), typeof(Image), typeof(LayoutElement));
go.transform.SetParent(parent, false);
go.GetComponent<Image>().color = color;
return go;
}
static void Stretch(RectTransform rt, float pad = 0f)
{
rt.anchorMin = Vector2.zero;
rt.anchorMax = Vector2.one;
rt.offsetMin = new Vector2(pad, pad);
rt.offsetMax = new Vector2(-pad, -pad);
}
static void ConfigureVerticalContent(GameObject go)
{
var rt = go.GetComponent<RectTransform>();
rt.anchorMin = new Vector2(0f, 0f);
rt.anchorMax = new Vector2(1f, 0f);
rt.pivot = new Vector2(0.5f, 0f);
// A RectTransform added via `new GameObject(..., typeof(RectTransform))`
// starts at sizeDelta (100,100). With horizontal-stretch anchors that
// makes the rect parentWidth + 100 wide, centred — overhanging 50px off
// each side, and the RectMask2D shears the left edge off every label.
// ContentSizeFitter only governs the vertical axis, so it never
// corrects this. Zero the horizontal size explicitly.
rt.sizeDelta = new Vector2(0f, rt.sizeDelta.y);
rt.anchoredPosition = Vector2.zero;
var vlg = go.GetComponent<VerticalLayoutGroup>();
vlg.childControlHeight = true;
vlg.childControlWidth = true;
vlg.childForceExpandHeight = false;
vlg.childForceExpandWidth = true;
vlg.spacing = 4f;
var csf = go.GetComponent<ContentSizeFitter>();
csf.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
}
}
@@ -1,48 +0,0 @@
using UnityEditor;
using UnityEngine;
/// <summary>
/// Reminds the user to run the one-shot prefab/scene wiring menu after scripts
/// compile. Runtime play works without it via UILayerBootstrap.
/// </summary>
[InitializeOnLoad]
static class UILayerSetupAutoRun
{
const string PrefKey = "NightclubArcadia.UILayerSetup.Reminded";
const string MarkerPrefab = "Assets/Prefabs/UI/PlayerMenuCanvas.prefab";
static UILayerSetupAutoRun()
{
EditorApplication.delayCall += RemindIfNeeded;
}
static void RemindIfNeeded()
{
if (EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isCompiling)
{
return;
}
if (AssetDatabase.LoadAssetAtPath<GameObject>(MarkerPrefab) != null)
{
return;
}
if (EditorPrefs.GetBool(PrefKey, false))
{
return;
}
EditorPrefs.SetBool(PrefKey, true);
Debug.Log(
"[UILayer] Prefabs not built yet. Play Mode works via UILayerBootstrap. " +
"To author prefabs into the scene, run Tools → Nightclub Arcadia → Set Up UI Layer.");
}
[MenuItem("Tools/Nightclub Arcadia/Reset UI Layer Auto-Setup Flag")]
static void ResetFlag()
{
EditorPrefs.DeleteKey(PrefKey);
Debug.Log("[UILayer] Reminder flag cleared.");
}
}
@@ -1,80 +0,0 @@
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 = "Assets/Scenes/DialogueTest.unity";
[MenuItem("Tools/Nightclub Arcadia/Set Up Yarn Dialogue Test")]
public static void SetUpYarnDialogueTest()
{
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();
runner.autoStart = true;
runner.startNode = "Start";
EditorUtility.SetDirty(runner);
#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}");
}
}
@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 6d9af60546b8c47c892a7b924fd4c91e
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1d48f257d1ed84378baccde7a64adf41
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,539 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &4737069642952972654
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1722946503423415487}
- component: {fileID: 8432845660793814868}
- component: {fileID: 6335817353128072766}
- component: {fileID: 2944890677120165287}
m_Layer: 0
m_Name: Prompt
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1722946503423415487
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4737069642952972654}
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: 172386393200463862}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0.7}
m_SizeDelta: {x: 1.5, y: 0.4}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!23 &8432845660793814868
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4737069642952972654}
m_Enabled: 1
m_CastShadows: 0
m_ReceiveShadows: 0
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_MaskInteraction: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!114 &6335817353128072766
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4737069642952972654}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshPro
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:
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: 0.92156863, b: 0.015686275, 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: 3
m_fontSizeBase: 3
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
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: 0
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
_SortingLayer: 0
_SortingLayerID: 0
_SortingOrder: 0
m_hasFontAssetChanged: 0
m_renderer: {fileID: 8432845660793814868}
m_maskType: 0
--- !u!114 &2944890677120165287
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4737069642952972654}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 10b4e7c1069944b49acca9287528f275, type: 3}
m_Name:
m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.Interaction.InteractionPrompt
--- !u!1 &7322328536378480179
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4239915935349831280}
- component: {fileID: 5807897220633392622}
- component: {fileID: 2641391509207732614}
- component: {fileID: 2690437797691371565}
m_Layer: 0
m_Name: Label
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &4239915935349831280
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7322328536378480179}
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: 172386393200463862}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 1.2}
m_SizeDelta: {x: 2, y: 0.5}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!23 &5807897220633392622
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7322328536378480179}
m_Enabled: 1
m_CastShadows: 0
m_ReceiveShadows: 0
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_MaskInteraction: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!114 &2641391509207732614
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7322328536378480179}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshPro
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: Bartender
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: 4
m_fontSizeBase: 4
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
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: 0
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
_SortingLayer: 0
_SortingLayerID: 0
_SortingOrder: 0
m_hasFontAssetChanged: 0
m_renderer: {fileID: 5807897220633392622}
m_maskType: 0
--- !u!114 &2690437797691371565
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7322328536378480179}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5d24ca2949394cc78a1fdde5d83e08c2, type: 3}
m_Name:
m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.Interaction.WorldSpaceLabel
billboard: 1
--- !u!1 &7530910684996007227
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 172386393200463862}
- component: {fileID: 1403734579041167056}
- component: {fileID: 3418223217292734787}
- component: {fileID: 2161798758485273970}
- component: {fileID: 3703434673071649520}
- component: {fileID: 3878869479229240904}
m_Layer: 0
m_Name: Bartender
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &172386393200463862
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7530910684996007227}
serializedVersion: 2
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:
- {fileID: 4239915935349831280}
- {fileID: 1722946503423415487}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!33 &1403734579041167056
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7530910684996007227}
m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
--- !u!135 &3418223217292734787
SphereCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7530910684996007227}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Radius: 0.5
m_Center: {x: 0, y: 0, z: 0}
--- !u!23 &2161798758485273970
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7530910684996007227}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: fa72b8a577b83400c8fe35f9f594fb93, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 1
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_MaskInteraction: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!114 &3703434673071649520
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7530910684996007227}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ba3ce042c3b3457ba101f1c6643b983f, type: 3}
m_Name:
m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.Interaction.DialogueInteractor
definition: {fileID: 11400000, guid: 8ccb543c858f74a969cb025cb3e1f0ea, type: 2}
label: {fileID: 2690437797691371565}
prompt: {fileID: 2944890677120165287}
dialogueUI: {fileID: 0}
--- !u!114 &3878869479229240904
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7530910684996007227}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 7862f80331f384d28b27600075971a77, type: 3}
m_Name:
m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.Cinematics.CameraPointOfInterest
weight: 1
triggerRadius: 8
maxBias: 2.5
extraDistance: 1.5
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c0db6e63cdcba4608a13198c04bfc610
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,137 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Bartender_Placeholder
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap:
RenderType: Opaque
disabledShaderPasses:
- MOTIONVECTORS
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AddPrecomputedVelocity: 0
- _AlphaClip: 0
- _AlphaToMask: 0
- _Blend: 0
- _BlendModePreserveSpecular: 1
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _Cull: 2
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _DstBlendAlpha: 0
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _Metallic: 0
- _OcclusionStrength: 1
- _Parallax: 0.005
- _QueueOffset: 0
- _ReceiveShadows: 1
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 0
- _WorkflowMode: 1
- _XRMotionVectorsPass: 1
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 1, g: 0.92, b: 0.016, a: 1}
- _Color: {r: 1, g: 0.92, b: 0.016, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1
--- !u!114 &9147223334991767282
MonoBehaviour:
m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
version: 10
@@ -1,8 +1,8 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 8105016687592461f977c054a80ce2f2 guid: fa72b8a577b83400c8fe35f9f594fb93
NativeFormatImporter: NativeFormatImporter:
externalObjects: {} externalObjects: {}
mainObjectFileID: 0 mainObjectFileID: 2100000
userData: userData:
assetBundleName: assetBundleName:
assetBundleVariant: assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e8c20d75ae36249ab8379c0e4913f984
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,539 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &777994819892892268
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1239266274743412553}
- component: {fileID: 4457577143334209326}
- component: {fileID: 7850630094993076482}
- component: {fileID: 5006241980557930104}
m_Layer: 0
m_Name: Prompt
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1239266274743412553
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 777994819892892268}
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: 8926026372035049776}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0.7}
m_SizeDelta: {x: 1.5, y: 0.4}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!23 &4457577143334209326
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 777994819892892268}
m_Enabled: 1
m_CastShadows: 0
m_ReceiveShadows: 0
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_MaskInteraction: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!114 &7850630094993076482
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 777994819892892268}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshPro
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:
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: 0.92156863, b: 0.015686275, 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: 3
m_fontSizeBase: 3
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
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: 0
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
_SortingLayer: 0
_SortingLayerID: 0
_SortingOrder: 0
m_hasFontAssetChanged: 0
m_renderer: {fileID: 4457577143334209326}
m_maskType: 0
--- !u!114 &5006241980557930104
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 777994819892892268}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 10b4e7c1069944b49acca9287528f275, type: 3}
m_Name:
m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.Interaction.InteractionPrompt
--- !u!1 &1028094190342798046
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4034517959994022032}
- component: {fileID: 6899414861324739809}
- component: {fileID: 2525172943720193920}
- component: {fileID: 8100187015087210284}
m_Layer: 0
m_Name: Label
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &4034517959994022032
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1028094190342798046}
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: 8926026372035049776}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 1.2}
m_SizeDelta: {x: 2, y: 0.5}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!23 &6899414861324739809
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1028094190342798046}
m_Enabled: 1
m_CastShadows: 0
m_ReceiveShadows: 0
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_MaskInteraction: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!114 &2525172943720193920
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1028094190342798046}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.TextMeshPro::TMPro.TextMeshPro
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: Chair
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: 4
m_fontSizeBase: 4
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
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: 0
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
_SortingLayer: 0
_SortingLayerID: 0
_SortingOrder: 0
m_hasFontAssetChanged: 0
m_renderer: {fileID: 6899414861324739809}
m_maskType: 0
--- !u!114 &8100187015087210284
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1028094190342798046}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 5d24ca2949394cc78a1fdde5d83e08c2, type: 3}
m_Name:
m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.Interaction.WorldSpaceLabel
billboard: 1
--- !u!1 &7280501095255275029
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8926026372035049776}
- component: {fileID: 5837614995048342275}
- component: {fileID: 3813584389814668824}
- component: {fileID: 5825175854856588849}
- component: {fileID: 9133955159482683932}
- component: {fileID: 758253250585826679}
m_Layer: 0
m_Name: Chair
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &8926026372035049776
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7280501095255275029}
serializedVersion: 2
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:
- {fileID: 4034517959994022032}
- {fileID: 1239266274743412553}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!33 &5837614995048342275
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7280501095255275029}
m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
--- !u!135 &3813584389814668824
SphereCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7280501095255275029}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Radius: 0.5
m_Center: {x: 0, y: 0, z: 0}
--- !u!23 &5825175854856588849
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7280501095255275029}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: dcf0462a407634956a12aae26cb9768b, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 1
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_MaskInteraction: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!114 &9133955159482683932
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7280501095255275029}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ba3ce042c3b3457ba101f1c6643b983f, type: 3}
m_Name:
m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.Interaction.DialogueInteractor
definition: {fileID: 11400000, guid: 403e142c457b0412a8c8604a2a9807ed, type: 2}
label: {fileID: 8100187015087210284}
prompt: {fileID: 5006241980557930104}
dialogueUI: {fileID: 0}
--- !u!114 &758253250585826679
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7280501095255275029}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 7862f80331f384d28b27600075971a77, type: 3}
m_Name:
m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.Cinematics.CameraPointOfInterest
weight: 1
triggerRadius: 8
maxBias: 2.5
extraDistance: 1.5
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5f94d8e9cc93d47deb267073aebce344
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,137 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-386927403897027456
MonoBehaviour:
m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Editor::UnityEditor.Rendering.Universal.AssetVersion
version: 10
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Chair_Placeholder
m_Shader: {fileID: 4800000, guid: 933532a4fcc9baf4fa0491de14d08ed7, type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap:
RenderType: Opaque
disabledShaderPasses:
- MOTIONVECTORS
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AddPrecomputedVelocity: 0
- _AlphaClip: 0
- _AlphaToMask: 0
- _Blend: 0
- _BlendModePreserveSpecular: 1
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _Cull: 2
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _DstBlendAlpha: 0
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _Metallic: 0
- _OcclusionStrength: 1
- _Parallax: 0.005
- _QueueOffset: 0
- _ReceiveShadows: 1
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 0
- _WorkflowMode: 1
- _XRMotionVectorsPass: 1
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 0, g: 0, b: 1, a: 1}
- _Color: {r: 0, g: 0, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []
m_AllowLocking: 1
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: dcf0462a407634956a12aae26cb9768b
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:
@@ -51,7 +51,7 @@ MonoBehaviour:
m_EditorHideFlags: 0 m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a7773ea9a6f44798aa98356903037d16, type: 3} m_Script: {fileID: 11500000, guid: a7773ea9a6f44798aa98356903037d16, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: Assembly-CSharp::NightclubArcadia.UI.Dialogue.DialogueMessageRow m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.UI.Dialogue.DialogueMessageRow
speakerText: {fileID: 5900251945930220314} speakerText: {fileID: 5900251945930220314}
bodyText: {fileID: 1670956017877202442} bodyText: {fileID: 1670956017877202442}
speakerLabel: {fileID: 5822252844234204748} speakerLabel: {fileID: 5822252844234204748}
@@ -542,7 +542,7 @@ MonoBehaviour:
m_EditorHideFlags: 0 m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 88cb6495795a4e13ac7fb72343c132af, type: 3} m_Script: {fileID: 11500000, guid: 88cb6495795a4e13ac7fb72343c132af, type: 3}
m_Name: 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} messageRowPrefab: {fileID: 5353601244371665078, guid: 90818ef7dc74247ceb348994755cea86, type: 3}
messageContainer: {fileID: 4838388606347767229} messageContainer: {fileID: 4838388606347767229}
scrollRect: {fileID: 7105587415705135446} scrollRect: {fileID: 7105587415705135446}
@@ -559,7 +559,7 @@ MonoBehaviour:
m_EditorHideFlags: 0 m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 8d86cc99d5b545c4a3fad9e1482031a2, type: 3} m_Script: {fileID: 11500000, guid: 8d86cc99d5b545c4a3fad9e1482031a2, type: 3}
m_Name: 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} optionViewPrefab: {fileID: 2576261519635394347, guid: e605972137b0b4c1399ffb07beae9a9b, type: 3}
optionsContainer: {fileID: 6329947636030823459} optionsContainer: {fileID: 6329947636030823459}
canvasGroup: {fileID: 5117926241503925785} canvasGroup: {fileID: 5117926241503925785}
@@ -252,7 +252,7 @@ MonoBehaviour:
m_EditorHideFlags: 0 m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fd1354ade14b4b1d80da9acac4aa9e12, type: 3} m_Script: {fileID: 11500000, guid: fd1354ade14b4b1d80da9acac4aa9e12, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: Assembly-CSharp::NightclubArcadia.UI.HUD.PortraitHudView m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.UI.HUD.PortraitHudView
panelRoot: {fileID: 4989543578856257477} panelRoot: {fileID: 4989543578856257477}
--- !u!1 &4989543578856257477 --- !u!1 &4989543578856257477
GameObject: GameObject:
@@ -61,7 +61,7 @@ MonoBehaviour:
m_EditorHideFlags: 0 m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 74efa3bf7a354892a401418d8f56fb2b, type: 3} m_Script: {fileID: 11500000, guid: 74efa3bf7a354892a401418d8f56fb2b, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: Assembly-CSharp::NightclubArcadia.UI.Menu.JournalPanelView m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.UI.Menu.JournalPanelView
placeholderLabel: {fileID: 438358810008138731} placeholderLabel: {fileID: 438358810008138731}
--- !u!1 &2044419659697384337 --- !u!1 &2044419659697384337
GameObject: GameObject:
@@ -140,7 +140,7 @@ MonoBehaviour:
m_EditorHideFlags: 0 m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: db83a1a74e0e418881880ca808f68160, type: 3} m_Script: {fileID: 11500000, guid: db83a1a74e0e418881880ca808f68160, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: Assembly-CSharp::NightclubArcadia.UI.Menu.MenuTabBar m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.UI.Menu.MenuTabBar
tabs: tabs:
- button: {fileID: 1673770274793931208} - button: {fileID: 1673770274793931208}
panel: {fileID: 5076829831943889175} panel: {fileID: 5076829831943889175}
@@ -245,7 +245,7 @@ MonoBehaviour:
m_EditorHideFlags: 0 m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ef17c93c7dec4af2ae7ce565c8984de3, type: 3} m_Script: {fileID: 11500000, guid: ef17c93c7dec4af2ae7ce565c8984de3, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: Assembly-CSharp::NightclubArcadia.UI.Menu.CharacterPanelView m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.UI.Menu.CharacterPanelView
nameLabel: {fileID: 8967222838737055253} nameLabel: {fileID: 8967222838737055253}
aliasLabel: {fileID: 4652515771799086270} aliasLabel: {fileID: 4652515771799086270}
inventoryPlaceholder: {fileID: 1990427928476398531} inventoryPlaceholder: {fileID: 1990427928476398531}
@@ -483,7 +483,7 @@ MonoBehaviour:
m_EditorHideFlags: 0 m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 118cc9783dba4b3cac1646d97ebd3998, type: 3} m_Script: {fileID: 11500000, guid: 118cc9783dba4b3cac1646d97ebd3998, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: Assembly-CSharp::NightclubArcadia.UI.Menu.PlayerMenuController m_EditorClassIdentifier: NightclubArcadia.Game::NightclubArcadia.UI.Menu.PlayerMenuController
menuRoot: {fileID: 2249656863633318815} menuRoot: {fileID: 2249656863633318815}
menuInput: {fileID: 0} menuInput: {fileID: 0}
controlLock: {fileID: 0} controlLock: {fileID: 0}
@@ -783,6 +783,143 @@ MonoBehaviour:
m_hasFontAssetChanged: 0 m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0} m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 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 --- !u!1 &3533277334474984255
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@@ -1388,7 +1525,7 @@ RectTransform:
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0 m_ConstrainProportionsScale: 0
m_Children: m_Children:
- {fileID: 3528103284151106981} - {fileID: 1481520485721663919}
m_Father: {fileID: 5714344749226447693} m_Father: {fileID: 5714344749226447693}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMin: {x: 0.5, y: 0.5}
@@ -1605,7 +1742,7 @@ RectTransform:
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0 m_ConstrainProportionsScale: 0
m_Children: m_Children:
- {fileID: 1015917500768946775} - {fileID: 2894368236897154238}
m_Father: {fileID: 5714344749226447693} m_Father: {fileID: 5714344749226447693}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5} m_AnchorMin: {x: 0.5, y: 0.5}
@@ -1873,7 +2010,7 @@ MonoBehaviour:
m_FlexibleWidth: -1 m_FlexibleWidth: -1
m_FlexibleHeight: -1 m_FlexibleHeight: -1
m_LayoutPriority: 1 m_LayoutPriority: 1
--- !u!1 &7644334300092530069 --- !u!1 &7967390318583634950
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
@@ -1881,9 +2018,9 @@ GameObject:
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
serializedVersion: 6 serializedVersion: 6
m_Component: m_Component:
- component: {fileID: 1015917500768946775} - component: {fileID: 1481520485721663919}
- component: {fileID: 4696967337599140493} - component: {fileID: 2759775973399345411}
- component: {fileID: 3131234387202370334} - component: {fileID: 6167893425112707945}
m_Layer: 0 m_Layer: 0
m_Name: Label m_Name: Label
m_TagString: Untagged m_TagString: Untagged
@@ -1891,40 +2028,40 @@ GameObject:
m_NavMeshLayer: 0 m_NavMeshLayer: 0
m_StaticEditorFlags: 0 m_StaticEditorFlags: 0
m_IsActive: 1 m_IsActive: 1
--- !u!224 &1015917500768946775 --- !u!224 &1481520485721663919
RectTransform: RectTransform:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {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_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0 m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []
m_Father: {fileID: 6001922808625371455} m_Father: {fileID: 453386429374550589}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0} m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1} m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0} m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0} m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5} m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &4696967337599140493 --- !u!222 &2759775973399345411
CanvasRenderer: CanvasRenderer:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7644334300092530069} m_GameObject: {fileID: 7967390318583634950}
m_CullTransparentMesh: 1 m_CullTransparentMesh: 1
--- !u!114 &3131234387202370334 --- !u!114 &6167893425112707945
MonoBehaviour: MonoBehaviour:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0} m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0} m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7644334300092530069} m_GameObject: {fileID: 7967390318583634950}
m_Enabled: 1 m_Enabled: 1
m_EditorHideFlags: 0 m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
@@ -1938,7 +2075,7 @@ MonoBehaviour:
m_OnCullStateChanged: m_OnCullStateChanged:
m_PersistentCalls: m_PersistentCalls:
m_Calls: [] m_Calls: []
m_text: Skills m_text: Journal
m_isRightToLeft: 0 m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
@@ -2213,143 +2350,6 @@ MonoBehaviour:
rowPrefab: {fileID: 1141587833647839303, guid: e14f68d6a57ea4945bd93c44202db910, type: 3} rowPrefab: {fileID: 1141587833647839303, guid: e14f68d6a57ea4945bd93c44202db910, type: 3}
axisHeaderPrefab: {fileID: 5719341463139795832} axisHeaderPrefab: {fileID: 5719341463139795832}
displayMaxRank: 6 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 --- !u!1 &9109014941581283762
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
-34
View File
@@ -1,34 +0,0 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fcf7219bab7fe46a1ad266029b2fee19, type: 3}
m_Name: Readme
m_EditorClassIdentifier:
icon: {fileID: 2800000, guid: 727a75301c3d24613a3ebcec4a24c2c8, type: 3}
title: URP Empty Template
sections:
- heading: Welcome to the Universal Render Pipeline
text: This template includes the settings and assets you need to start creating with the Universal Render Pipeline.
linkText:
url:
- heading: URP Documentation
text:
linkText: Read more about URP
url: https://docs.unity3d.com/Packages/com.unity.render-pipelines.universal@latest
- heading: Forums
text:
linkText: Get answers and support
url: https://forum.unity.com/forums/universal-render-pipeline.383/
- heading: Report bugs
text:
linkText: Submit a report
url: https://unity3d.com/unity/qa/bug-reporting
loadedLayout: 1
@@ -0,0 +1,172 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_OcclusionBakeSettings:
smallestOccluder: 5
smallestHole: 0.25
backfaceThreshold: 100
m_SceneGUID: 00000000000000000000000000000000
m_OcclusionCullingData: {fileID: 0}
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 10
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 0
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 13
m_BakeOnSceneLoad: 0
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 1
m_EnableRealtimeLightmaps: 0
m_LightmapEditorSettings:
serializedVersion: 12
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 2
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 512
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 256
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 1
m_PVRDenoiserTypeDirect: 1
m_PVRDenoiserTypeIndirect: 1
m_PVRDenoiserTypeAO: 1
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVREnvironmentMIS: 1
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 1
m_PVRFilteringGaussRadiusAO: 1
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0}
m_LightingSettings: {fileID: 0}
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 3
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
buildHeightMesh: 0
maxJobWorkers: 0
preserveTilesOutsideBounds: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &1325409732
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1325409734}
- component: {fileID: 1325409733}
m_Layer: 0
m_Name: Bootstrap
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &1325409733
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1325409732}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 612d8b8b7afa48d68f187e4d51bae0cd, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::NightclubArcadia.Core.GameBootstrap
systemsScene: Systems
startLevel: SC101_ConferenceHall
--- !u!4 &1325409734
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1325409732}
serializedVersion: 2
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: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1660057539 &9223372036854775807
SceneRoots:
m_ObjectHideFlags: 0
m_Roots:
- {fileID: 1325409734}
@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 99c9720ab356a0642a771bea13969a05 guid: 940e7dc5e84654c9fb808956223fc11e
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}
userData: userData:
Binary file not shown.
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: eaad6a890d839422a94db2c27a839bd9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 55882bf97662d4abbaf3691c8c0c9b4a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because it is too large Load Diff
@@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 67a0ad6ebebd640a59b91b85221b30df guid: a4910059112fe4675827519a3f55afe5
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}
userData: userData:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 73a81211deb844562a24ef6db1dc3c46
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 23800000
userData:
assetBundleName:
assetBundleVariant:
@@ -1,432 +0,0 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
OcclusionCullingSettings:
m_ObjectHideFlags: 0
serializedVersion: 2
m_OcclusionBakeSettings:
smallestOccluder: 5
smallestHole: 0.25
backfaceThreshold: 100
m_SceneGUID: 00000000000000000000000000000000
m_OcclusionCullingData: {fileID: 0}
--- !u!104 &2
RenderSettings:
m_ObjectHideFlags: 0
serializedVersion: 10
m_Fog: 0
m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
m_FogMode: 3
m_FogDensity: 0.01
m_LinearFogStart: 0
m_LinearFogEnd: 300
m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
m_AmbientIntensity: 1
m_AmbientMode: 0
m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
m_HaloStrength: 0.5
m_FlareStrength: 1
m_FlareFadeSpeed: 3
m_HaloTexture: {fileID: 0}
m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
m_DefaultReflectionMode: 0
m_DefaultReflectionResolution: 128
m_ReflectionBounces: 1
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_IndirectSpecularColor: {r: 0.18028378, g: 0.22571412, b: 0.30692285, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
m_ObjectHideFlags: 0
serializedVersion: 12
m_GISettings:
serializedVersion: 2
m_BounceScale: 1
m_IndirectOutputScale: 1
m_AlbedoBoost: 1
m_EnvironmentLightingMode: 0
m_EnableBakedLightmaps: 1
m_EnableRealtimeLightmaps: 0
m_LightmapEditorSettings:
serializedVersion: 12
m_Resolution: 2
m_BakeResolution: 40
m_AtlasSize: 1024
m_AO: 0
m_AOMaxDistance: 1
m_CompAOExponent: 1
m_CompAOExponentDirect: 0
m_ExtractAmbientOcclusion: 0
m_Padding: 2
m_LightmapParameters: {fileID: 0}
m_LightmapsBakeMode: 1
m_TextureCompression: 1
m_ReflectionCompression: 2
m_MixedBakeMode: 2
m_BakeBackend: 1
m_PVRSampling: 1
m_PVRDirectSampleCount: 32
m_PVRSampleCount: 512
m_PVRBounces: 2
m_PVREnvironmentSampleCount: 256
m_PVREnvironmentReferencePointCount: 2048
m_PVRFilteringMode: 1
m_PVRDenoiserTypeDirect: 1
m_PVRDenoiserTypeIndirect: 1
m_PVRDenoiserTypeAO: 1
m_PVRFilterTypeDirect: 0
m_PVRFilterTypeIndirect: 0
m_PVRFilterTypeAO: 0
m_PVREnvironmentMIS: 1
m_PVRCulling: 1
m_PVRFilteringGaussRadiusDirect: 1
m_PVRFilteringGaussRadiusIndirect: 5
m_PVRFilteringGaussRadiusAO: 2
m_PVRFilteringAtrousPositionSigmaDirect: 0.5
m_PVRFilteringAtrousPositionSigmaIndirect: 2
m_PVRFilteringAtrousPositionSigmaAO: 1
m_ExportTrainingData: 0
m_TrainingDataDestination: TrainingData
m_LightProbeSampleCountMultiplier: 4
m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0}
m_LightingSettings: {fileID: 0}
--- !u!196 &4
NavMeshSettings:
serializedVersion: 2
m_ObjectHideFlags: 0
m_BuildSettings:
serializedVersion: 3
agentTypeID: 0
agentRadius: 0.5
agentHeight: 2
agentSlope: 45
agentClimb: 0.4
ledgeDropHeight: 0
maxJumpAcrossDistance: 0
minRegionArea: 2
manualCellSize: 0
cellSize: 0.16666667
manualTileSize: 0
tileSize: 256
buildHeightMesh: 0
maxJobWorkers: 0
preserveTilesOutsideBounds: 0
debug:
m_Flags: 0
m_NavMeshData: {fileID: 0}
--- !u!1 &330585543
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 330585546}
- component: {fileID: 330585545}
- component: {fileID: 330585544}
- component: {fileID: 330585547}
m_Layer: 0
m_Name: Main Camera
m_TagString: MainCamera
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!81 &330585544
AudioListener:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 330585543}
m_Enabled: 1
--- !u!20 &330585545
Camera:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 330585543}
m_Enabled: 1
serializedVersion: 2
m_ClearFlags: 1
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
m_projectionMatrixMode: 1
m_GateFitMode: 2
m_FOVAxisMode: 0
m_Iso: 200
m_ShutterSpeed: 0.005
m_Aperture: 16
m_FocusDistance: 10
m_FocalLength: 50
m_BladeCount: 5
m_Curvature: {x: 2, y: 11}
m_BarrelClipping: 0.25
m_Anamorphism: 0
m_SensorSize: {x: 36, y: 24}
m_LensShift: {x: 0, y: 0}
m_NormalizedViewPortRect:
serializedVersion: 2
x: 0
y: 0
width: 1
height: 1
near clip plane: 0.3
far clip plane: 1000
field of view: 60
orthographic: 0
orthographic size: 5
m_Depth: -1
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingPath: -1
m_TargetTexture: {fileID: 0}
m_TargetDisplay: 0
m_TargetEye: 3
m_HDR: 1
m_AllowMSAA: 1
m_AllowDynamicResolution: 0
m_ForceIntoRT: 0
m_OcclusionCulling: 1
m_StereoConvergence: 10
m_StereoSeparation: 0.022
--- !u!4 &330585546
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 330585543}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1, z: -10}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &330585547
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 330585543}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3}
m_Name:
m_EditorClassIdentifier:
m_RenderShadows: 1
m_RequiresDepthTextureOption: 2
m_RequiresOpaqueTextureOption: 2
m_CameraType: 0
m_Cameras: []
m_RendererIndex: -1
m_VolumeLayerMask:
serializedVersion: 2
m_Bits: 1
m_VolumeTrigger: {fileID: 0}
m_VolumeFrameworkUpdateModeOption: 2
m_RenderPostProcessing: 1
m_Antialiasing: 0
m_AntialiasingQuality: 2
m_StopNaN: 0
m_Dithering: 0
m_ClearDepth: 1
m_AllowXRRendering: 1
m_AllowHDROutput: 1
m_UseScreenCoordOverride: 0
m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0}
m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0}
m_RequiresDepthTexture: 0
m_RequiresColorTexture: 0
m_Version: 2
m_TaaSettings:
quality: 3
frameInfluence: 0.1
jitterScale: 1
mipBias: 0
varianceClampScale: 0.9
contrastAdaptiveSharpening: 0
--- !u!1 &410087039
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 410087041}
- component: {fileID: 410087040}
- component: {fileID: 410087042}
m_Layer: 0
m_Name: Directional Light
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!108 &410087040
Light:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 410087039}
m_Enabled: 1
serializedVersion: 11
m_Type: 1
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_Intensity: 2
m_Range: 10
m_SpotAngle: 30
m_InnerSpotAngle: 21.80208
m_CookieSize: 10
m_Shadows:
m_Type: 2
m_Resolution: -1
m_CustomResolution: -1
m_Strength: 1
m_Bias: 0.05
m_NormalBias: 0.4
m_NearPlane: 0.2
m_CullingMatrixOverride:
e00: 1
e01: 0
e02: 0
e03: 0
e10: 0
e11: 1
e12: 0
e13: 0
e20: 0
e21: 0
e22: 1
e23: 0
e30: 0
e31: 0
e32: 0
e33: 1
m_UseCullingMatrixOverride: 0
m_Cookie: {fileID: 0}
m_DrawHalo: 0
m_Flare: {fileID: 0}
m_RenderMode: 0
m_CullingMask:
serializedVersion: 2
m_Bits: 4294967295
m_RenderingLayerMask: 1
m_Lightmapping: 4
m_LightShadowCasterMode: 0
m_AreaSize: {x: 1, y: 1}
m_BounceIntensity: 1
m_ColorTemperature: 5000
m_UseColorTemperature: 1
m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
m_UseBoundingSphereOverride: 0
m_UseViewFrustumForShadowCasterCull: 1
m_ForceVisible: 0
m_ShadowRadius: 0
m_ShadowAngle: 0
--- !u!4 &410087041
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 410087039}
serializedVersion: 2
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
m_LocalPosition: {x: 0, y: 3, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
--- !u!114 &410087042
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 410087039}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Version: 3
m_UsePipelineSettings: 1
m_AdditionalLightsShadowResolutionTier: 2
m_LightLayerMask: 1
m_RenderingLayers: 1
m_CustomShadowLayers: 0
m_ShadowLayerMask: 1
m_ShadowRenderingLayers: 1
m_LightCookieSize: {x: 1, y: 1}
m_LightCookieOffset: {x: 0, y: 0}
m_SoftShadowQuality: 1
--- !u!1 &832575517
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 832575519}
- component: {fileID: 832575518}
m_Layer: 0
m_Name: Global Volume
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &832575518
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 832575517}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 172515602e62fb746b5d573b38a5fe58, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IsGlobal: 1
priority: 0
blendDistance: 0
weight: 1
sharedProfile: {fileID: 11400000, guid: 10fc4df2da32a41aaa32d77bc913491c, type: 2}
--- !u!4 &832575519
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 832575517}
serializedVersion: 2
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: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1660057539 &9223372036854775807
SceneRoots:
m_ObjectHideFlags: 0
m_Roots:
- {fileID: 330585546}
- {fileID: 410087041}
- {fileID: 832575519}
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a7fa9631487c347788c76d7f8eac9692
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c1fc9f8ca900943ce9f61d41d56bc763
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,49 @@
using System.Collections;
using Unity.Cinemachine;
using UnityEngine;
using NightclubArcadia.Core;
namespace NightclubArcadia.Cinematics
{
/// <summary>
/// Points a CinemachineCamera at the player once the player exists.
///
/// Level cameras — the reveal cameras in particular — used to hold a serialized
/// reference to the PlayerArmature. The player now lives in the Systems scene, so
/// that reference cannot be serialized any more and has to be bound at runtime.
/// </summary>
[RequireComponent(typeof(CinemachineCamera))]
public sealed class CinemachineFollowsPlayer : MonoBehaviour
{
[Tooltip("Also drive LookAt, not just Follow.")]
[SerializeField] bool alsoLookAt;
[Tooltip("Seconds to keep retrying while the Systems scene finishes loading.")]
[SerializeField] float resolveTimeout = 5f;
IEnumerator Start()
{
var cam = GetComponent<CinemachineCamera>();
var deadline = Time.unscaledTime + resolveTimeout;
while (SceneServices.Player == null && Time.unscaledTime < deadline)
{
yield return null;
}
var player = SceneServices.Player;
if (player == null)
{
Debug.LogError($"[CinemachineFollowsPlayer] {name}: no object tagged Player appeared " +
$"within {resolveTimeout}s.", this);
yield break;
}
cam.Follow = player;
if (alsoLookAt)
{
cam.LookAt = player;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1cc7a0e83be949f5974b1f675c37c84e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0a917e0f38654c5d9c73026e20ad3e16
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,65 @@
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace NightclubArcadia.Core
{
/// <summary>
/// The entry point. Loads the persistent Systems scene, then a level, additively.
///
/// Splitting the game across scenes is what lets a level be edited without touching
/// the systems wiring, and stops a corrupted level from taking the dialogue runner,
/// the UI layer and the player with it. The cost is that serialized references
/// cannot cross a scene boundary — Unity nulls those — so the handful of level
/// objects that need a system resolve it at runtime instead. See SceneServices.
/// </summary>
public sealed class GameBootstrap : MonoBehaviour
{
[Tooltip("Persistent scene holding dialogue, skills, UI, the camera rig and the player.")]
[SerializeField] string systemsScene = "Systems";
[Tooltip("Level to open on start. Leave empty to load only the systems layer.")]
[SerializeField] string startLevel = "SC101_ConferenceHall";
IEnumerator Start()
{
yield return LoadIfNeeded(systemsScene);
if (!string.IsNullOrEmpty(startLevel))
{
yield return LoadIfNeeded(startLevel);
var level = SceneManager.GetSceneByName(startLevel);
if (level.IsValid() && level.isLoaded)
{
// The active scene decides where new objects land and which
// lighting settings apply, so it must be the level, not this one.
SceneManager.SetActiveScene(level);
}
}
}
static IEnumerator LoadIfNeeded(string sceneName)
{
if (string.IsNullOrEmpty(sceneName))
{
yield break;
}
var existing = SceneManager.GetSceneByName(sceneName);
if (existing.IsValid() && existing.isLoaded)
{
yield break;
}
var op = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);
if (op == null)
{
Debug.LogError($"[GameBootstrap] '{sceneName}' is not in the build settings.");
yield break;
}
yield return op;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 612d8b8b7afa48d68f187e4d51bae0cd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,61 @@
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.LowLevel;
namespace NightclubArcadia.Core
{
/// <summary>
/// Which input device was most recently active, globally.
///
/// InteractionPrompt — and anything else that shows a button glyph — reads Current
/// to decide between "[F]", "(X)" and "(✕)".
///
/// Requires the Input System package, with Active Input Handling set to
/// "Input System Package (New)" or "Both".
/// </summary>
public static class InputDeviceTracker
{
public enum DeviceType { Keyboard, Xbox, PlayStation, Generic }
public static DeviceType Current { get; private set; } = DeviceType.Keyboard;
[RuntimeInitializeOnLoadMethod]
static void Init()
{
InputSystem.onEvent += OnEvent;
}
static void OnEvent(InputEventPtr eventPtr, InputDevice device)
{
// Only actual state changes — button, stick, key — not every event.
if (!eventPtr.IsA<StateEvent>() && !eventPtr.IsA<DeltaStateEvent>())
{
return;
}
switch (device)
{
case Keyboard:
case Mouse:
Current = DeviceType.Keyboard;
break;
case Gamepad pad:
var name = pad.displayName.ToLowerInvariant();
if (name.Contains("dualshock") || name.Contains("dualsense") || name.Contains("playstation"))
{
Current = DeviceType.PlayStation;
}
else if (name.Contains("xbox") || name.Contains("xinput"))
{
Current = DeviceType.Xbox;
}
else
{
Current = DeviceType.Generic;
}
break;
}
}
}
}
@@ -0,0 +1,16 @@
{
"name": "NightclubArcadia.Core",
"rootNamespace": "NightclubArcadia.Core",
"references": [
"Unity.InputSystem"
],
"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,79 @@
using UnityEngine;
namespace NightclubArcadia.Core
{
/// <summary>
/// Finds objects that live in a different loaded scene.
///
/// Unity cannot serialize a reference across a scene boundary — the Inspector
/// refuses it and any existing reference is nulled when the scenes are split. So a
/// level object that needs the dialogue runner, or the player, has to resolve it at
/// runtime. This is a lookup helper, not a service container: there is no
/// registration step and nothing to keep in sync.
///
/// It is deliberately thin. FindFirstObjectByType is not cheap, so callers cache
/// what they get in Awake rather than calling per frame, and an Inspector-assigned
/// reference always wins — this only fills in what the split left null.
/// </summary>
public static class SceneServices
{
/// <summary>
/// Inspector value if set, otherwise the first one in any loaded scene. Silent:
/// returns null when nothing is found.
///
/// Use this when the answer may legitimately not exist yet — during Awake, for
/// instance, when the scene holding it may not have loaded.
/// </summary>
public static T TryResolve<T>(T assigned) where T : Object
{
if (assigned != null)
{
return assigned;
}
// Include inactive: a system parked inactive at startup is still the object
// we mean, and excluding it produces a confusing "not found" for something
// sitting right there in the hierarchy.
return Object.FindFirstObjectByType<T>(FindObjectsInactive.Include);
}
/// <summary>
/// As TryResolve, but logs an error when nothing is found. Only call this at the
/// point the dependency is actually needed — calling it during Awake reports a
/// failure that may simply be a scene that has not finished loading.
/// </summary>
public static T Resolve<T>(T assigned, Object context, string field) where T : Object
{
var found = TryResolve(assigned);
if (found == null)
{
Debug.LogError(
$"[SceneServices] {context?.name}: could not resolve {field} ({typeof(T).Name}). " +
"Is the Systems scene loaded?", context);
}
return found;
}
static Transform player;
/// <summary>
/// The player transform, by tag, cached. Null between scene loads if the
/// systems scene has not come up yet, so callers must handle null.
/// </summary>
public static Transform Player
{
get
{
if (player == null)
{
var go = GameObject.FindGameObjectWithTag("Player");
player = go != null ? go.transform : null;
}
return player;
}
}
/// <summary>Drop the cache. Call when unloading a scene that held the player.</summary>
public static void Forget() => player = null;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: db6a827f17574ac1b7c92185a089300a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,69 +0,0 @@
using UnityEngine;
using UnityEngine.InputSystem;
using Yarn.Unity;
namespace NightclubArcadia.Dialogue
{
/// <summary>
/// Trigger-zone interactable: player walks in range, presses E, and this
/// starts the given Yarn node. The reverse of DialogueTransitionController's
/// <<enter_environment>> — this is the "step into dialogue" half of the loop.
/// </summary>
public class DialogueInteractable : MonoBehaviour
{
[SerializeField] private DialogueRunner dialogueRunner;
[SerializeField] private GameObject dialogueUI;
[SerializeField] private string yarnNodeName = "Bartender_Chat";
private bool playerInRange;
private InputAction interactAction;
void Awake()
{
interactAction = new InputAction("Interact");
interactAction.AddBinding("<Keyboard>/e");
interactAction.AddBinding("<Gamepad>/buttonNorth");
interactAction.performed += _ =>
{
if (playerInRange)
{
StartConversation();
}
};
}
void OnEnable() => interactAction?.Enable();
void OnDisable() => interactAction?.Disable();
void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Player"))
{
playerInRange = true;
}
}
void OnTriggerExit(Collider other)
{
if (other.CompareTag("Player"))
{
playerInRange = false;
}
}
async void StartConversation()
{
// Player controls are locked by DialogueTransitionController off the
// runner's onDialogueStart event — nothing to do for that here.
if (DialogueUIVisibility.Show(dialogueUI))
{
// Only reached if the UI was found deactivated; give TMP a
// frame to re-cache its Canvas in OnEnable before any text is
// generated.
await Awaitable.NextFrameAsync();
}
await dialogueRunner.StartDialogue(yarnNodeName);
}
}
}
@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 99afbbd28c8054d59a7a0dec94f5ec8f
@@ -11,7 +11,7 @@ namespace NightclubArcadia.Dialogue
/// ///
/// The lock is driven by the DialogueRunner's own lifecycle events rather /// The lock is driven by the DialogueRunner's own lifecycle events rather
/// than by each interactable, so every entry point — auto-started nodes, /// than by each interactable, so every entry point — auto-started nodes,
/// NPCStandIn, DialogueInteractable — gets the same behaviour without /// DialogueInteractor — gets the same behaviour without
/// having to remember to do it. Control locking is delegated to /// having to remember to do it. Control locking is delegated to
/// <see cref="PlayerControlLock"/> so the player menu can hold a second /// <see cref="PlayerControlLock"/> so the player menu can hold a second
/// independent lock without re-enabling movement mid-conversation. /// independent lock without re-enabling movement mid-conversation.
@@ -6,7 +6,7 @@ namespace NightclubArcadia.Dialogue
/// <summary> /// <summary>
/// Shows and hides the dialogue UI *without* deactivating its GameObject. /// Shows and hides the dialogue UI *without* deactivating its GameObject.
/// Forwards to <see cref="PanelVisibility"/> — kept as a thin wrapper so /// Forwards to <see cref="PanelVisibility"/> — kept as a thin wrapper so
/// existing call sites (NPCStandIn, DialogueInteractable, /// existing call sites (DialogueInteractor,
/// DialogueTransitionController) continue to compile unchanged. /// DialogueTransitionController) continue to compile unchanged.
/// </summary> /// </summary>
public static class DialogueUIVisibility public static class DialogueUIVisibility
@@ -1,29 +0,0 @@
using UnityEngine;
namespace NightclubArcadia.Interaction
{
/// <summary>
/// Adapts NPCStandIn to the click-to-interact pipeline without modifying
/// the existing proximity + keypress path.
/// </summary>
public sealed class ClickInteractableBridge : MonoBehaviour, IClickInteractable
{
[SerializeField] NPCStandIn npc;
public Transform ApproachPoint => transform;
public float ApproachRadius => npc != null ? Mathf.Max(0.15f, npc.interactionRange - 0.5f) : 0.15f;
void Awake()
{
if (npc == null)
{
npc = GetComponent<NPCStandIn>();
}
}
public void OnApproached()
{
npc?.Interact();
}
}
}
@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 5257f07d188de44eb9a04ba4d3a65fec
@@ -0,0 +1,170 @@
using NightclubArcadia.Core;
using NightclubArcadia.Dialogue;
using NightclubArcadia.UI;
using UnityEngine;
using UnityEngine.InputSystem;
using Yarn.Unity;
namespace NightclubArcadia.Interaction
{
/// <summary>
/// Anything the player can walk up to and talk to: a character, or an object with
/// something to say.
///
/// Replaces NPCStandIn, which was written to be dropped on a sphere primitive and
/// carried its identity in per-instance public fields. Two objects could claim the
/// same character and disagree, and in practice did — the scene's second "Bartender"
/// was the chair, renamed in the data but not in the hierarchy.
///
/// Identity now comes from an InteractableDefinition asset, so a prefab is the thing
/// and the scene only places it. Also replaces DialogueInteractable, a trigger-zone
/// variant of the same idea that was in no scene at all.
/// </summary>
[RequireComponent(typeof(SphereCollider))]
public sealed class DialogueInteractor : MonoBehaviour, IClickInteractable
{
[Header("Identity")]
[SerializeField] InteractableDefinition definition;
[Header("Presentation (optional)")]
[SerializeField] WorldSpaceLabel label;
[SerializeField] InteractionPrompt prompt;
[Header("Overrides")]
[Tooltip("Leave empty to use the Canvas under the DialogueRunner.")]
[SerializeField] GameObject dialogueUI;
DialogueRunner runner;
Transform player;
InputAction interact;
bool playerInRange;
public Transform ApproachPoint => transform;
public float ApproachRadius =>
definition != null ? Mathf.Max(0.15f, definition.InteractionRange - 0.5f) : 0.15f;
/// <summary>
/// The dialogue runner, resolved on demand and cached only on success.
///
/// Never resolved once in Awake: the runner lives in the Systems scene and this
/// object lives in a level, so it can wake up before the runner exists. Caching a
/// failure there left NPCs permanently mute for the session. See SceneOrderTests.
/// </summary>
public DialogueRunner ResolvedRunner =>
runner != null ? runner : runner = SceneServices.TryResolve<DialogueRunner>(null);
Transform Player =>
player != null ? player : player = SceneServices.Player;
void Awake()
{
if (definition == null)
{
Debug.LogError($"[Interactor] {name} has no InteractableDefinition; it will do nothing.", this);
enabled = false;
return;
}
GetComponent<SphereCollider>().isTrigger = false;
if (label != null)
{
label.gameObject.SetActive(definition.ShowLabel);
label.SetText(definition.DisplayName);
}
prompt?.SetShown(false);
interact = new InputAction("Interact");
interact.AddBinding("<Keyboard>/f");
interact.AddBinding("<Gamepad>/buttonSouth");
interact.performed += _ =>
{
if (playerInRange)
{
Interact();
}
};
}
void OnEnable() => interact?.Enable();
void OnDisable() => interact?.Disable();
void Update()
{
var target = Player;
if (target == null)
{
return;
}
var inRange = Vector3.Distance(transform.position, target.position) <= definition.InteractionRange;
if (inRange == playerInRange)
{
return;
}
playerInRange = inRange;
prompt?.SetShown(inRange);
}
/// <summary>Entry point for both the proximity keypress and click-to-move arrival.</summary>
public void Interact()
{
var dialogue = ResolvedRunner;
if (dialogue == null)
{
Debug.LogError(
$"[Interactor] {definition.DisplayName}: no DialogueRunner in any loaded scene. " +
"It lives in Systems.unity — open Bootstrap, or Tools → Nightclub Arcadia → " +
"Open Game Scenes.", this);
return;
}
if (UIStateController.Instance != null && UIStateController.Instance.IsMenuOpen)
{
return;
}
if (!dialogue.IsDialogueRunning)
{
StartDialogueAsync(dialogue);
}
}
public void OnApproached() => Interact();
async void StartDialogueAsync(DialogueRunner dialogue)
{
// The dialogue UI is hidden when the player leaves a conversation via
// <<enter_environment>>. Make it visible again before the first line renders.
if (DialogueUIVisibility.Show(ResolveDialogueUI(dialogue)))
{
// Only reached if the UI was found deactivated; give TMP a frame to
// re-cache its Canvas in OnEnable before any text is generated.
await Awaitable.NextFrameAsync();
}
await dialogue.StartDialogue(definition.YarnNode);
}
GameObject ResolveDialogueUI(DialogueRunner dialogue)
{
if (dialogueUI != null)
{
return dialogueUI;
}
var canvas = dialogue.GetComponentInChildren<Canvas>(true);
if (canvas == null)
{
Debug.LogWarning(
$"[Interactor] No Canvas under {dialogue.name} for {definition.DisplayName}", this);
return null;
}
return canvas.gameObject;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ba3ce042c3b3457ba101f1c6643b983f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,46 @@
using UnityEngine;
namespace NightclubArcadia.Interaction
{
/// <summary>
/// What a thing in the world is called and which conversation it starts.
///
/// This replaces a set of public fields edited per scene object. The scaffold it
/// grew out of had the name, colour, yarn node, ranges and font sizes all set on
/// each sphere by hand, which meant two objects claiming to be the same character
/// could disagree, and nothing outside the scene could see what existed.
///
/// Generated from Assets/Characters/characters.json — edit the JSON, not the asset.
/// Hand edits are overwritten, the same contract as Skills and Candidates.
/// </summary>
[CreateAssetMenu(menuName = "Nightclub Arcadia/Interactable Definition", order = 30)]
public sealed class InteractableDefinition : ScriptableObject
{
[SerializeField] string id;
[SerializeField] string displayName;
[SerializeField] string yarnNode;
[SerializeField] float interactionRange = 3f;
[Tooltip("Shown as a floating label. Off for scenery that should not announce itself.")]
[SerializeField] bool showLabel = true;
public string Id => id;
public string DisplayName => displayName;
public string YarnNode => yarnNode;
public float InteractionRange => interactionRange;
public bool ShowLabel => showLabel;
#if UNITY_EDITOR
/// <summary>Editor-only, for the generator. Not part of the runtime surface.</summary>
public void EditorSet(string newId, string newDisplayName, string newYarnNode,
float newRange, bool newShowLabel)
{
id = newId;
displayName = newDisplayName;
yarnNode = newYarnNode;
interactionRange = newRange;
showLabel = newShowLabel;
}
#endif
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8f4df63859ea4e39910d900aa7a5510a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,54 @@
using NightclubArcadia.Core;
using TMPro;
using UnityEngine;
namespace NightclubArcadia.Interaction
{
/// <summary>
/// The "[F]" that appears when the player is close enough to interact, showing the
/// glyph for whichever input device was last used.
///
/// Separated from the interactor so the prompt can be positioned and styled in a
/// prefab rather than constructed in code, and so anything else that needs a
/// proximity prompt can reuse it.
/// </summary>
[RequireComponent(typeof(TextMeshPro))]
public sealed class InteractionPrompt : MonoBehaviour
{
TextMeshPro text;
bool shown;
void Awake()
{
text = GetComponent<TextMeshPro>();
SetShown(false);
}
public void SetShown(bool value)
{
shown = value;
if (text != null)
{
text.enabled = value;
}
}
void Update()
{
if (shown && text != null)
{
text.text = GlyphFor(InputDeviceTracker.Current);
}
}
static string GlyphFor(InputDeviceTracker.DeviceType type)
{
switch (type)
{
case InputDeviceTracker.DeviceType.Xbox: return "(X)";
case InputDeviceTracker.DeviceType.PlayStation: return "(✕)";
default: return "[F]";
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 10b4e7c1069944b49acca9287528f275
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,54 @@
using TMPro;
using UnityEngine;
namespace NightclubArcadia.Interaction
{
/// <summary>
/// A floating text label that turns to face the camera.
///
/// Lifted out of NPCStandIn, which created its label in Awake and billboarded it in
/// LateUpdate. That worked, but it meant the text only existed at runtime and could
/// not be seen or positioned in the Editor. This is a normal component on a normal
/// child object, so a prefab can show what it will look like.
/// </summary>
[RequireComponent(typeof(TextMeshPro))]
public sealed class WorldSpaceLabel : MonoBehaviour
{
[SerializeField] bool billboard = true;
TextMeshPro text;
Camera view;
void Awake() => text = GetComponent<TextMeshPro>();
public void SetText(string value)
{
if (text == null)
{
text = GetComponent<TextMeshPro>();
}
text.text = value;
}
void LateUpdate()
{
if (!billboard)
{
return;
}
// Camera.main is a tagged lookup; cache it, but re-acquire if the camera was
// destroyed with a scene, which happens when the Systems scene reloads.
if (view == null)
{
view = Camera.main;
if (view == null)
{
return;
}
}
transform.rotation = Quaternion.LookRotation(transform.position - view.transform.position);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5d24ca2949394cc78a1fdde5d83e08c2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,48 +0,0 @@
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.LowLevel;
/// <summary>
/// Tracks which input device was most recently active, globally, across the whole game.
/// NPCStandIn (and any other UI that shows button prompts) reads InputDeviceTracker.Current
/// to decide whether to show "[F]", "(X)", "(✕)", etc.
/// Requires the Input System package (Window > Package Manager > Input System),
/// and Project Settings > Player > Active Input Handling set to
/// "Input System Package (New)" or "Both".
/// </summary>
public static class InputDeviceTracker
{
public enum DeviceType { Keyboard, Xbox, PlayStation, Generic }
public static DeviceType Current { get; private set; } = DeviceType.Keyboard;
[RuntimeInitializeOnLoadMethod]
static void Init()
{
InputSystem.onEvent += OnEvent;
}
static void OnEvent(InputEventPtr eventPtr, InputDevice device)
{
// Only care about actual state changes (button/stick/key presses), not noise.
if (!eventPtr.IsA<StateEvent>() && !eventPtr.IsA<DeltaStateEvent>()) return;
switch (device)
{
case Keyboard:
case Mouse:
Current = DeviceType.Keyboard;
break;
case Gamepad gp:
string n = gp.displayName.ToLowerInvariant();
if (n.Contains("dualshock") || n.Contains("dualsense") || n.Contains("playstation"))
Current = DeviceType.PlayStation;
else if (n.Contains("xbox") || n.Contains("xinput"))
Current = DeviceType.Xbox;
else
Current = DeviceType.Generic;
break;
}
}
}
@@ -1,205 +0,0 @@
using UnityEngine;
using UnityEngine.InputSystem;
using TMPro;
using Yarn.Unity;
using NightclubArcadia.Dialogue;
using NightclubArcadia.UI;
/// <summary>
/// Drop this on a sphere primitive to use it as a placeholder NPC:
/// - Sets sphere color per-instance
/// - Spawns a floating TextMeshPro name label that billboards to face the camera
/// - Shows a proximity interaction prompt ("[F]", "(X)", "(✕)") that swaps based on
/// the last input device used, via InputDeviceTracker
/// - Press the interact button while in range to start a Yarn Spinner dialogue node
/// Requires: TextMeshPro Essentials imported, Input System package installed,
/// InputDeviceTracker.cs in the project, and a "Player" tag on your player object
/// (or assign the Player field manually in the Inspector).
/// </summary>
[RequireComponent(typeof(SphereCollider))]
public class NPCStandIn : MonoBehaviour
{
[Header("Identity")]
public string npcName = "Unnamed NPC";
public Color npcColor = Color.white;
[Header("Dialogue")]
public DialogueRunner dialogueRunner;
public string yarnStartNode = "Start";
[Tooltip("Optional. Left empty, the Canvas under the DialogueRunner is used.")]
public GameObject dialogueUI;
[Header("Label")]
public float labelHeight = 1.2f;
public float labelFontSize = 4f;
public Color labelColor = Color.white;
[Header("Interaction Prompt")]
public Transform player; // auto-found by "Player" tag if left empty
public float interactionRange = 3f;
public float promptHeight = 0.7f;
public float promptFontSize = 3f;
private TextMeshPro labelText;
private TextMeshPro promptText;
private Renderer rend;
private Camera mainCam;
private InputAction interactAction;
private bool playerInRange;
void Awake()
{
rend = GetComponent<Renderer>();
rend.material.color = npcColor;
mainCam = Camera.main;
if (player == null)
{
GameObject found = GameObject.FindGameObjectWithTag("Player");
if (found != null) player = found.transform;
}
CreateLabel();
CreatePrompt();
interactAction = new InputAction("Interact");
interactAction.AddBinding("<Keyboard>/f");
interactAction.AddBinding("<Gamepad>/buttonSouth");
interactAction.performed += ctx =>
{
if (playerInRange) Interact();
};
}
void OnEnable() => interactAction?.Enable();
void OnDisable() => interactAction?.Disable();
void CreateLabel()
{
GameObject labelObj = new GameObject($"{npcName}_Label");
labelObj.transform.SetParent(transform);
labelObj.transform.localPosition = Vector3.up * labelHeight;
labelText = labelObj.AddComponent<TextMeshPro>();
labelText.text = npcName;
labelText.fontSize = labelFontSize;
labelText.color = labelColor;
labelText.alignment = TextAlignmentOptions.Center;
labelText.rectTransform.sizeDelta = new Vector2(2f, 0.5f);
}
void CreatePrompt()
{
GameObject promptObj = new GameObject($"{npcName}_Prompt");
promptObj.transform.SetParent(transform);
promptObj.transform.localPosition = Vector3.up * promptHeight;
promptText = promptObj.AddComponent<TextMeshPro>();
promptText.fontSize = promptFontSize;
promptText.color = Color.yellow;
promptText.alignment = TextAlignmentOptions.Center;
promptText.rectTransform.sizeDelta = new Vector2(1.5f, 0.4f);
promptObj.SetActive(false); // hidden until player is in range
}
void Update()
{
if (player == null) return;
float dist = Vector3.Distance(transform.position, player.position);
bool inRangeNow = dist <= interactionRange;
if (inRangeNow != playerInRange)
{
playerInRange = inRangeNow;
promptText.gameObject.SetActive(playerInRange);
}
if (playerInRange)
{
promptText.text = GlyphFor(InputDeviceTracker.Current);
}
}
void LateUpdate()
{
if (mainCam == null) return;
if (labelText != null)
labelText.transform.rotation = Quaternion.LookRotation(
labelText.transform.position - mainCam.transform.position);
if (promptText != null)
promptText.transform.rotation = Quaternion.LookRotation(
promptText.transform.position - mainCam.transform.position);
}
static string GlyphFor(InputDeviceTracker.DeviceType type)
{
switch (type)
{
case InputDeviceTracker.DeviceType.Xbox: return "(X)";
case InputDeviceTracker.DeviceType.PlayStation: return "(\u2715)"; // Cross button
default: return "[F]";
}
}
public void Interact()
{
if (dialogueRunner == null)
{
Debug.LogWarning($"[NPCStandIn] No DialogueRunner assigned on {npcName}");
return;
}
if (UIStateController.Instance != null && UIStateController.Instance.IsMenuOpen)
{
return;
}
if (!dialogueRunner.IsDialogueRunning)
{
StartDialogueAsync();
}
}
async void StartDialogueAsync()
{
// The dialogue UI is hidden when the player leaves a conversation via
// <<enter_environment>>. Make it visible again before the runner
// renders its first line.
if (DialogueUIVisibility.Show(ResolveDialogueUI()))
{
// Only reached if the UI was found deactivated; give TMP a frame
// to re-cache its Canvas in OnEnable before any text is generated.
await Awaitable.NextFrameAsync();
}
await dialogueRunner.StartDialogue(yarnStartNode);
}
/// <summary>
/// The Canvas under the DialogueRunner, unless one was assigned explicitly.
/// Resolved at call time (including inactive children) so this works
/// without any per-NPC Inspector wiring.
/// </summary>
GameObject ResolveDialogueUI()
{
if (dialogueUI != null)
{
return dialogueUI;
}
var canvas = dialogueRunner.GetComponentInChildren<Canvas>(true);
if (canvas == null)
{
Debug.LogWarning($"[NPCStandIn] No Canvas found under {dialogueRunner.name} for {npcName}");
return null;
}
dialogueUI = canvas.gameObject;
return dialogueUI;
}
}
@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 23d0ac85377c640a1900cfd13e89c389
@@ -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:
@@ -111,6 +111,12 @@ namespace NightclubArcadia.Player
return false; return false;
} }
if (!agent.isOnNavMesh)
{
pendingInteractable = null;
return false;
}
agent.stoppingDistance = 0.15f; agent.stoppingDistance = 0.15f;
agent.isStopped = false; agent.isStopped = false;
agent.SetDestination(hit.position); agent.SetDestination(hit.position);
@@ -136,6 +142,12 @@ namespace NightclubArcadia.Player
return false; return false;
} }
if (!agent.isOnNavMesh)
{
pendingInteractable = null;
return false;
}
agent.stoppingDistance = Mathf.Max(0.15f, interactable.ApproachRadius); agent.stoppingDistance = Mathf.Max(0.15f, interactable.ApproachRadius);
agent.isStopped = false; agent.isStopped = false;
agent.SetDestination(hit.position); agent.SetDestination(hit.position);
@@ -147,7 +159,11 @@ namespace NightclubArcadia.Player
public void Cancel() public void Cancel()
{ {
if (agent != null) // isOnNavMesh, not just a null check: the agent lives in the Systems scene
// and the NavMesh is baked into the level, so between those two scenes
// loading there is a window where the agent exists but is not on a mesh.
// ResetPath and isStopped both log an error in that state.
if (agent != null && agent.isOnNavMesh)
{ {
agent.ResetPath(); agent.ResetPath();
agent.isStopped = true; agent.isStopped = true;
@@ -198,10 +198,8 @@ namespace NightclubArcadia.UI
SetPrivate(transition, "dialogueUI", canvasGo); SetPrivate(transition, "dialogueUI", canvasGo);
} }
foreach (var npc in FindObjectsByType<NPCStandIn>(FindObjectsInactive.Include, FindObjectsSortMode.None)) // Interactors used to be pushed this canvas here. DialogueInteractor resolves
{ // it from the runner at the point of use instead, so there is nothing to push.
npc.dialogueUI = canvasGo;
}
} }
DialogueMessageRow BuildMessageRowPrefab(Transform parent) DialogueMessageRow BuildMessageRowPrefab(Transform parent)
@@ -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:

Some files were not shown because too many files have changed in this diff Show More