@zhin.js/plugin-tic-tac-toe 1.0.1 → 1.0.3
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/commands/ttt/[action:string=].ts +15 -0
- package/lib/board-view.d.ts +2 -3
- package/lib/board-view.js +1 -1
- package/lib/board-view.js.map +1 -1
- package/lib/engine.d.ts +0 -1
- package/lib/game-flow.d.ts +6 -7
- package/lib/game-flow.js +24 -14
- package/lib/game-flow.js.map +1 -1
- package/lib/index.d.ts +8 -2
- package/lib/index.js +6 -34
- package/lib/index.js.map +1 -1
- package/lib/memory-db.d.ts +6 -0
- package/lib/memory-db.js +18 -0
- package/lib/memory-db.js.map +1 -0
- package/lib/models.d.ts +5 -4
- package/lib/models.js +5 -5
- package/lib/models.js.map +1 -1
- package/lib/player-label.d.ts +1 -2
- package/lib/runtime-store.d.ts +6 -0
- package/lib/runtime-store.js +7 -0
- package/lib/runtime-store.js.map +1 -0
- package/lib/session-service.d.ts +1 -3
- package/lib/session-service.js +1 -4
- package/lib/session-service.js.map +1 -1
- package/lib/ttt-command.d.ts +4 -3
- package/lib/ttt-command.js +8 -3
- package/lib/ttt-command.js.map +1 -1
- package/middlewares/ttt-alias.ts +18 -0
- package/middlewares/ttt-choice.ts +71 -0
- package/package.json +36 -18
- package/plugin.ts +64 -0
- package/schema.json +6 -0
- package/src/board-view.ts +2 -2
- package/src/game-flow.ts +31 -24
- package/src/index.ts +7 -39
- package/src/memory-db.ts +22 -0
- package/src/models.ts +10 -10
- package/src/player-label.ts +1 -1
- package/src/runtime-store.ts +9 -0
- package/src/session-service.ts +2 -5
- package/src/ttt-command.ts +15 -5
- package/lib/board-view.d.ts.map +0 -1
- package/lib/commands.d.ts +0 -6
- package/lib/commands.d.ts.map +0 -1
- package/lib/commands.js +0 -129
- package/lib/commands.js.map +0 -1
- package/lib/engine.d.ts.map +0 -1
- package/lib/game-flow.d.ts.map +0 -1
- package/lib/hub-register.d.ts +0 -5
- package/lib/hub-register.d.ts.map +0 -1
- package/lib/hub-register.js +0 -30
- package/lib/hub-register.js.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/models.d.ts.map +0 -1
- package/lib/player-label.d.ts.map +0 -1
- package/lib/session-service.d.ts.map +0 -1
- package/lib/ttt-command.d.ts.map +0 -1
- package/plugin.yml +0 -2
- package/src/commands.ts +0 -157
- package/src/hub-register.ts +0 -31
package/lib/commands.js
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { MessageCommand, getActionFromMessage } from 'zhin.js';
|
|
2
|
-
import { channelKey, normalizeTttAction, parseChoicePayload, registerGameTextMiddleware, resolveGameChoice, resolveGameTextPayload, } from '@zhin.js/game-shared';
|
|
3
|
-
import { buildFallbackMap, TTT_PREFIX } from './board-view.js';
|
|
4
|
-
import { parseBoard } from './engine.js';
|
|
5
|
-
import { handleMove, restartFromTerminal } from './game-flow.js';
|
|
6
|
-
import { runTttCommand } from './ttt-command.js';
|
|
7
|
-
function actionPayload(message) {
|
|
8
|
-
return getActionFromMessage(message)?.payload;
|
|
9
|
-
}
|
|
10
|
-
function parseTttPayload(payload) {
|
|
11
|
-
const m = /^ttt:([^:]+):(\d)$/.exec(payload);
|
|
12
|
-
if (!m)
|
|
13
|
-
return null;
|
|
14
|
-
return { sessionId: m[1], cell: Number(m[2]) };
|
|
15
|
-
}
|
|
16
|
-
function parseCellButtonId(id) {
|
|
17
|
-
const m = /^c(\d)$/.exec(id);
|
|
18
|
-
if (!m)
|
|
19
|
-
return null;
|
|
20
|
-
const cell = Number(m[1]);
|
|
21
|
-
return cell >= 0 && cell <= 8 ? cell : null;
|
|
22
|
-
}
|
|
23
|
-
async function resolveTttAction(message, services) {
|
|
24
|
-
const restart = await resolveGameChoice({
|
|
25
|
-
message,
|
|
26
|
-
gamePrefix: TTT_PREFIX,
|
|
27
|
-
validChoiceIds: ['restart'],
|
|
28
|
-
getById: (id) => services.session.getById(id),
|
|
29
|
-
getActiveForUser: (ch, uid) => services.session.getActiveForUser(ch, uid),
|
|
30
|
-
getByBoardMessageId: (mid) => services.session.getActiveByBoardMessageId(mid),
|
|
31
|
-
});
|
|
32
|
-
if (restart)
|
|
33
|
-
return { kind: 'restart', sessionId: restart.sessionId };
|
|
34
|
-
const action = getActionFromMessage(message);
|
|
35
|
-
if (!action)
|
|
36
|
-
return null;
|
|
37
|
-
const fromPayload = parseTttPayload(action.payload);
|
|
38
|
-
if (fromPayload)
|
|
39
|
-
return { kind: 'move', ...fromPayload };
|
|
40
|
-
const cell = parseCellButtonId(action.payload)
|
|
41
|
-
?? parseCellButtonId(action.id ?? '');
|
|
42
|
-
if (cell == null)
|
|
43
|
-
return null;
|
|
44
|
-
const ch = channelKey(message);
|
|
45
|
-
const session = await services.session.getActiveForUser(ch, message.$sender.id)
|
|
46
|
-
?? (action.sourceMessageId
|
|
47
|
-
? await services.session.getActiveByBoardMessageId(action.sourceMessageId)
|
|
48
|
-
: null);
|
|
49
|
-
if (!session || session.channel_key !== ch)
|
|
50
|
-
return null;
|
|
51
|
-
return { kind: 'move', sessionId: session.id, cell };
|
|
52
|
-
}
|
|
53
|
-
export function registerCommands(plugin, getServices) {
|
|
54
|
-
registerTttPattern(plugin, '/ttt [action:word]', '井字棋(ttt)', getServices);
|
|
55
|
-
registerTttPattern(plugin, '/井字棋 [action:word]', '井字棋(中文)', getServices);
|
|
56
|
-
}
|
|
57
|
-
function registerTttPattern(plugin, pattern, desc, getServices) {
|
|
58
|
-
plugin.addCommand(new MessageCommand(pattern)
|
|
59
|
-
.desc(desc)
|
|
60
|
-
.action(async (message, result) => {
|
|
61
|
-
const services = getServices();
|
|
62
|
-
if (!services)
|
|
63
|
-
return '井字棋需要启用 database 配置。';
|
|
64
|
-
const raw = result.params.action ?? '';
|
|
65
|
-
return runTttCommand(plugin, services, message, normalizeTttAction(raw));
|
|
66
|
-
}));
|
|
67
|
-
}
|
|
68
|
-
async function handleTttAction(plugin, getServices, message) {
|
|
69
|
-
const services = getServices();
|
|
70
|
-
if (!services)
|
|
71
|
-
return false;
|
|
72
|
-
const action = await resolveTttAction(message, services);
|
|
73
|
-
if (!action)
|
|
74
|
-
return false;
|
|
75
|
-
if (action.kind === 'restart') {
|
|
76
|
-
const err = await restartFromTerminal(plugin, services, message, action.sessionId);
|
|
77
|
-
if (err)
|
|
78
|
-
await message.$reply?.(err);
|
|
79
|
-
return true;
|
|
80
|
-
}
|
|
81
|
-
const err = await handleMove(plugin, services, message, action.sessionId, action.cell);
|
|
82
|
-
if (err)
|
|
83
|
-
await message.$reply?.(err);
|
|
84
|
-
return true;
|
|
85
|
-
}
|
|
86
|
-
export function registerInteractive(plugin, getServices) {
|
|
87
|
-
plugin.registerInteractiveHandler('ttt:', (message) => handleTttAction(plugin, getServices, message));
|
|
88
|
-
plugin.registerInteractiveHandler('c', (message) => handleTttAction(plugin, getServices, message));
|
|
89
|
-
}
|
|
90
|
-
export function registerTextFallback(plugin, getServices) {
|
|
91
|
-
registerGameTextMiddleware(plugin, async (message, next) => {
|
|
92
|
-
const services = getServices();
|
|
93
|
-
if (!services)
|
|
94
|
-
return next();
|
|
95
|
-
const inboundAction = actionPayload(message);
|
|
96
|
-
if (inboundAction?.startsWith('ttt:'))
|
|
97
|
-
return next();
|
|
98
|
-
const raw = message.$raw?.trim() ?? '';
|
|
99
|
-
const ch = channelKey(message);
|
|
100
|
-
const payloadFromText = resolveGameTextPayload(raw);
|
|
101
|
-
if (payloadFromText?.startsWith(`${TTT_PREFIX}:`)) {
|
|
102
|
-
const parsed = parseChoicePayload(payloadFromText, TTT_PREFIX);
|
|
103
|
-
if (parsed?.choiceId === 'restart') {
|
|
104
|
-
const session = await services.session.getById(parsed.sessionId);
|
|
105
|
-
if (session?.channel_key === ch) {
|
|
106
|
-
const err = await restartFromTerminal(plugin, services, message, parsed.sessionId);
|
|
107
|
-
if (err)
|
|
108
|
-
await message.$reply?.(err);
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
const session = await services.session.getActiveForUser(ch, message.$sender.id);
|
|
114
|
-
if (!session)
|
|
115
|
-
return next();
|
|
116
|
-
let cell = null;
|
|
117
|
-
const map = buildFallbackMap(session.id, parseBoard(session.board));
|
|
118
|
-
const payloadText = resolveGameTextPayload(raw, map);
|
|
119
|
-
const p = payloadText ? parseTttPayload(payloadText) : null;
|
|
120
|
-
if (p?.sessionId === session.id)
|
|
121
|
-
cell = p.cell;
|
|
122
|
-
if (cell == null)
|
|
123
|
-
return next();
|
|
124
|
-
const err = await handleMove(plugin, services, message, session.id, cell);
|
|
125
|
-
if (err)
|
|
126
|
-
await message.$reply?.(err);
|
|
127
|
-
}, 'ttt:text');
|
|
128
|
-
}
|
|
129
|
-
//# sourceMappingURL=commands.js.map
|
package/lib/commands.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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"}
|
package/lib/engine.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,KAAK,IAAI,CAAC;AACvB,eAAO,MAAM,CAAC,IAAI,CAAC;AACnB,eAAO,MAAM,CAAC,IAAI,CAAC;AAEnB,MAAM,MAAM,IAAI,GAAG,OAAO,KAAK,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC;AACtD,MAAM,MAAM,KAAK,GAAG,IAAI,EAAE,CAAC;AAE3B,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC;AAQ/D,wBAAgB,UAAU,IAAI,KAAK,CAElC;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAa3E;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAI5C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAYrE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CASjF;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAE5C;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,GAAG,KAAK,CAKzE;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,IAAI,GAAG,IAAI,CAE3C;AAED,iEAAiE;AACjE,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,GAAE,IAAQ,GAAG,MAAM,CAe3D;AA0BD,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAAG,IAAI,CAIvG"}
|
package/lib/game-flow.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"game-flow.d.ts","sourceRoot":"","sources":["../src/game-flow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAExD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAejD,OAAO,EACL,MAAM,EAOP,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAE1E,OAAO,EAAE,MAAM,EAAE,CAAC;AAElB,wBAAgB,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAE5D;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EACrB,OAAO,EAAE,aAAa,EACtB,UAAU,EAAE,MAAM,EAClB,QAAQ,UAAQ,EAChB,SAAS,CAAC,EAAE,MAAM,EAAE,GACnB,OAAO,CAAC,MAAM,CAAC,CAmCjB;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EACrB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAWxB;AAUD,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EACrB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAsFxB;AAqBD,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,GACpB,OAAO,CAAC,MAAM,CAAC,CAiBjB;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EACrB,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,IAAI,CAAC,CAYf"}
|
package/lib/hub-register.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { TTT_HELP } from './ttt-command.js';
|
|
2
|
-
import type { SessionServices } from './session-service.js';
|
|
3
|
-
export declare function registerTttHub(getServices: () => SessionServices | null): () => void;
|
|
4
|
-
export { TTT_HELP };
|
|
5
|
-
//# sourceMappingURL=hub-register.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hub-register.d.ts","sourceRoot":"","sources":["../src/hub-register.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,eAAe,GAAG,IAAI,GAAG,MAAM,IAAI,CAuBpF;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|
package/lib/hub-register.js
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { getPlugin } from 'zhin.js';
|
|
2
|
-
import { ensureGameHubService } from '@zhin.js/game-shared';
|
|
3
|
-
import { runTttCommand, TTT_HELP } from './ttt-command.js';
|
|
4
|
-
export function registerTttHub(getServices) {
|
|
5
|
-
const plugin = getPlugin();
|
|
6
|
-
ensureGameHubService(plugin);
|
|
7
|
-
return plugin.registerGame({
|
|
8
|
-
id: 'ttt',
|
|
9
|
-
title: '井字棋',
|
|
10
|
-
icon: '♟️',
|
|
11
|
-
description: '三子连珠,群聊排队或人机对战',
|
|
12
|
-
commandPrefix: '/井字棋',
|
|
13
|
-
quickStart: '人机',
|
|
14
|
-
aliases: ['ttt'],
|
|
15
|
-
menus: [
|
|
16
|
-
{ id: 'bot', label: '🤖 人机对战', style: 'primary' },
|
|
17
|
-
{ id: 'join', label: '👥 加入排队', groupOnly: true },
|
|
18
|
-
{ id: 'spectate', label: '👀 观战', groupOnly: true },
|
|
19
|
-
{ id: 'help', label: '📖 玩法说明' },
|
|
20
|
-
],
|
|
21
|
-
runAction: async (actionId, ctx) => {
|
|
22
|
-
const services = getServices();
|
|
23
|
-
if (!services)
|
|
24
|
-
return '井字棋需要启用 database 配置。';
|
|
25
|
-
return runTttCommand(ctx.plugin, services, ctx.message, actionId);
|
|
26
|
-
},
|
|
27
|
-
});
|
|
28
|
-
}
|
|
29
|
-
export { TTT_HELP };
|
|
30
|
-
//# sourceMappingURL=hub-register.js.map
|
package/lib/hub-register.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hub-register.js","sourceRoot":"","sources":["../src/hub-register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAG3D,MAAM,UAAU,cAAc,CAAC,WAAyC;IACtE,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,OAAO,MAAM,CAAC,YAAY,CAAC;QACzB,EAAE,EAAE,KAAK;QACT,KAAK,EAAE,KAAK;QACZ,IAAI,EAAE,IAAI;QACV,WAAW,EAAE,gBAAgB;QAC7B,aAAa,EAAE,MAAM;QACrB,UAAU,EAAE,IAAI;QAChB,OAAO,EAAE,CAAC,KAAK,CAAC;QAChB,KAAK,EAAE;YACL,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;YACjD,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE;YACjD,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE;YACnD,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE;SACjC;QACD,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE;YACjC,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;YAC/B,IAAI,CAAC,QAAQ;gBAAE,OAAO,sBAAsB,CAAC;YAC7C,OAAO,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACpE,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|
package/lib/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/lib/models.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAE9C,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC;AAErE,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,MAAM;QACd,YAAY,EAAE;YACZ,EAAE,EAAE,MAAM,CAAC;YACX,OAAO,EAAE,MAAM,CAAC;YAChB,QAAQ,EAAE,MAAM,CAAC;YACjB,YAAY,EAAE,MAAM,CAAC;YACrB,UAAU,EAAE,MAAM,CAAC;YACnB,WAAW,EAAE,MAAM,CAAC;YACpB,QAAQ,EAAE,MAAM,CAAC;YACjB,QAAQ,EAAE,MAAM,CAAC;YACjB,aAAa,EAAE,MAAM,CAAC;YACtB,aAAa,EAAE,MAAM,CAAC;YACtB,KAAK,EAAE,MAAM,CAAC;YACd,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,EAAE,gBAAgB,CAAC;YACzB,MAAM,EAAE,MAAM,CAAC;YACf,gBAAgB,EAAE,MAAM,CAAC;YACzB,UAAU,EAAE,MAAM,CAAC;YACnB,UAAU,EAAE,MAAM,CAAC;YACnB,UAAU,EAAE,MAAM,CAAC;SACpB,CAAC;QACF,SAAS,EAAE;YACT,EAAE,EAAE,MAAM,CAAC;YACX,WAAW,EAAE,MAAM,CAAC;YACpB,OAAO,EAAE,MAAM,CAAC;YAChB,SAAS,EAAE,MAAM,CAAC;YAClB,SAAS,EAAE,MAAM,CAAC;SACnB,CAAC;QACF,SAAS,EAAE;YACT,EAAE,EAAE,MAAM,CAAC;YACX,UAAU,EAAE,MAAM,CAAC;YACnB,SAAS,EAAE,MAAM,CAAC;YAClB,IAAI,EAAE,MAAM,CAAC;YACb,UAAU,EAAE,MAAM,CAAC;YACnB,UAAU,EAAE,MAAM,CAAC;SACpB,CAAC;QACF,cAAc,EAAE;YACd,EAAE,EAAE,MAAM,CAAC;YACX,UAAU,EAAE,MAAM,CAAC;YACnB,OAAO,EAAE,MAAM,CAAC;YAChB,SAAS,EAAE,MAAM,CAAC;SACnB,CAAC;KACH;CACF;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,cAAc,CAAC,CAAC;AACnD,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;AAC9C,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;AAC7C,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;AAEvD,iBAAiB;AACjB,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,WAAW,GAAG,WAAW,GAAG,gBAAgB,CAAC;AAEzF,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CA6CnD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"player-label.d.ts","sourceRoot":"","sources":["../src/player-label.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAQ,KAAK,IAAI,EAAa,MAAM,aAAa,CAAC;AAEzD,eAAO,MAAM,MAAM,gBAAgB,CAAC;AAEpC,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,MAAM,CAAC,GAAG,MAAM,CAGpF;AAED,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAI/E;AAED,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,IAAI,EAAE,GAAG,GAAG,GAAG,GACd,MAAM,CAER;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAE/D;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,IAAI,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAGlG;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAIlF;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,GAAG,MAAM,CAG9E;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEhG"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"session-service.d.ts","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"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"}
|
package/lib/ttt-command.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ttt-command.d.ts","sourceRoot":"","sources":["../src/ttt-command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAI/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE5D,eAAO,MAAM,QAAQ,QAQT,CAAC;AAEb,wBAAsB,aAAa,CACjC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAsD7B"}
|
package/plugin.yml
DELETED
package/src/commands.ts
DELETED
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
import { Message, MessageCommand, getActionFromMessage, type Plugin } from 'zhin.js';
|
|
2
|
-
import {
|
|
3
|
-
channelKey,
|
|
4
|
-
normalizeTttAction,
|
|
5
|
-
parseChoicePayload,
|
|
6
|
-
registerGameTextMiddleware,
|
|
7
|
-
resolveGameChoice,
|
|
8
|
-
resolveGameTextPayload,
|
|
9
|
-
} from '@zhin.js/game-shared';
|
|
10
|
-
import { buildFallbackMap, TTT_PREFIX } from './board-view.js';
|
|
11
|
-
import { parseBoard } from './engine.js';
|
|
12
|
-
import { handleMove, restartFromTerminal } from './game-flow.js';
|
|
13
|
-
import { runTttCommand } from './ttt-command.js';
|
|
14
|
-
import type { SessionServices } from './session-service.js';
|
|
15
|
-
|
|
16
|
-
function actionPayload(message: Message<any>): string | undefined {
|
|
17
|
-
return getActionFromMessage(message)?.payload;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function parseTttPayload(payload: string): { sessionId: string; cell: number } | null {
|
|
21
|
-
const m = /^ttt:([^:]+):(\d)$/.exec(payload);
|
|
22
|
-
if (!m) return null;
|
|
23
|
-
return { sessionId: m[1]!, cell: Number(m[2]) };
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function parseCellButtonId(id: string): number | null {
|
|
27
|
-
const m = /^c(\d)$/.exec(id);
|
|
28
|
-
if (!m) return null;
|
|
29
|
-
const cell = Number(m[1]);
|
|
30
|
-
return cell >= 0 && cell <= 8 ? cell : null;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async function resolveTttAction(
|
|
34
|
-
message: Message<any>,
|
|
35
|
-
services: SessionServices,
|
|
36
|
-
): Promise<{ kind: 'move'; sessionId: string; cell: number } | { kind: 'restart'; sessionId: string } | null> {
|
|
37
|
-
const restart = await resolveGameChoice({
|
|
38
|
-
message,
|
|
39
|
-
gamePrefix: TTT_PREFIX,
|
|
40
|
-
validChoiceIds: ['restart'],
|
|
41
|
-
getById: (id) => services.session.getById(id),
|
|
42
|
-
getActiveForUser: (ch, uid) => services.session.getActiveForUser(ch, uid),
|
|
43
|
-
getByBoardMessageId: (mid) => services.session.getActiveByBoardMessageId(mid),
|
|
44
|
-
});
|
|
45
|
-
if (restart) return { kind: 'restart', sessionId: restart.sessionId };
|
|
46
|
-
|
|
47
|
-
const action = getActionFromMessage(message);
|
|
48
|
-
if (!action) return null;
|
|
49
|
-
|
|
50
|
-
const fromPayload = parseTttPayload(action.payload);
|
|
51
|
-
if (fromPayload) return { kind: 'move', ...fromPayload };
|
|
52
|
-
|
|
53
|
-
const cell =
|
|
54
|
-
parseCellButtonId(action.payload)
|
|
55
|
-
?? parseCellButtonId(action.id ?? '');
|
|
56
|
-
if (cell == null) return null;
|
|
57
|
-
|
|
58
|
-
const ch = channelKey(message);
|
|
59
|
-
const session =
|
|
60
|
-
await services.session.getActiveForUser(ch, message.$sender.id)
|
|
61
|
-
?? (action.sourceMessageId
|
|
62
|
-
? await services.session.getActiveByBoardMessageId(action.sourceMessageId)
|
|
63
|
-
: null);
|
|
64
|
-
if (!session || session.channel_key !== ch) return null;
|
|
65
|
-
return { kind: 'move', sessionId: session.id, cell };
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function registerCommands(
|
|
69
|
-
plugin: Plugin,
|
|
70
|
-
getServices: () => SessionServices | null,
|
|
71
|
-
): void {
|
|
72
|
-
registerTttPattern(plugin, '/ttt [action:word]', '井字棋(ttt)', getServices);
|
|
73
|
-
registerTttPattern(plugin, '/井字棋 [action:word]', '井字棋(中文)', getServices);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function registerTttPattern(
|
|
77
|
-
plugin: Plugin,
|
|
78
|
-
pattern: string,
|
|
79
|
-
desc: string,
|
|
80
|
-
getServices: () => SessionServices | null,
|
|
81
|
-
): void {
|
|
82
|
-
plugin.addCommand(
|
|
83
|
-
new MessageCommand(pattern)
|
|
84
|
-
.desc(desc)
|
|
85
|
-
.action(async (message, result) => {
|
|
86
|
-
const services = getServices();
|
|
87
|
-
if (!services) return '井字棋需要启用 database 配置。';
|
|
88
|
-
const raw = (result.params.action as string | undefined) ?? '';
|
|
89
|
-
return runTttCommand(plugin, services, message, normalizeTttAction(raw));
|
|
90
|
-
}),
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
async function handleTttAction(
|
|
95
|
-
plugin: Plugin,
|
|
96
|
-
getServices: () => SessionServices | null,
|
|
97
|
-
message: Message<any>,
|
|
98
|
-
): Promise<boolean> {
|
|
99
|
-
const services = getServices();
|
|
100
|
-
if (!services) return false;
|
|
101
|
-
const action = await resolveTttAction(message, services);
|
|
102
|
-
if (!action) return false;
|
|
103
|
-
|
|
104
|
-
if (action.kind === 'restart') {
|
|
105
|
-
const err = await restartFromTerminal(plugin, services, message, action.sessionId);
|
|
106
|
-
if (err) await message.$reply?.(err);
|
|
107
|
-
return true;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const err = await handleMove(plugin, services, message, action.sessionId, action.cell);
|
|
111
|
-
if (err) await message.$reply?.(err);
|
|
112
|
-
return true;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export function registerInteractive(plugin: Plugin, getServices: () => SessionServices | null): void {
|
|
116
|
-
plugin.registerInteractiveHandler('ttt:', (message) => handleTttAction(plugin, getServices, message));
|
|
117
|
-
plugin.registerInteractiveHandler('c', (message) => handleTttAction(plugin, getServices, message));
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export function registerTextFallback(plugin: Plugin, getServices: () => SessionServices | null): void {
|
|
121
|
-
registerGameTextMiddleware(plugin, async (message, next) => {
|
|
122
|
-
const services = getServices();
|
|
123
|
-
if (!services) return next();
|
|
124
|
-
|
|
125
|
-
const inboundAction = actionPayload(message);
|
|
126
|
-
if (inboundAction?.startsWith('ttt:')) return next();
|
|
127
|
-
|
|
128
|
-
const raw = message.$raw?.trim() ?? '';
|
|
129
|
-
const ch = channelKey(message);
|
|
130
|
-
|
|
131
|
-
const payloadFromText = resolveGameTextPayload(raw);
|
|
132
|
-
if (payloadFromText?.startsWith(`${TTT_PREFIX}:`)) {
|
|
133
|
-
const parsed = parseChoicePayload(payloadFromText, TTT_PREFIX);
|
|
134
|
-
if (parsed?.choiceId === 'restart') {
|
|
135
|
-
const session = await services.session.getById(parsed.sessionId);
|
|
136
|
-
if (session?.channel_key === ch) {
|
|
137
|
-
const err = await restartFromTerminal(plugin, services, message, parsed.sessionId);
|
|
138
|
-
if (err) await message.$reply?.(err);
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const session = await services.session.getActiveForUser(ch, message.$sender.id);
|
|
145
|
-
if (!session) return next();
|
|
146
|
-
|
|
147
|
-
let cell: number | null = null;
|
|
148
|
-
const map = buildFallbackMap(session.id, parseBoard(session.board));
|
|
149
|
-
const payloadText = resolveGameTextPayload(raw, map);
|
|
150
|
-
const p = payloadText ? parseTttPayload(payloadText) : null;
|
|
151
|
-
if (p?.sessionId === session.id) cell = p.cell;
|
|
152
|
-
if (cell == null) return next();
|
|
153
|
-
|
|
154
|
-
const err = await handleMove(plugin, services, message, session.id, cell);
|
|
155
|
-
if (err) await message.$reply?.(err);
|
|
156
|
-
}, 'ttt:text');
|
|
157
|
-
}
|
package/src/hub-register.ts
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { getPlugin } from 'zhin.js';
|
|
2
|
-
import { ensureGameHubService } from '@zhin.js/game-shared';
|
|
3
|
-
import { runTttCommand, TTT_HELP } from './ttt-command.js';
|
|
4
|
-
import type { SessionServices } from './session-service.js';
|
|
5
|
-
|
|
6
|
-
export function registerTttHub(getServices: () => SessionServices | null): () => void {
|
|
7
|
-
const plugin = getPlugin();
|
|
8
|
-
ensureGameHubService(plugin);
|
|
9
|
-
return plugin.registerGame({
|
|
10
|
-
id: 'ttt',
|
|
11
|
-
title: '井字棋',
|
|
12
|
-
icon: '♟️',
|
|
13
|
-
description: '三子连珠,群聊排队或人机对战',
|
|
14
|
-
commandPrefix: '/井字棋',
|
|
15
|
-
quickStart: '人机',
|
|
16
|
-
aliases: ['ttt'],
|
|
17
|
-
menus: [
|
|
18
|
-
{ id: 'bot', label: '🤖 人机对战', style: 'primary' },
|
|
19
|
-
{ id: 'join', label: '👥 加入排队', groupOnly: true },
|
|
20
|
-
{ id: 'spectate', label: '👀 观战', groupOnly: true },
|
|
21
|
-
{ id: 'help', label: '📖 玩法说明' },
|
|
22
|
-
],
|
|
23
|
-
runAction: async (actionId, ctx) => {
|
|
24
|
-
const services = getServices();
|
|
25
|
-
if (!services) return '井字棋需要启用 database 配置。';
|
|
26
|
-
return runTttCommand(ctx.plugin, services, ctx.message, actionId);
|
|
27
|
-
},
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export { TTT_HELP };
|