@zhin.js/plugin-idiom-chain 1.0.1 → 1.0.2
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/chain/[action:string=].ts +15 -0
- package/lib/chain-command.d.ts +4 -3
- package/lib/chain-command.js +5 -1
- package/lib/chain-command.js.map +1 -1
- package/lib/engine.d.ts +0 -1
- package/lib/game-flow.d.ts +6 -7
- package/lib/game-flow.js +26 -21
- package/lib/game-flow.js.map +1 -1
- package/lib/idiom-provider.d.ts +0 -1
- package/lib/idiom-provider.js +1 -1
- package/lib/idiom-provider.js.map +1 -1
- package/lib/index.d.ts +8 -2
- package/lib/index.js +8 -25
- 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 +2 -2
- package/lib/models.js.map +1 -1
- 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/view.d.ts +1 -2
- package/lib/view.js +1 -1
- package/lib/view.js.map +1 -1
- package/middlewares/chain-alias.ts +18 -0
- package/middlewares/chain-text.ts +75 -0
- package/package.json +36 -10
- package/plugin.ts +64 -0
- package/schema.json +6 -0
- package/src/chain-command.ts +12 -3
- package/src/game-flow.ts +32 -28
- package/src/idiom-provider.ts +1 -1
- package/src/index.ts +9 -30
- package/src/memory-db.ts +22 -0
- package/src/models.ts +7 -4
- package/src/runtime-store.ts +9 -0
- package/src/session-service.ts +2 -5
- package/src/view.ts +2 -2
- package/lib/chain-command.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 -95
- 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 -31
- package/lib/hub-register.js.map +0 -1
- package/lib/idiom-provider.d.ts.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/models.d.ts.map +0 -1
- package/lib/session-service.d.ts.map +0 -1
- package/lib/view.d.ts.map +0 -1
- package/plugin.yml +0 -2
- package/src/commands.ts +0 -116
- package/src/hub-register.ts +0 -32
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/plugin-idiom-chain",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Zhin.js 成语接龙 — 四字成语文字接龙",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Zhin.js 成语接龙 — 四字成语文字接龙 (Plugin Runtime)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
7
7
|
"types": "./lib/index.d.ts",
|
|
@@ -14,22 +14,26 @@
|
|
|
14
14
|
"./package.json": "./package.json"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
|
+
"plugin.ts",
|
|
18
|
+
"schema.json",
|
|
19
|
+
"commands",
|
|
20
|
+
"middlewares",
|
|
17
21
|
"src",
|
|
18
22
|
"lib",
|
|
19
|
-
"plugin.yml",
|
|
20
23
|
"README.md"
|
|
21
24
|
],
|
|
22
25
|
"license": "MIT",
|
|
23
|
-
"peerDependencies": {
|
|
24
|
-
"zhin.js": "4.1.2"
|
|
25
|
-
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"chinese-idiom-chengyu": "^1.1.0",
|
|
28
|
-
"@zhin.js/
|
|
28
|
+
"@zhin.js/command": "1.0.1",
|
|
29
|
+
"@zhin.js/core": "1.3.5",
|
|
30
|
+
"@zhin.js/game-kit": "1.0.2",
|
|
31
|
+
"@zhin.js/middleware": "1.0.1",
|
|
32
|
+
"@zhin.js/plugin-runtime": "1.0.1"
|
|
29
33
|
},
|
|
30
34
|
"devDependencies": {
|
|
31
35
|
"typescript": "^6.0.3",
|
|
32
|
-
"
|
|
36
|
+
"vitest": "^4.1.10"
|
|
33
37
|
},
|
|
34
38
|
"repository": {
|
|
35
39
|
"type": "git",
|
|
@@ -40,8 +44,30 @@
|
|
|
40
44
|
"access": "public",
|
|
41
45
|
"registry": "https://registry.npmjs.org"
|
|
42
46
|
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": "^20.19.0 || >=22.12.0"
|
|
49
|
+
},
|
|
50
|
+
"zhin": {
|
|
51
|
+
"protocol": 1,
|
|
52
|
+
"type": "plugin",
|
|
53
|
+
"entry": "./plugin.ts",
|
|
54
|
+
"engine": "^1.0.0",
|
|
55
|
+
"runtime": "trusted",
|
|
56
|
+
"features": [
|
|
57
|
+
{
|
|
58
|
+
"package": "@zhin.js/command",
|
|
59
|
+
"api": "^1.0.0"
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
"package": "@zhin.js/middleware",
|
|
63
|
+
"api": "^1.0.0"
|
|
64
|
+
}
|
|
65
|
+
],
|
|
66
|
+
"plugins": []
|
|
67
|
+
},
|
|
43
68
|
"scripts": {
|
|
44
|
-
"build": "tsc
|
|
45
|
-
"clean": "rimraf lib"
|
|
69
|
+
"build": "tsc",
|
|
70
|
+
"clean": "rimraf lib",
|
|
71
|
+
"test": "NODE_OPTIONS=--experimental-strip-types vitest run --root ../../.. plugins/games/idiom-chain/tests"
|
|
46
72
|
}
|
|
47
73
|
}
|
package/plugin.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
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 { mountChainHostServices, mountChainMemoryServices } from './src/memory-db.js';
|
|
9
|
+
import { gameServicesToken } from './src/runtime-store.js';
|
|
10
|
+
import type { SessionService } from './src/session-service.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Plugin Runtime:
|
|
14
|
+
* - Commands under `commands/` are authoritative (help + start/continue/quit via in-memory DB).
|
|
15
|
+
* - DB: prefer databaseHostToken; else in-memory SessionService.
|
|
16
|
+
* - Text middleware under `middlewares/` handles idiom answer payloads.
|
|
17
|
+
*/
|
|
18
|
+
export default definePlugin({
|
|
19
|
+
name: 'idiom-chain',
|
|
20
|
+
metadata: {
|
|
21
|
+
displayName: 'Idiom Chain',
|
|
22
|
+
},
|
|
23
|
+
setup(context) {
|
|
24
|
+
let services: SessionService;
|
|
25
|
+
if (context.resources.has(databaseHostToken)) {
|
|
26
|
+
const host = context.resources.use(databaseHostToken);
|
|
27
|
+
services = mountChainHostServices(host);
|
|
28
|
+
context.lifecycle.add(initGameRecordHost(host));
|
|
29
|
+
} else {
|
|
30
|
+
services = mountChainMemoryServices();
|
|
31
|
+
}
|
|
32
|
+
context.resources.provide(gameServicesToken, services);
|
|
33
|
+
const disposeHub = registerRuntimeGame({
|
|
34
|
+
id: 'chain',
|
|
35
|
+
title: '成语接龙',
|
|
36
|
+
icon: '📜',
|
|
37
|
+
description: '四字成语接龙(同音/同字)',
|
|
38
|
+
commandPrefix: '/接龙',
|
|
39
|
+
quickStart: 'start_pinyin',
|
|
40
|
+
aliases: ['chain'],
|
|
41
|
+
menus: [
|
|
42
|
+
{ id: 'start_pinyin', label: '🎮 同音接龙' },
|
|
43
|
+
{ id: 'start_char', label: '📝 同字接龙' },
|
|
44
|
+
{ id: 'continue', 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: 'chain/abort-stale',
|
|
54
|
+
cron: DEFAULT_GAME_STALE_CRON,
|
|
55
|
+
description: 'Abort stale idiom-chain sessions',
|
|
56
|
+
async execute() {
|
|
57
|
+
if (!services.abortStale) return;
|
|
58
|
+
await services.abortStale(DEFAULT_GAME_STALE_IDLE_MS);
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
context.lifecycle.add(disposeCron);
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
});
|
package/schema.json
ADDED
package/src/chain-command.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Message, Plugin } from 'zhin.js';
|
|
2
|
-
import { channelKey } from '@zhin.js/game-
|
|
1
|
+
import type { Message, Plugin } from '@zhin.js/core';
|
|
2
|
+
import { channelKey } from '@zhin.js/game-kit';
|
|
3
3
|
import { continueGame, startGame } from './game-flow.js';
|
|
4
4
|
import { idiomCount, modeLabel, promptLine, type MatchMode } from './engine.js';
|
|
5
5
|
|
|
@@ -19,7 +19,7 @@ export const CHAIN_HELP = [
|
|
|
19
19
|
].join('\n');
|
|
20
20
|
|
|
21
21
|
export async function runChainCommand(
|
|
22
|
-
plugin: Plugin,
|
|
22
|
+
plugin: Plugin | null,
|
|
23
23
|
services: SessionService,
|
|
24
24
|
message: Message<any>,
|
|
25
25
|
action: string,
|
|
@@ -55,3 +55,12 @@ export async function runChainCommand(
|
|
|
55
55
|
|
|
56
56
|
return `未知子命令:${action}\n\n${CHAIN_HELP}`;
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
/** Plugin Runtime / smoke: text-only, no Adapter.editMessage. */
|
|
60
|
+
export async function runChainCommandText(
|
|
61
|
+
services: SessionService,
|
|
62
|
+
message: Message<any>,
|
|
63
|
+
action: string,
|
|
64
|
+
): Promise<string> {
|
|
65
|
+
return (await runChainCommand(null, services, message, action)) ?? '';
|
|
66
|
+
}
|
package/src/game-flow.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type { Adapter, Message, Plugin } from 'zhin.js';
|
|
1
|
+
import type { Adapter, Message, Plugin } from '@zhin.js/core';
|
|
2
|
+
import { plainTextFromSendContent } from '@zhin.js/game-kit';
|
|
2
3
|
import {
|
|
3
4
|
CHAIN_PREFIX,
|
|
4
5
|
getGloss,
|
|
@@ -21,13 +22,15 @@ function sessionMode(session: ChainSessionRow): MatchMode {
|
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
export async function sendOrEditView(
|
|
24
|
-
plugin: Plugin,
|
|
25
|
+
plugin: Plugin | null,
|
|
25
26
|
services: SessionService,
|
|
26
27
|
message: Message<any>,
|
|
27
28
|
session: ChainSessionRow,
|
|
28
29
|
eventLines: string[] = [],
|
|
29
|
-
): Promise<void> {
|
|
30
|
+
): Promise<string | void> {
|
|
30
31
|
const content = buildChainView(session, eventLines, message.$channel.type);
|
|
32
|
+
if (!plugin) return plainTextFromSendContent(content);
|
|
33
|
+
|
|
31
34
|
const adapter = plugin.root.inject(message.$adapter) as Adapter;
|
|
32
35
|
|
|
33
36
|
if (session.board_message_id) {
|
|
@@ -83,7 +86,7 @@ async function botTurn(
|
|
|
83
86
|
}
|
|
84
87
|
|
|
85
88
|
export async function startGame(
|
|
86
|
-
plugin: Plugin,
|
|
89
|
+
plugin: Plugin | null,
|
|
87
90
|
services: SessionService,
|
|
88
91
|
message: Message<any>,
|
|
89
92
|
matchMode: MatchMode = 'pinyin',
|
|
@@ -108,15 +111,15 @@ export async function startGame(
|
|
|
108
111
|
});
|
|
109
112
|
|
|
110
113
|
const gloss = starter.gloss ?? getGloss(starter.text);
|
|
111
|
-
await sendOrEditView(plugin, services, message, session, [
|
|
114
|
+
const text = await sendOrEditView(plugin, services, message, session, [
|
|
112
115
|
`🎬 ${modeLabel(matchMode)}开局!我先出:**${starter.text}**${gloss ? `(${gloss})` : ''}`,
|
|
113
116
|
promptLine(starter.text, matchMode),
|
|
114
117
|
]);
|
|
115
|
-
return undefined;
|
|
118
|
+
return typeof text === 'string' ? text : undefined;
|
|
116
119
|
}
|
|
117
120
|
|
|
118
121
|
export async function continueGame(
|
|
119
|
-
plugin: Plugin,
|
|
122
|
+
plugin: Plugin | null,
|
|
120
123
|
services: SessionService,
|
|
121
124
|
message: Message<any>,
|
|
122
125
|
): Promise<string> {
|
|
@@ -125,12 +128,13 @@ export async function continueGame(
|
|
|
125
128
|
message.$sender.id,
|
|
126
129
|
);
|
|
127
130
|
if (!session) return '你没有进行中的接龙,发送「接龙 开始」。';
|
|
128
|
-
await sendOrEditView(plugin, services, message, session);
|
|
131
|
+
const text = await sendOrEditView(plugin, services, message, session);
|
|
132
|
+
if (typeof text === 'string') return text;
|
|
129
133
|
return '已刷新接龙界面。';
|
|
130
134
|
}
|
|
131
135
|
|
|
132
136
|
export async function processIdiomText(
|
|
133
|
-
plugin: Plugin,
|
|
137
|
+
plugin: Plugin | null,
|
|
134
138
|
services: SessionService,
|
|
135
139
|
message: Message<any>,
|
|
136
140
|
raw: string,
|
|
@@ -153,13 +157,14 @@ export async function processIdiomText(
|
|
|
153
157
|
streak: 0,
|
|
154
158
|
});
|
|
155
159
|
const updated = (await services.getById(session.id))!;
|
|
156
|
-
await sendOrEditView(plugin, services, message, updated, [
|
|
157
|
-
|
|
160
|
+
return (await sendOrEditView(plugin, services, message, updated, [
|
|
161
|
+
check.reason!,
|
|
162
|
+
'失误过多,本局结束。',
|
|
163
|
+
])) ?? null;
|
|
158
164
|
}
|
|
159
165
|
await services.updateSession(session.id, { wrong_count: wrong, streak: 0 });
|
|
160
166
|
const updated = (await services.getById(session.id))!;
|
|
161
|
-
await sendOrEditView(plugin, services, message, updated, [check.reason!]);
|
|
162
|
-
return null;
|
|
167
|
+
return (await sendOrEditView(plugin, services, message, updated, [check.reason!])) ?? null;
|
|
163
168
|
}
|
|
164
169
|
|
|
165
170
|
used.add(idiom);
|
|
@@ -181,12 +186,14 @@ export async function processIdiomText(
|
|
|
181
186
|
const userLine = `✅ 你:${idiom}${gloss ? `(${gloss})` : ''}`;
|
|
182
187
|
|
|
183
188
|
const botResult = await botTurn(services, current, used);
|
|
184
|
-
await sendOrEditView(plugin, services, message, botResult.session, [
|
|
185
|
-
|
|
189
|
+
return (await sendOrEditView(plugin, services, message, botResult.session, [
|
|
190
|
+
userLine,
|
|
191
|
+
...botResult.lines,
|
|
192
|
+
])) ?? null;
|
|
186
193
|
}
|
|
187
194
|
|
|
188
195
|
export async function handleChoice(
|
|
189
|
-
plugin: Plugin,
|
|
196
|
+
plugin: Plugin | null,
|
|
190
197
|
services: SessionService,
|
|
191
198
|
message: Message<any>,
|
|
192
199
|
sessionId: string,
|
|
@@ -214,11 +221,10 @@ export async function handleChoice(
|
|
|
214
221
|
});
|
|
215
222
|
const updated = (await services.getById(session.id))!;
|
|
216
223
|
const gloss = starter.gloss ?? getGloss(starter.text);
|
|
217
|
-
await sendOrEditView(plugin, services, message, updated, [
|
|
224
|
+
return (await sendOrEditView(plugin, services, message, updated, [
|
|
218
225
|
`🎬 新一局!我先出:**${starter.text}**${gloss ? `(${gloss})` : ''}`,
|
|
219
226
|
promptLine(starter.text, mode),
|
|
220
|
-
]);
|
|
221
|
-
return null;
|
|
227
|
+
])) ?? null;
|
|
222
228
|
}
|
|
223
229
|
|
|
224
230
|
if (session.status !== 'active') {
|
|
@@ -233,17 +239,15 @@ export async function handleChoice(
|
|
|
233
239
|
await sendOrEditView(plugin, services, message, session, ['💡 词库中暂无可用提示,你赢了!']);
|
|
234
240
|
await services.updateSession(session.id, { status: 'won', player_score: session.player_score + 1 });
|
|
235
241
|
const updated = (await services.getById(session.id))!;
|
|
236
|
-
await sendOrEditView(plugin, services, message, updated);
|
|
237
|
-
return null;
|
|
242
|
+
return (await sendOrEditView(plugin, services, message, updated)) ?? null;
|
|
238
243
|
}
|
|
239
244
|
const gloss = getGloss(hint);
|
|
240
245
|
await services.updateSession(session.id, { hints_used: session.hints_used + 1, streak: 0 });
|
|
241
246
|
const updated = (await services.getById(session.id))!;
|
|
242
|
-
await sendOrEditView(plugin, services, message, updated, [
|
|
247
|
+
return (await sendOrEditView(plugin, services, message, updated, [
|
|
243
248
|
`💡 提示:可试 **${hint}**${gloss ? `(${gloss})` : ''}`,
|
|
244
249
|
'(使用提示会清零连击)',
|
|
245
|
-
]);
|
|
246
|
-
return null;
|
|
250
|
+
])) ?? null;
|
|
247
251
|
}
|
|
248
252
|
|
|
249
253
|
if (choiceId === 'skip') {
|
|
@@ -253,15 +257,15 @@ export async function handleChoice(
|
|
|
253
257
|
streak: 0,
|
|
254
258
|
});
|
|
255
259
|
const updated = (await services.getById(session.id))!;
|
|
256
|
-
await sendOrEditView(plugin, services, message, updated, [
|
|
257
|
-
|
|
260
|
+
return (await sendOrEditView(plugin, services, message, updated, [
|
|
261
|
+
'⏭️ 你选择跳过,机器人得一分。',
|
|
262
|
+
])) ?? null;
|
|
258
263
|
}
|
|
259
264
|
|
|
260
265
|
if (choiceId === 'quit') {
|
|
261
266
|
await services.updateSession(session.id, { status: 'lost', bot_score: session.bot_score + 1 });
|
|
262
267
|
const updated = (await services.getById(session.id))!;
|
|
263
|
-
await sendOrEditView(plugin, services, message, updated, ['🏳️ 你认输了。']);
|
|
264
|
-
return null;
|
|
268
|
+
return (await sendOrEditView(plugin, services, message, updated, ['🏳️ 你认输了。'])) ?? null;
|
|
265
269
|
}
|
|
266
270
|
|
|
267
271
|
return '未知操作。';
|
package/src/idiom-provider.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* @see https://www.npmjs.com/package/chinese-idiom-chengyu
|
|
4
4
|
*/
|
|
5
5
|
import { createRequire } from 'node:module';
|
|
6
|
-
import { secureRandomItem } from '@zhin.js/game-
|
|
6
|
+
import { secureRandomItem } from '@zhin.js/game-kit';
|
|
7
7
|
|
|
8
8
|
const require = createRequire(import.meta.url);
|
|
9
9
|
|
package/src/index.ts
CHANGED
|
@@ -1,30 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
registerModels(plugin);
|
|
11
|
-
|
|
12
|
-
let services: SessionService | null = null;
|
|
13
|
-
|
|
14
|
-
useContext('database', (dbFeature: DatabaseFeature) => {
|
|
15
|
-
services = createServices(resolveGameDatabase(dbFeature));
|
|
16
|
-
logger.debug(formatCompact({ 模块: '成语接龙', 数据模型: '已就绪' }));
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
registerChainHub(() => services);
|
|
20
|
-
registerCommands(plugin, () => services);
|
|
21
|
-
registerInteractive(plugin, () => services);
|
|
22
|
-
registerTextMiddleware(plugin, () => services);
|
|
23
|
-
|
|
24
|
-
addSchedule({ kind: 'solar', cron: '0 */15 * * * *' }, async () => {
|
|
25
|
-
if (!services) return;
|
|
26
|
-
const n = await services.abortStale(45 * 60 * 1000);
|
|
27
|
-
if (n > 0) logger.debug(formatCompact({ 成语接龙: '清理超时局', count: n }));
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
logger.debug(formatCompact({ 模块: '成语接龙', 状态: '已加载' }));
|
|
1
|
+
export { CHAIN_HELP } from './chain-command.js';
|
|
2
|
+
export { gameServicesToken, resolveGameServices } from './runtime-store.js';
|
|
3
|
+
export { createInMemoryChainDb, mountChainMemoryServices } from './memory-db.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 已由 plugin.ts 接线:commands/ 命令、middlewares/ 文本与选项中间件、
|
|
7
|
+
* 游戏大厅注册(registerRuntimeGame)、过期会话 cron(scheduleHostToken)、
|
|
8
|
+
* host DatabaseHost(databaseHostToken)。仍未接:interactive 按钮回调。
|
|
9
|
+
*/
|
package/src/memory-db.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
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 ChainDatabase, type SessionService } from './session-service.js';
|
|
5
|
+
|
|
6
|
+
const CHAIN_TABLES = ['idiom_chain_sessions'] as const;
|
|
7
|
+
|
|
8
|
+
/** In-memory idiom_chain_sessions for Plugin Runtime slice-2 (no DatabaseFeature). */
|
|
9
|
+
export function createInMemoryChainDb(): ChainDatabase {
|
|
10
|
+
return createInMemoryGameDb(CHAIN_TABLES) as unknown as ChainDatabase;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function mountChainMemoryServices(): SessionService {
|
|
14
|
+
const services = createServices(createInMemoryChainDb());
|
|
15
|
+
return services;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function mountChainHostServices(host: DatabaseHost): SessionService {
|
|
19
|
+
defineHostTables(host);
|
|
20
|
+
const services = createServices(createHostGameDb(host, CHAIN_TABLES) as unknown as ChainDatabase);
|
|
21
|
+
return services;
|
|
22
|
+
}
|
package/src/models.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type { Models
|
|
1
|
+
import type { Models } from '@zhin.js/core';
|
|
2
2
|
import type { MatchMode } from './engine.js';
|
|
3
3
|
|
|
4
4
|
export type ChainSessionStatus = 'active' | 'won' | 'lost' | 'aborted';
|
|
5
5
|
|
|
6
|
-
declare module 'zhin.js' {
|
|
6
|
+
declare module '@zhin.js/core' {
|
|
7
7
|
interface Models {
|
|
8
8
|
idiom_chain_sessions: {
|
|
9
9
|
id: string;
|
|
@@ -35,8 +35,11 @@ declare module 'zhin.js' {
|
|
|
35
35
|
|
|
36
36
|
export type ChainSessionRow = Models['idiom_chain_sessions'];
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
|
|
39
|
+
export function defineHostTables(
|
|
40
|
+
db: { define: (name: string, definition: Record<string, unknown>) => void },
|
|
41
|
+
): void {
|
|
42
|
+
db.define('idiom_chain_sessions', {
|
|
40
43
|
id: { type: 'text', primary: true },
|
|
41
44
|
adapter: { type: 'text', nullable: false },
|
|
42
45
|
endpoint: { type: 'text', nullable: false },
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { createToken } from '@zhin.js/plugin-runtime';
|
|
2
|
+
import type { SessionService } from './session-service.js';
|
|
3
|
+
|
|
4
|
+
/** Owner-scoped service consumed by discovered commands and middleware. */
|
|
5
|
+
export const gameServicesToken = createToken<SessionService>('zhin.game.idiom-chain.services');
|
|
6
|
+
|
|
7
|
+
export function resolveGameServices(context: { use<T>(token: typeof gameServicesToken): T }): SessionService {
|
|
8
|
+
return context.use(gameServicesToken) as SessionService;
|
|
9
|
+
}
|
package/src/session-service.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Database,
|
|
2
|
-
import { channelKey, generateSessionId, boardMessageMatches } from '@zhin.js/game-
|
|
1
|
+
import type { Database, Message, Models, RelatedModel } from '@zhin.js/core';
|
|
2
|
+
import { channelKey, generateSessionId, boardMessageMatches } from '@zhin.js/game-kit';
|
|
3
3
|
import type { MatchMode } from './engine.js';
|
|
4
4
|
import type { ChainSessionRow } from './models.js';
|
|
5
5
|
|
|
@@ -110,6 +110,3 @@ export function createServices(db: ChainDatabase): SessionService {
|
|
|
110
110
|
return new SessionService(db);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
export function resolveGameDatabase(feature: DatabaseFeature): ChainDatabase {
|
|
114
|
-
return feature.db;
|
|
115
|
-
}
|
package/src/view.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { buildChoiceKeyboard } from '@zhin.js/game-
|
|
2
|
-
import type { SendContent } from 'zhin.js';
|
|
1
|
+
import { buildChoiceKeyboard } from '@zhin.js/game-kit';
|
|
2
|
+
import type { SendContent } from '@zhin.js/core';
|
|
3
3
|
import type { ChainSessionRow } from './models.js';
|
|
4
4
|
import { CHAIN_PREFIX, getGloss, idiomCount, modeLabel, promptLine } from './engine.js';
|
|
5
5
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chain-command.d.ts","sourceRoot":"","sources":["../src/chain-command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAK/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,eAAO,MAAM,UAAU,QAWX,CAAC;AAEb,wBAAsB,eAAe,CACnC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA+B7B"}
|
package/lib/commands.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { type Plugin } from 'zhin.js';
|
|
2
|
-
import type { SessionService } from './session-service.js';
|
|
3
|
-
export declare function registerCommands(plugin: Plugin, getServices: () => SessionService | null): void;
|
|
4
|
-
export declare function registerInteractive(plugin: Plugin, getServices: () => SessionService | null): void;
|
|
5
|
-
export declare function registerTextMiddleware(plugin: Plugin, getServices: () => SessionService | null): void;
|
|
6
|
-
//# sourceMappingURL=commands.d.ts.map
|
package/lib/commands.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiD,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAYrF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAsB3D,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,CAG/F;AAgBD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,CAUlG;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,CAkDrG"}
|
package/lib/commands.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { MessageCommand, getActionFromMessage } from 'zhin.js';
|
|
2
|
-
import { buildChoiceFallbackMap, channelKey, normalizeChainAction, parseChoicePayload, registerGameTextMiddleware, resolveGameChoice, resolveGameTextPayload, } from '@zhin.js/game-shared';
|
|
3
|
-
import { CHAIN_PREFIX, handleChoice, processIdiomText } from './game-flow.js';
|
|
4
|
-
import { runChainCommand } from './chain-command.js';
|
|
5
|
-
const VALID_CHOICES = ['hint', 'skip', 'quit', 'restart'];
|
|
6
|
-
function registerPattern(plugin, pattern, desc, getServices) {
|
|
7
|
-
plugin.addCommand(new MessageCommand(pattern)
|
|
8
|
-
.desc(desc)
|
|
9
|
-
.action(async (message, result) => {
|
|
10
|
-
const services = getServices();
|
|
11
|
-
if (!services)
|
|
12
|
-
return '成语接龙需要启用 database 配置。';
|
|
13
|
-
const raw = result.params.action ?? '';
|
|
14
|
-
return runChainCommand(plugin, services, message, normalizeChainAction(raw));
|
|
15
|
-
}));
|
|
16
|
-
}
|
|
17
|
-
export function registerCommands(plugin, getServices) {
|
|
18
|
-
registerPattern(plugin, '/chain [action:word]', '成语接龙(chain)', getServices);
|
|
19
|
-
registerPattern(plugin, '/接龙 [action:word]', '成语接龙(中文)', getServices);
|
|
20
|
-
}
|
|
21
|
-
async function resolveChoice(message, services) {
|
|
22
|
-
return resolveGameChoice({
|
|
23
|
-
message,
|
|
24
|
-
gamePrefix: CHAIN_PREFIX,
|
|
25
|
-
validChoiceIds: VALID_CHOICES,
|
|
26
|
-
getById: (id) => services.getById(id),
|
|
27
|
-
getActiveForUser: (ch, uid) => services.getActiveForUser(ch, uid),
|
|
28
|
-
getByBoardMessageId: (mid) => services.getActiveByBoardMessageId(mid),
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
export function registerInteractive(plugin, getServices) {
|
|
32
|
-
plugin.registerInteractiveHandler(`${CHAIN_PREFIX}:`, async (message) => {
|
|
33
|
-
const services = getServices();
|
|
34
|
-
if (!services)
|
|
35
|
-
return false;
|
|
36
|
-
const choice = await resolveChoice(message, services);
|
|
37
|
-
if (!choice)
|
|
38
|
-
return false;
|
|
39
|
-
const err = await handleChoice(plugin, services, message, choice.sessionId, choice.choiceId);
|
|
40
|
-
if (err)
|
|
41
|
-
await message.$reply?.(err);
|
|
42
|
-
return true;
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
export function registerTextMiddleware(plugin, getServices) {
|
|
46
|
-
registerGameTextMiddleware(plugin, async (message, next) => {
|
|
47
|
-
const services = getServices();
|
|
48
|
-
if (!services)
|
|
49
|
-
return next();
|
|
50
|
-
const action = getActionFromMessage(message);
|
|
51
|
-
if (action?.payload.startsWith(`${CHAIN_PREFIX}:`))
|
|
52
|
-
return next();
|
|
53
|
-
const raw = message.$raw?.trim() ?? '';
|
|
54
|
-
if (!raw)
|
|
55
|
-
return next();
|
|
56
|
-
const ch = channelKey(message);
|
|
57
|
-
const payloadFromText = resolveGameTextPayload(raw);
|
|
58
|
-
if (payloadFromText?.startsWith(`${CHAIN_PREFIX}:`)) {
|
|
59
|
-
const parsed = parseChoicePayload(payloadFromText, CHAIN_PREFIX);
|
|
60
|
-
if (parsed) {
|
|
61
|
-
const session = await services.getById(parsed.sessionId);
|
|
62
|
-
if (session?.channel_key === ch) {
|
|
63
|
-
const err = await handleChoice(plugin, services, message, parsed.sessionId, parsed.choiceId);
|
|
64
|
-
if (err)
|
|
65
|
-
await message.$reply?.(err);
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
const session = await services.getActiveForUser(ch, message.$sender.id);
|
|
71
|
-
if (!session)
|
|
72
|
-
return next();
|
|
73
|
-
if (session.status === 'active') {
|
|
74
|
-
const map = buildChoiceFallbackMap(CHAIN_PREFIX, session.id, [
|
|
75
|
-
{ id: 'hint', label: '提示' },
|
|
76
|
-
{ id: 'skip', label: '跳过' },
|
|
77
|
-
{ id: 'quit', label: '认输' },
|
|
78
|
-
]);
|
|
79
|
-
const payload = resolveGameTextPayload(raw, map);
|
|
80
|
-
const parsed = payload ? parseChoicePayload(payload, CHAIN_PREFIX) : null;
|
|
81
|
-
if (parsed?.sessionId === session.id) {
|
|
82
|
-
const err = await handleChoice(plugin, services, message, session.id, parsed.choiceId);
|
|
83
|
-
if (err)
|
|
84
|
-
await message.$reply?.(err);
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
if (/^[\u4e00-\u9fff]{2,8}$/.test(raw)) {
|
|
89
|
-
await processIdiomText(plugin, services, message, raw);
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
return next();
|
|
93
|
-
}, 'idiom-chain:text');
|
|
94
|
-
}
|
|
95
|
-
//# 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,YAAY,UAAU,CAAC;AAEpC,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,EACL,UAAU,EACV,cAAc,EACd,YAAY,EACZ,QAAQ,EACR,QAAQ,EACR,kBAAkB,EAClB,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,mBAAmB,EACnB,UAAU,GACX,MAAM,qBAAqB,CAAC"}
|
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;AACxD,OAAO,EACL,YAAY,EAUZ,KAAK,SAAS,EACf,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAOtE,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EACrB,OAAO,EAAE,eAAe,EACxB,UAAU,GAAE,MAAM,EAAO,GACxB,OAAO,CAAC,IAAI,CAAC,CAqBf;AAmCD,wBAAsB,SAAS,CAC7B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EACrB,SAAS,GAAE,SAAoB,GAC9B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA0B7B;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,GACpB,OAAO,CAAC,MAAM,CAAC,CAQjB;AAED,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EACrB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiDxB;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EACrB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA0ExB;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
|
package/lib/hub-register.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { CHAIN_HELP } from './chain-command.js';
|
|
2
|
-
import type { SessionService } from './session-service.js';
|
|
3
|
-
export declare function registerChainHub(getServices: () => SessionService | null): () => void;
|
|
4
|
-
export { CHAIN_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":"AAGA,OAAO,EAAmB,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,cAAc,GAAG,IAAI,GAAG,MAAM,IAAI,CAuBrF;AAED,OAAO,EAAE,UAAU,EAAE,CAAC"}
|
package/lib/hub-register.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { getPlugin } from 'zhin.js';
|
|
2
|
-
import { ensureGameHubService } from '@zhin.js/game-shared';
|
|
3
|
-
import { idiomCount } from './engine.js';
|
|
4
|
-
import { runChainCommand, CHAIN_HELP } from './chain-command.js';
|
|
5
|
-
export function registerChainHub(getServices) {
|
|
6
|
-
const plugin = getPlugin();
|
|
7
|
-
ensureGameHubService(plugin);
|
|
8
|
-
return plugin.registerGame({
|
|
9
|
-
id: 'chain',
|
|
10
|
-
title: '成语接龙',
|
|
11
|
-
icon: '📜',
|
|
12
|
-
description: `四字成语接龙(同音/同字),词库 ${idiomCount()} 条`,
|
|
13
|
-
commandPrefix: '/接龙',
|
|
14
|
-
quickStart: 'start_pinyin',
|
|
15
|
-
aliases: ['chain'],
|
|
16
|
-
menus: [
|
|
17
|
-
{ id: 'start_pinyin', label: '🎮 同音接龙', style: 'primary' },
|
|
18
|
-
{ id: 'start_char', label: '📝 同字接龙' },
|
|
19
|
-
{ id: 'continue', label: '🔄 继续' },
|
|
20
|
-
{ id: 'help', label: '📖 玩法说明' },
|
|
21
|
-
],
|
|
22
|
-
runAction: async (actionId, ctx) => {
|
|
23
|
-
const services = getServices();
|
|
24
|
-
if (!services)
|
|
25
|
-
return '成语接龙需要启用 database 配置。';
|
|
26
|
-
return runChainCommand(ctx.plugin, services, ctx.message, actionId);
|
|
27
|
-
},
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
export { CHAIN_HELP };
|
|
31
|
-
//# 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,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGjE,MAAM,UAAU,gBAAgB,CAAC,WAAwC;IACvE,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,OAAO,MAAM,CAAC,YAAY,CAAC;QACzB,EAAE,EAAE,OAAO;QACX,KAAK,EAAE,MAAM;QACb,IAAI,EAAE,IAAI;QACV,WAAW,EAAE,oBAAoB,UAAU,EAAE,IAAI;QACjD,aAAa,EAAE,KAAK;QACpB,UAAU,EAAE,cAAc;QAC1B,OAAO,EAAE,CAAC,OAAO,CAAC;QAClB,KAAK,EAAE;YACL,EAAE,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;YAC1D,EAAE,EAAE,EAAE,YAAY,EAAE,KAAK,EAAE,SAAS,EAAE;YACtC,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE;YAClC,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,uBAAuB,CAAC;YAC9C,OAAO,eAAe,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACtE,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,OAAO,EAAE,UAAU,EAAE,CAAC"}
|