Interaction reach rules live in World rather than a pure contract #20

Closed
opened 2026-07-27 22:31:56 +00:00 by sickday · 0 comments
Owner

World.reachable?/1 is three clauses of interaction policy — what "close enough
to use this" means for an NPC, for a loc footprint, and for a wall — living
inside the module that owns the tick. It is reachable only through
resolve_action/4, which means the only way to test any of it is to stand a
player up in a running world and drive it through World.request/2.

This is the case the contracts standard exists for: a rule set buried inside
something expensive to run gets extracted into a pure contract, and the burden
is on not doing it.

It is also not academic. The cheap distance gate lives in
Contract.Interaction and the real answer lives in World, and the two drifted
apart in exactly the way that split invites — the gate was used as the verdict
in two separate places, both of which shipped:

  • reachable?/1 answered true unconditionally for :npc and for walls, so
    the gate was the answer,
  • follow/2 decided a walk to a moving target was finished using the gate while
    arrival used the strict test, which strands the player when the target stops
    on a diagonal tile.

Shape of a fix

A Contract.Reach taking the collision snapshot and a target, with one clause
per target kind and one test per clause. World keeps the thunk that fetches
the snapshot; the rules stop being something only the tick can answer.

`World.reachable?/1` is three clauses of interaction policy — what "close enough to use this" means for an NPC, for a loc footprint, and for a wall — living inside the module that owns the tick. It is reachable only through `resolve_action/4`, which means the only way to test any of it is to stand a player up in a running world and drive it through `World.request/2`. This is the case the contracts standard exists for: a rule set buried inside something expensive to run gets extracted into a pure contract, and the burden is on not doing it. It is also not academic. The cheap distance gate lives in `Contract.Interaction` and the real answer lives in `World`, and the two drifted apart in exactly the way that split invites — the gate was used as the verdict in two separate places, both of which shipped: * `reachable?/1` answered `true` unconditionally for `:npc` and for walls, so the gate *was* the answer, * `follow/2` decided a walk to a moving target was finished using the gate while arrival used the strict test, which strands the player when the target stops on a diagonal tile. ### Shape of a fix A `Contract.Reach` taking the collision snapshot and a target, with one clause per target kind and one test per clause. `World` keeps the thunk that fetches the snapshot; the rules stop being something only the tick can answer.
Sign in to join this conversation.
No labels
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
Revenant/Server#20
No description provided.