added missing assets

This commit is contained in:
Sebastian Bularca
2026-03-22 15:21:28 +01:00
parent 0f0189726e
commit da74abb039
18 changed files with 330 additions and 53 deletions

View File

@@ -9,7 +9,12 @@
"Bash(cmd //c \"where gh\")",
"Bash(\"/c/Program Files/GitHub CLI/gh.exe\" --version)",
"Bash(\"/c/Users/sebas/AppData/Local/GitHub CLI/gh.exe\" --version)",
"Bash(cmd //c \"gh --version\")"
"Bash(cmd //c \"gh --version\")",
"Bash(find /d/repos/trail-into-darkness -maxdepth 2 -type f \\\\\\(-name manifest.json -o -name ProjectSettings.asset -o -name *.yml -o -name *.yaml -o -name *.json \\\\\\))",
"Bash(grep -E \"\\\\.cs$\")",
"Bash(ls -la /d/repos/trail-into-darkness/Assets/Database/Entities/*.asset)",
"Bash(grep -r \"CharacterBaseSettings\\\\|PerkRegistry\\\\|CharacterRegistry\" /d/repos/trail-into-darkness/Assets/AddressableAssetsData --include=*.yaml --include=*.asset)",
"Bash(grep -l \"bc14507c6a9500d4eac9e684e289d084\" /d/repos/trail-into-darkness/Assets/**/*.meta)"
]
}
}

View File

@@ -30,6 +30,11 @@ MonoBehaviour:
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 11a8dc4883c617b46a29d5dfdd4a67d1
m_Address: AdventureSettings
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 13c02b14c4d048fa9653293d54f6e0e1
m_Address: Packages/com.unity.render-pipelines.universal/Shaders/2D/Sprite-Unlit-Default.shader
m_ReadOnly: 0
@@ -60,6 +65,11 @@ MonoBehaviour:
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 5672eb4ca16a50b4c86b7fae03e98a30
m_Address: PerksRegistry
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 60a7c1e10ed7ff94cbe191d9d3e305ed
m_Address: Assets/Art/UI/menu_corner.png
m_ReadOnly: 0
@@ -115,6 +125,11 @@ MonoBehaviour:
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: 9e8339bc69fe33641a8fbc5bffd0ebd5
m_Address: EntitiesBaseSettings
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: a0ee74bf6f853704a8a568d5ef638ee9
m_Address: Assets/TextMesh Pro/Fonts/1529ChampFleuryPro SDF.asset
m_ReadOnly: 0
@@ -136,6 +151,11 @@ MonoBehaviour:
m_SerializedLabels:
- mouse_cursor
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: bc14507c6a9500d4eac9e684e289d084
m_Address: CharacterRegistry
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
- m_GUID: c8578ae5b690b4a43b15e00c4c8314be
m_Address: Assets/Art/Map/map_icon_village.png
m_ReadOnly: 0

View File

@@ -14,12 +14,7 @@ MonoBehaviour:
m_EditorClassIdentifier: Unity.Addressables.Editor::UnityEditor.AddressableAssets.Settings.AddressableAssetGroup
m_GroupName: Default Local Group
m_GUID: 05b724f967e7d40e69a2f8086a7d78cd
m_SerializeEntries:
- m_GUID: 11a8dc4883c617b46a29d5dfdd4a67d1
m_Address: Assets/Database/Game/AdventureSettings.asset
m_ReadOnly: 0
m_SerializedLabels: []
FlaggedDuringContentUpdateRestriction: 0
m_SerializeEntries: []
m_ReadOnly: 0
m_Settings: {fileID: 11400000, guid: 7e98b357dd76a43e191428299c44eef2, type: 2}
m_SchemaSet:

View File

