Files
UnrealPrototyping/Docs/Spec/README.md
T
Moto 0e61a77346 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
2026-09-15 17:54:00 +03:00

92 lines
7.0 KiB
Markdown

# Specifications
These documents are written for an implementer that reads carefully and lifts code, which today means Claude and
whoever reviews its pull requests. They are not the human summary; that is [`../Design.md`](../Design.md). Read the
summary first, then [`Architecture.md`](Architecture.md), then the document for the system you are touching.
Each spec is pseudocode plus the reasoning behind it. The pseudocode is C++-shaped Unreal code and it is meant to be
implemented, not admired: a class skeleton here is the class we expect to find in `Source/`, with the same name, the
same members and the same comments about why. Where a spec says `// pure`, that is a promise about testability the
real code is expected to keep.
## Documents
| Doc | Owns | Read when |
| --- | --- | --- |
| [Architecture.md](Architecture.md) | Modules, lifetimes, authority, data assets, gameplay tags, the C++/Blueprint boundary, testing, conventions | Before writing any code |
| [Stats.md](Stats.md) | The one stat block every body carries, effects and their sources (abilities, areas, surfaces, items, the world), stacking, counters | Step 5, and anything that changes a number on a body |
| [Movement.md](Movement.md) | The character, the movement component, the look model, camera modes, input, the gym level | Steps 3 to 5 |
| [Interaction.md](Interaction.md) | The one interaction system every prop uses, carrying, throwing | Step 6, and any prop |
| [Combat.md](Combat.md) | Attributes, the one damage funnel, melee hit detection, enemies, abilities, kits, downed and revive | Steps 7 to 11 |
| [Crafting.md](Crafting.md) | Families, parts, pieces, traits, substances, the pure rules, stations, activities, the link back to combat | Steps 12 to 15 |
| [Networking.md](Networking.md) | The authority model, the responsiveness tiers, prediction posture, persistence and identity seams | Any replicated feature |
| [Telemetry.md](Telemetry.md) | The sink, the envelope, the event catalogue | Any feature (every feature emits) |
| [UI.md](UI.md) | HUD, prompts, the theme asset, world-space text, localisation | Any screen or prop text |
## Notation
```
Server*(...) runs on the authority only. Validates the instigator and re-checks every precondition,
then mutates. A UFUNCTION(Server, Reliable) RPC or a plain method guarded by HasAuthority().
Get* / Preview* side-effect-free query. Safe to call from UI every frame, on any peer.
// pure deterministic, no world access, unit-tested, reused by the client preview and the server verdict.
On* (delegate) a multicast delegate a service raises. UI subscribes; UI never polls.
*_Cosmetic a BlueprintAssignable hook a designer may wire. Never load-bearing.
UFooDefinition a UPrimaryDataAsset, authored content.
FFooInstance runtime state with identity (an FGuid).
FFooRecord the persisted snapshot of an instance. Separate type from the instance on purpose.
TAG_Foo_Bar a native gameplay tag, "Foo.Bar", declared once in code. Never a string literal at a call site.
```
Status markers inside a spec:
```
[DECIDED] settled, with the reason. Logged in ../Decisions.md.
[PROPOSED] the recommended shape, not yet built on. Becomes [DECIDED] when the step that builds it closes.
[SALVAGED] an idea carried over from the two earlier projects, reshaped for this one. See ../Ideas.md.
Qn an open question, collected at the end of each document.
```
## Cross-cutting rules
Every spec obeys these. They are stated once here so no spec has to restate them, and any spec that appears to
break one is wrong.
1. **The server decides. The client asks, and predicts only its own body.** Every mutation has an explicit
instigator and is re-validated on the authority, even when the game is being played alone. Standalone and
listen-server play are development conveniences; the dedicated server is the real target and nothing may assume
it is absent. See [Networking.md](Networking.md).
2. **One formula, many consumers.** A preview and the real thing call the same pure function. Damage, coherence,
naming, assembly validation, spec matching and interaction prompts all follow this. If a UI-side "fast copy" of a
rule ever appears, it is a bug.
3. **One funnel per kind of consequence.** All damage goes through one execution. All interactions go through one
service. All activity quality goes through one result type. A second path is where rules quietly diverge.
4. **Rules are plain C++ in the core module; actors and components adapt them to the world.** The core module knows
no `AActor`. This is what makes rules testable without a level and runnable on a headless server.
5. **Content is data, addressed by gameplay tag or primary asset id, never by string.** A new sword, enemy or
substance is an asset, not a code change. If adding a variant needs code, the model is wrong.
6. **Every rejection carries a reason a player can read.** A refused interaction, an illegal assembly, a blocked
ability: each returns a reason tag that the prompt or panel shows. Silent refusal is a failed step.
7. **Nothing is destroyed silently.** Dropped things persist on the floor, full containers refuse with a reason,
thrown things land where they land. The rare deliberate deletion is announced before it happens.
8. **Bonuses, never locks.** A class, a level or a piece of gear changes speed, quality or numbers. It never changes
what a station accepts or what an assembly permits, and it never grants another class's signature ability.
9. **Solo viability is a gate, not a mode.** Every rule is checked against one player. Where it costs a solo player
something, the spec says so and names the tuning knob.
10. **Derived state is recomputed on load, never trusted from storage.** A rebalance re-scores old items everywhere.
11. **Telemetry from the first line.** Every feature emits through the injected sink into a catalogue that exists
before there is anyone to measure. Retrofitting emit calls is the tax this avoids.
12. **Determinism where it is promised.** Anything generated from a seed uses its own `FRandomStream`, integer
coordinates and ordered collections, and never reads physics, time or frame counts. Nothing today is generated
from a seed; the rule exists so the first thing that is inherits it.
13. **One stat block; every outside influence is an effect on it.** Every body carries the same attribute set.
A buff, a debuff, ground, weight, gear and base values are all gameplay effects applied to it; counters are
tags and attributes on the receiver. No system keeps its own multiplier. See [Stats.md](Stats.md).
## How a spec relates to the steps
[`../Steps.md`](../Steps.md) schedules; these documents specify. A step links to the sections it builds and states
what proves it done. If a step and its spec disagree, the spec wins and the step is corrected. A spec that turns out
wrong in the building is corrected in the same pull request as the code, under a **What was built, and where it
differs** heading at the end of the affected document, so the next reader is not misled by the sketch.