From e7f7da985b82a7968dbaf361e75922f58116c64f Mon Sep 17 00:00:00 2001 From: Sebastian Bularca Date: Fri, 8 May 2026 01:13:30 +0200 Subject: [PATCH] minor fixes --- AGENTS.md | 81 +++++++++++++++++++ .../GameState/PlayModes/AdventurePlayMode.cs | 38 ++++----- 2 files changed, 96 insertions(+), 23 deletions(-) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..a2954ec --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,81 @@ +# AGENTS.md + +## Project + +Nox — Unity 6 party-based RPG. Code lives under `Assets/Code/` with namespaces `Nox.Core`, `Nox.Game`, `Nox.Input`, `Nox.Platform`, `Nox.Util`. In-house packages under `Packages/com.jovian.*` are first-party code, not third-party. + +## Unity & Tools + +- **Unity**: 6000.3.7f1 (C# 9.0, .NET Framework 4.7.1) +- **URP**: 17.3.0 +- **Input System**: 1.18.0 (com.unity.inputsystem) +- **Editor only** — no CI/CD, no CLI build command. Build via Unity Editor → Windows target `Nox.exe`. +- **Solution**: `trail-into-darkness.sln` at root. Rider is primary IDE (`com.unity.ide.rider`). + +## Boot Sequence + +1. `Boot.cs` `[RuntimeInitializeOnLoadMethod]` loads `"Initializer"` addressable prefab (or `"Startup"` scene in FullBoot mode) +2. `EntryPoint.Start()` coroutine initializes platform, creates game states, adds `GameStateRunner` MonoBehaviour +3. `GameStateRunner` ticks current state: `SplashGameState` → `MainMenuGameState` → `GameModeGameState` + +Editor-only: `BootMode.cs` (`Nox.EditorCode`) controls boot mode (Full Boot, Scene Boot, Unity Default). + +## State Architecture + +Dual-layer state: +- **Game States** (`IGameState`): Application flow. Lifecycle: `EnterGameState()` → `Tick()`/`LateTick()` → `ExitGameState()` → `Dispose()` +- **Play Modes** (`IPlayMode`): GameModes inside `GameModeGameState`. Same tick lifecycle. + +Central store: `GameDataState` holds `ActiveGameState`, `ActivePlayMode`, `ActiveParty`, `platformSelector`, `activeSessionId`. + +Scene authoring: `SceneReference` MonoBehaviour per scene sets initial `GameState`. Enables standalone scene playback in editor. + +## Addressable Keys + +Assets loaded by string key. Do not change keys without checking all callers: `"Initializer"`, `"AdventureMapPrefabs"`, `"PauseMenuPrefabs"`, `"AdventureSettings"`, `"CharacterBaseSettings"`, `"PerkRegistry"`, `"CharacterRegistry"`, `"BootstrapReferences"`. + +## Character System + +Factory chain initialized from ScriptableObjects: `CharacterSystemsFactory.Create()` builds `PerkFactory` → `CharacterAttributesFactory` → `CharacterStatsFactory` → `CharacterFactory` → `PartyFactory`. Config loaded via Addressables. + +## Persistence + +`Jovian.SaveSystem` package handles JSON serialization to `Application.persistentDataPath`. Nox wrapper: `NoxSaveData.RestoreSavedData()` loads `NoxSavedDataSet` (playMode, party, position, adventure data, game log). Save slots managed by `SaveSlotManager`. + +## Platform Abstraction + +`IPlatform` interface with `DesktopPlatform` and `UnityEditorPlatform` implementations. Each initializes platform-specific `IInput`. Switched via `PlatformSelector`. + +## In-House Jovian Packages + +- `com.jovian.savesystem` — JSON persistence +- `com.jovian.encounter-system` — data-driven encounters, `IEncounterKind` payloads, `EncounterLink` refs, `QuestProgress` gating. Designer tool: `Jovian → Encounters → Encounter Browser` +- `com.jovian.calendar` — in-game calendar +- `com.jovian.ingame-logging` — runtime game log +- `com.jovian.popup-system` — popup/dialog UI +- `com.jovian.zonesystem` — zone/region management +- `com.jovian.logger` — dev logging +- `com.jovian.utilities` / `com.jovian.inspector-tools` — editor utilities + +## C# Style (from .editorconfig) + +- 4 spaces, LF endings +- `var` preferred when type is apparent +- Target-typed `new()` when type is evident +- No space after keywords in control flow: `if(` not `if (` +- Braces on same line; `else`/`catch`/`finally` on new line +- Block-scoped namespaces, usings outside namespace +- PascalCase types/methods/properties, camelCase all fields (public and private), `I` prefix interfaces +- Expression-bodied: yes for properties/accessors/lambdas; no for constructors/methods/operators/local functions +- No `this.` qualifier; language keywords (`int` not `Int32`) + +## Planning Docs + +Non-trivial features planned in `docs/plans/` as paired files: `{date}-{name}-design.md` + `{date}-{name}-implementation.md`. Check here before starting new feature work. + +## Gotchas + +- No test suite exists despite `com.unity.test-framework` in manifest +- No runtime build/lint/typecheck commands — all validation happens in Unity Editor +- Generated `.csproj` files are Unity output, not source of truth for assembly structure +- `Assets/Code/` is the only code location to modify; never edit `Packages/com.jovian.*` core unless working on that package diff --git a/Assets/Code/GameState/PlayModes/AdventurePlayMode.cs b/Assets/Code/GameState/PlayModes/AdventurePlayMode.cs index da571b0..071d5dc 100644 --- a/Assets/Code/GameState/PlayModes/AdventurePlayMode.cs +++ b/Assets/Code/GameState/PlayModes/AdventurePlayMode.cs @@ -8,9 +8,9 @@ using Nox.Core; using Nox.Platform; using Nox.Game.UI; using Nox.UI; -using ZLinq; using UnityEngine; using UnityEngine.AddressableAssets; +using ZLinq; using PlayMode = Nox.Core.PlayMode; namespace Nox.Game { @@ -84,27 +84,10 @@ namespace Nox.Game { inputActions.UI.PauseMenu.Enable(); Debug.Log("Entering Adventure Play Mode"); if(partyDefinition == null) { - var sessions = saveSystem.GetAllSessions().AsValueEnumerable().OrderByDescending(s => s.lastSaveDateUtc).ToList(); - if(sessions.Count == 0) { - return; + var restoreResult = NoxSaveData.RestoreSavedData(saveSystem, gameDataState, ref adventureData); + if(restoreResult == null) { + Debug.LogError("AdventurePlayMode: no save data found for auto-recovery. Party will be null."); } - - var latestSession = sessions[0]; - var slots = saveSystem.GetSlots(latestSession.sessionId).AsValueEnumerable().OrderByDescending(s => s.timestampUtc).ToList(); - if(slots.Count == 0) { - return; - } - - var latestSlot = slots[0]; - var saveData = saveSystem.Load(latestSlot); - Debug.Log($"Loaded save {latestSlot.DisplayLabel}"); - if(saveData == null) { - Debug.LogError("Failed to load save data"); - return; - } - - NoxSaveData.RestoreSavedData(saveSystem, gameDataState, ref adventureData); - Debug.LogWarning("AdventurePlayMode started from the Adventure Scene. Loading the last Autosave"); } encounterRegistry ??= Addressables.LoadAssetAsync("EncounterRegistry").WaitForCompletion(); @@ -171,7 +154,7 @@ namespace Nox.Game { } public void Tick() { - if(!IsGameModeInitialized) { + if(!IsGameModeInitialized || gameDataState.ActiveParty == null) { return; } @@ -197,7 +180,8 @@ namespace Nox.Game { return new NoxSavedDataSet { activePlayMode = PlayMode.Adventure, activeParty = partyDefinition, - partyPosition = partyRef ? SerializableVector3.FromVector3(partyRef.transform.position) : SerializableVector3.Zero + partyPosition = partyRef ? SerializableVector3.FromVector3(partyRef.transform.position) : SerializableVector3.Zero, + adventureData = this.adventureData }; } @@ -205,7 +189,15 @@ namespace Nox.Game { inputActions.Player.Disable(); inputActions.UI.PauseMenu.Disable(); } + public void Dispose() { + encounterRegistry = null; + scenePrefabs = null; + mapRef = null; + partyRef = null; + mapLocationsReference = null; + guiReferences = null; + partyGuiView?.Dispose(); popupSystem?.Dispose();