@zhin.js/plugin-dice-duel 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.
Files changed (60) hide show
  1. package/commands/dice/[action:string=].ts +15 -0
  2. package/lib/dice-command.d.ts +4 -3
  3. package/lib/dice-command.js +5 -1
  4. package/lib/dice-command.js.map +1 -1
  5. package/lib/engine.d.ts +0 -1
  6. package/lib/engine.js +1 -1
  7. package/lib/engine.js.map +1 -1
  8. package/lib/game-flow.d.ts +6 -7
  9. package/lib/game-flow.js +12 -8
  10. package/lib/game-flow.js.map +1 -1
  11. package/lib/index.d.ts +8 -2
  12. package/lib/index.js +8 -25
  13. package/lib/index.js.map +1 -1
  14. package/lib/memory-db.d.ts +6 -0
  15. package/lib/memory-db.js +18 -0
  16. package/lib/memory-db.js.map +1 -0
  17. package/lib/models.d.ts +5 -4
  18. package/lib/models.js +2 -2
  19. package/lib/models.js.map +1 -1
  20. package/lib/runtime-store.d.ts +6 -0
  21. package/lib/runtime-store.js +7 -0
  22. package/lib/runtime-store.js.map +1 -0
  23. package/lib/session-service.d.ts +1 -3
  24. package/lib/session-service.js +1 -4
  25. package/lib/session-service.js.map +1 -1
  26. package/lib/view.d.ts +1 -2
  27. package/lib/view.js +1 -1
  28. package/lib/view.js.map +1 -1
  29. package/middlewares/dice-alias.ts +18 -0
  30. package/middlewares/dice-choice.ts +62 -0
  31. package/package.json +36 -10
  32. package/plugin.ts +63 -0
  33. package/schema.json +6 -0
  34. package/src/dice-command.ts +12 -3
  35. package/src/engine.ts +1 -1
  36. package/src/game-flow.ts +17 -14
  37. package/src/index.ts +9 -34
  38. package/src/memory-db.ts +22 -0
  39. package/src/models.ts +7 -4
  40. package/src/runtime-store.ts +9 -0
  41. package/src/session-service.ts +2 -5
  42. package/src/view.ts +2 -2
  43. package/lib/commands.d.ts +0 -6
  44. package/lib/commands.d.ts.map +0 -1
  45. package/lib/commands.js +0 -83
  46. package/lib/commands.js.map +0 -1
  47. package/lib/dice-command.d.ts.map +0 -1
  48. package/lib/engine.d.ts.map +0 -1
  49. package/lib/game-flow.d.ts.map +0 -1
  50. package/lib/hub-register.d.ts +0 -5
  51. package/lib/hub-register.d.ts.map +0 -1
  52. package/lib/hub-register.js +0 -29
  53. package/lib/hub-register.js.map +0 -1
  54. package/lib/index.d.ts.map +0 -1
  55. package/lib/models.d.ts.map +0 -1
  56. package/lib/session-service.d.ts.map +0 -1
  57. package/lib/view.d.ts.map +0 -1
  58. package/plugin.yml +0 -2
  59. package/src/commands.ts +0 -103
  60. package/src/hub-register.ts +0 -30
@@ -1,5 +1,5 @@
1
- import type { Message, Plugin } from 'zhin.js';
2
- import { channelKey } from '@zhin.js/game-shared';
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 type { SessionService } from './session-service.js';
5
5
 
@@ -12,7 +12,7 @@ export const DICE_HELP = [
12
12
  ].join('\n');
13
13
 
