feat(sprint1-step3b): backend save system + anti-cheat + données rattrapées
- game_saves table + migration 002 (JSON state, anti-cheat metadata) - saveControllers.js : load/save avec validation delta ressources (750k/s × 1.1) - GameSaveManager : upsert MySQL ON DUPLICATE KEY UPDATE - useSaveSync hook : auto-save 30s + keepalive beforeunload + guest fallback - save-validation.test.ts : 8 tests anti-cheat - economy.ts : arbre d'évolution 5 nœuds + prestige ADN (rattrapage step 2) - economy.test.ts : +40 tests (évolution tree, multipliers, start bonus) - GDD + SPRINT1.md : docs sprint complètes - Rethème data : shop.json, Achievements.json, Cookie, Legal (rattrapage step 1)
This commit is contained in:
43
Backend/src/models/GameSaveManager.js
Normal file
43
Backend/src/models/GameSaveManager.js
Normal file
@@ -0,0 +1,43 @@
|
||||
const AbstractManager = require("./AbstractManager");
|
||||
|
||||
class GameSaveManager extends AbstractManager {
|
||||
constructor() {
|
||||
super({ table: "game_saves" });
|
||||
}
|
||||
|
||||
async getByUserId(userId) {
|
||||
const [rows] = await this.database.query(
|
||||
`SELECT * FROM ${this.table} WHERE user_id = ?`,
|
||||
[userId]
|
||||
);
|
||||
return rows[0] ?? null;
|
||||
}
|
||||
|
||||
async upsert(userId, gameState, metadata) {
|
||||
const { lifetimeTadpoles, prestigeCount, playTimeSeconds } = metadata;
|
||||
const gameStateJson = JSON.stringify(gameState);
|
||||
|
||||
const [result] = await this.database.query(
|
||||
`INSERT INTO ${this.table} (user_id, game_state, lifetime_tadpoles, prestige_count, play_time_seconds)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
game_state = VALUES(game_state),
|
||||
lifetime_tadpoles = VALUES(lifetime_tadpoles),
|
||||
prestige_count = VALUES(prestige_count),
|
||||
play_time_seconds = VALUES(play_time_seconds),
|
||||
last_save = CURRENT_TIMESTAMP`,
|
||||
[userId, gameStateJson, lifetimeTadpoles, prestigeCount, playTimeSeconds]
|
||||
);
|
||||
|
||||
return result.affectedRows;
|
||||
}
|
||||
|
||||
async delete(userId) {
|
||||
await this.database.query(
|
||||
`DELETE FROM ${this.table} WHERE user_id = ?`,
|
||||
[userId]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GameSaveManager;
|
||||
Reference in New Issue
Block a user