boardgame.io
Version:
library for turn-based games
284 lines (283 loc) • 10.6 kB
TypeScript
import { Object } from 'ts-toolbelt';
import Koa from 'koa';
import { Store as ReduxStore } from 'redux';
import * as ActionCreators from './core/action-creators';
import { Flow } from './core/flow';
import { CreateGameReducer } from './core/reducer';
import { INVALID_MOVE } from './core/constants';
import * as StorageAPI from './server/db/base';
import { EventsAPI } from './plugins/plugin-events';
import { RandomAPI } from './plugins/plugin-random';
export { StorageAPI };
export declare type AnyFn = (...args: any[]) => any;
export interface State<G extends any = any, CtxWithPlugins extends Ctx = Ctx> {
G: G;
ctx: Ctx | CtxWithPlugins;
deltalog?: Array<LogEntry>;
plugins: {
[pluginName: string]: PluginState;
};
_undo: Array<Undo<G>>;
_redo: Array<Undo<G>>;
_stateID: number;
}
export declare type PartialGameState = Pick<State, 'G' | 'ctx' | 'plugins'>;
export declare type StageName = string;
export declare type PlayerID = string;
export declare type StageArg = StageName | {
stage?: StageName;
moveLimit?: number;
};
export interface ActivePlayersArg {
currentPlayer?: StageArg;
others?: StageArg;
all?: StageArg;
value?: Record<PlayerID, StageArg>;
moveLimit?: number;
revert?: boolean;
next?: ActivePlayersArg;
}
export interface ActivePlayers {
[playerID: string]: StageName;
}
export interface Ctx {
numPlayers: number;
playOrder: Array<PlayerID>;
playOrderPos: number;
playerID?: PlayerID;
activePlayers: null | ActivePlayers;
currentPlayer: PlayerID;
numMoves?: number;
gameover?: any;
turn: number;
phase: string;
_activePlayersMoveLimit?: Record<PlayerID, number>;
_activePlayersNumMoves?: Record<PlayerID, number>;
_prevActivePlayers?: Array<{
activePlayers: null | ActivePlayers;
_activePlayersMoveLimit?: Record<PlayerID, number>;
_activePlayersNumMoves?: Record<PlayerID, number>;
}>;
_nextActivePlayers?: ActivePlayersArg;
_random?: {
seed: string | number;
};
events?: EventsAPI;
random?: RandomAPI;
}
export interface PluginState {
data: any;
api?: any;
}
export interface LogEntry {
action: ActionShape.MakeMove | ActionShape.GameEvent;
_stateID: number;
turn: number;
phase: string;
redact?: boolean;
automatic?: boolean;
}
interface PluginContext<API extends any = any, Data extends any = any, G extends any = any> {
G: G;
ctx: Ctx;
game: Game;
api: API;
data: Data;
}
export interface Plugin<API extends any = any, Data extends any = any, G extends any = any> {
name: string;
noClient?: (context: PluginContext<API, Data, G>) => boolean;
setup?: (setupCtx: {
G: G;
ctx: Ctx;
game: Game<G, Ctx>;
}) => Data;
action?: (data: Data, payload: ActionShape.Plugin['payload']) => Data;
api?: (context: {
G: G;
ctx: Ctx;
game: Game<G, Ctx>;
data: Data;
playerID?: PlayerID;
}) => API;
flush?: (context: PluginContext<API, Data, G>) => Data;
dangerouslyFlushRawState?: (flushCtx: {
state: State<G, Ctx>;
game: Game<G, Ctx>;
api: API;
data: Data;
}) => State<G, Ctx>;
fnWrap?: (fn: AnyFn) => (G: G, ctx: Ctx, ...args: any[]) => any;
}
declare type MoveFn<G extends any = any, CtxWithPlugins extends Ctx = Ctx> = (G: G, ctx: CtxWithPlugins, ...args: any[]) => any;
export interface LongFormMove<G extends any = any, CtxWithPlugins extends Ctx = Ctx> {
move: MoveFn<G, CtxWithPlugins>;
redact?: boolean;
noLimit?: boolean;
client?: boolean;
undoable?: boolean | ((G: G, ctx: CtxWithPlugins) => boolean);
}
export declare type Move<G extends any = any, CtxWithPlugins extends Ctx = Ctx> = MoveFn<G, CtxWithPlugins> | LongFormMove<G, CtxWithPlugins>;
export interface MoveMap<G extends any = any, CtxWithPlugins extends Ctx = Ctx> {
[moveName: string]: Move<G, CtxWithPlugins>;
}
export interface PhaseConfig<G extends any = any, CtxWithPlugins extends Ctx = Ctx> {
start?: boolean;
next?: string;
onBegin?: (G: G, ctx: CtxWithPlugins) => any;
onEnd?: (G: G, ctx: CtxWithPlugins) => any;
endIf?: (G: G, ctx: CtxWithPlugins) => boolean | void | {
next: string;
};
moves?: MoveMap<G, CtxWithPlugins>;
turn?: TurnConfig<G, CtxWithPlugins>;
wrapped?: {
endIf?: (state: State<G, CtxWithPlugins>) => boolean | void | {
next: string;
};
onBegin?: (state: State<G, CtxWithPlugins>) => any;
onEnd?: (state: State<G, CtxWithPlugins>) => any;
};
}
export interface StageConfig<G extends any = any, CtxWithPlugins extends Ctx = Ctx> {
moves?: MoveMap<G, CtxWithPlugins>;
next?: string;
}
export interface StageMap<G extends any = any, CtxWithPlugins extends Ctx = Ctx> {
[stageName: string]: StageConfig<G, CtxWithPlugins>;
}
export interface TurnOrderConfig<G extends any = any, CtxWithPlugins extends Ctx = Ctx> {
first: (G: G, ctx: CtxWithPlugins) => number;
next: (G: G, ctx: CtxWithPlugins) => number | undefined;
playOrder?: (G: G, ctx: CtxWithPlugins) => PlayerID[];
}
export interface TurnConfig<G extends any = any, CtxWithPlugins extends Ctx = Ctx> {
activePlayers?: object;
moveLimit?: number;
onBegin?: (G: G, ctx: CtxWithPlugins) => any;
onEnd?: (G: G, ctx: CtxWithPlugins) => any;
endIf?: (G: G, ctx: CtxWithPlugins) => boolean | void | {
next: PlayerID;
};
onMove?: (G: G, ctx: CtxWithPlugins) => any;
stages?: StageMap<G, CtxWithPlugins>;
moves?: MoveMap<G, CtxWithPlugins>;
order?: TurnOrderConfig<G, CtxWithPlugins>;
wrapped?: {
endIf?: (state: State<G, CtxWithPlugins>) => boolean | void | {
next: PlayerID;
};
onBegin?: (state: State<G, CtxWithPlugins>) => any;
onEnd?: (state: State<G, CtxWithPlugins>) => any;
onMove?: (state: State<G, CtxWithPlugins>) => any;
};
}
interface PhaseMap<G extends any = any, CtxWithPlugins extends Ctx = Ctx> {
[phaseName: string]: PhaseConfig<G, CtxWithPlugins>;
}
export interface Game<G extends any = any, CtxWithPlugins extends Ctx = Ctx> {
name?: string;
disableUndo?: boolean;
seed?: string | number;
setup?: (ctx: CtxWithPlugins, setupData?: any) => any;
moves?: MoveMap<G, CtxWithPlugins>;
phases?: PhaseMap<G, CtxWithPlugins>;
turn?: TurnConfig<G, CtxWithPlugins>;
events?: {
endGame?: boolean;
endPhase?: boolean;
endTurn?: boolean;
setPhase?: boolean;
endStage?: boolean;
setStage?: boolean;
pass?: boolean;
setActivePlayers?: boolean;
};
endIf?: (G: G, ctx: CtxWithPlugins) => any;
onEnd?: (G: G, ctx: CtxWithPlugins) => any;
playerView?: (G: G, ctx: CtxWithPlugins, playerID: PlayerID) => any;
plugins?: Array<Plugin<any, any, G>>;
ai?: {
enumerate: (G: G, ctx: Ctx, playerID: PlayerID) => Array<{
event: string;
args?: any[];
} | {
move: string;
args?: any[];
} | ActionShape.MakeMove | ActionShape.GameEvent>;
};
processMove?: (state: State<G, Ctx | CtxWithPlugins>, action: ActionPayload.MakeMove) => State<G, CtxWithPlugins> | typeof INVALID_MOVE;
flow?: ReturnType<typeof Flow>;
}
declare type Undo<G extends any = any> = {
G: G;
ctx: Ctx;
moveType?: string;
};
export declare namespace Server {
type GenerateCredentials = (ctx: Koa.DefaultContext) => Promise<string> | string;
type AuthenticateCredentials = (credentials: string, playerMetadata: PlayerMetadata) => Promise<boolean> | boolean;
type PlayerMetadata = {
id: number;
name?: string;
credentials?: string;
data?: any;
};
interface GameMetadata {
gameName: string;
players: {
[id: number]: PlayerMetadata;
};
setupData?: any;
gameover?: any;
nextRoomID?: string;
unlisted?: boolean;
}
interface LobbyConfig {
uuid?: () => string;
generateCredentials?: GenerateCredentials;
apiPort?: number;
apiCallback?: () => void;
}
}
export declare type Reducer = ReturnType<typeof CreateGameReducer>;
export declare type Store = ReduxStore<State, ActionShape.Any>;
export declare namespace CredentialedActionShape {
type MakeMove = ReturnType<typeof ActionCreators.makeMove>;
type GameEvent = ReturnType<typeof ActionCreators.gameEvent>;
type Plugin = ReturnType<typeof ActionCreators.plugin>;
type AutomaticGameEvent = ReturnType<typeof ActionCreators.automaticGameEvent>;
type Undo = ReturnType<typeof ActionCreators.undo>;
type Redo = ReturnType<typeof ActionCreators.redo>;
type Any = MakeMove | GameEvent | AutomaticGameEvent | Undo | Redo | Plugin;
}
export declare namespace ActionShape {
type StripCredentials<T extends object> = Object.P.Omit<T, ['payload', 'credentials']>;
export type MakeMove = StripCredentials<CredentialedActionShape.MakeMove>;
export type GameEvent = StripCredentials<CredentialedActionShape.GameEvent>;
export type Plugin = StripCredentials<CredentialedActionShape.Plugin>;
export type AutomaticGameEvent = StripCredentials<CredentialedActionShape.AutomaticGameEvent>;
export type Sync = ReturnType<typeof ActionCreators.sync>;
export type Update = ReturnType<typeof ActionCreators.update>;
export type Reset = ReturnType<typeof ActionCreators.reset>;
export type Undo = StripCredentials<CredentialedActionShape.Undo>;
export type Redo = StripCredentials<CredentialedActionShape.Redo>;
export type Any = MakeMove | GameEvent | AutomaticGameEvent | Sync | Update | Reset | Undo | Redo | Plugin;
export {};
}
export declare namespace ActionPayload {
type GetPayload<T extends object> = Object.At<T, 'payload'>;
export type MakeMove = GetPayload<ActionShape.MakeMove>;
export type GameEvent = GetPayload<ActionShape.GameEvent>;
export {};
}
export declare type FilteredMetadata = {
id: number;
name?: string;
}[];
export interface SyncInfo {
state: State;
filteredMetadata: FilteredMetadata;
initialState: State;
log: LogEntry[];
}