@@ -98,14 +98,17 @@ namespace Nox.Core {
ISaveSlotManager saveSlotManager = new SaveSlotManager(saveStorage, saveSettings);
saveSystem = new SaveSystem(saveSerializer, saveStorage, saveSlotManager, saveSettings);
var adventuredata = new AdventureData();
var characterSystems = DefaultCharacterSystemsFactory.Create(maxPartySize: 4, new PerkRegistry(), new CharacterRegistry());
var adventureData = new AdventureData();
var characterBaseSettings = Addressables.LoadAssetAsync<CharacterBaseSettings>("CharacterBaseSettings").WaitForCompletion();
var perKRegistry = Addressables.LoadAssetAsync<PerkRegistry>("PerkRegistry").WaitForCompletion();
var characterRegistry = Addressables.LoadAssetAsync<CharacterRegistry>("CharacterRegistry").WaitForCompletion();
var characterSystems = DefaultCharacterSystemsFactory.Create(characterBaseSettings, perKRegistry, characterRegistry);
var partyCreatorModel = new PartyCreatorModel(characterSystems.CharacterFactory, characterSystems.PartyFactory);
applicationStates = new Dictionary<GameState, IGameState> {
[GameState.BootState] = new SplashGameState(bootstrapReferences, gameDataState),
[GameState.MainMenu] = new MainMenuGameState(gameDataState, menuGameStateData, bootstrapReferences, saveSystem, partyCreatorModel, adventuredata),
[GameState.GameMode] = new GameModeGameState(gameDataState, bootstrapReferences, platform.PlatformSettings, saveSystem, sceneTransition, adventuredata),
[GameState.MainMenu] = new MainMenuGameState(gameDataState, menuGameStateData, bootstrapReferences, saveSystem, partyCreatorModel, adventureData),
[GameState.GameMode] = new GameModeGameState(gameDataState, bootstrapReferences, platform.PlatformSettings, saveSystem, sceneTransition, adventureData),
};
createApplicationStateMarker.End();
}

View File

@@ -60,7 +60,7 @@ namespace Nox.Core {
gameDataState.ChangePlayMode(sceneReference.playMode);
}
}
advSettingsHandler = Addressables.LoadAssetAsync<AdventureSettings>("Assets/Database/Game/AdventureSettings.asset");
advSettingsHandler = Addressables.LoadAssetAsync<AdventureSettings>("AdventureSettings");
adventureSettings = advSettingsHandler.WaitForCompletion();
InitializeGameViews();
currentPlaymode = gameDataState.ActivePlayMode;

View File

@@ -0,0 +1,42 @@
using System;
using UnityEngine;
namespace Nox.Game {
[CreateAssetMenu(fileName = "EntitiesBaseSettings", menuName = "Nox/Database/Entities/EntitiesBaseSettings")]
public class CharacterBaseSettings: ScriptableObject {
[Header("Character General Defaults")]
public int startAttributesPool = 12;
[Header("Character Creation Defaults")]
public EntityAttributes defaultEntityAttributes;
public EntityStats defaultEntityStats;
public PerksData defaultPerksData;
public ModifiersData defaultModifiersData;
[Header("General Racial Bonuses and Perks per Class")]
public RacialBonuses [] racialBonuses;
public ClassBonuses [] classBonuses;
[Header("Party System Defaults")]
public int maxPartySize = 4;
}
[Serializable]
public sealed class RacialBonuses {
public CharacterRace race;
public EntityAttributes defaultEntityAttributes;
public EntityStats defaultEntityStats;
public PerksData perksData;
public ModifiersData modifiersData;
}
[Serializable]
public sealed class ClassBonuses {
public CharacterClass @class;
public EntityAttributes defaultEntityAttributes;
public EntityStats defaultEntityStats;
public PerksData perksData;
public ModifiersData modifiersData;
}
}

View File

