koishi-plugin-gl-bot 0.0.11 → 0.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/lib/gl/index.d.ts +36 -55
  2. package/lib/gl/index.js +4 -6
  3. package/lib/gl/queqiao.adapter.d.ts +11 -0
  4. package/lib/gl/queqiao.adapter.js +41 -0
  5. package/lib/mcsManager/api.d.ts +1 -0
  6. package/lib/mcsManager/api.js +13 -1
  7. package/lib/mcsManager/bot.d.ts +2 -2
  8. package/lib/mcsManager/bot.js +1 -0
  9. package/lib/mcsManager/commands/index.d.ts +1 -0
  10. package/lib/mcsManager/commands/index.js +3 -1
  11. package/lib/mcsManager/commands/mc/health.d.ts +16 -0
  12. package/lib/mcsManager/commands/mc/health.js +46 -0
  13. package/lib/mcsManager/commands/mc/list.d.ts +1 -0
  14. package/lib/mcsManager/commands/mc/list.js +21 -6
  15. package/lib/mcsManager/commands/mc/online.d.ts +6 -1
  16. package/lib/mcsManager/commands/mc/online.js +49 -12
  17. package/lib/mcsManager/config.d.ts +39 -0
  18. package/lib/mcsManager/config.js +21 -0
  19. package/lib/mcsManager/index.d.ts +32 -1
  20. package/lib/mcsManager/index.js +4 -1
  21. package/lib/mcsManager/type.d.ts +2 -0
  22. package/lib/queQiao/index.d.ts +47 -38
  23. package/lib/queQiao/index.js +82 -47
  24. package/lib/queQiao/locale/zh-CN.json +1 -1
  25. package/lib/queQiao/locale/zh-CN.yml +4 -4
  26. package/lib/queQiao/mcwss.d.ts +12 -9
  27. package/lib/queQiao/mcwss.js +34 -2
  28. package/lib/queQiao/values.js +2 -2
  29. package/lib/utils/game.mc.js +5 -4
  30. package/package.json +1 -1
  31. package/lib/constants/env.d.ts +0 -0
  32. package/lib/constants/env.js +0 -0
  33. package/lib/gl/index.type.d.ts +0 -0
  34. package/lib/gl/index.type.js +0 -0
  35. package/lib/mcsManager/commands/create.d.ts +0 -16
  36. package/lib/mcsManager/commands/create.js +0 -135
  37. package/lib/mcsManager/commands/list copy.d.ts +0 -13
  38. package/lib/mcsManager/commands/list copy.js +0 -34
  39. package/lib/mcsManager/commands/list.d.ts +0 -14
  40. package/lib/mcsManager/commands/list.js +0 -35
  41. package/lib/mcsManager/commands/mc/restart copy.d.ts +0 -15
  42. package/lib/mcsManager/commands/mc/restart copy.js +0 -62
  43. package/lib/mcsManager/commands/mc copy/create.d.ts +0 -16
  44. package/lib/mcsManager/commands/mc copy/create.js +0 -135
  45. package/lib/mcsManager/commands/mc copy/list.d.ts +0 -14
  46. package/lib/mcsManager/commands/mc copy/list.js +0 -35
  47. package/lib/mcsManager/commands/mc copy/restart.d.ts +0 -15
  48. package/lib/mcsManager/commands/mc copy/restart.js +0 -62
  49. package/lib/mcsManager/commands/mc copy/start.d.ts +0 -15
  50. package/lib/mcsManager/commands/mc copy/start.js +0 -54
  51. package/lib/mcsManager/commands/mc copy/stop.d.ts +0 -15
  52. package/lib/mcsManager/commands/mc copy/stop.js +0 -54
  53. package/lib/mcsManager/commands/restart.d.ts +0 -15
  54. package/lib/mcsManager/commands/restart.js +0 -62
  55. package/lib/mcsManager/commands/start copy.d.ts +0 -14
  56. package/lib/mcsManager/commands/start copy.js +0 -53
  57. package/lib/mcsManager/commands/start.d.ts +0 -15
  58. package/lib/mcsManager/commands/start.js +0 -54
  59. package/lib/mcsManager/commands/stop.d.ts +0 -15
  60. package/lib/mcsManager/commands/stop.js +0 -54
  61. package/lib/utils/file.download.d.ts +0 -47
  62. package/lib/utils/file.download.js +0 -142
  63. package/lib/utils/file.examples.d.ts +0 -12
  64. package/lib/utils/file.examples.js +0 -73
  65. package/lib/utils/napcat.file.d.ts +0 -63
  66. package/lib/utils/napcat.file.js +0 -133
package/lib/gl/index.d.ts CHANGED
@@ -1,85 +1,66 @@
1
1
  import { Context, Schema } from 'koishi';
