Server actually ticks

This commit is contained in:
2026-09-25 13:25:25 -03:00
parent 2a2ccae9ce
commit dfabe40e7a
18 changed files with 763 additions and 79 deletions
+27 -18
View File
@@ -211,8 +211,10 @@ program**, so the server and each client can number blocks differently. Saves an
The client needs this data too (for meshing, mining time and collision), so it's sent to every player. It can't contain
functions.
Block states work the same as today: `[{ "name": "facing", "bits": 2, "default": 0 }]`. They can't change textures yet,
because the mesher ignores them. `variants` is reserved for that.
Block states are declared like `[{ "name": "facing", "bits": 2, "default": 0 }]`, at most 16 bits in total. A block
starts with its defaults when it's placed or generated, and server scripts read and change them with
`ctx.world.get_state` / `set_state`. States are saved with the world and synced to players. They can't change textures
yet, because the mesher ignores them. `variants` is reserved for that.
## Items
@@ -335,18 +337,24 @@ ctx.components.register_block("copper_tools:oxidizes", {
});
```
| Handler | Called when | Return value |
| ------------------------------------ | ----------------------------------------------------- | ------------------------------------------ |
| `on_create(block, params)` | The block is placed or set. | ignored |
| `on_break(block, params, player?)` | The block is broken or replaced. | ignored |
| `on_click(block, params, player)` | A player left clicks it. | ignored |
| `on_interact(block, params, player)` | A player right clicks it. | `true` if handled, so no block gets placed |
| `on_tick(block, params, dt)` | Every tick (20 per second) while its chunk is loaded. | ignored |
| `on_second(block, params, dt)` | Every second while its chunk is loaded. | ignored |
| Handler | Called when | Return value |
| ------------------------------------ | ----------------------------------------- | ------------------------------------------ |
| `on_create(block, params)` | The block is placed or set. | ignored |
| `on_break(block, params, player?)` | The block is broken or replaced. | ignored |
| `on_click(block, params, player)` | A player starts hitting it. | ignored |
| `on_interact(block, params, player)` | A player right clicks it. | `true` if handled, so no block gets placed |
| `on_tick(block, params, dt)` | Every tick (20 per second) near a player. | ignored |
| `on_second(block, params, dt)` | Every second near a player. | ignored |
`block` is `{ id, x, y, z, data }`. `data` is tile data: any JSON value, `undefined` until a handler sets it, saved with
the world and **never sent to clients**. To show tile data to a player, open a screen with it (see [GUIs](#guis)).
`on_tick` and `on_second` only run for blocks that have tile data, like today.
`on_tick` and `on_second` only run for blocks that have tile data, so a component that ticks from the start sets
`block.data` in `on_create`. They run within 6 chunks of a player. `dt` is in seconds: 0.05 for `on_tick`, 1 for
`on_second`.
The server runs a fixed 20 ticks per second. When a tick takes too long, the next ones run back to back until it has
caught up, so game time keeps pace with real time. When it's more than ten ticks behind it skips the rest and logs a
warning. `/tps` shows how it's doing. Timers (`ctx.system`) count these ticks.
When a block lists several components, each handler runs in the listed order. `on_interact` counts as handled if any
component returns `true`.
@@ -354,6 +362,8 @@ component returns `true`.
Item components use
`ctx.components.register_item(id, { on_create(item, params), get_lore(item, params), on_use(item,
params, player) })`.
`on_use` runs when a player right clicks while holding the item, both at nothing and at a block. At a block, the block's
own interaction comes first, and an item with `on_use` is used instead of being placed.
### Events
@@ -436,8 +446,8 @@ ctx.commands.register("heal", {
});
```
Commands run on the server when a player types `/name` in chat. Two mods using the same name, or a mod using a base game
name like `give`, is a load error. `/copper_tools:heal` always works as the unambiguous form.
Commands run on the server when a player types `/name` in chat. Two mods using the same name, or a mod using one of the
engine's (`give` and `tps`), is a load error. `/copper_tools:heal` always works as the unambiguous form.
## Client scripts
@@ -1118,7 +1128,7 @@ loading mods (the base game and the template), their scripts and worldgen, saves
## Implementation plan
Steps 1–5 are done and 6 and 9 mostly, enough that a mod made from the template loads and runs. Each step keeps the game
Steps 1–6 are done and 9 mostly, enough that a mod made from the template loads and runs. Each step keeps the game
working:
1. **Game server core.** Move `client/generation.ts` to `common/` (it already only needs constants and the rng package)
@@ -1136,10 +1146,9 @@ working:
5. **Delivery.** Split `welcome` into `welcome` / `ready` / `join`. Clients download, verify and run mods before
joining. Add the confirm screen for cross-origin servers and CORS headers on the server. _Done._
6. **Server scripts.** Components, events, commands, system, storage and `ctx.recipes`. Move `FURNACE_RECIPES` and
`FUEL_VALUES` into the recipe registry. _Mostly done_ (`server/game/mod_runtime.ts`). Not yet: `on_click` (clients
don't report left clicks on blocks), item `on_use` (there's no item use action), `world.get_state` / `set_state`
(block states aren't synced or saved), and `Container.on_change`. `ctx.containers`, `ctx.ui` and `ctx.net` throw
until steps 7 and 8, and so do the client's `ctx.ui`, `ctx.hud`, `ctx.input` and `ctx.net`.
`FUEL_VALUES` into the recipe registry. _Done_ (`server/game/mod_runtime.ts`, with the loop in
`server/game/game_loop.ts`). `ctx.containers`, `ctx.ui` and `ctx.net` throw until steps 7 and 8, and so do the
client's `ctx.ui`, `ctx.hud`, `ctx.input` and `ctx.net`.
7. **GUIs.** Forms, then container screens (rebuild chest and furnace with them), then custom screens, the `Graphics`
API (built on the existing renderer and debug UI widgets) and the HUD.
8. **Mod channels** and keybinds.