// what server scripts get, see "Server scripts" in MODS.md import type { EventSignal, Face, Id, ItemStack, ModInfo, Position } from "./shared.ts"; export type { EventSignal, Face, Id, ItemStack, ModInfo, Position } from "./shared.ts"; export interface ServerContext { mod: ModInfo; components: ComponentRegistry; // only during setup commands: CommandRegistry; // only during setup events: { before: ServerBeforeEvents; after: ServerAfterEvents }; system: System; world: ServerWorld; players: PlayerList; containers: ContainerApi; recipes: RecipeApi; ui: ServerUi; net: ServerNet; storage: ModStorage; log(...args: unknown[]): void; } // components export interface BlockRef { readonly id: Id; readonly x: number; readonly y: number; readonly z: number; // tile data, any json value. saved with the world, never sent to clients // deno-lint-ignore no-explicit-any data: any; } // P is the component's params from the block json // deno-lint-ignore no-explicit-any export interface BlockComponent

{ on_create?(block: BlockRef, params: P): void; on_break?(block: BlockRef, params: P, player: Player | undefined): void; on_click?(block: BlockRef, params: P, player: Player): void; // return true if it did something, so no block gets placed on_interact?(block: BlockRef, params: P, player: Player): boolean; on_tick?(block: BlockRef, params: P, dt: number): void; on_second?(block: BlockRef, params: P, dt: number): void; } // deno-lint-ignore no-explicit-any export interface ItemComponent

{ on_create?(item: ItemStack, params: P): void; get_lore?(item: ItemStack, params: P): string; on_use?(item: ItemStack, params: P, player: Player): void; } export interface ComponentRegistry { register_block

(id: Id, component: BlockComponent

): void; register_item

(id: Id, component: ItemComponent

): void; } // commands export interface Command { description: string; usage: string; run(args: string[], player: Player): void; } export interface CommandRegistry { register(name: string, command: Command): void; } // events export interface Cancelable { cancel: boolean; } export interface BlockBreakEvent { readonly player: Player; readonly block: BlockRef; readonly item: ItemStack | undefined; } export interface BlockPlaceEvent { readonly player: Player; readonly block: { readonly id: Id } & Position; readonly face: Face; readonly item: ItemStack | undefined; } export interface BlockInteractEvent { readonly player: Player; readonly block: BlockRef; readonly item: ItemStack | undefined; } export interface ChatSendEvent { readonly player: Player; message: string; } export interface ServerBeforeEvents { block_break: EventSignal; block_place: EventSignal; block_interact: EventSignal; chat_send: EventSignal; } export interface ServerAfterEvents { block_break: EventSignal; block_place: EventSignal; block_interact: EventSignal; chat_send: EventSignal>; player_join: EventSignal<{ readonly player: Player }>; player_leave: EventSignal<{ readonly player: Player }>; server_start: EventSignal>; tick: EventSignal<{ readonly dt: number }>; } // world and players export interface ServerWorld { get_block(x: number, y: number, z: number): Id | undefined; // undefined when the chunk isn't loaded set_block(x: number, y: number, z: number, id: Id): boolean; // runs on_break / on_create, synced to everyone get_state(x: number, y: number, z: number, name: string): number | undefined; set_state(x: number, y: number, z: number, name: string, value: number): boolean; get_block_data(x: number, y: number, z: number): T | undefined; is_loaded(x: number, z: number): boolean; readonly seed: string; } export interface Player { readonly id: string; readonly name: string; readonly position: Readonly; readonly inventory: Container; // 36 slots, hotbar is 0-8 readonly selected_slot: number; readonly held_item: ItemStack | undefined; give_item(id: Id, count?: number, data?: unknown): void; send_message(text: string): void; teleport(x: number, y: number, z: number): void; } export interface PlayerList { all(): Player[]; get(id: string): Player | undefined; by_name(name: string): Player | undefined; } export interface System { run_timeout(fn: () => void, ticks: number): number; run_interval(fn: () => void, ticks: number): number; clear_run(handle: number): void; readonly current_tick: number; } // small key value store per mod, saved with the world export interface ModStorage { get(key: string): T | undefined; set(key: string, value: unknown): void; // json values only delete(key: string): void; } // containers and recipes export interface Container { readonly id: string; readonly size: number; get(slot: number): ItemStack | undefined; set(slot: number, item: ItemStack | undefined): void; add(item: ItemStack): ItemStack | undefined; // returns what didn't fit on_change(fn: (slot: number) => void): () => void; } export interface ContainerApi { create(size: number): Container; // saved with the world get(id: string): Container | undefined; delete(id: string): void; } export interface RecipeApi { furnace_result(input: Id): { output: ItemStack; cook_time: number } | undefined; fuel_value(item: Id): number; // burn time in ticks, 0 if it isn't fuel is_fuel(item: Id): boolean; is_smeltable(item: Id): boolean; } // guis export interface ActionForm { title: string; body?: string; buttons: { text: string; icon?: Id }[]; } export interface MessageForm { title: string; body: string; buttons: [string, string]; } export type FormField = | { type: "toggle"; label: string; default?: boolean } | { type: "slider"; label: string; min: number; max: number; step?: number; default?: number } | { type: "dropdown"; label: string; options: string[]; default?: number } | { type: "text"; label: string; placeholder?: string; default?: string; max_length?: number }; export interface ModalForm { title: string; fields: FormField[]; } export type FormResult = ({ canceled: true } & Partial) | ({ canceled: false } & T); export type SlotFilter = "smeltable" | "fuel" | ((item: ItemStack) => boolean); export interface ContainerScreenOptions { title: string; container: Container; // x and y in slot units layout: { slot: number; x: number; y: number; filter?: SlotFilter; output_only?: boolean }[]; player_inventory?: boolean; bars?: { id: string; x: number; y: number; texture: Id }[]; labels?: { x: number; y: number; property: string }[]; } export interface ScreenHandle { readonly player: Player; set_property(id: string, value: number): void; update(props: Props): void; // custom screens only close(): void; on_close(fn: () => void): void; } export interface ServerUi { message_form(player: Player, form: MessageForm): Promise>; action_form(player: Player, form: ActionForm): Promise>; modal_form(player: Player, form: ModalForm): Promise>; open_container(player: Player, options: ContainerScreenOptions): ScreenHandle; open_screen( player: Player, id: Id, props: Props, options?: { containers?: Record }, ): ScreenHandle; } // mod channels export interface ServerNet { on(channel: Id, handler: (player: Player, data: T) => void): void; send(player: Player, channel: Id, data: unknown): void; broadcast(channel: Id, data: unknown): void; }