2
+ import { MCManager } from '../mcsManager';
2
3
  import { NapCat } from '../napCat';
4
+ import { GLQueQiaoAdapter } from './queqiao.adapter';
3
5
  export declare class GLBot {
4
6
  private ctx;
5
7
  private config;
6
8
  static inject: string[];
7
9
  static Config: Schema<Schemastery.ObjectS<{
8
- wsServer: Schema<"客户端" | "服务端", "客户端" | "服务端">;
9
- wsHost: Schema<string, string>;
10
- wsPort: Schema<number, number>;
11
- Token: Schema<string, string>;
12
- serverName: Schema<string, string>;
13
- joinMsg: Schema<string, string>;
14
- event: Schema<number | readonly ("AsyncPlayerChatEvent" | "PlayerCommandPreprocessEvent" | "PlayerDeathEvent" | "PlayerJoinEvent" | "PlayerQuitEvent")[], number>;
15
- maxReconnectCount: Schema<number, number>;
16
- maxReconnectInterval: Schema<number, number>;
17
- }> | Schemastery.ObjectS<{
18
- rconEnable: Schema<boolean, boolean>;
19
- rconServerHost: Schema<string, string>;
20
- rconServerPort: Schema<number, number>;
21
- rconPassword: Schema<string, string>;
22
- alluser: Schema<boolean, boolean>;
23
- superuser: Schema<string[], string[]>;
24
- commonCmd: Schema<string[], string[]>;
25
- cannotCmd: Schema<string[], string[]>;
26
- }> | Schemastery.ObjectS<{
27
- sendToChannel: Schema<string[], string[]>;
28
- watchChannel: Schema<string[], string[]>;
29
- sendprefix: Schema<string, string>;
30
- cmdprefix: Schema<string, string>;
31
- hideConnect: Schema<boolean, boolean>;
32
- locale: Schema<"zh-CN" | "en-US", "zh-CN" | "en-US">;
33
- }> | Schemastery.ObjectS<{
34
10
  mcManagerUsername: Schema<string, string>;
35
11
  mcManagerPassword: Schema<string, string>;
36
12
  mcManagerKey: Schema<string, string>;
37
13
  mcManagerHost: Schema<string, string>;
38
14
  mcManagerWs: Schema<string, string>;
39
15
  mcManagerMaxConnectWs: Schema<number, number>;
16
+ }> | Schemastery.ObjectS<{
17
+ queQiaoEnable: Schema<boolean, boolean>;
18
+ queQiaoSendToChannel: Schema<string[], string[]>;
19
+ queQiaoWatchChannel: Schema<string[], string[]>;
20
+ queQiaoServers: Schema<Schemastery.ObjectS<{
21
+ enable: Schema<boolean, boolean>;
22
+ rconServerHost: Schema<string, string>;
23
+ rconPassword: Schema<string, string>;
24
+ wsHost: Schema<string, string>;
25
+ Token: Schema<string, string>;
26
+ serverName: Schema<string, string>;
27
+ }>[], Schemastery.ObjectT<{
28
+ enable: Schema<boolean, boolean>;
29
+ rconServerHost: Schema<string, string>;
30
+ rconPassword: Schema<string, string>;
31
+ wsHost: Schema<string, string>;
32
+ Token: Schema<string, string>;
33
+ serverName: Schema<string, string>;
34
+ }>[]>;
40
35
  }> | Schemastery.ObjectS<{
41
36
  napCatBaseUrl: Schema<string, string>;
42
37
  napCatToken: Schema<string, string>;
43
38
  }>, {
44
- wsServer: "客户端" | "服务端";
45
- wsHost: string;
46
- wsPort: number;
47
- Token: string;
48
- serverName: string;
49
- joinMsg: string;
50
- event: number;
51
- maxReconnectCount: number;
52
- maxReconnectInterval: number;
53
- } & import("cosmokit").Dict & {
54
- rconEnable: boolean;
55
- rconServerHost: string;
56
- rconServerPort: number;
57
- rconPassword: string;
58
- alluser: boolean;
59
- superuser: string[];
60
- commonCmd: string[];
61
- cannotCmd: string[];
62
- } & {
63
- sendToChannel: string[];
64
- watchChannel: string[];
65
- sendprefix: string;
66
- cmdprefix: string;
67
- hideConnect: boolean;
68
- locale: "zh-CN" | "en-US";
69
- } & {
70
39
  mcManagerUsername: string;
71
40
  mcManagerPassword: string;
72
41
  mcManagerKey: string;
73
42
  mcManagerHost: string;
74
43
  mcManagerWs: string;
75
44
  mcManagerMaxConnectWs: number;
45
+ } & import("cosmokit").Dict & {
46
+ queQiaoEnable: boolean;
47
+ queQiaoSendToChannel: string[];
48
+ queQiaoWatchChannel: string[];
49
+ queQiaoServers: Schemastery.ObjectT<{
50
+ enable: Schema<boolean, boolean>;
51
+ rconServerHost: Schema<string, string>;
52
+ rconPassword: Schema<string, string>;
53
+ wsHost: Schema<string, string>;
54
+ Token: Schema<string, string>;
55
+ serverName: Schema<string, string>;
56
+ }>[];
76
57
  } & {
77
58
  napCatBaseUrl: string;
78
59
  napCatToken: string;
79
60
  }>;
80
- private mcSyncMsg;
81
- private mcsManager;
82
- napCat: NapCat;
61
+ readonly mcsManager: MCManager;
62
+ readonly queQiaoAdapter: GLQueQiaoAdapter;
63
+ readonly napCat: NapCat;
83
64
  constructor(ctx: Context, config: GLBotConfigType);
84
65
  private initialize;
85
66
  private globalCommand;
package/lib/gl/index.js CHANGED
@@ -1,21 +1,19 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.GLBotBase = exports.GLBot = void 0;
7
4
  const koishi_1 = require("koishi");
8
5
  const constants_1 = require("../constants");
9
6
  const mcsManager_1 = require("../mcsManager");
10
7
  const napCat_1 = require("../napCat");
11
- const queQiao_1 = __importDefault(require("../queQiao"));
8
+ const queqiao_adapter_1 = require("./queqiao.adapter");
12
9
  const logger = new koishi_1.Logger('gl-bot');
13
10
  class GLBot {
14
11
  constructor(ctx, config) {
15
12
  this.ctx = ctx;
16
13
  this.config = config;
17
- this.mcSyncMsg = new queQiao_1.default(ctx, config);
14
+ // this.mcSyncMsg = new MinecraftSyncMsg(ctx, config);
18
15
  this.mcsManager = new mcsManager_1.MCManager(this, ctx, config);
16
+ this.queQiaoAdapter = new queqiao_adapter_1.GLQueQiaoAdapter(this, ctx, config);
19
17
  this.napCat = new napCat_1.NapCat(ctx, config);
20
18
  this.initialize();
21
19
  }
@@ -45,7 +43,7 @@ class GLBot {
45
43
  exports.GLBot = GLBot;
46
44
  GLBot.inject = ['database'];
47
45
  GLBot.Config = koishi_1.Schema.intersect([
48
- queQiao_1.default.Config,
46
+ // MinecraftSyncMsg.Config,
49
47
  mcsManager_1.MCManager.Config,
50
48
  napCat_1.NapCat.Config,
51
49
  ]);
@@ -0,0 +1,11 @@
1
+ import { Context } from 'koishi';
2
+ import { GLBot, GLBotConfigType } from '.';
3
+ import MinecraftSyncMsg from '../queQiao';
4
+ export declare class GLQueQiaoAdapter {
5
+ readonly gl: GLBot;
6
+ readonly ctx: Context;
7
+ private readonly config;
8
+ servers: Record<string, MinecraftSyncMsg>;
9
+ constructor(gl: GLBot, ctx: Context, config: GLBotConfigType);
10
+ private initialize;
11
+ }
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.GLQueQiaoAdapter = void 0;
7
+ const queQiao_1 = __importDefault(require("../queQiao"));
8
+ class GLQueQiaoAdapter {
9
+ constructor(gl, ctx, config) {
10
+ this.gl = gl;
11
+ this.ctx = ctx;
12
+ this.config = config;
13
+ this.servers = {};
14
+ if (this.config.queQiaoEnable) {
15
+ this.initialize();
16
+ }
17
+ }
18
+ initialize() {
19
+ this.config.queQiaoServers?.forEach(serverConfig => {
20
+ if (serverConfig.enable) {
21
+ const [wsHost, wsProt] = serverConfig.wsHost.split(':') ?? serverConfig.wsProt;
22
+ const [rconHost, rconProt] = serverConfig.rconServerHost.split(':') ?? serverConfig.rconServerHost;
23
+ this.servers[serverConfig.serverName] = new queQiao_1.default(this.ctx, this, {
24
+ rconEnable: serverConfig.rconEnable,
25
+ rconServerHost: rconHost ?? serverConfig.rconServerHost,
26
+ rconServerPort: rconProt ?? serverConfig.rconServerPort,
27
+ rconPassword: serverConfig.rconPassword,
28
+ wsServer: '客户端',
29
+ wsHost: wsHost ?? serverConfig.wsHost,
30
+ wsPort: wsProt ?? serverConfig.wsPort,
31
+ Token: serverConfig.Token,
32
+ serverName: serverConfig.serverName,
33
+ // event: [],
34
+ sendToChannel: this.config.queQiaoSendToChannel,
35
+ watchChannel: this.config.queQiaoWatchChannel,
36
+ });
37
+ }
38
+ });
39
+ }
40
+ }
41
+ exports.GLQueQiaoAdapter = GLQueQiaoAdapter;
@@ -37,4 +37,5 @@ export declare class MCSManagerAPI {
37
37
  remoteMappings: string[];
38
38
  }>;
39
39
  uploadFileToRemoteInstance(daemonId: string, filePath: string): Promise<boolean>;
40
+ readServerProperties(daemonId: string, instanceId: string): Promise<Record<string, never>>;
40
41
  }
@@ -33,7 +33,7 @@ class MCSManagerAPI {
33
33
  return false;
34
34
  }
35
35
  async getUserInfo() {
36
- const result = await this.http(`${this.baseUrl}/auth/`, {
36
+ const result = await this.http(`${this.baseUrl}/auth`, {
37
37
  headers: this.requestHeaders,
38
38
  });
39
39
  if (result.status === 200) {
@@ -236,6 +236,18 @@ class MCSManagerAPI {
236
236
  });
237
237
  return result.status === 200;
238
238
  }
239
+ async readServerProperties(daemonId, instanceId) {
240
+ return (await this.http(`${this.baseUrl}/protected_instance/process_config/file`, {
241
+ headers: this.requestHeaders,
242
+ params: {
243
+ daemonId,
244
+ uuid: instanceId,
245
+ fileName: 'server.properties',
246
+ type: 'properties',
247
+ token: this.userInfo.token,
248
+ },
249
+ })).data.data;
250
+ }
239
251
  }
240
252
  exports.MCSManagerAPI = MCSManagerAPI;
241
253
  function extractCookiesWithRegex(cookieStr) {
@@ -1,7 +1,7 @@
1
1
  import { Context } from 'koishi';
2
2
  import { MCManager } from '.';
3
3
  import { GLBotConfigType } from '../gl';
4
- import { MCBotListCommand } from './commands';
4
+ import { ARKBotListCommand, MCBotHealthCommand, MCBotListCommand, MCBotOnlineTimeCommand } from './commands';
5
5
  import { MCSManagerPanel } from './panel';
6
6
  export declare class MCSManagerBot {
7
7
  readonly manager: MCManager;
@@ -10,7 +10,7 @@ export declare class MCSManagerBot {
10
10
  readonly panel: MCSManagerPanel;
11
11
  constructor(manager: MCManager, ctx: Context, config: GLBotConfigType, panel: MCSManagerPanel);
12
12
  help(): string[];
13
- commands(): (typeof MCBotListCommand)[];
13
+ commands(): (typeof MCBotOnlineTimeCommand | typeof MCBotHealthCommand | typeof MCBotListCommand | typeof ARKBotListCommand)[];
14
14
  initialize(): Promise<void>;
15
15
  private registerCommands;
16
16
  }
@@ -30,6 +30,7 @@ class MCSManagerBot {
30
30
  create_1.MCBotCreateCommand,
31
31
  commands_1.MCBotOnlineTimeCommand,
32
32
  commands_1.MCBotGameOnline,
33
+ commands_1.MCBotHealthCommand,
33
34
  commands_1.ARKBotListCommand,
34
35
  commands_1.ARKBotRestartCommand,
35
36
  commands_1.ARKBotStartCommand,
@@ -1,4 +1,5 @@
1
1
  export { BotCommandBase } from './base';
2
+ export { MCBotHealthCommand } from './mc/health';
2
3
  export { MCBotListCommand } from './mc/list';
3
4
  export { MCBotGameOnline, MCBotOnlineTimeCommand } from './mc/online';
4
5
  export { MCBotRestartCommand } from './mc/restart';
@@ -1,8 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ARKBotStopCommand = exports.ARKBotStartCommand = exports.ARKBotRestartCommand = exports.ARKBotListCommand = exports.MCBotStopCommand = exports.MCBotStartCommand = exports.MCBotRestartCommand = exports.MCBotOnlineTimeCommand = exports.MCBotGameOnline = exports.MCBotListCommand = exports.BotCommandBase = void 0;
3
+ exports.ARKBotStopCommand = exports.ARKBotStartCommand = exports.ARKBotRestartCommand = exports.ARKBotListCommand = exports.MCBotStopCommand = exports.MCBotStartCommand = exports.MCBotRestartCommand = exports.MCBotOnlineTimeCommand = exports.MCBotGameOnline = exports.MCBotListCommand = exports.MCBotHealthCommand = exports.BotCommandBase = void 0;
4
4
  var base_1 = require("./base");
5
5
  Object.defineProperty(exports, "BotCommandBase", { enumerable: true, get: function () { return base_1.BotCommandBase; } });
6
+ var health_1 = require("./mc/health");
7
+ Object.defineProperty(exports, "MCBotHealthCommand", { enumerable: true, get: function () { return health_1.MCBotHealthCommand; } });
6
8
  var list_1 = require("./mc/list");
7
9
  Object.defineProperty(exports, "MCBotListCommand", { enumerable: true, get: function () { return list_1.MCBotListCommand; } });
8
10
  var online_1 = require("./mc/online");
@@ -0,0 +1,16 @@
1
+ import MinecraftSyncMsg from '../../../queQiao';
2
+ import { MCSManagerBot } from '../../bot';
3
+ import { BotCommandBase } from '../base';
4
+ /**
5
+ * 服务器 健康 指令
6
+ *
7
+ * @example 服务器 健康
8
+ */
9
+ export declare class MCBotHealthCommand extends BotCommandBase {
10
+ readonly bot: MCSManagerBot;
11
+ command: string[];
12
+ roles: any[];
13
+ constructor(bot: MCSManagerBot);
14
+ getHealthStatus(connect: MinecraftSyncMsg): Promise<any[]>;
15
+ handle(_: any, status?: string[]): Promise<string>;
16
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MCBotHealthCommand = void 0;
4
+ const lodash_1 = require("lodash");
5
+ const base_1 = require("../base");
6
+ /**
7
+ * 服务器 健康 指令
8
+ *
9
+ * @example 服务器 健康
10
+ */
11
+ class MCBotHealthCommand extends base_1.BotCommandBase {
12
+ constructor(bot) {
13
+ super(bot);
14
+ this.bot = bot;
15
+ this.command = ['服务器.健康 <status>', 'MC.健康 <status>'];
16
+ this.roles = [];
17
+ this.initialize();
18
+ }
19
+ async getHealthStatus(connect) {
20
+ const healths = [];
21
+ if (!connect.rcon || !connect.rcon.authenticated) {
22
+ return healths;
23
+ }
24
+ // FIXME: 此处需适配
25
+ const result = await connect.sendRconCommand('forge tps');
26
+ // Overall: Mean tick time: 3.314 ms. Mean TPS: 20.000
27
+ const [, tickTimeMatch, tpsMatch] = result.match(/Mean tick time: ([\d.]+) ms\. Mean TPS: ([\d.]+)/) || [];
28
+ if (tickTimeMatch && (0, lodash_1.isNumber)(Number(tickTimeMatch))) {
29
+ healths.push(`Tick:${Number(tickTimeMatch).toFixed(2)} ms [${Number(tickTimeMatch) <= 50 ? '优秀' : '过高'}]`);
30
+ }
31
+ if (tpsMatch && (0, lodash_1.isNumber)(Number(tpsMatch))) {
32
+ healths.push(`TPS:${Number(tpsMatch).toFixed(2)} [${Number(tpsMatch) >= 15 ? '优秀' : '过低'}]`);
33
+ }
34
+ return healths;
35
+ }
36
+ async handle(_, status) {
37
+ const result = ['服务器 健康 状态:'];
38
+ for (const [name, server] of Object.entries(this.bot.manager.gl.queQiaoAdapter.servers)) {
39
+ const headers = await this.getHealthStatus(server);
40
+ const queQIaoConnected = server.ws?.readyState === 1;
41
+ result.push(`- [${name}] 互通:${queQIaoConnected ? 'OK' : 'NO'} | 后端:${server.rcon.authenticated ? 'OK' : 'NO'} | ${headers.join(' | ')}`);
42
+ }
43
+ return result.join('\n');
44
+ }
45
+ }
46
+ exports.MCBotHealthCommand = MCBotHealthCommand;
@@ -10,5 +10,6 @@ export declare class MCBotListCommand extends BotCommandBase {
10
10
  command: string[];
11
11
  roles: any[];
12
12
  constructor(bot: MCSManagerBot);
13
+ readServerProperties(daemonId: string, instanceId: string): Promise<Record<string, never>>;
13
14
  handle(_: any, status?: string[]): Promise<string>;
14
15
  }
@@ -18,22 +18,37 @@ class MCBotListCommand extends base_1.BotCommandBase {
18
18
  this.roles = [];
19
19
  this.initialize();
20
20
  }
21
+ async readServerProperties(daemonId, instanceId) {
22
+ return this.bot.panel.api.readServerProperties(daemonId, instanceId);
23
+ }
21
24
  async handle(_, status) {
22
25
  await this.bot.panel.handleRemoteServices();
23
- const filteredStatus = status?.at(0);
26
+ let filteredStatus = status?.at(0) ?? '运行中';
27
+ if (filteredStatus === '全部') {
28
+ filteredStatus = '';
29
+ }
24
30
  const nameInstances = (await this.bot.panel.searchInstanceByName('')).filter(item => !filteredStatus ||
25
31
  ~item.instance.cfg.config.nickname.indexOf(filteredStatus) ||
26
32
  constants_1.RemoteInstanceStatusName[item.instance.cfg.status] === filteredStatus);
27
- return `${'='.repeat(10)}服务器列表${'='.repeat(10)}\n${nameInstances
28
- .map(item => {
33
+ const list = [];
34
+ for (const item of nameInstances) {
35
+ let properties = {};
29
36
  const { cfg } = item.instance;
30
37
  const lastDatetime = (0, lodash_1.isEqual)(cfg.status, constants_1.RemoteInstanceStatusEnum.RUNNING)
31
38
  ? Date.now()
32
39
  : cfg.config.lastDatetime;
33
40
  const duration = (0, utils_1.formatDuration)(lastDatetime - new Date(cfg.config.createDatetime).getTime());
34
- return `- [${constants_1.RemoteInstanceStatusName[cfg.status]}] ${cfg.config.nickname} 「${duration}」`;
35
- })
36
- .join('\n')}\n ${'='.repeat(28)} `;
41
+ try {
42
+ properties = await this.readServerProperties(item.remote.uuid, item.instance.cfg.instanceUuid);
43
+ }
44
+ catch (err) {
45
+ properties = {};
46
+ }
47
+ list.push(`- ${constants_1.RemoteInstanceStatusName[cfg.status]} ${cfg.config.nickname} 「${duration}」[端口 ${properties?.['server-port'] || '--'}]`
48
+ .replace('运行中', '✅')
49
+ .replace('已停止', '❌'));
50
+ }
51
+ return `${'='.repeat(10)}服务器列表${'='.repeat(10)}\n${list.join('\n')}\n ${'='.repeat(28)} `;
37
52
  }
38
53
  }
39
54
  exports.MCBotListCommand = MCBotListCommand;
@@ -1,12 +1,17 @@
1
+ import MinecraftSyncMsg from '../../../queQiao';
1
2
  import { MCSManagerBot } from '../../bot';
2
3
  import { McUser } from '../../type';
3
4
  import { BotCommandBase } from '../base';
4
5
  export declare class MCBotGameOnline extends BotCommandBase {
5
6
  readonly bot: MCSManagerBot;
6
- static list: Record<string, McUser>;
7
+ static list: Record<string, {
8
+ config: Schemastery.TypeS<typeof MinecraftSyncMsg.Config>;
9
+ list: Record<string, McUser>;
10
+ }>;
7
11
  command: string[];
8
12
  roles: any[];
9
13
  constructor(bot: MCSManagerBot);
14
+ getOnlinePlayers(connect: MinecraftSyncMsg): Promise<string[]>;
10
15
  handle(): Promise<string>;
11
16
  }
12
17
  /**
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MCBotOnlineTimeCommand = exports.MCBotGameOnline = void 0;
4
+ const lodash_1 = require("lodash");
4
5
  const utils_1 = require("../../../utils");
5
6
  const base_1 = require("../base");
6
7
  class MCBotGameOnline extends base_1.BotCommandBase {
@@ -11,14 +12,50 @@ class MCBotGameOnline extends base_1.BotCommandBase {
11
12
  this.roles = [];
12
13
  this.initialize();
13
14
  }
15
+ async getOnlinePlayers(connect) {
16
+ // There are 2 of a max of 2026 players online: xxx, xxxx
17
+ return ((await connect.sendRconCommand('list'))
18
+ ?.match(/There are \d+ of a max of \d+ players online: (.*)/)?.[1]
19
+ ?.split(',')
20
+ ?.map(name => name.trim())
21
+ ?.filter(name => name.length > 0) ?? []);
22
+ }
14
23
  async handle() {
24
+ // 先获取在线人数
25
+ const rconPlayersResults = {};
26
+ for (const [name, server] of Object.entries(this.bot.manager.gl.queQiaoAdapter.servers)) {
27
+ const online = await this.getOnlinePlayers(server);
28
+ const serverConfig = server.config;
29
+ rconPlayersResults[server.config.serverName || ''] = {
30
+ config: serverConfig,
31
+ list: online.reduce((acc, nickname) => {
32
+ acc[nickname] = {
33
+ nickname,
34
+ uuid: '', // UUID 需要通过其他方式获取
35
+ server: serverConfig,
36
+ };
37
+ return acc;
38
+ }, {}),
39
+ };
40
+ }
41
+ // 内存中的在线玩家
15
42
  try {
16
43
  const users = await this.bot.ctx.database.get('mcUser', {});
17
- const userRankings = Object.values(MCBotGameOnline.list)
44
+ const allOnlineUsers = Object.values((0, lodash_1.merge)({}, rconPlayersResults, MCBotGameOnline.list)).flatMap(server => {
45
+ return Object.values(server.list).map(user => {
46
+ user.server = server.config;
47
+ return user;
48
+ });
49
+ });
50
+ const userRankings = allOnlineUsers
18
51
  .map(user => {
19
- const dbUser = users.find(u => u.uuid === user.uuid);
20
- const totalOnlineTime = +((Date.now() - (dbUser?.lastTime?.getTime() || 0)) /
52
+ const dbUser = users.find(u => u.uuid === user.uuid || u.nickname === user.nickname);
53
+ let totalOnlineTime = +((Date.now() - (dbUser?.lastTime?.getTime() || 0)) /
21
54
  1000).toFixed(0);
55
+ // rcon 未获取到 UUID 情况
56
+ if ((0, lodash_1.isEmpty)(user.uuid)) {
57
+ totalOnlineTime = -1;
58
+ }
22
59
  return {
23
60
  ...user,
24
61
  totalOnlineTime,
@@ -26,18 +63,18 @@ class MCBotGameOnline extends base_1.BotCommandBase {
26
63
  })
27
64
  .sort((a, b) => b.totalOnlineTime - a.totalOnlineTime)
28
65
  .slice(0, 10);
29
- let result = '==== 服务器在线玩家 ====\n';
30
- const tag = [, '🥇', '🥈', '🥉'];
66
+ let result = `==== 在线 玩家 ====\n`;
31
67
  userRankings.forEach((user, index) => {
32
68
  const rank = index + 1;
33
- const medal = tag[rank] || `${rank}.`;
34
- const onlineTimeStr = (0, utils_1.formatOnlineTime)(user.totalOnlineTime);
35
- result += `${medal} ${user.nickname} [HP: ${user.health.toFixed(1)} | LV: ${user.experience_level}] 「${onlineTimeStr}」\n`;
36
- if (index < userRankings.length - 1) {
37
- result += '\n';
38
- }
69
+ const onlineTimeStr = (0, lodash_1.isEqual)(user.totalOnlineTime, -1)
70
+ ? ''
71
+ : `「${(0, utils_1.formatOnlineTime)(user.totalOnlineTime)}」`;
72
+ result += `[${user.server.serverName ?? '-'}] ${rank}. ${user.nickname} ${onlineTimeStr}\n`;
39
73
  });
40
- result += '====================';
74
+ result += '=================';
75
+ if (userRankings.length === 0) {
76
+ return '当前没有在线玩家';
77
+ }
41
78
  return result;
42
79
  }
43
80
  catch (error) {
@@ -15,4 +15,43 @@ export declare class MCManagerConfig {
15
15
  mcManagerWs: Schema<string, string>;
16
16
  mcManagerMaxConnectWs: Schema<number, number>;
17
17
  }>>;
18
+ static QueQiao: Schema<Schemastery.ObjectS<{
19
+ queQiaoEnable: Schema<boolean, boolean>;
20
+ queQiaoSendToChannel: Schema<string[], string[]>;
21
+ queQiaoWatchChannel: Schema<string[], string[]>;
22
+ queQiaoServers: Schema<Schemastery.ObjectS<{
23
+ enable: Schema<boolean, boolean>;
24
+ rconServerHost: Schema<string, string>;
25
+ rconPassword: Schema<string, string>;
26
+ wsHost: Schema<string, string>;
27
+ Token: Schema<string, string>;
28
+ serverName: Schema<string, string>;
29
+ }>[], Schemastery.ObjectT<{
30
+ enable: Schema<boolean, boolean>;
31
+ rconServerHost: Schema<string, string>;
32
+ rconPassword: Schema<string, string>;
33
+ wsHost: Schema<string, string>;
34
+ Token: Schema<string, string>;
35
+ serverName: Schema<string, string>;
36
+ }>[]>;
37
+ }>, Schemastery.ObjectT<{
38
+ queQiaoEnable: Schema<boolean, boolean>;
39
+ queQiaoSendToChannel: Schema<string[], string[]>;
40
+ queQiaoWatchChannel: Schema<string[], string[]>;
41
+ queQiaoServers: Schema<Schemastery.ObjectS<{
42
+ enable: Schema<boolean, boolean>;
43
+ rconServerHost: Schema<string, string>;
44
+ rconPassword: Schema<string, string>;
45
+ wsHost: Schema<string, string>;
46
+ Token: Schema<string, string>;
47
+ serverName: Schema<string, string>;
48
+ }>[], Schemastery.ObjectT<{
49
+ enable: Schema<boolean, boolean>;
50
+ rconServerHost: Schema<string, string>;
51
+ rconPassword: Schema<string, string>;
52
+ wsHost: Schema<string, string>;
53
+ Token: Schema<string, string>;
54
+ serverName: Schema<string, string>;
55
+ }>[]>;
56
+ }>>;
18
57
  }
@@ -22,3 +22,24 @@ MCManagerConfig.Base = koishi_1.Schema.object({
22
22
  .default(20)
23
23
  .description('最大连接实例数'),
24
24
  }).description('MCSMANAGER 基础配置');
25
+ MCManagerConfig.QueQiao = koishi_1.Schema.object({
26
+ queQiaoEnable: koishi_1.Schema.boolean().default(false).description('是否启用鹊桥'),
27
+ queQiaoSendToChannel: koishi_1.Schema.array(String).description('消息发送到目标群组格式{platform}:{groupId}'),
28
+ queQiaoWatchChannel: koishi_1.Schema.array(String).description('消息观察频道目标群组格式{platform}:{groupId}'),
29
+ queQiaoServers: koishi_1.Schema.array(koishi_1.Schema.object({
30
+ enable: koishi_1.Schema.boolean().default(false).description('-- 是否启用'),
31
+ rconServerHost: koishi_1.Schema.string()
32
+ .default('127.0.0.1:25575')
33
+ .description('-- rcon地址'),
34
+ rconPassword: koishi_1.Schema.string()
35
+ .role('secret')
36
+ .description('-- rcon服务器的密码(推荐设置)'),
37
+ wsHost: koishi_1.Schema.string()
38
+ .default('127.0.0.1:8080')
39
+ .description('-- websocket服务器的地址(服务器监听地址)'),
40
+ Token: koishi_1.Schema.string().description('-- websocket服务器的验证Token'),
41
+ serverName: koishi_1.Schema.string().description('-- 鹊桥配置文件中对应的server_name'),
42
+ }))
43
+ .default([])
44
+ .description('启用鹊桥的服务器列表,留空表示全部启用'),
45
+ }).description('MCSMANAGER 鹊桥配置');
@@ -11,6 +11,25 @@ export declare class MCManager {
11
11
  mcManagerHost: Schema<string, string>;
12
12
  mcManagerWs: Schema<string, string>;
13
13
  mcManagerMaxConnectWs: Schema<number, number>;
14
+ }> | Schemastery.ObjectS<{
15
+ queQiaoEnable: Schema<boolean, boolean>;
16
+ queQiaoSendToChannel: Schema<string[], string[]>;
17
+ queQiaoWatchChannel: Schema<string[], string[]>;
18
+ queQiaoServers: Schema<Schemastery.ObjectS<{
19
+ enable: Schema<boolean, boolean>;
20
+ rconServerHost: Schema<string, string>;
21
+ rconPassword: Schema<string, string>;
22
+ wsHost: Schema<string, string>;
23
+ Token: Schema<string, string>;
24
+ serverName: Schema<string, string>;
25
+ }>[], Schemastery.ObjectT<{
26
+ enable: Schema<boolean, boolean>;
27
+ rconServerHost: Schema<string, string>;
28
+ rconPassword: Schema<string, string>;
29
+ wsHost: Schema<string, string>;
30
+ Token: Schema<string, string>;
31
+ serverName: Schema<string, string>;
32
+ }>[]>;
14
33
  }>, {
15
34
  mcManagerUsername: string;
16
35
  mcManagerPassword: string;
@@ -18,7 +37,19 @@ export declare class MCManager {
18
37
  mcManagerHost: string;
19
38
  mcManagerWs: string;
20
39
  mcManagerMaxConnectWs: number;
21
- } & import("cosmokit").Dict>;
40
+ } & import("cosmokit").Dict & {
41
+ queQiaoEnable: boolean;
42
+ queQiaoSendToChannel: string[];
43
+ queQiaoWatchChannel: string[];
44
+ queQiaoServers: Schemastery.ObjectT<{
45
+ enable: Schema<boolean, boolean>;
46
+ rconServerHost: Schema<string, string>;
47
+ rconPassword: Schema<string, string>;
48
+ wsHost: Schema<string, string>;
49
+ Token: Schema<string, string>;
50
+ serverName: Schema<string, string>;
51
+ }>[];
52
+ }>;
22
53
  private panel;
23
54
  private bot;
24
55
  constructor(gl: GLBot, ctx: Context, config: GLBotConfigType);
@@ -21,4 +21,7 @@ class MCManager {
21
21
  }
22
22
  }
23
23
  exports.MCManager = MCManager;
24
- MCManager.Config = koishi_1.Schema.intersect([config_1.MCManagerConfig.Base]);
24
+ MCManager.Config = koishi_1.Schema.intersect([
25
+ config_1.MCManagerConfig.Base,
26
+ config_1.MCManagerConfig.QueQiao,
27
+ ]);