102 lines
5.7 KiB
Markdown
Executable File
102 lines
5.7 KiB
Markdown
Executable File
# Woodland traveler character creator
|
||
|
||
Use `/character` at any time while connected, or open **Character appearance**
|
||
from the inventory. Creation is opt-in: joining restores the saved appearance
|
||
without opening the creator. Existing location selection and field-note join
|
||
forms retain priority.
|
||
|
||
## A quiet traveler, not a costume catalogue
|
||
|
||
All choices are inclusive and independent, with no gender, identity or stat
|
||
fields. Compact, lean, balanced, broad and sturdy silhouettes have identical
|
||
mechanics, height, camera, collision, reach, movement and held-tool anchors.
|
||
Hair, layered field clothes, cloaks, belt gear and packs use original low-poly
|
||
geometry with hand-drawn, muted woodland pixel art.
|
||
|
||
Four tabs keep the 14 × 11 form manageable:
|
||
|
||
| Tab | Choices |
|
||
| --- | --- |
|
||
| Face | 5 body silhouettes, 6 skin tones, 5 face-line patterns, 5 eye colors |
|
||
| Hair | 10 styles, 6 shared hair/facial-hair colors, 7 facial-hair styles |
|
||
| Clothing | 7 garments, 8 cloth colors, 4 trousers, 3 boot leathers |
|
||
| Finishing | 9 accents, 8 accent colors, 5 face-detail patterns |
|
||
|
||
Dropdowns use readable names, not gender categories or free-form colors. Cloth
|
||
and accent palettes are sage, teal, slate, mauve, ochre, rust, linen and charcoal.
|
||
Transparent `none` layers and colors under absent hair/accents mean the raw
|
||
selection combinations are not all visually distinct; no uniqueness count is
|
||
claimed.
|
||
|
||
## Preview and explicit consent
|
||
|
||
The form contains a real Luanti `model[]` preview, not a screenshot, external
|
||
browser or URL. It uses one composited 64 × 64 texture and the selected B3D.
|
||
The preview turns continuously and supports mouse dragging; Front, Profile and
|
||
Back reset its camera angle. These controls never rotate the actual player.
|
||
|
||
Changing a dropdown, switching tabs, **Randomize** and **Reset draft** affect
|
||
only a private session draft. Randomize chooses from every fixed allowlist using
|
||
bounded `math.random`; it is not security randomness and introduces no secrets.
|
||
Reset copies the defaults rather than modifying shared state. **Cancel** or
|
||
Escape discards the draft, preserving both the real appearance and saved bytes.
|
||
Only **Save / Apply** commits. No need, inventory, identity or physics values
|
||
are changed. Drafts disappear when the session ends.
|
||
|
||
## Version-1 storage and recovery
|
||
|
||
The only new persistent value is the engine-owned player metadata string
|
||
`hearth:appearance`. It is independent of the existing global save schema and
|
||
world/mod storage. A complete flat JSON object contains exactly `version:1` and
|
||
these string selections:
|
||
|
||
`body`, `skin`, `face`, `eyes`, `hair`, `hairColor`, `beard`, `garment`, `cloth`,
|
||
`trousers`, `boots`, `accent`, `accentColor`, `detail`.
|
||
|
||
Defaults match the [authoritative art contract](art-direction.md): balanced,
|
||
sand, calm, hazel, sidepart, chestnut, none, tunic, teal, earth, walnut, scarf,
|
||
sage, none. An absent value uses defaults without writing metadata. Invalid,
|
||
unknown-version, missing/extra-field, malformed, nested or over-2048-byte values
|
||
show safe defaults and a fixed warning. Original corrupt bytes are **not
|
||
overwritten**, and appearance errors never kick a player. Only an explicit
|
||
successful Apply replaces that value. Back up the world before manual recovery.
|
||
|
||
Encoding and decoding use `core.write_json` / `core.parse_json(raw,nil,true)`;
|
||
parser errors do not log player payloads. There is no executable deserialization,
|
||
custom path, uploaded texture or free-form hexadecimal color. Every mesh and
|
||
layer filename is built solely from fixed IDs. Compositing order is skin, face,
|
||
eyes, garment, trousers, boots, hair, beard, accent, detail; accents layer above
|
||
hair so a selected hood frames and covers it. The model includes an original
|
||
draped mantle, belt, pack, projecting nose and ears. Face overlays are
|
||
skin-neutral; there is no global color tint.
|
||
The held-tool material remains the existing compatibility texture.
|
||
|
||
Apply serializes and checks the roundtrip, then writes metadata **before**
|
||
publishing `mesh` and `textures`. A thrown/false metadata write or serialization
|
||
failure keeps the previous published appearance and saved session selection,
|
||
leaving the draft available to retry. Engine metadata durability still follows
|
||
normal engine player saving; this is not a new disk transaction service.
|
||
|
||
## Integration and validation boundary
|
||
|
||
[The factory](../mods/hearth/character.lua) receives `(hearth, api)`, registers
|
||
its own command/receive-fields callback, and exports `apply`, `on_join`, `show`,
|
||
`handle`, `defaults`, `options`, `validate`, `decode`, `encode`, `preview` and
|
||
snapshot-only `state`. Bootstrap instantiates it before the interface and
|
||
players; the player join handler calls it after base property initialization.
|
||
Only the current engine-supplied connected player object and its own session can
|
||
edit an open draft. Target names, arbitrary fields, hidden-tab selections and
|
||
invalid dropdown indices are rejected as a whole event. All displayed data is
|
||
formspec-escaped; text and input sizes are bounded.
|
||
|
||
CodeGuard input/storage guidance was applied: allowlisted keys and selections,
|
||
bounded parsing, session ownership, preserved corrupt data and sanitized errors.
|
||
No credentials, certificate handling, cryptography, network calls or dependencies
|
||
are introduced. No authentication or database infrastructure is changed.
|
||
|
||
Focused offline Lua harnesses cover character behavior, player join integration,
|
||
inventory navigation and bootstrap order. Mocks model native JSON through
|
||
registered exact fixture strings, not executable Lua. Native engine rendering,
|
||
mouse behavior and visual fit still require client review; no full-engine or
|
||
live-world test is claimed by this change.
|