Modules / Networking

visionplugin + addon

Team vision: each seat sent only the rows its team sees, and the fog of war drawn over render2d.

Putting it in a scene

List the plugin before render2d, which draws the fog. The scene gives one block, world.vision, which the server half and the page half both read. The player addon attaches the server half to a scene that names the player plugin and has world.vision, when its first seat joins.

"plugins": ["loader", "scenemanager", "player", "vision", "render2d"],
"world": {
  "vision": {
    "cell": 32, "size": [40, 30],
    "at": "pos", "slot": "seat",
    "teams": [0, 0, 1, 1],
    "sight": { "player": 6, "tower": 10 },
    "always": ["tilemap"],
    "layer": "fog", "unexplored": 0.9, "explored": 0.5
  }
}

A seat is then sent a row only when the row is its team's own, or stands on a cell that a row of its team sees. A row of a kind in always is sent to every seat wherever it is, and so is a row with no place: a manager, the ground, anything that is not a thing on the map. A row that walks out of sight is in the seat's next packet's ended, and one that walks back in is in its born, as if it had been spawned again. A seat with no slot is sent only the rows with no place and the always kinds.

Vision limits what is sent, never what the rules know: the truth holds every row, and a rule that must act only on what a team sees asks sees. What a team sees through a step is what it saw as the step began, so a rule that asks after another row has moved this step is told what one asking before it is told.

Properties

Read from world.vision. A block of the wrong shape is refused.

The map and the seers

SettingMeaning
.cellWorld units across one cell, above 0.
.size[across, down]: the cells of the map, whole numbers above 0. A cell off the map is seen by nobody.
.atThe name of the field holding a row's place, [x, y] or [x, y, h] in world units. h is never read. The row's cell is [⌊x / cell⌋, ⌊y / cell⌋]. A row without the field has no place.
.slotThe name of the field holding the slot of the seat a row belongs to, the slot the player addon gave that seat. A row without it belongs to no team. A player row's team is the slot in its seat field.
.teamsOptional. Each slot's team, a list by slot. Left out, each slot is a team of its own.
.sightKind name to how many cells round its own cell a row of that kind sees, 0 or more: every cell whose middle is within that many cells of the middle of the row's cell. Each kind must have a prefab. A kind not listed sees nothing.
.alwaysKinds sent to every seat wherever their rows stand, the map's pieces. Required, and may be empty. Each must have a prefab.

The fog

Read by the plugin in the page.

SettingMeaning
.layerThe render2d layer the fog is drawn on. Name one above the layers of the things it should cover.
.unexploredThe fog's opacity, 0 to 1, over a cell the team has never seen.
.exploredThe fog's opacity, 0 to 1, over a cell the team has seen and sees no more.

Cells the team sees now are clear. The fog is black, one pixel for each cell stretched over the map through render2d's ground, so it follows the camera as the ground does. Where a cell's edge is drawn smooth, it fades into the next over one cell. Before the seat's player row arrives the whole map is dark.

The page works out what the team sees from the rows it is sent, as the server does. What the team has seen is the page's own memory and lasts as long as this client does, so a seat that leaves the scene and comes back has seen nothing.

Methods

On the server

From #addons/vision/vision.addon.ts.

sees( world, slot, row ) : boolean

Whether the team of slot sees row. A team always sees its own rows. A rule calls it as sees(w.world, slot, row). It is true for every row on a world that no vision is attached to, such as a truth before the player addon has first seated a seat on it.

vision( truth, slot )

Attaches team vision to a truth. slot(seat) returns the slot of the seat, or undefined for a seat with none. The player addon calls it; a game does not need to.

sight( block, rows, into? ) : Map<team, Uint8Array>

Each team's cells seen among rows, one byte a cell, 1 where seen, indexed y × across + x. A team with no seer has no grid. Given into, the grids in it are cleared and filled in place.

visible( block, always, grids, team, row ) : boolean

Whether the team sees the row among the grids sight made: it is the team's own, it has no place, its kind is in the always set, or its cell is seen. grids may be a function returning the grids, called only when the row's cell decides it.

cellOf( block, row ) : number

The row's cell index, y × across + x, or -1 when it has no place or stands off the map.

teamOf( block, slot ) : team | undefined

The team of a slot: the entry of teams for it, or the slot itself when there is no teams. Undefined for a slot that is undefined or null.

On the page

Through plugins.vision, for a map of the page's own, such as a minimap.

cells( ) : Uint8Array | undefined

What the fog was last drawn from, a byte a cell, c = y × across + x: 0 where the team has never seen, 1 where it has seen and sees no more, 2 where it sees now. Undefined until the fog is first drawn. It is written in place each frame, so code that reads it in a tick reads the frame before's.

Used by

  • player
    Attaches the server half to a scene with world.vision when its first seat joins.

In the guide