Logger UI

This commit is contained in:
RedstonewolfX 2024-07-07 14:04:53 -04:00
parent a7d28e1ee7
commit 4f4d107b21
3 changed files with 327 additions and 5 deletions

69
src/logger.ts Normal file
View File

@ -0,0 +1,69 @@
import i18next from "i18next";
import * as Utils from "./utils";
/**
* All logs.
*
* Format: [filename, localStorage key, name, header]
*/
export const logs: string[][] = [
["instructions.txt", "path_log", "Steps", "Run Steps", "wide_lens"],
["encounters.csv", "enc_log", "Encounters", "Encounter Data"],
["log.txt", "debug_log", "Debug", "Debug Log"],
]
export var logKeys: string[] = [
"i", // Instructions/steps
"e", // Encounters
"d", // Debug
];
export const byteSize = str => new Blob([str]).size
const filesizes = ["b", "kb", "mb", "gb", "tb"]
export function getSize(str: string) {
var d = byteSize(str)
var unit = 0
while (d > 1000 && unit < filesizes.length - 1) {
d = Math.round(d/100)/10
unit++
}
return d.toString() + filesizes[unit]
}
/**
* Writes data to a new line.
* @param keyword The identifier key for the log you're writing to
* @param data The string you're writing to the given log
*/
export function toLog(keyword: string, data: string) {
localStorage.setItem(logs[logKeys.indexOf(keyword)][1], localStorage.getItem(logs[logKeys.indexOf(keyword)][1] + "\n" + data))
}
/**
* Writes data on the same line you were on.
* @param keyword The identifier key for the log you're writing to
* @param data The string you're writing to the given log
*/
export function appendLog(keyword: string, data: string) {
localStorage.setItem(logs[logKeys.indexOf(keyword)][1], localStorage.getItem(logs[logKeys.indexOf(keyword)][1] + data))
}
/**
*
* Clears all data from a log.
* @param keyword The identifier key for the log you want to reste
*/
export function clearLog(keyword: string) {
localStorage.setItem(logs[logKeys.indexOf(keyword)][1], "---- " + logs[logKeys.indexOf(keyword)][3] + " ----")
}
/**
* Saves a log to your device.
* @param keyword The identifier key for the log you want to reste
*/
export function downloadLog(keyword: string) {
var d = localStorage.getItem(logs[logKeys.indexOf(keyword)][1])
// logs[logKeys.indexOf(keyword)][1]
const blob = new Blob([ d ], {type: "text/json"});
const link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = `${logs[logKeys.indexOf(keyword)][0]}`;
link.click();
link.remove();
}

View File

