@zhin.js/plugin-tic-tac-toe 1.0.4 → 1.0.5

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.
@@ -0,0 +1,16 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineCommand } from '@zhin.js/command';
3
+ import { messageFromCommandInput, normalizeTttAction } from '@zhin.js/game-kit';
4
+ import { TTT_HELP, runTttCommand } from "../../lib/ttt-command.js";
5
+ import { resolveGameServices } from "../../lib/runtime-store.js";
6
+ export default defineCommand({
7
+ description: 'Tic Tac Toe',
8
+ async execute({ params, input, use, owner }) {
9
+ const action = normalizeTttAction(String(params.action ?? ''));
10
+ if (!action || action === 'help')
11
+ return TTT_HELP;
12
+ const services = resolveGameServices({ use, owner });
13
+ const message = messageFromCommandInput(input);
14
+ return runTttCommand(services, message, action);
15
+ },
16
+ });
@@ -1,16 +1,12 @@
1
- import { type GameMessageLike } from '@zhin.js/game-kit';
1
+ import type { GameMessageLike, GameReply } from '@zhin.js/game-kit';
2
2
  import type { TttSessionRow } from './models.js';
3
3
  import { BOT_ID } from './player-label.js';
4
4
  import type { SessionServices, TttPlayerRef } from './session-service.js';
5
5
  export { BOT_ID };
6
6
  export declare function isBotSession(session: TttSessionRow): boolean;
7
- /**
8
- * Plugin Runtime: render the board as text. Interactive in-place board editing
9
- * (the old Adapter.editMessage path) is not part of the runtime flow; commands
10
- * and the choice middleware return fresh text each turn.
11
- */
12
- export declare function sendOrEditBoard(message: GameMessageLike, session: TttSessionRow, statusLine: string, terminal?: boolean, highlight?: number[]): string;
13
- export declare function restartFromTerminal(services: SessionServices, message: GameMessageLike, sessionId: string): Promise<string | null>;
14
- export declare function handleMove(services: SessionServices, message: GameMessageLike, sessionId: string, cell: number): Promise<string | null>;
15
- export declare function startBotGame(services: SessionServices, message: GameMessageLike): Promise<string>;
16
- export declare function startPvpGame(services: SessionServices, message: GameMessageLike, playerX: TttPlayerRef, playerO: TttPlayerRef): Promise<string>;
7
+ /** Render the canonical board reply; delivery belongs to the Runtime Host. */
8
+ export declare function renderBoard(message: GameMessageLike, session: TttSessionRow, statusLine: string, terminal?: boolean, highlight?: number[]): GameReply;
9
+ export declare function restartFromTerminal(services: SessionServices, message: GameMessageLike, sessionId: string): Promise<GameReply | null>;
10
+ export declare function handleMove(services: SessionServices, message: GameMessageLike, sessionId: string, cell: number): Promise<GameReply | null>;
11
+ export declare function startBotGame(services: SessionServices, message: GameMessageLike): Promise<GameReply>;
12
+ export declare function startPvpGame(services: SessionServices, message: GameMessageLike, playerX: TttPlayerRef, playerO: TttPlayerRef): Promise<GameReply>;
package/lib/game-flow.js CHANGED
@@ -1,4 +1,3 @@
1
- import { plainTextFromSendContent, recordGameOutcome } from '@zhin.js/game-kit';
2
1
  import { buildBoardInteractive } from './board-view.js';
3
2
  import { applyMove, bestMove, checkWinner, isDraw, parseBoard, playerMark, validMove, X, O, cellLabel, } from './engine.js';
4
3
  import { BOT_ID, formatPlayerWithMark, formatRosterLine, formatTurnStatus, formatWinHeadline, playerRefForMark, senderDisplayName, } from './player-label.js';
@@ -6,12 +5,8 @@ export { BOT_ID };
6
5
  export function isBotSession(session) {
7
6
  return session.player_o === BOT_ID || session.player_x === BOT_ID;
8
7
  }
9
- /**
10
- * Plugin Runtime: render the board as text. Interactive in-place board editing
11
- * (the old Adapter.editMessage path) is not part of the runtime flow; commands
12
- * and the choice middleware return fresh text each turn.
13
- */
14
- export function sendOrEditBoard(message, session, statusLine, terminal = false, highlight) {
8
+ /** Render the canonical board reply; delivery belongs to the Runtime Host. */
9
+ export function renderBoard(message, session, statusLine, terminal = false, highlight) {
15
10
  const board = parseBoard(session.board);
16
11
  const content = buildBoardInteractive({
17
12
  sessionId: session.id,
@@ -23,7 +18,7 @@ export function sendOrEditBoard(message, session, statusLine, terminal = false,
23
18
  highlight,
24
19
  channelType: message.$channel.type,
25
20
  });
26
- return plainTextFromSendContent(content);
21
+ return content;
27
22
  }
28
23
  export async function restartFromTerminal(services, message, sessionId) {
29
24
  const session = await services.session.getById(sessionId);
@@ -41,12 +36,12 @@ export async function restartFromTerminal(services, message, sessionId) {
41
36
  // PvP 局重开仍是 PvP(原班人马),不静默降级为人机
42
37
  if (!isBotSession(session)) {
43
38
  const board = await startPvpGame(services, message, { id: session.player_x, displayName: session.player_x_name }, { id: session.player_o, displayName: session.player_o_name });
44
- if (board.includes('已有'))
39
+ if (typeof board === 'string' && board.includes('已有'))
45
40
  return board;
46
41
  return board;
47
42
  }
48
43
  const hint = await startBotGame(services, message);
49
- if (hint.includes('已有'))
44
+ if (typeof hint === 'string' && hint.includes('已有'))
50
45
  return hint;
51
46
  return hint;
52
47
  }
@@ -93,42 +88,19 @@ export async function handleMove(services, message, sessionId, cell) {
93
88
  winner: win ? win.winner : 0,
94
89
  });
95
90
  const updated = (await services.session.getById(session.id));
96
- if (win || draw) {
97
- const humanId = isBotSession(updated)
98
- ? (updated.player_x === BOT_ID ? updated.player_o : updated.player_x)
99
- : message.$sender.id;
100
- const humanName = isBotSession(updated)
101
- ? (updated.player_x === BOT_ID ? updated.player_o_name : updated.player_x_name)
102
- : String(message.$sender.name ?? message.$sender.id);
103
- const humanMsg = {
104
- ...message,
105
- $sender: { ...message.$sender, id: humanId, name: humanName },
106
- };
107
- if (win) {
108
- const humanMark = playerMark(humanId, {
109
- playerX: updated.player_x,
110
- playerO: updated.player_o,
111
- });
112
- const humanWon = humanMark === win.winner;
113
- void recordGameOutcome(humanMsg, 'ttt', humanWon ? 'won' : 'lost', humanWon ? 20 : 0);
114
- }
115
- else {
116
- void recordGameOutcome(humanMsg, 'ttt', 'draw');
117
- }
118
- }
119
91
  if (win) {
120
92
  const status = formatWinHeadline(updated, win.winner);
121
- return sendOrEditBoard(message, updated, status, true, win.line);
93
+ return renderBoard(message, updated, status, true, win.line);
122
94
  }
123
95
  if (draw) {
124
- return sendOrEditBoard(message, updated, '平局。', true);
96
+ return renderBoard(message, updated, '平局。', true);
125
97
  }
126
98
  // 人机:玩家落子后立刻由服务端代下,避免先发「轮到机器人」再发终盘(QQ 被动消息多耗一次)
127
99
  if (isBotSession(updated) && playerIdForTurn(updated) === BOT_ID) {
128
100
  return runBotMove(services, message, updated);
129
101
  }
130
102
  const status = formatTurnStatus(updated, moveCount);
131
- return sendOrEditBoard(message, updated, status, false);
103
+ return renderBoard(message, updated, status, false);
132
104
  }
133
105
  async function runBotMove(services, message, session) {
134
106
  const board = parseBoard(session.board);
@@ -156,8 +128,9 @@ export async function startBotGame(services, message) {
156
128
  boardJson: JSON.stringify([0, 0, 0, 0, 0, 0, 0, 0, 0]),
157
129
  });
158
130
  const status = `${formatRosterLine(session)} · 你先手 (✕)`;
159
- const boardText = sendOrEditBoard(message, session, status, false);
160
- return `${boardText}\n\n开局成功!回复数字 1–9 落子。`;
131
+ const board = renderBoard(message, session, status, false);
132
+ const success = '\n\n开局成功!点击空格或回复数字 1–9 落子。';
133
+ return Array.isArray(board) ? [...board, success] : [board, success];
161
134
  }
