feat(stdlib): Tiled P4 — objects, custom props/types, templates, opt-in spawn (#72)
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 21s
ci / build-and-test (push) Successful in 1m57s
commit-lint / conventional-commits (push) Successful in 3s
docs / build-and-deploy (push) Successful in 27s

- Object layers: all shapes (rectangle/ellipse/point/polygon/polyline/text) and
  custom properties parse and are queryable — Tiled.object_count / Tiled.object /
  Tiled.object_shape, and Tiled.prop / prop_int / prop_type over any object /
  tile / layer / map.
- Custom types: Tiled.load_types reads an objecttypes.xml project custom-type
  table so a class property resolves its default; enum values resolve as strings.
- Templates: Tiled.template reads a .tx/.tj, and Tiled.load merges each object's
  `template` reference under the instance's overrides (field inheritance).
- Opt-in spawning: Tiled.spawn / Tiled.spawn_layer map an object's class +
  properties onto Ludic components through the reflection ABI (Position from x/y,
  each property to a like-named field). Off by default — no gameplay coupling in
  the core load. Split into tiled_spawn.ludic, spliced only for a Tiled *game*
  (the world table exists only under has_ecs), so a plain map-reading tool never
  links against the reflection ABI.

Proven by library/tiled_p4.ludic (18 assertions) incl. the design's named
orthogonal-outside.tmx object shapes. x test: 95 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-01 15:08:06 +03:00
parent 58e1105f2d
commit b8c71d2a8e
22 changed files with 18278 additions and 17081 deletions

View file

@ -630,6 +630,17 @@ function emit_ns_call(ns: pointer, meth: pointer, e: Node) -> Val {
if (meth == "tree") { bare = "tmap_tree"; push(labels, "map") }
if (meth == "tile_prop") { bare = "tmap_tile_prop"; push(labels, "map"); push(labels, "gid"); push(labels, "name") }
if (meth == "tile_shapes") { bare = "tmap_tile_has_shapes"; push(labels, "map"); push(labels, "gid") }
# P4 (#72): objects / properties / custom types / templates / opt-in spawn
if (meth == "object_count") { bare = "tmap_object_count"; push(labels, "map"); push(labels, "layer") }
if (meth == "object") { bare = "tmap_object"; push(labels, "map"); push(labels, "layer"); push(labels, "index") }
if (meth == "object_shape") { bare = "tiled_object_shape"; push(labels, "object") }
if (meth == "prop") { bare = "tiled_prop_str"; push(labels, "container"); push(labels, "name") }
if (meth == "prop_int") { bare = "tiled_prop_int"; push(labels, "container"); push(labels, "name") }
if (meth == "prop_type") { bare = "tiled_prop_type"; push(labels, "container"); push(labels, "name") }
if (meth == "load_types") { bare = "tiled_load_types"; push(labels, "path") }
if (meth == "template") { bare = "tiled_read_template"; push(labels, "path") }
if (meth == "spawn") { bare = "tiled_spawn_object"; push(labels, "map"); push(labels, "object"); push(labels, "model") }
if (meth == "spawn_layer") { bare = "tiled_spawn_layer"; push(labels, "map"); push(labels, "layer"); push(labels, "model") }
}
# #62: a package-provided namespace (declared with @Namespace(Foo)) that none
# of the hardcoded core blocks matched — alias Foo.method to the bare function

View file

@ -744,6 +744,11 @@ function maybe_splice_runtime() -> void {
do_import("runtime/native/base64.ludic")
do_import("runtime/native/value.ludic")
do_import("runtime/native/tiled.ludic")
# #72 opt-in spawning stands on the reflection ABI, which the compiler emits
# only for a game (emit_decl: has_ecs -> emit_world_table). So splice the
# spawn helpers only for a Tiled game; a plain map-reading tool never links
# against the world table.
if has_ecs() { do_import("runtime/native/tiled_spawn.ludic") }
cur_dir = saved
}
# Reflect.serialize/apply add the reflection serializer, which stands on both

File diff suppressed because it is too large Load diff