@zhin.js/plugin-dungeon-expedition 1.1.18 → 1.1.20
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/dungeon/[[action]]/index.js +5 -3
- package/commands/dungeon/[[action]]/index.ts +5 -7
- package/lib/dungeon-command.d.ts +3 -3
- package/lib/dungeon-command.js +13 -11
- package/lib/dungeon-command.js.map +1 -1
- package/lib/game-flow.d.ts +4 -4
- package/lib/game-flow.js +70 -64
- package/lib/game-flow.js.map +1 -1
- package/lib/session-service.d.ts +2 -2
- package/lib/session-service.js +21 -23
- package/lib/session-service.js.map +1 -1
- package/middlewares/dungeon-alias/index.js +14 -5
- package/middlewares/dungeon-alias/index.ts +13 -10
- package/middlewares/dungeon-choice/index.js +10 -6
- package/middlewares/dungeon-choice/index.ts +12 -10
- package/package.json +7 -7
- package/src/dungeon-command.ts +17 -15
- package/src/game-flow.ts +69 -63
- package/src/session-service.ts +22 -25
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { replyGameOperation, gamePlayerFromInput } from '@zhin.js/game-kit';
|
|
2
3
|
import { defineCommand } from 'zhin.js/command';
|
|
3
|
-
import { messageFromCommandInput } from '@zhin.js/game-kit';
|
|
4
4
|
import { getDungeonHelp, normalizeDungeonAction, runDungeonCommand, } from "../../../lib/dungeon-command.js";
|
|
5
5
|
import { resolveGameServices } from "../../../lib/runtime-store.js";
|
|
6
6
|
export default defineCommand({
|
|
7
7
|
description: 'Multiplayer dungeon expedition',
|
|
8
8
|
params: { action: { type: 'string', default: '' } },
|
|
9
|
-
async execute({ params, input, use, locale, formatCommand }) {
|
|
9
|
+
async execute({ params, input, use, locale, formatCommand, session }) {
|
|
10
10
|
const rawAction = String(params.action ?? '');
|
|
11
11
|
if (normalizeDungeonAction(rawAction) === 'help')
|
|
12
12
|
return getDungeonHelp({ locale, formatCommand });
|
|
13
13
|
const service = resolveGameServices({ use });
|
|
14
|
-
|
|
14
|
+
const player = gamePlayerFromInput(input, { locale, formatCommand });
|
|
15
|
+
await replyGameOperation({ session: service, player, reply: session?.reply,
|
|
16
|
+
run: () => runDungeonCommand(service, player, rawAction) });
|
|
15
17
|
},
|
|
16
18
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { replyGameOperation, gamePlayerFromInput } from '@zhin.js/game-kit';
|
|
1
2
|
import { defineCommand } from 'zhin.js/command';
|
|
2
|
-
import { messageFromCommandInput } from '@zhin.js/game-kit';
|
|
3
3
|
import {
|
|
4
4
|
getDungeonHelp,
|
|
5
5
|
normalizeDungeonAction,
|
|
@@ -10,14 +10,12 @@ import { resolveGameServices } from '../../../src/runtime-store.js';
|
|
|
10
10
|
export default defineCommand({
|
|
11
11
|
description: 'Multiplayer dungeon expedition',
|
|
12
12
|
params: { action: { type: 'string', default: '' } },
|
|
13
|
-
async execute({ params, input, use, locale, formatCommand }) {
|
|
13
|
+
async execute({ params, input, use, locale, formatCommand, session }) {
|
|
14
14
|
const rawAction = String(params.action ?? '');
|
|
15
15
|
if (normalizeDungeonAction(rawAction) === 'help') return getDungeonHelp({ locale, formatCommand });
|
|
16
16
|
const service = resolveGameServices({ use });
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
rawAction,
|
|
21
|
-
);
|
|
17
|
+
const player = gamePlayerFromInput(input, { locale, formatCommand });
|
|
18
|
+
await replyGameOperation({ session: service, player, reply: session?.reply,
|
|
19
|
+
run: () => runDungeonCommand(service, player, rawAction) });
|
|
22
20
|
},
|
|
23
21
|
});
|
package/lib/dungeon-command.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type GamePlayer, type GameReply } from '@zhin.js/game-kit';
|
|
2
2
|
import type { SessionService } from './session-service.js';
|
|
3
|
-
export declare function getDungeonHelp(message?: Pick<
|
|
3
|
+
export declare function getDungeonHelp(message?: Pick<GamePlayer, 'locale' | 'formatCommand'>): string;
|
|
4
4
|
export declare const DUNGEON_HELP: string;
|
|
5
5
|
export declare function normalizeDungeonAction(action: string): string | null;
|
|
6
|
-
export declare function runDungeonCommand(service: SessionService, message:
|
|
6
|
+
export declare function runDungeonCommand(service: SessionService, message: GamePlayer, rawAction: string): Promise<GameReply>;
|
package/lib/dungeon-command.js
CHANGED
|
@@ -55,16 +55,18 @@ export function normalizeDungeonAction(action) {
|
|
|
55
55
|
return ACTION_ALIASES[action.trim().toLowerCase()] ?? null;
|
|
56
56
|
}
|
|
57
57
|
export async function runDungeonCommand(service, message, rawAction) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
58
|
+
return service.runInScope({ scope: channelKey(message), run: async () => {
|
|
59
|
+
const action = normalizeDungeonAction(rawAction);
|
|
60
|
+
if (!action || action === 'help')
|
|
61
|
+
return getDungeonHelp(message);
|
|
62
|
+
if (action === 'create')
|
|
63
|
+
return startDungeon(service, message);
|
|
64
|
+
if (action === 'status')
|
|
65
|
+
return continueDungeon(service, message);
|
|
66
|
+
const session = await service.getActiveByChannel(channelKey(message));
|
|
67
|
+
if (!session)
|
|
68
|
+
return messages(message.locale, 'empty') + gameCommandHint(message, 'dungeon');
|
|
69
|
+
return handleDungeonChoice(service, message, dungeonSessionToken(session), action);
|
|
70
|
+
} });
|
|
69
71
|
}
|
|
70
72
|
//# sourceMappingURL=dungeon-command.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dungeon-command.js","sourceRoot":"","sources":["../src/dungeon-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"dungeon-command.js","sourceRoot":"","sources":["../src/dungeon-command.ts"],"names":[],"mappings":"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"}
|
package/lib/game-flow.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type GamePlayer, type GameReply } from '@zhin.js/game-kit';
|
|
2
2
|
import type { DungeonSessionRow } from './models.js';
|
|
3
3
|
import { type SessionService } from './session-service.js';
|
|
4
|
-
export declare function startDungeon(service: SessionService, message:
|
|
5
|
-
export declare function continueDungeon(service: SessionService, message:
|
|
6
|
-
export declare function handleDungeonChoice(service: SessionService, message:
|
|
4
|
+
export declare function startDungeon(service: SessionService, message: GamePlayer): Promise<GameReply>;
|
|
5
|
+
export declare function continueDungeon(service: SessionService, message: GamePlayer): Promise<GameReply>;
|
|
6
|
+
export declare function handleDungeonChoice(service: SessionService, message: GamePlayer, sessionToken: string, choiceId: string): Promise<GameReply>;
|
|
7
7
|
export declare function commandActionId(session: DungeonSessionRow, actorId: string, choiceId: string): string;
|
package/lib/game-flow.js
CHANGED
|
@@ -4,73 +4,79 @@ import { DungeonRuleError, } from './engine.js';
|
|
|
4
4
|
import { stateFromSession, } from './session-service.js';
|
|
5
5
|
import { buildDungeonView, parseDungeonSessionToken, } from './view.js';
|
|
6
6
|
export async function startDungeon(service, message) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
7
|
+
return service.runInScope({ scope: channelKey(message), run: async () => {
|
|
8
|
+
const active = await service.getActiveByChannel(channelKey(message));
|
|
9
|
+
if (active)
|
|
10
|
+
return buildDungeonView(active, stateFromSession(active), message.target.kind);
|
|
11
|
+
try {
|
|
12
|
+
const session = await service.createSession(message);
|
|
13
|
+
return buildDungeonView(session, stateFromSession(session), message.target.kind);
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
if (error instanceof GameSessionConflictError)
|
|
17
|
+
return error.format(message.locale);
|
|
18
|
+
throw error;
|
|
19
|
+
}
|
|
20
|
+
} });
|
|
19
21
|
}
|
|
20
22
|
export async function continueDungeon(service, message) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
return service.runInScope({ scope: channelKey(message), run: async () => {
|
|
24
|
+
const locale = resolveLocale(message.locale);
|
|
25
|
+
const session = await service.getActiveByChannel(channelKey(message));
|
|
26
|
+
if (!session)
|
|
27
|
+
return messages(locale, 'text1');
|
|
28
|
+
return buildDungeonView(session, stateFromSession(session), message.target.kind);
|
|
29
|
+
} });
|
|
26
30
|
}
|
|
27
31
|
export async function handleDungeonChoice(service, message, sessionToken, choiceId) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
32
|
+
return service.runInScope({ scope: channelKey(message), run: async () => {
|
|
33
|
+
let locale = resolveLocale(message.locale);
|
|
34
|
+
const token = parseDungeonSessionToken(sessionToken);
|
|
35
|
+
if (!token)
|
|
36
|
+
return messages(locale, 'text2');
|
|
37
|
+
const session = await service.getById(token.sessionId);
|
|
38
|
+
if (!session || session.channel_key !== channelKey(message)) {
|
|
39
|
+
return messages(locale, 'text3');
|
|
40
|
+
}
|
|
41
|
+
locale = resolveLocale(session.locale);
|
|
42
|
+
if (choiceId === 'restart') {
|
|
43
|
+
if (session.status === 'active')
|
|
44
|
+
return messages(locale, 'text4');
|
|
45
|
+
if (session.owner_id !== message.sender.id)
|
|
46
|
+
return messages(locale, 'text5');
|
|
47
|
+
return startDungeon(service, message);
|
|
48
|
+
}
|
|
49
|
+
const action = actionFromChoice(choiceId, message);
|
|
50
|
+
if (!action)
|
|
51
|
+
return messages(locale, 'text6');
|
|
52
|
+
try {
|
|
53
|
+
const result = await service.performAction({
|
|
54
|
+
sessionId: session.id,
|
|
55
|
+
actorId: message.sender.id,
|
|
56
|
+
actorName: message.sender.name?.trim() || message.sender.id,
|
|
57
|
+
action,
|
|
58
|
+
expectedRevision: token.revision,
|
|
59
|
+
actionId: `${session.id}:${token.revision}:${message.sender.id}:${choiceId}`,
|
|
60
|
+
});
|
|
61
|
+
return buildDungeonView(result.session, stateFromSession(result.session), message.target.kind);
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
if (error instanceof DungeonRuleError)
|
|
65
|
+
return error.message;
|
|
66
|
+
if (error instanceof GameSessionConflictError)
|
|
67
|
+
return error.format(locale);
|
|
68
|
+
if (error instanceof SessionRevisionConflictError) {
|
|
69
|
+
const latest = await service.getById(session.id);
|
|
70
|
+
if (!latest)
|
|
71
|
+
return messages(locale, 'text7');
|
|
72
|
+
const view = buildDungeonView(latest, stateFromSession(latest), message.target.kind);
|
|
73
|
+
return Array.isArray(view)
|
|
74
|
+
? [messages(locale, 'text8'), ...view]
|
|
75
|
+
: [messages(locale, 'text8'), view];
|
|
76
|
+
}
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
} });
|
|
74
80
|
}
|
|
75
81
|
export function commandActionId(session, actorId, choiceId) {
|
|
76
82
|
return `${session.id}:${session.revision}:${actorId}:${choiceId}`;
|
|
@@ -79,7 +85,7 @@ function actionFromChoice(choiceId, message) {
|
|
|
79
85
|
if (choiceId === 'join') {
|
|
80
86
|
return {
|
|
81
87
|
type: 'join',
|
|
82
|
-
name: message
|
|
88
|
+
name: message.sender.name?.trim() || message.sender.id,
|
|
83
89
|
};
|
|
84
90
|
}
|
|
85
91
|
if (choiceId === 'ready')
|
package/lib/game-flow.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"game-flow.js","sourceRoot":"","sources":["../src/game-flow.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EACL,wBAAwB,EACxB,4BAA4B,EAC5B,UAAU,GAGX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,gBAAgB,GAEjB,MAAM,aAAa,CAAC;AAErB,OAAO,EAEL,gBAAgB,GACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,WAAW,CAAC;AAEnB,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAuB,EACvB,
|
|
1
|
+
{"version":3,"file":"game-flow.js","sourceRoot":"","sources":["../src/game-flow.ts"],"names":[],"mappings":"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"}
|
package/lib/session-service.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Database, Models } from '@zhin.js/core';
|
|
2
|
-
import { VersionedSessionService, type
|
|
2
|
+
import { VersionedSessionService, type GamePlayer, type SessionMutationResult } from '@zhin.js/game-kit';
|
|
3
3
|
import { type DungeonAction, type DungeonState } from './engine.js';
|
|
4
4
|
import type { DungeonSessionRow } from './models.js';
|
|
5
5
|
export type DungeonDatabase = Database<unknown, Models, string>;
|
|
@@ -13,7 +13,7 @@ export interface PerformDungeonActionOptions {
|
|
|
13
13
|
}
|
|
14
14
|
export declare class SessionService extends VersionedSessionService<DungeonSessionRow> {
|
|
15
15
|
constructor(database: DungeonDatabase);
|
|
16
|
-
createSession(message:
|
|
16
|
+
createSession(message: GamePlayer, seed?: string | number): Promise<DungeonSessionRow>;
|
|
17
17
|
getActiveForUser(channelKeyValue: string, userId: string): Promise<DungeonSessionRow | null>;
|
|
18
18
|
performAction(options: PerformDungeonActionOptions): Promise<SessionMutationResult<DungeonSessionRow>>;
|
|
19
19
|
}
|
package/lib/session-service.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DeterministicRandom, VersionedSessionService,
|
|
1
|
+
import { DeterministicRandom, VersionedSessionService, generateCompactId, } from '@zhin.js/game-kit';
|
|
2
2
|
import { activePlayer, applyDungeonAction, createDungeonState, decodeDungeonState, } from './engine.js';
|
|
3
3
|
export class SessionService extends VersionedSessionService {
|
|
4
4
|
constructor(database) {
|
|
@@ -12,30 +12,28 @@ export class SessionService extends VersionedSessionService {
|
|
|
12
12
|
async createSession(message, seed) {
|
|
13
13
|
const now = Date.now();
|
|
14
14
|
const id = generateCompactId('dng_');
|
|
15
|
-
const ownerName = message
|
|
16
|
-
const state = createDungeonState(message
|
|
15
|
+
const ownerName = message.sender.name?.trim() || message.sender.id;
|
|
16
|
+
const state = createDungeonState(message.sender.id, ownerName, message.locale);
|
|
17
17
|
const random = DeterministicRandom.fromSeed(seed ?? id);
|
|
18
18
|
return this.createRow({
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
updated_at: now,
|
|
38
|
-
created_at: now,
|
|
19
|
+
target: message.target,
|
|
20
|
+
fields: {
|
|
21
|
+
id,
|
|
22
|
+
locale: message.locale ?? 'zh-CN',
|
|
23
|
+
owner_id: message.sender.id,
|
|
24
|
+
owner_name: ownerName,
|
|
25
|
+
state_json: JSON.stringify(state),
|
|
26
|
+
phase: state.phase,
|
|
27
|
+
turn: activePlayer(state)?.id ?? '',
|
|
28
|
+
rng_state: random.state,
|
|
29
|
+
schema_version: state.schemaVersion,
|
|
30
|
+
revision: 0,
|
|
31
|
+
processed_actions: '[]',
|
|
32
|
+
deadline_at: now + 5 * 60_000,
|
|
33
|
+
status: 'active',
|
|
34
|
+
updated_at: now,
|
|
35
|
+
created_at: now,
|
|
36
|
+
},
|
|
39
37
|
});
|
|
40
38
|
}
|
|
41
39
|
async getActiveForUser(channelKeyValue, userId) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-service.js","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,mBAAmB,EACnB,uBAAuB,EACvB,
|
|
1
|
+
{"version":3,"file":"session-service.js","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
-
import {
|
|
3
|
-
import { normalizeDungeonAction, runDungeonCommand, } from "../../lib/dungeon-command.js";
|
|
2
|
+
import { replyGameOperation, defineGameCommandAliasMiddleware, gamePlayerFromInput } from '@zhin.js/game-kit';
|
|
3
|
+
import { normalizeDungeonAction, getDungeonHelp, runDungeonCommand, } from "../../lib/dungeon-command.js";
|
|
4
4
|
import { resolveGameServices } from "../../lib/runtime-store.js";
|
|
5
5
|
export default defineGameCommandAliasMiddleware({
|
|
6
6
|
aliases: ['地牢', 'dungeon'],
|
|
7
7
|
async run(action, input, context) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
const normalized = normalizeDungeonAction(action);
|
|
9
|
+
if (normalized === null)
|
|
10
|
+
return false;
|
|
11
|
+
if (normalized === 'help') {
|
|
12
|
+
await context.input.$reply(getDungeonHelp({ locale: context.input.locale,
|
|
13
|
+
formatCommand: path => context.input.formatCommand?.(path, context.owner.id) }));
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
const services = resolveGameServices(context), player = gamePlayerFromInput(input);
|
|
17
|
+
await replyGameOperation({ session: services, player, reply: content => context.input.$reply(content),
|
|
18
|
+
run: () => runDungeonCommand(services, player, action) });
|
|
19
|
+
return true;
|
|
11
20
|
},
|
|
12
21
|
});
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
defineGameCommandAliasMiddleware,
|
|
3
|
-
messageFromCommandInput,
|
|
4
|
-
} from '@zhin.js/game-kit';
|
|
1
|
+
import { replyGameOperation, defineGameCommandAliasMiddleware, gamePlayerFromInput } from '@zhin.js/game-kit';
|
|
5
2
|
import {
|
|
6
3
|
normalizeDungeonAction,
|
|
4
|
+
getDungeonHelp,
|
|
7
5
|
runDungeonCommand,
|
|
8
6
|
} from '../../src/dungeon-command.js';
|
|
9
7
|
import { resolveGameServices } from '../../src/runtime-store.js';
|
|
@@ -11,11 +9,16 @@ import { resolveGameServices } from '../../src/runtime-store.js';
|
|
|
11
9
|
export default defineGameCommandAliasMiddleware({
|
|
12
10
|
aliases: ['地牢', 'dungeon'],
|
|
13
11
|
async run(action, input, context) {
|
|
14
|
-
|
|
15
|
-
return
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
const normalized = normalizeDungeonAction(action);
|
|
13
|
+
if (normalized === null) return false;
|
|
14
|
+
if (normalized === 'help') {
|
|
15
|
+
await context.input.$reply(getDungeonHelp({ locale: context.input.locale,
|
|
16
|
+
formatCommand: path => context.input.formatCommand?.(path, context.owner.id) }));
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
const services = resolveGameServices(context), player = gamePlayerFromInput(input);
|
|
20
|
+
await replyGameOperation({ session: services, player, reply: content => context.input.$reply(content),
|
|
21
|
+
run: () => runDungeonCommand(services, player, action) });
|
|
22
|
+
return true;
|
|
20
23
|
},
|
|
21
24
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Generated by build-plugin-runtime-entries.mjs. Do not edit.
|
|
2
|
+
import { replyGameOperation, buildChoiceFallbackMap, channelKey, gamePlayerFromInput, parseChoicePayload, resolveGameTextPayload, } from '@zhin.js/game-kit';
|
|
2
3
|
import { defineMiddleware } from 'zhin.js/middleware';
|
|
3
|
-
import { buildChoiceFallbackMap, channelKey, messageFromCommandInput, parseChoicePayload, resolveGameTextPayload, } from '@zhin.js/game-kit';
|
|
4
4
|
import { handleDungeonChoice } from "../../lib/game-flow.js";
|
|
5
5
|
import { resolveGameServices } from "../../lib/runtime-store.js";
|
|
6
6
|
import { stateFromSession } from "../../lib/session-service.js";
|
|
@@ -8,19 +8,23 @@ import { DUNGEON_PREFIX, choicesForState, dungeonSessionToken, } from "../../lib
|
|
|
8
8
|
export default defineMiddleware({
|
|
9
9
|
target: 'inbound',
|
|
10
10
|
async handle(context, next) {
|
|
11
|
+
if (!context.input.sender?.id) {
|
|
12
|
+
await next();
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
11
15
|
const raw = context.input.content?.trim() ?? '';
|
|
12
16
|
if (!raw) {
|
|
13
17
|
await next();
|
|
14
18
|
return;
|
|
15
19
|
}
|
|
16
20
|
const service = resolveGameServices(context);
|
|
17
|
-
const message =
|
|
21
|
+
const message = gamePlayerFromInput(context.input);
|
|
18
22
|
const payloadFromText = resolveGameTextPayload(raw);
|
|
19
23
|
if (payloadFromText?.startsWith(`${DUNGEON_PREFIX}:`)) {
|
|
20
24
|
const parsed = parseChoicePayload(payloadFromText, DUNGEON_PREFIX);
|
|
21
25
|
if (parsed) {
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
await replyGameOperation({ session: service, player: message, reply: content => context.input.$reply(content),
|
|
27
|
+
run: () => handleDungeonChoice(service, message, parsed.sessionId, parsed.choiceId) });
|
|
24
28
|
return;
|
|
25
29
|
}
|
|
26
30
|
await next();
|
|
@@ -39,7 +43,7 @@ export default defineMiddleware({
|
|
|
39
43
|
await next();
|
|
40
44
|
return;
|
|
41
45
|
}
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
await replyGameOperation({ session: service, player: message, reply: content => context.input.$reply(content),
|
|
47
|
+
run: () => handleDungeonChoice(service, message, parsed.sessionId, parsed.choiceId) });
|
|
44
48
|
},
|
|
45
49
|
});
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import type { Message } from '@zhin.js/core/runtime';
|
|
2
|
-
import { defineMiddleware } from 'zhin.js/middleware';
|
|
3
1
|
import {
|
|
2
|
+
replyGameOperation,
|
|
4
3
|
buildChoiceFallbackMap,
|
|
5
4
|
channelKey,
|
|
6
|
-
|
|
5
|
+
gamePlayerFromInput,
|
|
7
6
|
parseChoicePayload,
|
|
8
7
|
resolveGameTextPayload,
|
|
9
8
|
} from '@zhin.js/game-kit';
|
|
9
|
+
import type { Message } from '@zhin.js/core/runtime';
|
|
10
|
+
import { defineMiddleware } from 'zhin.js/middleware';
|
|
10
11
|
import { handleDungeonChoice } from '../../src/game-flow.js';
|
|
11
12
|
import { resolveGameServices } from '../../src/runtime-store.js';
|
|
12
13
|
import { stateFromSession } from '../../src/session-service.js';
|
|
@@ -19,24 +20,25 @@ import {
|
|
|
19
20
|
export default defineMiddleware<Message>({
|
|
20
21
|
target: 'inbound',
|
|
21
22
|
async handle(context, next) {
|
|
23
|
+
if (!context.input.sender?.id) { await next(); return; }
|
|
22
24
|
const raw = context.input.content?.trim() ?? '';
|
|
23
25
|
if (!raw) {
|
|
24
26
|
await next();
|
|
25
27
|
return;
|
|
26
28
|
}
|
|
27
29
|
const service = resolveGameServices(context);
|
|
28
|
-
const message =
|
|
30
|
+
const message = gamePlayerFromInput(context.input);
|
|
29
31
|
const payloadFromText = resolveGameTextPayload(raw);
|
|
30
32
|
if (payloadFromText?.startsWith(`${DUNGEON_PREFIX}:`)) {
|
|
31
33
|
const parsed = parseChoicePayload(payloadFromText, DUNGEON_PREFIX);
|
|
32
34
|
if (parsed) {
|
|
33
|
-
|
|
35
|
+
await replyGameOperation({ session: service, player: message, reply: content => context.input.$reply(content),
|
|
36
|
+
run: () => handleDungeonChoice(
|
|
34
37
|
service,
|
|
35
38
|
message,
|
|
36
39
|
parsed.sessionId,
|
|
37
40
|
parsed.choiceId,
|
|
38
|
-
);
|
|
39
|
-
await context.input.$reply(reply);
|
|
41
|
+
) });
|
|
40
42
|
return;
|
|
41
43
|
}
|
|
42
44
|
await next();
|
|
@@ -60,12 +62,12 @@ export default defineMiddleware<Message>({
|
|
|
60
62
|
await next();
|
|
61
63
|
return;
|
|
62
64
|
}
|
|
63
|
-
|
|
65
|
+
await replyGameOperation({ session: service, player: message, reply: content => context.input.$reply(content),
|
|
66
|
+
run: () => handleDungeonChoice(
|
|
64
67
|
service,
|
|
65
68
|
message,
|
|
66
69
|
parsed.sessionId,
|
|
67
70
|
parsed.choiceId,
|
|
68
|
-
);
|
|
69
|
-
await context.input.$reply(reply);
|
|
71
|
+
) });
|
|
70
72
|
},
|
|
71
73
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/plugin-dungeon-expedition",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.20",
|
|
4
4
|
"description": "Zhin.js multiplayer deterministic dungeon expedition",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -23,13 +23,13 @@
|
|
|
23
23
|
],
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@zhin.js/core": "1.1.
|
|
27
|
-
"@zhin.js/game-kit": "1.1.
|
|
26
|
+
"@zhin.js/core": "1.1.55",
|
|
27
|
+
"@zhin.js/game-kit": "1.1.20"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"typescript": "^6.0.3",
|
|
31
31
|
"vitest": "^4.1.10",
|
|
32
|
-
"zhin.js": "1.1.
|
|
32
|
+
"zhin.js": "1.1.20"
|
|
33
33
|
},
|
|
34
34
|
"repository": {
|
|
35
35
|
"type": "git",
|
|
@@ -66,9 +66,9 @@
|
|
|
66
66
|
"plugins": []
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
|
-
"@zhin.js/command": "^1.1.
|
|
70
|
-
"@zhin.js/middleware": "^1.1.
|
|
71
|
-
"zhin.js": "^1.1.
|
|
69
|
+
"@zhin.js/command": "^1.1.13",
|
|
70
|
+
"@zhin.js/middleware": "^1.1.12",
|
|
71
|
+
"zhin.js": "^1.1.20"
|
|
72
72
|
},
|
|
73
73
|
"peerDependenciesMeta": {
|
|
74
74
|
"@zhin.js/command": {
|
package/src/dungeon-command.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createMessages } from 'zhin.js/i18n';
|
|
2
|
-
import { gameCommandHint, channelKey, type
|
|
2
|
+
import { gameCommandHint, channelKey, type GamePlayer, type GameReply } from '@zhin.js/game-kit';
|
|
3
3
|
import {
|
|
4
4
|
continueDungeon,
|
|
5
5
|
handleDungeonChoice,
|
|
@@ -20,7 +20,7 @@ const messages = createMessages({
|
|
|
20
20
|
abort: { 'zh-CN': '队长结束远征', en: 'Leader ends the expedition' },
|
|
21
21
|
empty: { 'zh-CN': '当前频道没有远征队。', en: 'This channel has no expedition party.' },
|
|
22
22
|
});
|
|
23
|
-
export function getDungeonHelp(message: Pick<
|
|
23
|
+
export function getDungeonHelp(message: Pick<GamePlayer, 'locale' | 'formatCommand'> = {}): string {
|
|
24
24
|
const command = message.formatCommand?.('dungeon');
|
|
25
25
|
const actions = ['start', 'join', 'ready', 'go', 'explore', 'attack', 'defend', 'potion', 'status', 'abort'] as const;
|
|
26
26
|
return [messages(message.locale, 'title'), ...(command === undefined ? [] : actions.map(action => `${command} ${action} — ${messages(message.locale, action)}`))].join('\n');
|
|
@@ -65,20 +65,22 @@ export function normalizeDungeonAction(action: string): string | null {
|
|
|
65
65
|
|
|
66
66
|
export async function runDungeonCommand(
|
|
67
67
|
service: SessionService,
|
|
68
|
-
message:
|
|
68
|
+
message: GamePlayer,
|
|
69
69
|
rawAction: string,
|
|
70
70
|
): Promise<GameReply> {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
return service.runInScope({ scope: channelKey(message), run: async () => {
|
|
72
|
+
const action = normalizeDungeonAction(rawAction);
|
|
73
|
+
if (!action || action === 'help') return getDungeonHelp(message);
|
|
74
|
+
if (action === 'create') return startDungeon(service, message);
|
|
75
|
+
if (action === 'status') return continueDungeon(service, message);
|
|
75
76
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
77
|
+
const session = await service.getActiveByChannel(channelKey(message));
|
|
78
|
+
if (!session) return messages(message.locale, 'empty') + gameCommandHint(message, 'dungeon');
|
|
79
|
+
return handleDungeonChoice(
|
|
80
|
+
service,
|
|
81
|
+
message,
|
|
82
|
+
dungeonSessionToken(session),
|
|
83
|
+
action,
|
|
84
|
+
);
|
|
85
|
+
} });
|
|
84
86
|
}
|
package/src/game-flow.ts
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
GameSessionConflictError,
|
|
4
4
|
SessionRevisionConflictError,
|
|
5
5
|
channelKey,
|
|
6
|
-
type
|
|
6
|
+
type GamePlayer,
|
|
7
7
|
type GameReply,
|
|
8
8
|
} from '@zhin.js/game-kit';
|
|
9
9
|
import {
|
|
@@ -22,81 +22,87 @@ import {
|
|
|
22
22
|
|
|
23
23
|
export async function startDungeon(
|
|
24
24
|
service: SessionService,
|
|
25
|
-
message:
|
|
25
|
+
message: GamePlayer,
|
|
26
26
|
): Promise<GameReply> {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
return service.runInScope({ scope: channelKey(message), run: async () => {
|
|
28
|
+
const active = await service.getActiveByChannel(channelKey(message));
|
|
29
|
+
if (active) return buildDungeonView(active, stateFromSession(active), message.target.kind);
|
|
30
|
+
try {
|
|
31
|
+
const session = await service.createSession(message);
|
|
32
|
+
return buildDungeonView(session, stateFromSession(session), message.target.kind);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
if (error instanceof GameSessionConflictError) return error.format(message.locale);
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
} });
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
export async function continueDungeon(
|
|
39
41
|
service: SessionService,
|
|
40
|
-
message:
|
|
42
|
+
message: GamePlayer,
|
|
41
43
|
): Promise<GameReply> {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
return service.runInScope({ scope: channelKey(message), run: async () => {
|
|
45
|
+
const locale = resolveLocale(message.locale);
|
|
46
|
+
const session = await service.getActiveByChannel(channelKey(message));
|
|
47
|
+
if (!session) return messages(locale, 'text1');
|
|
48
|
+
return buildDungeonView(session, stateFromSession(session), message.target.kind);
|
|
49
|
+
} });
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
export async function handleDungeonChoice(
|
|
49
53
|
service: SessionService,
|
|
50
|
-
message:
|
|
54
|
+
message: GamePlayer,
|
|
51
55
|
sessionToken: string,
|
|
52
56
|
choiceId: string,
|
|
53
57
|
): Promise<GameReply> {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
} catch (error) {
|
|
84
|
-
if (error instanceof DungeonRuleError) return error.message;
|
|
85
|
-
if (error instanceof GameSessionConflictError) return error.format(locale);
|
|
86
|
-
if (error instanceof SessionRevisionConflictError) {
|
|
87
|
-
const latest = await service.getById(session.id);
|
|
88
|
-
if (!latest) return messages(locale, 'text7');
|
|
89
|
-
const view = buildDungeonView(
|
|
90
|
-
latest,
|
|
91
|
-
stateFromSession(latest),
|
|
92
|
-
message.$channel.type,
|
|
58
|
+
return service.runInScope({ scope: channelKey(message), run: async () => {
|
|
59
|
+
let locale = resolveLocale(message.locale);
|
|
60
|
+
const token = parseDungeonSessionToken(sessionToken);
|
|
61
|
+
if (!token) return messages(locale, 'text2');
|
|
62
|
+
const session = await service.getById(token.sessionId);
|
|
63
|
+
if (!session || session.channel_key !== channelKey(message)) {
|
|
64
|
+
return messages(locale, 'text3');
|
|
65
|
+
}
|
|
66
|
+
locale = resolveLocale(session.locale);
|
|
67
|
+
if (choiceId === 'restart') {
|
|
68
|
+
if (session.status === 'active') return messages(locale, 'text4');
|
|
69
|
+
if (session.owner_id !== message.sender.id) return messages(locale, 'text5');
|
|
70
|
+
return startDungeon(service, message);
|
|
71
|
+
}
|
|
72
|
+
const action = actionFromChoice(choiceId, message);
|
|
73
|
+
if (!action) return messages(locale, 'text6');
|
|
74
|
+
try {
|
|
75
|
+
const result = await service.performAction({
|
|
76
|
+
sessionId: session.id,
|
|
77
|
+
actorId: message.sender.id,
|
|
78
|
+
actorName: message.sender.name?.trim() || message.sender.id,
|
|
79
|
+
action,
|
|
80
|
+
expectedRevision: token.revision,
|
|
81
|
+
actionId: `${session.id}:${token.revision}:${message.sender.id}:${choiceId}`,
|
|
82
|
+
});
|
|
83
|
+
return buildDungeonView(
|
|
84
|
+
result.session,
|
|
85
|
+
stateFromSession(result.session),
|
|
86
|
+
message.target.kind,
|
|
93
87
|
);
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
88
|
+
} catch (error) {
|
|
89
|
+
if (error instanceof DungeonRuleError) return error.message;
|
|
90
|
+
if (error instanceof GameSessionConflictError) return error.format(locale);
|
|
91
|
+
if (error instanceof SessionRevisionConflictError) {
|
|
92
|
+
const latest = await service.getById(session.id);
|
|
93
|
+
if (!latest) return messages(locale, 'text7');
|
|
94
|
+
const view = buildDungeonView(
|
|
95
|
+
latest,
|
|
96
|
+
stateFromSession(latest),
|
|
97
|
+
message.target.kind,
|
|
98
|
+
);
|
|
99
|
+
return Array.isArray(view)
|
|
100
|
+
? [messages(locale, 'text8'), ...view]
|
|
101
|
+
: [messages(locale, 'text8'), view];
|
|
102
|
+
}
|
|
103
|
+
throw error;
|
|
97
104
|
}
|
|
98
|
-
|
|
99
|
-
}
|
|
105
|
+
} });
|
|
100
106
|
}
|
|
101
107
|
|
|
102
108
|
export function commandActionId(
|
|
@@ -109,12 +115,12 @@ export function commandActionId(
|
|
|
109
115
|
|
|
110
116
|
function actionFromChoice(
|
|
111
117
|
choiceId: string,
|
|
112
|
-
message:
|
|
118
|
+
message: GamePlayer,
|
|
113
119
|
): DungeonAction | null {
|
|
114
120
|
if (choiceId === 'join') {
|
|
115
121
|
return {
|
|
116
122
|
type: 'join',
|
|
117
|
-
name: message
|
|
123
|
+
name: message.sender.name?.trim() || message.sender.id,
|
|
118
124
|
};
|
|
119
125
|
}
|
|
120
126
|
if (choiceId === 'ready') return { type: 'ready' };
|
package/src/session-service.ts
CHANGED
|
@@ -2,9 +2,8 @@ import type { Database, Models } from '@zhin.js/core';
|
|
|
2
2
|
import {
|
|
3
3
|
DeterministicRandom,
|
|
4
4
|
VersionedSessionService,
|
|
5
|
-
channelKey,
|
|
6
5
|
generateCompactId,
|
|
7
|
-
type
|
|
6
|
+
type GamePlayer,
|
|
8
7
|
type GameOutcome,
|
|
9
8
|
type GameSessionDatabase,
|
|
10
9
|
type SessionMutationResult,
|
|
@@ -41,35 +40,33 @@ export class SessionService extends VersionedSessionService<DungeonSessionRow> {
|
|
|
41
40
|
}
|
|
42
41
|
|
|
43
42
|
async createSession(
|
|
44
|
-
message:
|
|
43
|
+
message: GamePlayer,
|
|
45
44
|
seed?: string | number,
|
|
46
45
|
): Promise<DungeonSessionRow> {
|
|
47
46
|
const now = Date.now();
|
|
48
47
|
const id = generateCompactId('dng_');
|
|
49
|
-
const ownerName = message
|
|
50
|
-
const state = createDungeonState(message
|
|
48
|
+
const ownerName = message.sender.name?.trim() || message.sender.id;
|
|
49
|
+
const state = createDungeonState(message.sender.id, ownerName, message.locale);
|
|
51
50
|
const random = DeterministicRandom.fromSeed(seed ?? id);
|
|
52
51
|
return this.createRow({
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
updated_at: now,
|
|
72
|
-
created_at: now,
|
|
52
|
+
target: message.target,
|
|
53
|
+
fields: {
|
|
54
|
+
id,
|
|
55
|
+
locale: message.locale ?? 'zh-CN',
|
|
56
|
+
owner_id: message.sender.id,
|
|
57
|
+
owner_name: ownerName,
|
|
58
|
+
state_json: JSON.stringify(state),
|
|
59
|
+
phase: state.phase,
|
|
60
|
+
turn: activePlayer(state)?.id ?? '',
|
|
61
|
+
rng_state: random.state,
|
|
62
|
+
schema_version: state.schemaVersion,
|
|
63
|
+
revision: 0,
|
|
64
|
+
processed_actions: '[]',
|
|
65
|
+
deadline_at: now + 5 * 60_000,
|
|
66
|
+
status: 'active',
|
|
67
|
+
updated_at: now,
|
|
68
|
+
created_at: now,
|
|
69
|
+
},
|
|
73
70
|
});
|
|
74
71
|
}
|
|
75
72
|
|