mine update

This commit is contained in:
Cay 2026-03-16 12:50:00 +00:00
parent d72fcb2fe7
commit 56cfcb2de1

View File

@ -1,50 +1,86 @@
const express = require("express"); const express = require("express");
const router = express.Router(); const router = require("express").Router();
const db = require("../database/database"); const db = require("../database/database");
const auth = require("../middleware/auth"); 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 GET /api/mine/:buildingId/status
Liefert Level, verfügbare Ressourcen
und Countdown bis zum nächsten Zyklus
*/ */
router.get("/:buildingId/status", auth, async (req, res) => { router.get("/:buildingId/status", auth, async (req, res) => {
const userId = req.session.user.id; const userId = req.session.user.id;
const buildingId = req.params.buildingId; const buildingId = req.params.buildingId;
try { try {
const [rows] = await db.query( // user_building holen
` const [[userBuilding]] = await db.query(
SELECT "SELECT id, level FROM user_buildings WHERE user_id = ? AND building_id = ?",
ub.id AS user_building_id,
ub.level,
bp.resource,
bp.amount,
bp.cycle_seconds,
COALESCE(bct.last_collected, NOW()) AS last_collected
FROM user_buildings ub
JOIN building_production bp
ON bp.building_id = ub.building_id
AND bp.level = ub.level
LEFT JOIN building_collect_timer bct
ON bct.user_building_id = ub.id
WHERE ub.user_id = ?
AND ub.building_id = ?
`,
[userId, buildingId] [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) { if (!rows.length) {
return res.status(404).json({ error: "Gebäude nicht gefunden" }); return res.status(404).json({ error: "Gebaeude nicht gefunden" });
} }
const { cycle_seconds, last_collected, level } = rows[0]; const { cycle_seconds, last_collected, level } = rows[0];
const elapsed = Math.floor( const elapsed = Math.floor((Date.now() - new Date(last_collected).getTime()) / 1000);
(Date.now() - new Date(last_collected).getTime()) / 1000 const cycles = Math.floor(elapsed / cycle_seconds);
); const nextIn = cycle_seconds - (elapsed % cycle_seconds);
const cycles = Math.floor(elapsed / cycle_seconds);
const nextIn = cycle_seconds - (elapsed % cycle_seconds);
const available = rows.map((r) => ({ const available = rows.map((r) => ({
resource: r.resource, resource: r.resource,
@ -59,6 +95,7 @@ router.get("/:buildingId/status", auth, async (req, res) => {
last_collected, last_collected,
next_cycle_in_seconds: nextIn, next_cycle_in_seconds: nextIn,
}); });
} catch (err) { } catch (err) {
console.error(err); console.error(err);
res.status(500).json({ error: "DB Fehler" }); res.status(500).json({ error: "DB Fehler" });
@ -67,44 +104,35 @@ router.get("/:buildingId/status", auth, async (req, res) => {
/* /*
POST /api/mine/:buildingId/collect POST /api/mine/:buildingId/collect
Schreibt Ressourcen gut, setzt Timer Ressourcen gutschreiben + Timer reset
*/ */
router.post("/:buildingId/collect", auth, async (req, res) => { router.post("/:buildingId/collect", auth, async (req, res) => {
const userId = req.session.user.id; const userId = req.session.user.id;
const buildingId = req.params.buildingId; const buildingId = req.params.buildingId;
try { try {
const [rows] = await db.query( // user_building holen
` const [[userBuilding]] = await db.query(
SELECT "SELECT id FROM user_buildings WHERE user_id = ? AND building_id = ?",
ub.id AS user_building_id,
ub.level,
bp.resource,
bp.amount,
bp.cycle_seconds,
COALESCE(bct.last_collected, NOW()) AS last_collected
FROM user_buildings ub
JOIN building_production bp
ON bp.building_id = ub.building_id
AND bp.level = ub.level
LEFT JOIN building_collect_timer bct
ON bct.user_building_id = ub.id
WHERE ub.user_id = ?
AND ub.building_id = ?
`,
[userId, buildingId] [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) { if (!rows.length) {
return res.status(404).json({ error: "Gebäude nicht gefunden" }); return res.status(404).json({ error: "Gebaeude nicht gefunden" });
} }
const { user_building_id, cycle_seconds, last_collected } = rows[0]; const { user_building_id, cycle_seconds, last_collected } = rows[0];
const elapsed = Math.floor( const elapsed = Math.floor((Date.now() - new Date(last_collected).getTime()) / 1000);
(Date.now() - new Date(last_collected).getTime()) / 1000 const cycles = Math.floor(elapsed / cycle_seconds);
);
const cycles = Math.floor(elapsed / cycle_seconds);
if (cycles < 1) { if (cycles < 1) {
const waitSeconds = cycle_seconds - elapsed; const waitSeconds = cycle_seconds - elapsed;
@ -121,27 +149,20 @@ router.post("/:buildingId/collect", auth, async (req, res) => {
for (const row of rows) { for (const row of rows) {
const toAdd = row.amount * cycles; const toAdd = row.amount * cycles;
await db.query( await db.query(
` "INSERT INTO account_currency (account_id, `" + row.resource + "`) VALUES (?, ?) ON DUPLICATE KEY UPDATE `" + row.resource + "` = `" + row.resource + "` + ?",
INSERT INTO account_currency (account_id, \`${row.resource}\`)
VALUES (?, ?)
ON DUPLICATE KEY UPDATE \`${row.resource}\` = \`${row.resource}\` + ?
`,
[userId, toAdd, toAdd] [userId, toAdd, toAdd]
); );
} }
// Timer vorsetzen — Rest-Sekunden bleiben erhalten, kein Verlust // Timer zuruecksetzen: last_collected um genau die abgeschlossenen
// Zyklen vorruecken Restsekunden bleiben erhalten, kein Verlust
const newLastCollected = new Date( const newLastCollected = new Date(
new Date(last_collected).getTime() + cycles * cycle_seconds * 1000 new Date(last_collected).getTime() + cycles * cycle_seconds * 1000
); );
await db.query( await db.query(
` "UPDATE building_collect_timer SET last_collected = ? WHERE user_building_id = ?",
INSERT INTO building_collect_timer (user_building_id, last_collected) [newLastCollected, user_building_id]
VALUES (?, ?)
ON DUPLICATE KEY UPDATE last_collected = ?
`,
[user_building_id, newLastCollected, newLastCollected]
); );
const collected = rows.map((r) => ({ const collected = rows.map((r) => ({
@ -149,15 +170,12 @@ router.post("/:buildingId/collect", auth, async (req, res) => {
amount: r.amount * cycles, amount: r.amount * cycles,
})); }));
res.json({ res.json({ success: true, cycles, collected });
success: true,
cycles,
collected,
});
} catch (err) { } catch (err) {
console.error(err); console.error(err);
res.status(500).json({ error: "DB Fehler" }); res.status(500).json({ error: "DB Fehler" });
} }
}); });
module.exports = router; module.exports = router;