mioku-plugin-mc 3.0.0 → 4.0.0

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/index.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { definePlugin, type MiokiContext } from "mioki";
2
- import type { AIService, ConfigService } from "mioku";
1
+ import { definePlugin, type MiokuContext } from "mioku";
2
+ import { getService, Services } from "mioku";
3
3
  import { createConfigHandler } from "./utils/config-handler";
4
4
  import { createPlayConfigHandler } from "./play/config";
5
5
  import { createPlayManager } from "./play";
6
- import { setMcPlayState } from "./play/runtime";
6
+ import { createMcSkill } from "./skills/mc";
7
7
  import { handleDebugCommand } from "./play/debug/commands";
8
8
  import { createServerManager } from "./utils/server-manager";
9
9
  import { parseMcCommand } from "./utils/command-router";
@@ -24,8 +24,8 @@ export default definePlugin({
24
24
  version: "1.0.0",
25
25
  description: "Minecraft服务器与QQ群消息互通插件",
26
26
 
27
- async setup(ctx: MiokiContext) {
28
- const configService = ctx.services?.config as ConfigService | undefined;
27
+ async setup(ctx: MiokuContext) {
28
+ const configService = getService(ctx, Services.Config);
29
29
 
30
30
  const configHandler = createConfigHandler(configService);
31
31
  await configHandler.register();
@@ -35,7 +35,7 @@ export default definePlugin({
35
35
  const playConfigHandler = createPlayConfigHandler(configService);
36
36
  await playConfigHandler.register();
37
37
 
38
- const aiService = ctx.services?.ai as AIService | undefined;
38
+ const aiService = getService(ctx, Services.AI);
39
39
 
40
40
  const playManager = createPlayManager({
41
41
  ctx,
@@ -44,9 +44,12 @@ export default definePlugin({
44
44
  playConfigHandler,
45
45
  syncConfigHandler: configHandler,
46
46
  });
47
- setMcPlayState({ playManager });
48
47
  ctx.logger.info("Minecraft 游玩子系统已就绪");
49
48
 
49
+ if (aiService) {
50
+ aiService.registerSkill(createMcSkill(playManager));
51
+ }
52
+
50
53
  const serverManager = createServerManager(
51
54
  (serverName, status) => {
52
55
  ctx.logger.info(`[MC] 服务器 ${serverName} 状态: ${status}`);
@@ -61,16 +64,20 @@ export default definePlugin({
61
64
 
62
65
  serverManager.startServers(config);
63
66
 
64
- ctx.handle("message", async (event: any) => {
67
+ ctx.handle("message", async (event) => {
65
68
  const text = ctx.text(event).trim();
69
+ const groupId =
70
+ "group_id" in event && typeof event.group_id === "number"
71
+ ? event.group_id
72
+ : undefined;
66
73
 
67
- if (event.group_id) {
74
+ if (groupId) {
68
75
  const reply = await handleDebugCommand({
69
76
  text,
70
77
  isOwner: ctx.isOwner?.(event) ?? false,
71
78
  debugEnabled: playConfigHandler.getConfig().debug.enabled,
72
79
  playManager,
73
- groupId: Number(event.group_id),
80
+ groupId: Number(groupId),
74
81
  });
75
82
  if (reply !== null) {
76
83
  await event.reply(reply);
@@ -81,7 +88,7 @@ export default definePlugin({
81
88
  const parsed = parseMcCommand(text);
82
89
 
83
90
  if (!parsed || parsed.action === "") {
84
- if (event.group_id) {
91
+ if (groupId) {
85
92
  playManager.onQqMessage(event);
86
93
  await forwardToMc(ctx, event, config, configHandler, serverManager);
87
94
  }
@@ -90,7 +97,9 @@ export default definePlugin({
90
97
 
91
98
  switch (parsed.action) {
92
99
  case "状态": {
93
- await handleStatus(serverManager, config, (msg) => event.reply(msg));
100
+ await handleStatus(serverManager, config, async (msg) => {
101
+ await event.reply(msg);
102
+ });
94
103
  break;
95
104
  }
96
105
  case "开启同步": {
@@ -101,7 +110,9 @@ export default definePlugin({
101
110
  serverManager,
102
111
  configHandler,
103
112
  config,
104
- (msg) => event.reply(msg),
113
+ async (msg) => {
114
+ await event.reply(msg);
115
+ },
105
116
  );
106
117
  break;
107
118
  }
@@ -113,13 +124,17 @@ export default definePlugin({
113
124
  serverManager,
114
125
  configHandler,
115
126
  config,
116
- (msg) => event.reply(msg),
127
+ async (msg) => {
128
+ await event.reply(msg);
129
+ },
117
130
  );
118
131
  break;
119
132
  }
120
133
  case "重连": {
121
134
  if (ctx.isOwner?.(event)) {
122
- await handleReconnect(serverManager, (msg) => event.reply(msg));
135
+ await handleReconnect(serverManager, async (msg) => {
136
+ await event.reply(msg);
137
+ });
123
138
  }
124
139
  break;
125
140
  }
@@ -131,13 +146,14 @@ export default definePlugin({
131
146
  return async () => {
132
147
  serverManager.stopServers();
133
148
  await playManager.dispose();
149
+ if (aiService) aiService.removeSkill("mc");
134
150
  ctx.logger.info("Minecraft插件已卸载");
135
151
  };
136
152
  },
137
153
  });
138
154
 
139
155
  async function handleMcEvent(
140
- ctx: MiokiContext,
156
+ ctx: MiokuContext,
141
157
  event: McEvent,
142
158
  config: McConfig,
143
159
  configHandler: ReturnType<typeof createConfigHandler>,
@@ -158,12 +174,12 @@ async function handleMcEvent(
158
174
  const groups = groupList ? [groupList] : [];
159
175
 
160
176
  for (const botId of bots) {
161
- const bot = ctx.pickBot(Number(botId));
177
+ const bot = ctx.pickBot(botId);
162
178
  if (!bot) continue;
163
179
 
164
180
  for (const groupId of groups) {
165
181
  try {
166
- await bot.sendGroupMsg(Number(groupId), messageText);
182
+ await bot.sendMessage({ type: "group", group_id: groupId}, messageText);
167
183
  } catch (err) {
168
184
  ctx.logger.error(`[MC] 发送消息到群 ${groupId} 失败: ${err}`);
169
185
  }
@@ -172,7 +188,7 @@ async function handleMcEvent(
172
188
  }
173
189
 
174
190
  async function forwardToMc(
175
- ctx: MiokiContext,
191
+ ctx: MiokuContext,
176
192
  event: any,
177
193
  config: McConfig,
178
194
  configHandler: ReturnType<typeof createConfigHandler>,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mioku-plugin-mc",
3
- "version": "3.0.0",
3
+ "version": "4.0.0",
4
4
  "description": "Minecraft与QQ群消息互通插件,支持服务器状态监控与RCON命令",
5
5
  "main": "index.ts",
6
6
  "type": "module",
@@ -71,11 +71,9 @@
71
71
  "zod": "^3.24.1"
72
72
  },
73
73
  "peerDependencies": {
74
- "mioku": "^0.8.0",
75
- "mioki": "^0.16.0"
74
+ "mioku": "^1.0.0"
76
75
  },
77
76
  "devDependencies": {
78
- "mioku": "workspace:*",
79
- "mioki": "^0.16.0"
77
+ "mioku": "workspace:*"
80
78
  }
81
79
  }
@@ -67,7 +67,7 @@ export class ActionRegistry {
67
67
  .map(
68
68
  (issue) => `${issue.path.join(".") || "params"}: ${issue.message}`,
69
69
  )
70
- .join("; "),
70
+ .join("); "),
71
71
  meta,
72
72
  );
73
73
  }
package/play/context.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { MiokiContext } from "mioki";
1
+ import type { MiokuContext } from "mioku";
2
2
  import type { AIService, AIInstance, ConfigService } from "mioku";
3
3
  import type { PlayConfig } from "./types";
4
4
  import type { ConfigHandler } from "../utils/config-handler";
@@ -6,7 +6,7 @@ import type { WorkSubroutine, WorkTerminator } from "./ai/work-subroutine";
6
6
  import type { PlaySession } from "./session";
7
7
 
8
8
  export interface PlayPluginContext {
9
- ctx: MiokiContext;
9
+ ctx: MiokuContext;
10
10
  config: PlayConfig;
11
11
  aiService: AIService | undefined;
12
12
  configService: ConfigService | undefined;
package/play/index.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { MiokiContext } from "mioki";
1
+ import type { MiokuContext } from "mioku";
2
2
  import type { AIService, AIInstance, ConfigService } from "mioku";
3
3
  import type { ConfigHandler } from "../utils/config-handler";
4
4
  import type { PlayPluginContext } from "./context";
@@ -17,7 +17,7 @@ import { SelfDefenseBehavior } from "./behavior/catalog/defend";
17
17
  import type { GroupBinding, PlayServerConfig } from "./types";
18
18
 
19
19
  export interface PlayManagerOptions {
20
- ctx: MiokiContext;
20
+ ctx: MiokuContext;
21
21
  aiService: AIService | undefined;
22
22
  configService: ConfigService | undefined;
23
23
  playConfigHandler: PlayConfigHandler;
@@ -36,7 +36,7 @@ export interface PlayExitResult {
36
36
  }
37
37
 
38
38
  export class PlayManager {
39
- private readonly ctx: MiokiContext;
39
+ private readonly ctx: MiokuContext;
40
40
  private readonly aiService: AIService | undefined;
41
41
  private readonly configService: ConfigService | undefined;
42
42
  private readonly playConfigHandler: PlayConfigHandler;
@@ -88,7 +88,7 @@ export class TaskRegistry {
88
88
  ok: false,
89
89
  error: `invalid_params: ${result.error.issues
90
90
  .map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`)
91
- .join("; ")}`,
91
+ .join("); ")}`,
92
92
  };
93
93
  }
94
94
  return { ok: true, params: result.data };
package/play/session.ts CHANGED
@@ -242,7 +242,7 @@ export class PlaySession {
242
242
  const bot = ctx.ctx.pickBot(this.binding.botSelfId);
243
243
  if (!bot) return;
244
244
  try {
245
- await bot.sendGroupMsg(this.binding.groupId, message);
245
+ await bot.sendMessage({ type: "group", group_id: this.binding.groupId}, message);
246
246
  } catch (err) {
247
247
  ctx.ctx.logger.error(`[MC/play] 发送 QQ 通知失败: ${err}`);
248
248
  }
@@ -264,7 +264,7 @@ export class PlaySession {
264
264
  const bot = ctx.ctx.pickBot(this.binding.botSelfId);
265
265
  if (!bot) return false;
266
266
  try {
267
- await bot.sendGroupMsg(this.binding.groupId, message);
267
+ await bot.sendMessage({ type: "group", group_id: this.binding.groupId}, message);
268
268
  return true;
269
269
  } catch (err) {
270
270
  ctx.ctx.logger.error(`[MC/play] 发送 QQ 消息失败: ${err}`);
package/skills/mc.ts ADDED
@@ -0,0 +1,58 @@
1
+ import type { AISkill } from "mioku";
2
+ import type { PlayManager } from "../play";
3
+
4
+ export function createMcSkill(playManager: PlayManager): AISkill {
5
+ return {
6
+ name: "mc",
7
+ description:
8
+ "让机器人进入或离开 Minecraft 服务器,让它可以与玩家一起游玩。进入后机器人将自主行动(探索、跟随、战斗、收集),直到决定离开或时间耗尽。",
9
+ permission: "admin",
10
+ tools: [
11
+ {
12
+ name: "control_bot",
13
+ description:
14
+ "进入或退出 Minecraft 服务器。action='enter' + serverId 加入服务器;action='exit' 退出。机器人进入后会自主决定行为。仅在群管理员要求或继续游戏有意义时调用。",
15
+ parameters: {
16
+ type: "object",
17
+ properties: {
18
+ action: {
19
+ type: "string",
20
+ enum: ["enter", "exit"],
21
+ description: "'enter' 加入服务器,'exit' 退出当前服务器",
22
+ },
23
+ serverId: {
24
+ type: "string",
25
+ description: "要进入的服务器 ID。enter 时需要,exit 时忽略。",
26
+ },
27
+ },
28
+ required: ["action"],
29
+ },
30
+ handler: async (args: any, runtimeCtx?: any) => {
31
+ const event = runtimeCtx?.event || runtimeCtx?.rawEvent;
32
+ const groupId = Number(event?.group_id);
33
+ if (!Number.isFinite(groupId) || groupId <= 0) {
34
+ return { error: "无法识别当前群,请在群聊中调用" };
35
+ }
36
+
37
+ const action = String(args?.action ?? "").toLowerCase();
38
+ if (action === "exit") {
39
+ const r = await playManager.exit(groupId);
40
+ return { success: r.success, message: r.message };
41
+ }
42
+
43
+ if (action !== "enter") {
44
+ return { error: `未知 action: ${action}` };
45
+ }
46
+
47
+ const serverId = String(args?.serverId ?? "").trim();
48
+ if (!serverId) return { error: "缺少 serverId" };
49
+
50
+ const r = await playManager.enter(groupId, serverId);
51
+ return r.success
52
+ ? { success: true, serverId: r.serverId, message: r.message }
53
+ : { error: r.message };
54
+ },
55
+ },
56
+ ],
57
+ };
58
+ }
package/play/runtime.ts DELETED
@@ -1,14 +0,0 @@
1
- import { getPluginRuntimeState, setPluginRuntimeState } from "mioku";
2
- import type { PlayManager } from "./index";
3
-
4
- export interface McPlayRuntimeState {
5
- playManager?: PlayManager;
6
- }
7
-
8
- export function getMcPlayState(): McPlayRuntimeState {
9
- return getPluginRuntimeState("mc") as McPlayRuntimeState;
10
- }
11
-
12
- export function setMcPlayState(state: McPlayRuntimeState): void {
13
- setPluginRuntimeState("mc", state);
14
- }
package/skills.ts DELETED
@@ -1,63 +0,0 @@
1
- import type { AISkill } from "mioku";
2
- import { getMcPlayState } from "./play/runtime";
3
-
4
- const skill: AISkill = {
5
- name: "mc",
6
- description:
7
- "Let the bot enter or leave a Minecraft server so it can play alongside players. " +
8
- "The bot will then act on its own (explore, follow, fight, gather) until it decides to leave or its time runs out.",
9
- permission: "admin",
10
- tools: [
11
- {
12
- name: "control_bot",
13
- description:
14
- "Enter or exit a Minecraft server. Use action='enter' with a serverId to join; action='exit' to leave. " +
15
- "The bot autonomously decides its behavior once inside. Only call this when a group admin asks for it " +
16
- "or when continuing play makes sense.",
17
- parameters: {
18
- type: "object",
19
- properties: {
20
- action: {
21
- type: "string",
22
- enum: ["enter", "exit"],
23
- description: "'enter' to join a server, 'exit' to leave the current one.",
24
- },
25
- serverId: {
26
- type: "string",
27
- description: "The server id to enter. Required for 'enter', ignored for 'exit'.",
28
- },
29
- },
30
- required: ["action"],
31
- },
32
- handler: async (args: any, event?: any) => {
33
- const pm = getMcPlayState().playManager;
34
- if (!pm) return { error: "mc 游玩子系统未就绪" };
35
-
36
- const groupId = Number(event?.group_id);
37
- if (!Number.isFinite(groupId) || groupId <= 0) {
38
- return { error: "无法识别当前群,请在群聊中调用" };
39
- }
40
-
41
- const action = String(args?.action ?? "").toLowerCase();
42
- if (action === "exit") {
43
- const r = await pm.exit(groupId);
44
- return { success: r.success, message: r.message };
45
- }
46
-
47
- if (action !== "enter") {
48
- return { error: `未知 action: ${action}` };
49
- }
50
-
51
- const serverId = String(args?.serverId ?? "").trim();
52
- if (!serverId) return { error: "缺少 serverId" };
53
-
54
- const r = await pm.enter(groupId, serverId);
55
- return r.success
56
- ? { success: true, serverId: r.serverId, message: r.message }
57
- : { error: r.message };
58
- },
59
- },
60
- ],
61
- };
62
-
63
- export default skill;