Files
Emil c7e86663d8
MVP checks / mvp (push) Waiting to run
Expand voxel gameplay, lighting, full-height streaming and world imports
Add shared Rust/WASM physics, worker meshing and diagnostics, 64-chunk full-height streaming, atlas texture support, and baseline world import. Document the current implementation and include the supplied in-game lobby screenshot.
2026-09-17 02:10:53 +03:00

9.1 KiB
Raw Permalink Blame History

Unified extension packages

packages/<directory>/manifest.json declares exact versions, licenses, dependencies, capabilities, and resources. At startup, the server verifies the entire dependency graph, sizes, SHA-256 hashes, paths, and absence of symlinks. A missing version, cycle, unknown capability, or modified resource prevents startup. Only client and common resources are published; server files have no public route. Resources are verified again when read over HTTP.

Examples are provided in packages/base and packages/trampoline. All images, audio, and models are original. Catalog data comes from official reports and measurements through the public Java 26.2 API; packages contain no vanilla textures or models.

A schema 1 manifest contains:

  • id, a version with three numeric components, and license;
  • dependencies:[{id,version}] with exact versions;
  • capabilities, such as blocks.define, client.texture, and server.on_jump;
  • resources:[{path,scope,role,sha256,size}].

Each resource is limited to 16 MiB; a package to 64 MiB and 128 resources; the package directory to 128 entries. These are server limits; the browser additionally limits the total verified public resources to 128 MiB per connection. Block definitions use the definitions role, and a resource with this role requires schema 1. The server allows up to 4096 additional definitions. A block specifies state as a new namespace:path identifier without properties (lowercase ASCII letters, digits, _, ., and -, plus / in the path), color:[r,g,b], collision:[{min,max}], and an optional render of the same form. Optional opacity is a number from 0…1. If render is omitted, the existing original shape for that state is used, or the collision shape for a new block. Each set may contain at most 64 boxes; the allowed local coordinate range is 2…3. Duplicate definitions and overrides of minecraft:* are rejected. The persistent registry assigns runtime IDs; Game::open extends the catalog with verified definitions before registering them in WorldStore. An ordinary package block without behavior is stored and participates in physics; behavior.server_hook: on_jump binds it to the active WASM provider.

{
  "schema": 1,
  "blocks": [{
    "state": "example:spring",
    "color": [97,205,151],
    "collision": [{"min":[0,0,0],"max":[1,1,1]}],
    "render": [{"min":[0,0,0],"max":[1,1,1]}],
    "behavior": {"server_hook":"on_jump"}
  }]
}

Module execution

The MVP requires exactly one active provider for the on_jump server hook; no provider or two modules with this role prevents startup. A server .wasm file is declared as a resource with role: "wasm-on-jump" and scope: "server"; the server.on_jump capability is required. The export on_jump: () -> f32 returns a jump impulse in blocks/s. The server calls it only when a player jumps from a block bound to the hook through a verified package definition.

Execution uses Wasmi with no imports, files, network access, or system calls; at most 10,000 fuel units per call, one memory up to 64 KiB, one table up to 128 elements, and one instance. The binary module is limited to 64 KiB. The result must be a finite number from 0…20; a trap or invalid value is recorded in a metric and falls back to a normal jump. The working example returns 10. Tests cover an actual invocation, an infinite loop, excessive memory, an attempted import, and NaN. A separate test creates an example:spring package, verifies its SHA-256, adds a new block to the catalog, registers and persists its runtime ID, binds the block to the module, and receives an impulse of 12 from its own binary WASM module. Duplicates, Minecraft overrides, invalid geometry, opacity/identifiers, and resource changes after loading are rejected.

This is a limited, working extension API, with no claim of arbitrary Forge/Fabric compatibility or WASM access to full world state. A new hook requires an explicit contract version. Spleef in this MVP is implemented as a Rust server mode with persistent rules.

Client resources

/api/manifest returns the public list with URLs, exact versions, sizes, and SHA-256 hashes. The browser downloads files, verifies their sizes and hashes before joining, then stores them in CacheStorage keyed by hash. Cached contents are verified again on subsequent connections. A hash error removes the corrupted entry and prevents joining. The server rejects a mismatched manifest_hash. A public hash does not prove that the client application is unmodified.

