Files
bworld/common/protocol.ts
T
2026-09-24 19:34:07 -03:00

81 lines
2.8 KiB
TypeScript

// messages sent between the client and the server, as json over a websocket
import type { Faces } from "./constants.ts";
import type { ItemData } from "./inventory.ts";
export const AIR_ID = "bworld:air";
export interface PlayerInfo {
id: string;
name: string;
x: number;
y: number;
z: number;
yaw: number;
pitch: number;
}
// x, y, z, block id
export type BlockChange = [number, number, number, string];
// the containers a client can see and click. "screen" is whatever the open server screen shows
export type ContainerKey = "inventory" | "crafting" | "screen";
export const CRAFTING_RESULT_SLOT = 9;
// a screen the server opens, drawn below the player's inventory and hotbar
export interface ScreenLayout {
// height of the screen's own area, in slots
rows: number;
// x and y in slots, can be fractional
// output slots can only be taken from, like the furnace result
slots: { index: number; x: number; y: number; output?: boolean }[];
// progress bars filled from properties[value] / properties[max]
bars: {
x: number;
y: number;
value: string;
max: string;
direction: "up" | "right";
empty_texture: string;
full_texture: string;
}[];
}
// clients send what the player is trying to do, the server decides what happens
export type ClientMessage =
| { type: "hello"; name: string }
| { type: "move"; x: number; y: number; z: number; yaw: number; pitch: number }
| { type: "break_block"; x: number; y: number; z: number }
// right click on a block: interact with it, or place the held block against `face`
| { type: "use_block"; x: number; y: number; z: number; face: Faces }
| { type: "select_slot"; slot: number }
| { type: "click"; container: ContainerKey; index: number; button: number }
// closes the open screen, including the player's own inventory screen
| { type: "close_screen" }
| { type: "chat"; text: string };
export type ServerMessage =
| {
type: "welcome";
id: string;
seed: string;
players: PlayerInfo[];
changes: BlockChange[];
spawn: { x: number; y: number; z: number; yaw: number; pitch: number };
selected_slot: number;
}
| { type: "player_join"; player: PlayerInfo }
| { type: "player_leave"; id: string }
| { type: "player_move"; id: string; x: number; y: number; z: number; yaw: number; pitch: number }
// also sent to the player who caused it, which corrects anything their client predicted wrong
| { type: "set_block"; x: number; y: number; z: number; id: string }
| { type: "chat"; from?: string; text: string }
| { type: "container"; container: ContainerKey; items: (ItemData | null)[] }
| { type: "cursor"; item: ItemData | null }
| { type: "open_screen"; layout: ScreenLayout; properties: Record<string, number> }
| { type: "screen_properties"; properties: Record<string, number> }
| { type: "close_screen" };
export const MAX_NAME_LENGTH = 16;
export const MAX_CHAT_LENGTH = 256;