move claude project files into git repo
This commit is contained in:
148
.claude/CLAUDE.md
Normal file
148
.claude/CLAUDE.md
Normal file
@@ -0,0 +1,148 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Interaction
|
||||
|
||||
* ONLY modify code or other files if explicitly asked to do so
|
||||
|
||||
## Project Overview
|
||||
|
||||
Dota Factory is a single-player game that blends a Factorio-style factory builder with
|
||||
DOTA-style wave defence. The player builds a factory on an asteroid — mining ores,
|
||||
transporting materials over belts and splitters, and crafting through a config-defined
|
||||
production tree — to supply shipyards that produce autonomous combat ships. Those ships
|
||||
fight off endless enemy waves advancing from the right. See `docs/concept.md` for the full design.
|
||||
|
||||
|
||||
## Project Structure
|
||||
|
||||
* the project root and the git repository root are the same directory
|
||||
* project requirements can be found at `docs/requirements.md`
|
||||
* architecture decisions can be found at `docs/architecture.md`
|
||||
* game content design (ship/module roster, layout grids, footprint gating) can be found at `docs/content_design.md`
|
||||
* replay/determinism design can be found at `docs/replay_design.md`
|
||||
* balancing rules, targets, tuned numbers, process, and history live under `docs/balancing/`
|
||||
|
||||
Requirements carry stable `REQ-<AREA>-<NAME>` ids. They are cited throughout the code in
|
||||
comments — when changing behavior, find the governing REQ id first and
|
||||
keep the citation accurate.
|
||||
|
||||
## Coding Guidelines
|
||||
|
||||
* avoid duplicate code
|
||||
* do not use the "auto" keyword
|
||||
* use Qt utility data types (like QPoint, QVector3D, QString, etc.)
|
||||
* wrap strings that appear in the UI with Qt's "tr()"
|
||||
* use the EventManager/EventHandler instead of defining own signals and slots
|
||||
* use std::optional if a variable can be "not set"
|
||||
* start the name of a getter method with "get"
|
||||
* don't use abbreviations, except very common ones ("s" for seconds, "min", "max", etc.)
|
||||
* if a variable holds a value that has a unit or if a function returns a value that has a unit, append that unit to the name (e.g. "m_shipVelocity_mps", "getAcceleration_mpss()")
|
||||
* always enclose scopes in braces
|
||||
|
||||
## Build
|
||||
|
||||
Requires CMake 3.14.4+, a C++17 compiler, and Qt 5 (developed against Qt 5.12.3,
|
||||
MSVC 2017 x64; `Qt5_DIR` is cached in `build/CMakeCache.txt`). Needs Qt components
|
||||
Widgets, Network, Multimedia, Charts, Svg, plus OpenGL.
|
||||
|
||||
External dependencies vendored under `src/external/`:
|
||||
* **toml++** — reading TOML config files
|
||||
* **tinyexpr** — evaluating formula strings from config files
|
||||
* **EnTT** — entity registry backing the ship/station/debris simulation
|
||||
* **Catch2** — test framework
|
||||
|
||||
Configure and build (a configured `build/` tree already exists):
|
||||
|
||||
```sh
|
||||
cmake -S . -B build # configure (multi-config VS generator)
|
||||
cmake --build build --config Debug # all targets
|
||||
cmake --build build --config Debug --target DotaFactory_test
|
||||
```
|
||||
|
||||
Targets: `DotaFactory` (app), `DotaFactory_lib`, `DotaFactory_ui`, `DotaFactory_test`,
|
||||
`DotaFactory_balancing`. Executables land in `build/DotaFactory/<Config>/{app,balancing}/`.
|
||||
|
||||
**Adding a source file requires editing CMake.** Every directory under `src/` has its own
|
||||
`CMakeLists.txt` listing files explicitly in `HDRS`/`SRCS` (or `TEST_FILES` for tests) —
|
||||
there is no globbing. A new file that is not registered simply will not compile.
|
||||
|
||||
Config data is not copied: `CONFIG_DIR` is a compile definition pointing at
|
||||
`bin/app/data/config` for the app and balancing tool, and `bin/test/data/config` for
|
||||
tests (a separate fixture set). On Windows the build also junctions `bin/*/data` into the
|
||||
output directories and copies the Qt DLLs.
|
||||
|
||||
Run the app: `build/DotaFactory/Debug/app/DotaFactory.exe`, optionally
|
||||
`--replay <file>` for view-only playback of a recorded run.
|
||||
|
||||
## Tests
|
||||
|
||||
Catch2, single executable, links `lib` only — no QApplication, no display.
|
||||
|
||||
```sh
|
||||
build/DotaFactory/Debug/app/DotaFactory_test.exe # all
|
||||
build/DotaFactory/Debug/app/DotaFactory_test.exe "[belt],[building]" # by tag
|
||||
build/DotaFactory/Debug/app/DotaFactory_test.exe "BeltSystem: *" # by name pattern
|
||||
build/DotaFactory/Debug/app/DotaFactory_test.exe --reporter compact
|
||||
```
|
||||
|
||||
Common tags: `[building] [belt] [behavior] [blueprint] [modules] [config] [wave] [combat]
|
||||
[replay] [determinism] [ship] [debris] [threat] [unlock]`.
|
||||
|
||||
`src/test/SimulationTestAccess.h` is a friend-struct backdoor to `Simulation`'s private
|
||||
mutators; tests use it instead of duplicating the command path. It lives under `src/test`
|
||||
and is deliberately off the lib/ui/app include path.
|
||||
|
||||
## Verification Tools
|
||||
|
||||
Python scripts in `tools/` read the real configs and are the first check
|
||||
after config edits (see `docs/balancing/process.md`):
|
||||
|
||||
* `verify_recipes.py` — recipe-tree closure, visuals coverage, orphan items
|
||||
* `verify_layouts.py` — module footprint gating per hull layout
|
||||
* `threat_report.py` — item/module/ship threat values, ratios, belt feasibility
|
||||
|
||||
The `DotaFactory_balancing` target runs parallel arena simulations from
|
||||
`bin/balancing/data/balancing.toml` for combat-stat tuning.
|
||||
|
||||
## Architecture
|
||||
|
||||
See `docs/architecture.md` for the full write-up. Highlights and the
|
||||
invariants that are easy to break:
|
||||
|
||||
* Strict simulation/presentation split, enforced at the CMake target level: `lib`
|
||||
(sim + config, Qt Core/Gui only — no QtWidgets), `ui` (QtWidgets + QOpenGLWidget),
|
||||
`app` (thin main), `test` (Catch2 against `lib`).
|
||||
* Fixed 30 Hz tick simulation, 60 FPS render, accumulator-driven; game speed is a
|
||||
tick-rate multiplier. All sim quantities are in ticks, never wall-clock seconds.
|
||||
* The tick order in `Simulation::tick()` is load-bearing for determinism — see the
|
||||
Tick Order section of `architecture.md` before reordering systems.
|
||||
* **Command chokepoint:** every sim mutation during play flows through
|
||||
`Simulation::apply(const Command&)` (see `sim/Command.h`, `CommandManager`), so runs can
|
||||
be recorded and replayed. Commands reference stable ids (`BuildingId`, tile coords,
|
||||
choice indices) — never raw `entt::entity` handles. UI code must not call sim mutators
|
||||
directly. Determinism is checksummed (`StateChecksum`) and covered by
|
||||
`DeterminismTest` / `ReplayPlaybackTest`.
|
||||
* Config is loaded once at startup, formulas compiled once via tinyexpr, immutable
|
||||
afterwards; malformed config aborts startup rather than failing mid-game. Restart
|
||||
reloads config from disk (REQ-CFG-RELOAD).
|
||||
* **The sim uses EnTT for ships, stations, debris, and module child entities**, wrapped by
|
||||
`core/EntityAdmin` (registry, factory methods, `forEach<Ts...>` views). Components live
|
||||
in `lib/ecs/component/`, systems in `lib/ecs/system/`. Note: `architecture.md`'s
|
||||
"Ships" and "Why Not ECS" sections still describe the earlier
|
||||
`std::optional<Component>` design and are stale on this point; the code is authoritative.
|
||||
Buildings and the belt subsystem stay outside the entity model.
|
||||
* Ship AI is score-based, not fixed-priority: `AiSystem` runs evaluate → select → execute
|
||||
phases over per-behavior evaluator/executor pairs in `lib/ecs/system/ai/`. Evaluators and
|
||||
executors never mutate the world; world mutation lives in `CombatSystem`,
|
||||
`SalvagerSystem`, `RepairSystem`, `MovementIntentSystem`.
|
||||
* Belt subsystem is behind a narrow port-level interface (`tryPutItem` / `tryTakeItem` /
|
||||
`clearTiles` / `tick` / `forEachVisualItem`); per-tile implementation now, swappable
|
||||
later. No other system asks "what is on tile X".
|
||||
* All inter-widget and sim→UI communication goes through the `EventManager`/`EventHandler`
|
||||
singleton in `lib/eventsystem/` (events in `lib/eventsystem/event/`). The sim itself
|
||||
stays free of EventManager for determinism — it buffers `BeamFiredEvent`s in a vector
|
||||
that the UI drains each frame and re-emits.
|
||||
* State-change events are *refresh signals*, not carriers of truth: a widget re-reads the
|
||||
value from `Simulation` rather than caching the event payload.
|
||||
Reference in New Issue
Block a user