@zhin.js/plugin-dice-duel 1.0.0 → 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/README.md +31 -0
- package/commands/dice/[action:string=].ts +15 -0
- package/lib/dice-command.d.ts +4 -3
- package/lib/dice-command.js +5 -1
- package/lib/dice-command.js.map +1 -1
- package/lib/engine.d.ts +0 -1
- package/lib/engine.js +2 -1
- package/lib/engine.js.map +1 -1
- package/lib/game-flow.d.ts +6 -7
- package/lib/game-flow.js +18 -18
- package/lib/game-flow.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 +3 -9
- package/lib/session-service.js.map +1 -1
- package/lib/view.d.ts +2 -3
- package/lib/view.js +5 -3
- package/lib/view.js.map +1 -1
- package/middlewares/dice-alias.ts +18 -0
- package/middlewares/dice-choice.ts +62 -0
- package/package.json +45 -10
- package/plugin.ts +63 -0
- package/schema.json +6 -0
- package/src/dice-command.ts +12 -3
- package/src/engine.ts +3 -1
- package/src/game-flow.ts +21 -24
- package/src/index.ts +9 -36
- 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 +4 -9
- package/src/view.ts +6 -3
- package/lib/commands.d.ts +0 -6
- package/lib/commands.d.ts.map +0 -1
- package/lib/commands.js +0 -82
- package/lib/commands.js.map +0 -1
- package/lib/dice-command.d.ts.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 -26
- 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/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 -98
- package/src/hub-register.ts +0 -30
package/README.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# @zhin.js/plugin-dice-duel
|
|
2
|
+
|
|
3
|
+
骰子对决插件:双方掷骰比大小,三局两胜。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```yaml
|
|
8
|
+
plugins:
|
|
9
|
+
- "@zhin.js/plugin-dice-duel"
|
|
10
|
+
database:
|
|
11
|
+
dialect: sqlite
|
|
12
|
+
storage: ./data/zhin.db
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## 命令
|
|
16
|
+
|
|
17
|
+
| 命令 | 说明 |
|
|
18
|
+
|------|------|
|
|
19
|
+
| `/骰子` | 帮助与频道状态 |
|
|
20
|
+
| `/骰子 开始` | 开始对局 |
|
|
21
|
+
| `/骰子 继续` | 继续当前局 |
|
|
22
|
+
| `/dice` | 英文别名 |
|
|
23
|
+
|
|
24
|
+
也可通过 `/游戏` 大厅按钮进入。
|
|
25
|
+
|
|
26
|
+
## 开发
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pnpm --filter @zhin.js/plugin-dice-duel build
|
|
30
|
+
pnpm vitest run plugins/games/dice-duel/tests
|
|
31
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineCommand } from '@zhin.js/command';
|
|
2
|
+
import { messageFromCommandInput, normalizeDiceAction } from '@zhin.js/game-kit';
|
|
3
|
+
import { DICE_HELP, runDiceCommandText } from '../../src/dice-command.js';
|
|
4
|
+
import { resolveGameServices } from '../../src/runtime-store.js';
|
|
5
|
+
|
|
6
|
+
export default defineCommand({
|
|
7
|
+
description: 'Dice Duel',
|
|
8
|
+
async execute({ params, input, use, owner }) {
|
|
9
|
+
const action = normalizeDiceAction(String(params.action ?? ''));
|
|
10
|
+
if (!action || action === 'help') return DICE_HELP;
|
|
11
|
+
const services = resolveGameServices({ use, owner });
|
|
12
|
+
const message = messageFromCommandInput(input);
|
|
13
|
+
return runDiceCommandText(services, message, action);
|
|
14
|
+
},
|
|
15
|
+
});
|
package/lib/dice-command.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { Message, Plugin } from 'zhin.js';
|
|
1
|
+
import type { Message, Plugin } from '@zhin.js/core';
|
|
2
2
|
import type { SessionService } from './session-service.js';
|
|
3
3
|
export declare const DICE_HELP: string;
|
|
4
|
-
export declare function runDiceCommand(plugin: Plugin, services: SessionService, message: Message<any>, action: string): Promise<string | undefined>;
|
|
5
|
-
|
|
4
|
+
export declare function runDiceCommand(plugin: Plugin | null, services: SessionService, message: Message<any>, action: string): Promise<string | undefined>;
|
|
5
|
+
/** Plugin Runtime / smoke: text-only, no Adapter.editMessage. */
|
|
6
|
+
export declare function runDiceCommandText(services: SessionService, message: Message<any>, action: string): Promise<string>;
|
package/lib/dice-command.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { channelKey } from '@zhin.js/game-
|
|
1
|
+
import { channelKey } from '@zhin.js/game-kit';
|
|
2
2
|
import { continueGame, startGame } from './game-flow.js';
|
|
3
3
|
export const DICE_HELP = [
|
|
4
4
|
'🎲 骰子对决(三局两胜)',
|
|
@@ -34,4 +34,8 @@ export async function runDiceCommand(plugin, services, message, action) {
|
|
|
34
34
|
}
|
|
35
35
|
return `未知子命令:${action}\n\n${DICE_HELP}`;
|
|
36
36
|
}
|
|
37
|
+
/** Plugin Runtime / smoke: text-only, no Adapter.editMessage. */
|
|
38
|
+
export async function runDiceCommandText(services, message, action) {
|
|
39
|
+
return (await runDiceCommand(null, services, message, action)) ?? '';
|
|
40
|
+
}
|
|
37
41
|
//# sourceMappingURL=dice-command.js.map
|
package/lib/dice-command.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dice-command.js","sourceRoot":"","sources":["../src/dice-command.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"dice-command.js","sourceRoot":"","sources":["../src/dice-command.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGzD,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,eAAe;IACf,gBAAgB;IAChB,aAAa;IACb,cAAc;IACd,cAAc;CACf,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAqB,EACrB,QAAwB,EACxB,OAAqB,EACrB,MAAc;IAEd,MAAM,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;IAElC,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;QACrD,MAAM,KAAK,GAAG,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAC9B,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,WAAW,MAAM,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QACrF,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,IAAI,MAAM,KAAK,OAAO;QAAE,OAAO,SAAS,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACpE,IAAI,MAAM,KAAK,UAAU;QAAE,OAAO,YAAY,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IAE1E,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,gBAAgB,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACxD,IAAI,CAAC,GAAG;YAAE,OAAO,cAAc,CAAC;QAChC,MAAM,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QAC5D,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,OAAO,SAAS,MAAM,OAAO,SAAS,EAAE,CAAC;AAC3C,CAAC;AAED,iEAAiE;AACjE,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,QAAwB,EACxB,OAAqB,EACrB,MAAc;IAEd,OAAO,CAAC,MAAM,cAAc,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;AACvE,CAAC"}
|
package/lib/engine.d.ts
CHANGED
package/lib/engine.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { secureRandomIntInclusive } from '@zhin.js/game-kit';
|
|
1
2
|
export const DICE_PREFIX = 'dice';
|
|
2
3
|
export const WIN_TARGET = 2; // best of 3 -> first to 2
|
|
3
4
|
export function rollD6() {
|
|
4
|
-
return 1
|
|
5
|
+
return secureRandomIntInclusive(1, 6);
|
|
5
6
|
}
|
|
6
7
|
export function diceEmoji(n) {
|
|
7
8
|
const faces = ['⚀', '⚁', '⚂', '⚃', '⚄', '⚅'];
|
package/lib/engine.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC;AAClC,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,CAAC,0BAA0B;AAEvD,MAAM,UAAU,MAAM;IACpB,OAAO,
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAE7D,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC;AAClC,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,CAAC,0BAA0B;AAEvD,MAAM,UAAU,MAAM;IACpB,OAAO,wBAAwB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,CAAS;IACjC,MAAM,KAAK,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IAC7C,OAAO,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC;AACnC,CAAC;AAED,wBAAwB;AACxB,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,GAAW;IACtD,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,CAAC,CAAC;IAC7B,OAAO,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9B,CAAC"}
|
package/lib/game-flow.d.ts
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import type { Message, Plugin } from 'zhin.js';
|
|
1
|
+
import type { Message, Plugin } from '@zhin.js/core';
|
|
2
2
|
import type { DiceSessionRow } from './models.js';
|
|
3
3
|
import { DICE_PREFIX } from './engine.js';
|
|
4
4
|
import type { SessionService } from './session-service.js';
|
|
5
|
-
export declare function sendOrEditView(plugin: Plugin, services: SessionService, message: Message<any>, session: DiceSessionRow, lastRound?: {
|
|
5
|
+
export declare function sendOrEditView(plugin: Plugin | null, services: SessionService, message: Message<any>, session: DiceSessionRow, lastRound?: {
|
|
6
6
|
player: number;
|
|
7
7
|
bot: number;
|
|
8
8
|
result: 0 | 1 | 2;
|
|
9
|
-
}): Promise<void>;
|
|
10
|
-
export declare function startGame(plugin: Plugin, services: SessionService, message: Message<any>): Promise<string | undefined>;
|
|
11
|
-
export declare function continueGame(plugin: Plugin, services: SessionService, message: Message<any>): Promise<string>;
|
|
12
|
-
export declare function handleChoice(plugin: Plugin, services: SessionService, message: Message<any>, sessionId: string, choiceId: string): Promise<string | null>;
|
|
9
|
+
}): Promise<string | void>;
|
|
10
|
+
export declare function startGame(plugin: Plugin | null, services: SessionService, message: Message<any>): Promise<string | undefined>;
|
|
11
|
+
export declare function continueGame(plugin: Plugin | null, services: SessionService, message: Message<any>): Promise<string>;
|
|
12
|
+
export declare function handleChoice(plugin: Plugin | null, services: SessionService, message: Message<any>, sessionId: string, choiceId: string): Promise<string | null>;
|
|
13
13
|
export { DICE_PREFIX };
|
|
14
|
-
//# sourceMappingURL=game-flow.d.ts.map
|
package/lib/game-flow.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { plainTextFromSendContent, recordGameOutcome } from '@zhin.js/game-kit';
|
|
1
2
|
import { compareRolls, DICE_PREFIX, rollD6, WIN_TARGET } from './engine.js';
|
|
2
3
|
import { buildDiceView } from './view.js';
|
|
3
4
|
export async function sendOrEditView(plugin, services, message, session, lastRound) {
|
|
4
|
-
const content = buildDiceView(session, lastRound);
|
|
5
|
+
const content = buildDiceView(session, lastRound, message.$channel.type);
|
|
6
|
+
if (!plugin)
|
|
7
|
+
return plainTextFromSendContent(content);
|
|
5
8
|
const adapter = plugin.root.inject(message.$adapter);
|
|
6
9
|
if (session.board_message_id) {
|
|
7
10
|
const msgId = await adapter.editMessage({
|
|
@@ -31,14 +34,16 @@ export async function startGame(plugin, services, message) {
|
|
|
31
34
|
return `本频道 ${active.player_name} 正在掷骰对决中。`;
|
|
32
35
|
}
|
|
33
36
|
const session = await services.createSession(message);
|
|
34
|
-
await sendOrEditView(plugin, services, message, session);
|
|
35
|
-
return undefined;
|
|
37
|
+
const text = await sendOrEditView(plugin, services, message, session);
|
|
38
|
+
return typeof text === 'string' ? text : undefined;
|
|
36
39
|
}
|
|
37
40
|
export async function continueGame(plugin, services, message) {
|
|
38
41
|
const session = await services.getActiveForUser(`${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`, message.$sender.id);
|
|
39
42
|
if (!session)
|
|
40
43
|
return '你没有进行中的骰子对决,发送「骰子 开始」。';
|
|
41
|
-
await sendOrEditView(plugin, services, message, session);
|
|
44
|
+
const text = await sendOrEditView(plugin, services, message, session);
|
|
45
|
+
if (typeof text === 'string')
|
|
46
|
+
return text;
|
|
42
47
|
return '已刷新骰子界面。';
|
|
43
48
|
}
|
|
44
49
|
export async function handleChoice(plugin, services, message, sessionId, choiceId) {
|
|
@@ -51,18 +56,9 @@ export async function handleChoice(plugin, services, message, sessionId, choiceI
|
|
|
51
56
|
return '对局已结束,请点击再来一局。';
|
|
52
57
|
}
|
|
53
58
|
if (choiceId === 'restart') {
|
|
54
|
-
await services.updateSession(session.id, {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
round: 0,
|
|
58
|
-
last_player_roll: 0,
|
|
59
|
-
last_bot_roll: 0,
|
|
60
|
-
status: 'active',
|
|
61
|
-
board_message_id: '',
|
|
62
|
-
});
|
|
63
|
-
const updated = (await services.getById(session.id));
|
|
64
|
-
await sendOrEditView(plugin, services, message, updated);
|
|
65
|
-
return null;
|
|
59
|
+
await services.updateSession(session.id, { status: 'aborted' });
|
|
60
|
+
// text-only 模式(plugin===null)下 startGame 的唯一输出就是返回文本
|
|
61
|
+
return (await startGame(plugin, services, message)) ?? null;
|
|
66
62
|
}
|
|
67
63
|
if (choiceId !== 'roll')
|
|
68
64
|
return '无效操作。';
|
|
@@ -89,8 +85,12 @@ export async function handleChoice(plugin, services, message, sessionId, choiceI
|
|
|
89
85
|
status,
|
|
90
86
|
});
|
|
91
87
|
const updated = (await services.getById(session.id));
|
|
92
|
-
|
|
93
|
-
|
|
88
|
+
if (status === 'won')
|
|
89
|
+
void recordGameOutcome(message, 'dice', 'won', playerWins * 10);
|
|
90
|
+
else if (status === 'lost')
|
|
91
|
+
void recordGameOutcome(message, 'dice', 'lost');
|
|
92
|
+
const text = await sendOrEditView(plugin, services, message, updated, { player, bot, result });
|
|
93
|
+
return typeof text === 'string' ? text : null;
|
|
94
94
|
}
|
|
95
95
|
export { DICE_PREFIX };
|
|
96
96
|
//# sourceMappingURL=game-flow.js.map
|
package/lib/game-flow.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"game-flow.js","sourceRoot":"","sources":["../src/game-flow.ts"],"names":[],"mappings":"
|
|
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,2 +1,8 @@
|
|
|
1
|
-
export {};
|
|
2
|
-
|
|
1
|
+
export { DICE_HELP } from './dice-command.js';
|
|
2
|
+
export { gameServicesToken, resolveGameServices } from './runtime-store.js';
|
|
3
|
+
export { createInMemoryDiceDb, mountDiceMemoryServices } from './memory-db.js';
|
|
4
|
+
/**
|
|
5
|
+
* 已由 plugin.ts 接线:commands/ 命令、middlewares/ 文本与选项中间件、
|
|
6
|
+
* 游戏大厅注册(registerRuntimeGame)、过期会话 cron(scheduleHostToken)、
|
|
7
|
+
* host DatabaseHost(databaseHostToken)。仍未接:interactive 按钮回调。
|
|
8
|
+
*/
|
package/lib/index.js
CHANGED
|
@@ -1,26 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
let services = null;
|
|
10
|
-
useContext('database', (dbFeature) => {
|
|
11
|
-
services = createServices(resolveGameDatabase(dbFeature));
|
|
12
|
-
logger.info(formatCompact({ 模块: '骰子对决', 数据模型: '已就绪' }));
|
|
13
|
-
});
|
|
14
|
-
registerDiceHub(() => services);
|
|
15
|
-
registerCommands(plugin, () => services);
|
|
16
|
-
registerInteractive(plugin, () => services);
|
|
17
|
-
registerTextFallback(plugin, () => services);
|
|
18
|
-
addCron(new Cron('0 */15 * * * *', async () => {
|
|
19
|
-
if (!services)
|
|
20
|
-
return;
|
|
21
|
-
const n = await services.abortStale(30 * 60 * 1000);
|
|
22
|
-
if (n > 0)
|
|
23
|
-
logger.debug(formatCompact({ 骰子对决: '清理超时局', count: n }));
|
|
24
|
-
}));
|
|
25
|
-
logger.info(formatCompact({ 模块: '骰子对决', 状态: '已加载' }));
|
|
1
|
+
export { DICE_HELP } from './dice-command.js';
|
|
2
|
+
export { gameServicesToken, resolveGameServices } from './runtime-store.js';
|
|
3
|
+
export { createInMemoryDiceDb, mountDiceMemoryServices } from './memory-db.js';
|
|
4
|
+
/**
|
|
5
|
+
* 已由 plugin.ts 接线:commands/ 命令、middlewares/ 文本与选项中间件、
|
|
6
|
+
* 游戏大厅注册(registerRuntimeGame)、过期会话 cron(scheduleHostToken)、
|
|
7
|
+
* host DatabaseHost(databaseHostToken)。仍未接:interactive 按钮回调。
|
|
8
|
+
*/
|
|
26
9
|
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAE/E;;;;GAIG"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DatabaseHost } from '@zhin.js/plugin-runtime';
|
|
2
|
+
import { type DiceDatabase, type SessionService } from './session-service.js';
|
|
3
|
+
/** In-memory dice_sessions for Plugin Runtime slice-2 (no DatabaseFeature). */
|
|
4
|
+
export declare function createInMemoryDiceDb(): DiceDatabase;
|
|
5
|
+
export declare function mountDiceMemoryServices(): SessionService;
|
|
6
|
+
export declare function mountDiceHostServices(host: DatabaseHost): SessionService;
|
package/lib/memory-db.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createHostGameDb, createInMemoryGameDb } from '@zhin.js/game-kit';
|
|
2
|
+
import { defineHostTables } from './models.js';
|
|
3
|
+
import { createServices } from './session-service.js';
|
|
4
|
+
const DICE_TABLES = ['dice_sessions'];
|
|
5
|
+
/** In-memory dice_sessions for Plugin Runtime slice-2 (no DatabaseFeature). */
|
|
6
|
+
export function createInMemoryDiceDb() {
|
|
7
|
+
return createInMemoryGameDb(DICE_TABLES);
|
|
8
|
+
}
|
|
9
|
+
export function mountDiceMemoryServices() {
|
|
10
|
+
const services = createServices(createInMemoryDiceDb());
|
|
11
|
+
return services;
|
|
12
|
+
}
|
|
13
|
+
export function mountDiceHostServices(host) {
|
|
14
|
+
defineHostTables(host);
|
|
15
|
+
const services = createServices(createHostGameDb(host, DICE_TABLES));
|
|
16
|
+
return services;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=memory-db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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,WAAW,GAAG,CAAC,eAAe,CAAU,CAAC;AAE/C,+EAA+E;AAC/E,MAAM,UAAU,oBAAoB;IAClC,OAAO,oBAAoB,CAAC,WAAW,CAA4B,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,uBAAuB;IACrC,MAAM,QAAQ,GAAG,cAAc,CAAC,oBAAoB,EAAE,CAAC,CAAC;IACxD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAAkB;IACtD,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACvB,MAAM,QAAQ,GAAG,cAAc,CAAC,gBAAgB,CAAC,IAAI,EAAE,WAAW,CAA4B,CAAC,CAAC;IAChG,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/lib/models.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { Models
|
|
1
|
+
import type { Models } from '@zhin.js/core';
|
|
2
2
|
export type DiceSessionStatus = 'active' | 'won' | 'lost' | 'aborted';
|
|
3
|
-
declare module 'zhin.js' {
|
|
3
|
+
declare module '@zhin.js/core' {
|
|
4
4
|
interface Models {
|
|
5
5
|
dice_sessions: {
|
|
6
6
|
id: string;
|
|
@@ -24,5 +24,6 @@ declare module 'zhin.js' {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
export type DiceSessionRow = Models['dice_sessions'];
|
|
27
|
-
export declare function
|
|
28
|
-
|
|
27
|
+
export declare function defineHostTables(db: {
|
|
28
|
+
define: (name: string, definition: Record<string, unknown>) => void;
|
|
29
|
+
}): void;
|
package/lib/models.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export function
|
|
2
|
-
|
|
1
|
+
export function defineHostTables(db) {
|
|
2
|
+
db.define('dice_sessions', {
|
|
3
3
|
id: { type: 'text', primary: true },
|
|
4
4
|
adapter: { type: 'text', nullable: false },
|
|
5
5
|
endpoint: { type: 'text', nullable: false },
|
package/lib/models.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AA+BA,MAAM,UAAU,gBAAgB,CAC9B,EAA2E;IAE3E,EAAE,CAAC,MAAM,CAAC,eAAe,EAAE;QACzB,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QACnC,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC1C,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC3C,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC/C,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC7C,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC9C,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC5C,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QAC1C,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACzC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACtC,gBAAgB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACjD,aAAa,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC9C,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE;QAC3C,gBAAgB,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QAC/C,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC3C,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;KAC5C,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SessionService } from './session-service.js';
|
|
2
|
+
/** Owner-scoped service consumed by discovered commands and middleware. */
|
|
3
|
+
export declare const gameServicesToken: import("@zhin.js/plugin-runtime").Token<SessionService>;
|
|
4
|
+
export declare function resolveGameServices(context: {
|
|
5
|
+
use<T>(token: typeof gameServicesToken): T;
|
|
6
|
+
}): SessionService;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createToken } from '@zhin.js/plugin-runtime';
|
|
2
|
+
/** Owner-scoped service consumed by discovered commands and middleware. */
|
|
3
|
+
export const gameServicesToken = createToken('zhin.game.dice-duel.services');
|
|
4
|
+
export function resolveGameServices(context) {
|
|
5
|
+
return context.use(gameServicesToken);
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=runtime-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-store.js","sourceRoot":"","sources":["../src/runtime-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAGtD,2EAA2E;AAC3E,MAAM,CAAC,MAAM,iBAAiB,GAAG,WAAW,CAAiB,8BAA8B,CAAC,CAAC;AAE7F,MAAM,UAAU,mBAAmB,CAAC,OAAuD;IACzF,OAAO,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAmB,CAAC;AAC1D,CAAC"}
|
package/lib/session-service.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Database,
|
|
1
|
+
import type { Database, Message, Models } from '@zhin.js/core';
|
|
2
2
|
import type { DiceSessionRow } from './models.js';
|
|
3
3
|
export type DiceDatabase = Database<unknown, Models, string>;
|
|
4
4
|
export declare class SessionService {
|
|
@@ -13,5 +13,3 @@ export declare class SessionService {
|
|
|
13
13
|
abortStale(idleMs: number): Promise<number>;
|
|
14
14
|
}
|
|
15
15
|
export declare function createServices(db: DiceDatabase): SessionService;
|
|
16
|
-
export declare function resolveGameDatabase(feature: DatabaseFeature): DiceDatabase;
|
|
17
|
-
//# sourceMappingURL=session-service.d.ts.map
|
package/lib/session-service.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { channelKey, generateSessionId } from '@zhin.js/game-
|
|
1
|
+
import { channelKey, generateSessionId, boardMessageMatches } from '@zhin.js/game-kit';
|
|
2
2
|
function getModel(db) {
|
|
3
3
|
const model = db.models.get('dice_sessions');
|
|
4
4
|
if (!model)
|
|
@@ -26,12 +26,9 @@ export class SessionService {
|
|
|
26
26
|
async getActiveByBoardMessageId(messageId) {
|
|
27
27
|
if (!messageId)
|
|
28
28
|
return null;
|
|
29
|
-
const rows = await getModel(this.db).findAll({
|
|
29
|
+
const rows = await getModel(this.db).findAll({});
|
|
30
30
|
for (const row of rows) {
|
|
31
|
-
|
|
32
|
-
if (!stored)
|
|
33
|
-
continue;
|
|
34
|
-
if (stored === messageId || stored.endsWith(`:${messageId}`))
|
|
31
|
+
if (boardMessageMatches(row.board_message_id ?? '', messageId))
|
|
35
32
|
return row;
|
|
36
33
|
}
|
|
37
34
|
return null;
|
|
@@ -80,7 +77,4 @@ export class SessionService {
|
|
|
80
77
|
export function createServices(db) {
|
|
81
78
|
return new SessionService(db);
|
|
82
79
|
}
|
|
83
|
-
export function resolveGameDatabase(feature) {
|
|
84
|
-
return feature.db;
|
|
85
|
-
}
|
|
86
80
|
//# sourceMappingURL=session-service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-service.js","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"session-service.js","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"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"}
|
package/lib/view.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import type { SendContent } from 'zhin.js';
|
|
1
|
+
import type { SendContent } from '@zhin.js/core';
|
|
2
2
|
import type { DiceSessionRow } from './models.js';
|
|
3
3
|
export declare function buildDiceView(session: DiceSessionRow, lastRound?: {
|
|
4
4
|
player: number;
|
|
5
5
|
bot: number;
|
|
6
6
|
result: 0 | 1 | 2;
|
|
7
|
-
}): SendContent;
|
|
8
|
-
//# sourceMappingURL=view.d.ts.map
|
|
7
|
+
}, channelType?: string): SendContent;
|
package/lib/view.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { buildChoiceKeyboard } from '@zhin.js/game-
|
|
1
|
+
import { buildChoiceKeyboard } from '@zhin.js/game-kit';
|
|
2
2
|
import { DICE_PREFIX, diceEmoji } from './engine.js';
|
|
3
|
-
export function buildDiceView(session, lastRound) {
|
|
3
|
+
export function buildDiceView(session, lastRound, channelType) {
|
|
4
4
|
const terminal = session.status !== 'active';
|
|
5
5
|
const lines = [
|
|
6
6
|
'🎲 **骰子对决**',
|
|
@@ -27,7 +27,7 @@ export function buildDiceView(session, lastRound) {
|
|
|
27
27
|
lines.push('', lastRound ? '点击继续掷骰:' : '点击掷骰开始!');
|
|
28
28
|
}
|
|
29
29
|
const choices = terminal
|
|
30
|
-
? [{ id: 'restart', label: '🔄 再来一局', style: 'primary' }]
|
|
30
|
+
? [{ id: 'restart', label: '🔄 再来一局', style: 'primary', keepEnabledWhenTerminal: true }]
|
|
31
31
|
: [{ id: 'roll', label: '🎲 掷骰', style: 'primary' }];
|
|
32
32
|
return buildChoiceKeyboard({
|
|
33
33
|
gamePrefix: DICE_PREFIX,
|
|
@@ -36,6 +36,8 @@ export function buildDiceView(session, lastRound) {
|
|
|
36
36
|
choices,
|
|
37
37
|
terminal,
|
|
38
38
|
fallbackHint: '回复 1 掷骰',
|
|
39
|
+
interactionProfile: terminal ? 'terminal' : 'gameplay',
|
|
40
|
+
channelType,
|
|
39
41
|
});
|
|
40
42
|
}
|
|
41
43
|
//# sourceMappingURL=view.js.map
|
package/lib/view.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view.js","sourceRoot":"","sources":["../src/view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"view.js","sourceRoot":"","sources":["../src/view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAGxD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAc,MAAM,aAAa,CAAC;AAEjE,MAAM,UAAU,aAAa,CAC3B,OAAuB,EACvB,SAA8D,EAC9D,WAAoB;IAEpB,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC;IAC7C,MAAM,KAAK,GAAG;QACZ,aAAa;QACb,EAAE;QACF,YAAY,OAAO,CAAC,WAAW,UAAU,OAAO,CAAC,QAAQ,cAAc;KACxE,CAAC;IAEF,IAAI,SAAS,EAAE,CAAC;QACd,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,SAAS,CAAC,MAAM,cAAc,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,GAAG,GAAG,CAAC,CAAC;QAC3H,KAAK,CAAC,IAAI,CACR,SAAS,CAAC,MAAM,KAAK,CAAC;YACpB,CAAC,CAAC,WAAW;YACb,CAAC,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;gBACtB,CAAC,CAAC,UAAU;gBACZ,CAAC,CAAC,YAAY,CACnB,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;aACrD,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACpE,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ;QACtB,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,SAAkB,EAAE,uBAAuB,EAAE,IAAI,EAAE,CAAC;QACjG,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,SAAkB,EAAE,CAAC,CAAC;IAEhE,OAAO,mBAAmB,CAAC;QACzB,UAAU,EAAE,WAAW;QACvB,SAAS,EAAE,OAAO,CAAC,EAAE;QACrB,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;QAC3B,OAAO;QACP,QAAQ;QACR,YAAY,EAAE,SAAS;QACvB,kBAAkB,EAAE,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU;QACtD,WAAW;KACZ,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineGameCommandAliasMiddleware,
|
|
3
|
+
messageFromCommandInput,
|
|
4
|
+
normalizeDiceAction,
|
|
5
|
+
} from '@zhin.js/game-kit';
|
|
6
|
+
import { DICE_HELP, runDiceCommandText } from '../src/dice-command.js';
|
|
7
|
+
import { resolveGameServices } from '../src/runtime-store.js';
|
|
8
|
+
|
|
9
|
+
export default defineGameCommandAliasMiddleware({
|
|
10
|
+
aliases: ['骰子', 'dice'],
|
|
11
|
+
async run(action, input, context) {
|
|
12
|
+
const normalized = normalizeDiceAction(String(action ?? ''));
|
|
13
|
+
if (!normalized || normalized === 'help') return DICE_HELP;
|
|
14
|
+
const services = resolveGameServices(context);
|
|
15
|
+
const message = messageFromCommandInput(input);
|
|
16
|
+
return runDiceCommandText(services, message, normalized);
|
|
17
|
+
},
|
|
18
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { defineMiddleware } from '@zhin.js/middleware';
|
|
2
|
+
import type { Message } from '@zhin.js/core/runtime';
|
|
3
|
+
import {
|
|
4
|
+
buildChoiceFallbackMap,
|
|
5
|
+
channelKey,
|
|
6
|
+
messageFromCommandInput,
|
|
7
|
+
parseChoicePayload,
|
|
8
|
+
resolveGameTextPayload,
|
|
9
|
+
} from '@zhin.js/game-kit';
|
|
10
|
+
import { resolveGameServices } from '../src/runtime-store.js';
|
|
11
|
+
import { DICE_PREFIX, handleChoice } from '../src/game-flow.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 文本入口:按钮 payload(`dice:session:roll|restart`)与数字 fallback
|
|
15
|
+
* (『回复 1 掷骰』,对应 view 的 fallbackHint)。
|
|
16
|
+
*/
|
|
17
|
+
export default defineMiddleware<Message>({
|
|
18
|
+
target: 'inbound',
|
|
19
|
+
async handle(context, next) {
|
|
20
|
+
const raw = context.input.content?.trim() ?? '';
|
|
21
|
+
if (!raw) {
|
|
22
|
+
await next();
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const services = resolveGameServices(context);
|
|
26
|
+
const message = messageFromCommandInput(context.input);
|
|
27
|
+
const ch = channelKey(message);
|
|
28
|
+
|
|
29
|
+
// 直接 payload(QQ 指令预填 / Sandbox action→text)
|
|
30
|
+
const payloadFromText = resolveGameTextPayload(raw);
|
|
31
|
+
if (payloadFromText?.startsWith(`${DICE_PREFIX}:`)) {
|
|
32
|
+
const parsed = parseChoicePayload(payloadFromText, DICE_PREFIX);
|
|
33
|
+
if (parsed) {
|
|
34
|
+
const session = await services.getById(parsed.sessionId);
|
|
35
|
+
if (session?.channel_key === ch) {
|
|
36
|
+
const reply = await handleChoice(null, services, message, parsed.sessionId, parsed.choiceId);
|
|
37
|
+
if (reply) await context.input.$reply(reply);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
await next();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const session = await services.getActiveForUser(ch, message.$sender.id);
|
|
46
|
+
if (!session || session.status !== 'active') {
|
|
47
|
+
await next();
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const map = buildChoiceFallbackMap(DICE_PREFIX, session.id, [{ id: 'roll', label: '掷骰' }]);
|
|
52
|
+
const payload = resolveGameTextPayload(raw, map);
|
|
53
|
+
const parsed = payload ? parseChoicePayload(payload, DICE_PREFIX) : null;
|
|
54
|
+
if (!parsed || parsed.sessionId !== session.id) {
|
|
55
|
+
await next();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const reply = await handleChoice(null, services, message, session.id, 'roll');
|
|
60
|
+
if (reply) await context.input.$reply(reply);
|
|
61
|
+
},
|
|
62
|
+
});
|