The base package provides a pixel texture; the trampoline provides its own texture, a GLSL color function, style settings, and a short synthesized sound. The custom WebGL2 renderer applies them. The core and server contain no graphics engine. Packages do not load arbitrary privileged JavaScript.

Local block texture packs

A client-style resource may declare a texture_pack with a display name, a pixel_size from 1 to 128, and textures: [{name, path}]. Each image path must name a resource from the same package that has already passed size and SHA-256 verification, and every image must be square with the declared pixel size. The client decodes the PNGs into a WebGL2 texture array and uses nearest-neighbor sampling. The local study uses actual 32×32 images. Known block faces select images by Minecraft texture name; missing faces keep the core's procedural material. Grass-top and oak-leaf masks receive a green tint, and transparent pixels are cut out. This is a partial block-texture layer, not support for arbitrary resource-pack models, animations, entities, or shaders.

Prepare the local 24-texture study using the standard-library helper:

python3 scripts/prepare_texture_pack.py \
  --source artifacts/pixel-pack-32/pack \
  --output artifacts/pixel-pack-32/shacraft-packages
target/release/shacraft-server \
  --data artifacts/mvp-demo \
  --packages artifacts/pixel-pack-32/shacraft-packages \
  --listen 127.0.0.1:4000

The helper copies the selected images verbatim and bundles the required base and trampoline packages. All 24 default images must exist and match the declared dimensions. The default is 32×32; --pixel-size 64 packages real 64×64 inputs (16, 32, 64 and 128 are supported). It validates dimensions without resampling, writes the matching pixel_size, and updates resource sizes and hashes. Use --textures stone dirt ... to select a different subset, and --name, --id, --version, and --license to describe another pack. --overwrite rebuilds only a directory marked as a previous output of this helper. It never downloads source art. Preparing a pack does not grant distribution rights; the reference-derived study and its bundle remain under ignored artifacts/ and are not included in the repository. Restart a running server with the generated --packages directory and reload the game to activate it. F3 shows the active pack name and texture count.

When modifying a package, recalculate the size and SHA-256 of each changed resource, increase the version, and update exact dependencies. scripts/catalog_assets.py reproducibly generates the bundled original resources and manifests. The format is designed for a future launcher: it can consume the same manifest and cache by (id,version,sha256); integration with a specific launcher is outside this repository's scope.

Local full-catalog atlas

For local compatibility testing, scripts/prepare_vanilla_texture_pack.py accepts an existing Java client JAR, its matching generated block-state report, and a new output directory. It does not download assets. Pillow is required.

python3 scripts/prepare_vanilla_texture_pack.py \
  --jar artifacts/pixel-pack-32/source-cache/minecraft-26.2-client.jar \
  --states artifacts/catalog-cache/generated/reports/blocks.json \
  --output artifacts/vanilla-local/packages

The resulting package declares atlas: {path, columns, rows} alongside the texture names. All tiles have pixel_size dimensions; integer texel sampling prevents bleeding and avoids the GPU's array-layer limit. The atlas and style are verified package resources. Optional block_faces: {sets, states, defaults} maps canonical states to six-face sets in east/west/up/down/south/north order. Each face supplies a texture name, optional tint/cutout flag, and optional eight-number UV transform (two affine rows over local x/y/z/1). Validated mappings are transferred to terrain and edit workers with the texture map.

The importer resolves model inheritance, variants, rotations, and face materials onto the engine's existing geometry. It selects a representative face for multipart geometry and uses particle materials for entity-rendered blocks. It does not import full models, block-entity rendering, biome tint maps, or animation playback. Animated sprites use the first declared frame; native 16-pixel sprites are doubled without changing their colors in 32-pixel atlas cells. These are local testing assets with Mojang/Microsoft ownership, not open-source repository assets or a redistributable default pack. Keep the output under ignored artifacts/. Select its directory with the server's --packages option; selecting the previous package directory restores the previous textures.