feat: add world map functionality and admin map management

- Added world map page with interactive marker display
- Implemented admin map management for marker CRUD operations
- Added map layers and markers seed data to database
- Integrated new routes for map functionality
- Updated database configuration for production environment
- Added documentation page route
- Enhanced package.json with required dependencies for map features
This commit is contained in:
Lars Behrends
2026-01-02 05:08:07 +01:00
parent ea2b803534
commit 065a6e657d
152 changed files with 5024 additions and 35 deletions

View File

@@ -2,9 +2,9 @@ const mysql = require('mysql2');
// Database Config from Env
const dbConfig = {
host: process.env.DB_HOST || 'localhost',
user: process.env.DB_USER || 'root',
password: process.env.DB_PASS || '',
host: process.env.DB_HOST || '192.168.1.102',
user: process.env.DB_USER || 'obsidian_user',
password: process.env.DB_PASS || 'obsidian_pass',
database: process.env.DB_NAME || 'obsidian_db',
waitForConnections: true,
connectionLimit: 10,
@@ -90,6 +90,41 @@ const SEED_PROJECTS = [
}
];
const SEED_MAP_LAYERS = [
{ id: 'layer-1', name: 'Städte', description: 'Alle Städte und Siedlungen', order_index: 1 },
{ id: 'layer-2', name: 'Points of Interest', description: 'Besondere Orte und Sehenswürdigkeiten', order_index: 2 },
{ id: 'layer-3', name: 'Spieler-Häuser', description: 'Spieler-Wohnsitze und Häuser', order_index: 3 }
];
const SEED_MAP_MARKERS = [
{
id: 'marker-1',
name: 'Provisorium Null',
type: 'city',
x_coord: -2560,
z_coord: 512,
description: 'Die erste Siedlung der neuen Ära',
linked_entity_type: 'organization',
linked_entity_id: 'org-3',
icon_type: 'city',
color: '#2563eb',
is_public: 1
},
{
id: 'marker-2',
name: 'Sakura',
type: 'city',
x_coord: 1536,
z_coord: -512,
description: 'Eine dunkle, biolumineszente Hafenstadt',
linked_entity_type: 'organization',
linked_entity_id: 'org-4',
icon_type: 'city',
color: '#dc2626',
is_public: 1
}
];
// Retry connection logic for Docker
function init() {
const tryConnect = () => {
@@ -169,6 +204,34 @@ function setupTables() {
logoImageId VARCHAR(50),
shopCatalog JSON,
gallery JSON
)`,
`CREATE TABLE IF NOT EXISTS map_markers (
id VARCHAR(50) PRIMARY KEY,
name VARCHAR(255),
type VARCHAR(50), -- 'city', 'poi', 'player_home', 'waypoint'
x_coord INTEGER,
z_coord INTEGER,
description TEXT,
linked_entity_type VARCHAR(50), -- 'city', 'organization', 'player'
linked_entity_id VARCHAR(50),
icon_type VARCHAR(50), -- 'city', 'house', 'chest', 'flag', etc.
color VARCHAR(7), -- hex color code
is_public TINYINT DEFAULT 1,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)`,
`CREATE TABLE IF NOT EXISTS map_layers (
id VARCHAR(50) PRIMARY KEY,
name VARCHAR(255),
description TEXT,
is_active TINYINT DEFAULT 1,
order_index INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)`,
`CREATE TABLE IF NOT EXISTS map_metadata (
key VARCHAR(100) PRIMARY KEY,
value TEXT,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
)`
];
@@ -212,6 +275,28 @@ function seedData() {
});
}
});
// Seed map layers
pool.query("SELECT COUNT(*) as count FROM map_layers", (err, rows) => {
if (!err && rows[0].count === 0) {
console.log("Seeding Map Layers...");
SEED_MAP_LAYERS.forEach(layer => {
pool.query("INSERT INTO map_layers VALUES (?, ?, ?, ?, ?, ?)",
[layer.id, layer.name, layer.description, 1, layer.order_index, new Date().toISOString().slice(0, 19).replace('T', ' ')]);
});
}
});
// Seed map markers
pool.query("SELECT COUNT(*) as count FROM map_markers", (err, rows) => {
if (!err && rows[0].count === 0) {
console.log("Seeding Map Markers...");
SEED_MAP_MARKERS.forEach(marker => {
pool.query("INSERT INTO map_markers (id, name, type, x_coord, z_coord, description, linked_entity_type, linked_entity_id, icon_type, color, is_public) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
[marker.id, marker.name, marker.type, marker.x_coord, marker.z_coord, marker.description, marker.linked_entity_type, marker.linked_entity_id, marker.icon_type, marker.color, marker.is_public]);
});
}
});
}
// Wrapper to mimic SQLite API for easy migration in server.js