@zhin.js/plugin-idiom-chain 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commands/chain/[action:string=].js +16 -0
- package/lib/chain-command.d.ts +2 -2
- package/lib/chain-command.js +1 -1
- package/lib/chain-command.js.map +1 -1
- package/lib/game-flow.d.ts +6 -6
- package/lib/game-flow.js +3 -9
- package/lib/game-flow.js.map +1 -1
- package/lib/index.d.ts +0 -1
- package/lib/index.js +0 -1
- package/lib/index.js.map +1 -1
- package/lib/models.d.ts +0 -1
- package/lib/models.js +0 -1
- package/lib/models.js.map +1 -1
- package/lib/session-service.d.ts +2 -9
- package/lib/session-service.js +8 -52
- package/lib/session-service.js.map +1 -1
- package/middlewares/chain-alias.js +18 -0
- package/middlewares/chain-text.js +66 -0
- package/package.json +7 -7
- package/plugin.js +37 -0
- package/src/chain-command.ts +6 -2
- package/src/game-flow.ts +9 -13
- package/src/index.ts +0 -1
- package/src/models.ts +0 -2
- package/src/session-service.ts +16 -55
- package/lib/memory-db.d.ts +0 -6
- package/lib/memory-db.js +0 -18
- package/lib/memory-db.js.map +0 -1
- package/plugin.ts +0 -64
- package/src/memory-db.ts +0 -22
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { defineCommand } from '@zhin.js/command';
|
|
3
|
+
import { messageFromCommandInput, normalizeChainAction } from '@zhin.js/game-kit';
|
|
4
|
+
import { CHAIN_HELP, runChainCommand } from "../../lib/chain-command.js";
|
|
5
|
+
import { resolveGameServices } from "../../lib/runtime-store.js";
|
|
6
|
+
export default defineCommand({
|
|
7
|
+
description: 'Idiom Chain',
|
|
8
|
+
async execute({ params, input, use, owner }) {
|
|
9
|
+
const action = normalizeChainAction(String(params.action ?? ''));
|
|
10
|
+
if (!action || action === 'help')
|
|
11
|
+
return CHAIN_HELP;
|
|
12
|
+
const services = resolveGameServices({ use, owner });
|
|
13
|
+
const message = messageFromCommandInput(input);
|
|
14
|
+
return runChainCommand(services, message, action);
|
|
15
|
+
},
|
|
16
|
+
});
|
package/lib/chain-command.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type GameMessageLike } from '@zhin.js/game-kit';
|
|
1
|
+
import { type GameMessageLike, type GameReply } from '@zhin.js/game-kit';
|
|
2
2
|
import type { SessionService } from './session-service.js';
|
|
3
3
|
export declare const CHAIN_HELP: string;
|
|
4
|
-
export declare function runChainCommand(services: SessionService, message: GameMessageLike, action: string): Promise<
|
|
4
|
+
export declare function runChainCommand(services: SessionService, message: GameMessageLike, action: string): Promise<GameReply>;
|
package/lib/chain-command.js
CHANGED
package/lib/chain-command.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chain-command.js","sourceRoot":"","sources":["../src/chain-command.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"chain-command.js","sourceRoot":"","sources":["../src/chain-command.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,GAGX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAkB,MAAM,aAAa,CAAC;AAIhF,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,sBAAsB;IACtB,QAAQ,UAAU,EAAE,eAAe;IACnC,iBAAiB;IACjB,8BAA8B;IAC9B,gBAAgB;IAChB,cAAc;IACd,cAAc;IACd,EAAE;IACF,cAAc;IACd,2BAA2B;CAC5B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAwB,EACxB,OAAwB,EACxB,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,UAAU,EAAE,EAAE,CAAC,CAAC;QAC/B,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,IAAI,GAAc,MAAM,CAAC,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;YACzE,KAAK,CAAC,IAAI,CACR,OAAO,MAAM,CAAC,WAAW,MAAM,SAAS,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,SAAS,SAAS,MAAM,CAAC,MAAM,EAAE,CACvH,CAAC;YACF,IAAI,MAAM,CAAC,UAAU;gBAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC;QACzE,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,cAAc;QAAE,OAAO,CAAC,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3F,IAAI,MAAM,KAAK,YAAY;QAAE,OAAO,CAAC,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IACvF,IAAI,MAAM,KAAK,UAAU;QAAE,OAAO,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAElE,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,YAAY,CAAC;QAC9B,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,UAAU,EAAE,CAAC;AAC5C,CAAC"}
|
package/lib/game-flow.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { GameMessageLike, GameReply } from '@zhin.js/game-kit';
|
|
2
2
|
import { CHAIN_PREFIX, type MatchMode } from './engine.js';
|
|
3
3
|
import type { ChainSessionRow } from './models.js';
|
|
4
4
|
import { type SessionService } from './session-service.js';
|
|
5
|
-
export declare function sendOrEditView(services: SessionService, message: GameMessageLike, session: ChainSessionRow, eventLines?: string[]): Promise<
|
|
6
|
-
export declare function startGame(services: SessionService, message: GameMessageLike, matchMode?: MatchMode): Promise<
|
|
7
|
-
export declare function continueGame(services: SessionService, message: GameMessageLike): Promise<
|
|
8
|
-
export declare function processIdiomText(services: SessionService, message: GameMessageLike, raw: string): Promise<
|
|
9
|
-
export declare function handleChoice(services: SessionService, message: GameMessageLike, sessionId: string, choiceId: string): Promise<
|
|
5
|
+
export declare function sendOrEditView(services: SessionService, message: GameMessageLike, session: ChainSessionRow, eventLines?: string[]): Promise<GameReply>;
|
|
6
|
+
export declare function startGame(services: SessionService, message: GameMessageLike, matchMode?: MatchMode): Promise<GameReply | undefined>;
|
|
7
|
+
export declare function continueGame(services: SessionService, message: GameMessageLike): Promise<GameReply>;
|
|
8
|
+
export declare function processIdiomText(services: SessionService, message: GameMessageLike, raw: string): Promise<GameReply | null>;
|
|
9
|
+
export declare function handleChoice(services: SessionService, message: GameMessageLike, sessionId: string, choiceId: string): Promise<GameReply | null>;
|
|
10
10
|
export { CHAIN_PREFIX };
|
package/lib/game-flow.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { plainTextFromSendContent } from '@zhin.js/game-kit';
|
|
2
1
|
import { CHAIN_PREFIX, getGloss, lastChar, modeLabel, normalizeInput, pickBotIdiom, pickHintIdiom, pickStarterIdiom, promptLine, validatePlayerIdiom, } from './engine.js';
|
|
3
2
|
import { parseUsed } from './session-service.js';
|
|
4
3
|
import { buildChainView, MAX_WRONG } from './view.js';
|
|
@@ -7,7 +6,7 @@ function sessionMode(session) {
|
|
|
7
6
|
}
|
|
8
7
|
export async function sendOrEditView(services, message, session, eventLines = []) {
|
|
9
8
|
const content = buildChainView(session, eventLines, message.$channel.type);
|
|
10
|
-
return
|
|
9
|
+
return content;
|
|
11
10
|
}
|
|
12
11
|
async function botTurn(services, session, used) {
|
|
13
12
|
const mode = sessionMode(session);
|
|
@@ -55,20 +54,16 @@ export async function startGame(services, message, matchMode = 'pinyin') {
|
|
|
55
54
|
matchMode,
|
|
56
55
|
});
|
|
57
56
|
const gloss = starter.gloss ?? getGloss(starter.text);
|
|
58
|
-
|
|
57
|
+
return sendOrEditView(services, message, session, [
|
|
59
58
|
`🎬 ${modeLabel(matchMode)}开局!我先出:**${starter.text}**${gloss ? `(${gloss})` : ''}`,
|
|
60
59
|
promptLine(starter.text, matchMode),
|
|
61
60
|
]);
|
|
62
|
-
return typeof text === 'string' ? text : undefined;
|
|
63
61
|
}
|
|
64
62
|
export async function continueGame(services, message) {
|
|
65
63
|
const session = await services.getActiveForUser(`${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`, message.$sender.id);
|
|
66
64
|
if (!session)
|
|
67
65
|
return '你没有进行中的接龙,发送「接龙 开始」。';
|
|
68
|
-
|
|
69
|
-
if (typeof text === 'string')
|
|
70
|
-
return text;
|
|
71
|
-
return '已刷新接龙界面。';
|
|
66
|
+
return sendOrEditView(services, message, session);
|
|
72
67
|
}
|
|
73
68
|
export async function processIdiomText(services, message, raw) {
|
|
74
69
|
const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
|
|
@@ -142,7 +137,6 @@ export async function handleChoice(services, message, sessionId, choiceId) {
|
|
|
142
137
|
wrong_count: 0,
|
|
143
138
|
turn: 'player',
|
|
144
139
|
status: 'active',
|
|
145
|
-
board_message_id: '',
|
|
146
140
|
});
|
|
147
141
|
const updated = (await services.getById(session.id));
|
|
148
142
|
const gloss = starter.gloss ?? getGloss(starter.text);
|
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,6 +1,5 @@
|
|
|
1
1
|
export { CHAIN_HELP } from './chain-command.js';
|
|
2
2
|
export { gameServicesToken, resolveGameServices } from './runtime-store.js';
|
|
3
|
-
export { createInMemoryChainDb, mountChainMemoryServices } from './memory-db.js';
|
|
4
3
|
/**
|
|
5
4
|
* 已由 plugin.ts 接线:commands/ 命令、middlewares/ 文本与选项中间件、
|
|
6
5
|
* 游戏大厅注册(registerRuntimeGame)、过期会话 cron(scheduleHostToken)、
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export { CHAIN_HELP } from './chain-command.js';
|
|
2
2
|
export { gameServicesToken, resolveGameServices } from './runtime-store.js';
|
|
3
|
-
export { createInMemoryChainDb, mountChainMemoryServices } from './memory-db.js';
|
|
4
3
|
/**
|
|
5
4
|
* 已由 plugin.ts 接线:commands/ 命令、middlewares/ 文本与选项中间件、
|
|
6
5
|
* 游戏大厅注册(registerRuntimeGame)、过期会话 cron(scheduleHostToken)、
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE5E;;;;GAIG"}
|
package/lib/models.d.ts
CHANGED
package/lib/models.js
CHANGED
|
@@ -20,7 +20,6 @@ export function defineHostTables(db) {
|
|
|
20
20
|
hints_used: { type: 'integer', default: 0 },
|
|
21
21
|
turn: { type: 'text', default: 'player' },
|
|
22
22
|
status: { type: 'text', default: 'active' },
|
|
23
|
-
board_message_id: { type: 'text', default: '' },
|
|
24
23
|
updated_at: { type: 'integer', default: 0 },
|
|
25
24
|
created_at: { type: 'integer', default: 0 },
|
|
26
25
|
});
|
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":"AAqCA,MAAM,UAAU,gBAAgB,CAC9B,EAA2E;IAE3E,EAAE,CAAC,MAAM,CAAC,sBAAsB,EAAE;QAChC,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,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QACzC,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QACxC,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE;QAC/C,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QAC5C,YAAY,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC7C,SAAS,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC1C,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACvC,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,UAAU,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC3C,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE;QACzC,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE;QAC3C,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"}
|
package/lib/session-service.d.ts
CHANGED
|
@@ -1,24 +1,17 @@
|
|
|
1
1
|
import type { Database, Models } from '@zhin.js/core';
|
|
2
|
-
import { type GameMessageLike } from '@zhin.js/game-kit';
|
|
2
|
+
import { BaseSessionService, type GameMessageLike } from '@zhin.js/game-kit';
|
|
3
3
|
import type { MatchMode } from './engine.js';
|
|
4
4
|
import type { ChainSessionRow } from './models.js';
|
|
5
5
|
export type ChainDatabase = Database<unknown, Models, string>;
|
|
6
6
|
export declare function parseUsed(value: string | string[] | unknown): Set<string>;
|
|
7
7
|
export declare function serializeUsed(set: Set<string>): string;
|
|
8
|
-
export declare class SessionService {
|
|
9
|
-
private readonly db;
|
|
8
|
+
export declare class SessionService extends BaseSessionService<ChainSessionRow> {
|
|
10
9
|
constructor(db: ChainDatabase);
|
|
11
|
-
getActiveByChannel(channel: string): Promise<ChainSessionRow | null>;
|
|
12
|
-
getActiveForUser(channel: string, userId: string): Promise<ChainSessionRow | null>;
|
|
13
|
-
getById(id: string): Promise<ChainSessionRow | null>;
|
|
14
|
-
getActiveByBoardMessageId(messageId: string): Promise<ChainSessionRow | null>;
|
|
15
10
|
createSession(message: GameMessageLike, starter: {
|
|
16
11
|
text: string;
|
|
17
12
|
nextChar: string;
|
|
18
13
|
used: string[];
|
|
19
14
|
matchMode: MatchMode;
|
|
20
15
|
}): Promise<ChainSessionRow>;
|
|
21
|
-
updateSession(id: string, patch: Partial<ChainSessionRow>): Promise<void>;
|
|
22
|
-
abortStale(idleMs: number): Promise<number>;
|
|
23
16
|
}
|
|
24
17
|
export declare function createServices(db: ChainDatabase): SessionService;
|
package/lib/session-service.js
CHANGED
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import { channelKey, generateSessionId,
|
|
2
|
-
function getModel(db) {
|
|
3
|
-
const model = db.models.get('idiom_chain_sessions');
|
|
4
|
-
if (!model)
|
|
5
|
-
throw new Error('idiom_chain_sessions not registered');
|
|
6
|
-
return model;
|
|
7
|
-
}
|
|
1
|
+
import { BaseSessionService, channelKey, generateSessionId, } from '@zhin.js/game-kit';
|
|
8
2
|
export function parseUsed(value) {
|
|
9
3
|
if (Array.isArray(value))
|
|
10
4
|
return new Set(value.filter((x) => typeof x === 'string'));
|
|
@@ -21,33 +15,13 @@ export function parseUsed(value) {
|
|
|
21
15
|
export function serializeUsed(set) {
|
|
22
16
|
return JSON.stringify([...set]);
|
|
23
17
|
}
|
|
24
|
-
export class SessionService {
|
|
25
|
-
db;
|
|
18
|
+
export class SessionService extends BaseSessionService {
|
|
26
19
|
constructor(db) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
async getActiveForUser(channel, userId) {
|
|
34
|
-
const row = await this.getActiveByChannel(channel);
|
|
35
|
-
if (!row || row.player_id !== userId)
|
|
36
|
-
return null;
|
|
37
|
-
return row;
|
|
38
|
-
}
|
|
39
|
-
async getById(id) {
|
|
40
|
-
return getModel(this.db).findOne({ id });
|
|
41
|
-
}
|
|
42
|
-
async getActiveByBoardMessageId(messageId) {
|
|
43
|
-
if (!messageId)
|
|
44
|
-
return null;
|
|
45
|
-
const rows = await getModel(this.db).findAll({});
|
|
46
|
-
for (const row of rows) {
|
|
47
|
-
if (boardMessageMatches(row.board_message_id ?? '', messageId))
|
|
48
|
-
return row;
|
|
49
|
-
}
|
|
50
|
-
return null;
|
|
20
|
+
super(db, {
|
|
21
|
+
gameId: 'chain',
|
|
22
|
+
table: 'idiom_chain_sessions',
|
|
23
|
+
userFields: ['player_id'],
|
|
24
|
+
});
|
|
51
25
|
}
|
|
52
26
|
async createSession(message, starter) {
|
|
53
27
|
const now = Date.now();
|
|
@@ -72,28 +46,10 @@ export class SessionService {
|
|
|
72
46
|
hints_used: 0,
|
|
73
47
|
turn: 'player',
|
|
74
48
|
status: 'active',
|
|
75
|
-
board_message_id: '',
|
|
76
49
|
updated_at: now,
|
|
77
50
|
created_at: now,
|
|
78
51
|
};
|
|
79
|
-
|
|
80
|
-
return row;
|
|
81
|
-
}
|
|
82
|
-
async updateSession(id, patch) {
|
|
83
|
-
await getModel(this.db).updateWhere({ id }, { ...patch, updated_at: Date.now() });
|
|
84
|
-
}
|
|
85
|
-
async abortStale(idleMs) {
|
|
86
|
-
const cutoff = Date.now() - idleMs;
|
|
87
|
-
const model = getModel(this.db);
|
|
88
|
-
const rows = await model.findAll({ status: 'active' });
|
|
89
|
-
let n = 0;
|
|
90
|
-
for (const row of rows) {
|
|
91
|
-
if (row.updated_at < cutoff) {
|
|
92
|
-
await model.updateWhere({ id: row.id }, { status: 'aborted', updated_at: Date.now() });
|
|
93
|
-
n++;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return n;
|
|
52
|
+
return this.createRow(row);
|
|
97
53
|
}
|
|
98
54
|
}
|
|
99
55
|
export function createServices(db) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-service.js","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"session-service.js","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,iBAAiB,GAGlB,MAAM,mBAAmB,CAAC;AAM3B,MAAM,UAAU,SAAS,CAAC,KAAkC;IAC1D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC;IAClG,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,GAAG,EAAE,CAAC;IAC1D,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC5B,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC;IACrG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,GAAG,EAAE,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAgB;IAC5C,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,OAAO,cAAe,SAAQ,kBAAmC;IACrE,YAAY,EAAiB;QAC3B,KAAK,CAAC,EAAqD,EAAE;YAC3D,MAAM,EAAE,OAAO;YACf,KAAK,EAAE,sBAAsB;YAC7B,UAAU,EAAE,CAAC,WAAW,CAAC;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,aAAa,CACjB,OAAwB,EACxB,OAAiF;QAEjF,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,GAAG,GAAoB;YAC3B,EAAE,EAAE,iBAAiB,EAAE;YACvB,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;YACjC,QAAQ,EAAE,OAAO,CAAC,SAAS;YAC3B,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI;YACnC,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE;YAC/B,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC;YAChC,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE;YAC7B,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;YAC/D,UAAU,EAAE,OAAO,CAAC,IAAI;YACxB,SAAS,EAAE,OAAO,CAAC,QAAQ;YAC3B,UAAU,EAAE,OAAO,CAAC,SAAS;YAC7B,WAAW,EAAE,aAAa,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACjD,YAAY,EAAE,CAAC;YACf,SAAS,EAAE,CAAC;YACZ,MAAM,EAAE,CAAC;YACT,WAAW,EAAE,CAAC;YACd,WAAW,EAAE,CAAC;YACd,UAAU,EAAE,CAAC;YACb,IAAI,EAAE,QAAQ;YACd,MAAM,EAAE,QAAQ;YAChB,UAAU,EAAE,GAAG;YACf,UAAU,EAAE,GAAG;SAChB,CAAC;QACF,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;CACF;AAED,MAAM,UAAU,cAAc,CAAC,EAAiB;IAC9C,OAAO,IAAI,cAAc,CAAC,EAAE,CAAC,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { defineGameCommandAliasMiddleware, isChainAction, messageFromCommandInput, normalizeChainAction, } from '@zhin.js/game-kit';
|
|
3
|
+
import { CHAIN_HELP, runChainCommand } from "../lib/chain-command.js";
|
|
4
|
+
import { resolveGameServices } from "../lib/runtime-store.js";
|
|
5
|
+
export default defineGameCommandAliasMiddleware({
|
|
6
|
+
aliases: ['接龙', 'chain'],
|
|
7
|
+
async run(action, input, context) {
|
|
8
|
+
const normalized = normalizeChainAction(String(action ?? ''));
|
|
9
|
+
if (normalized === 'help')
|
|
10
|
+
return CHAIN_HELP;
|
|
11
|
+
// action 无法识别:放行给后续中间件,避免劫持普通聊天
|
|
12
|
+
if (!isChainAction(normalized))
|
|
13
|
+
return null;
|
|
14
|
+
const services = resolveGameServices(context);
|
|
15
|
+
const message = messageFromCommandInput(input);
|
|
16
|
+
return runChainCommand(services, message, normalized);
|
|
17
|
+
},
|
|
18
|
+
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { defineMiddleware } from '@zhin.js/middleware';
|
|
3
|
+
import { buildChoiceFallbackMap, channelKey, messageFromCommandInput, parseChoicePayload, resolveGameTextPayload, } from '@zhin.js/game-kit';
|
|
4
|
+
import { resolveGameServices } from "../lib/runtime-store.js";
|
|
5
|
+
import { CHAIN_PREFIX, handleChoice, processIdiomText } from "../lib/game-flow.js";
|
|
6
|
+
/**
|
|
7
|
+
* 文本入口:按钮 payload(`chain:session:choiceId`)、数字 fallback
|
|
8
|
+
* (『1提示 2跳过 3认输』,对应 view 的 fallbackHint),其余按成语接龙作答。
|
|
9
|
+
*/
|
|
10
|
+
export default defineMiddleware({
|
|
11
|
+
target: 'inbound',
|
|
12
|
+
async handle(context, next) {
|
|
13
|
+
const raw = context.input.content?.trim() ?? '';
|
|
14
|
+
if (!raw) {
|
|
15
|
+
await next();
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const services = resolveGameServices(context);
|
|
19
|
+
const message = messageFromCommandInput(context.input);
|
|
20
|
+
const ch = channelKey(message);
|
|
21
|
+
// 直接 payload(QQ 指令预填 / Sandbox action→text)
|
|
22
|
+
const payloadFromText = resolveGameTextPayload(raw);
|
|
23
|
+
if (payloadFromText?.startsWith(`${CHAIN_PREFIX}:`)) {
|
|
24
|
+
const parsed = parseChoicePayload(payloadFromText, CHAIN_PREFIX);
|
|
25
|
+
if (parsed) {
|
|
26
|
+
const session = await services.getById(parsed.sessionId);
|
|
27
|
+
if (session?.channel_key === ch) {
|
|
28
|
+
const reply = await handleChoice(services, message, parsed.sessionId, parsed.choiceId);
|
|
29
|
+
if (reply)
|
|
30
|
+
await context.input.$reply(reply);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
await next();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const session = await services.getActiveForUser(ch, message.$sender.id);
|
|
38
|
+
if (!session) {
|
|
39
|
+
await next();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (session.status === 'active') {
|
|
43
|
+
const map = buildChoiceFallbackMap(CHAIN_PREFIX, session.id, [
|
|
44
|
+
{ id: 'hint', label: '提示' },
|
|
45
|
+
{ id: 'skip', label: '跳过' },
|
|
46
|
+
{ id: 'quit', label: '认输' },
|
|
47
|
+
]);
|
|
48
|
+
const payload = resolveGameTextPayload(raw, map);
|
|
49
|
+
const parsed = payload ? parseChoicePayload(payload, CHAIN_PREFIX) : null;
|
|
50
|
+
if (parsed?.sessionId === session.id) {
|
|
51
|
+
const reply = await handleChoice(services, message, session.id, parsed.choiceId);
|
|
52
|
+
if (reply)
|
|
53
|
+
await context.input.$reply(reply);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// 仅把 2-8 个汉字的纯文本当成语作答,其余放行
|
|
58
|
+
if (/^[\u4e00-\u9fff]{2,8}$/.test(raw)) {
|
|
59
|
+
const reply = await processIdiomText(services, message, raw);
|
|
60
|
+
if (reply)
|
|
61
|
+
await context.input.$reply(reply);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
await next();
|
|
65
|
+
},
|
|
66
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/plugin-idiom-chain",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Zhin.js 成语接龙 — 四字成语文字接龙 (Plugin Runtime)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"./package.json": "./package.json"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
|
-
"plugin.
|
|
17
|
+
"plugin.js",
|
|
18
18
|
"schema.json",
|
|
19
19
|
"commands",
|
|
20
20
|
"middlewares",
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
"license": "MIT",
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"chinese-idiom-chengyu": "^1.1.0",
|
|
28
|
-
"@zhin.js/command": "1.0.
|
|
29
|
-
"@zhin.js/core": "1.4.
|
|
30
|
-
"@zhin.js/game-kit": "2.0.
|
|
31
|
-
"@zhin.js/middleware": "1.0.
|
|
28
|
+
"@zhin.js/command": "1.0.4",
|
|
29
|
+
"@zhin.js/core": "1.4.2",
|
|
30
|
+
"@zhin.js/game-kit": "2.0.2",
|
|
31
|
+
"@zhin.js/middleware": "1.0.4",
|
|
32
32
|
"@zhin.js/plugin-runtime": "1.1.1"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"zhin": {
|
|
51
51
|
"protocol": 1,
|
|
52
52
|
"type": "plugin",
|
|
53
|
-
"entry": "./plugin.
|
|
53
|
+
"entry": "./plugin.js",
|
|
54
54
|
"engine": "^1.0.0",
|
|
55
55
|
"runtime": "trusted",
|
|
56
56
|
"features": [
|
package/plugin.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { defineGamePlugin } from '@zhin.js/game-kit';
|
|
3
|
+
import { defineHostTables } from "./lib/models.js";
|
|
4
|
+
import { gameServicesToken } from "./lib/runtime-store.js";
|
|
5
|
+
import { createServices, } from "./lib/session-service.js";
|
|
6
|
+
/**
|
|
7
|
+
* Plugin Runtime:
|
|
8
|
+
* - Commands under `commands/` are authoritative (help + start/continue/quit via in-memory DB).
|
|
9
|
+
* - DB: prefer databaseHostToken; else in-memory SessionService.
|
|
10
|
+
* - Text middleware under `middlewares/` handles idiom answer payloads.
|
|
11
|
+
*/
|
|
12
|
+
export default defineGamePlugin({
|
|
13
|
+
name: 'idiom-chain',
|
|
14
|
+
metadata: {
|
|
15
|
+
displayName: 'Idiom Chain',
|
|
16
|
+
},
|
|
17
|
+
game: {
|
|
18
|
+
id: 'chain',
|
|
19
|
+
title: '成语接龙',
|
|
20
|
+
icon: '📜',
|
|
21
|
+
description: '四字成语接龙(同音/同字)',
|
|
22
|
+
commandPrefix: '/接龙',
|
|
23
|
+
quickStart: 'start_pinyin',
|
|
24
|
+
aliases: ['chain'],
|
|
25
|
+
menus: [
|
|
26
|
+
{ id: 'start_pinyin', label: '🎮 同音接龙' },
|
|
27
|
+
{ id: 'start_char', label: '📝 同字接龙' },
|
|
28
|
+
{ id: 'continue', label: '🔄 继续' },
|
|
29
|
+
{ id: 'help', label: '📖 玩法说明' },
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
tables: ['idiom_chain_sessions'],
|
|
33
|
+
servicesToken: gameServicesToken,
|
|
34
|
+
defineHostTables,
|
|
35
|
+
createServices: (database) => createServices(database),
|
|
36
|
+
session: (services) => services,
|
|
37
|
+
});
|
package/src/chain-command.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
channelKey,
|
|
3
|
+
type GameMessageLike,
|
|
4
|
+
type GameReply,
|
|
5
|
+
} from '@zhin.js/game-kit';
|
|
2
6
|
import { continueGame, startGame } from './game-flow.js';
|
|
3
7
|
import { idiomCount, modeLabel, promptLine, type MatchMode } from './engine.js';
|
|
4
8
|
|
|
@@ -21,7 +25,7 @@ export async function runChainCommand(
|
|
|
21
25
|
services: SessionService,
|
|
22
26
|
message: GameMessageLike,
|
|
23
27
|
action: string,
|
|
24
|
-
): Promise<
|
|
28
|
+
): Promise<GameReply> {
|
|
25
29
|
const ch = channelKey(message);
|
|
26
30
|
const userId = message.$sender.id;
|
|
27
31
|
|
package/src/game-flow.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { GameMessageLike, GameReply } from '@zhin.js/game-kit';
|
|
2
2
|
import {
|
|
3
3
|
CHAIN_PREFIX,
|
|
4
4
|
getGloss,
|
|
@@ -25,9 +25,9 @@ export async function sendOrEditView(
|
|
|
25
25
|
message: GameMessageLike,
|
|
26
26
|
session: ChainSessionRow,
|
|
27
27
|
eventLines: string[] = [],
|
|
28
|
-
): Promise<
|
|
28
|
+
): Promise<GameReply> {
|
|
29
29
|
const content = buildChainView(session, eventLines, message.$channel.type);
|
|
30
|
-
return
|
|
30
|
+
return content;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
async function botTurn(
|
|
@@ -67,7 +67,7 @@ export async function startGame(
|
|
|
67
67
|
services: SessionService,
|
|
68
68
|
message: GameMessageLike,
|
|
69
69
|
matchMode: MatchMode = 'pinyin',
|
|
70
|
-
): Promise<
|
|
70
|
+
): Promise<GameReply | undefined> {
|
|
71
71
|
const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
|
|
72
72
|
const active = await services.getActiveByChannel(ch);
|
|
73
73
|
if (active) {
|
|
@@ -88,32 +88,29 @@ export async function startGame(
|
|
|
88
88
|
});
|
|
89
89
|
|
|
90
90
|
const gloss = starter.gloss ?? getGloss(starter.text);
|
|
91
|
-
|
|
91
|
+
return sendOrEditView(services, message, session, [
|
|
92
92
|
`🎬 ${modeLabel(matchMode)}开局!我先出:**${starter.text}**${gloss ? `(${gloss})` : ''}`,
|
|
93
93
|
promptLine(starter.text, matchMode),
|
|
94
94
|
]);
|
|
95
|
-
return typeof text === 'string' ? text : undefined;
|
|
96
95
|
}
|
|
97
96
|
|
|
98
97
|
export async function continueGame(
|
|
99
98
|
services: SessionService,
|
|
100
99
|
message: GameMessageLike,
|
|
101
|
-
): Promise<
|
|
100
|
+
): Promise<GameReply> {
|
|
102
101
|
const session = await services.getActiveForUser(
|
|
103
102
|
`${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`,
|
|
104
103
|
message.$sender.id,
|
|
105
104
|
);
|
|
106
105
|
if (!session) return '你没有进行中的接龙,发送「接龙 开始」。';
|
|
107
|
-
|
|
108
|
-
if (typeof text === 'string') return text;
|
|
109
|
-
return '已刷新接龙界面。';
|
|
106
|
+
return sendOrEditView(services, message, session);
|
|
110
107
|
}
|
|
111
108
|
|
|
112
109
|
export async function processIdiomText(
|
|
113
110
|
services: SessionService,
|
|
114
111
|
message: GameMessageLike,
|
|
115
112
|
raw: string,
|
|
116
|
-
): Promise<
|
|
113
|
+
): Promise<GameReply | null> {
|
|
117
114
|
const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
|
|
118
115
|
const session = await services.getActiveForUser(ch, message.$sender.id);
|
|
119
116
|
if (!session || session.status !== 'active') return null;
|
|
@@ -176,7 +173,7 @@ export async function handleChoice(
|
|
|
176
173
|
message: GameMessageLike,
|
|
177
174
|
sessionId: string,
|
|
178
175
|
choiceId: string,
|
|
179
|
-
): Promise<
|
|
176
|
+
): Promise<GameReply | null> {
|
|
180
177
|
const session = await services.getById(sessionId);
|
|
181
178
|
if (!session) return '对局不存在。';
|
|
182
179
|
if (session.player_id !== message.$sender.id) return '这是别人的接龙。';
|
|
@@ -195,7 +192,6 @@ export async function handleChoice(
|
|
|
195
192
|
wrong_count: 0,
|
|
196
193
|
turn: 'player',
|
|
197
194
|
status: 'active',
|
|
198
|
-
board_message_id: '',
|
|
199
195
|
});
|
|
200
196
|
const updated = (await services.getById(session.id))!;
|
|
201
197
|
const gloss = starter.gloss ?? getGloss(starter.text);
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export { CHAIN_HELP } from './chain-command.js';
|
|
2
2
|
export { gameServicesToken, resolveGameServices } from './runtime-store.js';
|
|
3
|
-
export { createInMemoryChainDb, mountChainMemoryServices } from './memory-db.js';
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* 已由 plugin.ts 接线:commands/ 命令、middlewares/ 文本与选项中间件、
|
package/src/models.ts
CHANGED
|
@@ -26,7 +26,6 @@ declare module '@zhin.js/core' {
|
|
|
26
26
|
hints_used: number;
|
|
27
27
|
turn: string;
|
|
28
28
|
status: ChainSessionStatus;
|
|
29
|
-
board_message_id: string;
|
|
30
29
|
updated_at: number;
|
|
31
30
|
created_at: number;
|
|
32
31
|
};
|
|
@@ -60,7 +59,6 @@ export function defineHostTables(
|
|
|
60
59
|
hints_used: { type: 'integer', default: 0 },
|
|
61
60
|
turn: { type: 'text', default: 'player' },
|
|
62
61
|
status: { type: 'text', default: 'active' },
|
|
63
|
-
board_message_id: { type: 'text', default: '' },
|
|
64
62
|
updated_at: { type: 'integer', default: 0 },
|
|
65
63
|
created_at: { type: 'integer', default: 0 },
|
|
66
64
|
});
|
package/src/session-service.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import type { Database, Models
|
|
2
|
-
import {
|
|
1
|
+
import type { Database, Models } from '@zhin.js/core';
|
|
2
|
+
import {
|
|
3
|
+
BaseSessionService,
|
|
4
|
+
channelKey,
|
|
5
|
+
generateSessionId,
|
|
6
|
+
type GameMessageLike,
|
|
7
|
+
type GameSessionDatabase,
|
|
8
|
+
} from '@zhin.js/game-kit';
|
|
3
9
|
import type { MatchMode } from './engine.js';
|
|
4
10
|
import type { ChainSessionRow } from './models.js';
|
|
5
11
|
|
|
6
12
|
export type ChainDatabase = Database<unknown, Models, string>;
|
|
7
13
|
|
|
8
|
-
function getModel(db: ChainDatabase) {
|
|
9
|
-
const model = db.models.get('idiom_chain_sessions');
|
|
10
|
-
if (!model) throw new Error('idiom_chain_sessions not registered');
|
|
11
|
-
return model as RelatedModel<unknown, Models, 'idiom_chain_sessions'>;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
14
|
export function parseUsed(value: string | string[] | unknown): Set<string> {
|
|
15
15
|
if (Array.isArray(value)) return new Set(value.filter((x): x is string => typeof x === 'string'));
|
|
16
16
|
if (typeof value !== 'string' || !value) return new Set();
|
|
@@ -26,31 +26,13 @@ export function serializeUsed(set: Set<string>): string {
|
|
|
26
26
|
return JSON.stringify([...set]);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
export class SessionService {
|
|
30
|
-
constructor(
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
async getActiveForUser(channel: string, userId: string): Promise<ChainSessionRow | null> {
|
|
38
|
-
const row = await this.getActiveByChannel(channel);
|
|
39
|
-
if (!row || row.player_id !== userId) return null;
|
|
40
|
-
return row;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async getById(id: string): Promise<ChainSessionRow | null> {
|
|
44
|
-
return getModel(this.db).findOne({ id });
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async getActiveByBoardMessageId(messageId: string): Promise<ChainSessionRow | null> {
|
|
48
|
-
if (!messageId) return null;
|
|
49
|
-
const rows = await getModel(this.db).findAll({});
|
|
50
|
-
for (const row of rows) {
|
|
51
|
-
if (boardMessageMatches(row.board_message_id ?? '', messageId)) return row;
|
|
52
|
-
}
|
|
53
|
-
return null;
|
|
29
|
+
export class SessionService extends BaseSessionService<ChainSessionRow> {
|
|
30
|
+
constructor(db: ChainDatabase) {
|
|
31
|
+
super(db as unknown as GameSessionDatabase<ChainSessionRow>, {
|
|
32
|
+
gameId: 'chain',
|
|
33
|
+
table: 'idiom_chain_sessions',
|
|
34
|
+
userFields: ['player_id'],
|
|
35
|
+
});
|
|
54
36
|
}
|
|
55
37
|
|
|
56
38
|
async createSession(
|
|
@@ -79,34 +61,13 @@ export class SessionService {
|
|
|
79
61
|
hints_used: 0,
|
|
80
62
|
turn: 'player',
|
|
81
63
|
status: 'active',
|
|
82
|
-
board_message_id: '',
|
|
83
64
|
updated_at: now,
|
|
84
65
|
created_at: now,
|
|
85
66
|
};
|
|
86
|
-
|
|
87
|
-
return row;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async updateSession(id: string, patch: Partial<ChainSessionRow>): Promise<void> {
|
|
91
|
-
await getModel(this.db).updateWhere({ id }, { ...patch, updated_at: Date.now() });
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
async abortStale(idleMs: number): Promise<number> {
|
|
95
|
-
const cutoff = Date.now() - idleMs;
|
|
96
|
-
const model = getModel(this.db);
|
|
97
|
-
const rows = await model.findAll({ status: 'active' });
|
|
98
|
-
let n = 0;
|
|
99
|
-
for (const row of rows) {
|
|
100
|
-
if (row.updated_at < cutoff) {
|
|
101
|
-
await model.updateWhere({ id: row.id }, { status: 'aborted', updated_at: Date.now() });
|
|
102
|
-
n++;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
return n;
|
|
67
|
+
return this.createRow(row);
|
|
106
68
|
}
|
|
107
69
|
}
|
|
108
70
|
|
|
109
71
|
export function createServices(db: ChainDatabase): SessionService {
|
|
110
72
|
return new SessionService(db);
|
|
111
73
|
}
|
|
112
|
-
|
package/lib/memory-db.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { DatabaseHost } from '@zhin.js/plugin-runtime';
|
|
2
|
-
import { type ChainDatabase, type SessionService } from './session-service.js';
|
|
3
|
-
/** In-memory idiom_chain_sessions for Plugin Runtime slice-2 (no DatabaseFeature). */
|
|
4
|
-
export declare function createInMemoryChainDb(): ChainDatabase;
|
|
5
|
-
export declare function mountChainMemoryServices(): SessionService;
|
|
6
|
-
export declare function mountChainHostServices(host: DatabaseHost): SessionService;
|
package/lib/memory-db.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { createHostGameDb, createInMemoryGameDb } from '@zhin.js/game-kit';
|
|
2
|
-
import { defineHostTables } from './models.js';
|
|
3
|
-
import { createServices } from './session-service.js';
|
|
4
|
-
const CHAIN_TABLES = ['idiom_chain_sessions'];
|
|
5
|
-
/** In-memory idiom_chain_sessions for Plugin Runtime slice-2 (no DatabaseFeature). */
|
|
6
|
-
export function createInMemoryChainDb() {
|
|
7
|
-
return createInMemoryGameDb(CHAIN_TABLES);
|
|
8
|
-
}
|
|
9
|
-
export function mountChainMemoryServices() {
|
|
10
|
-
const services = createServices(createInMemoryChainDb());
|
|
11
|
-
return services;
|
|
12
|
-
}
|
|
13
|
-
export function mountChainHostServices(host) {
|
|
14
|
-
defineHostTables(host);
|
|
15
|
-
const services = createServices(createHostGameDb(host, CHAIN_TABLES));
|
|
16
|
-
return services;
|
|
17
|
-
}
|
|
18
|
-
//# sourceMappingURL=memory-db.js.map
|
package/lib/memory-db.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"memory-db.js","sourceRoot":"","sources":["../src/memory-db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAE3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,cAAc,EAA2C,MAAM,sBAAsB,CAAC;AAE/F,MAAM,YAAY,GAAG,CAAC,sBAAsB,CAAU,CAAC;AAEvD,sFAAsF;AACtF,MAAM,UAAU,qBAAqB;IACnC,OAAO,oBAAoB,CAAC,YAAY,CAA6B,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,wBAAwB;IACtC,MAAM,QAAQ,GAAG,cAAc,CAAC,qBAAqB,EAAE,CAAC,CAAC;IACzD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAkB;IACvD,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACvB,MAAM,QAAQ,GAAG,cAAc,CAAC,gBAAgB,CAAC,IAAI,EAAE,YAAY,CAA6B,CAAC,CAAC;IAClG,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/plugin.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { definePlugin, databaseHostToken, scheduleHostToken } from '@zhin.js/plugin-runtime';
|
|
2
|
-
import {
|
|
3
|
-
registerRuntimeGame,
|
|
4
|
-
initGameRecordHost,
|
|
5
|
-
DEFAULT_GAME_STALE_CRON,
|
|
6
|
-
DEFAULT_GAME_STALE_IDLE_MS,
|
|
7
|
-
} from '@zhin.js/game-kit';
|
|
8
|
-
import { 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/src/memory-db.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { createHostGameDb, createInMemoryGameDb } from '@zhin.js/game-kit';
|
|
2
|
-
import type { DatabaseHost } from '@zhin.js/plugin-runtime';
|
|
3
|
-
import { defineHostTables } from './models.js';
|
|
4
|
-
import { createServices, type 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
|
-
}
|