feat: Implement database integration for turtle homes, world blocks, paths, tasks, and mining areas

This commit is contained in:
MayaTheShy
2026-02-19 22:40:16 -05:00
parent a68db21f9c
commit a3fe5c7471

View File

@@ -2,6 +2,7 @@ import express from 'express';
import { WebSocketServer } from 'ws';
import cors from 'cors';
import { createServer } from 'http';
import * as db from './database.js';
const app = express();
const PORT = 3001;
@@ -10,6 +11,16 @@ const WS_PORT = 3002;
app.use(cors());
app.use(express.json());
// Initialize database
db.initializeDatabase();
// Load persisted data from database
console.log('📂 Loading persisted data from database...');
const savedHomes = db.getAllTurtleHomes();
const savedBlocks = db.getWorldBlocks();
console.log(` Loaded ${savedHomes.length} turtle homes`);
console.log(` Loaded ${savedBlocks.length} world blocks`);
// Store connected web clients and turtle data
const webClients = new Set();
const turtleData = new Map(); // turtleID -> turtle state
@@ -17,6 +28,22 @@ const worldBlocks = new Map(); // "x,y,z" -> {name, metadata, discoveredBy, time
const turtleHomes = new Map(); // turtleID -> {x, y, z} home position
const turtleConfig = new Map(); // turtleID -> {maxDistance, facing, etc}
// Load saved homes into memory
for (const home of savedHomes) {
turtleHomes.set(home.turtle_id, { x: home.x, y: home.y, z: home.z });
}
// Load saved blocks into memory
for (const block of savedBlocks) {
const key = `${block.x},${block.y},${block.z}`;
worldBlocks.set(key, {
name: block.block_name,
metadata: block.metadata,
discoveredBy: block.discovered_by,
timestamp: block.discovered_at
});
}
// Timeout for considering turtles offline (30 seconds)
const TURTLE_TIMEOUT = 30000;
@@ -62,6 +89,9 @@ function storeBlock(x, y, z, blockData, turtleID) {
discoveredBy: turtleID,
timestamp: Date.now()
});
// Persist to database
db.saveWorldBlock(x, y, z, blockData.name, blockData.metadata, turtleID);
}
// Helper to calculate block position based on turtle position and facing
@@ -250,13 +280,16 @@ app.post('/api/turtle/:id/home', (req, res) => {
const turtleID = parseInt(req.params.id);
const { position } = req.body;
if (!position || !position.x || !position.y || !position.z) {
if (!position || position.x === undefined || position.y === undefined || position.z === undefined) {
return res.status(400).json({ error: 'Invalid position' });
}
turtleHomes.set(turtleID, position);
console.log(`📍 Set home for turtle ${turtleID}:`, position);
// Persist to database
db.saveTurtleHome(turtleID, position);
// Update turtle data
if (turtleData.has(turtleID)) {
const turtle = turtleData.get(turtleID);
@@ -350,6 +383,192 @@ setInterval(() => {
}
}, 10000); // Check every 10 seconds
// ========== PATH RECORDING ENDPOINTS ==========
// Save a recorded path
app.post('/api/paths', (req, res) => {
try {
const { turtleId, pathName, pathData } = req.body;
db.savePath(turtleId, pathName, pathData);
res.json({ success: true, message: 'Path saved' });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Get all paths for a turtle
app.get('/api/paths/:turtleId', (req, res) => {
try {
const turtleId = parseInt(req.params.turtleId);
const paths = db.getPaths(turtleId);
res.json({ paths });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Delete a path
app.delete('/api/paths/:pathId', (req, res) => {
try {
const pathId = parseInt(req.params.pathId);
db.deletePath(pathId);
res.json({ success: true });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// ========== TASK QUEUE ENDPOINTS ==========
// Create a new task
app.post('/api/tasks', (req, res) => {
try {
const { taskType, taskData, priority } = req.body;
const taskId = db.createTask(taskType, taskData, priority || 0);
broadcastToClients({
type: 'task_created',
taskId,
taskType,
priority
});
res.json({ success: true, taskId });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Get all tasks
app.get('/api/tasks', (req, res) => {
try {
const tasks = db.getAllTasks();
res.json({ tasks });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Get next available task
app.get('/api/tasks/next', (req, res) => {
try {
const task = db.getNextTask();
res.json({ task });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Assign task to turtle
app.post('/api/tasks/:taskId/assign', (req, res) => {
try {
const taskId = parseInt(req.params.taskId);
const { turtleId } = req.body;
db.assignTask(taskId, turtleId);
broadcastToClients({
type: 'task_assigned',
taskId,
turtleId
});
res.json({ success: true });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Complete a task
app.post('/api/tasks/:taskId/complete', (req, res) => {
try {
const taskId = parseInt(req.params.taskId);
db.completeTask(taskId);
broadcastToClients({
type: 'task_completed',
taskId
});
res.json({ success: true });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// ========== MINING AREA ENDPOINTS ==========
// Save a mining area claim
app.post('/api/mining-areas', (req, res) => {
try {
const { turtleId, bounds } = req.body;
db.saveMiningArea(turtleId, bounds);
const areas = db.getMiningAreas();
broadcastToClients({
type: 'mining_areas_updated',
areas
});
res.json({ success: true });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Get all active mining areas
app.get('/api/mining-areas', (req, res) => {
try {
const areas = db.getMiningAreas();
res.json({ areas });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Close a mining area
app.post('/api/mining-areas/:areaId/close', (req, res) => {
try {
const areaId = parseInt(req.params.areaId);
db.closeMiningArea(areaId);
const areas = db.getMiningAreas();
broadcastToClients({
type: 'mining_areas_updated',
areas
});
res.json({ success: true });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// ========== STATISTICS ENDPOINTS ==========
// Get server statistics
app.get('/api/stats', (req, res) => {
try {
const stats = {
activeTurtles: turtleData.size,
totalBlocks: worldBlocks.size,
savedHomes: turtleHomes.size,
connectedClients: webClients.size,
tasks: db.getAllTasks().length,
miningAreas: db.getMiningAreas().length
};
res.json(stats);
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Graceful shutdown
process.on('SIGINT', () => {
console.log('\n🛑 Shutting down server...');
db.closeDatabase();
process.exit(0);
});
server.listen(PORT, () => {
console.log(`✅ Server ready!`);
console.log(`\nConfigured turtles to send updates to:`);