@baipiaodajun/mcbots 1.2.1 → 1.2.3
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/package.json +1 -1
- package/server.js +133 -74
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -10,6 +10,13 @@ const fs = require('fs');
|
|
|
10
10
|
const PORT = process.env.SERVER_PORT || process.env.PORT || 3000 ;
|
|
11
11
|
const CHAT = process.env.CHAT || false ;
|
|
12
12
|
const MOVE = process.env.MOVE || false ;
|
|
13
|
+
//debug模式,只有开启时才会有很多日志。
|
|
14
|
+
const DEBUG = (process.env.DEBUG || '').toLowerCase() === 'true';
|
|
15
|
+
function debugPrint(...args) {
|
|
16
|
+
if (DEBUG) {
|
|
17
|
+
console.log(...args);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
13
20
|
// Minecraft服务器配置
|
|
14
21
|
const SERVERS = [
|
|
15
22
|
{
|
|
@@ -124,7 +131,7 @@ const BOT_CONFIG = {
|
|
|
124
131
|
|
|
125
132
|
const SERVER_CONFIG = {
|
|
126
133
|
statusCheckInterval: 30000,
|
|
127
|
-
maxFailedAttempts:
|
|
134
|
+
maxFailedAttempts: 1,
|
|
128
135
|
resetTimeout: 30000
|
|
129
136
|
};
|
|
130
137
|
|
|
@@ -207,6 +214,7 @@ class MinecraftBotManager {
|
|
|
207
214
|
this.version = version || "1.20.1";
|
|
208
215
|
this.currentBots = 0;
|
|
209
216
|
this.activeBots = new Map();
|
|
217
|
+
this.pendingReconnect = new Set(); // 等待重连的机器人名字(已断开但优先重用名字)
|
|
210
218
|
this.failedAttempts = 0;
|
|
211
219
|
this.lastUpdate = Date.now();
|
|
212
220
|
this.status = 'initializing';
|
|
@@ -300,19 +308,69 @@ class MinecraftBotManager {
|
|
|
300
308
|
this.notice=true;
|
|
301
309
|
}
|
|
302
310
|
}
|
|
311
|
+
async handleBottimeout(bot,botName){
|
|
312
|
+
this.timeout = setTimeout(() => {
|
|
313
|
+
debugPrint(`[${this.host}:${this.port}] ${botName} 连接超时,强制终止`);
|
|
314
|
+
|
|
315
|
+
// 第一步:尝试正常结束(推荐方式)
|
|
316
|
+
if (typeof bot.end === 'function') {
|
|
317
|
+
try {
|
|
318
|
+
bot.end();
|
|
319
|
+
debugPrint(`[${this.host}:${this.port}] ${botName} 调用 bot.end() 成功`);
|
|
320
|
+
return; // 如果正常结束,就不需要进一步操作
|
|
321
|
+
} catch (err) {
|
|
322
|
+
debugPrint(`[${this.host}:${this.port}] ${botName} bot.end() 抛出异常:`, err.message);
|
|
323
|
+
// 继续尝试强杀底层 socket
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// 第二步:bot.end 失败或不存在,强制关闭底层 client socket
|
|
328
|
+
if (bot._client?.socket) {
|
|
329
|
+
try {
|
|
330
|
+
bot._client.socket.destroy(); // 最彻底:直接 destroy socket
|
|
331
|
+
debugPrint(`[${this.host}:${this.port}] ${botName} 强制 destroy 底层 socket`);
|
|
332
|
+
} catch (err) {
|
|
333
|
+
debugPrint(`[${this.host}:${this.port}] ${botName} destroy socket 失败:`, err.message);
|
|
334
|
+
}
|
|
335
|
+
} else if (bot._client?.end) {
|
|
336
|
+
try {
|
|
337
|
+
bot._client.end();
|
|
338
|
+
debugPrint(`[${this.host}:${this.port}] ${botName} 调用 bot._client.end()`);
|
|
339
|
+
} catch (err) {
|
|
340
|
+
debugPrint(`[${this.host}:${this.port}] ${botName} bot._client.end() 失败:`, err.message);
|
|
341
|
+
}
|
|
342
|
+
} else {
|
|
343
|
+
debugPrint(`[${this.host}:${this.port}] ${botName} 无可用 client socket,无法强制关闭`);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// 可选:触发断开处理(确保进入重连逻辑)
|
|
347
|
+
this.handleBotDisconnect(botName);
|
|
348
|
+
|
|
349
|
+
}, BOT_CONFIG.connectTimeout);
|
|
350
|
+
}
|
|
303
351
|
// 创建Minecraft机器人
|
|
304
352
|
async createBot(botName) {
|
|
305
353
|
if (this.currentBots >= this.maxBots) {
|
|
306
354
|
console.log(`[${this.host}:${this.port}] 已达到最大机器人限制: ${this.maxBots}`);
|
|
307
355
|
return null;
|
|
308
356
|
}
|
|
309
|
-
|
|
310
|
-
if (!
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
357
|
+
|
|
358
|
+
if (!botName) {
|
|
359
|
+
if (this.pendingReconnect.size > 0) {
|
|
360
|
+
botName = this.pendingReconnect.keys().next().value;
|
|
361
|
+
this.pendingReconnect.delete(botName); // 用完就移除,避免重复分配
|
|
362
|
+
debugPrint(`[${this.host}:${this.port}] 优先重用待重连名字: ${botName} (剩余待重连: ${this.pendingReconnect.size})`);
|
|
363
|
+
} else {
|
|
364
|
+
botName = this.generateBotName();
|
|
365
|
+
debugPrint(`[${this.host}:${this.port}] 无待重连名字,生成新名字: ${botName}`);
|
|
366
|
+
}
|
|
367
|
+
} else {
|
|
368
|
+
if (this.pendingReconnect.has(botName)) {
|
|
369
|
+
this.pendingReconnect.delete(botName);
|
|
370
|
+
debugPrint(`[${this.host}:${this.port}] 使用指定的重连名字: ${botName} (已从待重连名单移除)`);
|
|
371
|
+
}
|
|
315
372
|
}
|
|
373
|
+
|
|
316
374
|
try {
|
|
317
375
|
console.log(`[${this.host}:${this.port}] 创建机器人: ${botName}`);
|
|
318
376
|
const bot = mineflayer.createBot({
|
|
@@ -324,12 +382,7 @@ class MinecraftBotManager {
|
|
|
324
382
|
auth: 'offline'
|
|
325
383
|
});
|
|
326
384
|
|
|
327
|
-
this.
|
|
328
|
-
console.error(`[${this.host}:${this.port}] ${botName}连接超时,放弃等待`);
|
|
329
|
-
if (typeof bot.end === 'function') {
|
|
330
|
-
bot.end();
|
|
331
|
-
}
|
|
332
|
-
}, BOT_CONFIG.connectTimeout);
|
|
385
|
+
this.handleBottimeout(bot,botName);
|
|
333
386
|
|
|
334
387
|
// 设置机器人事件处理
|
|
335
388
|
this.setupBotEvents(bot, botName);
|
|
@@ -340,7 +393,7 @@ class MinecraftBotManager {
|
|
|
340
393
|
this.updateStatus();
|
|
341
394
|
return bot;
|
|
342
395
|
} catch (error) {
|
|
343
|
-
|
|
396
|
+
debugPrint(`[${this.host}:${this.port}] 创建机器人 ${botName} 失败:`, error.message);
|
|
344
397
|
this.handleBotFailure(botName);
|
|
345
398
|
return null;
|
|
346
399
|
}
|
|
@@ -354,19 +407,20 @@ class MinecraftBotManager {
|
|
|
354
407
|
clearTimeout(this.timeout);
|
|
355
408
|
this.timeout = null;
|
|
356
409
|
}
|
|
410
|
+
this.failedAttempts = 0;
|
|
411
|
+
this.pendingReconnect.delete(botName);
|
|
357
412
|
this.updateStatus();
|
|
358
413
|
});
|
|
359
414
|
|
|
360
415
|
bot.on('spawn', () => {
|
|
361
|
-
|
|
362
|
-
|
|
416
|
+
debugPrint(`[${this.host}:${this.port}] 机器人 ${botName} 生成在世界中`);
|
|
363
417
|
// 机器人基础行为
|
|
364
418
|
this.setupBotBehavior(bot, botName);
|
|
365
419
|
});
|
|
366
420
|
|
|
367
421
|
bot.on('message', (message) => {
|
|
368
422
|
const text = message.toString();
|
|
369
|
-
|
|
423
|
+
debugPrint(`[${this.host}:${this.port}] ${botName} 收到消息: ${text}`);
|
|
370
424
|
});
|
|
371
425
|
|
|
372
426
|
bot.on('error', (error) => {
|
|
@@ -380,7 +434,7 @@ class MinecraftBotManager {
|
|
|
380
434
|
|
|
381
435
|
bot.on('end', (reason) => {
|
|
382
436
|
console.log(`[${this.host}:${this.port}] 机器人 ${botName} 断开连接:`, reason);
|
|
383
|
-
console.log(`[${this.host}:${this.port}] ${botName}:失败次数${this.failedAttempts}`);
|
|
437
|
+
// console.log(`[${this.host}:${this.port}] ${botName}:失败次数${this.failedAttempts}`);
|
|
384
438
|
this.handleBotDisconnect(botName);
|
|
385
439
|
});
|
|
386
440
|
|
|
@@ -419,27 +473,21 @@ class MinecraftBotManager {
|
|
|
419
473
|
}
|
|
420
474
|
}
|
|
421
475
|
|
|
422
|
-
// 处理机器人断开连接 - 增强版本
|
|
423
476
|
handleBotDisconnect(botName) {
|
|
424
477
|
if (this.activeBots.has(botName)) {
|
|
425
|
-
|
|
478
|
+
debugPrint(`[${this.host}:${this.port}] 从活跃列表中移除机器人: ${botName}`);
|
|
426
479
|
this.activeBots.delete(botName);
|
|
427
480
|
this.currentBots = Math.max(0, this.currentBots - 1);
|
|
428
481
|
this.updateStatus();
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
if(this.failedAttempts > SERVER_CONFIG.maxFailedAttempts){
|
|
434
|
-
console.log(`[${this.host}:${this.port}] 机器人 ${botName} 重连次数太多,跳过`);
|
|
435
|
-
return;
|
|
436
|
-
}
|
|
437
|
-
// 延迟重连,避免频繁重连
|
|
482
|
+
this.pendingReconnect.add(botName);
|
|
483
|
+
debugPrint(`[${this.host}:${this.port}] 当前活跃机器人数量: ${this.currentBots}, 目标: ${this.minBots}`);
|
|
484
|
+
|
|
438
485
|
setTimeout(() => {
|
|
439
486
|
this.reconnect(botName);
|
|
440
487
|
}, BOT_CONFIG.reconnectDelay);
|
|
488
|
+
|
|
441
489
|
} else {
|
|
442
|
-
|
|
490
|
+
debugPrint(`[${this.host}:${this.port}] 机器人 ${botName} 不在活跃列表中,无需处理`);
|
|
443
491
|
}
|
|
444
492
|
}
|
|
445
493
|
|
|
@@ -447,62 +495,63 @@ class MinecraftBotManager {
|
|
|
447
495
|
handleBotFailure(botName) {
|
|
448
496
|
this.failedAttempts++;
|
|
449
497
|
this.updateStatus();
|
|
450
|
-
|
|
451
|
-
console.log(`[${this.host}:${this.port}] 失败次数过多,${SERVER_CONFIG.resetTimeout / 1000}秒后再次尝试`);
|
|
452
|
-
setTimeout(() => {
|
|
453
|
-
this.failedAttempts = 0;
|
|
454
|
-
this.reconnect(botName);
|
|
455
|
-
}, SERVER_CONFIG.resetTimeout);
|
|
456
|
-
return;
|
|
457
|
-
}
|
|
458
|
-
setTimeout(() => {
|
|
459
|
-
this.reconnect(botName);
|
|
460
|
-
}, BOT_CONFIG.reconnectDelay);
|
|
498
|
+
this.reconnect(botName);
|
|
461
499
|
}
|
|
462
500
|
|
|
463
501
|
// 维护机器人数目 - 增强版本
|
|
464
|
-
maintainBots() {
|
|
465
|
-
const neededBots =
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
if (this.
|
|
470
|
-
|
|
471
|
-
this.notice=false;
|
|
472
|
-
}
|
|
473
|
-
for (let i = 0; i < neededBots; i++) {
|
|
474
|
-
setTimeout(() => {
|
|
475
|
-
this.createBot();
|
|
476
|
-
}, i * 8000); // 每隔8秒启动一个
|
|
502
|
+
async maintainBots() {
|
|
503
|
+
const neededBots = this.minBots -this.currentBots;
|
|
504
|
+
try {
|
|
505
|
+
debugPrint(`[${this.host}:${this.port}] 当前机器人: ${this.currentBots}, 需要: ${neededBots}, 失败次数: ${this.failedAttempts}`);
|
|
506
|
+
await this.testmc();
|
|
507
|
+
if (!this.reachable) {
|
|
508
|
+
return null;
|
|
477
509
|
}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
510
|
+
if (neededBots > 0 && this.failedAttempts < SERVER_CONFIG.maxFailedAttempts) {
|
|
511
|
+
if (this.notice) {
|
|
512
|
+
console.log(`[${this.host}:${this.port}] 需要启动 ${neededBots} 个机器人`);
|
|
513
|
+
this.notice=false;
|
|
514
|
+
}
|
|
515
|
+
for (let i = 0; i < neededBots; i++) {
|
|
516
|
+
setTimeout(() => {
|
|
517
|
+
this.createBot();
|
|
518
|
+
}, i * 8000); // 每隔8秒启动一个
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
this.updateStatus();
|
|
522
|
+
}
|
|
523
|
+
catch (err) {
|
|
524
|
+
console.error(`[${this.host}:${this.port}] maintainBots 异常:`, err);
|
|
525
|
+
}
|
|
483
526
|
}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
this.failedAttempts++;
|
|
488
|
-
setTimeout(() => {
|
|
489
|
-
this.createBot(botName);
|
|
490
|
-
}, 5000);
|
|
491
|
-
} else{
|
|
492
|
-
// 如果还没有设置过 resetTimer,就设置一次
|
|
527
|
+
|
|
528
|
+
reconnect(botName) {
|
|
529
|
+
if (this.failedAttempts >= SERVER_CONFIG.maxFailedAttempts) {
|
|
493
530
|
if (!this.resetTimer) {
|
|
494
531
|
this.resetTimer = setTimeout(() => {
|
|
495
532
|
this.failedAttempts = 0;
|
|
496
|
-
this.resetTimer = null;
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
);
|
|
533
|
+
this.resetTimer = null;
|
|
534
|
+
debugPrint(`[${this.host}:${this.port}] 冷却期结束,恢复维护`);
|
|
535
|
+
this.maintainBots();
|
|
500
536
|
}, SERVER_CONFIG.resetTimeout);
|
|
537
|
+
debugPrint(`[${this.host}:${this.port}] 失败过多,进入冷却 ${ SERVER_CONFIG.resetTimeout/ 1000}s`);
|
|
501
538
|
}
|
|
502
|
-
|
|
539
|
+
return;
|
|
503
540
|
}
|
|
504
|
-
|
|
541
|
+
|
|
542
|
+
this.failedAttempts++;
|
|
543
|
+
|
|
544
|
+
// 如果传入 botName(来自断开重连),且它还在待重连名单中 → 优先用原名字
|
|
545
|
+
if (botName && this.pendingReconnect.has(botName)) {
|
|
546
|
+
debugPrint(`[${this.host}:${this.port}] 第 ${this.failedAttempts} 次尝试重连原机器人: ${botName}`);
|
|
547
|
+
this.createBot(botName); // 传名字,保持固定
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
// 否则(新补人或名字已被放弃)→ 不传名字,生成新的
|
|
551
|
+
debugPrint(`[${this.host}:${this.port}] 第 ${this.failedAttempts} 次连接失败,触发维护补人`);
|
|
552
|
+
this.maintainBots();
|
|
505
553
|
}
|
|
554
|
+
|
|
506
555
|
// 更新状态
|
|
507
556
|
updateStatus() {
|
|
508
557
|
const serverInfo = globalServerStatus.servers.get(`${this.host}:${this.port}`);
|
|
@@ -1638,6 +1687,16 @@ function shutdown() {
|
|
|
1638
1687
|
|
|
1639
1688
|
// 启动
|
|
1640
1689
|
if (require.main === module) {
|
|
1690
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
1691
|
+
console.error('未处理的 Promise Rejection:', reason);
|
|
1692
|
+
// 不退出进程,但至少能看到问题
|
|
1693
|
+
});
|
|
1694
|
+
|
|
1695
|
+
process.on('uncaughtException', (error) => {
|
|
1696
|
+
console.error('未捕获的异常:', error);
|
|
1697
|
+
// process.exit(1);
|
|
1698
|
+
});
|
|
1699
|
+
|
|
1641
1700
|
initialize().catch(error => {
|
|
1642
1701
|
console.error('初始化失败:', error);
|
|
1643
1702
|
process.exit(1);
|