feat: updated collector
This commit is contained in:
63
README.md
63
README.md
@@ -1,2 +1,63 @@
|
|||||||
# MagicBot
|
# Magic Garden Bot
|
||||||
|
|
||||||
|
An advanced browser extension for automating and enhancing gameplay in **Magic Garden**. This bot injects a powerful utility sidebar directly into the game, offering automation features, real-time data visualization, and smart decision-making assistance.
|
||||||
|
|
||||||
|
## ✨ Key Features
|
||||||
|
|
||||||
|
### 🤖 Automation
|
||||||
|
- **Auto Plant**: Automatically replants crops in empty tiles.
|
||||||
|
- **Auto Harvest**: Harvests crops when they are ready.
|
||||||
|
- **Smart Harvest**: Uses advanced decision logic (Bellman Equation) to wait for optimal crop mutations (e.g., waiting for specific weather conditions to maximize value) before harvesting.
|
||||||
|
- **Auto Sell**: Automatically sells harvested resources to free up inventory space.
|
||||||
|
- **Auto Feed Pets**: Keeps your equipped pets fed with the cheapest compatible food from your inventory.
|
||||||
|
|
||||||
|
### 🖥️ User Interface
|
||||||
|
The bot features a clean, dark-themed UI that blends into the game.
|
||||||
|
- **Control Panel**: A sidebar for toggling specific automation features on/off.
|
||||||
|
- **Overlays**: Draggable, floating windows for deeper insight:
|
||||||
|
- **Garden Overlay**: Visual representation of plot status.
|
||||||
|
- **Inventory Overlay**: Filterable view of your items.
|
||||||
|
- **Shop Overlay**: Quick view of shop contents.
|
||||||
|
- **Players Overlay**: See other players in the vicinity.
|
||||||
|
- **Pets Overlay**: Manage your pets, view hunger levels, and toggle auto-feed per pet.
|
||||||
|
- **Model/Decision Overlay**: Visualizes the decision boundary for "Smart Harvest," showing potential value vs. current value.
|
||||||
|
|
||||||
|
### 🛠️ Visualizers & Logs
|
||||||
|
- **Log Viewer**: Searchable log of bot actions and network traffic.
|
||||||
|
- **Network Filtering**: specific filters to inspect socket message traffic.
|
||||||
|
|
||||||
|
## 🚀 Installation
|
||||||
|
|
||||||
|
1. Clone or download this repository.
|
||||||
|
2. Open Chrome (or a Chromium-based browser) and navigate to `chrome://extensions`.
|
||||||
|
3. Enable **Developer Mode** (toggle in the top right).
|
||||||
|
4. Click **Load unpacked**.
|
||||||
|
5. Select the `extension` folder from this project.
|
||||||
|
6. Navigate to [Magic Garden](https://magicgarden.gg/) (the bot will load automatically).
|
||||||
|
|
||||||
|
## 🎮 Usage
|
||||||
|
|
||||||
|
### Controls
|
||||||
|
- **Toggle UI**: Press `Insert` or `Backquote` (`` ` ``) to show/hide the sidebar.
|
||||||
|
- **Sidebar**: Click the arrow icons to expand/collapse sections.
|
||||||
|
- **Overlays**: Windows are draggable. Close them with the `X` button.
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
Automation settings are adjustable in the sidebar. "Smart Harvest" can be toggled to prioritize long-term value over immediate harvesting.
|
||||||
|
|
||||||
|
## 🏗️ Development
|
||||||
|
|
||||||
|
### Project Structure
|
||||||
|
- `extension/manifest.json`: Extension configuration.
|
||||||
|
- `extension/content_loader.js`: Entry point that injects the bot.
|
||||||
|
- `extension/modules/`: Core logic modules.
|
||||||
|
- `main.js`: Central loop and event orchestration.
|
||||||
|
- `decision.js`: Logic for Smart Harvest valuations.
|
||||||
|
- `ui/`: UI components and style definitions.
|
||||||
|
- `ui_manager.js`: Manages the sidebar and overlays.
|
||||||
|
- `overlays/`: Individual overlay implementations (Pets, Inventory, etc.).
|
||||||
|
|
||||||
|
### Permissions
|
||||||
|
The extension requires:
|
||||||
|
- `activeTab` & `scripting`: To inject the bot into the game page.
|
||||||
|
- Host permissions for `magicgarden.gg`.
|
||||||
|
|||||||
3226
collected_data.json
3226
collected_data.json
File diff suppressed because one or more lines are too long
3226
collector.log
3226
collector.log
File diff suppressed because it is too large
Load Diff
@@ -38,11 +38,13 @@
|
|||||||
"modules/ui/components/harvest.js",
|
"modules/ui/components/harvest.js",
|
||||||
"modules/ui/components/diet.js",
|
"modules/ui/components/diet.js",
|
||||||
"modules/ui/components/visualizers.js",
|
"modules/ui/components/visualizers.js",
|
||||||
|
"modules/ui/components/settings.js",
|
||||||
"modules/ui/overlays/garden.js",
|
"modules/ui/overlays/garden.js",
|
||||||
"modules/ui/overlays/inventory.js",
|
"modules/ui/overlays/inventory.js",
|
||||||
"modules/ui/overlays/shop.js",
|
"modules/ui/overlays/shop.js",
|
||||||
"modules/ui/overlays/players.js",
|
"modules/ui/overlays/players.js",
|
||||||
"modules/ui/overlays/pets.js",
|
"modules/ui/overlays/pets.js",
|
||||||
|
"modules/ui/overlays/model_overlay.js",
|
||||||
"modules/ui/ui_manager.js",
|
"modules/ui/ui_manager.js",
|
||||||
"fullstate.json"
|
"fullstate.json"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -5,8 +5,13 @@ console.log("%c Magic Garden Bot Starting... ", "background: #222; color: #bada5
|
|||||||
const MB = window.MagicBot;
|
const MB = window.MagicBot;
|
||||||
|
|
||||||
// --- AUTOMATION STATE ---
|
// --- AUTOMATION STATE ---
|
||||||
|
MB.settings = {
|
||||||
|
debug: false
|
||||||
|
};
|
||||||
|
|
||||||
MB.automation = {
|
MB.automation = {
|
||||||
autoPlant: false,
|
autoPlant: false,
|
||||||
|
|
||||||
autoHarvest: false,
|
autoHarvest: false,
|
||||||
autoSell: false,
|
autoSell: false,
|
||||||
autoSell: false,
|
autoSell: false,
|
||||||
@@ -48,6 +53,11 @@ console.log("%c Magic Garden Bot Starting... ", "background: #222; color: #bada5
|
|||||||
|
|
||||||
updateWeatherTracker();
|
updateWeatherTracker();
|
||||||
|
|
||||||
|
// Update Weather Stats for UI
|
||||||
|
if (MB.automation.weatherTracker) {
|
||||||
|
MB.automation.weatherTracker.probabilities = getWorldEvents(MB.state);
|
||||||
|
}
|
||||||
|
|
||||||
// 1. Auto Harvest
|
// 1. Auto Harvest
|
||||||
if (MB.automation.autoHarvest && MB.state.garden && MB.state.garden.tileObjects) {
|
if (MB.automation.autoHarvest && MB.state.garden && MB.state.garden.tileObjects) {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
@@ -55,6 +65,16 @@ console.log("%c Magic Garden Bot Starting... ", "background: #222; color: #bada5
|
|||||||
const tile = MB.state.garden.tileObjects[slotId];
|
const tile = MB.state.garden.tileObjects[slotId];
|
||||||
if (tile && tile.slots) {
|
if (tile && tile.slots) {
|
||||||
tile.slots.forEach((s, idx) => {
|
tile.slots.forEach((s, idx) => {
|
||||||
|
// Debug Logging
|
||||||
|
if (MB.settings && MB.settings.debug) {
|
||||||
|
console.log(`[AutoHarvest] Checking Slot ${slotId} Index ${idx}:`, {
|
||||||
|
species: s.species,
|
||||||
|
ready: now >= s.endTime,
|
||||||
|
timeLeft: (s.endTime - now) / 1000,
|
||||||
|
mutations: s.mutations
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (now >= s.endTime) {
|
if (now >= s.endTime) {
|
||||||
const mutations = s.mutations || [];
|
const mutations = s.mutations || [];
|
||||||
|
|
||||||
@@ -65,7 +85,7 @@ console.log("%c Magic Garden Bot Starting... ", "background: #222; color: #bada5
|
|||||||
// Based on standard state structures, if checks fail, better safe than sorry.
|
// Based on standard state structures, if checks fail, better safe than sorry.
|
||||||
// Inspecting fullstate shows objectType property on the tile itself.
|
// Inspecting fullstate shows objectType property on the tile itself.
|
||||||
if (tile.objectType && tile.objectType.toLowerCase().includes('egg')) {
|
if (tile.objectType && tile.objectType.toLowerCase().includes('egg')) {
|
||||||
// console.log("Skipping Egg at slot", slotId);
|
if (MB.settings && MB.settings.debug) console.log(`[AutoHarvest] Skipping Egg at slot ${slotId}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,50 +100,54 @@ console.log("%c Magic Garden Bot Starting... ", "background: #222; color: #bada5
|
|||||||
if (isRainbow) {
|
if (isRainbow) {
|
||||||
// Harvest immediately!
|
// Harvest immediately!
|
||||||
// Fall through to harvest call.
|
// Fall through to harvest call.
|
||||||
|
if (MB.settings && MB.settings.debug) console.log(`[AutoHarvest] Harvesting Rainbow at ${slotId}`);
|
||||||
}
|
}
|
||||||
// 2. Gold Strategy: Wait for Frozen (x200 EV)
|
// 2. Gold Strategy: Wait for Frozen (x200 EV)
|
||||||
else if (isGold && !isFrozen) {
|
else if (isGold && !isFrozen) {
|
||||||
|
if (MB.settings && MB.settings.debug) console.log(`[AutoHarvest] Skipping Gold (Waiting for Frozen) at ${slotId}`);
|
||||||
return; // Skip
|
return; // Skip
|
||||||
}
|
}
|
||||||
// 3. Long Crop Strategy (> 10 mins): Wait for Wet (x2 EV)
|
// 3. Long Crop Strategy (> 10 mins): Wait for Wet (x2 EV)
|
||||||
return; // Skip
|
// Continues to Bellman Logic below...
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Bellman Step (Section 3) Smart Harvest
|
// 4. Bellman Step (Section 3) Smart Harvest
|
||||||
// Check if decision module is loaded
|
// Check if decision module is loaded
|
||||||
if (MB.Decision) {
|
if (MB.Decision) {
|
||||||
const worldEvents = getWorldEvents(MB.state);
|
const worldEvents = getWorldEvents(MB.state);
|
||||||
const cropState = {
|
const cropState = {
|
||||||
species: s.species || tile.species,
|
species: s.species || tile.species,
|
||||||
baseValue: s.baseValue || 1, // Need base value source?
|
baseValue: s.baseValue || 1, // Need base value source?
|
||||||
scale: s.scale || 1, // Can use targetScale or derive current scale?
|
scale: s.scale || 1, // Can use targetScale or derive current scale?
|
||||||
mutations: mutations
|
mutations: mutations
|
||||||
};
|
};
|
||||||
|
|
||||||
const events = {
|
const events = {
|
||||||
...worldEvents,
|
...worldEvents,
|
||||||
Time_Remaining_Hrs: (s.endTime - Date.now()) / 3600000
|
Time_Remaining_Hrs: (s.endTime - Date.now()) / 3600000
|
||||||
};
|
};
|
||||||
const logic = MB.Decision.shouldHarvest(cropState, events);
|
const logic = MB.Decision.shouldHarvest(cropState, events);
|
||||||
|
|
||||||
// Log logic occasionally?
|
if (MB.settings && MB.settings.debug) {
|
||||||
// console.log(`[SmartHarvest] Slot ${slotId}: ${logic.action}`, logic);
|
console.log(`[SmartHarvest] Slot ${slotId}: ${logic.action}`, logic);
|
||||||
|
}
|
||||||
|
|
||||||
if (logic.action === 'WAIT') {
|
if (logic.action === 'WAIT') {
|
||||||
return; // Skip harvest
|
return; // Skip harvest
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Don't spam: check if we just sent it?
|
// Don't spam: check if we just sent it?
|
||||||
// For simplicity, relying on server or next state update.
|
// For simplicity, relying on server or next state update.
|
||||||
// A simple dedupe could be added if needed.
|
// A simple dedupe could be added if needed.
|
||||||
MB.sendMsg({
|
MB.sendMsg({
|
||||||
type: 'HarvestCrop',
|
type: 'HarvestCrop',
|
||||||
slot: parseInt(slotId),
|
slot: parseInt(slotId),
|
||||||
slotsIndex: idx,
|
slotsIndex: idx,
|
||||||
scopePath: ["Room", "Quinoa"]
|
scopePath: ["Room", "Quinoa"]
|
||||||
});
|
});
|
||||||
|
if (MB.settings && MB.settings.debug) console.log(`[AutoHarvest] Sent HarvestCrop for ${slotId}`);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
35
extension/modules/ui/components/settings.js
Normal file
35
extension/modules/ui/components/settings.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { Styles, createElement } from '../ui_styles.js';
|
||||||
|
|
||||||
|
export const Settings = {
|
||||||
|
init(container) {
|
||||||
|
const section = createElement('div', Styles.section);
|
||||||
|
section.innerHTML = `<h4 style="${Styles.header}">⚙️ Settings</h4>`;
|
||||||
|
|
||||||
|
const content = createElement('div', Styles.content);
|
||||||
|
|
||||||
|
// Debug Toggle
|
||||||
|
const debugRow = createElement('div', Styles.row);
|
||||||
|
const debugLabel = createElement('span', '', {}, 'Debug Mode');
|
||||||
|
const debugToggle = createElement('input', '', { type: 'checkbox' });
|
||||||
|
|
||||||
|
// Sync with state
|
||||||
|
if (window.MagicBot && window.MagicBot.settings) {
|
||||||
|
debugToggle.checked = window.MagicBot.settings.debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
debugToggle.onchange = (e) => {
|
||||||
|
if (window.MagicBot) {
|
||||||
|
if (!window.MagicBot.settings) window.MagicBot.settings = {};
|
||||||
|
window.MagicBot.settings.debug = e.target.checked;
|
||||||
|
console.log(`[MagicBot] Debug Mode: ${e.target.checked ? 'ON' : 'OFF'}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
debugRow.appendChild(debugLabel);
|
||||||
|
debugRow.appendChild(debugToggle);
|
||||||
|
content.appendChild(debugRow);
|
||||||
|
|
||||||
|
section.appendChild(content);
|
||||||
|
container.appendChild(section);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -30,8 +30,8 @@ export const ModelOverlay = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const MB = window.MagicBot;
|
const MB = window.MagicBot;
|
||||||
if (!MB || !MB.state || !MB.state.inventory) {
|
if (!MB || !MB.state || !MB.state.garden || !MB.state.garden.tileObjects) {
|
||||||
container.innerHTML = '<div style="color:red">No State Data</div>';
|
container.innerHTML = '<div style="color:red">No Garden Data</div>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,55 +40,68 @@ export const ModelOverlay = {
|
|||||||
|
|
||||||
// Header Info
|
// Header Info
|
||||||
const header = createElement('div', 'padding: 5px; background: rgba(0,0,0,0.2); margin-bottom: 5px; border-radius: 4px;');
|
const header = createElement('div', 'padding: 5px; background: rgba(0,0,0,0.2); margin-bottom: 5px; border-radius: 4px;');
|
||||||
const rainProb = MB.weatherTracker ? (MB.weatherTracker.probabilities.rain * 100).toFixed(0) : '?';
|
const probs = MB.automation && MB.automation.weatherTracker ? MB.automation.weatherTracker.probabilities : null;
|
||||||
const frostProb = MB.weatherTracker ? (MB.weatherTracker.probabilities.frost * 100).toFixed(0) : '?';
|
|
||||||
|
const rainProb = probs ? (probs.P_Next_Rain_Thunderstorm * 100).toFixed(0) : '?';
|
||||||
|
const frostProb = probs ? (probs.P_Next_Frost * 100).toFixed(0) : '?';
|
||||||
|
const nextEventHrs = probs ? probs.Time_Until_Next_Event_Hrs.toFixed(2) : '?';
|
||||||
|
|
||||||
|
const tracker = MB.automation ? MB.automation.weatherTracker : null;
|
||||||
|
const currentEvent = tracker ? tracker.currentEvent : 'None';
|
||||||
|
|
||||||
header.innerHTML = `
|
header.innerHTML = `
|
||||||
<div><b>Weather Probabilities:</b> Rain: ${rainProb}% | Frost: ${frostProb}%</div>
|
<div><b>Weather:</b> ${currentEvent || 'Clear'}</div>
|
||||||
|
<div><b>Next Event:</b> ${nextEventHrs} hrs (Rain: ${rainProb}%, Frost: ${frostProb}%)</div>
|
||||||
<div><b>Smart Harvest:</b> ${MB.automation && MB.automation.smartHarvest ? '<span style="color:#bada55">ON</span>' : '<span style="color:#ff5252">OFF</span>'}</div>
|
<div><b>Smart Harvest:</b> ${MB.automation && MB.automation.smartHarvest ? '<span style="color:#bada55">ON</span>' : '<span style="color:#ff5252">OFF</span>'}</div>
|
||||||
`;
|
`;
|
||||||
list.appendChild(header);
|
list.appendChild(header);
|
||||||
|
|
||||||
const plots = MB.state.inventory.items.filter(i => i.itemType === 'Plot');
|
const garden = MB.state.garden;
|
||||||
if (plots.length === 0) {
|
const tiles = garden ? garden.tileObjects : {};
|
||||||
container.innerHTML += '<div style="padding:10px">No Plots Found</div>';
|
const activeCrops = [];
|
||||||
|
|
||||||
|
if (tiles) {
|
||||||
|
Object.keys(tiles).forEach(key => {
|
||||||
|
|
||||||
|
const tile = tiles[key];
|
||||||
|
if (tile.slots) {
|
||||||
|
tile.slots.forEach((slot, idx) => {
|
||||||
|
activeCrops.push({
|
||||||
|
id: key,
|
||||||
|
idx: idx,
|
||||||
|
name: slot.species || tile.species || 'Unknown',
|
||||||
|
endTime: slot.endTime,
|
||||||
|
startTime: slot.startTime,
|
||||||
|
mutations: slot.mutations || []
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeCrops.length === 0) {
|
||||||
|
container.innerHTML += '<div style="padding:10px">No Active Crops Found</div>';
|
||||||
|
container.appendChild(list);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
plots.forEach(plot => {
|
// Limit to first 50 to prevent lag if huge farm
|
||||||
if (!plot.properties) return;
|
activeCrops.slice(0, 50).forEach(crop => {
|
||||||
const crop = plot.properties.crop;
|
|
||||||
if (!crop) return; // Empty plot
|
|
||||||
|
|
||||||
const row = createElement('div', 'background: rgba(255,255,255,0.05); padding: 5px; border-radius: 4px; display: flex; flex-direction: column; gap: 2px;');
|
const row = createElement('div', 'background: rgba(255,255,255,0.05); padding: 5px; border-radius: 4px; display: flex; flex-direction: column; gap: 2px;');
|
||||||
|
|
||||||
// Basic Crop Info
|
const now = Date.now();
|
||||||
const name = crop.name;
|
const isReady = now >= crop.endTime;
|
||||||
const stage = crop.stage;
|
const timeLeft = Math.max(0, (crop.endTime - now) / 60000).toFixed(1); // Minutes
|
||||||
const totalStages = crop.stages;
|
|
||||||
const isReady = stage >= totalStages;
|
|
||||||
|
|
||||||
// Value Calculation (Simple approximation if actual vals not available)
|
|
||||||
const sellPrice = crop.sellPrice || 0;
|
|
||||||
const currentVal = isReady ? sellPrice : 0;
|
|
||||||
|
|
||||||
// Decision Logic Inspection
|
|
||||||
// We can't easily "spy" on the exact decision function result without modifying it to store state,
|
|
||||||
// but we can replicate the visual indicators.
|
|
||||||
|
|
||||||
let statusColor = '#aaa';
|
let statusColor = '#aaa';
|
||||||
let statusText = 'Growing';
|
let statusText = `${timeLeft} min`;
|
||||||
|
|
||||||
if (isReady) {
|
if (isReady) {
|
||||||
// Check mutation potential
|
|
||||||
const nextWeather = MB.weatherTracker ? MB.weatherTracker.nextEvent : 'Unknown';
|
|
||||||
const hasMutation = crop.mutations && crop.mutations.length > 0;
|
const hasMutation = crop.mutations && crop.mutations.length > 0;
|
||||||
|
|
||||||
if (hasMutation) {
|
if (hasMutation) {
|
||||||
statusText = 'Ready (Mutated!)';
|
statusText = `Ready (${crop.mutations.join(', ')})`;
|
||||||
statusColor = '#bada55'; // Green
|
statusColor = '#bada55';
|
||||||
} else {
|
} else {
|
||||||
// This is where we'd ideally show the "Wait vs Harvest" logic
|
|
||||||
// For now, let's show the current value and a theoretical max if waiting
|
|
||||||
statusText = 'Ready';
|
statusText = 'Ready';
|
||||||
statusColor = '#fff';
|
statusColor = '#fff';
|
||||||
}
|
}
|
||||||
@@ -96,18 +109,9 @@ export const ModelOverlay = {
|
|||||||
|
|
||||||
row.innerHTML = `
|
row.innerHTML = `
|
||||||
<div style="font-weight:bold; display:flex; justify-content:space-between;">
|
<div style="font-weight:bold; display:flex; justify-content:space-between;">
|
||||||
<span style="color:${Styles.colors.primary}">${name}</span>
|
<span style="color:${Styles.colors.primary}">${crop.name} <span style="font-size:9px; color:#555">#${crop.id}</span></span>
|
||||||
<span style="color:${statusColor}">${statusText}</span>
|
<span style="color:${statusColor}">${statusText}</span>
|
||||||
</div>
|
</div>
|
||||||
<div style="display:flex; justify-content:space-between; color:#888;">
|
|
||||||
<span>Stage: ${stage}/${totalStages}</span>
|
|
||||||
<span>Value: ${currentVal}</span>
|
|
||||||
</div>
|
|
||||||
<!--
|
|
||||||
<div style="font-size:9px; color:#666;">
|
|
||||||
EV: ??? | Boundary: ???
|
|
||||||
</div>
|
|
||||||
-->
|
|
||||||
`;
|
`;
|
||||||
list.appendChild(row);
|
list.appendChild(row);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -83,4 +83,4 @@ export const PetsOverlay = {
|
|||||||
container.appendChild(list);
|
container.appendChild(list);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
```
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import { Teleport } from './components/teleport.js';
|
|||||||
import { Automation } from './components/automation.js';
|
import { Automation } from './components/automation.js';
|
||||||
import { Harvest } from './components/harvest.js';
|
import { Harvest } from './components/harvest.js';
|
||||||
import { Diet } from './components/diet.js';
|
import { Diet } from './components/diet.js';
|
||||||
|
|
||||||
|
import { Settings } from './components/settings.js';
|
||||||
import { Visualizers } from './components/visualizers.js';
|
import { Visualizers } from './components/visualizers.js';
|
||||||
|
|
||||||
import { GardenOverlay } from './overlays/garden.js';
|
import { GardenOverlay } from './overlays/garden.js';
|
||||||
@@ -62,6 +64,8 @@ import { ModelOverlay } from './overlays/model_overlay.js'; // Added
|
|||||||
try { Automation.init(content); } catch (e) { console.error('Automation Init Failed', e); }
|
try { Automation.init(content); } catch (e) { console.error('Automation Init Failed', e); }
|
||||||
try { Harvest.init(content); } catch (e) { console.error('Harvest Init Failed', e); }
|
try { Harvest.init(content); } catch (e) { console.error('Harvest Init Failed', e); }
|
||||||
try { Diet.init(content); } catch (e) { console.error('Diet Init Failed', e); }
|
try { Diet.init(content); } catch (e) { console.error('Diet Init Failed', e); }
|
||||||
|
try { Diet.init(content); } catch (e) { console.error('Diet Init Failed', e); }
|
||||||
|
try { Settings.init(content); } catch (e) { console.error('Settings Init Failed', e); }
|
||||||
try { Visualizers.init(content); } catch (e) { console.error('Visualizers Init Failed', e); }
|
try { Visualizers.init(content); } catch (e) { console.error('Visualizers Init Failed', e); }
|
||||||
|
|
||||||
this.sidebar.appendChild(content);
|
this.sidebar.appendChild(content);
|
||||||
|
|||||||
Reference in New Issue
Block a user