Download public/index.html from wpms/mcbot: direct link, hf CLI and curl.
- Browser
- Download file 37.4 kB
-
https://huggingface.co/spaces/wpms/mcbot/resolve/main/public/index.html
- Command line
-
hf download hf://spaces/wpms/mcbot/public/index.html
-
curl -L -o index.html https://huggingface.co/spaces/wpms/mcbot/resolve/main/public/index.html
37.4 kB
| <html lang="si"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Minecraft Bot Controller</title> | |
| <script src="/socket.io/socket.io.js"></script> | |
| <style> | |
| * { margin: 0; padding: 0; box-sizing: border-box; } | |
| body { | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%); | |
| color: #e2e8f0; | |
| min-height: 100vh; | |
| } | |
| .container { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| padding: 20px; | |
| } | |
| .header { | |
| text-align: center; | |
| padding: 30px 0; | |
| margin-bottom: 20px; | |
| } | |
| .header h1 { | |
| font-size: 2.5rem; | |
| background: linear-gradient(135deg, #60a5fa, #a78bfa); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| margin-bottom: 10px; | |
| } | |
| .header p { | |
| color: #94a3b8; | |
| font-size: 1.1rem; | |
| } | |
| .panel { | |
| background: rgba(30, 41, 59, 0.8); | |
| backdrop-filter: blur(10px); | |
| border: 1px solid rgba(255,255,255,0.1); | |
| border-radius: 16px; | |
| padding: 24px; | |
| margin-bottom: 20px; | |
| } | |
| .connection-form { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr 120px 150px; | |
| gap: 15px; | |
| align-items: end; | |
| } | |
| .form-group label { | |
| display: block; | |
| margin-bottom: 8px; | |
| color: #94a3b8; | |
| font-size: 0.9rem; | |
| font-weight: 500; | |
| } | |
| .form-group input { | |
| width: 100%; | |
| padding: 12px 16px; | |
| background: #0f172a; | |
| border: 2px solid #334155; | |
| border-radius: 10px; | |
| color: #f1f5f9; | |
| font-size: 1rem; | |
| transition: all 0.3s; | |
| } | |
| .form-group input:focus { | |
| outline: none; | |
| border-color: #3b82f6; | |
| box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2); | |
| } | |
| .btn { | |
| padding: 12px 24px; | |
| border: none; | |
| border-radius: 10px; | |
| font-size: 1rem; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: all 0.3s; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 8px; | |
| } | |
| .btn-primary { | |
| background: linear-gradient(135deg, #3b82f6, #2563eb); | |
| color: white; | |
| } | |
| .btn-primary:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 8px 20px rgba(59, 130, 246, 0.4); | |
| } | |
| .btn-danger { | |
| background: linear-gradient(135deg, #ef4444, #dc2626); | |
| color: white; | |
| } | |
| .btn-danger:hover { | |
| transform: translateY(-2px); | |
| box-shadow: 0 8px 20px rgba(239, 68, 68, 0.4); | |
| } | |
| .btn:disabled { | |
| opacity: 0.6; | |
| cursor: not-allowed; | |
| transform: none ; | |
| } | |
| .status-bar { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| background: rgba(15, 23, 42, 0.6); | |
| padding: 16px 20px; | |
| border-radius: 12px; | |
| margin-top: 20px; | |
| } | |
| .status-indicator { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| } | |
| .status-dot { | |
| width: 12px; | |
| height: 12px; | |
| border-radius: 50%; | |
| position: relative; | |
| } | |
| .status-dot::after { | |
| content: ''; | |
| position: absolute; | |
| inset: -4px; | |
| border-radius: 50%; | |
| opacity: 0.4; | |
| animation: pulse 2s infinite; | |
| } | |
| .status-online { | |
| background: #22c55e; | |
| box-shadow: 0 0 10px #22c55e; | |
| } | |
| .status-online::after { | |
| background: #22c55e; | |
| } | |
| .status-offline { | |
| background: #ef4444; | |
| box-shadow: 0 0 10px #ef4444; | |
| } | |
| .status-offline::after { | |
| background: #ef4444; | |
| animation: none; | |
| } | |
| .status-connecting { | |
| background: #eab308; | |
| box-shadow: 0 0 10px #eab308; | |
| animation: pulse 1s infinite; | |
| } | |
| @keyframes pulse { | |
| 0%, 100% { transform: scale(1); opacity: 1; } | |
| 50% { transform: scale(1.2); opacity: 0.7; } | |
| } | |
| .status-text { | |
| font-weight: 600; | |
| font-size: 1rem; | |
| } | |
| .status-online + .status-text { color: #4ade80; } | |
| .status-offline + .status-text { color: #f87171; } | |
| .status-connecting + .status-text { color: #facc15; } | |
| .bot-info { | |
| display: flex; | |
| align-items: center; | |
| gap: 15px; | |
| } | |
| .bot-avatar { | |
| width: 40px; | |
| height: 40px; | |
| border-radius: 8px; | |
| image-rendering: pixelated; | |
| border: 2px solid #3b82f6; | |
| } | |
| .bot-details { | |
| text-align: right; | |
| } | |
| .bot-name { | |
| font-weight: 700; | |
| color: #60a5fa; | |
| } | |
| .server-address { | |
| font-size: 0.85rem; | |
| color: #94a3b8; | |
| } | |
| .main-grid { | |
| display: grid; | |
| grid-template-columns: 2fr 1fr; | |
| gap: 20px; | |
| } | |
| .chat-section { | |
| display: flex; | |
| flex-direction: column; | |
| height: 600px; | |
| } | |
| .chat-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 16px; | |
| padding-bottom: 16px; | |
| border-bottom: 1px solid rgba(255,255,255,0.1); | |
| } | |
| .chat-header h2 { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| font-size: 1.3rem; | |
| } | |
| .badge { | |
| background: #ef4444; | |
| color: white; | |
| padding: 2px 8px; | |
| border-radius: 20px; | |
| font-size: 0.75rem; | |
| font-weight: 700; | |
| } | |
| .chat-controls { | |
| display: flex; | |
| gap: 8px; | |
| } | |
| .chat-controls button { | |
| padding: 6px 12px; | |
| background: #334155; | |
| border: none; | |
| border-radius: 6px; | |
| color: #cbd5e1; | |
| font-size: 0.85rem; | |
| cursor: pointer; | |
| transition: all 0.3s; | |
| } | |
| .chat-controls button:hover { | |
| background: #475569; | |
| } | |
| .chat-messages { | |
| flex: 1; | |
| overflow-y: auto; | |
| background: rgba(15, 23, 42, 0.6); | |
| border-radius: 12px; | |
| padding: 16px; | |
| margin-bottom: 16px; | |
| scrollbar-width: thin; | |
| scrollbar-color: #334155 transparent; | |
| } | |
| .chat-messages::-webkit-scrollbar { | |
| width: 6px; | |
| } | |
| .chat-messages::-webkit-scrollbar-track { | |
| background: transparent; | |
| } | |
| .chat-messages::-webkit-scrollbar-thumb { | |
| background: #334155; | |
| border-radius: 3px; | |
| } | |
| .empty-state { | |
| text-align: center; | |
| padding: 60px 20px; | |
| color: #64748b; | |
| } | |
| .empty-state .icon { | |
| font-size: 3rem; | |
| margin-bottom: 16px; | |
| } | |
| .message { | |
| display: flex; | |
| gap: 12px; | |
| padding: 10px; | |
| border-radius: 10px; | |
| margin-bottom: 8px; | |
| animation: fadeIn 0.3s ease; | |
| transition: background 0.2s; | |
| } | |
| .message:hover { | |
| background: rgba(255,255,255,0.03); | |
| } | |
| .message.bot-message { | |
| background: rgba(59, 130, 246, 0.1); | |
| border: 1px solid rgba(59, 130, 246, 0.2); | |
| } | |
| .message.system-message { | |
| justify-content: center; | |
| text-align: center; | |
| } | |
| .message.system-message .system-text { | |
| background: rgba(255,255,255,0.05); | |
| padding: 6px 16px; | |
| border-radius: 20px; | |
| font-size: 0.85rem; | |
| color: #94a3b8; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .message-avatar { | |
| width: 36px; | |
| height: 36px; | |
| border-radius: 6px; | |
| image-rendering: pixelated; | |
| flex-shrink: 0; | |
| } | |
| .message-content { | |
| flex: 1; | |
| min-width: 0; | |
| } | |
| .message-header { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| margin-bottom: 4px; | |
| } | |
| .message-author { | |
| font-weight: 700; | |
| font-size: 0.9rem; | |
| } | |
| .message-author.bot { color: #60a5fa; } | |
| .message-author.player { color: #4ade80; } | |
| .message-author.server { color: #fbbf24; } | |
| .message-time { | |
| font-size: 0.75rem; | |
| color: #64748b; | |
| } | |
| .message-text { | |
| color: #e2e8f0; | |
| line-height: 1.5; | |
| word-break: break-word; | |
| } | |
| .chat-input-area { | |
| display: flex; | |
| gap: 12px; | |
| } | |
| .chat-input { | |
| flex: 1; | |
| padding: 14px 18px; | |
| background: #0f172a; | |
| border: 2px solid #334155; | |
| border-radius: 12px; | |
| color: #f1f5f9; | |
| font-size: 1rem; | |
| transition: all 0.3s; | |
| } | |
| .chat-input:focus { | |
| outline: none; | |
| border-color: #3b82f6; | |
| box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2); | |
| } | |
| .chat-input:disabled { | |
| opacity: 0.5; | |
| cursor: not-allowed; | |
| } | |
| .sidebar { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 20px; | |
| } | |
| .players-list { | |
| max-height: 300px; | |
| overflow-y: auto; | |
| scrollbar-width: thin; | |
| scrollbar-color: #334155 transparent; | |
| } | |
| .players-list::-webkit-scrollbar { | |
| width: 6px; | |
| } | |
| .players-list::-webkit-scrollbar-thumb { | |
| background: #334155; | |
| border-radius: 3px; | |
| } | |
| .player-item { | |
| display: flex; | |
| align-items: center; | |
| gap: 12px; | |
| padding: 10px; | |
| border-radius: 10px; | |
| transition: all 0.3s; | |
| margin-bottom: 6px; | |
| } | |
| .player-item:hover { | |
| background: rgba(255,255,255,0.05); | |
| } | |
| .player-avatar { | |
| width: 32px; | |
| height: 32px; | |
| border-radius: 6px; | |
| image-rendering: pixelated; | |
| } | |
| .player-info { | |
| flex: 1; | |
| min-width: 0; | |
| } | |
| .player-name { | |
| font-weight: 600; | |
| font-size: 0.9rem; | |
| color: #e2e8f0; | |
| white-space: nowrap; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| } | |
| .player-ping { | |
| font-size: 0.75rem; | |
| color: #64748b; | |
| } | |
| .player-status { | |
| width: 8px; | |
| height: 8px; | |
| border-radius: 50%; | |
| background: #22c55e; | |
| box-shadow: 0 0 6px #22c55e; | |
| } | |
| .actions-grid { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 8px; | |
| } | |
| .action-btn { | |
| padding: 10px; | |
| background: #334155; | |
| border: none; | |
| border-radius: 8px; | |
| color: #cbd5e1; | |
| font-size: 0.9rem; | |
| cursor: pointer; | |
| transition: all 0.3s; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 6px; | |
| } | |
| .action-btn:hover { | |
| background: #475569; | |
| transform: translateY(-2px); | |
| } | |
| .action-btn:disabled { | |
| opacity: 0.5; | |
| cursor: not-allowed; | |
| transform: none; | |
| } | |
| .quick-commands { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 8px; | |
| } | |
| .quick-btn { | |
| padding: 8px 14px; | |
| background: #334155; | |
| border: none; | |
| border-radius: 8px; | |
| color: #cbd5e1; | |
| font-size: 0.85rem; | |
| cursor: pointer; | |
| transition: all 0.3s; | |
| } | |
| .quick-btn:hover { | |
| background: #475569; | |
| transform: translateY(-1px); | |
| } | |
| .console-section { | |
| margin-top: 20px; | |
| } | |
| .console-log { | |
| max-height: 200px; | |
| overflow-y: auto; | |
| background: rgba(15, 23, 42, 0.8); | |
| border-radius: 12px; | |
| padding: 16px; | |
| font-family: 'Courier New', monospace; | |
| font-size: 0.85rem; | |
| scrollbar-width: thin; | |
| scrollbar-color: #334155 transparent; | |
| } | |
| .console-log::-webkit-scrollbar { | |
| width: 6px; | |
| } | |
| .console-log::-webkit-scrollbar-thumb { | |
| background: #334155; | |
| border-radius: 3px; | |
| } | |
| .log-entry { | |
| padding: 4px 0; | |
| border-bottom: 1px solid rgba(255,255,255,0.05); | |
| } | |
| .log-time { | |
| color: #64748b; | |
| margin-right: 8px; | |
| } | |
| .log-info { color: #60a5fa; } | |
| .log-success { color: #4ade80; } | |
| .log-error { color: #f87171; } | |
| .log-chat { color: #c084fc; } | |
| .log-join { color: #86efac; } | |
| .log-leave { color: #fca5a5; } | |
| .stats-grid { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 12px; | |
| margin-top: 16px; | |
| } | |
| .stat-card { | |
| background: rgba(15, 23, 42, 0.6); | |
| padding: 16px; | |
| border-radius: 12px; | |
| text-align: center; | |
| } | |
| .stat-value { | |
| font-size: 1.5rem; | |
| font-weight: 700; | |
| color: #60a5fa; | |
| } | |
| .stat-label { | |
| font-size: 0.85rem; | |
| color: #94a3b8; | |
| margin-top: 4px; | |
| } | |
| .hidden { display: none ; } | |
| @media (max-width: 900px) { | |
| .main-grid { | |
| grid-template-columns: 1fr; | |
| } | |
| .connection-form { | |
| grid-template-columns: 1fr; | |
| } | |
| .sidebar { | |
| order: -1; | |
| } | |
| } | |
| .toast { | |
| position: fixed; | |
| bottom: 20px; | |
| right: 20px; | |
| padding: 16px 24px; | |
| border-radius: 12px; | |
| color: white; | |
| font-weight: 600; | |
| animation: slideIn 0.3s ease; | |
| z-index: 1000; | |
| } | |
| .toast-success { background: #22c55e; } | |
| .toast-error { background: #ef4444; } | |
| .toast-info { background: #3b82f6; } | |
| @keyframes slideIn { | |
| from { transform: translateX(100%); opacity: 0; } | |
| to { transform: translateX(0); opacity: 1; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <div class="header"> | |
| <h1>🎮 Minecraft Bot Controller</h1> | |
| <p>Connect your bot to any Minecraft server and control it from the web</p> | |
| </div> | |
| <!-- Connection Panel --> | |
| <div class="panel"> | |
| <div class="connection-form"> | |
| <div class="form-group"> | |
| <label>🧑 Player Name</label> | |
| <input type="text" id="playerName" placeholder="BotName123" value="HFBot_4220"> | |
| </div> | |
| <div class="form-group"> | |
| <label>🌐 Server IP</label> | |
| <input type="text" id="serverIp" placeholder="play.example.com" value="play.hypixel.net"> | |
| </div> | |
| <div class="form-group"> | |
| <label>🔌 Port</label> | |
| <input type="number" id="serverPort" placeholder="25565" value="25565"> | |
| </div> | |
| <button id="connectBtn" class="btn btn-primary" onclick="toggleConnection()"> | |
| <span id="btnIcon">🔗</span> | |
| <span id="btnText">Connect Bot</span> | |
| </button> | |
| </div> | |
| <div class="status-bar"> | |
| <div class="status-indicator"> | |
| <div id="statusDot" class="status-dot status-offline"></div> | |
| <span id="statusText" class="status-text">Disconnected</span> | |
| </div> | |
| <div id="botInfo" class="bot-info hidden"> | |
| <img id="botAvatar" src="" alt="" class="bot-avatar"> | |
| <div class="bot-details"> | |
| <div id="botName" class="bot-name"></div> | |
| <div id="serverAddr" class="server-address"></div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Main Grid --> | |
| <div class="main-grid"> | |
| <!-- Chat Section --> | |
| <div class="panel chat-section"> | |
| <div class="chat-header"> | |
| <h2> | |
| 💬 Server Chat | |
| <span id="chatBadge" class="badge hidden">0</span> | |
| </h2> | |
| <div class="chat-controls"> | |
| <button onclick="clearChat()">🧹 Clear</button> | |
| <button onclick="toggleAutoScroll()" id="autoScrollBtn">📜 Auto</button> | |
| </div> | |
| </div> | |
| <div id="chatMessages" class="chat-messages"> | |
| <div class="empty-state"> | |
| <div class="icon">📡</div> | |
| <p>Connect to a server to start chatting</p> | |
| </div> | |
| </div> | |
| <div class="chat-input-area"> | |
| <input type="text" id="chatInput" class="chat-input" placeholder="Type a message..." | |
| onkeypress="if(event.key==='Enter') sendChat()" disabled> | |
| <button id="sendBtn" class="btn btn-primary" onclick="sendChat()" disabled> | |
| 📤 Send | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Sidebar --> | |
| <div class="sidebar"> | |
| <!-- Players Online --> | |
| <div class="panel"> | |
| <h2 style="display:flex;align-items:center;gap:10px;margin-bottom:16px;"> | |
| 👥 Players Online | |
| <span id="onlineCount" class="badge" style="background:#22c55e;">0</span> | |
| </h2> | |
| <div id="playersList" class="players-list"> | |
| <p style="text-align:center;color:#64748b;padding:20px;">Not connected</p> | |
| </div> | |
| </div> | |
| <!-- Bot Stats --> | |
| <div class="panel"> | |
| <h2 style="margin-bottom:16px;">📊 Bot Stats</h2> | |
| <div class="stats-grid"> | |
| <div class="stat-card"> | |
| <div id="healthStat" class="stat-value">❤️ 20</div> | |
| <div class="stat-label">Health</div> | |
| </div> | |
| <div class="stat-card"> | |
| <div id="foodStat" class="stat-value">🍖 20</div> | |
| <div class="stat-label">Food</div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Bot Actions --> | |
| <div class="panel"> | |
| <h2 style="margin-bottom:16px;">🤖 Bot Actions</h2> | |
| <div class="actions-grid"> | |
| <button class="action-btn" onclick="botAction('jump')" id="jumpBtn" disabled> | |
| ⬆️ Jump | |
| </button> | |
| <button class="action-btn" onclick="botAction('sneak')" id="sneakBtn" disabled> | |
| 👇 Sneak | |
| </button> | |
| <button class="action-btn" onclick="botAction('move', 'forward')" id="forwardBtn" disabled> | |
| ⬆️ Forward | |
| </button> | |
| <button class="action-btn" onclick="botAction('move', 'back')" id="backBtn" disabled> | |
| ⬇️ Back | |
| </button> | |
| <button class="action-btn" onclick="sendCommand('/list')" id="listBtn" disabled> | |
| 📋 List | |
| </button> | |
| <button class="action-btn" onclick="sendCommand('/help')" id="helpBtn" disabled> | |
| ❓ Help | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Quick Commands --> | |
| <div class="panel"> | |
| <h2 style="margin-bottom:16px;">⚡ Quick Chat</h2> | |
| <div class="quick-commands"> | |
| <button class="quick-btn" onclick="quickChat('Hello everyone! 👋')">👋 Hello</button> | |
| <button class="quick-btn" onclick="quickChat('Good game! 🎮')">🎮 GG</button> | |
| <button class="quick-btn" onclick="quickChat('Anyone need help? 🆘')">🆘 Help?</button> | |
| <button class="quick-btn" onclick="quickChat('Nice build! 🏗️')">🏗️ Nice</button> | |
| <button class="quick-btn" onclick="quickChat('BRB ⏸️')">⏸️ BRB</button> | |
| <button class="quick-btn" onclick="quickChat('Back! ▶️')">▶️ Back</button> | |
| <button class="quick-btn" onclick="quickChat('Anyone want to team? 🤝')">🤝 Team?</button> | |
| <button class="quick-btn" onclick="quickChat('Lag? 🐌')">🐌 Lag?</button> | |
| </div> | |
| </div> | |
| <!-- Console Log --> | |
| <div class="panel console-section"> | |
| <h2 style="margin-bottom:16px;">📊 Console</h2> | |
| <div id="consoleLog" class="console-log"> | |
| <div class="log-entry"> | |
| <span class="log-time">[System]</span> | |
| <span class="log-info">Minecraft Bot Controller initialized</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Socket.IO Connection | |
| const socket = io(); | |
| // State | |
| let isConnected = false; | |
| let autoScroll = true; | |
| let unreadCount = 0; | |
| let currentUsername = ''; | |
| // DOM Elements | |
| const connectBtn = document.getElementById('connectBtn'); | |
| const btnText = document.getElementById('btnText'); | |
| const btnIcon = document.getElementById('btnIcon'); | |
| const statusDot = document.getElementById('statusDot'); | |
| const statusText = document.getElementById('statusText'); | |
| const chatMessages = document.getElementById('chatMessages'); | |
| const chatInput = document.getElementById('chatInput'); | |
| const sendBtn = document.getElementById('sendBtn'); | |
| const playersList = document.getElementById('playersList'); | |
| const consoleLog = document.getElementById('consoleLog'); | |
| const botInfo = document.getElementById('botInfo'); | |
| const botAvatar = document.getElementById('botAvatar'); | |
| const botName = document.getElementById('botName'); | |
| const serverAddr = document.getElementById('serverAddr'); | |
| const onlineCount = document.getElementById('onlineCount'); | |
| const chatBadge = document.getElementById('chatBadge'); | |
| const healthStat = document.getElementById('healthStat'); | |
| const foodStat = document.getElementById('foodStat'); | |
| // Action buttons | |
| const actionBtns = ['jumpBtn', 'sneakBtn', 'forwardBtn', 'backBtn', 'listBtn', 'helpBtn']; | |
| // Socket Events | |
| socket.on('connect', () => { | |
| log('Connected to server', 'success'); | |
| }); | |
| socket.on('disconnect', () => { | |
| log('Disconnected from server', 'error'); | |
| handleDisconnect(); | |
| }); | |
| socket.on('bot-status', (data) => { | |
| updateStatus('online', 'Online'); | |
| isConnected = true; | |
| currentUsername = data.username; | |
| btnText.textContent = 'Disconnect'; | |
| btnIcon.textContent = '🔌'; | |
| connectBtn.classList.remove('btn-primary'); | |
| connectBtn.classList.add('btn-danger'); | |
| chatInput.disabled = false; | |
| sendBtn.disabled = false; | |
| actionBtns.forEach(id => document.getElementById(id).disabled = false); | |
| botInfo.classList.remove('hidden'); | |
| botAvatar.src = `https://mc-heads.net/avatar/${data.username}/40`; | |
| botName.textContent = data.username; | |
| serverAddr.textContent = `${data.host}:${data.port}`; | |
| chatMessages.innerHTML = ''; | |
| addSystemMessage('Connected to server!'); | |
| showToast('Bot connected successfully!', 'success'); | |
| }); | |
| socket.on('bot-spawned', (data) => { | |
| log('Bot spawned in world', 'success'); | |
| if (data.health) healthStat.textContent = `❤️ ${Math.round(data.health)}`; | |
| if (data.food) foodStat.textContent = `🍖 ${Math.round(data.food)}`; | |
| }); | |
| socket.on('chat-message', (data) => { | |
| addChatMessage(data.username, data.message, false, data.timestamp); | |
| if (!document.hasFocus()) { | |
| unreadCount++; | |
| updateBadge(); | |
| } | |
| }); | |
| socket.on('chat-sent', (data) => { | |
| addChatMessage(data.username, data.message, true, data.timestamp); | |
| }); | |
| socket.on('system-message', (data) => { | |
| addSystemMessage(data.message); | |
| }); | |
| socket.on('player-joined', (data) => { | |
| addSystemMessage(`✅ ${data.username} joined the game`); | |
| log(`${data.username} joined`, 'join'); | |
| }); | |
| socket.on('player-left', (data) => { | |
| addSystemMessage(`❌ ${data.username} left the game`); | |
| log(`${data.username} left`, 'leave'); | |
| }); | |
| socket.on('players-list', (players) => { | |
| updatePlayersList(players); | |
| }); | |
| socket.on('bot-health', (data) => { | |
| healthStat.textContent = `❤️ ${Math.round(data.health)}`; | |
| foodStat.textContent = `🍖 ${Math.round(data.food)}`; | |
| }); | |
| socket.on('bot-death', (data) => { | |
| addSystemMessage('💀 Bot died!'); | |
| log('Bot died', 'error'); | |
| }); | |
| socket.on('bot-kicked', (data) => { | |
| addSystemMessage(`🚫 Kicked: ${data.reason}`); | |
| log(`Kicked: ${data.reason}`, 'error'); | |
| handleDisconnect(); | |
| }); | |
| socket.on('bot-disconnected', (data) => { | |
| addSystemMessage(`🔌 Disconnected: ${data.reason}`); | |
| log(`Disconnected: ${data.reason}`, 'error'); | |
| handleDisconnect(); | |
| }); | |
| socket.on('bot-error', (data) => { | |
| log(`Error: ${data.message}`, 'error'); | |
| showToast(data.message, 'error'); | |
| }); | |
| socket.on('error', (data) => { | |
| showToast(data.message, 'error'); | |
| updateStatus('offline', 'Connection Failed'); | |
| resetButton(); | |
| }); | |
| // Functions | |
| function toggleConnection() { | |
| if (isConnected) { | |
| disconnectBot(); | |
| } else { | |
| connectBot(); | |
| } | |
| } | |
| function connectBot() { | |
| const username = document.getElementById('playerName').value.trim(); | |
| const host = document.getElementById('serverIp').value.trim(); | |
| const port = document.getElementById('serverPort').value || 25565; | |
| if (!username || !host) { | |
| showToast('Please enter username and server IP', 'error'); | |
| return; | |
| } | |
| updateStatus('connecting', 'Connecting...'); | |
| btnText.textContent = 'Connecting...'; | |
| btnIcon.textContent = '⏳'; | |
| connectBtn.disabled = true; | |
| log(`Connecting to ${host}:${port} as ${username}...`, 'info'); | |
| socket.emit('connect-bot', { username, host, port }); | |
| // Timeout for connection | |
| setTimeout(() => { | |
| if (!isConnected && btnText.textContent === 'Connecting...') { | |
| updateStatus('offline', 'Connection Timeout'); | |
| resetButton(); | |
| showToast('Connection timeout. Check server details.', 'error'); | |
| } | |
| }, 30000); | |
| } | |
| function disconnectBot() { | |
| socket.emit('disconnect-bot'); | |
| log('Disconnecting...', 'info'); | |
| } | |
| function handleDisconnect() { | |
| isConnected = false; | |
| currentUsername = ''; | |
| updateStatus('offline', 'Disconnected'); | |
| resetButton(); | |
| chatInput.disabled = true; | |
| sendBtn.disabled = true; | |
| actionBtns.forEach(id => document.getElementById(id).disabled = true); | |
| botInfo.classList.add('hidden'); | |
| playersList.innerHTML = '<p style="text-align:center;color:#64748b;padding:20px;">Not connected</p>'; | |
| onlineCount.textContent = '0'; | |
| healthStat.textContent = '❤️ 20'; | |
| foodStat.textContent = '🍖 20'; | |
| addSystemMessage('Disconnected from server'); | |
| } | |
| function resetButton() { | |
| connectBtn.disabled = false; | |
| btnText.textContent = 'Connect Bot'; | |
| btnIcon.textContent = '🔗'; | |
| connectBtn.classList.remove('btn-danger'); | |
| connectBtn.classList.add('btn-primary'); | |
| } | |
| function updateStatus(status, text) { | |
| statusDot.className = 'status-dot'; | |
| if (status === 'online') { | |
| statusDot.classList.add('status-online'); | |
| statusText.className = 'status-text'; | |
| statusText.style.color = '#4ade80'; | |
| } else if (status === 'offline') { | |
| statusDot.classList.add('status-offline'); | |
| statusText.className = 'status-text'; | |
| statusText.style.color = '#f87171'; | |
| } else if (status === 'connecting') { | |
| statusDot.classList.add('status-connecting'); | |
| statusText.className = 'status-text'; | |
| statusText.style.color = '#facc15'; | |
| } | |
| statusText.textContent = text; | |
| } | |
| function addChatMessage(username, message, isBot, timestamp) { | |
| const div = document.createElement('div'); | |
| div.className = 'message' + (isBot ? ' bot-message' : ''); | |
| const time = timestamp ? new Date(timestamp).toLocaleTimeString() : new Date().toLocaleTimeString(); | |
| const avatar = `https://mc-heads.net/avatar/${username}/36`; | |
| const authorClass = isBot ? 'bot' : (username === 'Server' ? 'server' : 'player'); | |
| div.innerHTML = ` | |
| <img src="${avatar}" alt="${username}" class="message-avatar" | |
| onerror="this.src='https://mc-heads.net/avatar/Steve/36'"> | |
| <div class="message-content"> | |
| <div class="message-header"> | |
| <span class="message-author ${authorClass}">${escapeHtml(username)}</span> | |
| <span class="message-time">${time}</span> | |
| </div> | |
| <p class="message-text">${escapeHtml(message)}</p> | |
| </div> | |
| `; | |
| chatMessages.appendChild(div); | |
| if (autoScroll) { | |
| chatMessages.scrollTop = chatMessages.scrollHeight; | |
| } | |
| } | |
| function addSystemMessage(text) { | |
| const div = document.createElement('div'); | |
| div.className = 'message system-message'; | |
| div.innerHTML = `<span class="system-text">${escapeHtml(text)}</span>`; | |
| chatMessages.appendChild(div); | |
| if (autoScroll) { | |
| chatMessages.scrollTop = chatMessages.scrollHeight; | |
| } | |
| } | |
| function sendChat() { | |
| const message = chatInput.value.trim(); | |
| if (!message || !isConnected) return; | |
| socket.emit('send-chat', message); | |
| chatInput.value = ''; | |
| chatInput.focus(); | |
| } | |
| function quickChat(message) { | |
| if (!isConnected) { | |
| showToast('Connect to a server first', 'error'); | |
| return; | |
| } | |
| socket.emit('send-chat', message); | |
| } | |
| function sendCommand(command) { | |
| if (!isConnected) { | |
| showToast('Connect to a server first', 'error'); | |
| return; | |
| } | |
| socket.emit('send-command', command); | |
| log(`Command: ${command}`, 'info'); | |
| } | |
| function botAction(type, direction) { | |
| if (!isConnected) return; | |
| const action = { type }; | |
| if (direction) action.direction = direction; | |
| socket.emit('bot-action', action); | |
| log(`Action: ${type}${direction ? ' ' + direction : ''}`, 'info'); | |
| } | |
| function updatePlayersList(players) { | |
| onlineCount.textContent = players.length; | |
| if (players.length === 0) { | |
| playersList.innerHTML = '<p style="text-align:center;color:#64748b;padding:20px;">No players online</p>'; | |
| return; | |
| } | |
| playersList.innerHTML = players.map(p => ` | |
| <div class="player-item"> | |
| <img src="https://mc-heads.net/avatar/${p.username}/32" | |
| class="player-avatar" | |
| onerror="this.src='https://mc-heads.net/avatar/Steve/32'"> | |
| <div class="player-info"> | |
| <div class="player-name">${escapeHtml(p.username)}</div> | |
| <div class="player-ping">${p.ping}ms</div> | |
| </div> | |
| <div class="player-status"></div> | |
| </div> | |
| `).join(''); | |
| } | |
| function clearChat() { | |
| chatMessages.innerHTML = ` | |
| <div class="empty-state"> | |
| <div class="icon">🧹</div> | |
| <p>Chat cleared</p> | |
| </div> | |
| `; | |
| unreadCount = 0; | |
| updateBadge(); | |
| } | |
| function toggleAutoScroll() { | |
| autoScroll = !autoScroll; | |
| document.getElementById('autoScrollBtn').textContent = autoScroll ? '📜 Auto' : '📜 Manual'; | |
| if (autoScroll) { | |
| chatMessages.scrollTop = chatMessages.scrollHeight; | |
| } | |
| } | |
| function updateBadge() { | |
| if (unreadCount > 0) { | |
| chatBadge.textContent = unreadCount; | |
| chatBadge.classList.remove('hidden'); | |
| } else { | |
| chatBadge.classList.add('hidden'); | |
| } | |
| } | |
| function log(message, type = 'info') { | |
| const entry = document.createElement('div'); | |
| entry.className = 'log-entry'; | |
| const time = new Date().toLocaleTimeString(); | |
| entry.innerHTML = ` | |
| <span class="log-time">[${time}]</span> | |
| <span class="log-${type}">${escapeHtml(message)}</span> | |
| `; | |
| consoleLog.appendChild(entry); | |
| consoleLog.scrollTop = consoleLog.scrollHeight; | |
| } | |
| function showToast(message, type = 'info') { | |
| const toast = document.createElement('div'); | |
| toast.className = `toast toast-${type}`; | |
| toast.textContent = message; | |
| document.body.appendChild(toast); | |
| setTimeout(() => { | |
| toast.style.opacity = '0'; | |
| toast.style.transform = 'translateX(100%)'; | |
| setTimeout(() => toast.remove(), 300); | |
| }, 3000); | |
| } | |
| function escapeHtml(text) { | |
| const div = document.createElement('div'); | |
| div.textContent = text; | |
| return div.innerHTML; | |
| } | |
| // Window focus handler | |
| window.addEventListener('focus', () => { | |
| unreadCount = 0; | |
| updateBadge(); | |
| }); | |
| // Initialize | |
| log('System ready. Enter server details and click Connect.', 'info'); | |
| </script> | |
| </body> | |
| </html> |