@@ -2,14 +2,14 @@ using System;
namespace Nox.Game {
public static class DefaultCharacterSystemsFactory {
public static ICharacterSystems Create(int maxPartySize, PerkRegistry perkRegistry, CharacterRegistry characterRegistry) {
public static ICharacterSystems Create(CharacterBaseSettings characterBaseSettings, PerkRegistry perkRegistry, CharacterRegistry characterRegistry) {
IPerkFactory perkFactory = new PerkFactory(perkRegistry);
ICharacterAttributesFactory attributesFactory = new CharacterAttributesFactory(characterRegistry);
ICharacterStatsFactory statsFactory = new CharacterStatsFactory();
ICharacterFactory characterFactory = new CharacterFactory(attributesFactory, statsFactory, perkFactory);
IPartyFactory partyFactory = new PartyFactory(new PartyFactoryOptions {
minPartySize = 1,
maxPartySize = maxPartySize,
maxPartySize = characterBaseSettings.maxPartySize,
enforceUniqueCharacterIds = true
});

View File

@@ -1,18 +0,0 @@
using UnityEngine;
namespace Nox.Game {
[CreateAssetMenu(fileName = "EntitiesBaseSettings", menuName = "Nox/Database/Entities/EntitiesBaseSettings")]
public class EntitiesBaseSettings: ScriptableObject {
[Header("Character Creation")]
public int startAttributesPool = 12;
public int startLevel = 1;
public RacialBonus [] racialBonuses;
}
public class RacialBonus {
public CharacterRace race;
public CharacterClass characterClass;
public int bonus;
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: dc417caaee5ca6245ac02ea6fd77fbed
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,35 @@
%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: 91e3086d6951456e9a8a59fcbac0f750, type: 3}
m_Name: CharacterRegistry
m_EditorClassIdentifier: Assembly-CSharp::Nox.Game.CharacterRegistry
defaultCharacter:
id:
displayName:
race: 0
class: 0
role: 0
attributes:
might: 0
reflex: 0
knowledge: 0
perception: 0
stats:
health: 0
stamina: 0
level: 0
experience: 0
perksData:
perks: []
activeModifiers:
modifiers: []
characters: []

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bc14507c6a9500d4eac9e684e289d084
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,32 @@
%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: 1bbecc15c7cd4a7ca90ce17b3d3d75f0, type: 3}
m_Name: EntitiesBaseSettings
m_EditorClassIdentifier: Assembly-CSharp::Nox.Game.CharacterBaseSettings
startAttributesPool: 12
defaultEntityAttributes:
might: 0
reflex: 0
knowledge: 0
perception: 0
defaultEntityStats:
health: 0
stamina: 0
level: 0
experience: 0
defaultPerksData:
perks: []
defaultModifiersData:
modifiers: []
racialBonuses: []
classBonuses: []
maxPartySize: 4

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9e8339bc69fe33641a8fbc5bffd0ebd5
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,16 @@
%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: 0adb42b13ce44d8792247246a49e9c3f, type: 3}
m_Name: PerksRegistry
m_EditorClassIdentifier: Assembly-CSharp::Nox.Game.PerkRegistry
perksData:
perks: []

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5672eb4ca16a50b4c86b7fae03e98a30
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -592,6 +592,38 @@ PrefabInstance:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 836462145768403853, guid: ddc1b5dd628590a4084c1997dd102f62, type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 836462145768403853, guid: ddc1b5dd628590a4084c1997dd102f62, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 836462145768403853, guid: ddc1b5dd628590a4084c1997dd102f62, type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 836462145768403853, guid: ddc1b5dd628590a4084c1997dd102f62, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2124443195524357696, guid: ddc1b5dd628590a4084c1997dd102f62, type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2124443195524357696, guid: ddc1b5dd628590a4084c1997dd102f62, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2124443195524357696, guid: ddc1b5dd628590a4084c1997dd102f62, type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2124443195524357696, guid: ddc1b5dd628590a4084c1997dd102f62, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 2913371113149423864, guid: ddc1b5dd628590a4084c1997dd102f62, type: 3}
propertyPath: m_Name
value: GUI
@@ -676,6 +708,38 @@ PrefabInstance:
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6675701153400291410, guid: ddc1b5dd628590a4084c1997dd102f62, type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6675701153400291410, guid: ddc1b5dd628590a4084c1997dd102f62, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6675701153400291410, guid: ddc1b5dd628590a4084c1997dd102f62, type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6675701153400291410, guid: ddc1b5dd628590a4084c1997dd102f62, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7497223681040273609, guid: ddc1b5dd628590a4084c1997dd102f62, type: 3}
propertyPath: m_AnchorMax.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7497223681040273609, guid: ddc1b5dd628590a4084c1997dd102f62, type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7497223681040273609, guid: ddc1b5dd628590a4084c1997dd102f62, type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7497223681040273609, guid: ddc1b5dd628590a4084c1997dd102f62, type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []

View File

@@ -4,57 +4,108 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Project Overview
Nox is a Unity RPG game with party-based gameplay. It uses Addressables for asset management, Newtonsoft JSON for serialization, and URP for rendering.
Nox is a Unity 6 RPG game (product name "Nox", Windows build target `Nox.exe`). Party-based gameplay with Addressables for asset management, Newtonsoft JSON for serialization, URP 17.3.0 for rendering, and Unity Input System 1.18.0.
## Build & Development
- **Unity version**: 6.0.3 (C# 9.0, .NET Framework 4.7.1)
- **Build output**: `Builds/Nox.exe`
- **No CI/CD pipeline** — builds are done through Unity Editor
- **No test suite exists** — `com.unity.test-framework` is in manifest but unused
- **Scene authoring**: Individual scenes can be played standalone via `SceneReference` component
## Architecture
### Dual-Layer State Management
The game uses two layers of state:
Two layers of state drive the application:
- **Game States** (`IGameState`): Application-level flow — Splash → MainMenu → GameMode (PlayModeGameState)
- **Play Modes** (`IPlayMode`): Gameplay-level modes within GameMode — Adventure, Town, Rest, Combat, PauseMenu
- **Game States** (`IGameState`): Application-level flow — `SplashGameState``MainMenuGameState``GameModeGameState`
- Lifecycle: `EnterGameState()``Tick()` / `LateTick()``ExitGameState()``Dispose()`
- **Play Modes** (`IPlayMode`): Gameplay modes within GameMode — Adventure, Town, Rest, Combat, PauseMenu
- Lifecycle: `EnterPlayMode()``Tick()` / `LateTick()``ExitGameMode()``Dispose()`
`PlayModeGameState` bridges these layers, managing play mode transitions and scene loading via Addressables.
`GameModeGameState` bridges these layers, managing play mode transitions and scene loading via Addressables. `GameStateRunner` (MonoBehaviour) drives the update loop and handles fade-in/fade-out transitions via `ISceneTransition`.
### Key Subsystems
### Boot Sequence
- **Boot/Entry**: `Boot.cs``EntryPoint.cs``GameStateRunner.cs` (main update loop)
- **GameData**: Global state container holding party, map, settings, and current play mode
- **Platform Abstraction**: `IPlatform` with Desktop and UnityEditor implementations, selecting input mode and settings per platform
- **Persistence**: `GamePersistenceController` + `IPlayModeStateSerializer` for JSON save/load
- **Character System**: Attributes (Might, Reflex, Knowledge) → derived Stats (Health, Stamina), with Perks and party Roles (Protagonist + Companions)
`Boot.cs` (`[RuntimeInitializeOnLoadMethod]`) → loads `"Initializer"` prefab via Addressables → `EntryPoint.cs` (MonoBehaviour) loads all config ScriptableObjects, creates game states, initializes platform subsystems and character systems → `GameStateRunner` begins ticking states.
In editor, `Boot.cs` checks `BootMode` preference (Full Boot, Scene Boot, Unity Default).
### GameDataState
Central state container holding current `GameState`, `PlayMode`, `ActiveParty`, `platformSelector`, `activeSessionId`, and `savedPartyPosition`. State changes via `ChangeGameState()` and `ChangePlayMode()`.
### Character System
Factory-based architecture with ScriptableObject configuration:
```
DefaultCharacterSystemsFactory.Create()
├─ PerkFactory (PerkRegistry ScriptableObject)
├─ CharacterAttributesFactory (validates attributes)
├─ CharacterStatsFactory (derives stats from attributes)
├─ CharacterFactory (creates from templates or custom requests)
└─ PartyFactory (assembles: 1 protagonist + companions)
```
- **Data**: `EntityAttributes` (might, reflex, knowledge, perception) → `EntityStats` (health, stamina, level, experience)
- **CharacterDefinition**: ID, DisplayName, Attributes, Stats, Race, Class, Role (Protagonist/Companion), Perks, Modifiers
- **Config ScriptableObjects**: `CharacterBaseSettings`, `PerkRegistry`, `CharacterRegistry`
- **Key interfaces**: `ICharacterSystems`, `ICharacterFactory`, `IPartyFactory`, `IPerkFactory`
### Persistence
`GamePersistenceController` + Jovian.SaveSystem with JSON serialization to `Application.persistentDataPath`. Save data model: `NoxSavedDataSet` (activePlayMode, partyDefinition, partyPosition, adventureData). Save slots managed by `SaveSlotManager`.
### Platform Abstraction
`IPlatform` with `DesktopPlatform` and `UnityEditorPlatform`. Each initializes platform-specific `IInput` (DesktopInput/EditorInput using Unity InputSystem generated code).
### Addressables Asset Keys
Assets loaded by string key: `"Initializer"`, `"AdventureMapPrefabs"`, `"PauseMenuPrefabs"`, `"AdventureSettings"`, `"CharacterBaseSettings"`, `"PerkRegistry"`, `"CharacterRegistry"`, `"BootstrapReferences"`.
### Namespace Convention
Namespaces mirror the folder structure: `Nox.Core`, `Nox.Game`, `Nox.Input`, `Nox.Platform`, `Nox.Util`.
Namespaces mirror folder structure: `Nox.Core`, `Nox.Game`, `Nox.Input`, `Nox.Platform`, `Nox.Util`.
## Code Layout
```
Assets/Code/
├── Core/ # Game states, bootstrapping, GameData, GameStateRunner
├── Game/ # Gameplay: PlayModes/, Camera/, movement, persistence, factories
├── Platform/ # IPlatform, DesktopPlatform, UnityEditorPlatform
├── Input/ # IInput abstraction with Desktop/Editor implementations
├── UI/ # Menu views and MonoBehaviour references
└── Util/ # BootMode, editor utilities
├── Core/ # Boot, EntryPoint, GameStateRunner, IGameState, IPlayMode, GameDataState
├── GameState/
│ ├── Camera/ # CameraController, CameraSettings
│ ├── Entities/ # Character/Party/Perk factories and registries
│ ├── PlayModes/ # AdventurePlayMode, PauseMenuPlayMode, stubs for Town/Rest/Combat
└── UI/ # View implementations (PauseMenu, Adventure views)
├── Input/ # IInput abstraction, Desktop/Editor implementations
├── Platform/ # IPlatform, DesktopPlatform, UnityEditorPlatform
├── SplashMainMenuUI/
└── Util/ # BootMode editor utility
```
## C# Style (from .editorconfig)
- 4 spaces, LF line endings
- **No `var`** — use explicit types (`csharp_style_var_*: false`)
- **`var` preferred** (`csharp_style_var_*: true:suggestion`) — use `var` when type is apparent
- **Target-typed `new`** when type is evident (`CharacterDefinition c = new()`)
- **No space after keywords** in control flow (`if(`, `for(`, not `if (`)
- **Opening braces on same line** (`csharp_new_line_before_open_brace = none`)
- **`else`/`catch`/`finally` on new line** after closing brace
- Block-scoped namespaces (`namespace Foo { ... }`)
- Always use braces (`csharp_prefer_braces = true`)
- Naming: PascalCase for types/methods/properties, camelCase for all fields (public and private), `I` prefix for interfaces
- Expression-bodied: yes for properties/accessors/indexers/lambdas, no for constructors/methods/operators
- Expression-bodied: yes for properties/accessors/indexers/lambdas; no for constructors/methods/operators/local functions
- No `this.` qualifier
- Use language keywords over BCL types (`int` not `Int32`)
## Patterns
- Constructor-based dependency injection (no DI container)
- ScriptableObject-based configuration loaded via Addressables
- Factory pattern for character/party creation
- Action delegates for UI event communication
- Action delegates for UI event communication (e.g., `menuGameStateData.startGameRequests += handler`)
- Mixed async patterns: both `async Task` and `IEnumerator` coroutines for async operations