koishi-plugin-minecraft-search 1.3.9 → 2.0.1

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/lib/index.d.ts CHANGED
@@ -2,20 +2,33 @@ import { Context, Schema } from 'koishi';
2
2
  export declare const name = "minecraft-search";
3
3
  export interface ServerConfig {
4
4
  id: number;
5
+ userId: string;
6
+ groupId: string;
5
7
  name: string;
6
8
  host: string;
9
+ port: number;
10
+ serverType: 'java' | 'bedrock';
11
+ timeout: number;
7
12
  minekuaiInstanceId?: string;
8
- timeout?: number;
9
- serverType?: 'java' | 'bedrock';
13
+ }
14
+ export interface ApiKeyConfig {
15
+ id: number;
16
+ userId: string;
17
+ groupId: string;
18
+ apiKey: string;
10
19
  }
11
20
  export interface Config {
12
- servers: ServerConfig[];
13
- minekuaiSettings: MinekuaiSettings;
21
+ minekuaiApiUrl: string;
14
22
  showIpInDetail: boolean;
15
23
  }
16
- export interface MinekuaiSettings {
17
- apiUrl: string;
18
- apiKey: string;
19
- }
20
24
  export declare const Config: Schema<Config>;
25
+ export declare const inject: {
26
+ required: string[];
27
+ };
28
+ declare module 'koishi' {
29
+ interface Tables {
30
+ minecraft_server: ServerConfig;
31
+ minecraft_api_key: ApiKeyConfig;
32
+ }
33
+ }
21
34
  export declare function apply(ctx: Context, config: Config): void;
package/lib/index.js CHANGED
@@ -32,6 +32,7 @@ var src_exports = {};
32
32
  __export(src_exports, {
33
33
  Config: () => Config,
34
34
  apply: () => apply,
35
+ inject: () => inject,
35
36
  name: () => name
36
37
  });
37
38
  module.exports = __toCommonJS(src_exports);
@@ -43,26 +44,39 @@ import("mc-server-util").then((m) => {
43
44
  var name = "minecraft-search";
44
45
  var Config = import_koishi.Schema.intersect([
45
46
  import_koishi.Schema.object({
46
- servers: import_koishi.Schema.array(import_koishi.Schema.object({
47
- id: import_koishi.Schema.number().required().description("服务器ID"),
48
- name: import_koishi.Schema.string().required().description("服务器名称"),
49
- host: import_koishi.Schema.string().required().description("服务器地址"),
50
- serverType: import_koishi.Schema.union(["java", "bedrock"]).default("java").description("服务器类型"),
51
- timeout: import_koishi.Schema.number().default(5).description("查询超时时间(秒)"),
52
- minekuaiInstanceId: import_koishi.Schema.string().description("麦块实例ID (可选)")
53
- })).description("服务器列表").role("table").required()
54
- }).description("服务器配置"),
55
- import_koishi.Schema.object({
56
- minekuaiSettings: import_koishi.Schema.object({
57
- apiUrl: import_koishi.Schema.string().description("麦块API地址").default("https://minekuai.com/api/client"),
58
- apiKey: import_koishi.Schema.string().description("麦块API密钥")
59
- })
60
- }).description("麦块联机配置(可选)"),
47
+ minekuaiApiUrl: import_koishi.Schema.string().description("麦块API地址").default("https://minekuai.com/api/client")
48
+ }).description("麦块联机配置"),
61
49
  import_koishi.Schema.object({
62
50
  showIpInDetail: import_koishi.Schema.boolean().default(true).description("在查询详细状态时显示服务器IP地址")
63
51
  }).description("显示配置")
64
52
  ]);
