REPOSITORY SOURCE

index.ts

packages/sdk/index.ts

1/** Public source SDK. Game packages import this entry point, never engine internals. */
2import {validateWorld,type WorldDefinition} from '../schema';
3import {createWorldDocument,readWorldDocument,type WorldDocument} from '../authoring';
4import {compileWorld} from '../compiler';
5import {checkpointDigest,checkpointRecord} from '../schema/checkpoints';
6export const SDK_VERSION='0.1.0';
7export const SDK_API='darkwind-game-sdk.1';
8/** Stable source identity. Keep the key when renaming a display label. */
9export async function authoredEntityId(namespace:string,key:string){
10 if(!namespace||namespace.length>128||!key||key.length>256)throw new Error('Use a bounded namespace and stable entity key');
11 return `authored:${await checkpointDigest({namespace,key})}`;
12}
13export interface GameDefinition {api:typeof SDK_API;world:WorldDefinition}
14export interface GameRelease {format:1;sdk:typeof SDK_API;document:WorldDocument;compiler:string;worldHash:string}
15export function defineGame(value:GameDefinition):GameDefinition {
16 const game=checkpointRecord(value,['api','world']);if(game.api!==SDK_API)throw new Error('Unsupported game SDK API');
17 const world=structuredClone(game.world) as WorldDefinition;validateWorld(world);return {api:SDK_API,world};
18}
19/** A portable release uses existing world migration, semantic validation and hashes. */
20export async function buildGame(value:GameDefinition):Promise<GameRelease>{
21 const game=defineGame(value),document=await createWorldDocument(game.world),compiled=await compileWorld(document.world);
22 return {format:1,sdk:SDK_API,document,compiler:compiled.compiler,worldHash:compiled.worldHash};
23}
24export async function readGameRelease(value:unknown):Promise<GameRelease>{
25 const r=checkpointRecord(value,['format','sdk','document','compiler','worldHash']);if(r.format!==1||r.sdk!==SDK_API)throw new Error('Unsupported game release or SDK API');
26 const document=await readWorldDocument(r.document),compiled=await compileWorld(document.world);
27 if(r.compiler!==compiled.compiler||r.worldHash!==compiled.worldHash)throw new Error('Game release requires its matching compiler; rebuild explicitly with the selected engine');
28 return {format:1,sdk:SDK_API,document,compiler:compiled.compiler,worldHash:compiled.worldHash};
29}
30export {PlaceBuilder} from '../world';
31export {SKY_MOODS} from '../schema/sky';
32export {defineComponent} from '../schema/components';
33export {defineBehavior,BEHAVIOR_HOOKS} from '../behavior';
34export {ActionMap} from '../input';
35export {createWorldDocument,readWorldDocument,applyWorldTransaction} from '../authoring';
36export {authoringCommandSchema} from '../authoring/observations';
37export type {WorldDefinition,Place,SceneObject,Interaction,Material,Vec3} from '../schema';
38export type {WorldText} from '../schema/world-text';
39export type {WorldDocument,WorldTransaction,WorldCommand} from '../authoring';
40export type {BehaviorDefinition,BehaviorContext,BehaviorProgram} from '../behavior';
41export type {ActionMapDefinition,BindingProfile} from '../input';
42
43export {initialGameplay,readGameplay,useAbility} from '../schema/gameplay';
44export type {ResourceDefinition,AbilityDefinition,GameplayDefinition,GameplayState} from '../schema/gameplay';
45
46export {initialCombat,readCombat,hitTarget,respawnTargets} from '../schema/combat';
47export type {CombatTarget,TargetHit,CombatState,CombatantState} from '../schema/combat';
48
49export {initialNavigation,readNavigation,navigationPosition,navigationVisible,stepNavigation} from '../schema/navigation';
50export type {NavigationDefinition,NavigationState,NavigationTraveler} from '../schema/navigation';
51
52export {EXTENSION_API,EXTENSION_CAPABILITIES,readExtension,installWorldExtension} from '../schema/extensions';
53export type {GameExtension,ExtensionCapability,ExtensionJob} from '../schema/extensions';
54export {compileExtension} from '../behavior/extensions';
55export type {ValueSchema} from '../schema/components';
56
57export {defineBehaviorJob} from '../behavior';
58export type {BehaviorJobDefinition,JobResultEvent} from '../behavior';
59
60export {PLUGIN_API,defineEnginePlugin,installEnginePlugins,pluginPermissions,proposePluginCommand,compilePluginPanel} from '../plugins';
61export type {EnginePlugin,PluginCommand,PluginPanel,ObjectCommandCapability} from '../plugins';
62export {defineNativeSystem} from '../behavior';
63export type {NativeSystemDefinition,NativeSystemContext} from '../behavior';
64export type {DefinedComponent,ComponentMigration} from '../schema/components';
65
66export {defineScriptBehavior} from '../behavior/restricted';
67export type {ScriptPolicy} from '../behavior/script';
68export type {JobResultRecord} from '../behavior';
69
70export {publicComponentCatalog,validPublicComponents} from '../schema/public-components';
71export type {PublicComponent,PublicComponentValues} from '../schema/public-components';
72
73export {bakeNavigation} from '../schema/navigation-mesh';
74export type {NavigationBake,NavigationMesh} from '../schema/navigation-mesh';
75
76export {readRoomCrossing} from '../schema/room-crossing';
77export type {RoomCrossing,RoomCrossingRoute} from '../schema/room-crossing';
78/** Add a static, host-validated room doorway to a portable game document. */
79export function addRoomCrossing(world:WorldDefinition,place:string,crossing:import('../schema/room-crossing').RoomCrossing){const next=structuredClone(world),target=next.places.find(p=>p.id===place);if(!target)throw new Error('Missing crossing place');next.format=Math.max(next.format,crossing.walkThrough?69:crossing.roomWindow?68:67) as WorldDefinition['format'];target.interactions.push(structuredClone(crossing));validateWorld(next);return next;}
80
81export {bakeWorldNavigation} from '../compiler/navigation';
82