forked from Shardstone/trail-into-darkness
minor fixes
This commit is contained in:
81
AGENTS.md
Normal file
81
AGENTS.md
Normal file
@@ -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
|
||||||
@@ -8,9 +8,9 @@ using Nox.Core;
|
|||||||
using Nox.Platform;
|
using Nox.Platform;
|
||||||
using Nox.Game.UI;
|
using Nox.Game.UI;
|
||||||
using Nox.UI;
|
using Nox.UI;
|
||||||
using ZLinq;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.AddressableAssets;
|
using UnityEngine.AddressableAssets;
|
||||||
|
using ZLinq;
|
||||||
using PlayMode = Nox.Core.PlayMode;
|
using PlayMode = Nox.Core.PlayMode;
|
||||||
|
|
||||||
namespace Nox.Game {
|
namespace Nox.Game {
|
||||||
@@ -84,27 +84,10 @@ namespace Nox.Game {
|
|||||||
inputActions.UI.PauseMenu.Enable();
|
inputActions.UI.PauseMenu.Enable();
|
||||||
Debug.Log("Entering Adventure Play Mode");
|
Debug.Log("Entering Adventure Play Mode");
|
||||||
if(partyDefinition == null) {
|
if(partyDefinition == null) {
|
||||||
var sessions = saveSystem.GetAllSessions().AsValueEnumerable().OrderByDescending(s => s.lastSaveDateUtc).ToList();
|
var restoreResult = NoxSaveData.RestoreSavedData(saveSystem, gameDataState, ref adventureData);
|
||||||
if(sessions.Count == 0) {
|
if(restoreResult == null) {
|
||||||
return;
|
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<NoxSaveData>(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>("EncounterRegistry").WaitForCompletion();
|
encounterRegistry ??= Addressables.LoadAssetAsync<EncounterRegistry>("EncounterRegistry").WaitForCompletion();
|
||||||
@@ -171,7 +154,7 @@ namespace Nox.Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void Tick() {
|
public void Tick() {
|
||||||
if(!IsGameModeInitialized) {
|
if(!IsGameModeInitialized || gameDataState.ActiveParty == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,7 +180,8 @@ namespace Nox.Game {
|
|||||||
return new NoxSavedDataSet {
|
return new NoxSavedDataSet {
|
||||||
activePlayMode = PlayMode.Adventure,
|
activePlayMode = PlayMode.Adventure,
|
||||||
activeParty = partyDefinition,
|
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.Player.Disable();
|
||||||
inputActions.UI.PauseMenu.Disable();
|
inputActions.UI.PauseMenu.Disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose() {
|
public void Dispose() {
|
||||||
|
encounterRegistry = null;
|
||||||
|
scenePrefabs = null;
|
||||||
|
mapRef = null;
|
||||||
|
partyRef = null;
|
||||||
|
mapLocationsReference = null;
|
||||||
|
guiReferences = null;
|
||||||
|
|
||||||
partyGuiView?.Dispose();
|
partyGuiView?.Dispose();
|
||||||
popupSystem?.Dispose();
|
popupSystem?.Dispose();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user