koishi-plugin-gl-bot 0.0.10 → 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 (76) hide show
  1. package/lib/gl/index.d.ts +44 -54
  2. package/lib/gl/index.js +12 -7
  3. package/lib/gl/queqiao.adapter.d.ts +11 -0
  4. package/lib/gl/queqiao.adapter.js +41 -0
  5. package/lib/index.d.ts +0 -1
  6. package/lib/index.js +0 -2
  7. package/lib/mcsManager/api.d.ts +16 -2
  8. package/lib/mcsManager/api.js +149 -2
  9. package/lib/mcsManager/bot.d.ts +5 -3
  10. package/lib/mcsManager/bot.js +18 -9
  11. package/lib/mcsManager/commands/ark/create.d.ts +15 -0
  12. package/lib/mcsManager/commands/ark/create.js +66 -0
  13. package/lib/mcsManager/commands/ark/list.d.ts +14 -0
  14. package/lib/mcsManager/commands/ark/list.js +35 -0
  15. package/lib/mcsManager/commands/ark/restart.d.ts +15 -0
  16. package/lib/mcsManager/commands/{restart.js → ark/restart.js} +14 -13
  17. package/lib/mcsManager/commands/ark/start.d.ts +15 -0
  18. package/lib/mcsManager/commands/{start.js → ark/start.js} +13 -12
  19. package/lib/mcsManager/commands/ark/stop.d.ts +15 -0
  20. package/lib/mcsManager/commands/ark/stop.js +54 -0
  21. package/lib/mcsManager/commands/base.d.ts +21 -0
  22. package/lib/mcsManager/commands/base.js +44 -0
  23. package/lib/mcsManager/commands/index.d.ts +11 -10
  24. package/lib/mcsManager/commands/index.js +21 -14
  25. package/lib/mcsManager/commands/mc/create.d.ts +15 -0
  26. package/lib/mcsManager/commands/mc/create.js +79 -0
  27. package/lib/mcsManager/commands/mc/health.d.ts +16 -0
  28. package/lib/mcsManager/commands/mc/health.js +46 -0
  29. package/lib/mcsManager/commands/mc/list.d.ts +15 -0
  30. package/lib/mcsManager/commands/mc/list.js +54 -0
  31. package/lib/mcsManager/commands/mc/online.d.ts +29 -0
  32. package/lib/mcsManager/commands/mc/online.js +149 -0
  33. package/lib/mcsManager/commands/mc/restart.d.ts +15 -0
  34. package/lib/mcsManager/commands/mc/restart.js +62 -0
  35. package/lib/mcsManager/commands/mc/start.d.ts +15 -0
  36. package/lib/mcsManager/commands/mc/start.js +54 -0
  37. package/lib/mcsManager/commands/mc/stop.d.ts +15 -0
  38. package/lib/mcsManager/commands/mc/stop.js +54 -0
  39. package/lib/mcsManager/config.d.ts +39 -0
  40. package/lib/mcsManager/config.js +21 -0
  41. package/lib/mcsManager/index.d.ts +36 -4
  42. package/lib/mcsManager/index.js +9 -3
  43. package/lib/mcsManager/json/createInstanceUpload.json +49 -0
  44. package/lib/mcsManager/panel.d.ts +1 -1
  45. package/lib/mcsManager/panel.js +1 -1
  46. package/lib/mcsManager/schedules/index.d.ts +8 -0
  47. package/lib/mcsManager/schedules/index.js +41 -0
  48. package/lib/mcsManager/schedules/mc.schedule.d.ts +11 -0
  49. package/lib/mcsManager/schedules/mc.schedule.js +15 -0
  50. package/lib/mcsManager/type.d.ts +104 -0
  51. package/lib/mcsManager/ws.js +1 -1
  52. package/lib/napCat/api.d.ts +21 -0
  53. package/lib/napCat/api.js +43 -0
  54. package/lib/napCat/config.d.ts +10 -0
  55. package/lib/napCat/config.js +16 -0
  56. package/lib/napCat/index.d.ts +16 -0
  57. package/lib/napCat/index.js +15 -0
  58. package/lib/queQiao/index.d.ts +47 -37
  59. package/lib/queQiao/index.js +141 -39
  60. package/lib/queQiao/locale/zh-CN.json +1 -1
  61. package/lib/queQiao/locale/zh-CN.yml +6 -6
  62. package/lib/queQiao/mcwss.d.ts +12 -9
  63. package/lib/queQiao/mcwss.js +34 -2
  64. package/lib/queQiao/values.js +2 -2
  65. package/lib/utils/game.mc.js +5 -4
  66. package/lib/utils/index.d.ts +7 -0
  67. package/lib/utils/index.js +58 -0
  68. package/package.json +2 -1
  69. package/lib/constants/env.d.ts +0 -0
  70. package/lib/constants/env.js +0 -0
  71. package/lib/gl/index.type.d.ts +0 -0
  72. package/lib/gl/index.type.js +0 -0
  73. package/lib/mcsManager/commands/list.d.ts +0 -11
  74. package/lib/mcsManager/commands/list.js +0 -26
  75. package/lib/mcsManager/commands/restart.d.ts +0 -12
  76. package/lib/mcsManager/commands/start.d.ts +0 -12
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = (ctx) => {
4
+ ctx.model.extend('mcUser', {
5
+ id: { type: 'unsigned', length: 8 },
6
+ nickname: 'string',
7
+ uuid: 'string',
8
+ lastTime: 'timestamp',
9
+ level: 'integer',
10
+ onlineTimeJSON: 'text',
11
+ }, {
12
+ primary: 'id',
13
+ autoInc: true,
14
+ });
15
+ };
@@ -1,3 +1,4 @@
1
+ import MinecraftSyncMsg from '../queQiao';
1
2
  import { RemoteInstanceStatusEnum } from './constants';
