ball2d 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +154 -5
- package/dist/browser.js +4051 -0
- package/dist/core.wasm +0 -0
- package/dist/licenses/fflate.txt +21 -0
- package/dist/licenses/json5.txt +23 -0
- package/dist/licenses/native.json +236 -0
- package/dist/licenses/werift.txt +21 -0
- package/dist/node.js +43399 -0
- package/dist/stadiums/big.hbs +85 -0
- package/dist/stadiums/big_easy.hbs +85 -0
- package/dist/stadiums/big_hockey.hbs +87 -0
- package/dist/stadiums/big_rounded.hbs +100 -0
- package/dist/stadiums/classic.hbs +85 -0
- package/dist/stadiums/easy.hbs +85 -0
- package/dist/stadiums/hockey.hbs +87 -0
- package/dist/stadiums/huge.hbs +85 -0
- package/dist/stadiums/provenance.json +46 -0
- package/dist/stadiums/rounded.hbs +100 -0
- package/dist/stadiums/small.hbs +85 -0
- package/dist/types/client/announcement.d.ts +10 -0
- package/dist/types/client/connection-stats.d.ts +11 -0
- package/dist/types/client/headless.d.ts +130 -0
- package/dist/types/client/host-config.d.ts +11 -0
- package/dist/types/client/host-runtime.d.ts +10 -0
- package/dist/types/client/network-runtime.d.ts +8 -0
- package/dist/types/client/network.d.ts +91 -0
- package/dist/types/client/stadium-library.d.ts +4 -0
- package/dist/types/client/startup-scope.d.ts +6 -0
- package/dist/types/client/traffic.d.ts +9 -0
- package/dist/types/core/avatar.d.ts +2 -0
- package/dist/types/core/build-id.d.ts +2 -0
- package/dist/types/core/control.d.ts +5 -0
- package/dist/types/core/disc-properties.d.ts +7 -0
- package/dist/types/core/engine.d.ts +68 -0
- package/dist/types/core/host-types.d.ts +21 -0
- package/dist/types/core/match-state.d.ts +17 -0
- package/dist/types/core/protocol.d.ts +24 -0
- package/dist/types/core/replay-codec.d.ts +6 -0
- package/dist/types/core/replay-types.d.ts +41 -0
- package/dist/types/core/replay-wire.d.ts +5 -0
- package/dist/types/core/replay.d.ts +48 -0
- package/dist/types/core/stadium.d.ts +91 -0
- package/dist/types/core/team-colors.d.ts +8 -0
- package/dist/types/sdk/browser.d.ts +11 -0
- package/dist/types/sdk/command-queue.d.ts +11 -0
- package/dist/types/sdk/config.d.ts +6 -0
- package/dist/types/sdk/create-options.d.ts +4 -0
- package/dist/types/sdk/node-transport.d.ts +4 -0
- package/dist/types/sdk/node.d.ts +18 -0
- package/dist/types/sdk/replay.d.ts +4 -0
- package/dist/types/sdk/room.d.ts +7 -0
- package/dist/types/sdk/stadium.d.ts +9 -0
- package/dist/types/sdk/types.d.ts +78 -0
- package/dist/types/shared/room-link.d.ts +6 -0
- package/package.json +21 -19
- package/index.js +0 -3
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { MatchState } from './match-state.js';
|
|
2
|
+
import { type DiscPropertyPatch } from './disc-properties.js';
|
|
3
|
+
import { type Stadium } from './stadium.js';
|
|
4
|
+
export declare const HZ = 60, STRIDE = 18, SLOTS = 32, ENGINE_VERSION = "ball2d-core/1/3de72bdcf92ccb0d235a";
|
|
5
|
+
interface Exports extends WebAssembly.Exports {
|
|
6
|
+
memory: WebAssembly.Memory;
|
|
7
|
+
reset: () => void;
|
|
8
|
+
add_disc: () => number;
|
|
9
|
+
set_disc: (i: number, k: number, v: number) => void;
|
|
10
|
+
data_ptr: () => number;
|
|
11
|
+
count: () => number;
|
|
12
|
+
step: () => void;
|
|
13
|
+
wall: (...v: number[]) => void;
|
|
14
|
+
arc: (...v: number[]) => void;
|
|
15
|
+
plane: (...v: number[]) => void;
|
|
16
|
+
joint: (...v: number[]) => void;
|
|
17
|
+
configure: (...v: number[]) => void;
|
|
18
|
+
goal: (...v: number[]) => void;
|
|
19
|
+
physics_mode: (substeps: number) => void;
|
|
20
|
+
kick_limits: (...v: number[]) => void;
|
|
21
|
+
goal_event: () => number;
|
|
22
|
+
ball_kick_events: () => number;
|
|
23
|
+
}
|
|
24
|
+
export type { MatchState } from './match-state.js';
|
|
25
|
+
export declare class Engine {
|
|
26
|
+
core: Exports;
|
|
27
|
+
stadium: Stadium;
|
|
28
|
+
source: string;
|
|
29
|
+
colors: number[];
|
|
30
|
+
tick: number;
|
|
31
|
+
elapsed: number;
|
|
32
|
+
readonly ballKicks: number[];
|
|
33
|
+
red: number;
|
|
34
|
+
blue: number;
|
|
35
|
+
phase: MatchState['phase'];
|
|
36
|
+
paused: boolean;
|
|
37
|
+
resumeTicks: number;
|
|
38
|
+
countdown: number;
|
|
39
|
+
kickoff: 1 | 2;
|
|
40
|
+
kickoffActive: boolean;
|
|
41
|
+
scoreLimit: number;
|
|
42
|
+
timeLimit: number;
|
|
43
|
+
lastGoal: number;
|
|
44
|
+
kickRate: number;
|
|
45
|
+
setKickRateLimit(min: number, rate: number, burst: number): void;
|
|
46
|
+
constructor(instance: WebAssembly.Instance);
|
|
47
|
+
static create(bytes?: BufferSource, signal?: AbortSignal): Promise<Engine>;
|
|
48
|
+
get data(): Float64Array<ArrayBuffer>;
|
|
49
|
+
load(source: string): void;
|
|
50
|
+
private add;
|
|
51
|
+
index(slot: number): number;
|
|
52
|
+
joinPlayer(slot: number): void;
|
|
53
|
+
setTeam(slot: number, team: number): void;
|
|
54
|
+
input(slot: number, keys: number): void;
|
|
55
|
+
applyDiscProperties(index: number, properties: DiscPropertyPatch): boolean;
|
|
56
|
+
private restoreDiscProperties;
|
|
57
|
+
private spawn;
|
|
58
|
+
resetPositions(newMatch?: boolean): void;
|
|
59
|
+
start(): void;
|
|
60
|
+
stop(): void;
|
|
61
|
+
setPaused(paused: boolean): void;
|
|
62
|
+
private finish;
|
|
63
|
+
step(): void;
|
|
64
|
+
snapshot(): MatchState;
|
|
65
|
+
restore(s: MatchState): void;
|
|
66
|
+
}
|
|
67
|
+
export declare function crosses(a: number[], b: number[], c: number[], d: number[]): boolean;
|
|
68
|
+
export declare function packKickRate(min: number, rate: number, burst: number): number;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { DiscProperties } from './disc-properties.js';
|
|
2
|
+
export interface HostPlayer {
|
|
3
|
+
id: number;
|
|
4
|
+
peerId: string;
|
|
5
|
+
name: string;
|
|
6
|
+
team: 0 | 1 | 2;
|
|
7
|
+
admin: boolean;
|
|
8
|
+
avatar?: string | null;
|
|
9
|
+
position: {
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
} | null;
|
|
13
|
+
}
|
|
14
|
+
export interface HostScores {
|
|
15
|
+
red: number;
|
|
16
|
+
blue: number;
|
|
17
|
+
time: number;
|
|
18
|
+
scoreLimit: number;
|
|
19
|
+
timeLimit: number;
|
|
20
|
+
}
|
|
21
|
+
export type HostDiscProperties = DiscProperties;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface MatchState {
|
|
2
|
+
tick: number;
|
|
3
|
+
elapsed: number;
|
|
4
|
+
red: number;
|
|
5
|
+
blue: number;
|
|
6
|
+
phase: 'lobby' | 'playing' | 'goal' | 'finished';
|
|
7
|
+
paused: boolean;
|
|
8
|
+
resumeTicks: number;
|
|
9
|
+
countdown: number;
|
|
10
|
+
kickoff: 1 | 2;
|
|
11
|
+
kickoffActive: boolean;
|
|
12
|
+
scoreLimit: number;
|
|
13
|
+
timeLimit: number;
|
|
14
|
+
kickRate: number;
|
|
15
|
+
discs: number[];
|
|
16
|
+
colors: number[];
|
|
17
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { MatchState } from './engine.js';
|
|
2
|
+
export declare const PROTOCOL = 5, MAX_PACKET = 1200;
|
|
3
|
+
export declare function newer(a: number, b: number): boolean;
|
|
4
|
+
export declare function inputPacket(seq: number, keys: number, time: number, epoch?: number): ArrayBuffer;
|
|
5
|
+
export declare function readInput(b: ArrayBuffer): {
|
|
6
|
+
seq: number;
|
|
7
|
+
keys: number;
|
|
8
|
+
time: number;
|
|
9
|
+
epoch: number;
|
|
10
|
+
};
|
|
11
|
+
export declare function statePackets(state: MatchState, seq: number, epoch?: number): ArrayBuffer[];
|
|
12
|
+
export declare class StateAssembler {
|
|
13
|
+
epoch: number;
|
|
14
|
+
constructor(epoch?: number);
|
|
15
|
+
tick: number;
|
|
16
|
+
parts: Map<number, Uint8Array<ArrayBufferLike>>;
|
|
17
|
+
count: number;
|
|
18
|
+
complete: number;
|
|
19
|
+
reset(epoch?: number, floor?: number): void;
|
|
20
|
+
push(b: ArrayBuffer, baseline: MatchState): {
|
|
21
|
+
state: MatchState;
|
|
22
|
+
ack: number;
|
|
23
|
+
} | null;
|
|
24
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const MAX_REPLAY_BYTES: number;
|
|
2
|
+
/** B2DZ v1 envelope: magic, version/reserved, raw length, FNV checksum, raw DEFLATE. */
|
|
3
|
+
export declare function encodeReplayText(text: string): Uint8Array<ArrayBuffer>;
|
|
4
|
+
export declare function encodeReplayBytes(raw: Uint8Array): Uint8Array<ArrayBuffer>;
|
|
5
|
+
export declare function decodeReplayText(input: string | ArrayBuffer | Uint8Array): string;
|
|
6
|
+
export declare function decodeReplayBytes(input: string | ArrayBuffer | Uint8Array): Uint8Array;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { DiscPropertyPatch } from './disc-properties.js';
|
|
2
|
+
import type { TeamStyles } from './team-colors.js';
|
|
3
|
+
import type { MatchState } from './match-state.js';
|
|
4
|
+
export type ReplayCommand = {
|
|
5
|
+
tick: number;
|
|
6
|
+
kind: 'input' | 'team' | 'start' | 'stop' | 'pause' | 'scoreLimit' | 'timeLimit' | 'kickRate' | 'join' | 'disc';
|
|
7
|
+
properties?: DiscPropertyPatch;
|
|
8
|
+
slot: number;
|
|
9
|
+
value: number;
|
|
10
|
+
};
|
|
11
|
+
interface Checkpoint {
|
|
12
|
+
tick: number;
|
|
13
|
+
state: MatchState;
|
|
14
|
+
hash: string;
|
|
15
|
+
}
|
|
16
|
+
export interface Replay {
|
|
17
|
+
magic: 'B2DR';
|
|
18
|
+
version: 1;
|
|
19
|
+
engine: string;
|
|
20
|
+
stadium: string;
|
|
21
|
+
initial: MatchState;
|
|
22
|
+
commands: ReplayCommand[];
|
|
23
|
+
checkpoints: Checkpoint[];
|
|
24
|
+
roster: {
|
|
25
|
+
tick: number;
|
|
26
|
+
slot: number;
|
|
27
|
+
name: string | null;
|
|
28
|
+
avatar?: string | null;
|
|
29
|
+
}[];
|
|
30
|
+
styles?: {
|
|
31
|
+
tick: number;
|
|
32
|
+
teams: TeamStyles;
|
|
33
|
+
}[];
|
|
34
|
+
orders?: {
|
|
35
|
+
tick: number;
|
|
36
|
+
slots: number[];
|
|
37
|
+
}[];
|
|
38
|
+
end: number;
|
|
39
|
+
finalHash: string;
|
|
40
|
+
}
|
|
41
|
+
export {};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Replay } from './replay.js';
|
|
2
|
+
/** B2DP v2 stores checkpoint discs as lossless float64 before delta-tick commands. */
|
|
3
|
+
export declare function encodeReplayDocument(replay: Replay): Uint8Array<ArrayBuffer>;
|
|
4
|
+
export declare function packReplayDocument(replay: Replay): Uint8Array<ArrayBuffer>;
|
|
5
|
+
export declare function decodeReplayDocument(input: string | ArrayBuffer | Uint8Array): Replay;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type TeamStyles } from './team-colors.js';
|
|
2
|
+
import { Engine, type MatchState } from './engine.js';
|
|
3
|
+
import type { ReplayCommand, Replay } from './replay-types.js';
|
|
4
|
+
export type { ReplayCommand, Replay } from './replay-types.js';
|
|
5
|
+
export declare function stateHash(state: MatchState): string;
|
|
6
|
+
export declare function applyCommand(engine: Engine, c: ReplayCommand): void;
|
|
7
|
+
export declare class Recorder {
|
|
8
|
+
replay: Replay;
|
|
9
|
+
private playerOrder;
|
|
10
|
+
private lastInputs;
|
|
11
|
+
private bytes;
|
|
12
|
+
private full;
|
|
13
|
+
canRecord(engine: Engine): boolean;
|
|
14
|
+
constructor(engine: Engine, players?: {
|
|
15
|
+
slot: number;
|
|
16
|
+
name: string;
|
|
17
|
+
avatar?: string | null;
|
|
18
|
+
}[], styles?: TeamStyles);
|
|
19
|
+
private reserve;
|
|
20
|
+
player(tick: number, slot: number, name: string | null, avatar?: string | null): boolean;
|
|
21
|
+
style(tick: number, teams: TeamStyles): boolean;
|
|
22
|
+
order(tick: number, slots: number[]): boolean;
|
|
23
|
+
command(c: ReplayCommand): boolean;
|
|
24
|
+
step(engine: Engine): void;
|
|
25
|
+
pack(engine: Engine): Uint8Array<ArrayBuffer>;
|
|
26
|
+
finish(engine: Engine): Blob;
|
|
27
|
+
}
|
|
28
|
+
export declare function readReplay(blob: Blob): Promise<Replay>;
|
|
29
|
+
export declare function parseReplay(input: string | ArrayBuffer | Uint8Array): Replay;
|
|
30
|
+
export declare class Playback {
|
|
31
|
+
engine: Engine;
|
|
32
|
+
replay: Replay;
|
|
33
|
+
cursor: number;
|
|
34
|
+
constructor(engine: Engine, replay: Replay);
|
|
35
|
+
teamStyles(): TeamStyles;
|
|
36
|
+
players(): {
|
|
37
|
+
id: string;
|
|
38
|
+
avatar: string | null;
|
|
39
|
+
slot: number;
|
|
40
|
+
name: string;
|
|
41
|
+
team: number;
|
|
42
|
+
admin: boolean;
|
|
43
|
+
}[];
|
|
44
|
+
private commands;
|
|
45
|
+
private final;
|
|
46
|
+
step(): boolean;
|
|
47
|
+
seek(tick: number): void;
|
|
48
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export declare const FLAGS: Record<string, number>;
|
|
2
|
+
export type Vec = [number, number];
|
|
3
|
+
export interface Disc {
|
|
4
|
+
pos: Vec;
|
|
5
|
+
speed: Vec;
|
|
6
|
+
gravity: Vec;
|
|
7
|
+
radius: number;
|
|
8
|
+
invMass: number;
|
|
9
|
+
damping: number;
|
|
10
|
+
bCoef: number;
|
|
11
|
+
cGroup: number;
|
|
12
|
+
cMask: number;
|
|
13
|
+
color: string;
|
|
14
|
+
}
|
|
15
|
+
export interface Segment {
|
|
16
|
+
a: Vec;
|
|
17
|
+
b: Vec;
|
|
18
|
+
bCoef: number;
|
|
19
|
+
cGroup: number;
|
|
20
|
+
cMask: number;
|
|
21
|
+
bias: number;
|
|
22
|
+
color: string;
|
|
23
|
+
vis: boolean;
|
|
24
|
+
renderOnly?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface Arc extends Segment {
|
|
27
|
+
center: Vec;
|
|
28
|
+
radius: number;
|
|
29
|
+
start: number;
|
|
30
|
+
sweep: number;
|
|
31
|
+
major: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface Stadium {
|
|
34
|
+
version: 1;
|
|
35
|
+
physicsMode: 'hbs' | 'substeps';
|
|
36
|
+
name: string;
|
|
37
|
+
canBeStored: boolean;
|
|
38
|
+
width: number;
|
|
39
|
+
height: number;
|
|
40
|
+
maxViewWidth: number;
|
|
41
|
+
cameraFollow: 'ball' | 'player';
|
|
42
|
+
bg: {
|
|
43
|
+
type: 'grass' | 'hockey' | 'none';
|
|
44
|
+
width: number;
|
|
45
|
+
height: number;
|
|
46
|
+
color: string;
|
|
47
|
+
kickOffRadius: number;
|
|
48
|
+
cornerRadius: number;
|
|
49
|
+
goalLine: number;
|
|
50
|
+
};
|
|
51
|
+
discs: Disc[];
|
|
52
|
+
segments: Segment[];
|
|
53
|
+
arcs: Arc[];
|
|
54
|
+
colliders: (Segment | Arc)[];
|
|
55
|
+
planes: {
|
|
56
|
+
normal: Vec;
|
|
57
|
+
dist: number;
|
|
58
|
+
bCoef: number;
|
|
59
|
+
cGroup: number;
|
|
60
|
+
cMask: number;
|
|
61
|
+
}[];
|
|
62
|
+
goals: {
|
|
63
|
+
p0: Vec;
|
|
64
|
+
p1: Vec;
|
|
65
|
+
team: 1 | 2;
|
|
66
|
+
}[];
|
|
67
|
+
joints: {
|
|
68
|
+
d0: number;
|
|
69
|
+
d1: number;
|
|
70
|
+
min: number;
|
|
71
|
+
max: number;
|
|
72
|
+
strength: number | 'rigid';
|
|
73
|
+
color: string;
|
|
74
|
+
}[];
|
|
75
|
+
redSpawnPoints: Vec[];
|
|
76
|
+
blueSpawnPoints: Vec[];
|
|
77
|
+
player: Disc & {
|
|
78
|
+
acceleration: number;
|
|
79
|
+
kickingAcceleration: number;
|
|
80
|
+
kickingDamping: number;
|
|
81
|
+
kickStrength: number;
|
|
82
|
+
kickback: number;
|
|
83
|
+
};
|
|
84
|
+
spawnDistance: number;
|
|
85
|
+
kickOffReset: 'full' | 'partial';
|
|
86
|
+
warnings: string[];
|
|
87
|
+
}
|
|
88
|
+
/** Conservative per-tick work bound, including all possible player slots and static discs. */
|
|
89
|
+
export declare function assertCollisionBudget(mode: Stadium['physicsMode'], discs: number, segments: number, constraints: number, radius: number): void;
|
|
90
|
+
export declare function parseStadium(text: string): Stadium;
|
|
91
|
+
export declare function arenaSource(name?: string, width?: number, height?: number): string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface TeamColors {
|
|
2
|
+
angle: number;
|
|
3
|
+
textColor: number;
|
|
4
|
+
colors: number[];
|
|
5
|
+
}
|
|
6
|
+
export declare function teamColors(angle: number, textColor: number, colors: number[]): TeamColors;
|
|
7
|
+
export type TeamStyles = [TeamColors | null, TeamColors | null];
|
|
8
|
+
export declare function readTeamStyles(value: unknown): TeamStyles;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CreateRoomOptions } from './create-options.js';
|
|
2
|
+
export type { CreateRoomOptions } from './create-options.js';
|
|
3
|
+
import { type RoomConfig } from './config.js';
|
|
4
|
+
import type { Room } from './types.js';
|
|
5
|
+
/** Browser host SDK. Requires the matching Ball2D assets and API on this origin. */
|
|
6
|
+
export declare function createRoom(config?: RoomConfig, options?: CreateRoomOptions): Promise<Room>;
|
|
7
|
+
export { readReplay, type Replay } from './replay.js';
|
|
8
|
+
export type { HostPlayer, HostScores, HostDiscProperties } from '../core/host-types.js';
|
|
9
|
+
export type { Room } from './types.js';
|
|
10
|
+
export type { RoomConfig } from './config.js';
|
|
11
|
+
export { validateStadium, type StadiumValidation } from './stadium.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare class CommandQueue {
|
|
2
|
+
private readonly onError;
|
|
3
|
+
private pending;
|
|
4
|
+
private active?;
|
|
5
|
+
private scheduled;
|
|
6
|
+
private closed;
|
|
7
|
+
constructor(onError?: (error: unknown) => void);
|
|
8
|
+
enqueue<T>(run: () => T | Promise<T>): Promise<T>;
|
|
9
|
+
private drain;
|
|
10
|
+
close(): void;
|
|
11
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type HostConfig } from '../client/host-config.js';
|
|
2
|
+
export interface RoomConfig extends Omit<HostConfig, 'roomName'> {
|
|
3
|
+
roomName?: string;
|
|
4
|
+
}
|
|
5
|
+
/** SDK defaults follow the reference room contract; legacy page defaults are separate. */
|
|
6
|
+
export declare function roomConfig(input: unknown): HostConfig;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { CreateRoomOptions } from './create-options.js';
|
|
2
|
+
export type { CreateRoomOptions } from './create-options.js';
|
|
3
|
+
import { type RoomConfig } from './config.js';
|
|
4
|
+
import type { Room } from './types.js';
|
|
5
|
+
export interface NodeRoomConfig extends RoomConfig {
|
|
6
|
+
/** Ball2D signaling service. Defaults to https://ball2d.com. */
|
|
7
|
+
serviceOrigin?: string;
|
|
8
|
+
/** Optional account-owned SDK key. Keep it in an environment variable, never browser code. */
|
|
9
|
+
apiKey?: string;
|
|
10
|
+
}
|
|
11
|
+
export type NodeRoom = Room & {
|
|
12
|
+
readonly closed: Promise<void>;
|
|
13
|
+
};
|
|
14
|
+
/** Native Node host. close() begins shutdown; closed settles after peer cleanup. */
|
|
15
|
+
export declare function createRoom(config?: NodeRoomConfig, creation?: CreateRoomOptions): Promise<NodeRoom>;
|
|
16
|
+
export { readReplay, type Replay } from './replay.js';
|
|
17
|
+
export { validateStadium, type StadiumValidation } from './stadium.js';
|
|
18
|
+
export type { HostPlayer, HostScores, HostDiscProperties } from '../core/host-types.js';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { HeadlessRoom } from '../client/headless.js';
|
|
2
|
+
import type { Room } from './types.js';
|
|
3
|
+
export type { Room } from './types.js';
|
|
4
|
+
export declare function roomFacade(host: HeadlessRoom): Room;
|
|
5
|
+
export declare function roomFacade(host: HeadlessRoom, closed: Promise<void>): Room & {
|
|
6
|
+
readonly closed: Promise<void>;
|
|
7
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface StadiumValidation {
|
|
2
|
+
readonly name: string;
|
|
3
|
+
readonly canBeStored: boolean;
|
|
4
|
+
readonly warnings: readonly string[];
|
|
5
|
+
}
|
|
6
|
+
/** Validates Ball2D's supported HBS contract without allocating a host or WASM engine.
|
|
7
|
+
* Throws on malformed or unsupported input. Warnings describe ignored field names.
|
|
8
|
+
*/
|
|
9
|
+
export declare function validateStadium(source: string): StadiumValidation;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { HostPlayer, HostScores, HostDiscProperties } from '../core/host-types.js';
|
|
2
|
+
import type { DiscPropertyPatch } from '../core/disc-properties.js';
|
|
3
|
+
import type { MatchState } from '../core/match-state.js';
|
|
4
|
+
import type { AnnouncementStyle } from '../client/announcement.js';
|
|
5
|
+
/** Public room contract: runtime classes and transport types are deliberately absent. */
|
|
6
|
+
export interface Room {
|
|
7
|
+
readonly roomId: string;
|
|
8
|
+
readonly roomLink: string;
|
|
9
|
+
readonly roomName: string;
|
|
10
|
+
readonly signal: AbortSignal;
|
|
11
|
+
readonly lastRecording: Blob | null;
|
|
12
|
+
onRecordingComplete?: (blob: Blob, reason: string) => void;
|
|
13
|
+
onRoomLink?: (url: string) => void;
|
|
14
|
+
onPlayerJoin?: (p: HostPlayer) => void;
|
|
15
|
+
onPlayerTeamChange?: (p: HostPlayer, byPlayer: HostPlayer | null) => void;
|
|
16
|
+
onPlayerAdminChange?: (p: HostPlayer, byPlayer: HostPlayer | null) => void;
|
|
17
|
+
onGameStart?: (byPlayer: HostPlayer | null) => void;
|
|
18
|
+
onGameStop?: (byPlayer: HostPlayer | null) => void;
|
|
19
|
+
onTeamVictory?: (scores: HostScores) => void;
|
|
20
|
+
/** Legacy Ball2D callback; prefer onTeamVictory. */
|
|
21
|
+
onGameVictory?: (scores: HostScores) => void;
|
|
22
|
+
onGamePauseChange?: (paused: boolean) => void;
|
|
23
|
+
onGamePause?: (byPlayer: HostPlayer | null) => void;
|
|
24
|
+
onGameUnpause?: (byPlayer: HostPlayer | null) => void;
|
|
25
|
+
onPlayerLeave?: (p: HostPlayer) => void;
|
|
26
|
+
onPlayerKicked?: (p: HostPlayer, reason: string, ban: boolean, byPlayer: HostPlayer | null) => void;
|
|
27
|
+
onPlayerActivity?: (p: HostPlayer) => void;
|
|
28
|
+
onPlayerChat?: (p: HostPlayer, text: string) => boolean | void;
|
|
29
|
+
onPlayerBallKick?: (p: HostPlayer) => void;
|
|
30
|
+
onTeamGoal?: (team: 1 | 2) => void;
|
|
31
|
+
onPositionsReset?: () => void;
|
|
32
|
+
onStadiumChange?: (name: string, byPlayer: HostPlayer | null) => void;
|
|
33
|
+
onTeamsLockChange?: (locked: boolean, byPlayer: HostPlayer | null) => void;
|
|
34
|
+
onKickRateLimitSet?: (min: number, rate: number, burst: number, byPlayer: HostPlayer | null) => void;
|
|
35
|
+
onGameTick?: () => void;
|
|
36
|
+
onError?: (message: string) => void;
|
|
37
|
+
getPlayerList(): HostPlayer[];
|
|
38
|
+
getPlayer(id: number): HostPlayer | null;
|
|
39
|
+
setTeamColors(team: number, angle: number, textColor: number, colors: number[]): Promise<void>;
|
|
40
|
+
reorderPlayers(playerIdList: number[], moveToTop: boolean): Promise<void>;
|
|
41
|
+
setPlayerAvatar(id: number, avatar: string | null): Promise<void>;
|
|
42
|
+
setPlayerTeam(id: number, team: 0 | 1 | 2): Promise<void>;
|
|
43
|
+
setPlayerAdmin(id: number, admin: boolean): Promise<void>;
|
|
44
|
+
setTeamsLock(locked: boolean): Promise<void>;
|
|
45
|
+
kickPlayer(id: number, reason?: string, ban?: boolean): Promise<void>;
|
|
46
|
+
clearBan(id: number): Promise<void>;
|
|
47
|
+
clearBans(): Promise<void>;
|
|
48
|
+
sendChat(text: string, targetId?: number | null): Promise<void>;
|
|
49
|
+
sendAnnouncement(text: string, targetId?: number | null, color?: number | null, style?: AnnouncementStyle | null, sound?: number | null): Promise<void>;
|
|
50
|
+
startGame(): Promise<void>;
|
|
51
|
+
stopGame(): Promise<void>;
|
|
52
|
+
pauseGame(paused: boolean): Promise<void>;
|
|
53
|
+
setKickRateLimit(min?: number, rate?: number, burst?: number): Promise<void>;
|
|
54
|
+
setPassword(password: string | null): Promise<void>;
|
|
55
|
+
readonly requireVerification: boolean | null;
|
|
56
|
+
setRequireVerification(required: boolean): Promise<void>;
|
|
57
|
+
/** Migration alias: Ball2D uses Turnstile, not Google's reCAPTCHA. */
|
|
58
|
+
setRequireRecaptcha(required: boolean): Promise<void>;
|
|
59
|
+
setScoreLimit(limit: number): Promise<void>;
|
|
60
|
+
setTimeLimit(minutes: number): Promise<void>;
|
|
61
|
+
setDefaultStadium(name: string): Promise<void>;
|
|
62
|
+
setCustomStadium(source: string): Promise<void>;
|
|
63
|
+
getScores(): HostScores | null;
|
|
64
|
+
getBallPosition(): {
|
|
65
|
+
x: number;
|
|
66
|
+
y: number;
|
|
67
|
+
} | null;
|
|
68
|
+
readonly CollisionFlags: Readonly<Record<string, number>>;
|
|
69
|
+
getDiscCount(): number;
|
|
70
|
+
getDiscProperties(discIndex: number): HostDiscProperties | null;
|
|
71
|
+
setDiscProperties(discIndex: number, properties: DiscPropertyPatch): Promise<void>;
|
|
72
|
+
setPlayerDiscProperties(playerId: number, properties: DiscPropertyPatch): Promise<void>;
|
|
73
|
+
getPlayerDiscProperties(playerId: number): HostDiscProperties | null;
|
|
74
|
+
getState(): MatchState;
|
|
75
|
+
startRecording(): void;
|
|
76
|
+
stopRecording(): Blob | null;
|
|
77
|
+
close(): void;
|
|
78
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Room codes are public addresses, never host credentials. */
|
|
2
|
+
export declare function normalizeRoomId(value: string): string | null;
|
|
3
|
+
export declare function invitePath(id: string): string;
|
|
4
|
+
export declare function roomFromPath(path: string): string | null;
|
|
5
|
+
export declare function parseRoomLink(input: string): string | null;
|
|
6
|
+
export declare function createRoomCode(): string;
|
package/package.json
CHANGED
|
@@ -1,29 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ball2d",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Ball2D browser and experimental native Node room SDK",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/types/sdk/browser.d.ts",
|
|
14
|
+
"default": "./dist/browser.js"
|
|
15
|
+
},
|
|
16
|
+
"./node": {
|
|
17
|
+
"types": "./dist/types/sdk/node.d.ts",
|
|
18
|
+
"node": "./dist/node.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
6
21
|
"license": "UNLICENSED",
|
|
7
22
|
"homepage": "https://ball2d.com",
|
|
8
23
|
"repository": {
|
|
9
24
|
"type": "git",
|
|
10
|
-
"url": "git+https://github.com/fillbyte
|
|
11
|
-
|
|
12
|
-
"bugs": {
|
|
13
|
-
"url": "https://github.com/fillbyte-com/ball2d-issues/issues"
|
|
25
|
+
"url": "git+https://github.com/fillbyte/ball2d.com.git",
|
|
26
|
+
"directory": "packages/ball2d"
|
|
14
27
|
},
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"fillbyte",
|
|
18
|
-
"game",
|
|
19
|
-
"multiplayer"
|
|
20
|
-
],
|
|
21
|
-
"files": [
|
|
22
|
-
"README.md",
|
|
23
|
-
"index.js"
|
|
24
|
-
],
|
|
25
|
-
"exports": "./index.js",
|
|
26
|
-
"publishConfig": {
|
|
27
|
-
"access": "public"
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=24"
|
|
28
30
|
}
|
|
29
31
|
}
|
package/index.js
DELETED