@baipiaodajun/mcbots 1.0.4 → 1.0.6

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 +11 -1
  2. package/package.json +1 -1
  3. package/server.js +153 -80
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服务器地址和端口,其他可以根据情况改变,可以添加多台服务器。
@@ -30,7 +40,7 @@ process.on('SIGTERM', shutdown);
30
40
  "start": "node index.js"
31
41
  },
32
42
  "dependencies": {
33
- "@baipiaodajun/mcbots": "^1.0.4"
43
+ "@baipiaodajun/mcbots": "latest"
34
44
  }
35
45
  }
36
46
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@baipiaodajun/mcbots",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
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,7 +1,9 @@
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
- const CHAT = process.env.CHAT || false
5
+ const CHAT = process.env.CHAT || false ;
6
+ const MOVE = process.env.MOVE || false ;
5
7
  // Minecraft服务器配置
6
8
  const SERVERS = [
7
9
  {
@@ -25,24 +27,58 @@ if (process && process.env && process.env.SERVERS_JSON) {
25
27
  console.error('原因:', error.message);
26
28
  console.error('原始内容:\n', process.env.SERVERS_JSON);
27
29
  console.error('请检查 JSON 格式是否正确,例如引号、逗号是否缺失');
28
- console.error('容器即将退出...');
30
+ console.error('即将退出...');
29
31
  process.exit(1);
30
32
  }
31
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
+ });
32
56
 
57
+ // 超时
58
+ socket.setTimeout(timeoutMs, () => {
59
+ socket.destroy();
60
+ resolve(false);
61
+ });
62
+
63
+ // 尝试连接
64
+ socket.connect(port, host);
65
+ });
66
+ }
33
67
  // 配置常量
34
68
  const BOT_CONFIG = {
35
69
  reconnectDelay: 5000,
36
70
  maxReconnectAttempts: 5,
37
71
  healthCheckInterval: 60000,
38
72
  viewDistance: 4,
39
- chat: CHAT
73
+ connectTimeout: 2000,
74
+ chat: CHAT,
75
+ move: MOVE
40
76
  };
41
77
 
42
78
  const SERVER_CONFIG = {
43
79
  statusCheckInterval: 30000,
44
- maxFailedAttempts: 5,
45
- resetTimeout: 180000
80
+ maxFailedAttempts: 3,
81
+ resetTimeout: 30000
46
82
  };
47
83
 
48
84
  // 全局状态存储
@@ -56,15 +92,13 @@ function generateUsername() {
56
92
  ];
57
93
 
58
94
  const animals = [
59
- 'Fox', 'Wolf', 'Bear', 'Panda', 'Tiger', 'Eagle', 'Shark',
60
- 'Mole', 'Badger', 'Otter', 'Raccoon', 'Frog', 'Hedgehog'
95
+ 'Fox', 'Wolf', 'Bear', 'Panda', 'Tiger', 'Eagle', 'Shark',
96
+ 'Mole', 'Badger', 'Otter', 'Cat', 'Frog', 'Dog'
61
97
  ];
62
98
 
63
99
  const adjective = adjectives[Math.floor(Math.random() * adjectives.length)];
64
100
  const animal = animals[Math.floor(Math.random() * animals.length)];
65
- const number = Math.random() > 0.5 ? Math.floor(Math.random() * 99) : ''; // 50% 加数字
66
-
67
- return `${adjective}${animal}${number}`;
101
+ return `${adjective}${animal}`;
68
102
  }
69
103
  // Minecraft机器人管理器
