diff --git a/apps/api/src/routes/game.ts b/apps/api/src/routes/game.ts index ef268b5..2ec1d77 100644 --- a/apps/api/src/routes/game.ts +++ b/apps/api/src/routes/game.ts @@ -10,7 +10,7 @@ import { DEFAULT_BOSSES } from "../data/bosses.js"; import { DEFAULT_EQUIPMENT } from "../data/equipment.js"; import { DEFAULT_EQUIPMENT_SETS } from "../data/equipmentSets.js"; import { DEFAULT_EXPLORATIONS } from "../data/explorations.js"; -import { INITIAL_EXPLORATION } from "../data/initialState.js"; +import { INITIAL_EXPLORATION, INITIAL_GAME_STATE } from "../data/initialState.js"; import { DAILY_REWARDS } from "../data/loginBonus.js"; import { DEFAULT_QUESTS } from "../data/quests.js"; import { authMiddleware } from "../middleware/auth.js"; @@ -364,7 +364,37 @@ gameRouter.get("/load", async (context) => { ]); if (!record) { - return context.json({ error: "No save found" }, 404); + // No save found — create a fresh state (handles nuked DB or first-time load race) + if (!playerRecord) { + return context.json({ error: "No player found" }, 404); + } + const freshState = INITIAL_GAME_STATE( + { + discordId: playerRecord.discordId, + username: playerRecord.username, + discriminator: playerRecord.discriminator, + avatar: playerRecord.avatar, + characterName: playerRecord.characterName, + createdAt: playerRecord.createdAt, + lastSavedAt: Date.now(), + totalGoldEarned: 0, + totalClicks: 0, + lifetimeGoldEarned: playerRecord.lifetimeGoldEarned, + lifetimeClicks: playerRecord.lifetimeClicks, + lifetimeBossesDefeated: playerRecord.lifetimeBossesDefeated, + lifetimeQuestsCompleted: playerRecord.lifetimeQuestsCompleted, + lifetimeAdventurersRecruited: playerRecord.lifetimeAdventurersRecruited, + lifetimeAchievementsUnlocked: playerRecord.lifetimeAchievementsUnlocked, + }, + playerRecord.characterName, + ); + const createdAt = Date.now(); + await prisma.gameState.create({ + data: { discordId, state: freshState as object, updatedAt: createdAt }, + }); + const secret = process.env.ANTI_CHEAT_SECRET; + const signature = secret ? computeHmac(JSON.stringify(freshState), secret) : undefined; + return context.json({ state: freshState, offlineGold: 0, offlineEssence: 0, offlineSeconds: 0, signature, loginBonus: null, loginStreak: playerRecord.loginStreak ?? 1 }); } const state = record.state as unknown as GameState;