wpms commited on
Commit
95287d5
·
verified ·
1 Parent(s): 1829238

Upload 3 files

Browse files
Files changed (3) hide show
  1. Dockerfile +33 -0
  2. index.js +319 -0
  3. package.json +20 -0
Dockerfile ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM node:18-slim
2
+
3
+ # Install dependencies for mineflayer
4
+ RUN apt-get update && apt-get install -y \
5
+ python3 \
6
+ make \
7
+ g++ \
8
+ && rm -rf /var/lib/apt/lists/*
9
+
10
+ WORKDIR /app
11
+
12
+ # Copy package files
13
+ COPY package*.json ./
14
+
15
+ # Install dependencies
16
+ RUN npm install
17
+
18
+ # Copy app source
19
+ COPY . .
20
+
21
+ # Create non-root user
22
+ RUN useradd -m -u 1000 botuser && chown -R botuser:botuser /app
23
+ USER botuser
24
+
25
+ # Expose port
26
+ EXPOSE 7860
27
+
28
+ # Health check
29
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
30
+ CMD curl -f http://localhost:7860/health || exit 1
31
+
32
+ # Start the app
33
+ CMD ["npm", "start"]
index.js ADDED
@@ -0,0 +1,319 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const express = require('express');
2
+ const http = require('http');
3
+ const { Server } = require('socket.io');
4
+ const mineflayer = require('mineflayer');
5
+ const path = require('path');
6
+
7
+ const app = express();
8
+ const server = http.createServer(app);
9
+ const io = new Server(server, {
10
+ cors: {
11
+ origin: "*",
12
+ methods: ["GET", "POST"]
13
+ }
14
+ });
15
+
16
+ const PORT = process.env.PORT || 7860;
17
+
18
+ // Store active bots
19
+ const activeBots = new Map();
20
+
21
+ // Middleware
22
+ app.use(express.json());
23
+ app.use(express.static('public'));
24
+
25
+ // Health check endpoint
26
+ app.get('/health', (req, res) => {
27
+ res.json({ status: true, uptime: process.uptime(), bots: activeBots.size });
28
+ });
29
+
30
+ // API Routes
31
+ app.get('/api/bots', (req, res) => {
32
+ const bots = Array.from(activeBots.entries()).map(([id, data]) => ({
33
+ id,
34
+ username: data.bot.username,
35
+ host: data.host,
36
+ port: data.port,
37
+ connected: data.connected,
38
+ players: data.players || []
39
+ }));
40
+ res.json(bots);
41
+ });
42
+
43
+ // Socket.IO Connection
44
+ io.on('connection', (socket) => {
45
+ console.log('Client connected:', socket.id);
46
+
47
+ let currentBot = null;
48
+ let botId = null;
49
+
50
+ // Connect bot to Minecraft server
51
+ socket.on('connect-bot', (config) => {
52
+ const { username, host, port = 25565, version } = config;
53
+
54
+ if (!username || !host) {
55
+ socket.emit('error', { message: 'Username and host are required' });
56
+ return;
57
+ }
58
+
59
+ // Disconnect existing bot for this socket
60
+ if (currentBot) {
61
+ currentBot.quit();
62
+ activeBots.delete(botId);
63
+ }
64
+
65
+ botId = `${socket.id}_${Date.now()}`;
66
+
67
+ try {
68
+ const bot = mineflayer.createBot({
69
+ host: host,
70
+ port: parseInt(port),
71
+ username: username,
72
+ version: version || false,
73
+ auth: 'offline',
74
+ hideErrors: true
75
+ });
76
+
77
+ currentBot = bot;
78
+
79
+ const botData = {
80
+ bot: bot,
81
+ socket: socket,
82
+ host: host,
83
+ port: port,
84
+ connected: false,
85
+ players: [],
86
+ chatHistory: []
87
+ };
88
+
89
+ activeBots.set(botId, botData);
90
+
91
+ // Bot Events
92
+ bot.on('login', () => {
93
+ botData.connected = true;
94
+ socket.emit('bot-status', {
95
+ status: 'online',
96
+ username: bot.username,
97
+ host: host,
98
+ port: port
99
+ });
100
+ console.log(`Bot ${username} connected to ${host}:${port}`);
101
+ });
102
+
103
+ bot.on('spawn', () => {
104
+ socket.emit('bot-spawned', {
105
+ position: bot.entity?.position,
106
+ health: bot.health,
107
+ food: bot.food
108
+ });
109
+ updatePlayersList(bot, socket);
110
+ });
111
+
112
+ bot.on('chat', (username, message) => {
113
+ if (username === bot.username) return;
114
+
115
+ const chatData = {
116
+ username: username,
117
+ message: message,
118
+ timestamp: new Date().toISOString(),
119
+ type: 'chat'
120
+ };
121
+
122
+ botData.chatHistory.push(chatData);
123
+ socket.emit('chat-message', chatData);
124
+ });
125
+
126
+ bot.on('message', (jsonMsg) => {
127
+ const text = jsonMsg.toString();
128
+ if (text && !text.includes(bot.username)) {
129
+ socket.emit('system-message', {
130
+ message: text,
131
+ timestamp: new Date().toISOString()
132
+ });
133
+ }
134
+ });
135
+
136
+ bot.on('playerJoined', (player) => {
137
+ socket.emit('player-joined', {
138
+ username: player.username,
139
+ timestamp: new Date().toISOString()
140
+ });
141
+ updatePlayersList(bot, socket);
142
+ });
143
+
144
+ bot.on('playerLeft', (player) => {
145
+ socket.emit('player-left', {
146
+ username: player.username,
147
+ timestamp: new Date().toISOString()
148
+ });
149
+ updatePlayersList(bot, socket);
150
+ });
151
+
152
+ bot.on('health', () => {
153
+ socket.emit('bot-health', {
154
+ health: bot.health,
155
+ food: bot.food
156
+ });
157
+ });
158
+
159
+ bot.on('death', () => {
160
+ socket.emit('bot-death', {
161
+ message: 'Bot died!',
162
+ timestamp: new Date().toISOString()
163
+ });
164
+ });
165
+
166
+ bot.on('kicked', (reason) => {
167
+ socket.emit('bot-kicked', {
168
+ reason: reason.toString(),
169
+ timestamp: new Date().toISOString()
170
+ });
171
+ cleanupBot(botId);
172
+ });
173
+
174
+ bot.on('error', (err) => {
175
+ console.error('Bot error:', err.message);
176
+ socket.emit('bot-error', {
177
+ message: err.message,
178
+ timestamp: new Date().toISOString()
179
+ });
180
+ });
181
+
182
+ bot.on('end', (reason) => {
183
+ socket.emit('bot-disconnected', {
184
+ reason: reason || 'Connection closed',
185
+ timestamp: new Date().toISOString()
186
+ });
187
+ cleanupBot(botId);
188
+ });
189
+
190
+ } catch (error) {
191
+ socket.emit('error', { message: error.message });
192
+ }
193
+ });
194
+
195
+ // Send chat message
196
+ socket.on('send-chat', (message) => {
197
+ if (currentBot && currentBot.chat) {
198
+ currentBot.chat(message);
199
+ socket.emit('chat-sent', {
200
+ username: currentBot.username,
201
+ message: message,
202
+ timestamp: new Date().toISOString()
203
+ });
204
+ }
205
+ });
206
+
207
+ // Send command
208
+ socket.on('send-command', (command) => {
209
+ if (currentBot && currentBot.chat) {
210
+ currentBot.chat(command);
211
+ }
212
+ });
213
+
214
+ // Bot actions
215
+ socket.on('bot-action', (action) => {
216
+ if (!currentBot) return;
217
+
218
+ switch(action.type) {
219
+ case 'jump':
220
+ currentBot.setControlState('jump', true);
221
+ setTimeout(() => currentBot.setControlState('jump', false), 500);
222
+ break;
223
+ case 'sneak':
224
+ currentBot.setControlState('sneak', true);
225
+ setTimeout(() => currentBot.setControlState('sneak', false), 1000);
226
+ break;
227
+ case 'look':
228
+ if (action.x !== undefined && action.y !== undefined && action.z !== undefined) {
229
+ const Vec3 = require('vec3');
230
+ currentBot.lookAt(new Vec3(action.x, action.y, action.z));
231
+ }
232
+ break;
233
+ case 'move':
234
+ if (action.direction) {
235
+ currentBot.setControlState(action.direction, true);
236
+ setTimeout(() => currentBot.setControlState(action.direction, false), 500);
237
+ }
238
+ break;
239
+ }
240
+ });
241
+
242
+ // Disconnect bot
243
+ socket.on('disconnect-bot', () => {
244
+ if (currentBot) {
245
+ currentBot.quit();
246
+ cleanupBot(botId);
247
+ currentBot = null;
248
+ botId = null;
249
+ }
250
+ });
251
+
252
+ // Get players list
253
+ socket.on('get-players', () => {
254
+ if (currentBot) {
255
+ updatePlayersList(currentBot, socket);
256
+ }
257
+ });
258
+
259
+ // Disconnect handler
260
+ socket.on('disconnect', () => {
261
+ console.log('Client disconnected:', socket.id);
262
+ if (currentBot) {
263
+ currentBot.quit();
264
+ cleanupBot(botId);
265
+ }
266
+ });
267
+ });
268
+
269
+ function updatePlayersList(bot, socket) {
270
+ if (!bot.players) return;
271
+
272
+ const players = Object.values(bot.players).map(p => ({
273
+ username: p.username,
274
+ ping: p.ping,
275
+ uuid: p.uuid
276
+ }));
277
+
278
+ socket.emit('players-list', players);
279
+ }
280
+
281
+ function cleanupBot(id) {
282
+ if (activeBots.has(id)) {
283
+ const data = activeBots.get(id);
284
+ if (data.bot) {
285
+ try {
286
+ data.bot.quit();
287
+ data.bot.removeAllListeners();
288
+ } catch (e) {}
289
+ }
290
+ activeBots.delete(id);
291
+ }
292
+ }
293
+
294
+ // Start server
295
+ server.listen(PORT, () => {
296
+ console.log(`🎮 Minecraft Bot Controller running on port ${PORT}`);
297
+ console.log(`🌐 Access the web interface at http://localhost:${PORT}`);
298
+ });
299
+
300
+ // Graceful shutdown
301
+ process.on('SIGTERM', () => {
302
+ console.log('SIGTERM received, shutting down gracefully');
303
+ activeBots.forEach((data, id) => {
304
+ cleanupBot(id);
305
+ });
306
+ server.close(() => {
307
+ process.exit(0);
308
+ });
309
+ });
310
+
311
+ process.on('SIGINT', () => {
312
+ console.log('SIGINT received, shutting down gracefully');
313
+ activeBots.forEach((data, id) => {
314
+ cleanupBot(id);
315
+ });
316
+ server.close(() => {
317
+ process.exit(0);
318
+ });
319
+ });
package.json ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "minecraft-bot-controller",
3
+ "version": "1.0.0",
4
+ "description": "Minecraft Bot with Web Interface for Hugging Face",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "start": "node index.js"
8
+ },
9
+ "dependencies": {
10
+ "express": "^4.18.2",
11
+ "socket.io": "^4.7.2",
12
+ "mineflayer": "^4.20.0",
13
+ "mineflayer-pathfinder": "^2.4.5",
14
+ "mineflayer-collectblock": "^1.4.1",
15
+ "vec3": "^0.1.10"
16
+ },
17
+ "engines": {
18
+ "node": ">=18.0.0"
19
+ }
20
+ }