OrbitMC commited on
Commit
0260e41
·
verified ·
1 Parent(s): a34d80f

Update Dockerfile

Browse files
Files changed (1) hide show
  1. Dockerfile +172 -21
Dockerfile CHANGED
@@ -1,29 +1,180 @@
1
- # Use a slim Python image for efficiency
2
- FROM python:3.11-slim
3
 
4
- # Set the working directory
5
  WORKDIR /app
6
 
7
- # Install system dependencies if needed (none strictly required for aiohttp, but good practice)
8
- RUN apt-get update && apt-get install -y \
9
- build-essential \
10
- && rm -rf /var/lib/apt/lists/*
11
 
12
- # Copy requirements and install
13
- COPY requirements.txt .
14
- RUN pip install --no-cache-dir -r requirements.txt
 
 
15
 
16
- # Copy the rest of the application
17
- COPY . .
18
 
19
- # Hugging Face Spaces run on port 7860 by default
20
- ENV SERVER_PORT=7860
21
- # You should set these in the Hugging Face Space Settings (Secrets),
22
- # but we set defaults here to prevent the app from crashing.
23
- ENV ADMIN_PATH=/admin-panel
24
 
25
- # Expose the port
26
- EXPOSE 7860
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
- # Run the application
29
- CMD ["python", "main.py"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM node:20-alpine
 
2
 
 
3
  WORKDIR /app
4
 
5
+ # Install WebSocket dependency
6
+ RUN npm install ws
 
 
7
 
8
+ # Write the entire server and client into a single file inside the container
9
+ COPY <<EOF server.js
10
+ const http = require('http');
11
+ const crypto = require('crypto');
12
+ const WebSocket = require('ws');
13
 
14
+ const PORT = 7860;
15
+ const players = {};
16
 
17
+ // --- HTTP SERVER (Cookie Handling & HTML Delivery) ---
18
+ const server = http.createServer((req, res) => {
19
+ const cookieHeader = req.headers.cookie || '';
20
+ let playerId = cookieHeader.split('; ').find(row => row.startsWith('playerId='))?.split('=')[1];
21
+ let cookieSetHeader = [];
22
 
23
+ if (!playerId) {
24
+ playerId = crypto.randomUUID();
25
+ cookieSetHeader.push(\`playerId=\${playerId}; Max-Age=31536000; Path=/; SameSite=Strict\`);
26
+ }
27
+
28
+ if (!players[playerId]) {
29
+ players[playerId] = {
30
+ id: playerId,
31
+ x: Math.random() * 300 + 50,
32
+ y: Math.random() * 300 + 50,
33
+ color: \`#\${Math.floor(crypto.randomInt(16777215)).toString(16).padStart(6, '0')}\`
34
+ };
35
+ }
36
+
37
+ res.writeHead(200, { 'Content-Type': 'text/html', 'Set-Cookie': cookieSetHeader });
38
+ res.end(\`
39
+ <!DOCTYPE html>
40
+ <html>
41
+ <head>
42
+ <meta charset="UTF-8">
43
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
44
+ <title>HF Multiplayer Game</title>
45
+ <style>
46
+ * { box-sizing: border-box; margin: 0; padding: 0; user-select: none; }
47
+ body, html { width: 100%; height: 100%; overflow: hidden; background: #111; font-family: sans-serif; }
48
+ canvas { display: block; width: 100vw; height: 100vh; background: #1a1a1a; }
49
+ #ui { position: absolute; top: 10px; left: 10px; color: #fff; pointer-events: none; font-size: 14px; background: rgba(0,0,0,0.5); padding: 8px; border-radius: 4px; }
50
+ </style>
51
+ </head>
52
+ <body>
53
+ <div id="ui">Status: Connecting...</div>
54
+ <canvas id="gameCanvas"></canvas>
55
+ <script>
56
+ const canvas = document.getElementById('gameCanvas');
57
+ const ctx = canvas.getContext('2d');
58
+ const ui = document.getElementById('ui');
59
+ let myId = "\${playerId}";
60
+ let players = {};
61
+ let ws;
62
+
63
+ function resize() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; }
64
+ window.addEventListener('resize', resize); resize();
65
+
66
+ const wsProtocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
67
+ ws = new WebSocket(wsProtocol + window.location.host);
68
+ ws.onopen = () => ui.innerText = "Connected! Drag screen to move.";
69
+ ws.onclose = () => ui.innerText = "Disconnected! Reconnecting...";
70
+
71
+ ws.onmessage = (event) => {
72
+ const msg = JSON.parse(event.data);
73
+ if (msg.type === 'INIT') {
74
+ players = msg.players;
75
+ for (let id in players) {
76
+ players[id].targetX = players[id].x;
77
+ players[id].targetY = players[id].y;
78
+ }
79
+ } else if (msg.type === 'UPDATE') {
80
+ if (!players[msg.id]) players[msg.id] = msg.data;
81
+ players[msg.id].targetX = msg.data.x;
82
+ players[msg.id].targetY = msg.data.y;
83
+ if (msg.data.color) players[msg.id].color = msg.data.color;
84
+ } else if (msg.type === 'LEAVE') {
85
+ if (players[msg.id]) delete players[msg.id];
86
+ }
87
+ };
88
+
89
+ let lastSendTime = 0;
90
+ function sendPosition(x, y) {
91
+ const now = performance.now();
92
+ if (now - lastSendTime > 40 && ws.readyState === WebSocket.OPEN) {
93
+ ws.send(JSON.stringify({ type: 'MOVE', x, y }));
94
+ lastSendTime = now;
95
+ }
96
+ }
97
+
98
+ canvas.addEventListener('touchmove', (e) => {
99
+ e.preventDefault();
100
+ if (!players[myId]) return;
101
+ const touch = e.touches[0];
102
+ players[myId].x = touch.clientX - 20;
103
+ players[myId].y = touch.clientY - 20;
104
+ sendPosition(players[myId].x, players[myId].y);
105
+ }, { passive: false });
106
+
107
+ canvas.addEventListener('mousemove', (e) => {
108
+ if (!players[myId]) return;
109
+ players[myId].x = e.clientX - 20;
110
+ players[myId].y = e.clientY - 20;
111
+ sendPosition(players[myId].x, players[myId].y);
112
+ });
113
 
114
+ function draw() {
115
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
116
+ for (let id in players) {
117
+ const p = players[id];
118
+ if (id !== myId) {
119
+ // LERP: Smooth out 400ms lag spikes by sliding 12% of the way each frame
120
+ p.x += (p.targetX - p.x) * 0.12;
121
+ p.y += (p.targetY - p.y) * 0.12;
122
+ }
123
+ ctx.fillStyle = p.color || '#ffffff';
124
+ ctx.fillRect(p.x, p.y, 40, 40);
125
+ ctx.fillStyle = '#fff';
126
+ ctx.font = '12px sans-serif';
127
+ ctx.fillText(id === myId ? "You" : "Player", p.x, p.y - 6);
128
+ }
129
+ requestAnimationFrame(draw);
130
+ }
131
+ draw();
132
+ </script>
133
+ </body>
134
+ </html>
135
+ \`);
136
+ });
137
+
138
+ // --- WEBSOCKET SERVER (Movement Broadcasting) ---
139
+ const wss = new WebSocket.Server({ noServer: true });
140
+ server.on('upgrade', (req, socket, head) => {
141
+ wss.handleUpgrade(req, socket, head, (ws) => { wss.emit('connection', ws, req); });
142
+ });
143
+
144
+ wss.on('connection', (ws, req) => {
145
+ const cookieHeader = req.headers.cookie || '';
146
+ const playerId = cookieHeader.split('; ').find(row => row.startsWith('playerId='))?.split('=')[1];
147
+ if (!playerId || !players[playerId]) { ws.close(); return; }
148
+
149
+ ws.playerId = playerId;
150
+ ws.send(JSON.stringify({ type: 'INIT', selfId: playerId, players }));
151
+ broadcast({ type: 'UPDATE', id: playerId, data: players[playerId] });
152
+
153
+ ws.on('message', (message) => {
154
+ try {
155
+ const msg = JSON.parse(message);
156
+ if (msg.type === 'MOVE' && players[ws.playerId]) {
157
+ players[ws.playerId].x = msg.x;
158
+ players[ws.playerId].y = msg.y;
159
+ broadcast({ type: 'UPDATE', id: ws.playerId, data: { x: msg.x, y: msg.y } }, ws.playerId);
160
+ }
161
+ } catch (e) {}
162
+ });
163
+
164
+ ws.on('close', () => { broadcast({ type: 'LEAVE', id: ws.playerId }); });
165
+ });
166
+
167
+ function broadcast(data, excludeId = null) {
168
+ const packet = JSON.stringify(data);
169
+ wss.clients.forEach(client => {
170
+ if (client.readyState === WebSocket.OPEN && client.playerId !== excludeId) {
171
+ client.send(packet);
172
+ }
173
+ });
174
+ }
175
+
176
+ server.listen(PORT);
177
+ EOF
178
+
179
+ EXPOSE 7860
180
+ CMD ["node", "server.js"]