Files
2026-11-05 09:57:11 -05:00

367 lines
24 KiB
Markdown
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# The Last Hearth
An original, standalone Luanti survival prototype: gather flint and sticks, make
tools, build a supported shelter, fuel a hearth, cook forage and boil water.
It does not depend on Minetest Game (MTG). This is an **environment simulation
prototype, not a full physics simulator or a launch-ready public service**.
Original game code and procedural assets are MIT-licensed; the separately
distributed engine retains its own licenses.
## Status and planning
**M0 technical gates are complete. M1 implementation/preflight and M2 gameplay /
verification are complete; their human acceptance gates remain open. M3
implementation and automated verification are complete; its two-player acceptance
gate remains open.** M4 ecology, preservation, pottery, metalworking and bounded
offline process work has passed automated technical verification; its week-long
group acceptance remains open. M5 is now beginning with an offline-tested private
staging deployment contract, not a live deployment. See [M0 evidence](docs/m0-verification.md),
[M1 playtest gate](docs/m1-verification.md), [M2 evidence](docs/m2-verification.md),
[M3 implementation and verification](docs/m3-verification.md), and [M4 verification](docs/m4-verification.md).
The newer living-ecosystem and botanical field-journal/art integration is an
additional implementation pass, **pending main integrated validation and native
visual review**. Historical M4 results do not certify this new pass. No version
or save-schema bump is part of the journal work.
### Woodland traveler appearance
Use `/character`, or **Character appearance** in the inventory, to choose muted
woodland clothing, skin, face, hair and details with three equal-mechanics body
profiles. Four tabs and a rotatable 3D model preview keep changes in a private
draft: **Save / Apply** persists them; **Cancel** keeps the original. Joining
restores saved appearance without prompting. Corrupt appearance data is retained
with a safe-default warning, never a kick. Existing location forms retain priority.
See [character creator and recovery contract](docs/character-creator.md).
Focused offline tests do not certify native visuals or client interaction.
### Offline species reader
Use `/inspect` while pointing at a known plant/tree within six blocks, or
`/inspect oak` / `/inspect Quercus robur` for an exact catalogue ID or Latin name.
Field notes include **Inspect target**; `/botany` offers a **Species article**
selector for each ten-row page. Harvesting and building controls are unchanged.
The **Article** tab shows available cached plaintext Wikipedia introductions, labelled
**Wikipedia excerpt (offline)**, with copyable canonical/revision/history URLs,
contributor attribution and **CC BY-SA 4.0** licensing. Missing snapshots have
explicit availability notes, not counterfeit articles; cache expansion is a separate task. **Current
effects** distinguishes simulated game policy from descriptive natural history.
This is not a full wiki, embedded browser, or real-world identification/foraging
guide. Nothing is fetched or automatically opened; inspection writes no world or
player data. Text is escaped and bounded to 8,000 characters, 4,000 per page.
See [source coverage, licenses and reader contract](docs/species-references.md).
Focused isolated tests cover the reader; native visual/client integration remains
pending. Full-engine tests were not run for this change.
The [landscape/content expansion](docs/content-expansion.md) now wires ten
communities, thirteen tree species, a 100-species botanical catalogue and ordered
geology into the seasonal ecosystem. Its eight ecological groups are deliberately
uneven: 13 trees, 14 shrubs, 10 grasses, 22 herbs, 11 ferns/mosses, 10 fungi,
10 aquatic taxa and 10 lichens. The additions reflect ecological roles, not a
ten-per-category quota. The trees are oak, birch, pine, willow, alder, beech,
aspen, rowan, hazel, spruce, crab apple, wild cherry and field maple. All thirteen logs
fuel hearths for 180 seconds and craft four matching planks; buildings/planks
are not direct fuel. Copper charges/ingots/picks, copper smelting, coal fuel and
a three-quartz alternate window recipe are integrated; native validation of the
latest botanical pass remains pending. New launcher worlds use a broad-relief v7 preset with
a ±4096 bound; **existing saved mapgen/seed/bounds are not retuned**. Old chunks
are never regenerated; future unexplored chunks can change and leave seams.
Focused registration/tooling tests do not certify new-seed safety or engine visuals.
**Human acceptance remains open across M1–M4.** The actual M1 course has not been evidenced as
traversed/repeated by several testers, and there are no measured FPS, frame-time,
multiplayer, latency or hardware-envelope results. M2 implementation is proceeding
under the user's explicit direction; this does not waive those gates or claim the
M2 unfamiliar-tester, M3 two-player cabin, or M4 week-long group gate has passed.
- [Roadmap: M0–M6 and M1 acceptance](docs/roadmap.md)
- [Launch feature checklist: F01–F19](docs/launch-features.md)
- [M0 decisions, provisional budgets, risks and evidence](docs/m0-decisions.md)
- [Architecture and save/module contracts](docs/architecture.md)
The exact development contract is **Luanti 5.18.0, game 0.5.0-m4, save schema 1**.
See [release.json](release.json) and [package.json](package.json). Native-first:
Windows is natively verified on the existing development host. Linux/macOS path
selection has unit coverage only; native execution is unverified on both. No clean
machine was tested. A browser client
is **not promised launch-ready**. There is no committed public launch date.
## Run and test locally
Requires Node.js 22+ (built-in modules only), a separately installed stock Luanti
**5.18.0**, and a trusted writable runtime directory. The launcher checks the
engine's reported version; it does not download the engine or authenticate it.
On non-Windows systems set `HEARTH_ENGINE` to the absolute executable path. On
Windows it defaults to the existing Luanti 5.18.0 win64 runtime's bin directory;
setting `HEARTH_ENGINE` explicitly also works there. A headless-only server binary
can run checks but cannot provide graphical play.
From this repository, using Node on PATH:
```text
node scripts/run.mjs check
node scripts/run.mjs smoke
node scripts/run.mjs test
node scripts/run.mjs test:seeds
npm test
node scripts/run.mjs play
node scripts/run.mjs test:course
node scripts/run.mjs course
```
- **check:** disposable headless world, game startup and compilation of the Lua
sources/specs. Compilation alone does not execute the unit assertions.
- **smoke:** real-engine registry/crafting/terrain/resource/enclosure checks and
isolated execution of the discovered Lua unit specs. Mocked globals do not
replace globals in the live game.
- **test:** check plus smoke; with `HEARTH_LUA` set to an absolute Lua 5.1+/LuaJIT
executable, also runs the standalone Lua harnesses. No separate Lua is otherwise
required. Do not rely on historical test counts: record named suites/results.
- **test:seeds:** fresh real-engine worlds for eight fixed map seeds; checks safe
arrival surfaces and required starting resources without touching the play world.
- **M3:** structure removal is refused if it would strand connected construction.
`/claim share` manages household access and `/claim show` briefly marks boundaries.
See [M3 rules and remaining gates](docs/m3-verification.md).
- **npm test:** Node tooling tests only, not the engine suite. The `test:engine`
package script runs the engine suite; `test:recovery` is a separate, private
offline recovery exercise described below.
- **play:** persistent local singleplayer world. Uses normal engine controls.
The expanded v7 preset applies only at creation. Use a separate empty
`HEARTH_HOME` to try it without migrating/deleting the current world. See
[new-world settings and existing-world transitions](docs/content-expansion.md#broad-relief-v7-preset-new-worlds-only).
- **course:** a fresh disposable summer course; it never opens or changes
worlds/last_hearth. Wait for arrival, then run `/course` to generate the route
and receive a temporary kit. The course route covers half-steps, a one-wide
doorway, water, two controlled falls, gathering, construction and an arena.
Run `/course report` for checkpoint progress and server-step/Lua-callback
samples—**not** client FPS. `/spar` opts into a bounded moving sparring opponent;
`/practice` uses the stationary reference target. PvP remains disabled.
- **test:course:** native headless enrollment/staging and no-consent preflight.
It intentionally does not generate terrain, forge a player, or claim traversal.
Engine checks require zero exit status **and** a unique per-run success marker.
Their outer deadline is 90 seconds; standalone Lua invocations are bounded to
30 seconds. Graphical play has an eight-hour safety bound. Quit normally to save;
interrupts/deadlines kill the child and are not graceful-save guarantees. Session
configuration and logs are temporary and removed at session cleanup; retain
sanitized evidence separately when validating. See [scripts/run.mjs](scripts/run.mjs).
## Data locations and isolation
`HEARTH_HOME` overrides the runtime root and must be absolute. Without it:
| Platform | Default root (literal environment notation) |
| --- | --- |
| Windows | %LOCALAPPDATA%/last-hearth-runtime |
| Linux | $XDG_DATA_HOME/last-hearth-runtime, or $HOME/.local/share/last-hearth-runtime |
| macOS (runner unverified) | $HOME/Library/Application Support/last-hearth-runtime |
The **old Windows runtime and world location remain unchanged**. Within the root,
the persistent world is under worlds/last_hearth and retained snapshots are under
backups. Each invocation packages a generated game into a temporary session's
games directory and sets `LUANTI_GAME_PATH`; it does **not** overwrite the engine
installation or its games. See [scripts/launcher.mjs](scripts/launcher.mjs).
Use a **different absolute `HEARTH_HOME` for staging**, with an explicit
`HEARTH_ENGINE` when the engine lives outside it. Changing the root does not copy
or migrate the old world. Production must use a separate external deployment,
storage and configuration, outside this checkout, packages and webroots. The
local launcher is not a dedicated-server deployment tool. It binds loopback,
disables announcements, PvP and creative mode, and keeps mod security enabled.
## Package, back up and restore
Examples below use absolute Windows destinations; substitute your own trusted
paths (POSIX absolute paths on Linux/macOS). **Parents must already exist and
each destination must be new. No command overwrites an existing destination.**
```text
node scripts/run.mjs package C:/HearthArtifacts/game-0.1.0-m0
node scripts/run.mjs verify C:/HearthArtifacts/game-0.1.0-m0
node scripts/run.mjs backup C:/HearthPrivate/worlds/last_hearth C:/HearthPrivate/backups/manual-001 --offline
node scripts/run.mjs restore C:/HearthPrivate/backups/manual-001 C:/HearthPrivate/worlds/restored-001 --offline
```
Without a destination, `package` uses the dist/last_hearth directory, still
requiring it not to exist. Packaging generates assets and includes release,
configuration, license, mod and JSON fixture inputs plus an exact SHA-256
inventory. It is an engine-independent **game directory**, not an engine/client
bundle or installer; it excludes saves, tooling and the full test suite.
`verify` verifies a **game package**, not a world backup. Restore verifies a
backup before and after copying; [scripts/backup.mjs](scripts/backup.mjs) also
exports `verifyBackup()` for programmatic verification.
**Before backup, restore, recovery, or launching an existing managed world, stop
ALL engines that could access it, including external engines on other machines.**
`--offline` is the operator's confirmation, not a mechanism that stops them.
Launcher/world locks and SQLite sidecar checks cannot prove remote idleness.
Do not delete locks/sidecars merely to bypass a refusal. Clear a stale launcher
lock only after confirming every relevant process has stopped.
The launcher takes a full retained prelaunch snapshot of an existing managed
world; it has no automatic retention deletion. Backups include private map,
player, authentication, inventory and mod data: use access-controlled, preferably
encrypted storage, never a public artifact directory. Permissions remain the
operator's responsibility; portable file modes do not provision Windows ACLs.
SHA-256 detects **corruption, not authenticity**; it is not signing or encryption.
Preserve the original snapshot and restore to a new directory before considering
any operator-controlled cutover. See [scripts/package.mjs](scripts/package.mjs),
[scripts/files.mjs](scripts/files.mjs) and [scripts/backup.mjs](scripts/backup.mjs).
### Private old-save recovery evidence
The `test:recovery` package script runs [scripts/recovery.mjs](scripts/recovery.mjs).
Stop all engines and other Hearth tooling first. `HEARTH_RECOVERY_SOURCE` selects
an absolute existing SQLite world; otherwise it selects the legacy Windows world
under `LOCALAPPDATA`. **`HEARTH_HOME` changes recovery's working/backup root, not
that default source.** Non-Windows operators normally need an explicit source.
Recovery retains an untouched snapshot, verifies byte-exact restores, boots only
instrumented disposable copies twice, and checks migration/restart behavior.
Temporary copies omit old worldmods and use synthetic staging coordinates. A
sanitized report is retained beside, not inside, the immutable snapshot. The
original world is never launched. The retained successful report records 79 seed
and 81 restart assertions, two byte-exact restores, two engine shutdowns and an
unchanged source. It tested an earlier package, not the final export; its source
had zero claims, so claim-owner/protection coverage uses regression fixtures and
mocks, not preservation of existing source claims. This is not a real-client
recovery playtest or public-service disaster recovery certification. See the
[recovery evidence and qualifications](docs/m0-verification.md#retained-recovery-evidence).
## First play and current rules
- **I** opens crafting and field notes; `/guide` reopens help.
- **Ecosystem survey** in the field journal, or `/ecosystem`, observes one small
loaded habitat patch and reports the actual global active counts for all 23 animal identities. It does not
grow plants, spawn animals, force-load terrain or change world state.
- **Botanical guide** in the journal/survey, or `/botany [search]`, browses the
actual catalogue, ten species per page. Search is literal, escaped and limited
to 48 characters; it includes common/scientific names, category, habitat,
seasons and ecological roles. Toxicity flags are game labels, **not real-world
food-safety advice**; unflagged does not mean edible. Missing catalogue APIs
display an unavailable message. See the [100-taxon category list and role limits](docs/botany.md).
- **Fauna guide** in the journal/botanical guide/survey, or `/fauna [search]`,
browses all 23 animal identities, source URLs and lifecycle status. Field-level
source-reported ranges, unverified fallback policies and **UNKNOWN** are distinct;
identity citations do not establish numeric timing. The existing plant article
reader is unchanged. No runtime network fetch or ecological mutation occurs.
- Gather flint, sticks, berries and reeds. Make an axe to harvest timber; build
supported walls/roof and fuel a stone hearth with sticks/logs.
- Fallen logs are ordinary sideways full cubes. An axe yields **one canonical
log**, not two sticks gathered by hand. Existing full-block trees/deadwood are
retained; this journal/process pass does not replace their geometry.
- Use a cup on water, then use untreated water on a fueled hearth before drinking.
- **Aux1** (normally E) plus forward sprints; release after exhaustion and recover
stamina before sprinting again. FOV is unchanged by default; `/comfort fov 75`
applies a session-only static preference.
- `/practice` places a stationary target. In local play or privileged staging,
`/spar` opts into one moving opponent. Strike to begin a round; step back/aside
to evade or face the attacker and hold right-click with a spear to brace.
- The controlled route exists only in the disposable launcher-created course
world. `/course retry` restarts its run. A settings flag alone cannot authorize
course generation in a survival/production world.
- `/claim` protects one 25 × 25 area, extending ±24 vertically. `/claim share`
grants resident (build/use) or storekeeper (storage-only) rights; `/claim unshare`,
`/claim list`, `/claim show`, and `/claim remove` manage membership and bounds.
Death preserves inventory, food, water and wetness; respawn only limits stamina
and warmth before safe home/fallback arrival. A home must be inside the player's
own claim and is revalidated at use. Offline player needs pause; hearth fuel and
queued cooking/boiling use real-time deadlines, while completed output waits for
collection. Food cooks in six seconds, water boils in four, and fuel cost is
reserved when a job starts. A craftable bedroll grants a small warmth recovery
after five uninterrupted sheltered seconds; it does not skip world time.
M4 adds seasonal crops and preservation; general food spoilage remains disabled.
PvP is disabled. See the [M2 rules and limits](docs/m2-verification.md) and
[M4 offline contract](docs/m4-verification.md).
### A living landscape, a botanical field journal
The [living ecosystem model](docs/ecosystems.md) is an original implementation
inspired by Dynamic Life's ecological ideas, not copied datapack code or assets.
Light, shade, moisture and competition shape meadow grass, wildflowers, ferns and
slow tree succession. Litter, fungi and dung recycle finite nutrients; grazing
debits finite forage and wildlife links habitat to the food web. Calendar organism
ages include the full unloaded interval; ecological work remains bounded and
loaded-only, never replaying an offline backlog. Named trees use species-profile
calendar endpoints, typically years to decades; conservative fallback thresholds
are explicitly not researched timings. Fungi do not accelerate tree maturation.
Claims, placed plants, crops and construction are excluded from autonomous changes;
existing crop and planted-sapling clocks keep their separate rules. Survey counts
cover a fixed 5×5×5 patch at your feet, not the whole landscape; unloaded cells are
explicitly unknown. Wildlife totals describe all currently active animals, not a
local census or saved population. There is no compulsory ecological quest.
Content installs the pure lifecycle namespace before biological factories, and
publishes wildlife's exact returned fauna catalogue. Human botanical harvest and
animal frugivory share `botany_ready_at`: after a successful crop debit it rests
one mean real year (**365.2425 days**), then requires its fruit season, not a
24-hour refill. One live pollination credit can add only **one** berry to the
existing two-berry crop; empty or cooling bushes never manufacture fruit. Human
inventory rejection restores fruit and credit; partial delivery spends both once,
and reservations precede inventory callbacks to prevent reentrant duplication.
All 23 animal identities register fixed, originally authored skeletal B3D assets
with 100 frames and five clips (idle, locomotion, feeding, flight/swim and rest)
at 24 fps. Registration/animation contracts are not native visual acceptance.
Established recruitment is immigration, **not an adult birth**. Every incomplete
profile disables reproduction by default; pairing, pregnancy, nesting, egg/larval
development, caste/colony reproduction and delayed implantation remain future
work. Unknown lives and source longevity averages never imply automatic death.
No offline meals, dung, births, forced map loading or missed-season replay occur.
See [calendar evidence and transaction contract](docs/lifecycles.md),
[fauna behavior and limitations](docs/fauna.md) and [ecosystem policies](docs/ecosystems.md).
This integration was focused-test-only: no engine launch, world change, version
bump, wiki-cache edit or claim of complete true-life biology.
The [moonlit botanical art direction](docs/art-direction.md) pairs original pixel
materials with the eom.dev Mocha interface: base `#1e1e2e`, mantle `#181825`, raised
`#292940`, border `#3c3d56`, pale `#cdd6f4` text and `#a6adc8` annotations. Mauve
`#cba6f7`, teal `#94e2d5` and yellow `#f9e2af` are restrained navigation, botanical
and warmth accents. The eight-page guide, botanical browser, recipes, satchel/crafting and location
forms share controls, dark fields, list colors, tooltips and pressed-sprig dividers.
HUD needs use labeled percentages and colored tracks on a dark panel rather than
ASCII bars. The ten-slot hotbar repeats the authored single-slot texture and uses
the authored selection outline; standard crosshair asset integration belongs to
the generated-art pass. Client scaling, contrast, long text and artwork still need
native visual acceptance; automated checks are not a claim of polished gameplay.
### Location and privacy
Optionally set **both** `HEARTH_LATITUDE` and `HEARTH_LONGITUDE` (−90…90 and
−180…180). Local worlds can instead use the prompt or `/location`; an unchosen
local world shows a disclosed neutral equatorial preview. There is no IP lookup
or external location service. Configured/stored coordinates are private data.
Dedicated servers require explicit administrator-selected `hearth_latitude` and
`hearth_longitude`, even with a stored location. The community location is **not
chosen**: the user/operator must approve it before M2 climate staging. The M0
45°N, 0°E synthetic fixture is **not a production location**. The host UTC clock
drives a synthetic seasonal model and an approximate fixed-orbit sky, not live
weather. Labels are UTC and local solar time, not civil timezone/DST.
`HEARTH_FIXTURE` selects `first-session`, `summer`, or `winter` for isolated local
or staging work. First-session fixes seed 731104, not the date/location; summer
and winter fix UTC/weather/45°N, 0°E. Use a separate staging root/world; never
apply fixtures to valued play data. Production rejects preview/test settings.
See [tests/fixtures/scenarios.json](tests/fixtures/scenarios.json) and
[settingtypes.txt](settingtypes.txt).
## Known limits, not fixes
M1 code now implements smoothed stamina/sprint transitions, collision/course test
geometry, animated held tools, material feedback and moving sparring. Manual
feel/collision evaluation, voluntary repeat testing and performance/network
measurements remain open; see [M1 verification](docs/m1-verification.md). This
is not a custom engine/client controller; the newer bounded wildlife work is
documented separately above. Stock Luanti remains the
M1 baseline unless human measurements reveal a specific blocking engine limitation.
M2 replaced the old below-world teleport with safe bounded recovery. M3 now provides
bounded room/vent-aware comfort, a small building palette, refuse-unsafe-removal,
shared resident/storekeeper roles and protected storage. This is not a full structural
physics engine or persistent smoke simulation; two-player grief/comfort acceptance
is still open. Generated art remains procedural prototype art. Public operations,
moderation, identity and disaster-recovery acceptance remain later gates; no account,
browser parity or multiplayer-hardening approval is implied.