2
3
  import { MCSManagerInstance } from './instance';
3
4
  export interface MCManagerPanelResponse<T> {
@@ -113,3 +114,106 @@ export interface ServiceInstanceConnectAuth {
113
114
  addr: string;
114
115
  prefix: string;
115
116
  }
117
+ export interface CreateInstanceData {
118
+ nickname?: string;
119
+ startCommand?: string;
120
+ stopCommand?: string;
121
+ cwd?: string;
122
+ ie?: string;
123
+ oe?: string;
124
+ processType?: string;
125
+ createDatetime?: string;
126
+ lastDatetime?: string;
127
+ type?: string;
128
+ tag?: string[];
129
+ maxSpace?: null;
130
+ endTime?: string;
131
+ docker?: {
132
+ containerName?: string;
133
+ image?: string;
134
+ ports?: string[];
135
+ extraVolumes?: string[];
136
+ networkMode?: 'bridge';
137
+ networkAliases?: string[];
138
+ cpusetCpus?: string;
139
+ workingDir?: '/data';
140
+ changeWorkdir?: false;
141
+ env?: [];
142
+ };
143
+ }
144
+ export type TerminalOption = {
145
+ haveColor: boolean;
146
+ pty: boolean;
147
+ ptyWindowCol: number;
148
+ ptyWindowRow: number;
149
+ };
150
+ export type EventTaskConfig = {
151
+ autoStart: boolean;
152
+ autoRestart: boolean;
153
+ autoRestartMaxTimes: number;
154
+ ignore: boolean;
155
+ };
156
+ export type DockerConfig = {
157
+ containerName: string;
158
+ image: string;
159
+ ports: unknown[];
160
+ extraVolumes: unknown[];
161
+ networkMode: string;
162
+ networkAliases: string[];
163
+ cpusetCpus: string;
164
+ workingDir: string;
165
+ env: unknown[];
166
+ changeWorkdir: boolean;
167
+ };
168
+ export type PingConfig = {
169
+ ip: string;
170
+ type: number;
171
+ };
172
+ export type ExtraServiceConfig = {
173
+ openFrpTunnelId: string;
174
+ openFrpToken: string;
175
+ };
176
+ export type CreateInstanceConfig = {
177
+ nickname: string;
178
+ startCommand: string;
179
+ stopCommand: string;
180
+ cwd: string;
181
+ ie: string;
182
+ oe: string;
183
+ createDatetime: number;
184
+ lastDatetime: number;
185
+ type: string;
186
+ tag: string[];
187
+ endTime: number;
188
+ fileCode: string;
189
+ processType: string;
190
+ updateCommand: string;
191
+ runAs: string;
192
+ actionCommandList: unknown[];
193
+ crlf: number;
194
+ category: number;
195
+ enableRcon: boolean;
196
+ rconPassword: string;
197
+ rconIp: string;
198
+ terminalOption: TerminalOption;
199
+ eventTask: EventTaskConfig;
200
+ docker: DockerConfig;
201
+ pingConfig: PingConfig;
202
+ extraServiceConfig: ExtraServiceConfig;
203
+ };
204
+ export interface McUser {
205
+ nickname: string;
206
+ uuid: string;
207
+ address: string;
208
+ health: number;
209
+ max_health: number;
210
+ experience_level: number;
211
+ experience_progress: number;
212
+ total_experience: number;
213
+ is_op: boolean;
214
+ walk_speed: number;
215
+ x: number;
216
+ y: number;
217
+ z: number;
218
+ server?: Schemastery.TypeS<typeof MinecraftSyncMsg.Config>;
219
+ }
@@ -62,7 +62,7 @@ class MCSManagerWebSocketIO {
62
62
  reconnectionAttempts: 2000,
63
63
  });
