Tokipo commited on
Commit
8bb61b2
·
verified ·
1 Parent(s): 6ecb80a

Create server.js

Browse files
Files changed (1) hide show
  1. server.js +274 -0
server.js ADDED
@@ -0,0 +1,274 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const express = require('express');
2
+ const http = require('http');
3
+ const socketIo = require('socket.io');
4
+ const mineflayer = require('mineflayer');
5
+ const fetch = require('node-fetch');
6
+ const { parse } = require('csv-parse/sync');
7
+ const path = require('path');
8
+
9
+ const app = express();
10
+ const server = http.createServer(app);
11
+ const io = socketIo(server);
12
+
13
+ // Google Sheets configuration
14
+ const SHEET_ID = '109roJQr-Y4YCLTkCqaK6iwShC-Dr2Jb-hB0qE2phNqQ';
15
+ const SHEET_URL = `https://docs.google.com/spreadsheets/d/${SHEET_ID}/export?format=csv`;
16
+
17
+ // Bot management
18
+ const bots = new Map();
19
+ const botLastReconnect = new Map();
20
+ const serverBotMap = new Map(); // Track one bot per server
21
+
22
+ class BotManager {
23
+ constructor(botName, ip, port, version) {
24
+ this.botName = botName;
25
+ this.ip = ip;
26
+ this.port = port;
27
+ this.version = version || '1.20.1';
28
+ this.bot = null;
29
+ this.status = 'Disconnected';
30
+ this.deathCount = 0;
31
+ this.disconnectTime = null;
32
+ this.isManualDisconnect = false;
33
+ this.startTime = Date.now();
34
+ }
35
+
36
+ async connect() {
37
+ try {
38
+ // Check if server already has a bot
39
+ const serverKey = `${this.ip}:${this.port}`;
40
+ const existingBot = serverBotMap.get(serverKey);
41
+ if (existingBot && existingBot !== this.botName) {
42
+ this.status = 'Server already has a bot';
43
+ return false;
44
+ }
45
+
46
+ this.status = 'Connecting...';
47
+ this.bot = mineflayer.createBot({
48
+ host: this.ip,
49
+ port: parseInt(this.port),
50
+ username: this.botName,
51
+ auth: 'offline',
52
+ version: this.version,
53
+ hideErrors: true,
54
+ checkTimeoutInterval: 30000
55
+ });
56
+
57
+ // Register this bot for the server
58
+ serverBotMap.set(serverKey, this.botName);
59
+
60
+ this.bot.once('spawn', () => {
61
+ this.status = 'Connected';
62
+ this.disconnectTime = null;
63
+ console.log(`Bot ${this.botName} spawned on ${this.ip}:${this.port}`);
64
+
65
+ // Start AFK behavior
66
+ this.startAFK();
67
+ });
68
+
69
+ this.bot.on('death', () => {
70
+ this.deathCount++;
71
+ console.log(`Bot ${this.botName} died. Total deaths: ${this.deathCount}`);
72
+ });
73
+
74
+ this.bot.on('kicked', (reason) => {
75
+ console.log(`Bot ${this.botName} was kicked: ${reason}`);
76
+ this.handleDisconnect();
77
+ });
78
+
79
+ this.bot.on('error', (err) => {
80
+ console.error(`Bot ${this.botName} error:`, err.message);
81
+ });
82
+
83
+ this.bot.on('end', () => {
84
+ this.handleDisconnect();
85
+ });
86
+
87
+ return true;
88
+ } catch (error) {
89
+ console.error(`Failed to connect bot ${this.botName}:`, error);
90
+ this.status = 'Connection Failed';
91
+ return false;
92
+ }
93
+ }
94
+
95
+ handleDisconnect() {
96
+ const serverKey = `${this.ip}:${this.port}`;
97
+ if (serverBotMap.get(serverKey) === this.botName) {
98
+ serverBotMap.delete(serverKey);
99
+ }
100
+
101
+ this.status = 'Disconnected';
102
+ this.disconnectTime = Date.now();
103
+ this.bot = null;
104
+
105
+ if (!this.isManualDisconnect) {
106
+ console.log(`Bot ${this.botName} disconnected from ${this.ip}:${this.port}`);
107
+ }
108
+ }
109
+
110
+ disconnect() {
111
+ this.isManualDisconnect = true;
112
+ if (this.bot) {
113
+ this.bot.quit();
114
+ }
115
+ this.handleDisconnect();
116
+ }
117
+
118
+ startAFK() {
119
+ if (!this.bot) return;
120
+
121
+ // Simple AFK movement
122
+ let direction = 1;
123
+ const afkInterval = setInterval(() => {
124
+ if (!this.bot || this.status !== 'Connected') {
125
+ clearInterval(afkInterval);
126
+ return;
127
+ }
128
+
129
+ // Walk forward and backward
130
+ this.bot.setControlState('forward', direction > 0);
131
+ this.bot.setControlState('back', direction < 0);
132
+
133
+ setTimeout(() => {
134
+ if (this.bot) {
135
+ this.bot.clearControlStates();
136
+ }
137
+ }, 1000);
138
+
139
+ direction *= -1;
140
+ }, 5000);
141
+ }
142
+
143
+ canReconnect() {
144
+ if (this.status === 'Connected') return false;
145
+
146
+ const lastReconnect = botLastReconnect.get(this.botName) || 0;
147
+ const hourAgo = Date.now() - (60 * 60 * 1000);
148
+
149
+ return lastReconnect < hourAgo;
150
+ }
151
+
152
+ async reconnect() {
153
+ if (!this.canReconnect()) {
154
+ return false;
155
+ }
156
+
157
+ this.isManualDisconnect = false;
158
+ botLastReconnect.set(this.botName, Date.now());
159
+ return await this.connect();
160
+ }
161
+
162
+ getInfo() {
163
+ const uptime = this.status === 'Connected' ?
164
+ Math.floor((Date.now() - this.startTime) / 1000) : 0;
165
+
166
+ return {
167
+ botName: this.botName,
168
+ status: this.status,
169
+ deathCount: this.deathCount,
170
+ uptime: uptime,
171
+ canReconnect: this.canReconnect(),
172
+ disconnectTime: this.disconnectTime
173
+ };
174
+ }
175
+ }
176
+
177
+ // Fetch and parse Google Sheets data
178
+ async function fetchSheetData() {
179
+ try {
180
+ const response = await fetch(SHEET_URL);
181
+ const csvText = await response.text();
182
+
183
+ const records = parse(csvText, {
184
+ columns: true,
185
+ skip_empty_lines: true
186
+ });
187
+
188
+ return records;
189
+ } catch (error) {
190
+ console.error('Error fetching sheet data:', error);
191
+ return [];
192
+ }
193
+ }
194
+
195
+ // Update bots based on sheet data
196
+ async function updateBots() {
197
+ const sheetData = await fetchSheetData();
198
+ const activeBots = new Set();
199
+
200
+ for (const row of sheetData) {
201
+ const botName = row['BOT NAME']?.trim();
202
+ const ip = row['IP']?.trim();
203
+ const port = row['PORT']?.trim();
204
+ const version = row['Version']?.trim() || '1.20.1';
205
+
206
+ if (!botName || !ip || !port) continue;
207
+
208
+ activeBots.add(botName);
209
+
210
+ // Add new bot if it doesn't exist
211
+ if (!bots.has(botName)) {
212
+ const botManager = new BotManager(botName, ip, port, version);
213
+ bots.set(botName, botManager);
214
+ await botManager.connect();
215
+ }
216
+ }
217
+
218
+ // Remove bots that are no longer in the sheet
219
+ for (const [botName, botManager] of bots.entries()) {
220
+ if (!activeBots.has(botName)) {
221
+ botManager.disconnect();
222
+ bots.delete(botName);
223
+ botLastReconnect.delete(botName);
224
+ }
225
+ }
226
+ }
227
+
228
+ // Socket.IO events
229
+ io.on('connection', (socket) => {
230
+ console.log('Client connected');
231
+
232
+ // Send initial bot data
233
+ const sendBotData = () => {
234
+ const botData = Array.from(bots.values()).map(bot => bot.getInfo());
235
+ socket.emit('botUpdate', botData);
236
+ };
237
+
238
+ sendBotData();
239
+ const updateInterval = setInterval(sendBotData, 2000);
240
+
241
+ socket.on('reconnectBot', async (botName) => {
242
+ const botManager = bots.get(botName);
243
+ if (botManager) {
244
+ const success = await botManager.reconnect();
245
+ socket.emit('reconnectResult', { botName, success });
246
+ }
247
+ });
248
+
249
+ socket.on('refreshSheet', async () => {
250
+ await updateBots();
251
+ sendBotData();
252
+ });
253
+
254
+ socket.on('disconnect', () => {
255
+ clearInterval(updateInterval);
256
+ console.log('Client disconnected');
257
+ });
258
+ });
259
+
260
+ // Serve static files
261
+ app.use(express.static(__dirname));
262
+ app.get('/', (req, res) => {
263
+ res.sendFile(path.join(__dirname, 'index.html'));
264
+ });
265
+
266
+ // Start server
267
+ const PORT = process.env.PORT || 7860;
268
+ server.listen(PORT, () => {
269
+ console.log(`Server running on port ${PORT}`);
270
+ });
271
+
272
+ // Initial load and periodic updates
273
+ updateBots();
274
+ setInterval(updateBots, 30000); // Check sheet every 30 seconds