Skip to content

fix(script_contract): derive built-ins from scene.builtins; add Emitter (#886) - #909

Merged
apotema merged 1 commit into
mainfrom
fix/886-script-contract-builtins
Sep 28, 2026
Merged

apotema merged 1 commit into
mainfrom
fix/886-script-contract-builtins

Conversation

@apotema

@apotema apotema commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Closes #886.

Problem

src/script_contract.zig built its set of scene built-ins from a hand-written list (Sprite, Shape, Tilemap, Camera, Image). It left out Emitter, so labelle_component_set("Emitter", …) fell through to the registry loop and returned -1, even though scenes, .zon and prefab refresh all accept it. This was the third site that listed built-ins by hand. #884 fixed the other two.

Fix

  • builtin_comps is now derived from scene.builtins.Builtin. It keeps the enum's shadowable rule: Sprite/Shape are always built-ins, and Tilemap/Camera/Image/Emitter step aside when the project registers a component with the same name. Each type comes from Builtin.Type(G).

  • The code that differs per built-in is now written as exhaustive switches over Builtin:

    • setBuiltinComponent (which apply fn to call)
    • builtinJsonInto (get serialization and the batch write-back)
    • the typed teardown in componentRemoveImpl

    The old if (eql(name, "Sprite")) … else chains are gone, so adding a tag to Builtin without handling it here is a compile error.

  • Emitter:

    • set goes through the scene's own applyEmitter, which also turns on drive_particles.
    • After that it calls refreshParticleSystem, so a live pool picks up the new config.
    • remove drops the component and frees the pool right away, even while the game is hard-paused.
  • contract/labelle_script.h support table and the module docs now list Emitter. This is an additive change, so there is no version bump.

Tests

New file test/script_contract_builtins_test.zig, added to build.zig:

  • Drift guard: loops over scene.builtins.names. For each built-in it checks that set/get/has/remove work from a script and that the stored component is the engine's built-in type.
  • Emitter set/get: checks drive_particles gets turned on (only applyEmitter does that), a get→set round-trip, the preset enum, and that malformed JSON returns -1 and leaves the entity untouched.
  • Emitter resync: after a tick, a re-set drops the stale ParticleSystem at set time, and the next tick rebuilds it with the new rate. A remove under setTimeScale(0) frees it immediately.
  • Shadowing: when a project registers its own Emitter, set/get/remove go to the registry type, the engine type never appears, and drive_particles stays off.

How the tests were checked locally (Windows, Zig 0.16.0, zig build test):

  • Fake enum tag: added a fake tag Fake886 to Builtin. With no Fake886Comp decl, the derivation fails to compile (a clear @compileError), and so does entity_writer's switch. After adding Fake886Comp on Game, all three script_contract switches failed: switch must handle all possibilities at lines 1564 (set), 1589 (get JSON) and 1769 (remove).
  • Old bug: skipped .Emitter in the derivation to reproduce it. The drift-guard test and both Emitter tests failed.
  • Probe: a temporary probe error made the new test file fail, which confirms the file really runs.
  • Clean run: the final run has the same failure count as origin/main on this Windows machine (47 failed + 7 crashed on both, from tests that already fail on Windows: sockets and u64 pid types). None of those failures are in the script contract tests.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

…er (#886)

The scripting contract kept its own hand-written list of scene built-ins
and forgot `Emitter`, so `labelle_component_set("Emitter", ...)` returned
-1 while every other authoring channel accepted it.

`builtin_comps` is now derived from `scene.builtins.Builtin` with the
enum's `shadowable` rule (Sprite/Shape unconditional; the rest defer to a
project-registered component of the same name). Per-built-in behaviour
(apply fn, get serialization, typed teardown) moves into exhaustive
switches over `Builtin`, so a new tag fails to compile here until handled.

Emitter set goes through the scene's `applyEmitter` (drive_particles
opt-in) and resyncs a live ParticleSystem; remove releases it.

New test/script_contract_builtins_test.zig iterates the enum (drift
guard), covers Emitter set/get/remove + side-table resync, and the
registered-Emitter shadowing rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Caqyi5Snr6yKssztYFztzZ
@coderabbitai

coderabbitai Bot commented Sep 28, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 35 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available. Your 101 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 9254f113-9d8f-46ea-be67-9a705386bc84

📥 Commits

Reviewing files that changed from the base of the PR and between 1f238a7 and f5993ea.

📒 Files selected for processing (4)
  • build.zig
  • contract/labelle_script.h
  • src/script_contract.zig
  • test/script_contract_builtins_test.zig

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-28T23:49:29.127796Z f5993ea PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@apotema
apotema merged commit e0548a8 into main Sep 28, 2026
4 checks passed
@apotema
apotema deleted the fix/886-script-contract-builtins branch September 28, 2026 23:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Scripting contract has a third hand-maintained built-in list, and Emitter is missing from it

1 participant