fix: adventurer unlocks not applied by force-unlock tool #93

Merged
naomi merged 3 commits from fix/force-unlock-adventurers into main 2026-03-20 10:28:18 -07:00
4 changed files with 61 additions and 4 deletions
Showing only changes of commit 715ccd3fc7 - Show all commits
+48 -3
View File
@@ -257,6 +257,37 @@ const applyBossUnlocks = (state: GameState): number => {
return count;
};
/**
* Unlocks any adventurer tiers that were granted as rewards for completed quests
* but are still locked in the player's state.
* @param state - The player's current game state (mutated directly).
* @returns The number of adventurer tiers that were unlocked.
*/
const applyAdventurerUnlocks = (state: GameState): number => {
let count = 0;
const earnedAdventurerIds = new Set<string>();
for (const quest of state.quests) {
if (quest.status !== "completed") {
continue;
}
for (const reward of quest.rewards) {
if (reward.type === "adventurer" && reward.targetId !== undefined) {
earnedAdventurerIds.add(reward.targetId);
}
}
}
for (const adventurer of state.adventurers) {
if (!adventurer.unlocked && earnedAdventurerIds.has(adventurer.id)) {
adventurer.unlocked = true;
count = count + 1;
}
}
return count;
};
/**
* Makes available any exploration areas whose parent zone is now unlocked.
* @param state - The player's current game state (mutated directly).
@@ -301,6 +332,7 @@ const applyExplorationUnlocks = (state: GameState): number => {
const applyForceUnlocks = (
state: GameState,
): {
adventurersUnlocked: number;
bossesUnlocked: number;
explorationUnlocked: number;
questsUnlocked: number;
@@ -310,7 +342,14 @@ const applyForceUnlocks = (
const questsUnlocked = applyQuestUnlocks(state);
const bossesUnlocked = applyBossUnlocks(state);
const explorationUnlocked = applyExplorationUnlocks(state);
return { bossesUnlocked, explorationUnlocked, questsUnlocked, zonesUnlocked };
const adventurersUnlocked = applyAdventurerUnlocks(state);
return {
adventurersUnlocked,
bossesUnlocked,
explorationUnlocked,
questsUnlocked,
zonesUnlocked,
};
};
const debugRouter = new Hono<HonoEnvironment>();
@@ -330,8 +369,13 @@ debugRouter.post("/force-unlocks", async(context) => {
/* eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Prisma stores state as JSON object */
const state = gameStateRecord.state as unknown as GameState;
const { bossesUnlocked, explorationUnlocked, questsUnlocked, zonesUnlocked }
= applyForceUnlocks(state);
const {
adventurersUnlocked,
bossesUnlocked,
explorationUnlocked,
questsUnlocked,
zonesUnlocked,
} = applyForceUnlocks(state);
const updatedAt = Date.now();
await prisma.gameState.update({
@@ -347,6 +391,7 @@ debugRouter.post("/force-unlocks", async(context) => {
: computeHmac(JSON.stringify(state), secret);
return context.json({
adventurersUnlocked,
bossesUnlocked,
explorationUnlocked,
questsUnlocked,
+5 -1
View File
@@ -51,11 +51,15 @@ const DebugPanel = (): JSX.Element => {
if (result.explorationUnlocked > 0) {
parts.push(`${String(result.explorationUnlocked)} exploration area(s)`);
}
if (result.adventurersUnlocked > 0) {
parts.push(`${String(result.adventurersUnlocked)} adventurer tier(s)`);
}
const total
= result.zonesUnlocked
+ result.questsUnlocked
+ result.bossesUnlocked
+ result.explorationUnlocked;
+ result.explorationUnlocked
+ result.adventurersUnlocked;
const message
= parts.length === 0
? "Everything looks correct — no missing unlocks were found."
+3
View File
@@ -558,6 +558,7 @@ interface GameContextValue {
* @returns Counts of what was corrected.
*/
forceUnlocks: ()=> Promise<{
adventurersUnlocked: number;
bossesUnlocked: number;
explorationUnlocked: number;
questsUnlocked: number;
@@ -2104,6 +2105,7 @@ export const GameProvider = ({
localStorage.setItem("elysium_save_signature", data.signature);
}
return {
adventurersUnlocked: data.adventurersUnlocked,
bossesUnlocked: data.bossesUnlocked,
explorationUnlocked: data.explorationUnlocked,
questsUnlocked: data.questsUnlocked,
@@ -2116,6 +2118,7 @@ export const GameProvider = ({
: "Failed to force unlocks",
);
return {
adventurersUnlocked: 0,
bossesUnlocked: 0,
explorationUnlocked: 0,
questsUnlocked: 0,
+5
View File
@@ -425,6 +425,11 @@ interface ForceUnlocksResponse {
*/
explorationUnlocked: number;
/**
* Number of adventurer tiers that were unlocked by this operation.
*/
adventurersUnlocked: number;
/**
* HMAC-SHA256 signature of the corrected state for anti-cheat chain continuity.
*/