feat(ludic.base): Systems is an open registry - def a system from any module
The runner's list starts from the declared systems, in the order the compiler gives an open registry, and core_add appends after them. registry_test covers it; the README says ludic test runs the package. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
73129b59d5
commit
cac8c740fa
3 changed files with 43 additions and 12 deletions
|
|
@ -43,6 +43,7 @@ import "ludic.base"
|
||||||
| `sv_put_int`, `sv_put_float`, `sv_put_bool`, `sv_put_str`, `sv_put_ints` | the matching writes |
|
| `sv_put_int`, `sv_put_float`, `sv_put_bool`, `sv_put_str`, `sv_put_ints` | the matching writes |
|
||||||
| `System { key, phase, version, init, reset, tick, save, load }`, `system_new(key, phase)` | a system; a null function is a verb it does not have |
|
| `System { key, phase, version, init, reset, tick, save, load }`, `system_new(key, phase)` | a system; a null function is a verb it does not have |
|
||||||
| `core_add(s)`, `core_clear()`, `core_count()` | the game's system list (a key may appear once) |
|
| `core_add(s)`, `core_clear()`, `core_count()` | the game's system list (a key may appear once) |
|
||||||
|
| `def Systems key { ... }`, `SYS_<KEY>`, `SYS_COUNT` | a system declared from any module; the list starts from these |
|
||||||
| `core_init_all()`, `core_reset_all()`, `core_tick_all(t)`, `core_save_all() -> Val`, `core_load_all(v)` | the runner: in the order added, tick phase by phase |
|
| `core_init_all()`, `core_reset_all()`, `core_tick_all(t)`, `core_save_all() -> Val`, `core_load_all(v)` | the runner: in the order added, tick phase by phase |
|
||||||
|
|
||||||
## A toy mechanic
|
## A toy mechanic
|
||||||
|
|
@ -123,24 +124,26 @@ Both are compiled and run by `tests/route_test.ludic` (the mechanics are `tests/
|
||||||
|
|
||||||
## Tests
|
## Tests
|
||||||
|
|
||||||
Each piece has a program under `tests/`, built and run directly:
|
Each piece has a program under `tests/`, and `ludic test` runs them all, every test block in a
|
||||||
|
process of its own:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ludic build packages/ludic.base/tests/queue_test.ludic --headless -o /tmp/queue_test && /tmp/queue_test
|
ludic test packages/ludic.base
|
||||||
```
|
```
|
||||||
|
|
||||||
`queue_test`, `rng_test`, `save_test`, `system_test` and `route_test`. Two things the language
|
`queue_test`, `rng_test`, `save_test`, `system_test`, `registry_test` and `route_test`. They were
|
||||||
does not do yet shape them: a generic call inside a `test` body is not resolved (so the queue
|
written before a generic call inside a `test` body resolved and before each test had a fresh
|
||||||
cases are functions a test calls), and test blocks share one program's globals (so each case
|
state, so the queue cases are functions a test calls and the runner's cases start with
|
||||||
that uses the runner starts with `core_clear()`); `ludic test <dir>` with a fresh state per
|
`core_clear()`; neither is needed any more.
|
||||||
test will lift the second.
|
|
||||||
|
|
||||||
## Later
|
## Later
|
||||||
|
|
||||||
- `port FishingWorld { ... }` / `bind` will replace the record of function values, checked at
|
- `port FishingWorld { ... }` / `bind` will replace the record of function values, checked at
|
||||||
compile time instead of a null at run time.
|
compile time instead of a null at run time.
|
||||||
- `open registry Systems of System` could replace `core_add`: each mechanic `def`s its system and
|
- `Systems` is an `open registry`, so a system can be declared instead of added: `def Systems
|
||||||
the game's own `def`s give the order. Function values in a `def` work today (`def Systems a {
|
fishing { phase: PH_SIMULATE, tick: fn fishing_tick }` from any module. The runner starts from
|
||||||
tick: fn a_tick }`); what is missing is a registry a package declares and a game fills, in an
|
the declared systems - the order the compiler gives an open registry: ludic.base's own (none),
|
||||||
order the game controls. Until then the list is built by calls, in one place.
|
then each other module's by module name, each module's in the order it is read - and `core_add`
|
||||||
|
appends after them. A game that wants to decide the order itself writes the `def`s in its own
|
||||||
|
files, or keeps calling `core_add` in one place.
|
||||||
- `module toy_fishing uses ludic_base` will make rule 1 a compile error rather than a review.
|
- `module toy_fishing uses ludic_base` will make rule 1 a compile error rather than a review.
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,17 @@ export property System {
|
||||||
load: fn(Val, int) -> void = null
|
load: fn(Val, int) -> void = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# the declared list: a mechanic or the game writes `def Systems fishing { phase: PH_ACT, tick: fn
|
||||||
|
# fishing_tick }` from its own module; the runner starts from these, then core_add appends
|
||||||
|
export open registry Systems of System as SYS
|
||||||
|
|
||||||
var cs_list: []System = null
|
var cs_list: []System = null
|
||||||
|
|
||||||
function cs_all() -> []System {
|
function cs_all() -> []System {
|
||||||
if cs_list == null { cs_list = new []System }
|
if cs_list == null {
|
||||||
|
cs_list = new []System
|
||||||
|
for i in 0 .. SYS_COUNT { push(cs_list, Systems[i]) }
|
||||||
|
}
|
||||||
return cs_list
|
return cs_list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
21
packages/ludic.base/tests/registry_test.ludic
Normal file
21
packages/ludic.base/tests/registry_test.ludic
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
# registry_test.ludic - systems declared with `def Systems ...` from outside the package: the
|
||||||
|
# runner starts from them in the registry's order, and core_add still appends after them
|
||||||
|
import "ludic.base"
|
||||||
|
program RegistryTest {
|
||||||
|
numbers float
|
||||||
|
var trail: string = ""
|
||||||
|
function late_tick(t: Tick) -> void { trail = trail + "l" }
|
||||||
|
function early_tick(t: Tick) -> void { trail = trail + "e" }
|
||||||
|
function added_tick(t: Tick) -> void { trail = trail + "a" }
|
||||||
|
def Systems late { phase: PH_RESOLVE, tick: fn late_tick }
|
||||||
|
def Systems early { phase: PH_INPUT, tick: fn early_tick }
|
||||||
|
test "the declared systems run, phase by phase" {
|
||||||
|
expect_eq(core_count(), 2)
|
||||||
|
expect(Systems[SYS_LATE].key == "late")
|
||||||
|
let s = system_new("added", PH_INPUT)
|
||||||
|
s.tick = fn added_tick
|
||||||
|
core_add(s)
|
||||||
|
core_tick_all(tick_new(0.016, 1, 0.0))
|
||||||
|
expect(trail == "eal")
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue