generated from nhcarrigan/template
feat: add sync new content debug tool
Adds a new debug panel button that injects any adventurers, quests, bosses, equipment, upgrades, achievements, zones, and exploration areas that exist in the current game data but are missing from an existing player save (e.g. content added after the save was first created).
This commit is contained in:
@@ -10,7 +10,50 @@ import { type JSX, useState } from "react";
|
||||
import { useGame } from "../../context/gameContext.js";
|
||||
import { ConfirmationModal } from "../ui/confirmationModal.js";
|
||||
|
||||
type ActiveModal = "force-unlocks" | "hard-reset" | null;
|
||||
type ActiveModal = "force-unlocks" | "hard-reset" | "sync-new-content" | null;
|
||||
|
||||
interface SyncNewContentResult {
|
||||
achievementsAdded: number;
|
||||
adventurersAdded: number;
|
||||
bossesAdded: number;
|
||||
equipmentAdded: number;
|
||||
explorationAreasAdded: number;
|
||||
questsAdded: number;
|
||||
upgradesAdded: number;
|
||||
zonesAdded: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a human-readable summary of what the sync-new-content operation added.
|
||||
* @param result - The counts returned by the operation.
|
||||
* @returns A message string describing what was added, or a confirmation nothing was needed.
|
||||
*/
|
||||
const buildSyncNewContentMessage = (result: SyncNewContentResult): string => {
|
||||
const entries: Array<[ number, string ]> = [
|
||||
[ result.zonesAdded, "zone(s)" ],
|
||||
[ result.questsAdded, "quest(s)" ],
|
||||
[ result.bossesAdded, "boss(es)" ],
|
||||
[ result.explorationAreasAdded, "exploration area(s)" ],
|
||||
[ result.adventurersAdded, "adventurer tier(s)" ],
|
||||
[ result.upgradesAdded, "upgrade(s)" ],
|
||||
[ result.equipmentAdded, "equipment item(s)" ],
|
||||
[ result.achievementsAdded, "achievement(s)" ],
|
||||
];
|
||||
const parts = entries.
|
||||
filter(([ count ]) => {
|
||||
return count > 0;
|
||||
}).
|
||||
map(([ count, label ]) => {
|
||||
return `${String(count)} ${label}`;
|
||||
});
|
||||
if (parts.length === 0) {
|
||||
return "Your save is already up to date — no new content was found.";
|
||||
}
|
||||
const total = entries.reduce((sum, [ count ]) => {
|
||||
return sum + count;
|
||||
}, 0);
|
||||
return `Added ${String(total)} new item(s) to your save: ${parts.join(", ")}.`;
|
||||
};
|
||||
|
||||
interface ForceUnlocksResult {
|
||||
adventurersUnlocked: number;
|
||||
@@ -60,15 +103,21 @@ const buildForceUnlocksMessage = (result: ForceUnlocksResult): string => {
|
||||
* @returns The JSX element.
|
||||
*/
|
||||
const DebugPanel = (): JSX.Element => {
|
||||
const { forceUnlocks, debugHardReset, isLoading } = useGame();
|
||||
const { forceUnlocks, debugHardReset, syncNewContent, isLoading } = useGame();
|
||||
const [ activeModal, setActiveModal ] = useState<ActiveModal>(null);
|
||||
const [ forceUnlocksResult, setForceUnlocksResult ] = useState<string | null>(null);
|
||||
const [ syncNewContentResult, setSyncNewContentResult ] = useState<string | null>(null);
|
||||
|
||||
function handleOpenForceUnlocks(): void {
|
||||
setForceUnlocksResult(null);
|
||||
setActiveModal("force-unlocks");
|
||||
}
|
||||
|
||||
function handleOpenSyncNewContent(): void {
|
||||
setSyncNewContentResult(null);
|
||||
setActiveModal("sync-new-content");
|
||||
}
|
||||
|
||||
function handleOpenHardReset(): void {
|
||||
setActiveModal("hard-reset");
|
||||
}
|
||||
@@ -85,6 +134,14 @@ const DebugPanel = (): JSX.Element => {
|
||||
})();
|
||||
}
|
||||
|
||||
function handleConfirmSyncNewContent(): void {
|
||||
setActiveModal(null);
|
||||
void (async(): Promise<void> => {
|
||||
const result = await syncNewContent();
|
||||
setSyncNewContentResult(buildSyncNewContentMessage(result));
|
||||
})();
|
||||
}
|
||||
|
||||
function handleConfirmHardReset(): void {
|
||||
setActiveModal(null);
|
||||
void debugHardReset();
|
||||
@@ -120,6 +177,26 @@ const DebugPanel = (): JSX.Element => {
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className="debug-action-card">
|
||||
<h3>{"🔄 Sync New Content"}</h3>
|
||||
<p>
|
||||
{
|
||||
"If the game has been updated since your save was created, this will add any missing adventurers, quests, bosses, equipment, upgrades, and more to your save without affecting your existing progress."
|
||||
}
|
||||
</p>
|
||||
<button
|
||||
className="action-button"
|
||||
disabled={isLoading}
|
||||
onClick={handleOpenSyncNewContent}
|
||||
type="button"
|
||||
>
|
||||
{"Sync New Content"}
|
||||
</button>
|
||||
{syncNewContentResult !== null
|
||||
&& <p className="debug-result-message">{syncNewContentResult}</p>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className="debug-action-card">
|
||||
<h3>{"💀 Hard Reset"}</h3>
|
||||
<p>
|
||||
@@ -149,6 +226,17 @@ const DebugPanel = (): JSX.Element => {
|
||||
/>
|
||||
}
|
||||
|
||||
{activeModal === "sync-new-content"
|
||||
&& <ConfirmationModal
|
||||
confirmLabel="Yes, Sync New Content"
|
||||
description="This will scan for any adventurers, quests, bosses, equipment, upgrades, achievements, and zones added to the game after your save was created, and add them to your save. This operation is safe and non-destructive — your existing progress will not be affected."
|
||||
isLoading={isLoading}
|
||||
onCancel={handleCancel}
|
||||
onConfirm={handleConfirmSyncNewContent}
|
||||
title="Sync New Content"
|
||||
/>
|
||||
}
|
||||
|
||||
{activeModal === "hard-reset"
|
||||
&& <ConfirmationModal
|
||||
confirmLabel="Yes, Wipe Everything"
|
||||
|
||||
Reference in New Issue
Block a user