@ -36,7 +36,7 @@ import { EggHatchPhase } from "./egg-hatch-phase";
import { Egg } from "./data/egg"; import { Egg } from "./data/egg";
import { vouchers } from "./system/voucher"; import { vouchers } from "./system/voucher";
import { clientSessionId, loggedInUser, updateUserInfo } from "./account"; import { clientSessionId, loggedInUser, updateUserInfo } from "./account";
import { SessionSaveData } from "./system/game-data"; import { SessionSaveData, decrypt } from "./system/game-data";
import { addPokeballCaptureStars, addPokeballOpenParticles } from "./field/anims"; import { addPokeballCaptureStars, addPokeballOpenParticles } from "./field/anims";
import { SpeciesFormChangeActiveTrigger, SpeciesFormChangeManualTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangePreMoveTrigger } from "./data/pokemon-forms"; import { SpeciesFormChangeActiveTrigger, SpeciesFormChangeManualTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangePreMoveTrigger } from "./data/pokemon-forms";
import { battleSpecDialogue, getCharVariantFromDialogue, miscDialogue } from "./data/dialogue"; import { battleSpecDialogue, getCharVariantFromDialogue, miscDialogue } from "./data/dialogue";
@ -65,9 +65,171 @@ import { Moves } from "#enums/moves";
import { PlayerGender } from "#enums/player-gender"; import { PlayerGender } from "#enums/player-gender";
import { Species } from "#enums/species"; import { Species } from "#enums/species";
import { TrainerType } from "#enums/trainer-type"; import { TrainerType } from "#enums/trainer-type";
import TrainerData from "./system/trainer-data";
import PersistentModifierData from "./system/modifier-data";
import ArenaData from "./system/arena-data";
import ChallengeData from "./system/challenge-data";
import { Challenges } from "./enums/challenges"
import PokemonData from "./system/pokemon-data"
import * as LoggerTools from "./logger"
const { t } = i18next; const { t } = i18next;
export function parseSlotData(slotId: integer): SessionSaveData {
var S = localStorage.getItem(`sessionData${slotId ? slotId : ""}_${loggedInUser.username}`)
if (S == null) {
// No data in this slot
return undefined;
}
var dataStr = decrypt(S, true)
var Save = JSON.parse(dataStr, (k: string, v: any) => {
/*const versions = [ scene.game.config.gameVersion, sessionData.gameVersion || '0.0.0' ];
if (versions[0] !== versions[1]) {
const [ versionNumbers, oldVersionNumbers ] = versions.map(ver => ver.split('.').map(v => parseInt(v)));
}*/
if (k === "party" || k === "enemyParty") {
const ret: PokemonData[] = [];
if (v === null) {
v = [];
}
for (const pd of v) {
ret.push(new PokemonData(pd));
}
return ret;
}
if (k === "trainer") {
return v ? new TrainerData(v) : null;
}
if (k === "modifiers" || k === "enemyModifiers") {
const player = k === "modifiers";
const ret: PersistentModifierData[] = [];
if (v === null) {
v = [];
}
for (const md of v) {
if (md?.className === "ExpBalanceModifier") { // Temporarily limit EXP Balance until it gets reworked
md.stackCount = Math.min(md.stackCount, 4);
}
if (md instanceof EnemyAttackStatusEffectChanceModifier && md.effect === StatusEffect.FREEZE || md.effect === StatusEffect.SLEEP) {
continue;
}
ret.push(new PersistentModifierData(md, player));
}
return ret;
}
if (k === "arena") {
return new ArenaData(v);
}
if (k === "challenges") {
const ret: ChallengeData[] = [];
if (v === null) {
v = [];
}
for (const c of v) {
ret.push(new ChallengeData(c));
}
return ret;
}
return v;
}) as SessionSaveData;
Save.slot = slotId
Save.description = slotId + " - "
var challengeParts: ChallengeData[] = new Array(5)
var nameParts: string[] = new Array(5)
if (Save.challenges != undefined) {
for (var i = 0; i < Save.challenges.length; i++) {
switch (Save.challenges[i].id) {
case Challenges.SINGLE_TYPE:
challengeParts[0] = Save.challenges[i]
nameParts[1] = Save.challenges[i].toChallenge().getValue()
nameParts[1] = nameParts[1][0].toUpperCase() + nameParts[1].substring(1)
if (nameParts[1] == "unknown") {
nameParts[1] = undefined
challengeParts[1] = undefined
}
break;
case Challenges.SINGLE_GENERATION:
challengeParts[1] = Save.challenges[i]
nameParts[0] = "Gen " + Save.challenges[i].value
if (nameParts[0] == "Gen 0") {
nameParts[0] = undefined
challengeParts[0] = undefined
}
break;
case Challenges.LOWER_MAX_STARTER_COST:
challengeParts[2] = Save.challenges[i]
nameParts[3] = (10 - challengeParts[0].value) + "cost"
break;
case Challenges.LOWER_STARTER_POINTS:
challengeParts[3] = Save.challenges[i]
nameParts[4] = (10 - challengeParts[0].value) + "pt"
break;
case Challenges.FRESH_START:
challengeParts[4] = Save.challenges[i]
nameParts[2] = "FS"
break;
}
}
}
for (var i = 0; i < challengeParts.length; i++) {
if (challengeParts[i] == undefined || challengeParts[i] == null) {
challengeParts.splice(i, 1)
i--
}
}
for (var i = 0; i < nameParts.length; i++) {
if (nameParts[i] == undefined || nameParts[i] == null || nameParts[i] == "") {
nameParts.splice(i, 1)
i--
}
}
if (challengeParts.length == 1 && false) {
switch (challengeParts[0].id) {
case Challenges.SINGLE_TYPE:
Save.description += "Mono " + challengeParts[0].toChallenge().getValue()
break;
case Challenges.SINGLE_GENERATION:
Save.description += "Gen " + challengeParts[0].value
break;
case Challenges.LOWER_MAX_STARTER_COST:
Save.description += "Max cost " + (10 - challengeParts[0].value)
break;
case Challenges.LOWER_STARTER_POINTS:
Save.description += (10 - challengeParts[0].value) + "-point"
break;
case Challenges.FRESH_START:
Save.description += "Fresh Start"
break;
}
} else if (challengeParts.length == 0) {
switch (Save.gameMode) {
case GameModes.CLASSIC:
Save.description += "Classic";
break;
case GameModes.ENDLESS:
Save.description += "Endless";
break;
case GameModes.SPLICED_ENDLESS:
Save.description += "Endless+";
break;
case GameModes.DAILY:
Save.description += "Daily";
break;
}
} else {
Save.description += nameParts.join(" ")
}
Save.description += " (" + getBiomeName(Save.arena.biome) + " " + Save.waveIndex + ")"
return Save;
}
export class LoginPhase extends Phase { export class LoginPhase extends Phase {
private showText: boolean; private showText: boolean;
@ -198,8 +360,25 @@ export class TitlePhase extends Phase {
}); });
} }
getLastSave(log?: boolean, dailyOnly?: boolean): SessionSaveData {
var saves: Array<Array<any>> = [];
for (var i = 0; i < 5; i++) {
var s = parseSlotData(i);
if (s != undefined) {
if (!dailyOnly || s.gameMode == GameModes.DAILY) {
saves.push([i, s, s.timestamp]);
}
}
}
saves.sort((a, b): integer => {return b[2] - a[2]})
if (log) console.log(saves)
return saves[0][1]
}
showOptions(): void { showOptions(): void {
var hasFile = true
const options: OptionSelectItem[] = []; const options: OptionSelectItem[] = [];
if (false)
if (loggedInUser.lastSessionSlot > -1) { if (loggedInUser.lastSessionSlot > -1) {
options.push({ options.push({
label: i18next.t("continue", null, { ns: "menu"}), label: i18next.t("continue", null, { ns: "menu"}),
@ -209,6 +388,34 @@ export class TitlePhase extends Phase {
} }
}); });
} }
// Replaces 'Continue' with the last Daily Run that the player completed a floor on
// If there are no daily runs, it instead shows the most recently saved run
// If this fails too, there are no saves, and the option does not appear
var lastsave = this.getLastSave(false, true);
if (lastsave != undefined) {
options.push({
label: (this.getLastSave().description ? this.getLastSave().description : "[???]"),
handler: () => {
this.loadSaveSlot(this.getLastSave().slot);
return true;
}
})
} else {
lastsave = this.getLastSave(false);
if (lastsave != undefined) {
options.push({
label: (this.getLastSave().description ? this.getLastSave().description : "[???]"),
handler: () => {
this.loadSaveSlot(this.getLastSave().slot);
return true;
}
})
} else {
console.log("Failed to get last save")
this.getLastSave(true)
hasFile = false
}
}
options.push({ options.push({
label: i18next.t("menu:newGame"), label: i18next.t("menu:newGame"),
handler: () => { handler: () => {
@ -269,8 +476,52 @@ export class TitlePhase extends Phase {
} }
return true; return true;
} }
}, }, {
{ label: "Manage Logs",
handler: () => {
const options: OptionSelectItem[] = [];
for (var i = 0; i < LoggerTools.logs.length; i++) {
if (localStorage.getItem(LoggerTools.logs[i][1]) != null)
options.push({
label: `Export ${LoggerTools.logs[i][2]} (${LoggerTools.getSize(LoggerTools.logs[i][2])})`,
handler: () => {
LoggerTools.downloadLog(LoggerTools.logKeys[i])
return true;
}
})
}
options.push({
label: `Export all (${options.length})`,
handler: () => {
for (var i = 0; i < LoggerTools.logKeys[i].length; i++) {
LoggerTools.downloadLog(LoggerTools.logKeys[i])
}
return true;
}
}, {
label: `Reset all (${LoggerTools.logKeys[i].length})`,
handler: () => {
for (var i = 0; i < LoggerTools.logKeys[i].length; i++) {
LoggerTools.clearLog(LoggerTools.logKeys[i])
}
return true;
}
}, {
label: i18next.t("menu:cancel"),
handler: () => {
this.scene.clearPhaseQueue();
this.scene.pushPhase(new TitlePhase(this.scene));
super.end();
return true;
}
});
this.scene.ui.showText("Export or clear game logs.", null, () => this.scene.ui.setOverlayMode(Mode.OPTION_SELECT, { options: options }));
return true;
}
})
// If the player has no save data (as determined above), hide the "Load Game" button
if (hasFile)
options.push({
label: i18next.t("menu:loadGame"), label: i18next.t("menu:loadGame"),
handler: () => { handler: () => {
this.scene.ui.setOverlayMode(Mode.SAVE_SLOT, SaveSlotUiMode.LOAD, this.scene.ui.setOverlayMode(Mode.SAVE_SLOT, SaveSlotUiMode.LOAD,
@ -282,8 +533,8 @@ export class TitlePhase extends Phase {
}); });
return true; return true;
} }
}, })
{ options.push({
label: i18next.t("menu:dailyRun"), label: i18next.t("menu:dailyRun"),
handler: () => { handler: () => {
this.initDailyRun(); this.initDailyRun();

View File

@ -122,6 +122,8 @@ export interface SessionSaveData {
gameVersion: string; gameVersion: string;
timestamp: integer; timestamp: integer;
challenges: ChallengeData[]; challenges: ChallengeData[];
slot: integer;
description: string;
} }
interface Unlocks { interface Unlocks {