(function () { console.log("%c Magic Garden Bot Extension Loaded ", "background: #222; color: #bada55; font-size: 20px"); // --- LOGIC: WebSocket Hook --- window.gameSocket = null; const OriginalSend = WebSocket.prototype.send; WebSocket.prototype.send = function (data) { if (!window.gameSocket || window.gameSocket.readyState >= 2) { window.gameSocket = this; updateStatus(true); // Extract Player ID from URL try { const urlObj = new URL(this.url); let pid = urlObj.searchParams.get('playerId'); // Remove quotes content if wrapped in " " (e.g. from %22p_...%22) if (pid) pid = pid.replace(/^"|"$/g, ''); gameState.playerId = pid; console.log("[MagicBot] Captured Player ID:", gameState.playerId); } catch (e) { console.error("[MagicBot] Failed to parse Player ID:", e); } this.addEventListener('close', () => { updateStatus(false); }); // Capture Incoming this.addEventListener('message', (e) => { logToOverlay('RX', e.data); try { const msg = JSON.parse(e.data); if (msg.type === 'Welcome') { handleWelcome(msg); } } catch (err) { } }); } // Capture Outgoing logToOverlay('TX', data); return OriginalSend.apply(this, arguments); }; // --- STATE MANAGEMENT --- let gameState = { coins: 0, garden: {}, inventory: {}, playerId: null }; function handleWelcome(msg) { console.log("Parsing Welcome Message..."); const root = msg.fullState.data; console.log("Looking for slot for PlayerID:", gameState.playerId); // Find our user slot const userSlot = root.userSlots.find(s => s.playerId === gameState.playerId); if (userSlot) { console.log("Found User Slot!", userSlot); gameState.coins = userSlot.data.coinsCount; gameState.garden = userSlot.data.garden.tileObjects; gameState.inventory = userSlot.data.inventory; updateVisuals(); } else { console.error("Could not find user slot for ID:", gameState.playerId); // Debug: Log all available IDs console.log("Available Slots:", root.userSlots.map(s => s.playerId)); } } function updateVisuals() { // Update Wallet const walletContent = document.getElementById('window-wallet-content'); if (walletContent) { walletContent.innerHTML = `
CA$H: ${gameState.coins.toLocaleString()}
`; } // Update Garden const gardenContent = document.getElementById('window-garden-content'); if (gardenContent) { let html = '
'; const now = Date.now(); Object.entries(gameState.garden).forEach(([slotId, tile]) => { const crop = tile.slots[0]; // Assuming single slot for now if (!crop) return; const isReady = now >= tile.maturedAt; const timeLeft = Math.max(0, Math.ceil((tile.maturedAt - now) / 1000)); const color = isReady ? '#66bb6a' : '#ffa726'; html += `
${tile.species}
${slotId}
${isReady ? 'READY' : timeLeft + 's'}
`; }); html += '
'; gardenContent.innerHTML = html; } } // --- UI HELPER: Floating Windows --- function createFloatingWindow(id, title, x, y, width, height) { if (document.getElementById(id)) return; // Already exists const win = document.createElement('div'); win.id = id; win.style.cssText = ` position: fixed; top: ${y}px; left: ${x}px; width: ${width}px; height: ${height}px; background: rgba(10, 10, 20, 0.9); border: 1px solid #444; border-radius: 8px; z-index: 9999995; display: flex; flex-direction: column; box-shadow: 0 44px 15px rgba(0,0,0,0.5); font-family: sans-serif; color: #eee; backdrop-filter: blur(5px); resize: both; overflow: hidden; `; win.innerHTML = `
${title}
`; document.body.appendChild(win); // Drag Logic const header = win.querySelector(`#${id}-header`); let isDragging = false, offX = 0, offY = 0; header.addEventListener('mousedown', (e) => { isDragging = true; offX = e.clientX - win.offsetLeft; offY = e.clientY - win.offsetTop; }); window.addEventListener('mousemove', (e) => { if (isDragging) { win.style.left = (e.clientX - offX) + 'px'; win.style.top = (e.clientY - offY) + 'px'; } }); window.addEventListener('mouseup', () => isDragging = false); } // --- LOGIC: Commands --- function sendMsg(msg) { if (!window.gameSocket) { alert("Socket not connected! Wait for game to load."); return; } window.gameSocket.send(JSON.stringify(msg)); } async function harvestLoop(start, end, count, delay) { let sent = 0; for (let slot = start; slot <= end; slot++) { for (let i = 0; i < count; i++) { sendMsg({ type: 'HarvestCrop', slot: slot, slotsIndex: i, scopePath: ["Room", "Quinoa"] }); sent++; await new Promise(r => setTimeout(r, delay)); } } console.log(`Harvested ${sent} items.`); } // --- UI: Sidebar --- const sidebar = document.createElement('div'); sidebar.id = 'magic-bot-sidebar'; sidebar.style.cssText = ` position: fixed; top: 20px; right: 20px; width: 280px; background: rgba(20, 20, 25, 0.95); color: #eee; padding: 20px; border-radius: 12px; z-index: 9999999; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; box-shadow: 0 4px 15px rgba(0,0,0,0.6); border: 1px solid #444; backdrop-filter: blur(5px); `; sidebar.innerHTML = `

🌱 Magic Bot

● Disconnected
Start Slot
End Slot
Iter. (Count)
Delay (ms)
`; document.body.appendChild(sidebar); document.getElementById('btn-state').onclick = () => { createFloatingWindow('window-wallet', '💰 Wallet', 20, 400, 200, 80); createFloatingWindow('window-garden', '🌻 Garden', 240, 400, 300, 300); updateVisuals(); // Refresh if data exists }; // --- LOG OVERLAY --- const logOverlay = document.createElement('div'); logOverlay.id = 'magic-bot-logs'; logOverlay.style.cssText = ` display: none; position: fixed; bottom: 20px; left: 20px; width: 600px; height: 300px; background: rgba(10, 10, 15, 0.95); border: 1px solid #444; border-radius: 8px; z-index: 9999999; font-family: 'Consolas', 'Monaco', monospace; font-size: 11px; color: #eee; display: flex; flex-direction: column; box-shadow: 0 4px 15px rgba(0,0,0,0.6); resize: both; overflow: hidden; `; logOverlay.innerHTML = `
Network Logs
`; document.body.appendChild(logOverlay); logOverlay.style.display = 'none'; // Ensure hidden initially // Make Draggable let isDragging = false; let dragOffsetX = 0; let dragOffsetY = 0; const header = logOverlay.querySelector('#log-header'); header.addEventListener('mousedown', (e) => { isDragging = true; dragOffsetX = e.clientX - logOverlay.offsetLeft; dragOffsetY = e.clientY - logOverlay.offsetTop; }); window.addEventListener('mousemove', (e) => { if (isDragging) { logOverlay.style.left = (e.clientX - dragOffsetX) + 'px'; logOverlay.style.top = (e.clientY - dragOffsetY) + 'px'; } }); window.addEventListener('mouseup', () => isDragging = false); // Stop propagation for logs too logOverlay.addEventListener('keydown', (e) => e.stopPropagation()); logOverlay.addEventListener('keyup', (e) => e.stopPropagation()); logOverlay.addEventListener('keypress', (e) => e.stopPropagation()); function logToOverlay(type, data) { const container = document.getElementById('log-content'); if (!container) return; // Check if we are near the bottom BEFORE adding new content (within 50px) const isAtBottom = (container.scrollHeight - container.scrollTop - container.clientHeight) < 50; const line = document.createElement('div'); line.style.borderBottom = '1px solid #222'; line.style.padding = '2px 0'; const timestamp = new Date().toLocaleTimeString(); let color = type === 'TX' ? '#66bb6a' : '#448aff'; let content = data; // Pretty print JSON try { if (typeof data === 'string' && (data.startsWith('{') || data.startsWith('['))) { content = JSON.stringify(JSON.parse(data)); // Minify } } catch (e) { } line.innerHTML = `[${timestamp}] ${type} ${content}`; // Click to copy line.style.cursor = 'pointer'; line.title = 'Click to copy raw message'; line.addEventListener('click', () => { navigator.clipboard.writeText(data).then(() => { // Visual feedback line.style.background = 'rgba(255, 255, 255, 0.1)'; setTimeout(() => line.style.background = 'transparent', 200); console.log('Copied to clipboard:', data); }).catch(err => console.error('Failed to copy matches:', err)); }); container.appendChild(line); // Auto scroll ONLY if we were already at the bottom if (isAtBottom) { container.scrollTop = container.scrollHeight; } // Limit history (500 lines) if (container.children.length > 500) { container.removeChild(container.firstChild); } } // Stop keyboard events from reaching the game (Fixes specific keys not working) sidebar.addEventListener('keydown', (e) => e.stopPropagation()); sidebar.addEventListener('keyup', (e) => e.stopPropagation()); sidebar.addEventListener('keypress', (e) => e.stopPropagation()); // --- COLLAPSE LOGIC --- const setupCollapse = (headId, bodyId, arrowId) => { document.getElementById(headId).onclick = () => { const el = document.getElementById(bodyId); const arrow = document.getElementById(arrowId); if (el.style.display === 'none') { el.style.display = 'block'; arrow.textContent = '▼'; } else { el.style.display = 'none'; arrow.textContent = '▶'; } }; }; setupCollapse('head-tp', 'section-tp', 'arrow-tp'); setupCollapse('head-hv', 'section-hv', 'arrow-hv'); document.getElementById('btn-logs').onclick = () => { const el = document.getElementById('magic-bot-logs'); el.style.display = el.style.display === 'none' ? 'flex' : 'none'; // Reset position if off-screen (optional safety) if (el.style.display === 'flex') { el.style.top = 'auto'; el.style.bottom = '20px'; el.style.left = '20px'; } }; document.getElementById('btn-close-logs').onclick = () => { document.getElementById('magic-bot-logs').style.display = 'none'; }; document.getElementById('btn-clear-logs').onclick = () => { document.getElementById('log-content').innerHTML = ''; }; // --- UI LOGIC --- function updateStatus(connected) { const el = document.getElementById('status-indicator'); if (connected) { el.innerHTML = '● Connected'; el.style.color = '#66bb6a'; // Green } else { el.innerHTML = '● Disconnected'; el.style.color = '#ff5252'; // Red } } document.getElementById('btn-tp').onclick = () => { const x = parseInt(document.getElementById('tp-x').value); const y = parseInt(document.getElementById('tp-y').value); sendMsg({ type: 'Teleport', position: { x, y }, scopePath: ["Room", "Quinoa"] }); }; document.getElementById('btn-harvest').onclick = () => { const start = parseInt(document.getElementById('hv-start').value); const end = parseInt(document.getElementById('hv-end').value); const count = parseInt(document.getElementById('hv-count').value); const delay = parseInt(document.getElementById('hv-delay').value); harvestLoop(start, end, count, delay); }; document.getElementById('btn-sell').onclick = () => { sendMsg({ type: 'SellAllCrops', scopePath: ["Room", "Quinoa"] }); }; })();