70
104
  class MinecraftBotManager {
@@ -80,13 +114,11 @@ 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
- this.botNames = [
86
- generateUsername(),
87
- generateUsername(),
88
- generateUsername()
89
- ];
121
+ this.botNames = Array.from({ length: 20 }, () => generateUsername());
90
122
 
91
123
  // 注册到全局状态
92
124
  globalServerStatus.servers.set(`${host}:${port}`, {
@@ -107,41 +139,62 @@ class MinecraftBotManager {
107
139
  const randomNum = Math.floor(Math.random() * 1000);
108
140
  return `${baseName}${randomNum}`;
109
141
  }
110
-
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
+ }
111
156
  // 创建Minecraft机器人
112
- async createBot() {
157
+ async createBot(botName) {
113
158
  if (this.currentBots >= this.maxBots) {
114
159
  console.log(`[${this.host}:${this.port}] 已达到最大机器人限制: ${this.maxBots}`);
115
160
  return null;
116
161
  }
117
-
118
- const botName = this.generateBotName();
119
-
162
+ await this.testmc();
163
+ if (!this.reachable) {
164
+ return null;
165
+ }
166
+ if(!botName){
167
+ botName = this.generateBotName();
168
+ }
120
169
  try {
121
170
  console.log(`[${this.host}:${this.port}] 创建机器人: ${botName}`);
122
-
123
- const bot = mineflayer.createBot({
124
- host: this.host,
125
- port: this.port,
126
- username: botName,
127
- version: this.version,
128
- viewDistance: BOT_CONFIG.viewDistance,
129
- auth: 'offline'
130
- });
131
-
132
- // 设置机器人事件处理
133
- this.setupBotEvents(bot, botName);
134
-
135
- this.activeBots.set(botName, bot);
136
- this.currentBots++;
137
- this.failedAttempts = 0;
138
- this.updateStatus();
139
-
140
- return bot;
141
-
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);
186
+
187
+ // 设置机器人事件处理
188
+ this.setupBotEvents(bot, botName);
189
+
190
+ this.activeBots.set(botName, bot);
191
+ this.currentBots++;
192
+ // this.failedAttempts = 0;
193
+ this.updateStatus();
194
+ return bot;
142
195
  } catch (error) {
143
196
  console.log(`[${this.host}:${this.port}] 创建机器人 ${botName} 失败:`, error.message);
144
- this.handleBotFailure();
197
+ this.handleBotFailure(botName);
145
198
  return null;
146
199
  }
147
200
  }
@@ -150,6 +203,10 @@ class MinecraftBotManager {
150
203
  setupBotEvents(bot, botName) {
151
204
  bot.on('login', () => {
152
205
  console.log(`[${this.host}:${this.port}] 机器人 ${botName} 登录成功`);
206
+ if (this.timeout) {
207
+ clearTimeout(this.timeout);
208
+ this.timeout = null;
209
+ }
153
210
  this.updateStatus();
154
211
  });
155
212
 
@@ -167,25 +224,21 @@ class MinecraftBotManager {
167
224
 
168
225
  bot.on('error', (error) => {
169
226
  console.log(`[${this.host}:${this.port}] 机器人 ${botName} 错误:`, error.message);
170
-
171
- // 重要修复:在错误事件中也处理断开连接
172
- if (error.message.includes('timed out') || error.message.includes('keepAlive')) {
173
- console.log(`[${this.host}:${this.port}] 检测到超时错误,强制断开机器人: ${botName}`);
227
+ if (this.activeBots.has(botName) && this.failedAttempts <= SERVER_CONFIG.maxFailedAttempts) {
174
228
  this.handleBotDisconnect(botName);
175
- // 强制结束连接
176
- try {
177
- bot.end();
178
- } catch (e) {
179
- // 忽略结束时的错误
180
- }
181
229
  } else {
182
- this.handleBotFailure();
230
+ this.handleBotFailure(botName);
183
231
  }
184
232
  });
185
233
 
186
234
  bot.on('end', (reason) => {
187
235
  console.log(`[${this.host}:${this.port}] 机器人 ${botName} 断开连接:`, reason);
188
- 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
+ }
189
242
  });
190
243
 
191
244
  bot.on('kicked', (reason) => {
@@ -197,21 +250,22 @@ class MinecraftBotManager {
197
250
  // 设置机器人行为
198
251
  setupBotBehavior(bot, botName) {
199
252
  // 随机移动
200
- setInterval(() => {
201
- if (bot.entity && Math.random() < 0.3) {
202
- const yaw = Math.random() * Math.PI * 2;
203
- const pitch = Math.random() * Math.PI - Math.PI / 2;
204
- bot.look(yaw, pitch, false);
205
-
206
- if (Math.random() < 0.2) {
207
- bot.setControlState('forward', true);
208
- setTimeout(() => {
209
- bot.setControlState('forward', false);
210
- }, 1000);
253
+ if (BOT_CONFIG.move){
254
+ setInterval(() => {
255
+ if (bot.entity && Math.random() < 0.3) {
256
+ const yaw = Math.random() * Math.PI * 2;
257
+ const pitch = Math.random() * Math.PI - Math.PI / 2;
258
+ bot.look(yaw, pitch, false);
259
+
260
+ if (Math.random() < 0.2) {
261
+ bot.setControlState('forward', true);
262
+ setTimeout(() => {
263
+ bot.setControlState('forward', false);
264
+ }, 1000);
265
+ }
211
266
  }
212
- }
213
- }, 5000);
214
-
267
+ }, 5000);
268
+ }
215
269
  // 随机聊天(如果启用)
216
270
  if (BOT_CONFIG.chat && Math.random() < 0.1) {
217
271
  setInterval(() => {
@@ -233,25 +287,33 @@ class MinecraftBotManager {
233
287
  // 记录断开连接时间,用于调试
234
288
  console.log(`[${this.host}:${this.port}] 当前活跃机器人数量: ${this.currentBots}, 目标: ${this.minBots}`);
235
289
 
290
+ if(this.failedAttempts > SERVER_CONFIG.maxFailedAttempts){
291
+ console.log(`[${this.host}:${this.port}] 机器人 ${botName} 重连次数太多,跳过`);
292
+ return;
293
+ }
236
294
  // 延迟重连,避免频繁重连
237
295
  setTimeout(() => {
238
- this.maintainBots();
296
+ this.reconnect(botName);
239
297
  }, BOT_CONFIG.reconnectDelay);
240
298
  } else {
241
299
  console.log(`[${this.host}:${this.port}] 机器人 ${botName} 不在活跃列表中,无需处理`);
242
300
  }
243
301
  }
244
-
302
+
245
303
  // 处理机器人失败
246
- handleBotFailure() {
304
+ handleBotFailure(botName) {
247
305
  this.failedAttempts++;
248
306
  this.updateStatus();
249
-
250
307
  if (this.failedAttempts >= SERVER_CONFIG.maxFailedAttempts) {
251
- console.log(`[${this.host}:${this.port}] 失败次数过多,暂停连接尝试`);
308
+ console.log(`[${this.host}:${this.port}] 失败次数过多,${SERVER_CONFIG.resetTimeout / 1000}秒后再次尝试`);
252
309
  setTimeout(() => {
253
310
  this.failedAttempts = 0;
254
- this.maintainBots();
311
+ if(botName){
312
+ this.reconnect(botName);
313
+ }
314
+ else{
315
+ this.maintainBots();
316
+ }
255
317
  }, SERVER_CONFIG.resetTimeout);
256
318
  return;
257
319
  }
@@ -262,7 +324,7 @@ class MinecraftBotManager {
262
324
  }
263
325
 
264
326
  // 维护机器人数目 - 增强版本
265
- maintainBots() {
327
+ maintainBots(botName) {
266
328
  const neededBots = this.minBots - this.currentBots;
267
329
 
268
330
  // console.log(`[${this.host}:${this.port}] 当前机器人: ${this.currentBots}, 需要: ${neededBots}, 失败次数: ${this.failedAttempts}`);
@@ -272,16 +334,27 @@ class MinecraftBotManager {
272
334
 
273
335
  for (let i = 0; i < neededBots; i++) {
274
336
  setTimeout(() => {
275
- this.createBot();
276
- }, i * 2000); // 每隔2秒启动一个
337
+ this.createBot(botName);
338
+ }, i * 8000); // 每隔8秒启动一个
277
339
  }
278
- } 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{
279
354
  console.log(`[${this.host}:${this.port}] 由于失败次数过多,暂停创建新机器人`);
280
355
  }
281
-
282
356
  this.updateStatus();
283
357
  }
284
-
285
358
  // 更新状态
286
359
  updateStatus() {
287
360
  const serverInfo = globalServerStatus.servers.get(`${this.host}:${this.port}`);