@lizardon386/core-abi 0.0.0-stage → 0.3.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.
Files changed (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +8 -2
  3. package/dist/client.d.ts +14 -0
  4. package/dist/client.d.ts.map +1 -0
  5. package/dist/client.js +2 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/codes.d.ts +6 -0
  8. package/dist/codes.d.ts.map +1 -0
  9. package/dist/codes.js +28 -0
  10. package/dist/codes.js.map +1 -0
  11. package/dist/hash.d.ts +10 -0
  12. package/dist/hash.d.ts.map +1 -0
  13. package/dist/hash.js +86 -0
  14. package/dist/hash.js.map +1 -0
  15. package/dist/index.d.ts +10 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +10 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/manifest.d.ts +92 -0
  20. package/dist/manifest.d.ts.map +1 -0
  21. package/dist/manifest.js +2 -0
  22. package/dist/manifest.js.map +1 -0
  23. package/dist/module-api.d.ts +107 -0
  24. package/dist/module-api.d.ts.map +1 -0
  25. package/dist/module-api.js +7 -0
  26. package/dist/module-api.js.map +1 -0
  27. package/dist/reference.d.ts +36 -0
  28. package/dist/reference.d.ts.map +1 -0
  29. package/dist/reference.js +161 -0
  30. package/dist/reference.js.map +1 -0
  31. package/dist/rule-config.d.ts +25 -0
  32. package/dist/rule-config.d.ts.map +1 -0
  33. package/dist/rule-config.js +147 -0
  34. package/dist/rule-config.js.map +1 -0
  35. package/dist/seats.d.ts +20 -0
  36. package/dist/seats.d.ts.map +1 -0
  37. package/dist/seats.js +4 -0
  38. package/dist/seats.js.map +1 -0
  39. package/dist/version.d.ts +9 -0
  40. package/dist/version.d.ts.map +1 -0
  41. package/dist/version.js +11 -0
  42. package/dist/version.js.map +1 -0
  43. package/package.json +40 -4
  44. package/src/client.ts +11 -0
  45. package/src/codes.ts +33 -0
  46. package/src/hash.ts +87 -0
  47. package/src/index.ts +9 -0
  48. package/src/manifest.ts +88 -0
  49. package/src/module-api.ts +102 -0
  50. package/src/reference.ts +157 -0
  51. package/src/rule-config.ts +139 -0
  52. package/src/seats.ts +22 -0
  53. package/src/version.ts +16 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 3178-battle-platform contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,9 @@
1
- # Temporary Holding Version
1
+ # @lizardon386/core-abi
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 3178 对战平台的游戏 ABI:`GameModule`、`GameInstance`、`Effect`、`GameContext`、房间/座位视图和版本常量。
4
+
5
+ 游戏工程通常通过 `@lizardon386/game-sdk` 使用这些类型,不需要直接安装本包。需要单独引用 ABI 时可以直接依赖。
6
+
7
+ 接入文档:[INTEGRATION_GUIDE.md](https://github.com/Lizardon386/3178-battle-platform/blob/master/INTEGRATION_GUIDE.md)
8
+
9
+ License: MIT
@@ -0,0 +1,14 @@
1
+ export interface GameClientContract {
2
+ /** 把对局状态渲染进容器;返回的视图要能在下一次 mount 时替换。 */
3
+ mount(host: HTMLElement, view: unknown, actions: GameActions): void;
4
+ unmount?(host: HTMLElement): void;
5
+ onEvent?(event: {
6
+ name: string;
7
+ payload?: unknown;
8
+ }, actions: GameActions): void;
9
+ }
10
+ export interface GameActions {
11
+ send(name: string, payload?: unknown): void;
12
+ seatId(): string | null;
13
+ }
14
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,wCAAwC;IACxC,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IACpE,OAAO,CAAC,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IAClC,OAAO,CAAC,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;CAClF;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC5C,MAAM,IAAI,MAAM,GAAG,IAAI,CAAC;CACzB"}
package/dist/client.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":""}
@@ -0,0 +1,6 @@
1
+ /** 平台错误码和通知码:游戏会用到,放进 ABI;默认文案留在 protocol。 */
2
+ export declare const PLATFORM_CODES: readonly ["PROTOCOL", "VERSION", "RULES", "UNKNOWN_GAME", "NOROOM", "NOSEAT", "FULL", "NOTHOST", "HOSTONLY", "PASSWORD", "PHASE", "RATE", "SEATLOST", "BADMSG", "INTERNAL"];
3
+ export type PlatformCode = (typeof PLATFORM_CODES)[number];
4
+ export declare const NOTICE_CODES: readonly ["HOSTLEFT", "HOST_CHANGED", "ROOM_CLOSED", "SEAT_EJECTED", "RULES_MISMATCH", "REJOINED", "TOO_FEW"];
5
+ export type NoticeCode = (typeof NOTICE_CODES)[number];
6
+ //# sourceMappingURL=codes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codes.d.ts","sourceRoot":"","sources":["../src/codes.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAE9C,eAAO,MAAM,cAAc,6KAgBjB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D,eAAO,MAAM,YAAY,+GAQf,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC"}
package/dist/codes.js ADDED
@@ -0,0 +1,28 @@
1
+ /** 平台错误码和通知码:游戏会用到,放进 ABI;默认文案留在 protocol。 */
2
+ export const PLATFORM_CODES = [
3
+ 'PROTOCOL',
4
+ 'VERSION',
5
+ 'RULES',
6
+ 'UNKNOWN_GAME',
7
+ 'NOROOM',
8
+ 'NOSEAT',
9
+ 'FULL',
10
+ 'NOTHOST',
11
+ 'HOSTONLY',
12
+ 'PASSWORD',
13
+ 'PHASE',
14
+ 'RATE',
15
+ 'SEATLOST',
16
+ 'BADMSG',
17
+ 'INTERNAL',
18
+ ];
19
+ export const NOTICE_CODES = [
20
+ 'HOSTLEFT',
21
+ 'HOST_CHANGED',
22
+ 'ROOM_CLOSED',
23
+ 'SEAT_EJECTED',
24
+ 'RULES_MISMATCH',
25
+ 'REJOINED',
26
+ 'TOO_FEW',
27
+ ];
28
+ //# sourceMappingURL=codes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codes.js","sourceRoot":"","sources":["../src/codes.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAE9C,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,UAAU;IACV,SAAS;IACT,OAAO;IACP,cAAc;IACd,QAAQ;IACR,QAAQ;IACR,MAAM;IACN,SAAS;IACT,UAAU;IACV,UAAU;IACV,OAAO;IACP,MAAM;IACN,UAAU;IACV,QAAQ;IACR,UAAU;CACF,CAAC;AAIX,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,UAAU;IACV,cAAc;IACd,aAAa;IACb,cAAc;IACd,gBAAgB;IAChB,UAAU;IACV,SAAS;CACD,CAAC"}
package/dist/hash.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ /**
2
+ * 稳定摘要:把任意 JSON 值规范化后算出可跨端复现的短哈希。
3
+ * 只回答"两端配置是否一致",不做安全用途;包完整性另走 sha256。
4
+ */
5
+ /** 键排序、数组保序、undefined 归 null 的确定性 JSON。 */
6
+ export declare function canonicalJson(value: unknown): string;
7
+ /** 16 位十六进制稳定摘要。同一输入在 Node 与浏览器下结果必须一致。 */
8
+ export declare function stableDigest(value: unknown): string;
9
+ export declare function digestsMatch(a: string | undefined, b: string | undefined): boolean;
10
+ //# sourceMappingURL=hash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA0DH,2CAA2C;AAC3C,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAIpD;AAYD,2CAA2C;AAC3C,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEnD;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAGlF"}
package/dist/hash.js ADDED
@@ -0,0 +1,86 @@
1
+ /**
2
+ * 稳定摘要:把任意 JSON 值规范化后算出可跨端复现的短哈希。
3
+ * 只回答"两端配置是否一致",不做安全用途;包完整性另走 sha256。
4
+ */
5
+ const FNV_OFFSET = 0xcbf29ce484222325n;
6
+ const FNV_PRIME = 0x100000001b3n;
7
+ const MASK_64 = (1n << 64n) - 1n;
8
+ function isPlainObject(value) {
9
+ const proto = Object.getPrototypeOf(value);
10
+ return proto === Object.prototype || proto === null;
11
+ }
12
+ function encode(value, seen, out) {
13
+ if (value === null) {
14
+ out.push('null');
15
+ return;
16
+ }
17
+ if (typeof value === 'boolean' || typeof value === 'string' || typeof value === 'number') {
18
+ out.push(JSON.stringify(value) ?? 'null');
19
+ return;
20
+ }
21
+ if (typeof value === 'undefined' || typeof value === 'function' || typeof value === 'symbol') {
22
+ out.push('null');
23
+ return;
24
+ }
25
+ if (typeof value === 'bigint') {
26
+ out.push(`${value.toString(16)}n`);
27
+ return;
28
+ }
29
+ if (!isPlainObject(value) && !Array.isArray(value)) {
30
+ out.push(`"${String(value)}"`);
31
+ return;
32
+ }
33
+ if (seen.has(value))
34
+ throw new TypeError('规范化失败:存在循环引用');
35
+ seen.add(value);
36
+ try {
37
+ if (Array.isArray(value)) {
38
+ out.push('[');
39
+ value.forEach((item, i) => {
40
+ if (i)
41
+ out.push(',');
42
+ encode(item, seen, out);
43
+ });
44
+ out.push(']');
45
+ return;
46
+ }
47
+ const obj = value;
48
+ const keys = Object.keys(obj).filter((k) => obj[k] !== undefined).sort();
49
+ out.push('{');
50
+ keys.forEach((k, i) => {
51
+ if (i)
52
+ out.push(',');
53
+ out.push(JSON.stringify(k), ':');
54
+ encode(obj[k], seen, out);
55
+ });
56
+ out.push('}');
57
+ }
58
+ finally {
59
+ seen.delete(value);
60
+ }
61
+ }
62
+ /** 键排序、数组保序、undefined 归 null 的确定性 JSON。 */
63
+ export function canonicalJson(value) {
64
+ const out = [];
65
+ encode(value, new Set(), out);
66
+ return out.join('');
67
+ }
68
+ function fnv1a64(text) {
69
+ const bytes = new TextEncoder().encode(text);
70
+ let hash = FNV_OFFSET;
71
+ for (const b of bytes) {
72
+ hash ^= BigInt(b);
73
+ hash = (hash * FNV_PRIME) & MASK_64;
74
+ }
75
+ return hash;
76
+ }
77
+ /** 16 位十六进制稳定摘要。同一输入在 Node 与浏览器下结果必须一致。 */
78
+ export function stableDigest(value) {
79
+ return fnv1a64(canonicalJson(value)).toString(16).padStart(16, '0');
80
+ }
81
+ export function digestsMatch(a, b) {
82
+ if (typeof a !== 'string' || typeof b !== 'string')
83
+ return false;
84
+ return a.toLowerCase() === b.toLowerCase();
85
+ }
86
+ //# sourceMappingURL=hash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hash.js","sourceRoot":"","sources":["../src/hash.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export * from './module-api.js';
2
+ export * from './client.js';
3
+ export * from './seats.js';
4
+ export * from './manifest.js';
5
+ export * from './reference.js';
6
+ export * from './rule-config.js';
7
+ export * from './codes.js';
8
+ export * from './hash.js';
9
+ export * from './version.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ export * from './module-api.js';
2
+ export * from './client.js';
3
+ export * from './seats.js';
4
+ export * from './manifest.js';
5
+ export * from './reference.js';
6
+ export * from './rule-config.js';
7
+ export * from './codes.js';
8
+ export * from './hash.js';
9
+ export * from './version.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC"}
@@ -0,0 +1,92 @@
1
+ import type { SeatRole } from './seats.js';
2
+ export interface GameUiOptions {
3
+ /** 游戏内聊天由平台聊天卡提供,还是由游戏自己的界面提供。 */
4
+ chat?: 'platform' | 'game';
5
+ }
6
+ type RuleConfigFieldBase = {
7
+ key: string;
8
+ label: string;
9
+ description?: string;
10
+ };
11
+ /** 建房时房主需要填的一项规则;只声明表单项,值仍走 roomCreate.config。 */
12
+ export type RuleConfigField = (RuleConfigFieldBase & {
13
+ type: 'boolean';
14
+ default: boolean;
15
+ }) | (RuleConfigFieldBase & {
16
+ type: 'enum';
17
+ default: string;
18
+ options: Array<{
19
+ value: string;
20
+ label: string;
21
+ description?: string;
22
+ }>;
23
+ }) | (RuleConfigFieldBase & {
24
+ type: 'integer';
25
+ default: number;
26
+ min: number;
27
+ max: number;
28
+ step?: number;
29
+ });
30
+ /** 游戏的规则表单声明;平台据此渲染开关,规范化与校验仍由游戏和服务端负责。 */
31
+ export interface RuleConfigSpec {
32
+ fields: RuleConfigField[];
33
+ }
34
+ /** 游戏提供的静态资料入口;只给包内相对路径,内容懒加载。 */
35
+ export interface GameReferenceSpec {
36
+ entry: string;
37
+ }
38
+ export interface GameReferenceDocument {
39
+ version: 1;
40
+ title?: string;
41
+ groups: GameReferenceGroup[];
42
+ }
43
+ export interface GameReferenceGroup {
44
+ id: string;
45
+ title: string;
46
+ items: GameReferenceItem[];
47
+ }
48
+ export interface GameReferenceItem {
49
+ title?: string;
50
+ text: string;
51
+ images?: GameReferenceImage[];
52
+ }
53
+ export interface GameReferenceImage {
54
+ path: string;
55
+ alt: string;
56
+ caption?: string;
57
+ }
58
+ /** 游戏模块对外声明的自己:房主建房、客户端校验、模块下发三处都要用它。 */
59
+ export interface GameManifest {
60
+ id: string;
61
+ name: string;
62
+ /** 语义化版本,只用于展示与"版本不同"的提示文案。 */
63
+ version: string;
64
+ /** 房规摘要:由 create 时的 config 算出,与 config 一起构成入房闸。 */
65
+ rulesHash: string;
66
+ seats: {
67
+ min: number;
68
+ max: number;
69
+ };
70
+ allowSpectate: boolean;
71
+ /** 游戏是否支持 AI 填充席位(war3 的"电脑玩家")。 */
72
+ soloFill: boolean;
73
+ /** 需要的席位角色集合,平台据此拒绝模块乱用角色。 */
74
+ roles: SeatRole[];
75
+ /** 客户端 UI 入口,相对该模块的 base URL。 */
76
+ entry: string;
77
+ /** 下发给客户端的资源清单;hash 为 'sha256:<hex>' 或裸 hex。 */
78
+ assets?: GameAsset[];
79
+ /** 可选 UI 能力;缺省时按平台默认(聊天卡由平台显示)。 */
80
+ ui?: GameUiOptions;
81
+ /** 建房时的规则表单;缺省表示这个游戏没有可配置项。 */
82
+ ruleConfig?: RuleConfigSpec;
83
+ /** 静态资料入口;只声明路径,文档由平台按需取。 */
84
+ reference?: GameReferenceSpec;
85
+ }
86
+ export interface GameAsset {
87
+ path: string;
88
+ hash: string;
89
+ bytes?: number;
90
+ }
91
+ export {};
92
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":""}
@@ -0,0 +1,107 @@
1
+ import type { NoticeCode, PlatformCode } from './codes.js';
2
+ import type { GameReferenceSpec, GameUiOptions, RuleConfigSpec } from './manifest.js';
3
+ import type { RoomPhase, SeatRole } from './seats.js';
4
+ /**
5
+ * 宿主与游戏模块之间的 ABI。
6
+ * 1. 游戏状态不进平台对象,平台只搬 opaque blob。
7
+ * 2. 游戏不直接碰 socket,对外投递只通过 Effect[]。
8
+ * 3. 游戏不改房间相位、座位表或房主权限。
9
+ */
10
+ export type ViewerId = string | null;
11
+ export type Effect = {
12
+ kind: 'broadcast';
13
+ name: string;
14
+ payload?: unknown;
15
+ } | {
16
+ kind: 'toSeat';
17
+ seatId: string;
18
+ name: string;
19
+ payload?: unknown;
20
+ } | {
21
+ kind: 'notice';
22
+ code: NoticeCode;
23
+ text?: string;
24
+ } | {
25
+ kind: 'system';
26
+ text: string;
27
+ } | {
28
+ kind: 'end';
29
+ reason?: string;
30
+ } | {
31
+ kind: 'kick';
32
+ seatId: string;
33
+ reason?: string;
34
+ };
35
+ export interface Reject {
36
+ reject: string;
37
+ code?: PlatformCode;
38
+ }
39
+ export type Outcome = Effect[] | Reject;
40
+ export declare function isReject(value: Outcome): value is Reject;
41
+ export declare function reject(message: string, code?: PlatformCode): Reject;
42
+ export interface GameAction {
43
+ name: string;
44
+ payload?: unknown;
45
+ }
46
+ /** 传给游戏模块的座位信息:不含 socket、不含票据,游戏拿不到传输细节。 */
47
+ export interface GameSeatInfo {
48
+ seatId: string;
49
+ slot: number;
50
+ name: string;
51
+ role: SeatRole;
52
+ team: string | number | null;
53
+ ready: boolean;
54
+ connected: boolean;
55
+ }
56
+ export interface GameContext {
57
+ readonly roomCode: string;
58
+ readonly config: Record<string, unknown>;
59
+ /** 注入时钟与随机源,让规则测试可确定性推进。 */
60
+ now(): number;
61
+ random(): number;
62
+ seats(): GameSeatInfo[];
63
+ seat(seatId: string): GameSeatInfo | undefined;
64
+ }
65
+ export interface GameInstance {
66
+ /** 按视角裁剪后的状态;`null` 表示观战视角。 */
67
+ serialize(viewer: ViewerId): unknown;
68
+ handle(action: GameAction, by: string): Outcome;
69
+ /** 开局。平台已确认发话人是房主且所有人类玩家都 Ready。 */
70
+ begin(): Outcome;
71
+ snapshot(): unknown;
72
+ /** 心跳:规则计时窗口在这里推进(旧项目心跳里的玩法部分)。 */
73
+ tick?(now: number): Effect[];
74
+ onSeatJoin?(seat: GameSeatInfo): Effect[];
75
+ onSeatLeave?(seat: GameSeatInfo, phase: RoomPhase): Effect[];
76
+ /** 座位超时。托管与罚则属于游戏,不属于平台。 */
77
+ onTimeout?(seat: GameSeatInfo): Effect[];
78
+ dispose?(): void;
79
+ }
80
+ export interface GameModule {
81
+ id: string;
82
+ name: string;
83
+ version: string;
84
+ entry: string;
85
+ seats: {
86
+ min: number;
87
+ max: number;
88
+ };
89
+ allowSpectate: boolean;
90
+ soloFill: boolean;
91
+ roles: SeatRole[];
92
+ /** 把房主原始设置规范化;返回的形状决定 rulesHash 与 create 的输入。 */
93
+ normalizeConfig(raw: Record<string, unknown> | undefined): Record<string, unknown>;
94
+ /** 只摘要真正影响对局的字段,避免"改了房间名也算房规不同"。 */
95
+ rulesHashOf(config: Record<string, unknown>): string;
96
+ create(config: Record<string, unknown>, ctx: GameContext): GameInstance;
97
+ resume(snapshot: unknown, ctx: GameContext): GameInstance;
98
+ /** 存档快照的兼容性闸;返回 false 则平台丢弃快照并报错给房主。 */
99
+ acceptsSnapshot?(snapshot: unknown): boolean;
100
+ /** 可选 UI 声明;例如让游戏自己的聊天面板替代平台聊天卡。 */
101
+ ui?: GameUiOptions;
102
+ /** 建房规则表单;只声明可配置项,值仍由 normalizeConfig 收口。 */
103
+ ruleConfig?: RuleConfigSpec;
104
+ /** 静态资料入口;manifest 只带路径,文档由平台懒加载。 */
105
+ reference?: GameReferenceSpec;
106
+ }
107
+ //# sourceMappingURL=module-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-api.d.ts","sourceRoot":"","sources":["../src/module-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export function isReject(value) {
2
+ return !Array.isArray(value) && typeof value?.reject === 'string';
3
+ }
4
+ export function reject(message, code) {
5
+ return code ? { reject: message, code } : { reject: message };
6
+ }
7
+ //# sourceMappingURL=module-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-api.js","sourceRoot":"","sources":["../src/module-api.ts"],"names":[],"mappings":"AA4BA,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,OAAQ,KAAgB,EAAE,MAAM,KAAK,QAAQ,CAAC;AAChF,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,OAAe,EAAE,IAAmB;IACzD,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAChE,CAAC"}
@@ -0,0 +1,36 @@
1
+ import type { GameReferenceDocument } from './manifest.js';
2
+ /**
3
+ * 游戏静态资料:平台只认纯文本 + 图片,不解析 HTML / Markdown。
4
+ * 这一份解析器由平台客户端和 sdk-tools 共用,校验口径只有一处。
5
+ */
6
+ export declare const GAME_REFERENCE_LIMITS: {
7
+ readonly documentBytes: number;
8
+ readonly groups: 20;
9
+ readonly items: 120;
10
+ readonly groupId: 64;
11
+ readonly documentTitle: 40;
12
+ readonly groupTitle: 40;
13
+ readonly itemTitle: 60;
14
+ readonly text: 2000;
15
+ readonly imagesPerItem: 6;
16
+ readonly entryLength: 256;
17
+ readonly alt: 120;
18
+ readonly caption: 120;
19
+ };
20
+ export type GameReferenceParseResult = {
21
+ ok: true;
22
+ doc: GameReferenceDocument;
23
+ } | {
24
+ ok: false;
25
+ error: string;
26
+ };
27
+ /** 包内相对路径:不接受绝对路径、反斜杠、`..` 段和空段。 */
28
+ export declare function isValidPackRelativePath(value: unknown): value is string;
29
+ /** reference.entry 指向包内 JSON 文档。 */
30
+ export declare function isValidGameReferenceEntry(value: unknown): value is string;
31
+ /**
32
+ * 校验并规范化资料文档。输入可以是已解析的对象,也可以是原始 JSON 文本;
33
+ * 失败时返回一句可以直接显示给开发者的中文原因。
34
+ */
35
+ export declare function parseGameReference(value: unknown): GameReferenceParseResult;
36
+ //# sourceMappingURL=reference.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reference.d.ts","sourceRoot":"","sources":["../src/reference.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EAItB,MAAM,eAAe,CAAC;AAEvB;;;GAGG;AACH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;CAaxB,CAAC;AAIX,MAAM,MAAM,wBAAwB,GAChC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,GAAG,EAAE,qBAAqB,CAAA;CAAE,GACxC;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAoBjC,oCAAoC;AACpC,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAMvE;AAED,oCAAoC;AACpC,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEzE;AA+DD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,wBAAwB,CA2B3E"}