From 5217acaf8bfc96f4db0931b6b1e781e93d3e8bb0 Mon Sep 17 00:00:00 2001 From: Matheus Alves Date: Mon, 2 Jun 2025 16:31:53 +0100 Subject: [PATCH 1/5] Implement Name Run Feat Modified load session ui component, adding a submenu when selecting a 3 slot. This menu has 4 options: Load Game -> Behaves as before, allowing the player to continue progress from the last saved state in the slot. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename Run -> Overlays a rename form, allowing the player to type a name for the run, checking for string validity, with the option to cancel or confirm (Rename). Delete Run -> Prompts user confirmation to delete save data, removing the current save slot from the users save data. Cancel -> Hides menu overlay. Modified game data to implement a function to accept and store runNameText to the users data. Modified run info ui component, to display the chosen name when viewing run information. Example: When loading the game, the user can choose the Load Game menu option, then select a save slot, prompting the menu, then choose "Rename Run" and type the name "Monotype Water Run" then confirm, thus being able to better organize their save files. Signed-off-by: Matheus Alves Co-authored-by: Inês Simões --- src/system/game-data.ts | 42 +++++++ src/ui/run-info-ui-handler.ts | 4 + src/ui/save-slot-select-ui-handler.ts | 158 ++++++++++++++++++++++---- 3 files changed, 182 insertions(+), 22 deletions(-) diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 00b46b9e5f4..84b6367c38f 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -126,6 +126,7 @@ export interface SessionSaveData { battleType: BattleType; trainer: TrainerData; gameVersion: string; + runNameText: string; timestamp: number; challenges: ChallengeData[]; mysteryEncounterType: MysteryEncounterType | -1; // Only defined when current wave is ME, @@ -978,6 +979,47 @@ export class GameData { }); } + renameSession(slotId: number, newName: string): Promise { + return new Promise(async resolve => { + if (slotId < 0) { + return resolve(false); + } + + const sessionData: SessionSaveData | null = await this.getSession(slotId); + + if (!sessionData) return resolve(false); + + sessionData.runNameText = newName; + + const updatedDataStr = JSON.stringify(sessionData); + + if (bypassLogin) { + localStorage.setItem( + `sessionData${slotId ? slotId : ""}_${loggedInUser?.username}`, + encrypt(updatedDataStr, bypassLogin), + ); + resolve(true); + } else { + const encrypted = encrypt(updatedDataStr, bypassLogin); + const secretId = this.secretId; + const trainerId = this.trainerId; + + const error = await pokerogueApi.savedata.session.update( + { slot: slotId, trainerId, secretId, clientSessionId }, + encrypted, + ); + + if (!error) { + localStorage.setItem(`sessionData${slotId ? slotId : ""}_${loggedInUser?.username}`, encrypted); // Keep local in sync + resolve(true); + } else { + console.error("Failed to update session name:", error); + resolve(false); + } + } + }); + } + loadSession(slotId: number, sessionData?: SessionSaveData): Promise { // biome-ignore lint/suspicious/noAsyncPromiseExecutor: return new Promise(async (resolve, reject) => { diff --git a/src/ui/run-info-ui-handler.ts b/src/ui/run-info-ui-handler.ts index a4de2215fa4..a65802572da 100644 --- a/src/ui/run-info-ui-handler.ts +++ b/src/ui/run-info-ui-handler.ts @@ -206,6 +206,10 @@ export default class RunInfoUiHandler extends UiHandler { headerText.setOrigin(0, 0); headerText.setPositionRelative(headerBg, 8, 4); this.runContainer.add(headerText); + const runName = addTextObject(0, 0, this.runInfo.runNameText, TextStyle.WINDOW); + runName.setOrigin(0, 0); + runName.setPositionRelative(headerBg, 60, 4); + this.runContainer.add(runName); } /** diff --git a/src/ui/save-slot-select-ui-handler.ts b/src/ui/save-slot-select-ui-handler.ts index 7b4d46203c9..07f1ff14474 100644 --- a/src/ui/save-slot-select-ui-handler.ts +++ b/src/ui/save-slot-select-ui-handler.ts @@ -6,6 +6,7 @@ import { GameMode } from "../game-mode"; import * as Modifier from "#app/modifier/modifier"; import type { SessionSaveData } from "../system/game-data"; import type PokemonData from "../system/pokemon-data"; +import type { OptionSelectConfig } from "#app/ui/abstact-option-select-ui-handler"; import { isNullOrUndefined, fixedInt, getPlayTimeString, formatLargeNumber } from "#app/utils/common"; import MessageUiHandler from "./message-ui-handler"; import { TextStyle, addTextObject } from "./text"; @@ -14,7 +15,7 @@ import { addWindow } from "./ui-theme"; import { RunDisplayMode } from "#app/ui/run-info-ui-handler"; const SESSION_SLOTS_COUNT = 5; -const SLOTS_ON_SCREEN = 3; +const SLOTS_ON_SCREEN = 2; export enum SaveSlotUiMode { LOAD, @@ -32,6 +33,7 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { private uiMode: SaveSlotUiMode; private saveSlotSelectCallback: SaveSlotSelectCallback | null; + protected manageDataConfig: OptionSelectConfig; private scrollCursor = 0; @@ -100,6 +102,7 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { processInput(button: Button): boolean { const ui = this.getUi(); + const manageDataOptions: any[] = []; let success = false; let error = false; @@ -113,9 +116,107 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { } else { switch (this.uiMode) { case SaveSlotUiMode.LOAD: - this.saveSlotSelectCallback = null; - originalCallback?.(cursor); + manageDataOptions.push({ + label: i18next.t("menu:loadGame"), + handler: () => { + globalScene.ui.revertMode(); + originalCallback?.(cursor); + return true; + }, + keepOpen: false, + }); + + manageDataOptions.push({ + label: i18next.t("saveSlotSelectUiHandler:renameRun"), + handler: () => { + globalScene.ui.revertMode(); + ui.setOverlayMode( + UiMode.RENAME_POKEMON, + { + buttonActions: [ + (sanitizedName: string) => { + const name = decodeURIComponent((atob(sanitizedName))); + globalScene.gameData.renameSession(cursor, name).then(response => { + if (response[0] === false) { + globalScene.reset(true); + } else { + this.clearSessionSlots(); + this.cursorObj = null; + this.populateSessionSlots(); + this.setScrollCursor(0); + this.setCursor(0); + ui.revertMode(); + ui.showText("", 0); + } + }); + }, + () => { + ui.revertMode(); + }, + ], + }, + "", + ); + return true; + }, + }); + + this.manageDataConfig = { + xOffset: 0, + yOffset: 48, + options: manageDataOptions, + maxOptions: 4, + }; + + manageDataOptions.push({ + label: i18next.t("saveSlotSelectUiHandler:deleteRun"), + handler: () => { + globalScene.ui.revertMode(); + ui.showText(i18next.t("saveSlotSelectUiHandler:deleteData"), null, () => { + ui.setOverlayMode( + UiMode.CONFIRM, + () => { + globalScene.gameData.tryClearSession(cursor).then(response => { + if (response[0] === false) { + globalScene.reset(true); + } else { + this.clearSessionSlots(); + this.cursorObj = null; + this.populateSessionSlots(); + this.setScrollCursor(0); + this.setCursor(0); + ui.revertMode(); + ui.showText("", 0); + } + }); + }, + () => { + ui.revertMode(); + ui.showText("", 0); + }, + false, + 0, + 19, + import.meta.env.DEV ? 300 : 2000, + ); + }); + return true; + }, + keepOpen: false, + }); + + manageDataOptions.push({ + label: i18next.t("menuUiHandler:cancel"), + handler: () => { + globalScene.ui.revertMode(); + return true; + }, + keepOpen: true, + }); + + ui.setOverlayMode(UiMode.MENU_OPTION_SELECT, this.manageDataConfig); break; + case SaveSlotUiMode.SAVE: { const saveAndCallback = () => { const originalCallback = this.saveSlotSelectCallback; @@ -160,6 +261,7 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { } } else { this.saveSlotSelectCallback = null; + ui.showText("", 0); // Clear any UI text if needed originalCallback?.(-1); success = true; } @@ -266,33 +368,34 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { this.cursorObj = globalScene.add.container(0, 0); const cursorBox = globalScene.add.nineslice( 0, - 0, + 15, "select_cursor_highlight_thick", undefined, - 296, - 44, + 294, + this.sessionSlots[prevSlotIndex ?? 0]?.saveData?.runNameText ? 50 : 60, 6, 6, 6, 6, ); const rightArrow = globalScene.add.image(0, 0, "cursor"); - rightArrow.setPosition(160, 0); + rightArrow.setPosition(160, 15); rightArrow.setName("rightArrow"); this.cursorObj.add([cursorBox, rightArrow]); this.sessionSlotsContainer.add(this.cursorObj); } const cursorPosition = cursor + this.scrollCursor; - const cursorIncrement = cursorPosition * 56; + const valueHeight = this.sessionSlots[prevSlotIndex ?? 0]?.saveData?.runNameText ? 76 : 76; //nocas + const cursorIncrement = cursorPosition * 76; if (this.sessionSlots[cursorPosition] && this.cursorObj) { const hasData = this.sessionSlots[cursorPosition].hasData; // If the session slot lacks session data, it does not move from its default, central position. // Only session slots with session data will move leftwards and have a visible arrow. if (!hasData) { - this.cursorObj.setPosition(151, 26 + cursorIncrement); + this.cursorObj.setPosition(151, 20 + cursorIncrement); this.sessionSlots[cursorPosition].setPosition(0, cursorIncrement); } else { - this.cursorObj.setPosition(145, 26 + cursorIncrement); + this.cursorObj.setPosition(145, 20 + cursorIncrement); this.sessionSlots[cursorPosition].setPosition(-6, cursorIncrement); } this.setArrowVisibility(hasData); @@ -310,7 +413,8 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { revertSessionSlot(slotIndex: number): void { const sessionSlot = this.sessionSlots[slotIndex]; if (sessionSlot) { - sessionSlot.setPosition(0, slotIndex * 56); + const valueHeight = sessionSlot.saveData?.runNameText ? 76 : 76; + sessionSlot.setPosition(0, slotIndex * valueHeight); } } @@ -339,7 +443,7 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { this.setCursor(this.cursor, prevSlotIndex); globalScene.tweens.add({ targets: this.sessionSlotsContainer, - y: this.sessionSlotsContainerInitialY - 56 * scrollCursor, + y: this.sessionSlotsContainerInitialY - 76 * scrollCursor, duration: fixedInt(325), ease: "Sine.easeInOut", }); @@ -373,12 +477,12 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { class SessionSlot extends Phaser.GameObjects.Container { public slotId: number; public hasData: boolean; + private slotWindow: Phaser.GameObjects.NineSlice; private loadingLabel: Phaser.GameObjects.Text; - public saveData: SessionSaveData; constructor(slotId: number) { - super(globalScene, 0, slotId * 56); + super(globalScene, 0, slotId * 76); this.slotId = slotId; @@ -386,32 +490,42 @@ class SessionSlot extends Phaser.GameObjects.Container { } setup() { - const slotWindow = addWindow(0, 0, 304, 52); - this.add(slotWindow); + this.slotWindow = addWindow(0, 0, 304, 70); + this.add(this.slotWindow); - this.loadingLabel = addTextObject(152, 26, i18next.t("saveSlotSelectUiHandler:loading"), TextStyle.WINDOW); + this.loadingLabel = addTextObject(152, 33, i18next.t("saveSlotSelectUiHandler:loading"), TextStyle.WINDOW); this.loadingLabel.setOrigin(0.5, 0.5); this.add(this.loadingLabel); } async setupWithData(data: SessionSaveData) { + const hasName = data?.runNameText; this.remove(this.loadingLabel, true); + if (hasName) { + const nameLabel = addTextObject(8, 5, data.runNameText, TextStyle.WINDOW); + this.add(nameLabel); + } const gameModeLabel = addTextObject( 8, - 5, + hasName ? 19 : 12, `${GameMode.getModeName(data.gameMode) || i18next.t("gameMode:unkown")} - ${i18next.t("saveSlotSelectUiHandler:wave")} ${data.waveIndex}`, TextStyle.WINDOW, ); this.add(gameModeLabel); - const timestampLabel = addTextObject(8, 19, new Date(data.timestamp).toLocaleString(), TextStyle.WINDOW); + const timestampLabel = addTextObject( + 8, + hasName ? 33 : 26, + new Date(data.timestamp).toLocaleString(), + TextStyle.WINDOW, + ); this.add(timestampLabel); - const playTimeLabel = addTextObject(8, 33, getPlayTimeString(data.playTime), TextStyle.WINDOW); + const playTimeLabel = addTextObject(8, hasName ? 47 : 40, getPlayTimeString(data.playTime), TextStyle.WINDOW); this.add(playTimeLabel); - const pokemonIconsContainer = globalScene.add.container(144, 4); + const pokemonIconsContainer = globalScene.add.container(144, hasName ? 16 : 9); data.party.forEach((p: PokemonData, i: number) => { const iconContainer = globalScene.add.container(26 * i, 0); iconContainer.setScale(0.75); @@ -440,7 +554,7 @@ class SessionSlot extends Phaser.GameObjects.Container { this.add(pokemonIconsContainer); - const modifierIconsContainer = globalScene.add.container(148, 30); + const modifierIconsContainer = globalScene.add.container(148, 38); modifierIconsContainer.setScale(0.5); let visibleModifierIndex = 0; for (const m of data.modifiers) { From 1e806fa6ff5e702bca712ec7ddbc0888af0537f1 Mon Sep 17 00:00:00 2001 From: Matheus Alves Date: Wed, 4 Jun 2025 15:25:19 +0100 Subject: [PATCH 2/5] Implement Rename Input Design and Tests for Name Run Feat Created a test to verify Name Run Feature behaviour in the backend (rename_run.test.ts), checking possible errors and expected behaviours. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created a UiHandler RenameRunFormUiHandler (rename-run-ui-handler.ts), creating a frontend input overlay for the Name Run Feature. Signed-off-by: Matheus Alves Co-authored-by: Inês Simões --- src/enums/ui-mode.ts | 1 + src/system/game-data.ts | 5 +- src/ui/rename-run-ui-handler.ts | 49 ++++++++++++++++ src/ui/save-slot-select-ui-handler.ts | 4 +- src/ui/ui.ts | 3 + test/system/rename_run.test.ts | 82 +++++++++++++++++++++++++++ 6 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 src/ui/rename-run-ui-handler.ts create mode 100644 test/system/rename_run.test.ts diff --git a/src/enums/ui-mode.ts b/src/enums/ui-mode.ts index dcf6bd2a238..ac6480098d8 100644 --- a/src/enums/ui-mode.ts +++ b/src/enums/ui-mode.ts @@ -38,6 +38,7 @@ export enum UiMode { UNAVAILABLE, CHALLENGE_SELECT, RENAME_POKEMON, + RENAME_RUN, RUN_HISTORY, RUN_INFO, TEST_DIALOGUE, diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 84b6367c38f..27c5a60769e 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -979,7 +979,7 @@ export class GameData { }); } - renameSession(slotId: number, newName: string): Promise { + async renameSession(slotId: number, newName: string): Promise { return new Promise(async resolve => { if (slotId < 0) { return resolve(false); @@ -1010,7 +1010,8 @@ export class GameData { ); if (!error) { - localStorage.setItem(`sessionData${slotId ? slotId : ""}_${loggedInUser?.username}`, encrypted); // Keep local in sync + localStorage.setItem(`sessionData${slotId ? slotId : ""}_${loggedInUser?.username}`, encrypted); + await updateUserInfo(); resolve(true); } else { console.error("Failed to update session name:", error); diff --git a/src/ui/rename-run-ui-handler.ts b/src/ui/rename-run-ui-handler.ts new file mode 100644 index 00000000000..0ba27f760be --- /dev/null +++ b/src/ui/rename-run-ui-handler.ts @@ -0,0 +1,49 @@ +import type { InputFieldConfig } from "./form-modal-ui-handler"; +import { FormModalUiHandler } from "./form-modal-ui-handler"; +import type { ModalConfig } from "./modal-ui-handler"; +import i18next from "i18next"; + +export default class RenameRunFormUiHandler extends FormModalUiHandler { + getModalTitle(_config?: ModalConfig): string { + return i18next.t("menu:renamerun"); + } + + getWidth(_config?: ModalConfig): number { + return 160; + } + + getMargin(_config?: ModalConfig): [number, number, number, number] { + return [0, 0, 48, 0]; + } + + getButtonLabels(_config?: ModalConfig): string[] { + return [i18next.t("menu:rename"), i18next.t("menu:cancel")]; + } + + getReadableErrorMessage(error: string): string { + const colonIndex = error?.indexOf(":"); + if (colonIndex > 0) { + error = error.slice(0, colonIndex); + } + + return super.getReadableErrorMessage(error); + } + + override getInputFieldConfigs(): InputFieldConfig[] { + return [{ label: i18next.t("menu:runName") }]; + } + + show(args: any[]): boolean { + if (super.show(args)) { + const config = args[0] as ModalConfig; + this.submitAction = _ => { + this.sanitizeInputs(); + const sanitizedName = btoa(encodeURIComponent(this.inputs[0].text)); + config.buttonActions[0](sanitizedName); + return true; + }; + return true; + } + return false; + } +} diff --git a/src/ui/save-slot-select-ui-handler.ts b/src/ui/save-slot-select-ui-handler.ts index 07f1ff14474..6675d06bf00 100644 --- a/src/ui/save-slot-select-ui-handler.ts +++ b/src/ui/save-slot-select-ui-handler.ts @@ -131,11 +131,11 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { handler: () => { globalScene.ui.revertMode(); ui.setOverlayMode( - UiMode.RENAME_POKEMON, + UiMode.RENAME_RUN, { buttonActions: [ (sanitizedName: string) => { - const name = decodeURIComponent((atob(sanitizedName))); + const name = decodeURIComponent(atob(sanitizedName)); globalScene.gameData.renameSession(cursor, name).then(response => { if (response[0] === false) { globalScene.reset(true); diff --git a/src/ui/ui.ts b/src/ui/ui.ts index ad496df6382..a5d6cd8f5b9 100644 --- a/src/ui/ui.ts +++ b/src/ui/ui.ts @@ -58,6 +58,7 @@ import PokedexScanUiHandler from "./pokedex-scan-ui-handler"; import PokedexPageUiHandler from "./pokedex-page-ui-handler"; import { NavigationManager } from "./settings/navigationMenu"; import { UiMode } from "#enums/ui-mode"; +import RenameRunFormUiHandler from "./rename-run-ui-handler"; const transitionModes = [ UiMode.SAVE_SLOT, @@ -96,6 +97,7 @@ const noTransitionModes = [ UiMode.SESSION_RELOAD, UiMode.UNAVAILABLE, UiMode.RENAME_POKEMON, + UiMode.RENAME_RUN, UiMode.TEST_DIALOGUE, UiMode.AUTO_COMPLETE, UiMode.ADMIN, @@ -165,6 +167,7 @@ export default class UI extends Phaser.GameObjects.Container { new UnavailableModalUiHandler(), new GameChallengesUiHandler(), new RenameFormUiHandler(), + new RenameRunFormUiHandler(), new RunHistoryUiHandler(), new RunInfoUiHandler(), new TestDialogueUiHandler(UiMode.TEST_DIALOGUE), diff --git a/test/system/rename_run.test.ts b/test/system/rename_run.test.ts new file mode 100644 index 00000000000..2b728525a7c --- /dev/null +++ b/test/system/rename_run.test.ts @@ -0,0 +1,82 @@ +import * as bypassLoginModule from "#app/global-vars/bypass-login"; +import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; +import type { SessionSaveData } from "#app/system/game-data"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import GameManager from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import * as account from "#app/account"; + +describe("System - Rename Run", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .moveset([Moves.SPLASH]) + .battleStyle("single") + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + describe("renameSession", () => { + beforeEach(() => { + vi.spyOn(bypassLoginModule, "bypassLogin", "get").mockReturnValue(false); + vi.spyOn(account, "updateUserInfo").mockImplementation(async () => [true, 1]); + }); + + it("should return false if slotId < 0", async () => { + const result = await game.scene.gameData.renameSession(-1, "Named Run"); + + expect(result).toEqual(false); + }); + + it("should return false if getSession returns null", async () => { + vi.spyOn(game.scene.gameData, "getSession").mockResolvedValue(null as unknown as SessionSaveData); + + const result = await game.scene.gameData.renameSession(-1, "Named Run"); + + expect(result).toEqual(false); + }); + + it("should return true if bypassLogin is true", async () => { + vi.spyOn(bypassLoginModule, "bypassLogin", "get").mockReturnValue(true); + vi.spyOn(game.scene.gameData, "getSession").mockResolvedValue({} as SessionSaveData); + + const result = await game.scene.gameData.renameSession(0, "Named Run"); + + expect(result).toEqual(true); + }); + + it("should return false if api returns error", async () => { + vi.spyOn(game.scene.gameData, "getSession").mockResolvedValue({} as SessionSaveData); + vi.spyOn(pokerogueApi.savedata.session, "update").mockResolvedValue("Unknown Error!"); + + const result = await game.scene.gameData.renameSession(0, "Named Run"); + + expect(result).toEqual(false); + }); + + it("should return true if api is succesfull", async () => { + vi.spyOn(game.scene.gameData, "getSession").mockResolvedValue({} as SessionSaveData); + vi.spyOn(pokerogueApi.savedata.session, "update").mockResolvedValue(""); + + const result = await game.scene.gameData.renameSession(0, "Named Run"); + + expect(result).toEqual(true); + expect(account.updateUserInfo).toHaveBeenCalled(); + }); + }); +}); From 78d9b7b724087deccc45f6a4a70101003d7ce842 Mon Sep 17 00:00:00 2001 From: Matheus Alves Date: Thu, 5 Jun 2025 17:31:52 +0100 Subject: [PATCH 3/5] Fixed formating and best practices issues: Rewrote renameSession to be more inline with other API call funtions, removed debugging comments and whitespaces. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Matheus Alves Co-authored-by: Inês Simões --- src/system/game-data.ts | 43 +++++++++++++-------------- src/ui/save-slot-select-ui-handler.ts | 4 +-- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 27c5a60769e..6555408055f 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -984,39 +984,38 @@ export class GameData { if (slotId < 0) { return resolve(false); } - const sessionData: SessionSaveData | null = await this.getSession(slotId); - if (!sessionData) return resolve(false); + if (!sessionData) { + return resolve(false); + } sessionData.runNameText = newName; - const updatedDataStr = JSON.stringify(sessionData); + const encrypted = encrypt(updatedDataStr, bypassLogin); + const secretId = this.secretId; + const trainerId = this.trainerId; - if (bypassLogin) { + if (!bypassLogin) { + pokerogueApi.savedata.session.update({ slot: slotId, trainerId, secretId, clientSessionId },encrypted).then(error => { + if (error) { + console.error("Failed to update session name:", error); + resolve(false); + } else { + localStorage.setItem(`sessionData${slotId ? slotId : ""}_${loggedInUser?.username}`, encrypted); + updateUserInfo().then(success => { + if (success !== null && !success) { + return resolve(false); + }}); + resolve(true); + } + }); + } else { localStorage.setItem( `sessionData${slotId ? slotId : ""}_${loggedInUser?.username}`, encrypt(updatedDataStr, bypassLogin), ); resolve(true); - } else { - const encrypted = encrypt(updatedDataStr, bypassLogin); - const secretId = this.secretId; - const trainerId = this.trainerId; - - const error = await pokerogueApi.savedata.session.update( - { slot: slotId, trainerId, secretId, clientSessionId }, - encrypted, - ); - - if (!error) { - localStorage.setItem(`sessionData${slotId ? slotId : ""}_${loggedInUser?.username}`, encrypted); - await updateUserInfo(); - resolve(true); - } else { - console.error("Failed to update session name:", error); - resolve(false); - } } }); } diff --git a/src/ui/save-slot-select-ui-handler.ts b/src/ui/save-slot-select-ui-handler.ts index 6675d06bf00..0b305446fa9 100644 --- a/src/ui/save-slot-select-ui-handler.ts +++ b/src/ui/save-slot-select-ui-handler.ts @@ -261,7 +261,7 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { } } else { this.saveSlotSelectCallback = null; - ui.showText("", 0); // Clear any UI text if needed + ui.showText("", 0); originalCallback?.(-1); success = true; } @@ -385,7 +385,7 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { this.sessionSlotsContainer.add(this.cursorObj); } const cursorPosition = cursor + this.scrollCursor; - const valueHeight = this.sessionSlots[prevSlotIndex ?? 0]?.saveData?.runNameText ? 76 : 76; //nocas + const valueHeight = this.sessionSlots[prevSlotIndex ?? 0]?.saveData?.runNameText ? 76 : 76; const cursorIncrement = cursorPosition * 76; if (this.sessionSlots[cursorPosition] && this.cursorObj) { const hasData = this.sessionSlots[cursorPosition].hasData; From 361667dcf8ba9d87b25ce0d12c1f586ea823bd10 Mon Sep 17 00:00:00 2001 From: Matheus Alves Date: Thu, 12 Jun 2025 12:14:04 +0100 Subject: [PATCH 4/5] Minor Sanitization for aesthetics Deleting the input when closing the overlay for aesthetics purpose MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Matheus Alves Co-authored-by: Inês Simões --- src/ui/rename-run-ui-handler.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/ui/rename-run-ui-handler.ts b/src/ui/rename-run-ui-handler.ts index 0ba27f760be..0033079de63 100644 --- a/src/ui/rename-run-ui-handler.ts +++ b/src/ui/rename-run-ui-handler.ts @@ -35,6 +35,11 @@ export default class RenameRunFormUiHandler extends FormModalUiHandler { show(args: any[]): boolean { if (super.show(args)) { + if (this.inputs?.length) { + this.inputs.forEach(input => { + input.text = ""; + }); + } const config = args[0] as ModalConfig; this.submitAction = _ => { this.sanitizeInputs(); From de66b9a4f1ff5535578778a418a655b7337d79f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?In=C3=AAs=20Sim=C3=B5es?= Date: Thu, 12 Jun 2025 22:23:15 +0100 Subject: [PATCH 5/5] Fixed minor rebase alterations. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Matheus Alves matheus.r.noya.alves@tecnico.ulisboa.pt Co-authored-by: Inês Simões ines.p.simoes@tecnico.ulisboa.pt --- test/system/rename_run.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/system/rename_run.test.ts b/test/system/rename_run.test.ts index 2b728525a7c..38906129e15 100644 --- a/test/system/rename_run.test.ts +++ b/test/system/rename_run.test.ts @@ -1,12 +1,12 @@ import * as bypassLoginModule from "#app/global-vars/bypass-login"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; import type { SessionSaveData } from "#app/system/game-data"; -import { Abilities } from "#enums/abilities"; -import { Moves } from "#enums/moves"; +import { MoveId } from "#enums/move-id"; import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import * as account from "#app/account"; +import { AbilityId } from "#enums/ability-id"; describe("System - Rename Run", () => { let phaserGame: Phaser.Game; @@ -21,10 +21,10 @@ describe("System - Rename Run", () => { beforeEach(() => { game = new GameManager(phaserGame); game.override - .moveset([Moves.SPLASH]) + .moveset([MoveId.SPLASH]) .battleStyle("single") - .enemyAbility(Abilities.BALL_FETCH) - .enemyMoveset(Moves.SPLASH); + .enemyAbility(AbilityId.BALL_FETCH) + .enemyMoveset(MoveId.SPLASH); }); afterEach(() => {