@baipiaodajun/mcbots 1.0.5 → 1.0.7

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 (3) hide show
  1. package/README.md +10 -0
  2. package/package.json +1 -1
  3. package/server.js +120 -35
package/README.md CHANGED
@@ -1,6 +1,16 @@
1
1
  # 🛡️ Minecraft 保活机器人及监控面板 - @baipiaodajun/mcbots
2
2
 
3
+ ## 特性
4
+
5
+ - 多服务器配置:支持通过 SERVERS_JSON 文件一次性定义多个 MC 服务器,并为每个服务器自动创建对应的机器人连接。
6
+ - 智能网络检测:支持连接超时监控,自动在 30 秒后尝试重连。
7
+ - 实时监控面板:机器人运行状态即时更新,便于统一管理与观察。
8
+ - 多实例支持:同一服务器可同时连接并管理多个机器人。
9
+ - 可配置行为变量:通过设置 CHAT 与 MOVE 环境变量,灵活控制机器人聊天或移动行为。
10
+
11
+
3
12
  ## 用法
13
+
4
14
  ### nodejs
5
15
  新建一个 index.js 文件,内容如下:
6
16
  其中内容替换成你自己的MC服务器地址和端口,其他可以根据情况改变,可以添加多台服务器。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@baipiaodajun/mcbots",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Minecraft bot and status dashboard for multi-server management",
5
5
  "main": "server.js",
6
6
  "scripts": {
package/server.js CHANGED
@@ -1,5 +1,6 @@
1
1
  const mineflayer = require('mineflayer');
2
2
  const express = require('express');
3
+ const net = require('net');
3
4
  const PORT = process.env.SERVER_PORT || process.env.PORT || 3000 ;
4
5
  const CHAT = process.env.CHAT || false ;
5
6
  const MOVE = process.env.MOVE || false ;
@@ -30,21 +31,54 @@ if (process && process.env && process.env.SERVERS_JSON) {
30
31
  process.exit(1);
31
32
  }
32
33
  }
34
+ /**
35
+ * 测试 IP 和端口是否可达
36
+ * @param {string} host - IP 或域名
37
+ * @param {number} port - 端口号
38
+ * @param {number} timeoutMs - 超时时间(毫秒)
39
+ * @returns {Promise<boolean>}
40
+ */
41
+ function testConnection(host, port, timeoutMs = 5000) {
42
+ return new Promise((resolve) => {
43
+ const socket = new net.Socket();
44
+
45
+ // 成功连接
46
+ socket.once('connect', () => {
47
+ socket.destroy();
48
+ resolve(true);
49
+ });
50
+
51
+ // 出错或拒绝连接
52
+ socket.once('error', () => {
53
+ socket.destroy();
54
+ resolve(false);
55
+ });
56
+
57
+ // 超时
58
+ socket.setTimeout(timeoutMs, () => {
59
+ socket.destroy();
60
+ resolve(false);
61
+ });
33
62
 
63
+ // 尝试连接
64
+ socket.connect(port, host);
65
+ });
66
+ }
34
67
  // 配置常量
35
68
  const BOT_CONFIG = {
36
69
  reconnectDelay: 5000,
37
70
  maxReconnectAttempts: 5,
38
71
  healthCheckInterval: 60000,
39
72
  viewDistance: 4,
73
+ connectTimeout: 15000,
40
74
  chat: CHAT,
41
75
  move: MOVE
42
76
  };
43
77
 
44
78
  const SERVER_CONFIG = {
45
79
  statusCheckInterval: 30000,
46
- maxFailedAttempts: 5,
47
- resetTimeout: 300000
80
+ maxFailedAttempts: 3,
81
+ resetTimeout: 30000
48
82
  };
49
83
 
50
84
  // 全局状态存储