53
+ var inject = {
54
+ required: ["database"]
55
+ };
65
56
  function apply(ctx, config) {
57
+ ctx.model.extend("minecraft_server", {
58
+ id: "unsigned",
59
+ userId: "string",
60
+ groupId: "string",
61
+ name: "string",
62
+ host: "string",
63
+ port: "integer",
64
+ serverType: "string",
65
+ timeout: "float",
66
+ minekuaiInstanceId: "string"
67
+ }, {
68
+ autoInc: true,
69
+ primary: "id"
70
+ });
71
+ ctx.model.extend("minecraft_api_key", {
72
+ id: "unsigned",
73
+ userId: "string",
74
+ groupId: "string",
75
+ apiKey: "string"
76
+ }, {
77
+ autoInc: true,
78
+ primary: "id"
79
+ });
66
80
  function parseServerAddress(hostString, defaultPort) {
67
81
  if (hostString.includes(":")) {
68
82
  const [host, portStr] = hostString.split(":");
@@ -78,14 +92,16 @@ function apply(ctx, config) {
78
92
  };
79
93
  }
80
94
  __name(parseServerAddress, "parseServerAddress");
81
- async function minekuaiApiRequest(instanceId, operation, maxRetries = 3) {
82
- const { apiUrl, apiKey } = config.minekuaiSettings;
83
- if (!apiKey) throw new Error("麦块API密钥未配置");
84
- if (!apiUrl) throw new Error("麦块API地址未配置");
85
- const baseUrl = apiUrl.replace(/\/+$/, "");
95
+ async function minekuaiApiRequest(instanceId, operation, groupId, maxRetries = 3) {
96
+ const apiKeys = await ctx.database.get("minecraft_api_key", { groupId });
97
+ if (!apiKeys || apiKeys.length === 0) {
98
+ throw new Error("本群未配置麦块API密钥,请先使用 绑定密钥 指令");
99
+ }
100
+ const apiKeyRecord = apiKeys[0];
101
+ const baseUrl = config.minekuaiApiUrl.replace(/\/+$/, "");
86
102
  const url = `${baseUrl}/servers/${instanceId}/power`;
87
103
  const headers = {
88
- "Authorization": `Bearer ${apiKey}`,
104
+ "Authorization": `Bearer ${apiKeyRecord.apiKey}`,
89
105
  "Content-Type": "application/json",
90
106
  "Accept": "application/json"
91
107
  };
@@ -112,8 +128,7 @@ function apply(ctx, config) {
112
128
  if (!getMinecraftServerStatus) {
113
129
  throw new Error("mc-server-util 模块未正确加载");
114
130
  }
115
- const defaultPort = server.serverType === "bedrock" ? 19132 : 25565;
116
- const { host, port } = parseServerAddress(server.host, defaultPort);
131
+ const { host, port } = parseServerAddress(server.host, server.port || 25565);
117
132
  const timeout = (server.timeout || 5) * 1e3;
118
133
  let result;
119
134
  if (server.serverType === "bedrock") {
@@ -137,6 +152,7 @@ function apply(ctx, config) {
137
152
  errorMessage = errorMessage.replace(/getaddrinfo EAI_AGAIN/i, "网络波动,请稍后尝试");
138
153
  errorMessage = errorMessage.replace(/\s+(\d+\.\d+\.\d+\.\d+):\d+/, "");
139
154
  errorMessage = errorMessage.replace(/\s+[\w.-]+$/, "");
155
+ errorMessage = errorMessage.replace(/\s+[a-zA-Z0-9][a-zA-Z0-9.-]*:[0-9]+/, "");
140
156
  return {
141
157
  success: false,
142
158
  error: errorMessage,
@@ -145,22 +161,24 @@ function apply(ctx, config) {
145
161
  }
146
162
  }
147
163
  __name(queryServerStatus, "queryServerStatus");
164
+ function getServerName(server) {
165
+ return server.name || "Minecraft 服务器";
166
+ }
167
+ __name(getServerName, "getServerName");
148
168
  function formatShortStatus(result, server) {
169
+ const displayName = getServerName(server);
149
170
  if (!result.online) {
150
- return `🔴 ${server.name} - 离线`;
171
+ return `🔴 ${displayName} - 离线`;
151
172
  }
152
173
  const players = result.players ? `${result.players.online}/${result.players.max}` : "N/A";
153
174
  const version = result.version ? result.version.name : "N/A";
154
- return `🟢 ${server.name} - 在线 | 玩家: ${players} | 版本: ${version}`;
175
+ return `🟢 ${displayName} - 在线 | 玩家: ${players} | 版本: ${version}`;
155
176
  }
156
177
  __name(formatShortStatus, "formatShortStatus");
157
178
  function formatDetailedStatus(result, server, showIp) {
179
+ const displayName = getServerName(server);
158
180
  if (!result.online) {
159
- if (showIp) {
160
- return `🔴 服务器 ${server.name} (${server.host}) 当前离线`;
161
- } else {
162
- return `🔴 服务器 ${server.name} 当前离线`;
163
- }
181
+ return `🔴 ${displayName} 当前离线`;
164
182
  }
165
183
  let motdText = "暂无描述";
166
184
  if (result.description) {
@@ -179,11 +197,10 @@ function apply(ctx, config) {
179
197
  descriptionStr = descriptionStr.replace(/§[0-9a-fk-or]/gi, "");
180
198
  motdText = descriptionStr.replace(/\n/g, " ").replace(/\s+/g, " ").trim();
181
199
  }
182
- let message = `🟢 ${server.name} 状态信息
200
+ let message = `🟢 ${displayName} 状态信息
183
201
  `;
184
202
  if (showIp) {
185
- const defaultPort = server.serverType === "bedrock" ? 19132 : 25565;
186
- const { host, port } = parseServerAddress(server.host, defaultPort);
203
+ const { host, port } = parseServerAddress(server.host, server.port || 25565);
187
204
  message += `📡 地址: ${host}:${port}
188
205
  `;
189
206
  }
@@ -208,12 +225,13 @@ function apply(ctx, config) {
208
225
  return message;
209
226
  }
210
227
  __name(formatDetailedStatus, "formatDetailedStatus");
211
- ctx.command("mc/查服 [id:number]", "查询Minecraft服务器状态").action(async ({ session }, id) => {
212
- if (id === void 0) {
213
- if (config.servers.length === 0) {
214
- return "❌ 未配置任何服务器";
228
+ ctx.command("mc/查服 [target:text]", "查询Minecraft服务器状态").action(async ({ session }, target) => {
229
+ const servers = await ctx.database.get("minecraft_server", {});
230
+ if (target === void 0) {
231
+ if (servers.length === 0) {
232
+ return "❌ 本群未绑定任何服务器,请先使用 绑定 指令";
215
233
  }
216
- const queries = config.servers.map((server2) => queryServerStatus(server2));
234
+ const queries = servers.map((server) => queryServerStatus(server));
217
235
  const results = await Promise.all(queries);
218
236
  const onlineCount = results.filter((r) => r.success && r.data && r.data.online).length;
219
237
  let message = `📊 服务器状态汇总 (当前在线${onlineCount}/${results.length}台)
@@ -226,77 +244,206 @@ function apply(ctx, config) {
226
244
  message += `[ID:${serverId}] ${originalStatus}
227
245
  `;
228
246
  } else {
229
- message += `[ID:${serverId}] 🔴 ${result2.server.name} - 离线 | 原因:${result2.error}
247
+ message += `[ID:${serverId}] 🔴 ${getServerName(result2.server)} - 离线 | 原因:${result2.error}
230
248
  `;
231
249
  }
232
250
  });
233
251
  message += `
234
- 💡 输入"查服+服务器ID"即可查询详细状态,例如:查服 ${config.servers[0]?.id || 1}`;
252
+ 💡 输入"查服+服务器ID"即可查询详细状态,例如:查服 ${servers[0]?.id || 1}`;
253
+ message += `
254
+ 💡 也可以直接输入IP地址查询`;
235
255
  return message;
236
256
  }
237
- const server = config.servers.find((s) => s.id === id);
257
+ const id = parseInt(target);
258
+ if (!isNaN(id)) {
259
+ const server = servers.find((s) => s.id === id);
260
+ if (server) {
261
+ const result2 = await queryServerStatus(server);
262
+ if (!result2.success) {
263
+ return `🔴 ${getServerName(server)} - 离线 | 原因:${result2.error}`;
264
+ }
265
+ return formatDetailedStatus(result2.data, server, config.showIpInDetail);
266
+ }
267
+ }
268
+ const host = String(target);
269
+ const defaultPort = 25565;
270
+ const { host: parsedHost, port: parsedPort } = parseServerAddress(host, defaultPort);
271
+ const tempServer = {
272
+ id: 0,
273
+ userId: session.userId,
274
+ groupId: session.guildId || "",
275
+ name: parsedHost,
276
+ host: parsedHost,
277
+ port: parsedPort,
278
+ serverType: "java",
279
+ timeout: 5
280
+ };
281
+ const result = await queryServerStatus(tempServer);
282
+ if (!result.success) {
283
+ return `🔴 服务器 - 离线 | 原因:${result.error}`;
284
+ }
285
+ return formatDetailedStatus(result.data, tempServer, config.showIpInDetail);
286
+ });
287
+ ctx.guild().command("mc/绑定 <host:string>", "绑定Minecraft服务器").option("name", "-n <name:string>", { fallback: "" }).option("timeout", "-t <timeout:number>", { fallback: 5 }).option("instance", "-i <instance:string>", { fallback: "" }).action(async ({ session, options }, host) => {
288
+ if (!host) {
289
+ return "请提供服务器地址,例如:绑定+IP地址(不带端口时默认为25565)";
290
+ }
291
+ const groupId = session.guildId;
292
+ const userId = session.userId;
293
+ const defaultPort = 25565;
294
+ const { host: parsedHost, port: parsedPort } = parseServerAddress(host, defaultPort);
295
+ const existingServers = await ctx.database.get("minecraft_server", {
296
+ groupId,
297
+ host: parsedHost,
298
+ port: parsedPort
299
+ });
300
+ if (existingServers.length > 0) {
301
+ return `该服务器已在本群绑定,服务器ID为: ${existingServers[0].id}`;
302
+ }
303
+ const createData = {
304
+ userId,
305
+ groupId,
306
+ host: parsedHost,
307
+ port: parsedPort,
308
+ serverType: "java",
309
+ timeout: options.timeout,
310
+ minekuaiInstanceId: options.instance
311
+ };
312
+ if (options.name) {
313
+ createData.name = options.name;
314
+ }
315
+ await ctx.database.create("minecraft_server", createData);
316
+ const servers = await ctx.database.get("minecraft_server", { groupId });
317
+ const newServer = servers[servers.length - 1];
318
+ return `✅ 服务器绑定成功!
319
+ 服务器ID: ${newServer.id}
320
+ 名称: ${newServer.name || "Minecraft 服务器"}`;
321
+ });
322
+ ctx.guild().command("mc/绑定密钥 <apiKey:string>", "绑定麦块API密钥").action(async ({ session }, apiKey) => {
323
+ if (!apiKey) {
324
+ return "请提供API密钥";
325
+ }
326
+ const groupId = session.guildId;
327
+ const userId = session.userId;
328
+ const existingKeys = await ctx.database.get("minecraft_api_key", { groupId });
329
+ if (existingKeys.length > 0) {
330
+ await ctx.database.set("minecraft_api_key", { groupId }, { apiKey });
331
+ return "✅ API密钥更新成功!";
332
+ }
333
+ await ctx.database.create("minecraft_api_key", {
334
+ userId,
335
+ groupId,
336
+ apiKey
337
+ });
338
+ return "✅ API密钥绑定成功!";
339
+ });
340
+ ctx.guild().command("mc/解绑 <id:number>", "解绑Minecraft服务器").action(async ({ session }, id) => {
341
+ if (!id) {
342
+ return "请提供服务器ID,例如:解绑 1";
343
+ }
344
+ const groupId = session.guildId;
345
+ const servers = await ctx.database.get("minecraft_server", { groupId });
346
+ const server = servers.find((s) => s.id === id);
238
347
  if (!server) {
239
348
  return `❌ 未找到ID为 ${id} 的服务器`;
240
349
  }
241
- const result = await queryServerStatus(server);
242
- if (!result.success) {
243
- return `🔴 服务器 ${server.name} - 离线 | 原因:${result.error}`;
350
+ await ctx.database.remove("minecraft_server", { id });
351
+ return `✅ 服务器 ${server.name} 已解绑`;
352
+ });
353
+ ctx.guild().command("mc/修改 <id:number>", "修改Minecraft服务器信息").option("name", "-n <name:string>", { fallback: "" }).option("timeout", "-t <timeout:number>", { fallback: 0 }).option("instance", "-i <instance:string>", { fallback: "" }).action(async ({ session, options }, id) => {
354
+ if (!id) {
355
+ return "请提供服务器ID,例如:修改 1";
356
+ }
357
+ const groupId = session.guildId;
358
+ const servers = await ctx.database.get("minecraft_server", { groupId });
359
+ const server = servers.find((s) => s.id === id);
360
+ if (!server) {
361
+ return `❌ 未找到ID为 ${id} 的服务器`;
362
+ }
363
+ const updates = {};
364
+ if (options.name) {
365
+ updates.name = options.name;
366
+ }
367
+ if (options.timeout > 0) {
368
+ updates.timeout = options.timeout;
244
369
  }
245
- return formatDetailedStatus(result.data, server, config.showIpInDetail);
370
+ if (options.instance) {
371
+ updates.minekuaiInstanceId = options.instance;
372
+ }
373
+ if (Object.keys(updates).length === 0) {
374
+ return "请提供要修改的参数,使用 -n 指定新名称,-t 指定新超时时间,-i 指定新麦块实例ID";
375
+ }
376
+ await ctx.database.set("minecraft_server", { id }, updates);
377
+ const parts = [];
378
+ if (updates.name) parts.push(`名称: ${updates.name}`);
379
+ if (updates.timeout) parts.push(`超时: ${updates.timeout}秒`);
380
+ if (updates.minekuaiInstanceId) parts.push(`麦块实例ID: ${updates.minekuaiInstanceId}`);
381
+ return `✅ 服务器信息已更新!
382
+ ${parts.join("\n")}`;
246
383
  });
247
- ctx.command("mc/开服 <id:number>", "启动麦块服务器").action(async ({ session }, id) => {
384
+ ctx.guild().command("mc/开服 <id:number>", "启动麦块服务器").action(async ({ session }, id) => {
248
385
  if (!id) return "请提供服务器ID,例如:开服 1";
249
- const server = config.servers.find((s) => s.id === id);
250
- if (!server) return `未找到ID为 ${id} 的服务器`;
386
+ const groupId = session.guildId;
387
+ const servers = await ctx.database.get("minecraft_server", { groupId });
388
+ const server = servers.find((s) => s.id === id);
389
+ if (!server) return `❌ 未找到ID为 ${id} 的服务器,请确保操作的是本群绑定的服务器`;
251
390
  if (!server.minekuaiInstanceId) return `服务器 ${server.name} 未配置麦块实例ID`;
252
391
  try {
253
- await minekuaiApiRequest(server.minekuaiInstanceId, "start", 3);
392
+ await minekuaiApiRequest(server.minekuaiInstanceId, "start", groupId, 3);
254
393
  return `✅ 已发送启动指令到服务器 ${server.name} (ID: ${id})`;
255
394
  } catch (error) {
256
395
  return `❌ 启动服务器 ${server.name} 失败: ${error.message}`;
257
396
  }
258
397
  });
259
- ctx.command("mc/重启 <id:number>", "重启麦块服务器").action(async ({ session }, id) => {
398
+ ctx.guild().command("mc/重启 <id:number>", "重启麦块服务器").action(async ({ session }, id) => {
260
399
  if (!id) return "请提供服务器ID,例如:重启 1";
261
- const server = config.servers.find((s) => s.id === id);
262
- if (!server) return `未找到ID为 ${id} 的服务器`;
400
+ const groupId = session.guildId;
401
+ const servers = await ctx.database.get("minecraft_server", { groupId });
402
+ const server = servers.find((s) => s.id === id);
403
+ if (!server) return `❌ 未找到ID为 ${id} 的服务器,请确保操作的是本群绑定的服务器`;
263
404
  if (!server.minekuaiInstanceId) return `服务器 ${server.name} 未配置麦块实例ID`;
264
405
  try {
265
- await minekuaiApiRequest(server.minekuaiInstanceId, "restart", 3);
406
+ await minekuaiApiRequest(server.minekuaiInstanceId, "restart", groupId, 3);
266
407
  return `✅ 服务器 ${server.name} 重启指令已发送完成,请稍后检查服务器状态`;
267
408
  } catch (error) {
268
409
  return `❌ 重启服务器 ${server.name} 失败: ${error.message}`;
269
410
  }
270
411
  });
271
- ctx.command("mc/强制重启 <id:number>", "强制重启麦块服务器").action(async ({ session }, id) => {
412
+ ctx.guild().command("mc/强制重启 <id:number>", "强制重启麦块服务器").action(async ({ session }, id) => {
272
413
  if (!id) return "请提供服务器ID,例如:强制重启 1";
273
- const server = config.servers.find((s) => s.id === id);
274
- if (!server) return `未找到ID为 ${id} 的服务器`;
414
+ const groupId = session.guildId;
415
+ const servers = await ctx.database.get("minecraft_server", { groupId });
416
+ const server = servers.find((s) => s.id === id);
417
+ if (!server) return `❌ 未找到ID为 ${id} 的服务器,请确保操作的是本群绑定的服务器`;
275
418
  if (!server.minekuaiInstanceId) return `服务器 ${server.name} 未配置麦块实例ID`;
276
419
  try {
277
- await minekuaiApiRequest(server.minekuaiInstanceId, "stop", 3);
420
+ await minekuaiApiRequest(server.minekuaiInstanceId, "stop", groupId, 3);
278
421
  await new Promise((resolve) => setTimeout(resolve, 1e3));
279
- await minekuaiApiRequest(server.minekuaiInstanceId, "kill", 3);
422
+ await minekuaiApiRequest(server.minekuaiInstanceId, "kill", groupId, 3);
280
423
  await new Promise((resolve) => setTimeout(resolve, 3e3));
281
- await minekuaiApiRequest(server.minekuaiInstanceId, "start", 3);
424
+ await minekuaiApiRequest(server.minekuaiInstanceId, "start", groupId, 3);
282
425
  return `✅ 服务器 ${server.name} 强制重启指令已发送完成,请稍后检查服务器状态`;
283
426
  } catch (error) {
284
427
  return `❌ 强制重启服务器 ${server.name} 失败: ${error.message}`;
285
428
  }
286
429
  });
287
- ctx.command("mc/资源 <id:number>", "查看麦块服务器资源使用情况").action(async ({ session }, id) => {
430
+ ctx.guild().command("mc/资源 <id:number>", "查看麦块服务器资源使用情况").action(async ({ session }, id) => {
288
431
  if (!id) return "请提供服务器ID,例如:资源 1";
289
- const server = config.servers.find((s) => s.id === id);
290
- if (!server) return `未找到ID为 ${id} 的服务器`;
432
+ const groupId = session.guildId;
433
+ const servers = await ctx.database.get("minecraft_server", { groupId });
434
+ const server = servers.find((s) => s.id === id);
435
+ if (!server) return `❌ 未找到ID为 ${id} 的服务器,请确保操作的是本群绑定的服务器`;
291
436
  if (!server.minekuaiInstanceId) return `服务器 ${server.name} 未配置麦块实例ID`;
292
437
  try {
293
- const { apiUrl, apiKey } = config.minekuaiSettings;
294
- if (!apiKey) throw new Error("麦块API密钥未配置");
295
- if (!apiUrl) throw new Error("麦块API地址未配置");
296
- const baseUrl = apiUrl.replace(/\/+$/, "");
438
+ const apiKeys = await ctx.database.get("minecraft_api_key", { groupId });
439
+ if (!apiKeys || apiKeys.length === 0) {
440
+ throw new Error("本群未配置麦块API密钥,请先使用 绑定密钥 指令");
441
+ }
442
+ const apiKeyRecord = apiKeys[0];
443
+ const baseUrl = config.minekuaiApiUrl.replace(/\/+$/, "");
297
444
  const url = `${baseUrl}/servers/${server.minekuaiInstanceId}/resources`;
298
445
  const headers = {
299
- "Authorization": `Bearer ${apiKey}`,
446
+ "Authorization": `Bearer ${apiKeyRecord.apiKey}`,
300
447
  "Content-Type": "application/json",
301
448
  "Accept": "application/json"
302
449
  };
@@ -339,11 +486,51 @@ function apply(ctx, config) {
339
486
  return `❌ 查询服务器 ${server.name} 资源使用情况失败: ${error.message}`;
340
487
  }
341
488
  });
489
+ ctx.guild().command("mc/服务器列表", "查看已绑定的服务器列表").action(async ({ session }) => {
490
+ const groupId = session.guildId;
491
+ const servers = await ctx.database.get("minecraft_server", { groupId });
492
+ if (servers.length === 0) {
493
+ return "本群暂未绑定任何服务器";
494
+ }
495
+ let message = `📋 本群已绑定 ${servers.length} 台服务器:
496
+
497
+ `;
498
+ servers.forEach((server) => {
499
+ message += `[ID:${server.id}] ${server.name}
500
+ `;
501
+ if (config.showIpInDetail) {
502
+ message += ` 地址: ${server.host}:${server.port}
503
+ `;
504
+ }
505
+ message += ` 类型: ${server.serverType} | 超时: ${server.timeout}秒
506
+ `;
507
+ if (server.minekuaiInstanceId) {
508
+ message += ` 麦块实例: ${server.minekuaiInstanceId}
509
+ `;
510
+ }
511
+ message += "\n";
512
+ });
513
+ return message.trim();
514
+ });
515
+ ctx.guild().command("mc/设置实例 <id:number> <instanceId:string>", "设置服务器的麦块实例ID").action(async ({ session }, id, instanceId) => {
516
+ if (!id || !instanceId) {
517
+ return "请提供服务器ID和实例ID,例如:设置实例 1 abc123";
518
+ }
519
+ const groupId = session.guildId;
520
+ const servers = await ctx.database.get("minecraft_server", { groupId });
521
+ const server = servers.find((s) => s.id === id);
522
+ if (!server) {
523
+ return `❌ 未找到ID为 ${id} 的服务器`;
524
+ }
525
+ await ctx.database.set("minecraft_server", { id }, { minekuaiInstanceId: instanceId });
526
+ return `✅ 服务器 ${server.name} 的麦块实例ID已设置为: ${instanceId}`;
527
+ });
342
528
  }
343
529
  __name(apply, "apply");
344
530
  // Annotate the CommonJS export names for ESM import in node:
345
531
  0 && (module.exports = {
346
532
  Config,
347
533
  apply,
534
+ inject,
348
535
  name
349
536
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koishi-plugin-minecraft-search",
3
3
  "description": "使用API查询基础的mc服务器信息",
4
- "version": "1.3.9",
4
+ "version": "2.0.1",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
7
7
  "files": [
package/readme.md CHANGED
@@ -16,6 +16,7 @@
16
16
  ### ⚡ 服务器电源控制
17
17
  - 支持通过麦块联机 API 启动服务器
18
18
  - 支持通过麦块联机 API 重启服务器
19
+ - 支持通过麦块联机 API 强制重启服务器
19
20
  - 自动重试机制,提高操作成功率
20
21
 
21
22
  ### 📊 服务器资源查询
@@ -25,6 +26,18 @@
25
26
  - 显示服务器运行时间
26
27
  - 显示服务器状态和暂停状态
27
28
 
29
+ ### 🗄️ 数据库存储
30
+ - 使用数据库存储服务器配置,支持多群组管理
31
+ - 支持按群组绑定服务器,每个群组只能管理自己的服务器
32
+ - 支持 API 密钥按群组存储
33
+
34
+ ### 🔧 服务器管理
35
+ - 支持绑定服务器(自动解析地址和端口)
36
+ - 支持解绑服务器
37
+ - 支持修改服务器信息(名称、超时时间)
38
+ - 支持设置麦块实例ID
39
+ - 支持查看服务器列表
40
+
28
41
  ## 安装
29
42
 
30
43
  1. 安装插件:
@@ -36,34 +49,31 @@ npm install koishi-plugin-minecraft-search
36
49
 
37
50
  ## 配置说明
38
51
 
39
- ### 服务器配置
40
- ```typescript
41
- servers: [
42
- {
43
- id: 1, // 服务器ID(数字)
44
- name: "主服务器", // 服务器名称
45
- host: "play.example.com:25565", // 服务器地址(支持带端口)
46
- serverType: "java", // 服务器类型:java/bedrock
47
- timeout: 5.0, // 查询超时时间(秒)
48
- minekuaiInstanceId: "xxx" // 麦块实例ID(可选,用于电源控制)
49
- }
50
- ]
51
- ```
52
-
53
- ### 麦块联机配置(可选)
52
+ ### 基础配置
54
53
  ```typescript
55
- minekuaiSettings: {
56
- apiUrl: "https://minekuai.com/api/client", // 麦块API地址
57
- apiKey: "your-api-key" // 麦块API密钥
54
+ {
55
+ "minekuaiApiUrl": "https://minekuai.com/api/client", // 麦块API地址
56
+ "showIpInDetail": true // 是否在详细状态中显示IP地址
58
57
  }
59
58
  ```
60
59
 
61
60
  ## 使用指令
62
61
 
62
+ ### 服务器管理
63
+ ```
64
+ mc/绑定 <host> [-n <name>] [-t <timeout>] [-i <instance>] # 绑定服务器,支持指定名称、超时时间和麦块实例ID
65
+ mc/解绑 <id> # 解绑服务器
66
+ mc/修改 <id> [-n <name>] [-t <timeout>] [-i <instance>] # 修改服务器信息,支持修改名称、超时时间和麦块实例ID
67
+ mc/服务器列表 # 查看已绑定的服务器列表
68
+ mc/设置实例 <id> <instanceId> # 设置服务器的麦块实例ID
69
+ mc/绑定API密钥 <apiKey> # 绑定麦块API密钥
70
+ ```
71
+
63
72
  ### 查询服务器状态
64
73
  ```
65
- 查服 # 查询全部服务器状态(简短信息)
66
- 查服 1 # 查询ID为1的服务器的详细信息
74
+ mc/查服 # 查询全部服务器状态(简短信息)
75
+ mc/查服 1 # 查询ID为1的服务器的详细信息
76
+ mc/查服 <ip> # 直接输入IP地址查询服务器状态
67
77
  ```
68
78
 
69
79
  **输出示例:**
@@ -79,14 +89,14 @@ minekuaiSettings: {
79
89
 
80
90
  ### 服务器电源控制
81
91
  ```
82
- 开服 1 # 启动ID为1的麦块服务器
83
- 重启 1 # 重启ID为1的麦块服务器
84
- 强制重启 1 # 强制重启ID为1的麦块服务器
92
+ mc/开服 1 # 启动ID为1的麦块服务器
93
+ mc/重启 1 # 重启ID为1的麦块服务器
94
+ mc/强制重启 1 # 强制重启ID为1的麦块服务器
85
95
  ```
86
96
 
87
97
  ### 服务器资源查询
88
98
  ```
89
- 资源 1 # 查看ID为1的麦块服务器资源使用情况
99
+ mc/资源 1 # 查看ID为1的麦块服务器资源使用情况
90
100
  ```
91
101
 
92
102
  **输出示例:**
@@ -103,15 +113,37 @@ minekuaiSettings: {
103
113
  ⏰ 查询时间: 2026-03-13 12:00:00
104
114
  ```
105
115
 
106
- ## 配置选项说明
107
-
108
- ### 服务器类型 (serverType)
109
- - `java`:Java 版服务器(默认)
110
- - `bedrock`:基岩版服务器(暂不支持)
111
-
112
- ### 超时时间 (timeout)
113
- - 默认值:5.0 秒
114
- - 设置查询超时时间,避免长时间等待
116
+ ## 指令说明
117
+
118
+ ### 绑定服务器
119
+ - **命令**:`mc/绑定 <host> [-n <name>] [-t <timeout>] [-i <instance>]`
120
+ - **参数**:
121
+ - `<host>`:服务器地址,支持带端口格式(如:`play.example.com:25565`)
122
+ - `-n <name>`:服务器名称(可选,默认使用地址作为名称)
123
+ - `-t <timeout>`:查询超时时间(可选,默认5秒)
124
+ - `-i <instance>`:麦块实例ID(可选,用于电源控制)
125
+ - **示例**:
126
+ - `mc/绑定 s3.ungc.com.cn` - 绑定默认端口的服务器
127
+ - `mc/绑定 s3.ungc.com.cn:37095 -n 测试服 -t 10` - 绑定指定端口、名称和超时的服务器
128
+ - `mc/绑定 s3.ungc.com.cn -i abc123` - 绑定服务器并设置麦块实例ID
129
+
130
+ ### 绑定API密钥
131
+ - **命令**:`mc/绑定API密钥 <apiKey>`
132
+ - **参数**:
133
+ - `<apiKey>`:麦块联机平台的API密钥
134
+ - **说明**:每个群组只需绑定一次,后续会自动使用该密钥
135
+
136
+ ### 服务器管理指令
137
+ - **`mc/解绑 <id>`**:解绑指定ID的服务器
138
+ - **`mc/修改 <id> [-n <name>] [-t <timeout>] [-i <instance>]`**:修改服务器名称、超时时间或麦块实例ID
139
+ - **`mc/设置实例 <id> <instanceId>`**:为服务器设置麦块实例ID,用于电源控制
140
+ - **`mc/服务器列表`**:查看当前群组已绑定的所有服务器
141
+
142
+ ### 服务器控制指令
143
+ - **`mc/开服 <id>`**:启动指定服务器
144
+ - **`mc/重启 <id>`**:重启指定服务器
145
+ - **`mc/强制重启 <id>`**:强制停止并重启指定服务器
146
+ - **`mc/资源 <id>`**:查询服务器资源使用情况
115
147
 
116
148
  ## 技术特性
117
149
 
@@ -120,19 +152,24 @@ minekuaiSettings: {
120
152
  - 📱 **友好输出格式**:使用 emoji 和清晰排版,信息易读
121
153
  - ⚡ **高性能查询**:支持并行查询多个服务器
122
154
  - 🛡️ **错误处理**:完善的错误处理和用户提示
155
+ - 🗄️ **数据库存储**:使用数据库存储服务器配置,支持多群组管理
156
+ - 🔒 **权限控制**:每个群组只能管理自己绑定的服务器
157
+ - 🌐 **直接IP查询**:支持直接输入IP地址查询服务器状态
158
+ - 🔧 **实例ID管理**:支持在绑定和修改服务器时直接设置麦块实例ID
123
159
 
124
160
  ## 依赖说明
125
161
 
126
162
  - 使用 https://www.npmjs.com/package/mc-server-util 库进行服务器状态查询
127
163
  - 支持麦块联机平台的 API 集成
128
- - 基于 Koishi 框架开发
164
+ - 基于 Koishi 框架开发,依赖数据库插件
129
165
 
130
166
  ## 注意事项
131
167
 
132
168
  1. 麦块联机功能需要配置正确的 API 地址和密钥
133
- 2. Query 查询可能会增加查询时间,建议按需开启
134
- 3. 服务器地址支持带端口格式(如:`play.example.com:25565`)
135
- 4. 插件会自动处理 MOTD 中的换行符,确保输出整洁
169
+ 2. 服务器地址支持带端口格式(如:`play.example.com:25565`)
170
+ 3. 插件会自动处理 MOTD 中的换行符,确保输出整洁
171
+ 4. 所有服务器操作指令均限制为群组指令,只能操作本群绑定的服务器
172
+ 5. API 密钥按群组存储,每个群组需要单独绑定
136
173
 
137
174
  ## 故障排除
138
175
 
@@ -141,11 +178,27 @@ minekuaiSettings: {
141
178
  - 网络连接是否正常
142
179
  - 防火墙是否阻止了查询请求
143
180
  - 麦块 API 配置是否正确
181
+ - 服务器是否为本群绑定的服务器
144
182
 
145
183
  ## 更新日志
146
184
  <details>
147
185
  <summary>点我查看更新日志详情</summary>
148
186
 
187
+ ### v2.0.1
188
+ - 新增绑定服务器时支持 -i 选项直接设置麦块实例ID
189
+ - 新增修改服务器时支持 -i 选项修改麦块实例ID
190
+ - 新增支持直接输入IP地址查询服务器状态
191
+ - 优化服务器绑定逻辑,避免重复绑定
192
+ - 完善错误提示信息
193
+
194
+ ### v2.0.0
195
+ - 全新数据库存储架构,支持多群组管理
196
+ - 新增服务器绑定、解绑、修改等管理指令
197
+ - 支持按群组存储 API 密钥
198
+ - 增加服务器列表查看功能
199
+ - 优化错误提示,明确权限限制
200
+ - 移除配置文件中的服务器列表,改为数据库存储
201
+
149
202
  ### v1.3.6
150
203
  - 新增服务器资源使用情况查询功能
151
204
  - 支持查看 CPU、内存、磁盘使用情况
@@ -176,4 +229,4 @@ minekuaiSettings: {
176
229
 
177
230
  ## 支持与反馈
178
231
 
179
- 如有问题或建议,请通过相关渠道联系开发者。
232
+ 如有问题或建议,请通过相关渠道联系开发者。