5.7 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
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-frameworkis in manifest but unused - Scene authoring: Individual scenes can be played standalone via
SceneReferencecomponent
Architecture
Dual-Layer State Management
Two layers of state drive the application:
- Game States (
IGameState): Application-level flow —SplashGameState→MainMenuGameState→GameModeGameState- Lifecycle:
EnterGameState()→Tick()/LateTick()→ExitGameState()→Dispose()
- Lifecycle:
- Play Modes (
IPlayMode): Gameplay modes within GameMode — Adventure, Town, Rest, Combat, PauseMenu- Lifecycle:
EnterPlayMode()→Tick()/LateTick()→ExitGameMode()→Dispose()
- Lifecycle:
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.
Boot Sequence
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 folder structure: Nox.Core, Nox.Game, Nox.Input, Nox.Platform, Nox.Util.
Code Layout
Assets/Code/
├── 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
varpreferred (csharp_style_var_*: true:suggestion) — usevarwhen type is apparent- Target-typed
newwhen type is evident (CharacterDefinition c = new()) - No space after keywords in control flow (
if(,for(, notif () - Opening braces on same line (
csharp_new_line_before_open_brace = none) else/catch/finallyon 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),
Iprefix for interfaces - Expression-bodied: yes for properties/accessors/indexers/lambdas; no for constructors/methods/operators/local functions
- No
this.qualifier - Use language keywords over BCL types (
intnotInt32)
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 (e.g.,
menuGameStateData.startGameRequests += handler) - Mixed async patterns: both
async TaskandIEnumeratorcoroutines for async operations