162
135
  export async function startPvpGame(services, message, playerX, playerO) {
163
136
  const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
@@ -174,6 +147,6 @@ export async function startPvpGame(services, message, playerX, playerO) {
174
147
  });
175
148
  const opener = formatPlayerWithMark(session.player_x, session.player_x_name, '✕');
176
149
  const status = `${formatRosterLine(session)} · 先手:${opener}`;
177
- return sendOrEditBoard(message, session, status, false);
150
+ return renderBoard(message, session, status, false);
178
151
  }
179
152
  //# sourceMappingURL=game-flow.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"game-flow.js","sourceRoot":"","sources":["../src/game-flow.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"game-flow.js","sourceRoot":"","sources":["../src/game-flow.ts"],"names":[],"mappings":"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"}
package/lib/index.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  export { TTT_HELP } from './ttt-command.js';
2
2
  export { gameServicesToken, resolveGameServices } from './runtime-store.js';
3
- export { createInMemoryTttDb, mountTttMemoryServices } from './memory-db.js';
4
3
  /**
5
4
  * 已由 plugin.ts 接线:commands/ 命令、middlewares/ 文本与选项中间件、
6
5
  * 游戏大厅注册(registerRuntimeGame)、过期会话 cron(scheduleHostToken)、
package/lib/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  export { TTT_HELP } from './ttt-command.js';
2
2
  export { gameServicesToken, resolveGameServices } from './runtime-store.js';
3
- export { createInMemoryTttDb, mountTttMemoryServices } from './memory-db.js';
4
3
  /**
5
4
  * 已由 plugin.ts 接线:commands/ 命令、middlewares/ 文本与选项中间件、
6
5
  * 游戏大厅注册(registerRuntimeGame)、过期会话 cron(scheduleHostToken)、
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAE7E;;;;GAIG"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE5E;;;;GAIG"}
package/lib/models.d.ts CHANGED
@@ -17,7 +17,6 @@ declare module '@zhin.js/core' {
17
17
  turn: number;
18
18
  status: TttSessionStatus;
19
19
  winner: number;
20
- board_message_id: string;
21
20
  move_count: number;
22
21
  updated_at: number;
23
22
  created_at: number;
package/lib/models.js CHANGED
@@ -14,7 +14,6 @@ export function defineHostTables(db) {
14
14
  turn: { type: 'integer', default: 1 },
15
15
  status: { type: 'text', default: 'active' },
16
16
  winner: { type: 'integer', default: 0 },
17
- board_message_id: { type: 'text', default: '' },
18
17
  move_count: { type: 'integer', default: 0 },
19
18
  updated_at: { type: 'integer', default: 0 },
20
19
  created_at: { type: 'integer', default: 0 },
package/lib/models.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import type { Database, Models } from '@zhin.js/core';
2
- import { type GameMessageLike } from '@zhin.js/game-kit';
2
+ import { BaseSessionService, type GameMessageLike } from '@zhin.js/game-kit';
3
3
  import type { TttSessionRow } from './models.js';
4
4
  /** 井字棋服务使用的数据库实例(Models 经 models.ts 模块增强) */
5
5
  export type TttDatabase = Database<unknown, Models, string>;
@@ -24,14 +24,9 @@ export declare class QueueService {
24
24
  count(channel: string): Promise<number>;
25
25
  }
26
26
  export declare function sessionId(): string;
