Files
Farmer/211/server/src/core/FarmBot.js
2026-02-18 13:52:06 +08:00

187 lines
5.9 KiB
JavaScript

const EventEmitter = require('events');
const { NetworkClient } = require('./Network');
const { FarmManager } = require('./FarmManager');
const { FriendManager } = require('./FriendManager');
const { WarehouseManager } = require('./WarehouseManager');
const { ShopManager } = require('./ShopManager');
const { log, logWarn, emitRuntimeHint } = require('../utils');
const { CONFIG } = require('../config');
class FarmBot extends EventEmitter {
constructor(config = {}) {
super();
// Merge provided config with default CONFIG
// Deep copy to avoid modifying global CONFIG if passed by reference (though usually it's shallow copy)
this.config = { ...CONFIG, ...config };
// Initialize components
this.network = new NetworkClient(this);
this.farmManager = new FarmManager(this);
this.friendManager = new FriendManager(this);
this.warehouseManager = new WarehouseManager(this);
this.shopManager = new ShopManager(this);
this.dailyClaimTimer = null;
// State
this.isRunning = false;
this.user = {
gid: 0,
name: 'Loading...',
level: 0,
gold: 0,
exp: 0,
tickets: 0,
fertilizer: 0,
freeMallClaimDate: ''
};
// Error handling
this.network.on('error', (err) => {
log('机器人', `网络错误: ${err.message}`);
this.emit('error', err);
});
this.network.on('disconnected', () => {
if (this.isRunning) {
log('机器人', '连接断开,正在尝试重新连接...');
// Reconnection logic is handled in NetworkClient, but we can monitor it here
}
});
}
async start() {
if (this.isRunning) return;
this.isRunning = true;
this.log('系统', `正在启动农场小助手... 平台: ${this.config.platform}`);
emitRuntimeHint(true);
try {
// 1. Connect
this.log('系统', '正在连接服务器...');
await new Promise((resolve, reject) => {
const timeout = setTimeout(() => reject(new Error('连接超时')), 10000);
this.network.connect((success) => {
clearTimeout(timeout);
if (success) resolve();
else reject(new Error('连接失败'));
});
});
// 2. Login
this.log('系统', '正在登录...');
await new Promise((resolve, reject) => {
const timeout = setTimeout(() => reject(new Error('登录超时')), 10000);
this.network.sendLogin((success) => {
clearTimeout(timeout);
if (success) resolve();
else reject(new Error('登录失败'));
});
});
// 3. Start Loops
this.log('系统', '开始自动化作业...');
this.farmManager.startLoop();
if (this.config.enableFriendOps !== false) {
this.friendManager.startLoop();
}
if (this.config.enableAutoSell !== false) {
this.warehouseManager.startLoop();
}
this.startDailyClaimLoop();
this.emit('started');
this.log('系统', '农场小助手启动成功!');
} catch (error) {
this.log('系统', `启动失败: ${error.message}`);
this.stop();
throw error;
}
}
stop() {
this.isRunning = false;
this.farmManager.stopLoop();
this.friendManager.stopLoop();
this.warehouseManager.stopLoop();
this.stopDailyClaimLoop();
// Stop network
if (this.network.ws) {
this.network.ws.close();
}
this.emit('stopped');
log('系统', '农场小助手已停止');
}
log(tag, msg) {
log(tag, msg);
this.emit('log', {
tag,
msg,
time: Date.now()
});
}
logWarn(tag, msg) {
logWarn(tag, msg);
this.emit('log', {
tag,
msg,
type: 'warn',
time: Date.now()
});
}
getTodayKey() {
const now = new Date();
const y = now.getFullYear();
const m = `${now.getMonth() + 1}`.padStart(2, '0');
const d = `${now.getDate()}`.padStart(2, '0');
return `${y}-${m}-${d}`;
}
async runDailyClaims() {
if (!this.isRunning) return;
await this.network.tryClaimShareReward(1);
const todayKey = this.getTodayKey();
if (this.user.freeMallClaimDate === todayKey) return;
try {
await this.shopManager.purchaseMallItem(1001, 1);
this.user.freeMallClaimDate = todayKey;
this.emit('userUpdate', this.user);
this.log('商城', '已领取每日免费礼包');
} catch (e) {
this.logWarn('商城', `领取失败: ${e.message}`);
}
}
startDailyClaimLoop() {
if (this.dailyClaimTimer) return;
const scheduleNext = () => {
if (!this.isRunning) return;
const now = new Date();
const next = new Date(now);
next.setHours(24, 0, 0, 0);
const delay = Math.max(1000, next.getTime() - now.getTime());
this.dailyClaimTimer = setTimeout(async () => {
this.dailyClaimTimer = null;
await this.runDailyClaims();
scheduleNext();
}, delay);
};
scheduleNext();
}
stopDailyClaimLoop() {
if (this.dailyClaimTimer) {
clearTimeout(this.dailyClaimTimer);
this.dailyClaimTimer = null;
}
}
}
module.exports = { FarmBot };