|
|
|
|
|
const express = require('express'); |
|
|
const http = require('http'); |
|
|
const socketIo = require('socket.io'); |
|
|
const mineflayer = require('mineflayer'); |
|
|
const path = require('path'); |
|
|
|
|
|
const app = express(); |
|
|
const server = http.createServer(app); |
|
|
const io = socketIo(server); |
|
|
|
|
|
|
|
|
const SERVER_HOST = 'dm.progamer.me'; |
|
|
const SERVER_PORT = 40675; |
|
|
const SERVER_VERSION = '1.21.8'; |
|
|
const BOT_NAMES = ['Alfha_lag', 'Bigboybloom', 'Kitcat']; |
|
|
const ROTATION_DURATION = 3600; |
|
|
|
|
|
|
|
|
let currentBotIndex = 0; |
|
|
let rotationStartTime = null; |
|
|
let activeBot = null; |
|
|
let serverStatus = { online: false, players: '0/0', latency: 0 }; |
|
|
const botStats = {}; |
|
|
|
|
|
|
|
|
BOT_NAMES.forEach(name => { |
|
|
botStats[name] = { |
|
|
name, |
|
|
status: 'offline', |
|
|
deaths: 0, |
|
|
reconnects: 0, |
|
|
uptime: 0, |
|
|
position: { x: 0, y: 0, z: 0 }, |
|
|
health: 20, |
|
|
food: 20, |
|
|
isActive: false |
|
|
}; |
|
|
}); |
|
|
|
|
|
|
|
|
function createBot(botName) { |
|
|
console.log(`๐ Starting ${botName}...`); |
|
|
|
|
|
const bot = mineflayer.createBot({ |
|
|
host: SERVER_HOST, |
|
|
port: SERVER_PORT, |
|
|
username: botName, |
|
|
auth: 'offline', |
|
|
version: SERVER_VERSION, |
|
|
hideErrors: false, |
|
|
checkTimeoutInterval: 30000, |
|
|
keepAlive: true |
|
|
}); |
|
|
|
|
|
let circleInterval = null; |
|
|
let centerPos = null; |
|
|
let angle = 0; |
|
|
|
|
|
bot.once('spawn', () => { |
|
|
console.log(`โ
${botName} connected`); |
|
|
botStats[botName].status = 'online'; |
|
|
botStats[botName].uptime = Date.now(); |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
if (!bot.entity) return; |
|
|
|
|
|
centerPos = bot.entity.position.clone(); |
|
|
|
|
|
circleInterval = setInterval(() => { |
|
|
if (!bot.entity) return; |
|
|
|
|
|
try { |
|
|
const radius = 4; |
|
|
angle += 0.03; |
|
|
|
|
|
const targetX = centerPos.x + Math.cos(angle) * radius; |
|
|
const targetZ = centerPos.z + Math.sin(angle) * radius; |
|
|
|
|
|
const dx = targetX - bot.entity.position.x; |
|
|
const dz = targetZ - bot.entity.position.z; |
|
|
const yaw = Math.atan2(-dx, -dz); |
|
|
|
|
|
bot.look(yaw, 0, true); |
|
|
bot.setControlState('forward', true); |
|
|
|
|
|
|
|
|
botStats[botName].position = { |
|
|
x: Math.floor(bot.entity.position.x), |
|
|
y: Math.floor(bot.entity.position.y), |
|
|
z: Math.floor(bot.entity.position.z) |
|
|
}; |
|
|
botStats[botName].health = bot.health || 20; |
|
|
botStats[botName].food = bot.food || 20; |
|
|
} catch (err) { |
|
|
console.error(`Movement error for ${botName}:`, err.message); |
|
|
} |
|
|
}, 100); |
|
|
}, 2000); |
|
|
}); |
|
|
|
|
|
bot.on('death', () => { |
|
|
console.log(`๐ ${botName} died`); |
|
|
botStats[botName].deaths++; |
|
|
if (circleInterval) clearInterval(circleInterval); |
|
|
centerPos = null; |
|
|
}); |
|
|
|
|
|
bot.on('respawn', () => { |
|
|
console.log(`๐ ${botName} respawned`); |
|
|
if (circleInterval) clearInterval(circleInterval); |
|
|
centerPos = null; |
|
|
angle = 0; |
|
|
}); |
|
|
|
|
|
bot.on('kicked', (reason) => { |
|
|
console.log(`โ ${botName} kicked: ${reason}`); |
|
|
botStats[botName].status = 'offline'; |
|
|
if (circleInterval) clearInterval(circleInterval); |
|
|
}); |
|
|
|
|
|
bot.on('error', (err) => { |
|
|
console.error(`โ ${botName} error:`, err.message); |
|
|
}); |
|
|
|
|
|
bot.on('end', () => { |
|
|
console.log(`๐ ${botName} disconnected`); |
|
|
botStats[botName].status = 'offline'; |
|
|
if (circleInterval) clearInterval(circleInterval); |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
if (activeBot && activeBot.username === botName) { |
|
|
console.log(`๐ Reconnecting ${botName}...`); |
|
|
botStats[botName].reconnects++; |
|
|
activeBot = createBot(botName); |
|
|
} |
|
|
}, 5000); |
|
|
}); |
|
|
|
|
|
return bot; |
|
|
} |
|
|
|
|
|
|
|
|
function stopBot(bot) { |
|
|
if (!bot) return; |
|
|
|
|
|
try { |
|
|
bot.quit(); |
|
|
console.log(`โน๏ธ Stopped ${bot.username}`); |
|
|
} catch (err) { |
|
|
console.error('Error stopping bot:', err.message); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function rotationManager() { |
|
|
setInterval(() => { |
|
|
const currentBot = BOT_NAMES[currentBotIndex]; |
|
|
const now = Date.now(); |
|
|
|
|
|
if (!rotationStartTime || (now - rotationStartTime) >= (ROTATION_DURATION * 1000)) { |
|
|
|
|
|
if (activeBot) { |
|
|
stopBot(activeBot); |
|
|
botStats[activeBot.username].isActive = false; |
|
|
} |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
activeBot = createBot(currentBot); |
|
|
botStats[currentBot].isActive = true; |
|
|
rotationStartTime = Date.now(); |
|
|
|
|
|
console.log(`๐ Rotation: ${currentBot} is now active`); |
|
|
|
|
|
|
|
|
currentBotIndex = (currentBotIndex + 1) % BOT_NAMES.length; |
|
|
}, 2000); |
|
|
} |
|
|
}, 5000); |
|
|
} |
|
|
|
|
|
|
|
|
async function checkServerStatus() { |
|
|
try { |
|
|
const net = require('net'); |
|
|
const client = new net.Socket(); |
|
|
const startTime = Date.now(); |
|
|
|
|
|
client.setTimeout(5000); |
|
|
|
|
|
client.connect(SERVER_PORT, SERVER_HOST, () => { |
|
|
const latency = Date.now() - startTime; |
|
|
serverStatus = { |
|
|
online: true, |
|
|
latency, |
|
|
players: '?/?' |
|
|
}; |
|
|
client.destroy(); |
|
|
}); |
|
|
|
|
|
client.on('error', () => { |
|
|
serverStatus = { online: false, latency: 0, players: '0/0' }; |
|
|
client.destroy(); |
|
|
}); |
|
|
|
|
|
client.on('timeout', () => { |
|
|
serverStatus = { online: false, latency: 0, players: '0/0' }; |
|
|
client.destroy(); |
|
|
}); |
|
|
} catch (err) { |
|
|
serverStatus = { online: false, latency: 0, players: '0/0' }; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
io.on('connection', (socket) => { |
|
|
console.log('๐ฑ Client connected'); |
|
|
|
|
|
const sendUpdate = () => { |
|
|
const currentBot = BOT_NAMES[(currentBotIndex - 1 + BOT_NAMES.length) % BOT_NAMES.length]; |
|
|
const nextBot = BOT_NAMES[currentBotIndex]; |
|
|
const elapsed = rotationStartTime ? Math.floor((Date.now() - rotationStartTime) / 1000) : 0; |
|
|
const remaining = Math.max(0, ROTATION_DURATION - elapsed); |
|
|
|
|
|
|
|
|
Object.keys(botStats).forEach(name => { |
|
|
if (botStats[name].status === 'online' && botStats[name].uptime) { |
|
|
botStats[name].uptimeSeconds = Math.floor((Date.now() - botStats[name].uptime) / 1000); |
|
|
} else { |
|
|
botStats[name].uptimeSeconds = 0; |
|
|
} |
|
|
}); |
|
|
|
|
|
socket.emit('update', { |
|
|
server: { |
|
|
host: SERVER_HOST, |
|
|
port: SERVER_PORT, |
|
|
version: SERVER_VERSION, |
|
|
status: serverStatus |
|
|
}, |
|
|
rotation: { |
|
|
current: currentBot, |
|
|
next: nextBot, |
|
|
elapsed, |
|
|
remaining, |
|
|
queue: BOT_NAMES |
|
|
}, |
|
|
bots: Object.values(botStats) |
|
|
}); |
|
|
}; |
|
|
|
|
|
const interval = setInterval(sendUpdate, 1000); |
|
|
sendUpdate(); |
|
|
|
|
|
socket.on('forceRotation', () => { |
|
|
rotationStartTime = 0; |
|
|
socket.emit('rotationForced', true); |
|
|
}); |
|
|
|
|
|
socket.on('disconnect', () => { |
|
|
clearInterval(interval); |
|
|
console.log('๐ด Client disconnected'); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
app.use(express.static(__dirname)); |
|
|
app.get('/', (req, res) => { |
|
|
res.sendFile(path.join(__dirname, 'index.html')); |
|
|
}); |
|
|
|
|
|
|
|
|
const PORT = process.env.PORT || 7860; |
|
|
server.listen(PORT, () => { |
|
|
console.log('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ'); |
|
|
console.log('๐ฎ MINECRAFT BOT MANAGER'); |
|
|
console.log('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ'); |
|
|
console.log(`๐ก Server: ${SERVER_HOST}:${SERVER_PORT}`); |
|
|
console.log(`๐ค Bots: ${BOT_NAMES.join(', ')}`); |
|
|
console.log(`โฑ๏ธ Rotation: ${ROTATION_DURATION / 60} minutes`); |
|
|
console.log(`๐ Dashboard: http://localhost:${PORT}`); |
|
|
console.log('โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ'); |
|
|
}); |
|
|
|
|
|
|
|
|
rotationManager(); |
|
|
setInterval(checkServerStatus, 1000); |
|
|
checkServerStatus(); |