Skip to content

jengine-settlement

A world you dig and build in - tile edits as the main verb, support that collapses, and growth that settles on change rather than per frame.

KindProject package: linked into the builds of the projects that list it
Sourcepackages/jengine-settlement
Version0.1.0
Entry pointjengine_settlement::SettlementPackage
Script namespaceSettlement
Listed byprojects/arcade-classics

List it in the top-level "packages" array of project.jengine:

{
"packages": [
{ "name": "jengine-settlement", "source": { "type": "path", "path": "../../packages/jengine-settlement" } }
]
}

Then rebuild the editor viewport for the project (jengine viewport-build projects/<name>, or the editor’s Rebuild viewport banner). Native and web builds link it on their own.

A scene that uses its components must be a v2 scene ("version": 2): a v1 scene has no field for a package component and keeps it as inert custom data.

A script can check that the package is linked with if Settlement == nil then return end.

Scene keyRust type
lh_worldSettlementpackage only: needs a v2 scene

Commands run in every runtime and return nothing; a package publishes what scripts read onto components (see the notes below). The flat name also works.

CallFlat name
Settlement.start(e, which)lh_start
Settlement.input(e, px, py, tx, ty, dig, place)lh_input
Settlement.hold(e, item)lh_hold
Settlement.craft(e, item)lh_craft
  • projects/arcade-classics/assets/scenes/hollow.scene

From packages/jengine-settlement/src/lib.rs.

Loam Hollow - a world you dig and build in.

  • [world]: the grid, and the three rules that make editing it a game.
  • [craft]: what you carry, what you can make, and what a tool can touch.
  • [grow]: what changes while you are elsewhere, integrated rather than ticked.
  • [worldgen]: generating a world, and refusing one that cannot be finished.
  • [run]: the verbs joined up, and a day that turns.
  • [content]: the five data tables, and the pairings between them.

This is the game the arcade roadmap picked to force the tilemap collider work (BUGS #148), and the way it forces it is by not simulating anything itself. The package owns a grid of material ids and writes it into a core Tilemap; the engine builds colliders from that per 32x32 chunk, and a character_controller walks on them. So digging the floor out from under the hero is the engine’s problem, and jengine-platformer does the hero feel.

A package that ran its own player and its own collision would be testing its own arithmetic. What this one tests is that a tile edit is cheap enough to be the main verb - which, before the chunked rebuild, it was not: every pick swing rebuilt every collider on the map.

The layer is replaced on start rather than resized, which deliberately exercises the other half of that fix: a fresh layer carries a new LayerRevisions id, so the physics record cannot mistake it for the one it last saw.

lh_world on the same entity as the tilemap and tilemap_collider.

"lh_world": {
"tables": { "materials": "data/lh_materials", "tools": "data/lh_tools",
"recipes": "data/lh_recipes", "crops": "data/lh_crops",
"worlds": "data/lh_worlds" },
"which": 0, "tile": 16.0, "layer": "ground"
}
CallDoes
Settlement.start(e, which)generate a world and begin
Settlement.input(e, px, py, tx, ty, dig, place)tile coords; dig/place 0 or 1
Settlement.hold(e, item)choose what place puts down
Settlement.craft(e, item)make one of something

Everything read back comes through Entity.get_custom(e, "lh_world", …), which the step system republishes each frame from Settlement::view.