@@ -80,7 +114,9 @@ class MinecraftBotManager {
80
114
  this.lastUpdate = Date.now();
81
115
  this.status = 'initializing';
82
116
  this.monitoringInterval = null;
83
-
117
+ this.timeout= null;
118
+ this.reachable=false;
119
+ this.lastReachable = null;
84
120
  // 机器人名称池
85
121
  this.botNames = Array.from({ length: 20 }, () => generateUsername());
86
122
 
@@ -103,41 +139,62 @@ class MinecraftBotManager {
103
139
  const randomNum = Math.floor(Math.random() * 1000);
104
140
  return `${baseName}${randomNum}`;
105
141
  }
106
-
142
+ async testmc() {
143
+ const reachable = await testConnection(this.host, this.port, 3000);
144
+ this.reachable = reachable;
145
+
146
+ // 只有状态发生变化时才通知
147
+ if (this.reachable !== this.lastReachable) {
148
+ if (!this.reachable) {
149
+ console.log(`[${this.host}:${this.port}] MC服务器网络不可达`);
150
+ } else {
151
+ console.log(`[${this.host}:${this.port}] MC服务器恢复可达`);
152
+ }
153
+ this.lastReachable = this.reachable;
154
+ }
155
+ }
107
156
  // 创建Minecraft机器人
108
157
  async createBot(botName) {
109
158
  if (this.currentBots >= this.maxBots) {
110
159
  console.log(`[${this.host}:${this.port}] 已达到最大机器人限制: ${this.maxBots}`);
111
160
  return null;
112
161
  }
162
+ await this.testmc();
163
+ if (!this.reachable) {
164
+ return null;
165
+ }
113
166
  if(!botName){
114
167
  botName = this.generateBotName();
115
168
  }
116
169
  try {
117
170
  console.log(`[${this.host}:${this.port}] 创建机器人: ${botName}`);
118
-
119
- const bot = mineflayer.createBot({
120
- host: this.host,
121
- port: this.port,
122
- username: botName,
123
- version: this.version,
124
- viewDistance: BOT_CONFIG.viewDistance,
125
- auth: 'offline'
126
- });
127
-
128
- // 设置机器人事件处理
129
- this.setupBotEvents(bot, botName);
130
-
131
- this.activeBots.set(botName, bot);
132
- this.currentBots++;
133
- this.failedAttempts = 0;
134
- this.updateStatus();
171
+ const bot = mineflayer.createBot({
172
+ host: this.host,
173
+ port: this.port,
174
+ username: botName,
175
+ version: this.version,
176
+ viewDistance: BOT_CONFIG.viewDistance,
177
+ auth: 'offline'
178
+ });
179
+
180
+ this.timeout = setTimeout(() => {
181
+ console.error(`[${this.host}:${this.port}] ${botName}连接超时,放弃等待`);
182
+ if (typeof bot.end === 'function') {
183
+ bot.end();
184
+ }
185
+ }, BOT_CONFIG.connectTimeout);
135
186
 
136
- return bot;
187
+ // 设置机器人事件处理
188
+ this.setupBotEvents(bot, botName);
137
189
 
190
+ this.activeBots.set(botName, bot);
191
+ this.currentBots++;
192
+ // this.failedAttempts = 0;
193
+ this.updateStatus();
194
+ return bot;
138
195
  } catch (error) {
139
196
  console.log(`[${this.host}:${this.port}] 创建机器人 ${botName} 失败:`, error.message);
140
- this.handleBotFailure();
197
+ this.handleBotFailure(botName);
141
198
  return null;
142
199
  }
143
200
  }
@@ -146,6 +203,10 @@ class MinecraftBotManager {
146
203
  setupBotEvents(bot, botName) {
147
204
  bot.on('login', () => {
148
205
  console.log(`[${this.host}:${this.port}] 机器人 ${botName} 登录成功`);
206
+ if (this.timeout) {
207
+ clearTimeout(this.timeout);
208
+ this.timeout = null;
209
+ }
149
210
  this.updateStatus();
150
211
  });
151
212
 
@@ -163,16 +224,21 @@ class MinecraftBotManager {
163
224
 
164
225
  bot.on('error', (error) => {
165
226
  console.log(`[${this.host}:${this.port}] 机器人 ${botName} 错误:`, error.message);
166
- if (this.activeBots.has(botName)) {
227
+ if (this.activeBots.has(botName) && this.failedAttempts <= SERVER_CONFIG.maxFailedAttempts) {
167
228
  this.handleBotDisconnect(botName);
168
229
  } else {
169
- this.handleBotFailure();
230
+ this.handleBotFailure(botName);
170
231
  }
171
232
  });
172
233
 
173
234
  bot.on('end', (reason) => {
174
235
  console.log(`[${this.host}:${this.port}] 机器人 ${botName} 断开连接:`, reason);
175
- this.handleBotDisconnect(botName);
236
+ console.log(`[${this.host}:${this.port}] ${botName}:失败次数${this.failedAttempts}`);
237
+ if (this.failedAttempts < SERVER_CONFIG.maxFailedAttempts) {
238
+ this.handleBotDisconnect(botName);
239
+ } else {
240
+ this.handleBotFailure(botName);
241
+ }
176
242
  });
177
243
 
178
244
  bot.on('kicked', (reason) => {
@@ -221,9 +287,13 @@ class MinecraftBotManager {
221
287
  // 记录断开连接时间,用于调试
222
288
  console.log(`[${this.host}:${this.port}] 当前活跃机器人数量: ${this.currentBots}, 目标: ${this.minBots}`);
223
289
 
290
+ if(this.failedAttempts > SERVER_CONFIG.maxFailedAttempts){
291
+ console.log(`[${this.host}:${this.port}] 机器人 ${botName} 重连次数太多,跳过`);
292
+ return;
293
+ }
224
294
  // 延迟重连,避免频繁重连
225
295
  setTimeout(() => {
226
- this.maintainBots(botName);
296
+ this.reconnect(botName);
227
297
  }, BOT_CONFIG.reconnectDelay);
228
298
  } else {
229
299
  console.log(`[${this.host}:${this.port}] 机器人 ${botName} 不在活跃列表中,无需处理`);
@@ -231,15 +301,19 @@ class MinecraftBotManager {
231
301
  }
232
302
 
233
303
  // 处理机器人失败
234
- handleBotFailure() {
304
+ handleBotFailure(botName) {
235
305
  this.failedAttempts++;
236
306
  this.updateStatus();
237
-
238
307
  if (this.failedAttempts >= SERVER_CONFIG.maxFailedAttempts) {
239
- console.log(`[${this.host}:${this.port}] 失败次数过多,暂停连接尝试`);
308
+ console.log(`[${this.host}:${this.port}] 失败次数过多,${SERVER_CONFIG.resetTimeout / 1000}秒后再次尝试`);
240
309
  setTimeout(() => {
241
310
  this.failedAttempts = 0;
242
- this.maintainBots();
311
+ if(botName){
312
+ this.reconnect(botName);
313
+ }
314
+ else{
315
+ this.maintainBots();
316
+ }
243
317
  }, SERVER_CONFIG.resetTimeout);
244
318
  return;
245
319
  }
@@ -261,15 +335,26 @@ class MinecraftBotManager {
261
335
  for (let i = 0; i < neededBots; i++) {
262
336
  setTimeout(() => {
263
337
  this.createBot(botName);
264
- }, i * 10000); // 每隔10秒启动一个
338
+ }, i * 8000); // 每隔8秒启动一个
265
339
  }
266
- } else if (neededBots > 0) {
340
+ }
341
+ // else if (neededBots > 0) {
342
+ // console.log(`[${this.host}:${this.port}] 由于失败次数过多,暂停创建新机器人`);
343
+ // }
344
+ this.updateStatus();
345
+ }
346
+ reconnect(botName){
347
+ if (this.failedAttempts < SERVER_CONFIG.maxFailedAttempts) {
348
+ console.log(`[${this.host}:${this.port}] 第${this.failedAttempts}次重连 ${botName} 机器人`);
349
+ this.failedAttempts++;
350
+ setTimeout(() => {
351
+ this.createBot(botName);
352
+ }, 5000);
353
+ } else{
267
354
  console.log(`[${this.host}:${this.port}] 由于失败次数过多,暂停创建新机器人`);
268
355
  }
269
-
270
356
  this.updateStatus();
271
357
  }
272
-
273
358
  // 更新状态
274
359
  updateStatus() {
275
360
  const serverInfo = globalServerStatus.servers.get(`${this.host}:${this.port}`);