Spaces:
Paused
Paused
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>AFK Bot Control Panel</title> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap" rel="stylesheet"> | |
| <style> | |
| :root { | |
| --bg-darkest: #121212; | |
| --bg-dark: #1e1e1e; | |
| --bg-card: #2a2a2a; | |
| --text-primary: #e0e0e0; | |
| --text-secondary: #b3b3b3; | |
| --accent-primary: #00aaff; | |
| --accent-secondary: #0077b3; | |
| --accent-danger: #ff4d4d; | |
| --border-color: #444; | |
| --font-family: 'Inter', sans-serif; | |
| --border-radius: 8px; | |
| --shadow: 0 4px 6px rgba(0,0,0,0.1); | |
| } | |
| body { | |
| margin: 0; | |
| font-family: var(--font-family); | |
| background: var(--bg-darkest); | |
| color: var(--text-primary); | |
| } | |
| .container { | |
| max-width: 900px; | |
| margin: 0 auto; | |
| padding: 16px; | |
| } | |
| header { | |
| background: var(--bg-dark); | |
| padding: 24px 16px; | |
| text-align: center; | |
| border-bottom: 1px solid var(--border-color); | |
| margin-bottom: 24px; | |
| } | |
| h1 { font-size: 1.75rem; font-weight: 700; margin: 0; } | |
| #status { font-size: 0.9rem; margin-top: 8px; color: var(--text-secondary); } | |
| #status.connected { color: #4caf50; } | |
| #status.disconnected { color: var(--accent-danger); } | |
| h2 { | |
| font-size: 1.25rem; | |
| font-weight: 500; | |
| color: var(--text-primary); | |
| border-bottom: 1px solid var(--border-color); | |
| padding-bottom: 8px; | |
| margin-top: 0; | |
| margin-bottom: 17px; | |
| } | |
| section { | |
| background: var(--bg-card); | |
| border-radius: var(--border-radius); | |
| padding: 20px; | |
| margin-bottom: 24px; | |
| box-shadow: var(--shadow); | |
| } | |
| .btn-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); | |
| gap: 12px; | |
| } | |
| button { | |
| padding: 12px; | |
| background: var(--bg-dark); | |
| border: 1px solid var(--border-color); | |
| border-radius: var(--border-radius); | |
| color: var(--text-primary); | |
| font-family: var(--font-family); | |
| font-size: 0.95rem; | |
| font-weight: 500; | |
| cursor: pointer; | |
| transition: all 0.2s ease-in-out; | |
| text-align: center; | |
| } | |
| button:hover { | |
| border-color: var(--accent-primary); | |
| color: var(--accent-primary); | |
| } | |
| button.flash { | |
| animation: flash-animation 0.4s ease; | |
| } | |
| @keyframes flash-animation { | |
| 0% { background: var(--bg-dark); } | |
| 50% { background: var(--accent-secondary); } | |
| 100% { background: var(--bg-dark); } | |
| } | |
| .btn-danger { color: var(--accent-danger); border-color: var(--accent-danger); } | |
| .btn-danger:hover { background: var(--accent-danger); color: #fff; } | |
| .btn-success { color: #4caf50; border-color: #4caf50; } | |
| .btn-success:hover { background: #4caf50; color: #fff; } | |
| table { width: 100%; border-collapse: collapse; margin-top: 16px; } | |
| th, td { border-bottom: 1px solid var(--border-color); padding: 12px; text-align: left; } | |
| thead th { | |
| color: var(--text-secondary); | |
| font-size: 0.85rem; | |
| text-transform: uppercase; | |
| font-weight: 500; | |
| } | |
| tbody tr:hover { background: var(--bg-dark); } | |
| td:last-child { text-align: center; } | |
| td button { padding: 6px 12px; min-width: 70px; } | |
| .input-group { | |
| display: flex; | |
| gap: 8px; | |
| } | |
| .input-group input { | |
| flex: 1; | |
| padding: 12px; | |
| border-radius: 8px; | |
| border: 1px solid var(--border-color); | |
| background: var(--bg-dark); | |
| color: var(--text-primary); | |
| font-size: 0.95rem; | |
| } | |
| .input-group button { | |
| padding: 12px 20px; | |
| flex-shrink: 0; /* Prevent button from shrinking */ | |
| } | |
| @media (max-width: 600px) { | |
| .container { padding: 8px; } | |
| header { padding: 16px 8px; margin-bottom: 16px; } | |
| h1 { font-size: 1.5rem; } | |
| section { padding: 16px; margin-bottom: 16px; } | |
| .btn-grid { gap: 8px; grid-template-columns: repeat(auto-fit, minmax(80px, 1fr)); } | |
| th, td { padding: 8px; } | |
| .input-group { flex-direction: column; } | |
| .input-group input, .input-group button { width: 100%; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <h1>AFK Bot Control</h1> | |
| <div id="status">Connecting...</div> | |
| </header> | |
| <main class="container"> | |
| <section> | |
| <h2>Send Chat Command</h2> | |
| <div class="input-group"> | |
| <input type="text" id="chatInput" placeholder="/move galaxysmp"> | |
| <button id="sendChat">Send</button> | |
| </div> | |
| </section> | |
| <!-- NEW MANUAL COMMAND SECTION --> | |
| <section> | |
| <h2>Manual Command</h2> | |
| <div class="input-group"> | |
| <input type="text" id="cmdInput" placeholder="e.g., disconnect, get_inv, move:forward"> | |
| <button id="sendCmdBtn">Send</button> | |
| </div> | |
| </section> | |
| <!-- END NEW MANUAL COMMAND SECTION --> | |
| <section><h2>Movement</h2><div class="btn-grid"> | |
| <button data-command="move:forward" class="move-btn">W</button> | |
| <button data-command="move:back" class="move-btn">S</button> | |
| <button data-command="move:left" class="move-btn">A</button> | |
| <button data-command="move:right" class="move-btn">D</button> | |
| <button data-command="move:jump" class="move-btn">Jump</button> | |
| <button data-command="stop">Stop All</button> | |
| </div></section> | |
| <section><h2>Actions</h2><div class="btn-grid"> | |
| <button data-command="click_left">Left Click</button> | |
| <button data-command="click_right">Right Click</button> | |
| </div></section> | |
| <section><h2>Toggles</h2><div class="btn-grid"> | |
| <button data-command="toggle_afk">AFK Walk</button> | |
| <button data-command="toggle_dirt">Dirt Loop</button> | |
| <button data-command="toggle_follow">Follow DrTurjo</button> | |
| </div></section> | |
| <section><h2>Hotbar Slots</h2><div class="btn-grid"> | |
| <button data-command="slot:1">1</button> | |
| <button data-command="slot:2">2</button> | |
| <button data-command="slot:3">3</button> | |
| <button data-command="slot:4">4</button> | |
| <button data-command="slot:5">5</button> | |
| <button data-command="slot:6">6</button> | |
| <button data-command="slot:7">7</button> | |
| <button data-command="slot:8">8</button> | |
| <button data-command="slot:9">9</button> | |
| </div></section> | |
| <section><h2>Auto-Disconnect Timer</h2><div class="btn-grid"> | |
| <button data-command="timer:60">1 hr</button> | |
| <button data-command="timer:120">2 hr</button> | |
| <button data-command="timer:180">3 hr</button> | |
| <button data-command="timer:240">4 hr</button> | |
| <button data-command="timer:300">5 hr</button> | |
| <button data-command="timer:360">6 hr</button> | |
| <button data-command="timer:420">7 hr</button> | |
| </div></section> | |
| <section><h2>Connection</h2><div class="btn-grid"> | |
| <button data-command="reconnect" class="btn-success">Reconnect</button> | |
| <button data-command="disconnect" class="btn-danger">Disconnect</button> | |
| </div></section> | |
| <section><h2>Inventory</h2> | |
| <button data-command="get_inv">Refresh Inventory</button> | |
| <table id="invTable"><thead><tr><th>Slot</th><th>Item</th><th>Count</th><th>Equip</th></tr></thead><tbody></tbody></table> | |
| </section> | |
| </main> | |
| <script src="/socket.io/socket.io.js"></script> | |
| <script> | |
| const socket = io(); | |
| const statusEl = document.getElementById('status'); | |
| const invTableBody = document.querySelector('#invTable tbody'); | |
| function sendCommand(command) { | |
| if (socket.connected) socket.emit('command', command); | |
| } | |
| document.querySelectorAll('button[data-command]').forEach(button => { | |
| const command = button.dataset.command; | |
| if (button.classList.contains('move-btn')) { | |
| button.addEventListener('mousedown', () => sendCommand(command)); | |
| button.addEventListener('touchstart', e => { e.preventDefault(); sendCommand(command); }); | |
| button.addEventListener('mouseup', () => sendCommand('stop')); | |
| button.addEventListener('mouseleave', () => sendCommand('stop')); | |
| button.addEventListener('touchend', () => sendCommand('stop')); | |
| } else { | |
| button.addEventListener('click', () => { | |
| sendCommand(command); | |
| button.classList.add('flash'); | |
| setTimeout(() => button.classList.remove('flash'), 400); | |
| }); | |
| } | |
| }); | |
| invTableBody.addEventListener('click', e => { | |
| if (e.target.tagName === 'BUTTON' && e.target.dataset.command) { | |
| const btn = e.target; | |
| sendCommand(btn.dataset.command); | |
| btn.classList.add('flash'); | |
| setTimeout(() => btn.classList.remove('flash'), 400); | |
| } | |
| }); | |
| socket.on('connect', () => { | |
| statusEl.textContent = 'Connected'; | |
| statusEl.className = 'connected'; | |
| sendCommand('get_inv'); | |
| }); | |
| socket.on('disconnect', () => { | |
| statusEl.textContent = 'Disconnected'; | |
| statusEl.className = 'disconnected'; | |
| }); | |
| socket.on('inventory', inv => { | |
| invTableBody.innerHTML = ''; | |
| if (!inv || inv.length === 0) { | |
| invTableBody.innerHTML = `<tr><td colspan="4" style="text-align:center; color: var(--text-secondary);">Inventory is empty or not loaded.</td></tr>`; | |
| return; | |
| } | |
| inv.forEach(item => { | |
| const hotbarSlot = (item.slot >= 0 && item.slot <= 8) ? item.slot + 1 : null; | |
| const equipButton = hotbarSlot ? `<button data-command="slot:${hotbarSlot}">Equip</button>` : 'N/A'; | |
| const tr = document.createElement('tr'); | |
| tr.innerHTML = `<td>${item.slot}</td><td>${item.name}</td><td>${item.count}</td><td>${equipButton}</td>`; | |
| invTableBody.appendChild(tr); | |
| }); | |
| }); | |
| // Chat Command Logic | |
| document.getElementById('sendChat').addEventListener('click', () => { | |
| const input = document.getElementById('chatInput'); | |
| const text = input.value.trim(); | |
| if (text.length > 0) { | |
| sendCommand(`chat:${text}`); | |
| input.value = ''; | |
| } | |
| }); | |
| document.getElementById('chatInput').addEventListener('keydown', e => { | |
| if (e.key === 'Enter') document.getElementById('sendChat').click(); | |
| }); | |
| // Manual Command Logic (New Addition) | |
| const sendCmdBtn = document.getElementById('sendCmdBtn'); | |
| const cmdInput = document.getElementById('cmdInput'); | |
| sendCmdBtn.addEventListener('click', () => { | |
| const val = cmdInput.value.trim(); | |
| if (val.length > 0) { | |
| sendCommand(val); // Sends the raw input value as a command | |
| cmdInput.value = ''; | |
| } | |
| }); | |
| cmdInput.addEventListener('keydown', e => { | |
| if (e.key === 'Enter') sendCmdBtn.click(); | |
| }); | |
| </script> | |
| </body> | |
| </html> |