dok/routes/mine.js
2026-03-29 10:45:47 +01:00

204 lines
6.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const express = require("express");
const router = require("express").Router();
const db = require("../database/database");
const auth = require("../middleware/auth");
/* ─────────────────────────────────────────
HELPER: Timer sicherstellen
Legt beim allerersten Aufruf einen
Eintrag an laeuft dann fuer immer durch.
Wird NUR durch collect() zurueckgesetzt.
───────────────────────────────────────── */
async function ensureTimer(userBuildingId) {
const [[existing]] = await db.query(
"SELECT last_collected FROM building_collect_timer WHERE user_building_id = ?",
[userBuildingId],
);
if (!existing) {
await db.query(
"INSERT INTO building_collect_timer (user_building_id, last_collected) VALUES (?, NOW())",
[userBuildingId],
);
}
}
/* ─────────────────────────────────────────
HELPER: Produktionsdaten laden
Gibt immer last_collected aus der DB
───────────────────────────────────────── */
async function loadMineData(userId, buildingId) {
const [rows] = await db.query(
`
SELECT
ub.id AS user_building_id,
ub.level,
bp.resource,
bp.amount,
bp.cycle_seconds,
bct.last_collected
FROM user_buildings ub
JOIN building_production bp
ON bp.building_id = ub.building_id
AND bp.level = ub.level
JOIN building_collect_timer bct
ON bct.user_building_id = ub.id
WHERE ub.user_id = ?
AND ub.building_id = ?
`,
[userId, buildingId],
);
return rows;
}
/* ─────────────────────────────────────────
GET /api/mine/:buildingId/status
───────────────────────────────────────── */
router.get("/:buildingId/status", auth, async (req, res) => {
const userId = req.session.user.id;
const buildingId = req.params.buildingId;
try {
// user_building holen
const [[userBuilding]] = await db.query(
"SELECT id, level FROM user_buildings WHERE user_id = ? AND building_id = ?",
[userId, buildingId],
);
if (!userBuilding) {
return res.status(404).json({ error: "Gebaeude nicht gefunden" });
}
// Timer einmalig starten falls noch nie geoeffnet
await ensureTimer(userBuilding.id);
const rows = await loadMineData(userId, buildingId);
if (!rows.length) {
return res.status(404).json({ error: "Gebaeude nicht gefunden" });
}
const { cycle_seconds, last_collected, level } = rows[0];
const elapsed = Math.floor(
(Date.now() - new Date(last_collected).getTime()) / 1000,
);
const cycles = Math.floor(elapsed / cycle_seconds);
const nextIn = cycle_seconds - (elapsed % cycle_seconds);
const available = rows.map((r) => ({
resource: r.resource,
amount: r.amount * cycles,
}));
const production = rows.map((r) => ({
resource: r.resource,
amount: r.amount,
}));
res.json({
level,
cycles,
ready: cycles > 0,
available,
production,
last_collected,
next_cycle_in_seconds: nextIn,
cycle_seconds,
});
} catch (err) {
console.error(err);
res.status(500).json({ error: "DB Fehler" });
}
});
/* ─────────────────────────────────────────
POST /api/mine/:buildingId/collect
Ressourcen gutschreiben + Timer reset
───────────────────────────────────────── */
router.post("/:buildingId/collect", auth, async (req, res) => {
const userId = req.session.user.id;
const buildingId = req.params.buildingId;
try {
// user_building holen
const [[userBuilding]] = await db.query(
"SELECT id FROM user_buildings WHERE user_id = ? AND building_id = ?",
[userId, buildingId],
);
if (!userBuilding) {
return res.status(404).json({ error: "Gebaeude nicht gefunden" });
}
// Timer sicherstellen (Fallback falls Status nie aufgerufen wurde)
await ensureTimer(userBuilding.id);
const rows = await loadMineData(userId, buildingId);
if (!rows.length) {
return res.status(404).json({ error: "Gebaeude nicht gefunden" });
}
const { user_building_id, cycle_seconds, last_collected } = rows[0];
const elapsed = Math.floor(
(Date.now() - new Date(last_collected).getTime()) / 1000,
);
const cycles = Math.floor(elapsed / cycle_seconds);
if (cycles < 1) {
const waitSeconds = cycle_seconds - elapsed;
const minutes = Math.floor(waitSeconds / 60);
const seconds = waitSeconds % 60;
return res.json({
error: "Noch nichts bereit",
ready_in_seconds: waitSeconds,
ready_in_display: `${minutes}m ${seconds}s`,
});
}
// Jede Ressource einzeln gutschreiben
const allowedResources = [
"gold",
"silver",
"copper",
"iron",
"wood",
"stone",
"gems",
];
for (const row of rows) {
if (!allowedResources.includes(row.resource)) continue;
const toAdd = row.amount * cycles;
await db.query(
`UPDATE account_currency SET \`${row.resource}\` = \`${row.resource}\` + ? WHERE account_id = ?`,
[toAdd, userId],
);
}
// Timer zuruecksetzen: last_collected um genau die abgeschlossenen
// Zyklen vorruecken Restsekunden bleiben erhalten, kein Verlust
const newLastCollected = new Date(
new Date(last_collected).getTime() + cycles * cycle_seconds * 1000,
);
await db.query(
"UPDATE building_collect_timer SET last_collected = ? WHERE user_building_id = ?",
[newLastCollected, user_building_id],
);
const collected = rows.map((r) => ({
resource: r.resource,
amount: r.amount * cycles,
}));
res.json({ success: true, cycles, collected });
} catch (err) {
console.error(err);
res.status(500).json({ error: "DB Fehler" });
}
});
module.exports = router;