Files
UnrealPrototyping/Docs/Decisions.md
T
Rainer LeitandClaude Fable 5.1 3e52d26fb7 Step 2: the telemetry seam
ITelemetrySink with the null, log and JSON Lines sinks, FTelemetryEvent and the envelope, TelemetryEvents,
UTelemetrySubsystem on the game instance, ASaltyGameMode minting the session id into the replicated
ASaltyGameState, bs.TelemetryTest, the git hash in the build string (D-42) and four Salty.Core.Telemetry tests
replacing the placeholder. Proved standalone and with a headless server plus client sharing one session id.

Also enables the engine's Editor, AutomationTest, GameplayTags, ConfigSettings and LiveCoding MCP toolsets
(D-43) so the editor's MCP server exposes more than the skills toolset.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-16 20:22:20 +03:00

14 KiB
Raw Blame History

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-16 — Step 2, the telemetry seam

# Decision Where
D-43 The editor serves the engine's MCP plugin on 127.0.0.1:8000/mcp whenever it is open. bAutoStartServer in Config/DefaultEditorPerProjectUserSettings.ini, the port .mcp.json points Claude Code at, plus the EditorToolset, AutomationTestToolset, GameplayTagsToolset, ConfigSettingsToolset and LiveCodingToolset plugins. Loopback only; nothing listens when the editor is closed. Everything the plugin sends to an LLM is Licensed Technology under the UE EULA §6(e). CLAUDE.md
D-42 The build string is FApp::GetBuildVersion() plus the git short hash read by Salty.Build.cs at build time. A commit changes the definition and rebuilds the gameplay module; that cost is accepted so a telemetry file never lies about which build wrote it. nogit when git is unavailable. Telemetry

2026-09-16 — Step 1 closes the two open decisions

Taken when the project was created from the engine's Third Person template.

# Decision Where
D-41 The template's three gameplay variants stay in-tree as reference only. Source/Salty/Variant_* and Content/Variant_* (Combat, Platforming, SideScrolling) compile and load but nothing new is built on them; they break the conventions (rules in Blueprint, casts, no server path) and are deleted when step 7 closes or the moment they block a build. The plain template character, game mode and controller are renamed ATemplate* and are the placeholder body until step 3. Architecture
D-40 The project is Salty. Salty.uproject at the repository root, modules Salty and SaltyCore, test filter root Salty.. Closes OD-02. CLAUDE.md
D-39 Unreal Engine 5.8, the launcher build. Pinned in Salty.uproject; upgraded deliberately, never mid-step. Closes OD-01. Four Fab packs sit in Content/ unused: Medieval_Weapons is expected at step 7, RPGEnvironmentVFX at step 14, HouseForge_01 as dressing after 7, Elite_RockyMeadows serves no step on the ladder. A pack enters a step only when that step's spec names the asset. Steps

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
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

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
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
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
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
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
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, Architecture
D-07 Persistence behind one provider interface with a local-file implementation. Nothing is persisted yet; the seam exists first. Networking
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
D-09 Content is UPrimaryDataAssets addressed by primary asset id or tag, with soft references for art. Architecture
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
D-11 Telemetry from step 2, one subsystem, one sink interface, JSON Lines to a local file, no personal data, events not aggregates. Telemetry
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
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
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
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
D-16 The controller is built first and proved against a written checklist in a gym level that never leaves the project. Movement, Steps
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
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
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
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
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
D-22 Down before death. Bleed-out, revive by anyone, a solo down is an instant wipe. A downed player is a prop. Combat
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
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
D-25 Sublinear party scaling and role relaxation are reserved rules applied to a count. Combat
D-26 Part, piece, trait. A family declares parts; a piece fills one and carries three trait layers. No recipes anywhere. Crafting
D-27 "Material" is "substance" in code and docs, because UMaterial is the engine's. Crafting
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
D-29 Discovery unlocks, choice applies. Characteristics are discovered through play and chosen at the station. Known set is per player. Crafting
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
D-31 The assembly bench is domain-neutral; domains gate the work, never the worker. Class changes speed and quality only. Crafting
D-32 Durability is per part, summed; the item is lost at zero; nothing wears from crafting. Crafting
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, Combat
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
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, Design
D-36 The two earlier loops are not carried. Their ideas are catalogued as features with needs and constraints, none scheduled. Ideas

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. Closed, D-39 (5.8)
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. Closed, D-40 (Salty)
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)