64
64
  this.bindEvents();
65
- logger.info(`正在连接到 MCSManager 实例服务器 [${this.remote.remarks}] - ${this.instance.config.nickname} ...`);
65
+ logger.debug(`正在连接到 MCSManager 实例服务器 [${this.remote.remarks}] - ${this.instance.config.nickname} ...`);
66
66
  }
67
67
  // 发送MC指令到远程实例
68
68
  sendCommand(command) {
@@ -0,0 +1,21 @@
1
+ import { HTTP } from 'koishi';
2
+ export declare class NapCatApi {
3
+ private http;
4
+ private baseUrl;
5
+ private token;
6
+ get requestHeaders(): {
7
+ authorization: string;
8
+ };
9
+ constructor(http: HTTP, baseUrl: string, token: string);
10
+ /**
11
+ * 获取文件信息
12
+ * @param fileId 文件ID
13
+ * @returns 文件信息或false
14
+ */
15
+ getFile(fileId: string): Promise<false | {
16
+ file: string;
17
+ url: string;
18
+ file_size: string;
19
+ file_name: string;
20
+ }>;
21
+ }
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NapCatApi = void 0;
4
+ class NapCatApi {
5
+ get requestHeaders() {
6
+ return {
7
+ authorization: this.token,
8
+ };
9
+ }
10
+ constructor(http, baseUrl, token) {
11
+ this.http = http;
12
+ this.baseUrl = baseUrl;
13
+ this.token = token;
14
+ }
15
+ /**
16
+ * 获取文件信息
17
+ * @param fileId 文件ID
18
+ * @returns 文件信息或false
19
+ */
20
+ async getFile(fileId) {
21
+ console.log(`${this.baseUrl}/get_file`, {
22
+ file_id: fileId,
23
+ });
24
+ try {
25
+ const result = await this.http(`${this.baseUrl}/get_file`, {
26
+ method: 'POST',
27
+ headers: this.requestHeaders,
28
+ data: {
29
+ file_id: fileId,
30
+ },
31
+ });
32
+ console.log(result?.data);
33
+ if (result.status === 200 && result.data) {
34
+ return result.data.data;
35
+ }
36
+ }
37
+ catch (error) {
38
+ console.error('Error fetching file:', error);
39
+ }
40
+ return false;
41
+ }
42
+ }
43
+ exports.NapCatApi = NapCatApi;
@@ -0,0 +1,10 @@
1
+ import { Schema } from 'koishi';
2
+ export declare class NapCatConfig {
3
+ static Base: Schema<Schemastery.ObjectS<{
4
+ napCatBaseUrl: Schema<string, string>;
5
+ napCatToken: Schema<string, string>;
6
+ }>, Schemastery.ObjectT<{
7
+ napCatBaseUrl: Schema<string, string>;
8
+ napCatToken: Schema<string, string>;
9
+ }>>;
10
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NapCatConfig = void 0;
4
+ const koishi_1 = require("koishi");
5
+ class NapCatConfig {
6
+ }
7
+ exports.NapCatConfig = NapCatConfig;
8
+ NapCatConfig.Base = koishi_1.Schema.object({
9
+ napCatBaseUrl: koishi_1.Schema.string()
10
+ .default('http://localhost:3000')
11
+ .description('地址'),
12
+ napCatToken: koishi_1.Schema.string()
13
+ .role('secret')
14
+ .default('admin')
15
+ .description('密码'),
16
+ }).description('NapCat 基础配置');
@@ -0,0 +1,16 @@
1
+ import { Context, Schema } from 'koishi';
2
+ import { GLBotConfigType } from '../gl';
3
+ import { NapCatApi } from './api';
4
+ export declare class NapCat {
5
+ private readonly ctx;
6
+ private readonly config;
7
+ static Config: Schema<Schemastery.ObjectS<{
8
+ napCatBaseUrl: Schema<string, string>;
9
+ napCatToken: Schema<string, string>;
10
+ }>, {
11
+ napCatBaseUrl: string;
12
+ napCatToken: string;
13
+ } & import("cosmokit").Dict>;
14
+ readonly api: NapCatApi;
15
+ constructor(ctx: Context, config: GLBotConfigType);
16
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NapCat = void 0;
4
+ const koishi_1 = require("koishi");
5
+ const api_1 = require("./api");
6
+ const config_1 = require("./config");
7
+ class NapCat {
8
+ constructor(ctx, config) {
9
+ this.ctx = ctx;
10
+ this.config = config;
11
+ this.api = new api_1.NapCatApi(ctx.http, config.napCatBaseUrl, config.napCatToken);
12
+ }
13
+ }
14
+ exports.NapCat = NapCat;
15
+ NapCat.Config = koishi_1.Schema.intersect([config_1.NapCatConfig.Base]);
@@ -1,6 +1,13 @@
1
- import { Context, Schema } from 'koishi';
2
- import { GLBotConfigType } from '../gl';
1
+ import { Context, Schema, h } from 'koishi';
2
+ import { Rcon } from 'rcon-client';
3
+ import { RawData, WebSocket } from 'ws';
4
+ import { GLQueQiaoAdapter } from '../gl/queqiao.adapter';
5
+ import McWss from './mcwss';
3
6
  export declare const name = "minecraft-sync-msg";
7
+ interface MessageColor {
8
+ output: string;
9
+ color: string;
10
+ }
4
11
  export interface WsMessageData {
5
12
  api: string;
6
13
  data: {
@@ -13,41 +20,44 @@ export interface WsMessageData {
13
20
  };
14
21
  }
15
22
  declare class MinecraftSyncMsg {
16
- private ctx;
17
- private config;
18
- private ws;
19
- private rcon;
20
- private isDisposing;
21
- private reconnectAttempts;
22
- private reconnectIntervalId;
23
- private plFork;
24
- private enUS;
25
- private zhCN;
26
- constructor(ctx: Context, config: GLBotConfigType);
27
- private initialize;
28
- private setupRcon;
29
- private connectToRcon;
30
- private setupWebSocket;
31
- private connectWebSocket;
32
- private bindWebSocketEvents;
33
- private handleWsOpen;
34
- private handleWsMessage;
35
- private handleWsClose;
36
- private handleWsError;
37
- private setupWatchChannel;
38
- private reconnectWebSocket;
39
- private clearReconnectInterval;
40
- private setupMessageHandler;
41
- private isValidChannel;
42
- private isMessageCommand;
43
- private isRconCommand;
44
- private handleMessageCommand;
45
- private handleRconCommand;
46
- private sendRconCommand;
47
- private extractAndRemoveColor;
48
- private broadcastToChannels;
49
- private setupDisposeHandler;
50
- private dispose;
23
+ ctx: Context;
24
+ adapter: GLQueQiaoAdapter;
25
+ config: Schemastery.TypeS<typeof MinecraftSyncMsg.Config>;
26
+ ws: WebSocket | undefined;
27
+ rcon: Rcon;
28
+ isDisposing: boolean;
29
+ reconnectAttempts: number;
30
+ reconnectIntervalId: NodeJS.Timeout | null;
31
+ plFork: McWss;
32
+ enUS: any;
33
+ zhCN: any;
34
+ get serverName(): any;
35
+ constructor(ctx: Context, adapter: GLQueQiaoAdapter, config: Schemastery.TypeS<typeof MinecraftSyncMsg.Config>);
36
+ initialize(): void;
37
+ setupRcon(): void;
38
+ connectToRcon(): Promise<void>;
39
+ setupWebSocket(): void;
40
+ connectWebSocket(): void;
41
+ bindWebSocketEvents(): void;
42
+ handleWsOpen(): void;
43
+ handleWsMessage(buffer: RawData): void;
44
+ updatePlayerOnlineTime(data: any): Promise<void>;
45
+ handleWsClose(): void;
46
+ handleWsError(err: Error): void;
47
+ setupWatchChannel(): void;
48
+ reconnectWebSocket(): Promise<void>;
49
+ clearReconnectInterval(): void;
50
+ setupMessageHandler(): void;
51
+ isValidChannel(session: any): boolean;
52
+ isMessageCommand(session: any): boolean;
53
+ isRconCommand(session: any): boolean;
54
+ handleMessageCommand(session: any): Promise<void>;
55
+ handleRconCommand(session: any): Promise<void>;
56
+ sendRconCommand(command: string): Promise<string>;
57
+ extractAndRemoveColor(input?: string): MessageColor;
58
+ broadcastToChannels(message: string | h[]): void;
59
+ setupDisposeHandler(): void;
60
+ dispose(): Promise<void>;
51
61
  }
52
62
  declare namespace MinecraftSyncMsg {
53
63
  const Config: Schema<Schemastery.ObjectS<{
@@ -9,6 +9,7 @@ const lodash_1 = require("lodash");
9
9
  const rcon_client_1 = require("rcon-client");
10
10
  const ws_1 = require("ws");
11
11
  const constants_1 = require("../constants");
12
+ const online_1 = require("../mcsManager/commands/mc/online");
12
13
  const utils_1 = require("../utils");
13
14
  const mcwss_1 = __importDefault(require("./mcwss"));
14
15
  const values_1 = require("./values");
@@ -19,8 +20,12 @@ const enUS = require('./locale/en-US.json');
19
20
  exports.name = 'minecraft-sync-msg';
20
21
  const logger = new koishi_1.Logger('minecraft-sync-msg');
21
22
  class MinecraftSyncMsg {
22
- constructor(ctx, config) {
23
+ get serverName() {
24
+ return this.config.serverName ?? '--';
25
+ }
26
+ constructor(ctx, adapter, config) {
23
27
  this.ctx = ctx;
28
+ this.adapter = adapter;
24
29
  this.config = config;
25
30
  this.isDisposing = false;
26
31
  this.reconnectAttempts = 0;
@@ -37,7 +42,7 @@ class MinecraftSyncMsg {
37
42
  this.ctx.i18n.define('en-US', enUS);
38
43
  }
39
44
  setupRcon() {
40
- if (!this.config.rconEnable) {
45
+ if (!this.config.rconServerHost) {
41
46
  return;
42
47
  }
43
48
  this.rcon = new rcon_client_1.Rcon({
@@ -46,23 +51,23 @@ class MinecraftSyncMsg {
46
51
  password: this.config.rconPassword,
47
52
  });
48
53
  this.connectToRcon().catch(err => {
49
- logger.error('RCON服务器连接失败:', err);
54
+ logger.error(`[${this.serverName}] RCON服务器连接失败:`, err);
50
55
  });
51
56
  }
52
57
  async connectToRcon() {
53
58
  try {
54
59
  await this.rcon.connect();
55
- logger.info('已连接到RCON服务器');
60
+ logger.info(`[${this.serverName}] 已连接到RCON服务器`);
56
61
  }
57
62
  catch (err) {
58
- logger.error('连接到RCON服务器时发生错误:', err);
63
+ logger.error(`[${this.serverName}] 连接到RCON服务器时发生错误:`, err);
59
64
  throw err;
60
65
  }
61
66
  }
62
67
  setupWebSocket() {
63
68
  if (this.config.wsServer === '服务端') {
64
- this.plFork = this.ctx.plugin(mcwss_1.default, this.config);
65
- // this.plFork = new McWss(this.ctx, this.config);
69
+ // this.plFork = this.ctx.plugin(McWss, this.adapter, this.config);
70
+ this.plFork = new mcwss_1.default(this.ctx, this.adapter, this.config);
66
71
  return;
67
72
  }
68
73
  else {
@@ -90,10 +95,10 @@ class MinecraftSyncMsg {
90
95
  this.ws.on('error', err => this.handleWsError(err));
91
96
  }
92
97
  handleWsOpen() {
93
- logger.info('成功连上websocket服务器');
94
- if (!this.config.hideConnect) {
95
- this.broadcastToChannels('Websocket服务器连接成功!');
96
- }
98
+ logger.info(`[${this.serverName}] 成功连上websocket服务器`);
99
+ // if (!this.config.hideConnect) {
100
+ // this.broadcastToChannels('Websocket服务器连接成功!');
101
+ // }
97
102
  if (!constants_1.IS_DEV) {
98
103
  const msgData = {
99
104
  api: 'broadcast',
@@ -120,8 +125,11 @@ class MinecraftSyncMsg {
120
125
  logger.error('Failed to parse WebSocket message:', err);
121
126
  return;
122
127
  }
128
+ // 在线时间逻辑
129
+ this.updatePlayerOnlineTime(data);
123
130
  const eventName = data.event_name ? (0, values_1.getListeningEvent)(data.event_name) : '';
124
- if (eventName === 'PlayerCommandPreprocessEvent') {
131
+ if (!eventName ||
132
+ ['PlayerCommandPreprocessEvent', 'PlayerDeathEvent'].includes(eventName)) {
125
133
  return;
126
134
  }
127
135
  // console.log(data);
@@ -144,19 +152,112 @@ class MinecraftSyncMsg {
144
152
  if (sendImage) {
145
153
  sendMsg = sendMsg.replace(sendImage, `<img src="${sendImage}" />`);
146
154
  }
147
- sendMsg = this.ctx.i18n.render([this.config.locale ? this.config.locale : 'zh-CN'], [`minecraft-sync-msg.action.${eventName}`], [data.player?.nickname, sendMsg]);
155
+ sendMsg = this.ctx.i18n.render([this.config.locale ? this.config.locale : 'zh-CN'], [`minecraft-sync-msg.action.${eventName}`], [this.config.serverName ?? 'MC', data.player?.nickname, sendMsg]);
156
+ /// 多服消息互通逻辑
157
+ // if (data.event_name && isEqual(eventName, 'AsyncPlayerChatEvent')) {
158
+ // Object.entries(this.adapter.servers).forEach(
159
+ // async ([serverName, server]) => {
160
+ // if (!isEqual(serverName, this.config.serverName)) {
161
+ // const msgData: WsMessageData = {
162
+ // api: 'broadcast',
163
+ // data: {
164
+ // message: [
165
+ // {
166
+ // text: `[${this.config.serverName}] <${data.player?.nickname}> ${clearSessionContentToMcMessage(data.message)}`,
167
+ // color:
168
+ // server.extractAndRemoveColor(server.config.joinMsg)
169
+ // .color || 'white',
170
+ // },
171
+ // ],
172
+ // },
173
+ // };
174
+ // server.ws?.send(JSON.stringify(msgData));
175
+ // }
176
+ // },
177
+ // );
178
+ // }
148
179
  if (data.server_name && sendMsg) {
149
180
  this.broadcastToChannels(sendMsg);
150
181
  }
151
182
  }
183
+ async updatePlayerOnlineTime(data) {
184
+ if (!online_1.MCBotGameOnline.list[this.serverName]) {
185
+ online_1.MCBotGameOnline.list[this.serverName] = {
186
+ config: this.config,
187
+ list: {},
188
+ };
189
+ }
190
+ const playerId = data.player?.uuid + '|' + this.serverName;
191
+ if (data.player) {
192
+ online_1.MCBotGameOnline.list[this.serverName].list[data.player?.nickname] =
193
+ data.player;
194
+ }
195
+ if (!['PlayerJoinEvent', 'PlayerQuitEvent'].includes(data.event_name)) {
196
+ return;
197
+ }
198
+ const user = await this.ctx.database.get('mcUser', {
199
+ uuid: data.player?.uuid,
200
+ });
201
+ if (user.length === 0) {
202
+ await this.ctx.database.create('mcUser', {
203
+ nickname: data.player?.nickname,
204
+ uuid: data.player?.uuid,
205
+ lastTime: new Date(),
206
+ level: data.player?.level || 0,
207
+ onlineTimeJSON: JSON.stringify({
208
+ mc: {
209
+ [playerId]: 0,
210
+ },
211
+ }),
212
+ });
213
+ return;
214
+ }
215
+ if (data.event_name === 'PlayerJoinEvent') {
216
+ await this.ctx.database.set('mcUser', { uuid: data.player?.uuid }, {
217
+ nickname: data.player?.nickname,
218
+ level: data.player?.experience_level || 0,
219
+ lastTime: new Date(),
220
+ });
221
+ return;
222
+ }
223
+ // 更新在线时间 (加入游戏时会更新lastTime,退出游戏时通过lastTime算出本次在线时间,加到onlineTimeJSON中)
224
+ if (data.event_name === 'PlayerQuitEvent') {
225
+ const lastTime = new Date(user[0].lastTime).getTime();
226
+ const nowTime = Date.now();
227
+ const onlineDuration = Math.floor((nowTime - lastTime) / 1000); // 在线时长,单位秒
228
+ delete online_1.MCBotGameOnline.list[this.serverName].list[data.player?.nickname];
229
+ let onlineTimeJSON = {};
230
+ try {
231
+ onlineTimeJSON = JSON.parse(user[0].onlineTimeJSON);
232
+ }
233
+ catch (err) {
234
+ onlineTimeJSON = {};
235
+ }
236
+ if (!onlineTimeJSON.mc) {
237
+ onlineTimeJSON.mc = {};
238
+ }
239
+ if (!onlineTimeJSON.mc[playerId]) {
240
+ onlineTimeJSON.mc[playerId] = 0;
241
+ }
242
+ onlineTimeJSON.mc[playerId] += onlineDuration;
243
+ await this.ctx.database.set('mcUser', { uuid: data.player?.uuid }, {
244
+ nickname: data.player?.nickname,
245
+ lastTime: new Date(),
246
+ level: data.player?.experience_level || 0,
247
+ onlineTimeJSON: JSON.stringify(onlineTimeJSON),
248
+ });
249
+ }
250
+ }
152
251
  handleWsClose() {
153
252
  if (this.isDisposing) {
154
253
  return;
155
254
  }
156
- if (!this.config.hideConnect) {
157
- this.broadcastToChannels('与Websocket服务器断开连接!');
158
- }
159
- logger.error('非正常与Websocket服务器断开连接!');
255
+ // if (!this.config.hideConnect) {
256
+ // this.broadcastToChannels(
257
+ // `[${this.serverName}] 与Websocket服务器断开连接!`,
258
+ // );
259
+ // }
260
+ logger.error(`[${this.serverName}] 非正常与Websocket服务器断开连接!`);
160
261
  this.ws = undefined;
161
262
  this.reconnectWebSocket();
162
263
  }
@@ -164,10 +265,12 @@ class MinecraftSyncMsg {
164
265
  if (this.isDisposing) {
165
266
  return;
166
267
  }
167
- if (!this.config.hideConnect) {
168
- this.broadcastToChannels('与Websocket服务器断通信时发生错误!');
169
- }
170
- logger.error('与Websocket服务器断通信时发生错误:', err);
268
+ // if (!this.config.hideConnect) {
269
+ // this.broadcastToChannels(
270
+ // `[${this.serverName}] 与Websocket服务器断通信时发生错误!`,
271
+ // );
272
+ // }
273
+ logger.error(`[${this.serverName}] 与Websocket服务器断通信时发生错误:`, err);
171
274
  }
172
275
  setupWatchChannel() {
173
276
  this.ctx.on('message', async (session) => {
@@ -194,13 +297,13 @@ class MinecraftSyncMsg {
194
297
  async reconnectWebSocket() {
195
298
  this.clearReconnectInterval();
196
299
  this.reconnectIntervalId = setInterval(async () => {
197
- if (this.reconnectAttempts >= this.config.maxReconnectCount) {
198
- logger.error(`已达到最大重连次数 (${this.config.maxReconnectCount} 次),停止重连。`);
300
+ if (this.reconnectAttempts >= (this.config.maxReconnectCount || 3)) {
301
+ logger.error(`[${this.serverName}] 已达到最大重连次数 (${this.config.maxReconnectCount} 次),停止重连。`);
199
302
  this.clearReconnectInterval();
200
303
  return;
201
304
  }
202
305
  this.reconnectAttempts++;
203
- logger.info(`尝试第 ${this.reconnectAttempts} 次重连...`);
306
+ logger.info(`[${this.serverName}] 尝试第 ${this.reconnectAttempts} 次重连...`);
204
307
  try {
205
308
  const headers = {
206
309
  'x-self-name': encodeURIComponent(this.config.serverName),
@@ -211,24 +314,24 @@ class MinecraftSyncMsg {
211
314
  headers,
212
315
  });
213
316
  ws.on('open', () => {
214
- logger.info('WebSocket 重连成功');
317
+ logger.info(`[${this.serverName}] WebSocket 重连成功`);
215
318
  this.clearReconnectInterval();
216
319
  this.ws = ws;
217
320
  this.bindWebSocketEvents();
218
321
  });
219
322
  ws.on('error', err => {
220
- logger.error('重连时发生错误:', err);
323
+ logger.error(`[${this.serverName}] 重连时发生错误:`, err);
221
324
  ws.close();
222
325
  });
223
326
  ws.on('close', () => {
224
327
  if (!this.isDisposing) {
225
- logger.info('WebSocket 再次断开,将继续尝试重连...');
328
+ logger.info(`[${this.serverName}] WebSocket 再次断开,将继续尝试重连...`);
226
329
  }
227
330
  });
228
331
  }
229
332
  catch (err) {
230
- logger.error('创建WebSocket时发生错误:', err);
231
- if (this.reconnectAttempts >= this.config.maxReconnectCount) {
333
+ logger.error(`[${this.serverName}] 创建WebSocket时发生错误:`, err);
334
+ if (this.reconnectAttempts >= (this.config.maxReconnectCount || 3)) {
232
335
  this.clearReconnectInterval();
233
336
  }
234
337
  }
@@ -338,31 +441,33 @@ class MinecraftSyncMsg {
338
441
  session.send(response?.replaceAll(/§./g, '') || '');
339
442
  }
340
443
  async sendRconCommand(command) {
444
+ if (!this.rcon.authenticated) {
445
+ return '';
446
+ }
341
447
  try {
342
448
  const response = await this.rcon.send(command);
343
449
  return response;
344
450
  }
345
451
  catch (err) {
346
- logger.error('发送RCON命令时发生错误:', err);
452
+ logger.error(`[${this.serverName}] 发送RCON命令时发生错误:`, err);
347
453
  throw err;
348
454
  }
349
455
  }
350
456
  extractAndRemoveColor(input) {
351
457
  const regex = /&(\w+)&/;
352
- const match = input.match(regex);
458
+ const match = input?.match(regex) ?? [];
353
459
  if (match) {
354
460
  const color = match[1];
355
- const output = input.replace(regex, '');
461
+ const output = input?.replace(regex, '');
356
462
  return { output, color };
357
463
  }
358
- return { output: input, color: '' };
464
+ return { output: input ?? '', color: '' };
359
465
  }
360
466
  broadcastToChannels(message) {
361
467
  this.ctx.bots.forEach((bot) => {
362
468
  const channels = this.config.sendToChannel
363
- .filter(str => str.includes(`${bot.platform}`))
364
- .map(str => str.replace(`${bot.platform}:`, ''));
365
- console.log(this.config.sendToChannel);
469
+ ?.filter(str => str.includes(`${bot.platform}`))
470
+ ?.map(str => str.replace(`${bot.platform}:`, '')) ?? [];
366
471
  if (process.env.NODE_ENV === 'development') {
367
472
  logger.info((0, lodash_1.isString)(message)
368
473
  ? message
@@ -379,9 +484,6 @@ class MinecraftSyncMsg {
379
484
  });
380
485
  }
381
486
  async dispose() {
382
- if (this.plFork) {
383
- await this.plFork.dispose();
384
- }
385
487
  this.ctx.registry.delete(mcwss_1.default);
386
488
  if (this.ws) {
387
489
  this.ws.removeAllListeners();