import Database from 'better-sqlite3'; import path from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const db = new Database(path.join(__dirname, 'turtle_control.db')); // Initialize database schema export function initializeDatabase() { // Turtle homes table db.exec(` CREATE TABLE IF NOT EXISTS turtle_homes ( turtle_id INTEGER PRIMARY KEY, x INTEGER NOT NULL, y INTEGER NOT NULL, z INTEGER NOT NULL, updated_at INTEGER NOT NULL ) `); // Turtle configuration table db.exec(` CREATE TABLE IF NOT EXISTS turtle_config ( turtle_id INTEGER PRIMARY KEY, max_distance INTEGER DEFAULT 200, facing INTEGER DEFAULT 0, config_json TEXT, updated_at INTEGER NOT NULL ) `); // World blocks table db.exec(` CREATE TABLE IF NOT EXISTS world_blocks ( x INTEGER NOT NULL, y INTEGER NOT NULL, z INTEGER NOT NULL, block_name TEXT NOT NULL, metadata INTEGER DEFAULT 0, discovered_by INTEGER NOT NULL, discovered_at INTEGER NOT NULL, PRIMARY KEY (x, y, z) ) `); // Turtle paths table (for path recording) db.exec(` CREATE TABLE IF NOT EXISTS turtle_paths ( id INTEGER PRIMARY KEY AUTOINCREMENT, turtle_id INTEGER NOT NULL, path_name TEXT NOT NULL, path_data TEXT NOT NULL, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL ) `); // Task queue table (for multi-turtle coordination) db.exec(` CREATE TABLE IF NOT EXISTS task_queue ( id INTEGER PRIMARY KEY AUTOINCREMENT, task_type TEXT NOT NULL, task_data TEXT NOT NULL, assigned_turtle_id INTEGER, priority INTEGER DEFAULT 0, status TEXT DEFAULT 'pending', created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL ) `); // Mining areas table (for area visualization) db.exec(` CREATE TABLE IF NOT EXISTS mining_areas ( id INTEGER PRIMARY KEY AUTOINCREMENT, turtle_id INTEGER NOT NULL, min_x INTEGER NOT NULL, min_y INTEGER NOT NULL, min_z INTEGER NOT NULL, max_x INTEGER NOT NULL, max_y INTEGER NOT NULL, max_z INTEGER NOT NULL, status TEXT DEFAULT 'active', created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL ) `); // Create indexes for better performance db.exec(` CREATE INDEX IF NOT EXISTS idx_world_blocks_discovered ON world_blocks(discovered_by); `); db.exec(` CREATE INDEX IF NOT EXISTS idx_task_queue_status ON task_queue(status, priority DESC); `); console.log('✅ Database initialized'); } // Turtle Homes export function saveTurtleHome(turtleId, position) { const stmt = db.prepare(` INSERT OR REPLACE INTO turtle_homes (turtle_id, x, y, z, updated_at) VALUES (?, ?, ?, ?, ?) `); stmt.run(turtleId, position.x, position.y, position.z, Date.now()); } export function getTurtleHome(turtleId) { const stmt = db.prepare('SELECT x, y, z FROM turtle_homes WHERE turtle_id = ?'); return stmt.get(turtleId); } export function getAllTurtleHomes() { const stmt = db.prepare('SELECT turtle_id, x, y, z FROM turtle_homes'); return stmt.all(); } // Turtle Configuration export function saveTurtleConfig(turtleId, config) { const stmt = db.prepare(` INSERT OR REPLACE INTO turtle_config (turtle_id, max_distance, facing, config_json, updated_at) VALUES (?, ?, ?, ?, ?) `); stmt.run( turtleId, config.maxDistance || 200, config.facing || 0, JSON.stringify(config), Date.now() ); } export function getTurtleConfig(turtleId) { const stmt = db.prepare('SELECT * FROM turtle_config WHERE turtle_id = ?'); const row = stmt.get(turtleId); if (row && row.config_json) { return JSON.parse(row.config_json); } return null; } // World Blocks export function saveWorldBlock(x, y, z, blockName, metadata, discoveredBy) { const stmt = db.prepare(` INSERT OR REPLACE INTO world_blocks (x, y, z, block_name, metadata, discovered_by, discovered_at) VALUES (?, ?, ?, ?, ?, ?, ?) `); stmt.run(x, y, z, blockName, metadata || 0, discoveredBy, Date.now()); } export function getWorldBlocks(limit = 10000) { const stmt = db.prepare('SELECT * FROM world_blocks LIMIT ?'); return stmt.all(limit); } export function getWorldBlocksInArea(minX, minY, minZ, maxX, maxY, maxZ) { const stmt = db.prepare(` SELECT * FROM world_blocks WHERE x BETWEEN ? AND ? AND y BETWEEN ? AND ? AND z BETWEEN ? AND ? `); return stmt.all(minX, maxX, minY, maxY, minZ, maxZ); } export function clearOldBlocks(daysOld = 7) { const cutoffTime = Date.now() - (daysOld * 24 * 60 * 60 * 1000); const stmt = db.prepare('DELETE FROM world_blocks WHERE discovered_at < ?'); const result = stmt.run(cutoffTime); return result.changes; } // Turtle Paths export function savePath(turtleId, pathName, pathData) { const stmt = db.prepare(` INSERT INTO turtle_paths (turtle_id, path_name, path_data, created_at, updated_at) VALUES (?, ?, ?, ?, ?) `); const now = Date.now(); stmt.run(turtleId, pathName, JSON.stringify(pathData), now, now); } export function getPaths(turtleId) { const stmt = db.prepare('SELECT * FROM turtle_paths WHERE turtle_id = ? ORDER BY created_at DESC'); return stmt.all(turtleId).map(row => ({ ...row, path_data: JSON.parse(row.path_data) })); } export function deletePath(pathId) { const stmt = db.prepare('DELETE FROM turtle_paths WHERE id = ?'); return stmt.run(pathId); } // Task Queue export function createTask(taskType, taskData, priority = 0) { const stmt = db.prepare(` INSERT INTO task_queue (task_type, task_data, priority, status, created_at, updated_at) VALUES (?, ?, ?, 'pending', ?, ?) `); const now = Date.now(); const result = stmt.run(taskType, JSON.stringify(taskData), priority, now, now); return result.lastInsertRowid; } export function getNextTask() { const stmt = db.prepare(` SELECT * FROM task_queue WHERE status = 'pending' ORDER BY priority DESC, created_at ASC LIMIT 1 `); const row = stmt.get(); if (row) { return { ...row, task_data: JSON.parse(row.task_data) }; } return null; } export function assignTask(taskId, turtleId) { const stmt = db.prepare(` UPDATE task_queue SET assigned_turtle_id = ?, status = 'assigned', updated_at = ? WHERE id = ? `); stmt.run(turtleId, Date.now(), taskId); } export function completeTask(taskId) { const stmt = db.prepare(` UPDATE task_queue SET status = 'completed', updated_at = ? WHERE id = ? `); stmt.run(Date.now(), taskId); } export function getAllTasks() { const stmt = db.prepare('SELECT * FROM task_queue ORDER BY priority DESC, created_at DESC'); return stmt.all().map(row => ({ ...row, task_data: JSON.parse(row.task_data) })); } // Mining Areas export function saveMiningArea(turtleId, bounds) { const stmt = db.prepare(` INSERT INTO mining_areas (turtle_id, min_x, min_y, min_z, max_x, max_y, max_z, status, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, 'active', ?, ?) `); const now = Date.now(); stmt.run( turtleId, bounds.minX, bounds.minY, bounds.minZ, bounds.maxX, bounds.maxY, bounds.maxZ, now, now ); } export function getMiningAreas() { const stmt = db.prepare('SELECT * FROM mining_areas WHERE status = \'active\''); return stmt.all(); } export function closeMiningArea(areaId) { const stmt = db.prepare('UPDATE mining_areas SET status = \'closed\', updated_at = ? WHERE id = ?'); stmt.run(Date.now(), areaId); } // Cleanup function export function closeDatabase() { db.close(); } // Export database instance for custom queries if needed export { db };