feat(scripting): expose blocks.register and items.register #12

Merged
Serkyo merged 2 commits from feat/blocks-items-register into dev 2026-09-30 12:00:19 +00:00
Owner

What does this PR do?

I added synvael.blocks.register and synvael.items.register, the first content registration functions in the Lua API.

In shared, I defined BlockDef and ItemDef in registry.rs. Both derive Deserialize with deny_unknown_fields, and each has a validate method that returns the new RegistryError::InvalidDef naming the content id. A block only carries display_name for now. An item carries display_name, max_stack (at least 1) and weight (finite and non-negative).

In scripting, the new content.rs builds both functions through api::func, marked server-only and load-only. Each takes one table, reads the id, checks that its namespace matches the pack currently loading, deserialises the remaining fields into the definition, validates it and registers it into a RegistryBuilder kept in the VM's app data. The function returns the id string, so numeric handles never reach Lua. The block builder starts with syn:air. After finish_load, the new ScriptVm::take_content hands the caller a Content holding both unbound builders, and returns None while loading or once taken.

I updated docs/scripting.md with a section on registration, including the field table, and fixed the blocks.register example there. In docs/packs.md and ADR-0007 the example used a bare id = "stone"; I changed it to syn:stone and added a dated amendment note to the ADR.

Why is this change necessary?

Packs had a VM and a loader but no way to declare content, so nothing could populate the block and item registries. ADR-0007 requires data packs and Lua mods to share one registration path through the Lua API, and these two functions are that path. ADR-0005 requires fully qualified ids everywhere, which is why a bare id or an id in another pack's namespace is an error. Handles stay on the Rust side because they belong to one world's ID table and do not exist until the registries are bound.

Scope of Changes

shared, scripting, workspace

Testing

I ran on the branch head:

  • cargo check -p shared -p scripting: passed
  • cargo test -p shared -p scripting: all passed (18 in scripting, 278 in shared)
  • cargo clippy --all-targets --all-features -- -D warnings: passed
  • cargo fmt --all -- --check: passed

No Lua files changed, so selene and stylua were not needed.

New tests in scripting/src/tests/content.rs load real packs and cover registration order and binding after load, invalid registrations erroring with the id, syn:air being rejected as a duplicate, registration after load failing, the client VM lacking both functions, and the generated docs listing every accepted field. shared/src/tests/registry.rs gained a test for out of range definition fields. I made TempPack in the pack tests pub(crate) so the content tests reuse it, and narrowed the log test to log.* paths now that the VM exposes more functions.

Additional Context

This adds a Lua API surface at 0.1.0. Every definition field is required and unknown keys are rejected, so adding an optional field later is compatible but adding a required one will break existing packs. take_content returns unbound builders; binding against a world's ID tables is left to the caller, which does not exist yet.

None.

Checklist

  • I have branched from dev (or a feature branch off dev) and my PR targets dev.
  • I have kept my changes focused to a single concept.
  • I have added or updated documentation (/// doc comments for Rust) where necessary.
  • I have tested my changes and described any relevant automated or manual testing above.
### What does this PR do? I added `synvael.blocks.register` and `synvael.items.register`, the first content registration functions in the Lua API. In `shared`, I defined `BlockDef` and `ItemDef` in `registry.rs`. Both derive `Deserialize` with `deny_unknown_fields`, and each has a `validate` method that returns the new `RegistryError::InvalidDef` naming the content id. A block only carries `display_name` for now. An item carries `display_name`, `max_stack` (at least 1) and `weight` (finite and non-negative). In `scripting`, the new `content.rs` builds both functions through `api::func`, marked server-only and load-only. Each takes one table, reads the `id`, checks that its namespace matches the pack currently loading, deserialises the remaining fields into the definition, validates it and registers it into a `RegistryBuilder` kept in the VM's app data. The function returns the id string, so numeric handles never reach Lua. The block builder starts with `syn:air`. After `finish_load`, the new `ScriptVm::take_content` hands the caller a `Content` holding both unbound builders, and returns `None` while loading or once taken. I updated `docs/scripting.md` with a section on registration, including the field table, and fixed the `blocks.register` example there. In `docs/packs.md` and ADR-0007 the example used a bare `id = "stone"`; I changed it to `syn:stone` and added a dated amendment note to the ADR. ### Why is this change necessary? Packs had a VM and a loader but no way to declare content, so nothing could populate the block and item registries. ADR-0007 requires data packs and Lua mods to share one registration path through the Lua API, and these two functions are that path. ADR-0005 requires fully qualified ids everywhere, which is why a bare id or an id in another pack's namespace is an error. Handles stay on the Rust side because they belong to one world's ID table and do not exist until the registries are bound. ### Scope of Changes shared, scripting, workspace ### Testing I ran on the branch head: - `cargo check -p shared -p scripting`: passed - `cargo test -p shared -p scripting`: all passed (18 in `scripting`, 278 in `shared`) - `cargo clippy --all-targets --all-features -- -D warnings`: passed - `cargo fmt --all -- --check`: passed No Lua files changed, so selene and stylua were not needed. New tests in `scripting/src/tests/content.rs` load real packs and cover registration order and binding after load, invalid registrations erroring with the id, `syn:air` being rejected as a duplicate, registration after load failing, the client VM lacking both functions, and the generated docs listing every accepted field. `shared/src/tests/registry.rs` gained a test for out of range definition fields. I made `TempPack` in the pack tests `pub(crate)` so the content tests reuse it, and narrowed the log test to `log.*` paths now that the VM exposes more functions. ### Additional Context This adds a Lua API surface at `0.1.0`. Every definition field is required and unknown keys are rejected, so adding an optional field later is compatible but adding a required one will break existing packs. `take_content` returns unbound builders; binding against a world's ID tables is left to the caller, which does not exist yet. ### Related Issues None. ### Checklist - [x] I have branched from `dev` (or a feature branch off `dev`) and my PR targets `dev`. - [x] I have kept my changes focused to a single concept. - [x] I have added or updated documentation (`///` doc comments for Rust) where necessary. - [x] I have tested my changes and described any relevant automated or manual testing above.
feat(scripting): expose blocks.register and items.register
All checks were successful
Auto Labeler / label-scope (pull_request_target) Successful in 3s
CLA Signed All authors have signed the CLA.
CLA Check / cla-check (pull_request_target) Successful in 2s
CI / Rust Check, Lint & Test (pull_request) Successful in 35m19s
CI / Dependency Licenses & Advisories (pull_request) Successful in 30s
CI / Lua Lint & Format (pull_request) Successful in 7s
CI / Commit Message Lint (pull_request) Successful in 2s
CI / LFS Pointer Guard (pull_request) Successful in 5s
12d311c548
Serkyo deleted branch feat/blocks-items-register 2026-09-30 12:00:19 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Synvael/synvael!12
No description provided.