27
- export declare class SessionService {
27
+ export declare class SessionService extends BaseSessionService<TttSessionRow> {
28
28
  private readonly db;
29
29
  constructor(db: TttDatabase);
30
- getActiveByChannel(channel: string): Promise<TttSessionRow | null>;
31
- getById(id: string): Promise<TttSessionRow | null>;
32
- getActiveForUser(channel: string, userId: string): Promise<TttSessionRow | null>;
33
- /** 根据棋盘消息 ID 查找进行中的局(QQ 等 action 带 sourceMessageId) */
34
- getActiveByBoardMessageId(messageId: string): Promise<TttSessionRow | null>;
35
30
  createSession(input: {
36
31
  message: GameMessageLike;
37
32
  playerX: string;
@@ -40,11 +35,9 @@ export declare class SessionService {
40
35
  playerOName?: string;
41
36
  boardJson: string;
42
37
  }): Promise<TttSessionRow>;
43
- updateSession(id: string, patch: Partial<TttSessionRow>): Promise<void>;
44
38
  recordMove(sessionId: string, playerId: string, cell: number, moveIndex: number): Promise<void>;
45
39
  addSpectator(sessionId: string, userId: string): Promise<void>;
46
40
  listSpectators(sessionId: string): Promise<string[]>;
47
- abortStale(idleMs: number): Promise<number>;
48
41
  }
49
42
  export type SessionServices = {
50
43
  queue: QueueService;
@@ -1,4 +1,5 @@
1
- import { channelKey, boardMessageMatches, generateCompactId } from '@zhin.js/game-kit';
1
+ import { BaseSessionService, channelKey, generateCompactId, } from '@zhin.js/game-kit';
2
+ import { BOT_ID } from './player-label.js';
2
3
  /** 排队行过期时间(超时未匹配的排队视为失效) */
3
4
  export const QUEUE_TTL_MS = 10 * 60 * 1000;
4
5
  function getModel(db, name) {
@@ -77,39 +78,44 @@ export class QueueService {
77
78
  export function sessionId() {
78
79
  return generateCompactId('s');
79
80
  }
80
- export class SessionService {
81
+ export class SessionService extends BaseSessionService {
81
82
  db;
82
83
  constructor(db) {
83
- this.db = db;
84
- }
85
- async getActiveByChannel(channel) {
86
- const rows = await getModel(this.db, 'ttt_sessions').findAll({
87
- channel_key: channel,
88
- status: 'active',
84
+ super(db, {
85
+ gameId: 'ttt',
86
+ table: 'ttt_sessions',
87
+ userFields: ['player_x', 'player_o'],
88
+ projectOutcomes: (session) => {
89
+ if (session.status !== 'won' && session.status !== 'draw')
90
+ return [];
91
+ return [
92
+ {
93
+ id: session.player_x,
94
+ name: session.player_x_name,
95
+ mark: 1,
96
+ },
97
+ {
98
+ id: session.player_o,
99
+ name: session.player_o_name,
100
+ mark: 2,
101
+ },
102
+ ]
103
+ .filter((player) => player.id !== BOT_ID)
104
+ .map((player) => ({
105
+ userId: player.id,
106
+ userName: player.name,
107
+ result: session.status === 'draw'
108
+ ? 'draw'
109
+ : session.winner === player.mark
110
+ ? 'won'
111
+ : 'lost',
112
+ score: session.status === 'won' && session.winner === player.mark
113
+ ? 20
114
+ : undefined,
115
+ }));
116
+ },
89
117
  });
90
- return rows[0] ?? null;
91
- }
92
- async getById(id) {
93
- return getModel(this.db, 'ttt_sessions').findOne({ id });
94
- }
95
- async getActiveForUser(channel, userId) {
96
- const row = await this.getActiveByChannel(channel);
97
- if (!row)
98
- return null;
99
- if (row.player_x === userId || row.player_o === userId)
100
- return row;
101
- return null;
102
- }
103
- /** 根据棋盘消息 ID 查找进行中的局(QQ 等 action 带 sourceMessageId) */
104
- async getActiveByBoardMessageId(messageId) {
105
- if (!messageId)
106
- return null;
107
- const rows = await getModel(this.db, 'ttt_sessions').findAll({});
108
- for (const row of rows) {
109
- if (boardMessageMatches(row.board_message_id ?? '', messageId))
110
- return row;
111
- }
112
- return null;
118
+ this.db = db;
113
119
  }
114
120
  async createSession(input) {
115
121
  const now = Date.now();
@@ -130,16 +136,11 @@ export class SessionService {
130
136
  turn: 1,
131
137
  status: 'active',
132
138
  winner: 0,
133
- board_message_id: '',
134
139
  move_count: 0,
135
140
  updated_at: now,
136
141
  created_at: now,
137
142
  };
138
- await getModel(this.db, 'ttt_sessions').create(row);
139
- return row;
140
- }
141
- async updateSession(id, patch) {
142
- await getModel(this.db, 'ttt_sessions').updateWhere({ id }, { ...patch, updated_at: Date.now() });
143
+ return this.createRow(row);
143
144
  }
144
145
  async recordMove(sessionId, playerId, cell, moveIndex) {
145
146
  await getModel(this.db, 'ttt_moves').create({
@@ -161,19 +162,6 @@ export class SessionService {
161
162
  const rows = await getModel(this.db, 'ttt_spectators').findAll({ session_id: sessionId });
162
163
  return rows.map((r) => r.user_id);
163
164
  }
164
- async abortStale(idleMs) {
165
- const cutoff = Date.now() - idleMs;
166
- const sessions = getModel(this.db, 'ttt_sessions');
167
- const rows = await sessions.findAll({ status: 'active' });
168
- let n = 0;
169
- for (const row of rows) {
170
- if (row.updated_at < cutoff) {
171
- await sessions.updateWhere({ id: row.id }, { status: 'aborted', updated_at: Date.now() });
172
- n++;
173
- }
174
- }
175
- return n;
176
- }
177
165
  }
178
166
  export function createServices(db) {
179
167
  return { queue: new QueueService(db), session: new SessionService(db) };
@@ -1 +1 @@
1
- {"version":3,"file":"session-service.js","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"session-service.js","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { type GameMessageLike } from '@zhin.js/game-kit';
1
+ import { type GameMessageLike, type GameReply } from '@zhin.js/game-kit';
2
2
  import type { SessionServices } from './session-service.js';
3
3
  export declare const TTT_HELP: string;
4
- export declare function runTttCommand(services: SessionServices, message: GameMessageLike, action: string): Promise<string>;
4
+ export declare function runTttCommand(services: SessionServices, message: GameMessageLike, action: string): Promise<GameReply>;
@@ -1,4 +1,4 @@
1
- import { channelKey } from '@zhin.js/game-kit';
1
+ import { channelKey, } from '@zhin.js/game-kit';
2
2
  import { formatPlayerWithMark, formatRosterLine } from './player-label.js';
3
3
  import { startBotGame, startPvpGame } from './game-flow.js';
4
4
  export const TTT_HELP = [
@@ -38,7 +38,11 @@ export async function runTttCommand(services, message, action) {
38
38
  const [px, po] = pair;
39
39
  const board = await startPvpGame(services, message, px, po);
40
40
  const matchLine = `匹配成功!${formatPlayerWithMark(px.id, px.displayName, '✕')} vs ${formatPlayerWithMark(po.id, po.displayName, '○')}`;
41
- return board ? `${matchLine}\n\n${board}` : matchLine;
41
+ return board
42
+ ? Array.isArray(board)
43
+ ? [matchLine, '\n\n', ...board]
44
+ : [matchLine, '\n\n', board]
45
+ : matchLine;
42
46
  }
43
47
  return `已加入排队(第 ${position} 位),凑满 2 人自动开局。`;
44
48
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ttt-command.js","sourceRoot":"","sources":["../src/ttt-command.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ttt-command.js","sourceRoot":"","sources":["../src/ttt-command.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineGameCommandAliasMiddleware, isTttAction, messageFromCommandInput, normalizeTttAction, } from '@zhin.js/game-kit';
3
+ import { TTT_HELP, runTttCommand } from "../lib/ttt-command.js";
4
+ import { resolveGameServices } from "../lib/runtime-store.js";
5
+ export default defineGameCommandAliasMiddleware({
6
+ aliases: ['井字棋', 'ttt'],
7
+ async run(action, input, context) {
8
+ const normalized = normalizeTttAction(String(action ?? ''));
9
+ if (normalized === 'help')
10
+ return TTT_HELP;
11
+ // action 无法识别:放行给后续中间件,避免劫持普通聊天
12
+ if (!isTttAction(normalized))
13
+ return null;
14
+ const services = resolveGameServices(context);
15
+ const message = messageFromCommandInput(input);
16
+ return runTttCommand(services, message, normalized);
17
+ },
18
+ });
@@ -0,0 +1,66 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineMiddleware } from '@zhin.js/middleware';
3
+ import { channelKey, messageFromCommandInput, parseChoicePayload, resolveGameTextPayload, } from '@zhin.js/game-kit';
4
+ import { resolveGameServices } from "../lib/runtime-store.js";
5
+ import { buildFallbackMap, TTT_PREFIX, parseTttPayload } from "../lib/board-view.js";
6
+ import { parseBoard } from "../lib/engine.js";
7
+ import { handleMove, restartFromTerminal } from "../lib/game-flow.js";
8
+ /**
9
+ * 文本入口:按钮 payload(`ttt:session:0-8` 或 `ttt:session:restart`)
10
+ * 与裸数字 fallback(按空格 1-9 编号落子,对应视图『落子:回复数字 1-9(仅空格)』)。
11
+ */
12
+ export default defineMiddleware({
13
+ target: 'inbound',
14
+ async handle(context, next) {
15
+ const raw = context.input.content?.trim() ?? '';
16
+ if (!raw) {
17
+ await next();
18
+ return;
19
+ }
20
+ const services = resolveGameServices(context);
21
+ const message = messageFromCommandInput(context.input);
22
+ const ch = channelKey(message);
23
+ // 直接 payload(QQ 指令预填 / Sandbox action→text)
24
+ const payload = resolveGameTextPayload(raw);
25
+ if (payload?.startsWith(`${TTT_PREFIX}:`)) {
26
+ const restart = parseChoicePayload(payload, TTT_PREFIX);
27
+ if (restart?.choiceId === 'restart') {
28
+ const session = await services.session.getById(restart.sessionId);
29
+ if (session?.channel_key === ch) {
30
+ const reply = await restartFromTerminal(services, message, restart.sessionId);
31
+ if (reply)
32
+ await context.input.$reply(reply);
33
+ return;
34
+ }
35
+ }
36
+ const move = parseTttPayload(payload);
37
+ if (move) {
38
+ const session = await services.session.getById(move.sessionId);
39
+ if (session?.channel_key === ch) {
40
+ const reply = await handleMove(services, message, move.sessionId, move.cell);
41
+ if (reply)
42
+ await context.input.$reply(reply);
43
+ return;
44
+ }
45
+ }
46
+ await next();
47
+ return;
48
+ }
49
+ // 裸数字:按当前棋盘空格编号映射落子
50
+ const session = await services.session.getActiveForUser(ch, message.$sender.id);
51
+ if (!session || session.channel_key !== ch) {
52
+ await next();
53
+ return;
54
+ }
55
+ const map = buildFallbackMap(session.id, parseBoard(session.board));
56
+ const payloadFromDigit = resolveGameTextPayload(raw, map);
57
+ const move = payloadFromDigit ? parseTttPayload(payloadFromDigit) : null;
58
+ if (!move || move.sessionId !== session.id) {
59
+ await next();
60
+ return;
61
+ }
62
+ const reply = await handleMove(services, message, session.id, move.cell);
63
+ if (reply)
64
+ await context.input.$reply(reply);
65
+ },
66
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/plugin-tic-tac-toe",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Zhin.js 跨平台井字棋 (Plugin Runtime)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -14,7 +14,7 @@
14
14
  "./package.json": "./package.json"
15
15
  },
16
16
  "files": [
17
- "plugin.ts",
17
+ "plugin.js",
18
18
  "schema.json",
19
19
  "commands",
20
20
  "middlewares",
@@ -24,10 +24,10 @@
24
24
  ],
25
25
  "license": "MIT",
26
26
  "dependencies": {
27
- "@zhin.js/command": "1.0.3",
28
- "@zhin.js/core": "1.4.1",
29
- "@zhin.js/game-kit": "2.0.1",
30
- "@zhin.js/middleware": "1.0.3",
27
+ "@zhin.js/command": "1.0.4",
28
+ "@zhin.js/core": "1.4.2",
29
+ "@zhin.js/game-kit": "2.0.2",
30
+ "@zhin.js/middleware": "1.0.4",
31
31
  "@zhin.js/plugin-runtime": "1.1.1"
32
32
  },
33
33
  "devDependencies": {
@@ -49,7 +49,7 @@
49
49
  "zhin": {
50
50
  "protocol": 1,
51
51
  "type": "plugin",
52
- "entry": "./plugin.ts",
52
+ "entry": "./plugin.js",
53
53
  "engine": "^1.0.0",
54
54
  "runtime": "trusted",
55
55
  "features": [
package/plugin.js ADDED
@@ -0,0 +1,84 @@
1
+ // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
+ import { defineGamePlugin, gameEvents, plainTextFromSendContent, } from '@zhin.js/game-kit';
3
+ import { outboundHostToken } from '@zhin.js/plugin-runtime';
4
+ import { defineHostTables } from "./lib/models.js";
5
+ import { gameServicesToken } from "./lib/runtime-store.js";
6
+ import { renderBoard } from "./lib/game-flow.js";
7
+ import { formatTurnStatus, formatWinHeadline, } from "./lib/player-label.js";
8
+ import { createServices, } from "./lib/session-service.js";
9
+ /**
10
+ * Plugin Runtime:
11
+ * - Commands under `commands/` are authoritative (help + bot/join/…).
12
+ * - DB: prefer databaseHostToken; else in-memory SessionServices.
13
+ * - Choice middleware under `middlewares/` handles ttt grid / restart payloads (Sandbox action→text).
14
+ */
15
+ export default defineGamePlugin({
16
+ name: 'tic-tac-toe',
17
+ metadata: {
18
+ displayName: 'Tic Tac Toe',
19
+ },
20
+ game: {
21
+ id: 'ttt',
22
+ title: '井字棋',
23
+ icon: '♟️',
24
+ description: '三子连珠,群聊排队或人机对战',
25
+ commandPrefix: '/井字棋',
26
+ quickStart: '人机',
27
+ aliases: ['ttt'],
28
+ menus: [
29
+ { id: 'bot', label: '🤖 人机对战' },
30
+ { id: 'join', label: '👥 加入排队' },
31
+ { id: 'spectate', label: '👀 观战' },
32
+ { id: 'help', label: '📖 玩法说明' },
33
+ ],
34
+ },
35
+ tables: ['ttt_sessions', 'ttt_queue', 'ttt_moves', 'ttt_spectators'],
36
+ servicesToken: gameServicesToken,
37
+ defineHostTables,
38
+ createServices: (database) => createServices(database),
39
+ session: (services) => services.session,
40
+ setup(context, services) {
41
+ if (!context.resources.has(outboundHostToken))
42
+ return;
43
+ const outbound = context.resources.use(outboundHostToken);
44
+ const notify = async (raw, terminal) => {
45
+ const session = raw;
46
+ if (!session.adapter || !session.endpoint)
47
+ return;
48
+ const spectators = await services.session.listSpectators(session.id);
49
+ if (spectators.length === 0)
50
+ return;
51
+ const status = session.status === 'draw'
52
+ ? '平局。'
53
+ : terminal && (session.winner === 1 || session.winner === 2)
54
+ ? formatWinHeadline(session, session.winner)
55
+ : formatTurnStatus(session, session.move_count);
56
+ const content = plainTextFromSendContent(renderBoard({
57
+ $adapter: session.adapter,
58
+ $endpoint: session.endpoint,
59
+ $channel: { type: 'private', id: '' },
60
+ $sender: { id: '' },
61
+ }, session, status, terminal));
62
+ await Promise.all(spectators.map((userId) => outbound.send({
63
+ adapter: session.adapter,
64
+ endpointId: session.endpoint,
65
+ channelType: 'private',
66
+ channelId: userId,
67
+ content,
68
+ })));
69
+ };
70
+ const disposeTurn = gameEvents.on('turn:change', async (event) => {
71
+ if (event.gameId === 'ttt' && event.session.status === 'active') {
72
+ await notify(event.session, false);
73
+ }
74
+ });
75
+ const disposeEnd = gameEvents.on('game:end', async (event) => {
76
+ if (event.gameId === 'ttt')
77
+ await notify(event.session, true);
78
+ });
79
+ return () => {
80
+ disposeEnd();
81
+ disposeTurn();
82
+ };
83
+ },
84
+ });
package/src/game-flow.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { plainTextFromSendContent, recordGameOutcome, type GameMessageLike } from '@zhin.js/game-kit';
1
+ import type { GameMessageLike, GameReply } from '@zhin.js/game-kit';
2
2
  import type { TttSessionRow } from './models.js';
3
3
  import { buildBoardInteractive } from './board-view.js';
4
4
  import {
@@ -31,18 +31,14 @@ export function isBotSession(session: TttSessionRow): boolean {
31
31
  return session.player_o === BOT_ID || session.player_x === BOT_ID;
32
32
  }
33
33
 
34
- /**
35
- * Plugin Runtime: render the board as text. Interactive in-place board editing
36
- * (the old Adapter.editMessage path) is not part of the runtime flow; commands
37
- * and the choice middleware return fresh text each turn.
38
- */
39
- export function sendOrEditBoard(
34
+ /** Render the canonical board reply; delivery belongs to the Runtime Host. */
35
+ export function renderBoard(
40
36
  message: GameMessageLike,
41
37
  session: TttSessionRow,
42
38
  statusLine: string,
43
39
  terminal = false,
44
40
  highlight?: number[],
45
- ): string {
41
+ ): GameReply {
46
42
  const board = parseBoard(session.board);
47
43
  const content = buildBoardInteractive({
48
44
  sessionId: session.id,
@@ -55,14 +51,14 @@ export function sendOrEditBoard(
55
51
  channelType: message.$channel.type,
56
52
  });
57
53
 
58
- return plainTextFromSendContent(content);
54
+ return content;
59
55
  }
60
56
 
61
57
  export async function restartFromTerminal(
62
58
  services: SessionServices,
63
59
  message: GameMessageLike,
64
60
  sessionId: string,
65
- ): Promise<string | null> {
61
+ ): Promise<GameReply | null> {
66
62
  const session = await services.session.getById(sessionId);
67
63
  if (!session) return '对局不存在。';
68
64
  if (session.status === 'active') return '对局尚未结束,无法重开。';
@@ -80,11 +76,11 @@ export async function restartFromTerminal(
80
76
  { id: session.player_x, displayName: session.player_x_name },
81
77
  { id: session.player_o, displayName: session.player_o_name },
82
78
  );
83
- if (board.includes('已有')) return board;
79
+ if (typeof board === 'string' && board.includes('已有')) return board;
84
80
  return board;
85
81
  }
86
82
  const hint = await startBotGame(services, message);
87
- if (hint.includes('已有')) return hint;
83
+ if (typeof hint === 'string' && hint.includes('已有')) return hint;
88
84
  return hint;
89
85
  }
90
86
 
@@ -101,7 +97,7 @@ export async function handleMove(
101
97
  message: GameMessageLike,
102
98
  sessionId: string,
103
99
  cell: number,
104
- ): Promise<string | null> {
100
+ ): Promise<GameReply | null> {
105
101
  const session = await services.session.getById(sessionId);
106
102
  if (!session || session.status !== 'active') {
107
103
  return '对局不存在或已结束。';
@@ -144,35 +140,12 @@ export async function handleMove(
144
140
 
145
141
  const updated = (await services.session.getById(session.id))!;
146
142
 
147
- if (win || draw) {
148
- const humanId = isBotSession(updated)
149
- ? (updated.player_x === BOT_ID ? updated.player_o : updated.player_x)
150
- : message.$sender.id;
151
- const humanName = isBotSession(updated)
152
- ? (updated.player_x === BOT_ID ? updated.player_o_name : updated.player_x_name)
153
- : String(message.$sender.name ?? message.$sender.id);
154
- const humanMsg = {
155
- ...message,
156
- $sender: { ...message.$sender, id: humanId, name: humanName },
157
- } as GameMessageLike;
158
- if (win) {
159
- const humanMark = playerMark(humanId, {
160
- playerX: updated.player_x,
161
- playerO: updated.player_o,
162
- });
163
- const humanWon = humanMark === win.winner;
164
- void recordGameOutcome(humanMsg, 'ttt', humanWon ? 'won' : 'lost', humanWon ? 20 : 0);
165
- } else {
166
- void recordGameOutcome(humanMsg, 'ttt', 'draw');
167
- }
168
- }
169
-
170
143
  if (win) {
171
144
  const status = formatWinHeadline(updated, win.winner);
172
- return sendOrEditBoard(message, updated, status, true, win.line);
145
+ return renderBoard(message, updated, status, true, win.line);
173
146
  }
174
147
  if (draw) {
175
- return sendOrEditBoard(message, updated, '平局。', true);
148
+ return renderBoard(message, updated, '平局。', true);
176
149
  }
177
150
 
178
151
  // 人机:玩家落子后立刻由服务端代下,避免先发「轮到机器人」再发终盘(QQ 被动消息多耗一次)
@@ -181,14 +154,14 @@ export async function handleMove(
181
154
  }
182
155
 
183
156
  const status = formatTurnStatus(updated, moveCount);
184
- return sendOrEditBoard(message, updated, status, false);
157
+ return renderBoard(message, updated, status, false);
185
158
  }
186
159
 
187
160
  async function runBotMove(
188
161
  services: SessionServices,
189
162
  message: GameMessageLike,
190
163
  session: TttSessionRow,
191
- ): Promise<string | null> {
164
+ ): Promise<GameReply | null> {
192
165
  const board = parseBoard(session.board);
193
166
  const aiMark = session.player_o === BOT_ID ? O : X;
194
167
  const cell = bestMove(board, aiMark);
@@ -205,7 +178,7 @@ async function runBotMove(
205
178
  export async function startBotGame(
206
179
  services: SessionServices,
207
180
  message: GameMessageLike,
208
- ): Promise<string> {
181
+ ): Promise<GameReply> {
209
182
  const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
210
183
  const active = await services.session.getActiveByChannel(ch);
211
184
  if (active) return '当前频道已有进行中的对局。';
@@ -220,8 +193,9 @@ export async function startBotGame(
220
193
  });
221
194
 
222
195
  const status = `${formatRosterLine(session)} · 你先手 (✕)`;
223
- const boardText = sendOrEditBoard(message, session, status, false);
224
- return `${boardText}\n\n开局成功!回复数字 1–9 落子。`;
196
+ const board = renderBoard(message, session, status, false);
197
+ const success = '\n\n开局成功!点击空格或回复数字 1–9 落子。';
198
+ return Array.isArray(board) ? [...board, success] : [board, success];
225
199
  }
226
200
 
227
201
  export async function startPvpGame(
@@ -229,7 +203,7 @@ export async function startPvpGame(
229
203
  message: GameMessageLike,
230
204
  playerX: TttPlayerRef,
231
205
  playerO: TttPlayerRef,
232
- ): Promise<string> {
206
+ ): Promise<GameReply> {
233
207
  const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
234
208
  const active = await services.session.getActiveByChannel(ch);
235
209
  if (active) return '当前频道已有进行中的对局。';
@@ -244,5 +218,5 @@ export async function startPvpGame(
244
218
  });
245
219
  const opener = formatPlayerWithMark(session.player_x, session.player_x_name, '✕');
246
220
  const status = `${formatRosterLine(session)} · 先手:${opener}`;
247
- return sendOrEditBoard(message, session, status, false);
221
+ return renderBoard(message, session, status, false);
248
222
  }
package/src/index.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  export { TTT_HELP } from './ttt-command.js';
2
2
  export { gameServicesToken, resolveGameServices } from './runtime-store.js';
3
- export { createInMemoryTttDb, mountTttMemoryServices } from './memory-db.js';
4
3
 
5
4
  /**
6
5
  * 已由 plugin.ts 接线:commands/ 命令、middlewares/ 文本与选项中间件、
package/src/models.ts CHANGED
@@ -19,7 +19,6 @@ declare module '@zhin.js/core' {
19
19
  turn: number;
20
20
  status: TttSessionStatus;
21
21
  winner: number;
22
- board_message_id: string;
23
22
  move_count: number;
24
23
  updated_at: number;
25
24
  created_at: number;
@@ -75,7 +74,6 @@ export function defineHostTables(
75
74
  turn: { type: 'integer', default: 1 },
76
75
  status: { type: 'text', default: 'active' },
77
76
  winner: { type: 'integer', default: 0 },
78
- board_message_id: { type: 'text', default: '' },
79
77
  move_count: { type: 'integer', default: 0 },
80
78
  updated_at: { type: 'integer', default: 0 },
81
79
  created_at: { type: 'integer', default: 0 },
@@ -1,6 +1,13 @@
1
1
  import type { Database, Models, RelatedModel } from '@zhin.js/core';
2
- import { channelKey, boardMessageMatches, generateCompactId , type GameMessageLike } from '@zhin.js/game-kit';
2
+ import {
3
+ BaseSessionService,
4
+ channelKey,
5
+ generateCompactId,
6
+ type GameMessageLike,
7
+ type GameSessionDatabase,
8
+ } from '@zhin.js/game-kit';
3
9
  import type { TttModelName, TttSessionRow } from './models.js';
10
+ import { BOT_ID } from './player-label.js';
4
11
 
5
12
  /** 井字棋服务使用的数据库实例(Models 经 models.ts 模块增强) */
6
13
  export type TttDatabase = Database<unknown, Models, string>;
@@ -96,36 +103,41 @@ export function sessionId(): string {
96
103
  return generateCompactId('s');
97
104
  }
98
105
 
99
- export class SessionService {
100
- constructor(private readonly db: TttDatabase) {}
101
-
102
- async getActiveByChannel(channel: string): Promise<TttSessionRow | null> {
103
- const rows = await getModel(this.db, 'ttt_sessions').findAll({
104
- channel_key: channel,
105
- status: 'active',
106
+ export class SessionService extends BaseSessionService<TttSessionRow> {
107
+ constructor(private readonly db: TttDatabase) {
108
+ super(db as unknown as GameSessionDatabase<TttSessionRow>, {
109
+ gameId: 'ttt',
110
+ table: 'ttt_sessions',
111
+ userFields: ['player_x', 'player_o'],
112
+ projectOutcomes: (session) => {
113
+ if (session.status !== 'won' && session.status !== 'draw') return [];
114
+ return [
115
+ {
116
+ id: session.player_x,
117
+ name: session.player_x_name,
118
+ mark: 1,
119
+ },
120
+ {
121
+ id: session.player_o,
122
+ name: session.player_o_name,
123
+ mark: 2,
124
+ },
125
+ ]
126
+ .filter((player) => player.id !== BOT_ID)
127
+ .map((player) => ({
128
+ userId: player.id,
129
+ userName: player.name,
130
+ result: session.status === 'draw'
131
+ ? 'draw' as const
132
+ : session.winner === player.mark
133
+ ? 'won' as const
134
+ : 'lost' as const,
135
+ score: session.status === 'won' && session.winner === player.mark
136
+ ? 20
137
+ : undefined,
138
+ }));
139
+ },
106
140
  });
107
- return rows[0] ?? null;
108
- }
109
-
110
- async getById(id: string): Promise<TttSessionRow | null> {
111
- return getModel(this.db, 'ttt_sessions').findOne({ id });
112
- }
113
-
114
- async getActiveForUser(channel: string, userId: string): Promise<TttSessionRow | null> {
115
- const row = await this.getActiveByChannel(channel);
116
- if (!row) return null;
117
- if (row.player_x === userId || row.player_o === userId) return row;
118
- return null;
119
- }
120
-
121
- /** 根据棋盘消息 ID 查找进行中的局(QQ 等 action 带 sourceMessageId) */
122
- async getActiveByBoardMessageId(messageId: string): Promise<TttSessionRow | null> {
123
- if (!messageId) return null;
124
- const rows = await getModel(this.db, 'ttt_sessions').findAll({});
125
- for (const row of rows) {
126
- if (boardMessageMatches(row.board_message_id ?? '', messageId)) return row;
127
- }
128
- return null;
129
141
  }
130
142
 
131
143
  async createSession(input: {
@@ -154,20 +166,11 @@ export class SessionService {
154
166
  turn: 1,
155
167
  status: 'active',
156
168
  winner: 0,
157
- board_message_id: '',
158
169
  move_count: 0,
159
170
  updated_at: now,
160
171
  created_at: now,
161
172
  };
162
- await getModel(this.db, 'ttt_sessions').create(row);
163
- return row;
164
- }
165
-
166
- async updateSession(id: string, patch: Partial<TttSessionRow>): Promise<void> {
167
- await getModel(this.db, 'ttt_sessions').updateWhere(
168
- { id },
169
- { ...patch, updated_at: Date.now() },
170
- );
173
+ return this.createRow(row);
171
174
  }
172
175
 
173
176
  async recordMove(sessionId: string, playerId: string, cell: number, moveIndex: number): Promise<void> {
@@ -192,19 +195,6 @@ export class SessionService {
192
195
  return rows.map((r) => r.user_id);
193
196
  }
194
197
 
195
- async abortStale(idleMs: number): Promise<number> {
196
- const cutoff = Date.now() - idleMs;
197
- const sessions = getModel(this.db, 'ttt_sessions');
198
- const rows = await sessions.findAll({ status: 'active' });
199
- let n = 0;
200
- for (const row of rows) {
201
- if (row.updated_at < cutoff) {
202
- await sessions.updateWhere({ id: row.id }, { status: 'aborted', updated_at: Date.now() });
203
- n++;
204
- }
205
- }
206
- return n;
207
- }
208
198
  }
209
199
 
210
200
  export type SessionServices = { queue: QueueService; session: SessionService };
@@ -212,4 +202,3 @@ export type SessionServices = { queue: QueueService; session: SessionService };
212
202
  export function createServices(db: TttDatabase): SessionServices {
213
203
  return { queue: new QueueService(db), session: new SessionService(db) };
214
204
  }
215
-
@@ -1,4 +1,8 @@
1
- import { channelKey, type GameMessageLike } from '@zhin.js/game-kit';
1
+ import {
2
+ channelKey,
3
+ type GameMessageLike,
4
+ type GameReply,
5
+ } from '@zhin.js/game-kit';
2
6
  import { formatPlayerWithMark, formatRosterLine } from './player-label.js';
3
7
  import { startBotGame, startPvpGame } from './game-flow.js';
4
8
  import type { SessionServices } from './session-service.js';
@@ -17,7 +21,7 @@ export async function runTttCommand(
17
21
  services: SessionServices,
18
22
  message: GameMessageLike,
19
23
  action: string,
20
- ): Promise<string> {
24
+ ): Promise<GameReply> {
21
25
  const ch = channelKey(message);
22
26
  const userId = message.$sender.id;
23
27
 
@@ -43,7 +47,11 @@ export async function runTttCommand(
43
47
  const [px, po] = pair;
44
48
  const board = await startPvpGame(services, message, px, po);
45
49
  const matchLine = `匹配成功!${formatPlayerWithMark(px.id, px.displayName, '✕')} vs ${formatPlayerWithMark(po.id, po.displayName, '○')}`;
46
- return board ? `${matchLine}\n\n${board}` : matchLine;
50
+ return board
51
+ ? Array.isArray(board)
52
+ ? [matchLine, '\n\n', ...board]
53
+ : [matchLine, '\n\n', board]
54
+ : matchLine;
47
55
  }
48
56
  return `已加入排队(第 ${position} 位),凑满 2 人自动开局。`;
49
57
  }
@@ -1,6 +0,0 @@
1
- import type { DatabaseHost } from '@zhin.js/plugin-runtime';
2
- import { type TttDatabase, type SessionServices } from './session-service.js';
3
- /** In-memory ttt tables for Plugin Runtime slice-2 (no DatabaseFeature). */
4
- export declare function createInMemoryTttDb(): TttDatabase;
5
- export declare function mountTttMemoryServices(): SessionServices;
6
- export declare function mountTttHostServices(host: DatabaseHost): SessionServices;
package/lib/memory-db.js DELETED
@@ -1,18 +0,0 @@
1
- import { createHostGameDb, createInMemoryGameDb } from '@zhin.js/game-kit';
2
- import { defineHostTables } from './models.js';
3
- import { createServices } from './session-service.js';
4
- const TTT_TABLES = ['ttt_sessions', 'ttt_queue', 'ttt_moves', 'ttt_spectators'];
5
- /** In-memory ttt tables for Plugin Runtime slice-2 (no DatabaseFeature). */
6
- export function createInMemoryTttDb() {
7
- return createInMemoryGameDb(TTT_TABLES);
8
- }
9
- export function mountTttMemoryServices() {
10
- const services = createServices(createInMemoryTttDb());
11
- return services;
12
- }
13
- export function mountTttHostServices(host) {
14
- defineHostTables(host);
15
- const services = createServices(createHostGameDb(host, TTT_TABLES));
16
- return services;
17
- }
18
- //# sourceMappingURL=memory-db.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"memory-db.js","sourceRoot":"","sources":["../src/memory-db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,cAAc,EAA0C,MAAM,sBAAsB,CAAC;AAE9F,MAAM,UAAU,GAAG,CAAC,cAAc,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,CAAU,CAAC;AAEzF,4EAA4E;AAC5E,MAAM,UAAU,mBAAmB;IACjC,OAAO,oBAAoB,CAAC,UAAU,CAA2B,CAAC;AACpE,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,MAAM,QAAQ,GAAG,cAAc,CAAC,mBAAmB,EAAE,CAAC,CAAC;IACvD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAkB;IACrD,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACvB,MAAM,QAAQ,GAAG,cAAc,CAAC,gBAAgB,CAAC,IAAI,EAAE,UAAU,CAA2B,CAAC,CAAC;IAC9F,OAAO,QAAQ,CAAC;AAClB,CAAC"}
package/plugin.ts DELETED
@@ -1,64 +0,0 @@
1
- import { definePlugin, databaseHostToken, scheduleHostToken } from '@zhin.js/plugin-runtime';
2
- import {
3
- registerRuntimeGame,
4
- initGameRecordHost,
5
- DEFAULT_GAME_STALE_CRON,
6
- DEFAULT_GAME_STALE_IDLE_MS,
7
- } from '@zhin.js/game-kit';
8
- import { mountTttHostServices, mountTttMemoryServices } from './src/memory-db.js';
9
- import { gameServicesToken } from './src/runtime-store.js';
10
- import type { SessionServices } from './src/session-service.js';
11
-
12
- /**
13
- * Plugin Runtime:
14
- * - Commands under `commands/` are authoritative (help + bot/join/…).
15
- * - DB: prefer databaseHostToken; else in-memory SessionServices.
16
- * - Choice middleware under `middlewares/` handles ttt grid / restart payloads (Sandbox action→text).
17
- */
18
- export default definePlugin({
19
- name: 'tic-tac-toe',
20
- metadata: {
21
- displayName: 'Tic Tac Toe',
22
- },
23
- setup(context) {
24
- let services: SessionServices;
25
- if (context.resources.has(databaseHostToken)) {
26
- const host = context.resources.use(databaseHostToken);
27
- services = mountTttHostServices(host);
28
- context.lifecycle.add(initGameRecordHost(host));
29
- } else {
30
- services = mountTttMemoryServices();
31
- }
32
- context.resources.provide(gameServicesToken, services);
33
- const disposeHub = registerRuntimeGame({
34
- id: 'ttt',
35
- title: '井字棋',
36
- icon: '♟️',
37
- description: '三子连珠,群聊排队或人机对战',
38
- commandPrefix: '/井字棋',
39
- quickStart: '人机',
40
- aliases: ['ttt'],
41
- menus: [
42
- { id: 'bot', label: '🤖 人机对战' },
43
- { id: 'join', label: '👥 加入排队' },
44
- { id: 'spectate', label: '👀 观战' },
45
- { id: 'help', label: '📖 玩法说明' },
46
- ],
47
- });
48
- context.lifecycle.add(disposeHub);
49
-
50
- if (context.resources.has(scheduleHostToken)) {
51
- const schedule = context.resources.use(scheduleHostToken);
52
- const disposeCron = schedule.register({
53
- id: 'ttt/abort-stale',
54
- cron: DEFAULT_GAME_STALE_CRON,
55
- description: 'Abort stale tic-tac-toe sessions',
56
- async execute() {
57
- if (!services.session.abortStale) return;
58
- await services.session.abortStale(DEFAULT_GAME_STALE_IDLE_MS);
59
- },
60
- });
61
- context.lifecycle.add(disposeCron);
62
- }
63
- },
64
- });
package/src/memory-db.ts DELETED
@@ -1,22 +0,0 @@
1
- import { createHostGameDb, createInMemoryGameDb } from '@zhin.js/game-kit';
2
- import type { DatabaseHost } from '@zhin.js/plugin-runtime';
3
- import { defineHostTables } from './models.js';
4
- import { createServices, type TttDatabase, type SessionServices } from './session-service.js';
5
-
6
- const TTT_TABLES = ['ttt_sessions', 'ttt_queue', 'ttt_moves', 'ttt_spectators'] as const;
7
-
8
- /** In-memory ttt tables for Plugin Runtime slice-2 (no DatabaseFeature). */
9
- export function createInMemoryTttDb(): TttDatabase {
10
- return createInMemoryGameDb(TTT_TABLES) as unknown as TttDatabase;
11
- }
12
-
13
- export function mountTttMemoryServices(): SessionServices {
14
- const services = createServices(createInMemoryTttDb());
15
- return services;
16
- }
17
-
18
- export function mountTttHostServices(host: DatabaseHost): SessionServices {
19
- defineHostTables(host);
20
- const services = createServices(createHostGameDb(host, TTT_TABLES) as unknown as TttDatabase);
21
- return services;
22
- }