Add comprehensive design and specification documentation (#1)

* Write the Unreal documentation set: design, steps, ideas, decisions and specs

Rewrites the design and engineering docs of the two earlier Unity projects
(Adventurer Guild, Project Malleable) for an Unreal Engine 5 prototype that
builds and proves three things in order: a movement controller, fighting and
crafting. Neither earlier core loop is carried; their ideas are catalogued as
features with what each needs.

- Docs/Design.md: the human summary (pillars, fixed decisions, glossary)
- Docs/Steps.md: a ladder of fifteen proofs, the first six in full
- Docs/Ideas.md: salvaged ideas from both projects, none scheduled
- Docs/Decisions.md: D-01..D-36, open decisions OD-01..OD-08, deferrals
- Docs/Spec/: notation, Architecture, Movement, Interaction, Combat,
  Crafting, Networking, Telemetry, UI, written as Unreal C++ skeletons
- CLAUDE.md and README.md for the repository


* Add the stat block: one attribute set on every body, every influence an effect

Every body (player, enemy, NPC) carries the same UStatBlockAttributeSet, and
every outside influence on it is a gameplay effect: base values, buffs,
debuffs, ground surfaces, carried weight, gear, being downed. Counters are
tags and attributes on the receiver: immunity blocks by tag, resistance
scales by attribute, cleanse removes by tag. Same status from several
sources: strongest wins; different statuses multiply.

- Docs/Spec/Stats.md: the block, effects and their five sources (abilities,
  areas, surfaces, items, the world), stacking, counters, readers, tests
- Movement: the movement component's tagged speed-multiplier map is removed;
  speed is tuning times the MoveSpeed attribute; the ground surface trace
  turns mud into an effect; the gym gets mud and ice patches
- Combat: the attribute set moves to Stats; enemies and kits carry
  FStatBlockDefaults; the funnel reads MagicResist and Immune.Damage tags;
  taunt and mark are statuses
- Interaction: carried weight is GE_Encumbered against CarryCapacity
- Crafting: class bonuses are the WorkSpeed and WorkQuality attributes;
  enchantments may grant a holder effect
- Steps: step 5 builds the block with mud, a volume and an immunity
- Decisions D-37 and D-38; design summary, CLAUDE.md, indexes, worklog
This commit is contained in:
2026-09-15 17:54:00 +03:00
committed by GitHub
parent abac63da16
commit 0e61a77346
18 changed files with 4026 additions and 0 deletions
+98
View File
@@ -0,0 +1,98 @@
# Decisions
One line per decision, newest first, with a pointer to where it lives in full. A decision belongs here the moment
it is made, even if the doc it affects has not caught up. Never delete an entry; supersede it with a newer one and
say so.
Status: `Decided` · `Supersedes` (contradicts an earlier decision, names it) · `Deferred` (deliberately not now,
with a trigger)
## 2026-09-15 — The stat block
Taken on the same day, after the first read of the doc set.
| # | Decision | Where |
| --- | --- | --- |
| D-38 | **Counters live on the receiver as tags and attributes**: immunity blocks by tag, resistance scales by attribute, cleanse removes by tag, and every status and every block is visible. The same status from several sources: strongest wins, longest remaining duration; different statuses multiply. | [Stats](Spec/Stats.md) |
| D-37 | **One stat block on everything with a body, and every outside influence is a gameplay effect on it.** Base values, buffs, debuffs, ground, carried weight, gear and being downed all go through the same effects; no system keeps its own multiplier. `Supersedes` the tagged speed-multiplier map the first draft of Movement gave the movement component. | [Stats](Spec/Stats.md) |
## 2026-09-15 — The move to Unreal and the reframing
Taken while rewriting the two earlier projects' documentation into this one. Everything below is `Decided`
unless marked.
| # | Decision | Where |
| --- | --- | --- |
| D-01 | **Unreal Engine 5, C++ first.** Blueprints compose, tune and decorate; they never hold a rule, a replicated property or a server RPC. | [Architecture](Spec/Architecture.md) |
| D-02 | **Two runtime modules**, `<Project>Core` (rules, data, tags, telemetry contract; no actors) and `<Project>` (gameplay). Dependency one way. A third arrives when a feature is stable, never before. | [Architecture](Spec/Architecture.md) |
| D-03 | **Server-authoritative from the first line; the dedicated server is the real target.** No listen-server design, no "are we multiplayer" branch. Tested with the editor's dedicated server option from step 1. | [Networking](Spec/Networking.md) |
| D-04 | **The client predicts only its own movement and its own animation.** Three responsiveness tiers assigned by one test: does a rollback have a visible victim? No rollback of world state a player can already see. | [Networking](Spec/Networking.md) |
| D-05 | **Ask, then show.** Commit-shaped moments wait for the server inside their own feedback beat. Never show a number as final before it is committed. | [Networking](Spec/Networking.md) |
| D-06 | **A player is an identity, not a body.** Class, attributes, cooldowns, discoveries and identity live on the player state; the character actor is lent. | [Networking](Spec/Networking.md), [Architecture](Spec/Architecture.md) |
| D-07 | **Persistence behind one provider interface with a local-file implementation.** Nothing is persisted yet; the seam exists first. | [Networking](Spec/Networking.md) |
| D-08 | **Gameplay Tags are the vocabulary.** `Config/Tags/<Feature>.ini` is the source; code-referenced tags are declared natively. No string ids anywhere. | [Architecture](Spec/Architecture.md) |
| D-09 | **Content is `UPrimaryDataAsset`s** addressed by primary asset id or tag, with soft references for art. | [Architecture](Spec/Architecture.md) |
| D-10 | **Rules are pure functions in the core module**, tested without a world, called by both the client preview and the server verdict. | [Architecture](Spec/Architecture.md) |
| D-11 | **Telemetry from step 2**, one subsystem, one sink interface, JSON Lines to a local file, no personal data, events not aggregates. | [Telemetry](Spec/Telemetry.md) |
| D-12 | **`UCharacterMovementComponent`, extended**, not a custom controller and not the Mover plugin. Sprint is a saved-move flag; dodge and blink are root-motion abilities. | [Movement](Spec/Movement.md) |
| D-13 | **One rig, two camera modes.** First and third person on the same mannequin; the camera never enters the authority path; both modes exist from step 3; the default is decided by playing (OD-03). | [Movement](Spec/Movement.md) |
| D-14 | **The deadzone look model**, salvaged: the head turns freely inside a yaw deadzone, then the body follows; the deadzone widens while carrying. | [Movement](Spec/Movement.md) |
| D-15 | **Sprint takes Shift.** The earlier four-slot layout (Q, E, Shift, R) becomes Q, E, R, C. Interact F, drop G tap, throw G hold. `Supersedes` the earlier project's Controls decision. | [Movement](Spec/Movement.md) |
| D-16 | **The controller is built first and proved against a written checklist in a gym level** that never leaves the project. | [Movement](Spec/Movement.md), [Steps](Steps.md) |
| D-17 | **One interaction system.** An interface, a world subsystem as the funnel, the player's component as the only RPC path; reach re-checked server-side with tolerance; prompt and permission from one function. | [Interaction](Spec/Interaction.md) |
| D-18 | **Interaction is a discrete act on a fixed prop; carrying is continuous possession.** Pick-up is routed by the interaction key but is a carry verb. | [Interaction](Spec/Interaction.md) |
| D-19 | **Two hands; two-handed objects block interaction and, in first person, the view.** Held objects attach and stop simulating; dropped and thrown ones are server physics. Throwing is in and scrappy; nothing is destroyed by it. | [Interaction](Spec/Interaction.md) |
| D-20 | **The Gameplay Ability System** for attributes, abilities, effects, cooldowns and cues. The component is on the player state for players and on the pawn for enemies. | [Combat](Spec/Combat.md) |
| D-21 | **One damage funnel**: one execution calculation every damaging effect uses. **No friendly fire**: the funnel discards player-on-player damage and keeps the impulse. | [Combat](Spec/Combat.md) |
| D-22 | **Down before death.** Bleed-out, revive by anyone, a solo down is an instant wipe. A downed player is a prop. | [Combat](Spec/Combat.md) |
| D-23 | **Kits define ability access; gear defines stats and crosses classes; mods never grant a signature.** The `bSignature` flag exists from the first ability; gear and mods do not. | [Combat](Spec/Combat.md) |
| D-24 | **The recoverability contract** applies to any verb that inconveniences a teammate: recovery takes less time than the verb, and none may down, kill or deprive. All emit `grief_action`. | [Combat](Spec/Combat.md) |
| D-25 | **Sublinear party scaling and role relaxation** are reserved rules applied to a count. | [Combat](Spec/Combat.md) |
| D-26 | **Part, piece, trait.** A family declares parts; a piece fills one and carries three trait layers. No recipes anywhere. | [Crafting](Spec/Crafting.md) |
| D-27 | **"Material" is "substance"** in code and docs, because `UMaterial` is the engine's. | [Crafting](Spec/Crafting.md) |
| D-28 | **Substances are objects, not stacks**, with identity, quality and provenance. Affordable only because storage is physical; an abstract bank is refused on that ground. | [Crafting](Spec/Crafting.md) |
| D-29 | **Discovery unlocks, choice applies.** Characteristics are discovered through play and chosen at the station. Known set is per player. | [Crafting](Spec/Crafting.md) |
| D-30 | **One activity runtime, three guarantees**: completion never gated on skill; skill modulates a quality band only; a second operator is additive, never required. The anvil is the growing zone; the forge is a 5×5 bed with two levels of detail bound by an equivalence rule. | [Crafting](Spec/Crafting.md) |
| D-31 | **The assembly bench is domain-neutral; domains gate the work, never the worker.** Class changes speed and quality only. | [Crafting](Spec/Crafting.md) |
| D-32 | **Durability is per part, summed; the item is lost at zero; nothing wears from crafting.** | [Crafting](Spec/Crafting.md) |
| D-33 | **A crafted weapon-family item is a weapon**: both authored and crafted weapons produce one `FWeaponProfile` that the swing, the funnel and the bar read. `[PROPOSED]` until step 13 closes. | [Crafting](Spec/Crafting.md), [Combat](Spec/Combat.md) |
| D-34 | **UMG with CommonUI; one theme asset by role; prop text is world-space with no canvas; every readable string is `FText` from a string table.** The menu never pauses the world. | [UI](Spec/UI.md) |
| D-35 | **Steps, not a roadmap.** A ladder closed by proofs; the next few steps concrete, the rest sketched and detailed only when reached. | [Steps](Steps.md), [Design](Design.md) |
| D-36 | **The two earlier loops are not carried.** Their ideas are catalogued as features with needs and constraints, none scheduled. | [Ideas](Ideas.md) |
## Open decisions
Questions that block steps. Each names what it blocks and the recommendation on record, so closing one is a
confirmation, not a fresh discussion. When one is taken it moves up as a D-line and the row is marked closed.
| id | Question | Blocks | Recommendation | Status |
| --- | --- | --- | --- | --- |
| OD-01 | **Engine version.** | 1 | The newest release with a hotfix out (5.6.x at the time of writing). Pin it in `CLAUDE.md` and the `.uproject` in step 1; upgrade deliberately, never mid-step. | Open |
| OD-02 | **Project and module name.** | 1 | Short, one word, no spaces. It becomes the `.uproject`, the module prefix and the test filter root. The docs write `<Project>` until it exists. | Open |
| OD-03 | **Default camera mode.** | none until 8 | Build both in step 3, play the gym and the first fight in each, let `camera_mode_changed` and `movement_sample` settle it by step 8. | Recommended |
| OD-04 | **Engine from source.** | the first packaged server | The launcher build until then; the editor's dedicated-server option covers every step in the ladder. | Recommended |
| OD-05 | **Placeholder character and animations.** | 3 | The engine's Third Person template mannequin and its animation blueprint; a retargeted pack only when the swing needs a clip the template lacks. | Recommended |
| OD-06 | **Physics replication mode for thrown objects.** | 6 | The engine's predictive interpolation mode; resimulation is not needed for objects nobody predicts. | Recommended |
| OD-07 | **Which two kits ship first.** | 9 | Warrior and Cleric: a taunt and a heal are what make the goblin's threat table and the downed state legible. | Recommended |
| OD-08 | **Crafting professions against combat kits.** | after 15 | A design session, not a step. See Ideas. | Open |
## Deferred, with triggers
Not gates. Listed so nobody reopens them as if they were undecided.
| Deferred | Until |
| --- | --- |
| The Mover plugin | It leaves experimental and a movement feature needs what it has (Movement Q2) |
| Stamina as a cost | A kit wants one (Combat Q2); the attribute exists so it is a cost effect, not a refactor |
| A blade sweep instead of the box hit check | Real animation makes the box read wrong (Combat Q4) |
| Storage beyond hands and station buffers | A step needs more than hands can hold (Crafting Q4, Ideas) |
| Alloys and the kiln | Post-fifteen; meanwhile nobody hard-codes one-to-one processing (Crafting Q5) |
| Generated glyph discovery | Its own session; the composition path never changes, any seed is global |
| Reconnect into a running session | Written down before the first playtest with strangers (Networking Q1) |
| Seamless travel, a second map | The second map |
| Replication Graph or Iris | A world with many actors and many players; dormancy and relevancy keep it cheap |
| Steam, lobbies, invitations, voice | A session layer in front of the server; never inside gameplay |
| Continuous integration | A reason for it; tests run by hand until then |
| Resistances per damage type beyond physical and magic | A second elemental damage type (Stats Q2) |
| Predicting surface effects on the owning client | The correction on entering mud is felt (Stats Q1) |
| A stat block on props that are not bodies | The first prop that should burn or freeze (Stats Q3) |