14
14
  export async function runDiceCommand(
15
- plugin: Plugin,
15
+ plugin: Plugin | null,
16
16
  services: SessionService,
17
17
  message: Message<any>,
18
18
  action: string,
@@ -43,3 +43,12 @@ export async function runDiceCommand(
43
43
 
44
44
  return `未知子命令:${action}\n\n${DICE_HELP}`;
45
45
  }
46
+
47
+ /** Plugin Runtime / smoke: text-only, no Adapter.editMessage. */
48
+ export async function runDiceCommandText(
49
+ services: SessionService,
50
+ message: Message<any>,
51
+ action: string,
52
+ ): Promise<string> {
53
+ return (await runDiceCommand(null, services, message, action)) ?? '';
54
+ }
package/src/engine.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { secureRandomIntInclusive } from '@zhin.js/game-shared';
1
+ import { secureRandomIntInclusive } from '@zhin.js/game-kit';
2
2
 
3
3
  export const DICE_PREFIX = 'dice';
4
4
  export const WIN_TARGET = 2; // best of 3 -> first to 2
package/src/game-flow.ts CHANGED
@@ -1,18 +1,20 @@
1
- import type { Adapter, Message, Plugin } from 'zhin.js';
2
- import { recordGameOutcome } from '@zhin.js/game-shared';
1
+ import type { Adapter, Message, Plugin } from '@zhin.js/core';
2
+ import { plainTextFromSendContent, recordGameOutcome } from '@zhin.js/game-kit';
3
3
  import type { DiceSessionRow } from './models.js';
4
4
  import { compareRolls, DICE_PREFIX, rollD6, WIN_TARGET } from './engine.js';
5
5
  import type { SessionService } from './session-service.js';
6
6
  import { buildDiceView } from './view.js';
7
7
 
8
8
  export async function sendOrEditView(
9
- plugin: Plugin,
9
+ plugin: Plugin | null,
10
10
  services: SessionService,
11
11
  message: Message<any>,
12
12
  session: DiceSessionRow,
13
13
  lastRound?: { player: number; bot: number; result: 0 | 1 | 2 },
14
- ): Promise<void> {
14
+ ): Promise<string | void> {
15
15
  const content = buildDiceView(session, lastRound, message.$channel.type);
16
+ if (!plugin) return plainTextFromSendContent(content);
17
+
16
18
  const adapter = plugin.root.inject(message.$adapter) as Adapter;
17
19
 
18
20
  if (session.board_message_id) {
@@ -35,7 +37,7 @@ export async function sendOrEditView(
35
37
  }
36
38
 
37
39
  export async function startGame(
38
- plugin: Plugin,
40
+ plugin: Plugin | null,
39
41
  services: SessionService,
40
42
  message: Message<any>,
41
43
  ): Promise<string | undefined> {
@@ -48,12 +50,12 @@ export async function startGame(
48
50
  return `本频道 ${active.player_name} 正在掷骰对决中。`;
49
51
  }
50
52
  const session = await services.createSession(message);
51
- await sendOrEditView(plugin, services, message, session);
52
- return undefined;
53
+ const text = await sendOrEditView(plugin, services, message, session);
54
+ return typeof text === 'string' ? text : undefined;
53
55
  }
54
56
 
55
57
  export async function continueGame(
56
- plugin: Plugin,
58
+ plugin: Plugin | null,
57
59
  services: SessionService,
58
60
  message: Message<any>,
59
61
  ): Promise<string> {
@@ -62,12 +64,13 @@ export async function continueGame(
62
64
  message.$sender.id,
63
65
  );
64
66
  if (!session) return '你没有进行中的骰子对决,发送「骰子 开始」。';
65
- await sendOrEditView(plugin, services, message, session);
67
+ const text = await sendOrEditView(plugin, services, message, session);
68
+ if (typeof text === 'string') return text;
66
69
  return '已刷新骰子界面。';
67
70
  }
68
71
 
69
72
  export async function handleChoice(
70
- plugin: Plugin,
73
+ plugin: Plugin | null,
71
74
  services: SessionService,
72
75
  message: Message<any>,
73
76
  sessionId: string,
@@ -83,8 +86,8 @@ export async function handleChoice(
83
86
 
84
87
  if (choiceId === 'restart') {
85
88
  await services.updateSession(session.id, { status: 'aborted' });
86
- await startGame(plugin, services, message);
87
- return null;
89
+ // text-only 模式(plugin===null)下 startGame 的唯一输出就是返回文本
90
+ return (await startGame(plugin, services, message)) ?? null;
88
91
  }
89
92
 
90
93
  if (choiceId !== 'roll') return '无效操作。';
@@ -114,8 +117,8 @@ export async function handleChoice(
114
117
  const updated = (await services.getById(session.id))!;
115
118
  if (status === 'won') void recordGameOutcome(message, 'dice', 'won', playerWins * 10);
116
119
  else if (status === 'lost') void recordGameOutcome(message, 'dice', 'lost');
117
- await sendOrEditView(plugin, services, message, updated, { player, bot, result });
118
- return null;
120
+ const text = await sendOrEditView(plugin, services, message, updated, { player, bot, result });
121
+ return typeof text === 'string' ? text : null;
119
122
  }
120
123
 
121
124
  export { DICE_PREFIX };
package/src/index.ts CHANGED
@@ -1,34 +1,9 @@
1
- import { formatCompact, usePlugin, type DatabaseFeature } from 'zhin.js';
2
- import { registerModels } from './models.js';
3
- import {
4
- createServices,
5
- resolveGameDatabase,
6
- type SessionService,
7
- } from './session-service.js';
8
- import { registerCommands, registerInteractive, registerTextFallback } from './commands.js';
9
- import { registerDiceHub } from './hub-register.js';
10
-
11
- const plugin = usePlugin();
12
- const { logger, useContext, addSchedule } = plugin;
13
-
14
- registerModels(plugin);
15
-
16
- let services: SessionService | null = null;
17
-
18
- useContext('database', (dbFeature: DatabaseFeature) => {
19
- services = createServices(resolveGameDatabase(dbFeature));
20
- logger.debug(formatCompact({ 模块: '骰子对决', 数据模型: '已就绪' }));
21
- });
22
-
23
- registerDiceHub(() => services);
24
- registerCommands(plugin, () => services);
25
- registerInteractive(plugin, () => services);
26
- registerTextFallback(plugin, () => services);
27
-
28
- addSchedule({ kind: 'solar', cron: '0 */15 * * * *' }, async () => {
29
- if (!services) return;
30
- const n = await services.abortStale(30 * 60 * 1000);
31
- if (n > 0) logger.debug(formatCompact({ 骰子对决: '清理超时局', count: n }));
32
- });
33
-
34
- logger.debug(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
+ /**
6
+ * 已由 plugin.ts 接线:commands/ 命令、middlewares/ 文本与选项中间件、
7
+ * 游戏大厅注册(registerRuntimeGame)、过期会话 cron(scheduleHostToken)、
8
+ * host DatabaseHost(databaseHostToken)。仍未接:interactive 按钮回调。
9
+ */
@@ -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 DiceDatabase, type SessionService } from './session-service.js';
5
+
6
+ const DICE_TABLES = ['dice_sessions'] as const;
7
+
8
+ /** In-memory dice_sessions for Plugin Runtime slice-2 (no DatabaseFeature). */
9
+ export function createInMemoryDiceDb(): DiceDatabase {
10
+ return createInMemoryGameDb(DICE_TABLES) as unknown as DiceDatabase;
11
+ }
12
+
13
+ export function mountDiceMemoryServices(): SessionService {
14
+ const services = createServices(createInMemoryDiceDb());
15
+ return services;
16
+ }
17
+
18
+ export function mountDiceHostServices(host: DatabaseHost): SessionService {
19
+ defineHostTables(host);
20
+ const services = createServices(createHostGameDb(host, DICE_TABLES) as unknown as DiceDatabase);
21
+ return services;
22
+ }
package/src/models.ts CHANGED
@@ -1,8 +1,8 @@
1
- import type { Models, Plugin } from 'zhin.js';
1
+ import type { Models } from '@zhin.js/core';
2
2
 
3
3
  export type DiceSessionStatus = 'active' | 'won' | 'lost' | 'aborted';
4
4
 
5
- declare module 'zhin.js' {
5
+ declare module '@zhin.js/core' {
6
6
  interface Models {
7
7
  dice_sessions: {
8
8
  id: string;
@@ -28,8 +28,11 @@ declare module 'zhin.js' {
28
28
 
29
29
  export type DiceSessionRow = Models['dice_sessions'];
30
30
 
31
- export function registerModels(plugin: Plugin): void {
32
- plugin.defineModel('dice_sessions', {
31
+
32
+ export function defineHostTables(
33
+ db: { define: (name: string, definition: Record<string, unknown>) => void },
34
+ ): void {
35
+ db.define('dice_sessions', {
33
36
  id: { type: 'text', primary: true },
34
37
  adapter: { type: 'text', nullable: false },
35
38
  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.dice-duel.services');
6
+
7
+ export function resolveGameServices(context: { use<T>(token: typeof gameServicesToken): T }): SessionService {
8
+ return context.use(gameServicesToken) as SessionService;
9
+ }
@@ -1,5 +1,5 @@
1
- import type { Database, DatabaseFeature, Message, Models, RelatedModel } from 'zhin.js';
2
- import { channelKey, generateSessionId, boardMessageMatches } from '@zhin.js/game-shared';
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 { DiceSessionRow } from './models.js';
4
4
 
5
5
  export type DiceDatabase = Database<unknown, Models, string>;
@@ -85,6 +85,3 @@ export function createServices(db: DiceDatabase): SessionService {
85
85
  return new SessionService(db);
86
86
  }
87
87
 
88
- export function resolveGameDatabase(feature: DatabaseFeature): DiceDatabase {
89
- return feature.db;
90
- }
package/src/view.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { buildChoiceKeyboard } from '@zhin.js/game-shared';
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 { DiceSessionRow } from './models.js';
4
4
  import { DICE_PREFIX, diceEmoji, WIN_TARGET } from './engine.js';
5
5
 
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 registerTextFallback(plugin: Plugin, getServices: () => SessionService | null): void;
6
- //# sourceMappingURL=commands.d.ts.map
@@ -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,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,CAqCnG"}
package/lib/commands.js DELETED
@@ -1,83 +0,0 @@
1
- import { MessageCommand, getActionFromMessage } from 'zhin.js';
2
- import { buildChoiceFallbackMap, channelKey, normalizeDiceAction, parseChoicePayload, registerGameTextMiddleware, resolveGameChoice, resolveGameTextPayload, } from '@zhin.js/game-shared';
3
- import { DICE_PREFIX, handleChoice } from './game-flow.js';
4
- import { runDiceCommand } from './dice-command.js';
5
- const VALID_CHOICES = ['roll', '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 runDiceCommand(plugin, services, message, normalizeDiceAction(raw));
15
- }));
16
- }
17
- export function registerCommands(plugin, getServices) {
18
- registerPattern(plugin, '/dice [action:word]', '骰子对决(dice)', getServices);
19
- registerPattern(plugin, '/骰子 [action:word]', '骰子对决(中文)', getServices);
20
- }
21
- async function resolveChoice(message, services) {
22
- return resolveGameChoice({
23
- message,
24
- gamePrefix: DICE_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(`${DICE_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 registerTextFallback(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(`${DICE_PREFIX}:`))
52
- return next();
53
- const raw = message.$raw?.trim() ?? '';
54
- const ch = channelKey(message);
55
- const payloadFromText = resolveGameTextPayload(raw);
56
- if (payloadFromText?.startsWith(`${DICE_PREFIX}:`)) {
57
- const parsed = parseChoicePayload(payloadFromText, DICE_PREFIX);
58
- if (parsed) {
59
- const session = await services.getById(parsed.sessionId);
60
- if (session?.channel_key === ch) {
61
- const err = await handleChoice(plugin, services, message, parsed.sessionId, parsed.choiceId);
62
- if (err)
63
- await message.$reply?.(err);
64
- return;
65
- }
66
- }
67
- }
68
- const session = await services.getActiveForUser(ch, message.$sender.id);
69
- if (!session || session.status !== 'active')
70
- return next();
71
- const map = buildChoiceFallbackMap(DICE_PREFIX, session.id, [
72
- { id: 'roll', label: '掷骰' },
73
- ]);
74
- const payload = resolveGameTextPayload(raw, map);
75
- const parsed = payload ? parseChoicePayload(payload, DICE_PREFIX) : null;
76
- if (!parsed || parsed.sessionId !== session.id)
77
- return next();
78
- const err = await handleChoice(plugin, services, message, session.id, 'roll');
79
- if (err)
80
- await message.$reply?.(err);
81
- }, 'dice:text');
82
- }
83
- //# sourceMappingURL=commands.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"commands.js","sourceRoot":"","sources":["../src/commands.ts"],"names":[],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"dice-command.d.ts","sourceRoot":"","sources":["../src/dice-command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAG/C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,eAAO,MAAM,SAAS,QAMV,CAAC;AAEb,wBAAsB,cAAc,CAClC,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,CA0B7B"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW,SAAS,CAAC;AAClC,eAAO,MAAM,UAAU,IAAI,CAAC;AAE5B,wBAAgB,MAAM,IAAI,MAAM,CAE/B;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAG3C;AAED,wBAAwB;AACxB,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAGnE"}
@@ -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,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAgB,WAAW,EAAsB,MAAM,aAAa,CAAC;AAC5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,EACrB,OAAO,EAAE,cAAc,EACvB,SAAS,CAAC,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;CAAE,GAC7D,OAAO,CAAC,IAAI,CAAC,CAqBf;AAED,wBAAsB,SAAS,CAC7B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,GACpB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAY7B;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,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,CA4CxB;AAED,OAAO,EAAE,WAAW,EAAE,CAAC"}
@@ -1,5 +0,0 @@
1
- import { DICE_HELP } from './dice-command.js';
2
- import type { SessionService } from './session-service.js';
3
- export declare function registerDiceHub(getServices: () => SessionService | null): () => void;
4
- export { DICE_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,EAAkB,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,cAAc,GAAG,IAAI,GAAG,MAAM,IAAI,CAsBpF;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -1,29 +0,0 @@
1
- import { getPlugin } from 'zhin.js';
2
- import { ensureGameHubService } from '@zhin.js/game-shared';
3
- import { runDiceCommand, DICE_HELP } from './dice-command.js';
4
- export function registerDiceHub(getServices) {
5
- const plugin = getPlugin();
6
- ensureGameHubService(plugin);
7
- return plugin.registerGame({
8
- id: 'dice',
9
- title: '骰子对决',
10
- icon: '🎲',
11
- description: '掷骰比大小,三局两胜',
12
- commandPrefix: '/骰子',
13
- quickStart: '开始',
14
- aliases: ['dice'],
15
- menus: [
16
- { id: 'start', label: '🎮 开始对局', style: 'primary' },
17
- { id: 'continue', label: '🔄 继续' },
18
- { id: 'help', label: '📖 玩法说明' },
19
- ],
20
- runAction: async (actionId, ctx) => {
21
- const services = getServices();
22
- if (!services)
23
- return '骰子对决需要启用 database 配置。';
24
- return runDiceCommand(ctx.plugin, services, ctx.message, actionId);
25
- },
26
- });
27
- }
28
- export { DICE_HELP };
29
- //# sourceMappingURL=hub-register.js.map
@@ -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,cAAc,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAG9D,MAAM,UAAU,eAAe,CAAC,WAAwC;IACtE,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,OAAO,MAAM,CAAC,YAAY,CAAC;QACzB,EAAE,EAAE,MAAM;QACV,KAAK,EAAE,MAAM;QACb,IAAI,EAAE,IAAI;QACV,WAAW,EAAE,YAAY;QACzB,aAAa,EAAE,KAAK;QACpB,UAAU,EAAE,IAAI;QAChB,OAAO,EAAE,CAAC,MAAM,CAAC;QACjB,KAAK,EAAE;YACL,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;YACnD,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,cAAc,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACrE,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
@@ -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,iBAAiB,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,SAAS,CAAC;AAEtE,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,MAAM;QACd,aAAa,EAAE;YACb,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,SAAS,EAAE,MAAM,CAAC;YAClB,WAAW,EAAE,MAAM,CAAC;YACpB,WAAW,EAAE,MAAM,CAAC;YACpB,QAAQ,EAAE,MAAM,CAAC;YACjB,KAAK,EAAE,MAAM,CAAC;YACd,gBAAgB,EAAE,MAAM,CAAC;YACzB,aAAa,EAAE,MAAM,CAAC;YACtB,MAAM,EAAE,iBAAiB,CAAC;YAC1B,gBAAgB,EAAE,MAAM,CAAC;YACzB,UAAU,EAAE,MAAM,CAAC;YACnB,UAAU,EAAE,MAAM,CAAC;SACpB,CAAC;KACH;CACF;AAED,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;AAErD,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAoBnD"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"session-service.d.ts","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,EAAgB,MAAM,SAAS,CAAC;AAExF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAQ7D,qBAAa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,EAAE;gBAAF,EAAE,EAAE,YAAY;IAEvC,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAKnE,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAMjF,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAInD,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAS5E,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC;IAyB7D,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxE,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAalD;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,YAAY,GAAG,cAAc,CAE/D;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,eAAe,GAAG,YAAY,CAE1E"}
package/lib/view.d.ts.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../src/view.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAGlD,wBAAgB,aAAa,CAC3B,OAAO,EAAE,cAAc,EACvB,SAAS,CAAC,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;CAAE,EAC9D,WAAW,CAAC,EAAE,MAAM,GACnB,WAAW,CA0Cb"}
package/plugin.yml DELETED
@@ -1,2 +0,0 @@
1
- name: "@zhin.js/plugin-dice-duel"
2
- description: "骰子对决"
package/src/commands.ts DELETED
@@ -1,103 +0,0 @@
1
- import { Message, MessageCommand, getActionFromMessage, type Plugin } from 'zhin.js';
2
- import {
3
- buildChoiceFallbackMap,
4
- channelKey,
5
- normalizeDiceAction,
6
- parseChoicePayload,
7
- registerGameTextMiddleware,
8
- resolveGameChoice,
9
- resolveGameTextPayload,
10
- } from '@zhin.js/game-shared';
11
- import { DICE_PREFIX, handleChoice } from './game-flow.js';
12
- import { runDiceCommand } from './dice-command.js';
13
- import type { SessionService } from './session-service.js';
14
-
15
- const VALID_CHOICES = ['roll', 'restart'] as const;
16
-
17
- function registerPattern(
18
- plugin: Plugin,
19
- pattern: string,
20
- desc: string,
21
- getServices: () => SessionService | null,
22
- ): void {
23
- plugin.addCommand(
24
- new MessageCommand(pattern)
25
- .desc(desc)
26
- .action(async (message, result) => {
27
- const services = getServices();
28
- if (!services) return '骰子对决需要启用 database 配置。';
29
- const raw = (result.params.action as string | undefined) ?? '';
30
- return runDiceCommand(plugin, services, message, normalizeDiceAction(raw));
31
- }),
32
- );
33
- }
34
-
35
- export function registerCommands(plugin: Plugin, getServices: () => SessionService | null): void {
36
- registerPattern(plugin, '/dice [action:word]', '骰子对决(dice)', getServices);
37
- registerPattern(plugin, '/骰子 [action:word]', '骰子对决(中文)', getServices);
38
- }
39
-
40
- async function resolveChoice(
41
- message: Message<any>,
42
- services: SessionService,
43
- ): Promise<{ sessionId: string; choiceId: string } | null> {
44
- return resolveGameChoice({
45
- message,
46
- gamePrefix: DICE_PREFIX,
47
- validChoiceIds: VALID_CHOICES,
48
- getById: (id) => services.getById(id),
49
- getActiveForUser: (ch, uid) => services.getActiveForUser(ch, uid),
50
- getByBoardMessageId: (mid) => services.getActiveByBoardMessageId(mid),
51
- });
52
- }
53
-
54
- export function registerInteractive(plugin: Plugin, getServices: () => SessionService | null): void {
55
- plugin.registerInteractiveHandler(`${DICE_PREFIX}:`, async (message) => {
56
- const services = getServices();
57
- if (!services) return false;
58
- const choice = await resolveChoice(message, services);
59
- if (!choice) return false;
60
- const err = await handleChoice(plugin, services, message, choice.sessionId, choice.choiceId);
61
- if (err) await message.$reply?.(err);
62
- return true;
63
- });
64
- }
65
-
66
- export function registerTextFallback(plugin: Plugin, getServices: () => SessionService | null): void {
67
- registerGameTextMiddleware(plugin, async (message, next) => {
68
- const services = getServices();
69
- if (!services) return next();
70
-
71
- const action = getActionFromMessage(message);
72
- if (action?.payload.startsWith(`${DICE_PREFIX}:`)) return next();
73
-
74
- const raw = message.$raw?.trim() ?? '';
75
- const ch = channelKey(message);
76
-
77
- const payloadFromText = resolveGameTextPayload(raw);
78
- if (payloadFromText?.startsWith(`${DICE_PREFIX}:`)) {
79
- const parsed = parseChoicePayload(payloadFromText, DICE_PREFIX);
80
- if (parsed) {
81
- const session = await services.getById(parsed.sessionId);
82
- if (session?.channel_key === ch) {
83
- const err = await handleChoice(plugin, services, message, parsed.sessionId, parsed.choiceId);
84
- if (err) await message.$reply?.(err);
85
- return;
86
- }
87
- }
88
- }
89
-
90
- const session = await services.getActiveForUser(ch, message.$sender.id);
91
- if (!session || session.status !== 'active') return next();
92
-
93
- const map = buildChoiceFallbackMap(DICE_PREFIX, session.id, [
94
- { id: 'roll', label: '掷骰' },
95
- ]);
96
- const payload = resolveGameTextPayload(raw, map);
97
- const parsed = payload ? parseChoicePayload(payload, DICE_PREFIX) : null;
98
- if (!parsed || parsed.sessionId !== session.id) return next();
99
-
100
- const err = await handleChoice(plugin, services, message, session.id, 'roll');
101
- if (err) await message.$reply?.(err);
102
- }, 'dice:text');
103
- }
@@ -1,30 +0,0 @@
1
- import { getPlugin } from 'zhin.js';
2
- import { ensureGameHubService } from '@zhin.js/game-shared';
3
- import { runDiceCommand, DICE_HELP } from './dice-command.js';
4
- import type { SessionService } from './session-service.js';
5
-
6
- export function registerDiceHub(getServices: () => SessionService | null): () => void {
7
- const plugin = getPlugin();
8
- ensureGameHubService(plugin);
9
- return plugin.registerGame({
10
- id: 'dice',
11
- title: '骰子对决',
12
- icon: '🎲',
13
- description: '掷骰比大小,三局两胜',
14
- commandPrefix: '/骰子',
15
- quickStart: '开始',
16
- aliases: ['dice'],
17
- menus: [
18
- { id: 'start', label: '🎮 开始对局', style: 'primary' },
19
- { id: 'continue', label: '🔄 继续' },
20
- { id: 'help', label: '📖 玩法说明' },
21
- ],
22
- runAction: async (actionId, ctx) => {
23
- const services = getServices();
24
- if (!services) return '骰子对决需要启用 database 配置。';
25
- return runDiceCommand(ctx.plugin, services, ctx.message, actionId);
26
- },
27
- });
28
- }
29
-
30
- export { DICE_HELP };