From 727a78efdd5457cb7038b72c0e3b29aa4aee8155 Mon Sep 17 00:00:00 2001 From: Frankly George <54015-franklygeorge@users.noreply.gitgud.io> Date: Fri, 11 Oct 2024 19:40:12 +0000 Subject: [PATCH] Fix slave import and export not serializing correctly --- devTools/types/SugarCubeExtensions.d.ts | 22 +++++++++++++++++ src/002-config/fc-version.js | 2 +- .../backwardsCompatibility/datatypeCleanup.js | 6 ++--- src/data/patches/patch.js | 19 +++++++-------- .../releases/1261_fixBrokenEyesAndPartners.js | 4 ++-- .../patches/releases/1266_fixPartnersAgain.js | 10 ++++++++ src/data/verification/verifyHumanState.js | 2 +- src/data/verification/verifyUtils.js | 5 ++-- src/data/verification/zVerify.js | 1 - src/debugging/debugJS.js | 10 ++++++-- src/events/intro/customizeSlaveTrade.js | 4 ++-- src/events/intro/introSummary.js | 4 ++-- src/facilities/dressingRoom/dressingRoom.js | 4 ++-- src/js/displayVariables.js | 2 +- src/js/releaseRules.js | 2 +- src/js/rulesAssistantOptions.js | 10 ++++---- src/js/rulesAssistantSummary.js | 4 ++-- src/js/states/001-GenePoolRecord.js | 6 ++--- src/js/storyJS.js | 2 +- src/js/utilsSlave.js | 2 +- src/npc/importSlave.js | 6 ++--- src/npc/slaveBot/generateSlaveBot.js | 24 +++++++++---------- 22 files changed, 92 insertions(+), 59 deletions(-) create mode 100644 src/data/patches/releases/1266_fixPartnersAgain.js diff --git a/devTools/types/SugarCubeExtensions.d.ts b/devTools/types/SugarCubeExtensions.d.ts index a4971ee3f33..ef0899024f2 100644 --- a/devTools/types/SugarCubeExtensions.d.ts +++ b/devTools/types/SugarCubeExtensions.d.ts @@ -12,11 +12,33 @@ declare module "twine-sugarcube" { interface StateAPI { expired: StoryMoment[]; clearTemporary(): void; + /** + * Restores the game state to the last state it was in. + * Usually the state that it was in when the latest passage was loaded + */ + restore(): void; } interface UIBarAPI { update(): void; } + + interface SerialAPI { + /** + * Converts a JavaScript Object Notation (JSON) string with custom revival methods into an object. + * @param text A valid JSON string created using Serial.stringify(). + * @param reviver A function that transforms the results. This function is called for each member of the object. + * If a member contains nested objects, the nested objects are transformed before the parent object is. + */ + parse(text: string, reviver?: (this: any, key: string, value: any) => any): any; + /** + * Converts a JavaScript value to a JavaScript Object Notation (JSON) string with custom revival methods. + * @param value A JavaScript value, usually an object or array, to be converted. + * @param replacer A function that transforms the results. + * @param space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read. + */ + stringify(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string; + } } export {}; diff --git a/src/002-config/fc-version.js b/src/002-config/fc-version.js index e8d4759972f..7676d245b18 100644 --- a/src/002-config/fc-version.js +++ b/src/002-config/fc-version.js @@ -10,5 +10,5 @@ App.Version = { * The release numbers got messed up, this is corrected in `src/js/eventHandlers.js` and `/src/data/patches/patch.js`. * The two line above and this line should be safe to remove after release 2001. */ - release: 1265, + release: 1266, }; diff --git a/src/data/backwardsCompatibility/datatypeCleanup.js b/src/data/backwardsCompatibility/datatypeCleanup.js index d07247ac764..fafad5265fd 100644 --- a/src/data/backwardsCompatibility/datatypeCleanup.js +++ b/src/data/backwardsCompatibility/datatypeCleanup.js @@ -2446,7 +2446,7 @@ App.Update.RARuleDatatypeCleanup = function() { if (count === 0) { count++; cond.activation = [false]; - console.log("no match", JSON.parse(JSON.stringify(cond))); + console.log("no match", Serial.parse(Serial.stringify(cond))); } cond.activation.push(count, "and"); } @@ -2455,7 +2455,7 @@ App.Update.RARuleDatatypeCleanup = function() { cond.activation = [false, 1, "and"]; } } catch (e) { - console.log("condition broke", e.message, JSON.parse(JSON.stringify(cond))); + console.log("condition broke", e.message, Serial.parse(Serial.stringify(cond))); cond.activation = [false, 1, "and"]; } finally { delete cond.function; @@ -2487,7 +2487,7 @@ App.Update.RARuleDatatypeCleanup = function() { } } } catch (e) { - console.log("assignments broke", e.message, JSON.parse(JSON.stringify(cond))); + console.log("assignments broke", e.message, Serial.parse(Serial.stringify(cond))); } finally { // @ts-ignore delete cond.assignment; diff --git a/src/data/patches/patch.js b/src/data/patches/patch.js index 4a6a712a25f..8c995fc9e4d 100644 --- a/src/data/patches/patch.js +++ b/src/data/patches/patch.js @@ -180,7 +180,6 @@ App.Patch.applyAll = () => { if (App.Verify.Utils.verificationError) { header.innerHTML += `<span class="error">Verification failed!</span>`; console.error("Verification failed!"); - // @ts-ignore State.restore(); // restore the state to before patching } else { if (patchCount !== 0) { @@ -231,7 +230,6 @@ App.Patch.applyAll = () => { header.innerHTML += `<span class="error">Verification failed!</span>`; console.error("Verification failed!"); App.Patch.Utils.current.div.append(App.UI.DOM.formatException(e)); - // @ts-ignore State.restore(); // restore the state to before patching header.innerHTML += `<br><span>See below for details</span><hr>`; // close the loading screen so that the user can see the error @@ -269,14 +267,14 @@ App.Patch.applyAll = () => { App.Patch.Utils.playerState("V.PC", V.PC, "V.PC", App.Patch.Utils.current.div, patchID); wombs.push({identifier: `V.PC`, actor: V.PC, div: App.Patch.Utils.current.div}); - // SlaveState - const slaves = getSlaves(); - for (i in slaves ?? []) { - App.Patch.Utils.slaveState( - `getSlaves()[${i}]`, slaves[i], "main slave pool", App.Patch.Utils.current.div, patchID - ); - wombs.push({identifier: `getSlaves()[${i}]`, actor: slaves[i], div: App.Patch.Utils.current.div}); - } + // SlaveState + const slaves = getSlaves(); + for (i in slaves ?? []) { + App.Patch.Utils.slaveState( + `getSlaves()[${i}]`, slaves[i], "main slave pool", App.Patch.Utils.current.div, patchID + ); + wombs.push({identifier: `getSlaves()[${i}]`, actor: slaves[i], div: App.Patch.Utils.current.div}); + } if (V.hostage) { App.Patch.Utils.slaveState( @@ -361,7 +359,6 @@ App.Patch.applyAll = () => { } catch (e) { header.innerHTML += `<span class="error">Patching Failed when applying patch ${App.Patch.Utils.current.patch}["${App.Patch.Utils.current.type}"] to ${App.Patch.Utils.current.identifier}!</span>`; App.Patch.Utils.current.div.append(App.UI.DOM.formatException(e)); - // @ts-ignore State.restore(); // restore the state to before patching header.innerHTML += `<br><span>See below for details</span><hr>`; // close the loading screen so that the user can see the error diff --git a/src/data/patches/releases/1261_fixBrokenEyesAndPartners.js b/src/data/patches/releases/1261_fixBrokenEyesAndPartners.js index 9daad3875cb..96ff6f736a7 100644 --- a/src/data/patches/releases/1261_fixBrokenEyesAndPartners.js +++ b/src/data/patches/releases/1261_fixBrokenEyesAndPartners.js @@ -10,7 +10,7 @@ App.Patch.register({ if (Array.isArray(actor.partners)) { actor.partners = new Set(getProp(actor, "partners")); } else { - App.Patch.log(`partners was '${JSON.stringify(actor.partners)}' of type '${typeof actor.partners}', setting partners to an empty set`); + App.Patch.log(`partners was '${Serial.stringify(actor.partners)}' of type '${typeof actor.partners}', setting partners to an empty set`); actor.partners = new Set([]); } } @@ -47,7 +47,7 @@ App.Patch.register({ App.Utils.assignMissingDefaults(actor.eye.right, defaultEye.right); } actor.eye.origColor = actor.eye.origColor ?? origColor; - if (JSON.stringify(origEye) !== JSON.stringify(actor.eye)) { + if (Serial.stringify(origEye) !== Serial.stringify(actor.eye)) { App.Patch.log('Fixed corrupted eye object'); } deleteProps(actor, "eyeColor"); diff --git a/src/data/patches/releases/1266_fixPartnersAgain.js b/src/data/patches/releases/1266_fixPartnersAgain.js new file mode 100644 index 00000000000..359c8724022 --- /dev/null +++ b/src/data/patches/releases/1266_fixPartnersAgain.js @@ -0,0 +1,10 @@ +App.Patch.register({ + releaseID: 1266, + descriptionOfChanges: `Recent changes to SC meant that imported/exported slaves were not serialized correctly. This 'fixes' (data is lost) those slaves.`, + humanState: (div, actor, location) => { + if (!(actor.partners instanceof Set)) { + actor.partners = new Set([]); + } + return actor; + } +}); diff --git a/src/data/verification/verifyHumanState.js b/src/data/verification/verifyHumanState.js index cb210f2caed..69cf4d65821 100644 --- a/src/data/verification/verifyHumanState.js +++ b/src/data/verification/verifyHumanState.js @@ -76,7 +76,7 @@ App.Verify.I.humanHealth = (actor, location) => { * @see updateHealth * To get around this issue we are only running updateHealth(actor) if the values were actually changed by this function */ - if (JSON.stringify(oldHealth) !== JSON.stringify(actor.health)) { + if (Serial.stringify(oldHealth) !== Serial.stringify(actor.health)) { updateHealth(actor); } return actor; diff --git a/src/data/verification/verifyUtils.js b/src/data/verification/verifyUtils.js index be0b47d88eb..90d21cf568b 100644 --- a/src/data/verification/verifyUtils.js +++ b/src/data/verification/verifyUtils.js @@ -29,7 +29,7 @@ App.Verify.Utils.findSlaveId = (predicate) => { App.Verify.Utils.changeSummary = (obj1, obj2, setKey, instructionID, identifier) => { const temp = `When executing 'App.Verify.instructions.${setKey}.${instructionID}': '{path}' {change}`; - if (JSON.stringify(obj1) === JSON.stringify(obj2)) { return undefined; } // Quick and dirty comparision, don't do work when it isn't needed + if (Serial.stringify(obj1) === Serial.stringify(obj2)) { return undefined; } // Quick and dirty comparision, don't do work when it isn't needed // something has changed, deep comparision needed /** @@ -42,7 +42,7 @@ App.Verify.Utils.changeSummary = (obj1, obj2, setKey, instructionID, identifier) /** @type {App.Verify.Utils.ChangeRecord[]} */ let changes = []; - if (JSON.stringify(obj1) === JSON.stringify(obj2)) { return changes; } // don't do work when it isn't needed + if (Serial.stringify(obj1) === Serial.stringify(obj2)) { return changes; } // don't do work when it isn't needed let keys1 = Object.keys(obj1); let keys2 = Object.keys(obj2); @@ -178,7 +178,6 @@ App.Verify.Utils.verify = (setKey, identifier, obj, extra, div) => { } if (isV) { // rollback the game state - // @ts-ignore restore does exist on our custom SugarCube State.restore(); // and return nothing return; diff --git a/src/data/verification/zVerify.js b/src/data/verification/zVerify.js index 5972d8589c1..fbb53f4296d 100644 --- a/src/data/verification/zVerify.js +++ b/src/data/verification/zVerify.js @@ -283,7 +283,6 @@ App.Verify.everything = (div, callback) => { console.error(e); console.error("Verification failed!"); } - // @ts-ignore State.restore(); // restore the state to before patching // close the loading screen (if it is open) so that the user can see the error App.Patch.Utils.loadingScreen.end(); diff --git a/src/debugging/debugJS.js b/src/debugging/debugJS.js index dfc06f84247..61fda059a51 100644 --- a/src/debugging/debugJS.js +++ b/src/debugging/debugJS.js @@ -107,12 +107,18 @@ App.Debug.dumpGameState = function() { } const handler = (save) => { - downloadToFile(JSON.stringify(save, null, 2), save.id + ".json", "text/plain"); + let name = save.id + ".json"; + try { + name = App.Utils.getSaveFilename(undefined, "json"); + } catch (ex) { + console.error(ex); + } + downloadToFile(Serial.stringify(save, null, 2), name, "text/plain"); }; Save.onSave.add(handler); try { - SugarCube.Save.base64.save(); + Save.base64.save(); } finally { Save.onSave.delete(handler); } diff --git a/src/events/intro/customizeSlaveTrade.js b/src/events/intro/customizeSlaveTrade.js index aceb9beccb7..3d0483c9888 100644 --- a/src/events/intro/customizeSlaveTrade.js +++ b/src/events/intro/customizeSlaveTrade.js @@ -394,7 +394,7 @@ App.Intro.CustomSlaveTrade = function() { */ function settingsExport(container) { let textArea = document.createElement("textarea"); - textArea.value = JSON.stringify(V.nationalities); + textArea.value = Serial.stringify(V.nationalities); $(container).empty().append(textArea); } @@ -407,7 +407,7 @@ App.Intro.CustomSlaveTrade = function() { button.append("Load"); button.onclick = () => { try { - V.nationalities = JSON.parse(textArea.value); + V.nationalities = Serial.parse(textArea.value); } catch (SyntaxError) { Dialog.create("Invalid Input"); Dialog.append("The input is not a valid nationalities object."); diff --git a/src/events/intro/introSummary.js b/src/events/intro/introSummary.js index a1720a0ce8b..06983579f46 100644 --- a/src/events/intro/introSummary.js +++ b/src/events/intro/introSummary.js @@ -26,7 +26,7 @@ App.Intro.getNondefaultOptionsAsObject = function(exportFrom = V, defaults = App }; App.Intro.getNondefaultOptionsAsJSON = function() { - return JSON.stringify(App.Intro.getNondefaultOptionsAsObject(), null, 2); + return Serial.stringify(App.Intro.getNondefaultOptionsAsObject(), null, 2); }; App.Intro.summary = function() { @@ -436,7 +436,7 @@ App.Intro.summary = function() { App.UI.DOM.link( "Import game options", () => { - const optionsFromJSON = JSON.parse(textareaElement.value); + const optionsFromJSON = Serial.parse(textareaElement.value); const tooltipsEnabled = V.tooltipsEnabled; App.Intro.assignOnlyMatchingKeys(V, optionsFromJSON, App.Data.defaultGameOptions); if (tooltipsEnabled !== V.tooltipsEnabled) { diff --git a/src/facilities/dressingRoom/dressingRoom.js b/src/facilities/dressingRoom/dressingRoom.js index 68250d55381..a75b874acf1 100644 --- a/src/facilities/dressingRoom/dressingRoom.js +++ b/src/facilities/dressingRoom/dressingRoom.js @@ -418,7 +418,7 @@ App.UI.DressingRoom.render = function() { cont.appendChild(element); } // @ts-ignore - element.value = JSON.stringify(V.customClothesPrompts, null, 2); + element.value = Serial.stringify(V.customClothesPrompts, null, 2); } ), App.UI.DOM.link( @@ -438,7 +438,7 @@ App.UI.DressingRoom.render = function() { submitBtn.onclick = () => { try { // @ts-ignore - V.customClothesPrompts = JSON.parse(element.value); + V.customClothesPrompts = Serial.parse(element.value); options.refresh(); } catch (e) { alert(`Couldn't import prompts:\n${e.message}`); diff --git a/src/js/displayVariables.js b/src/js/displayVariables.js index c80544ca7f8..c065dc7786a 100644 --- a/src/js/displayVariables.js +++ b/src/js/displayVariables.js @@ -8,7 +8,7 @@ App.checkVars = function() { case"number": return isNaN(value) ? "NaN" : isFinite(value) ? String(value) : "Infinity"; case"string": - return JSON.stringify(value); + return Serial.stringify(value); case"function": return "(function)"; default: diff --git a/src/js/releaseRules.js b/src/js/releaseRules.js index 892774cbb9a..e08dffc2319 100644 --- a/src/js/releaseRules.js +++ b/src/js/releaseRules.js @@ -336,7 +336,7 @@ App.Utils.testAllReleaseText = function testAllReleaseText() { rule.master = Number(bits[4]); slave.rules.release = rule; - r += JSON.stringify(rule) + "\n"; + r += Serial.stringify(rule) + "\n"; r += App.Utils.releaseSummaryShort(slave) + "\n"; r += App.Utils.releaseSummaryLong(slave) + "\n"; r += App.Desc.releaseDesc(slave) + "\n"; diff --git a/src/js/rulesAssistantOptions.js b/src/js/rulesAssistantOptions.js index 1d8eae27a20..996bfa1ed13 100644 --- a/src/js/rulesAssistantOptions.js +++ b/src/js/rulesAssistantOptions.js @@ -418,7 +418,7 @@ App.RA.options = (function() { } else { selected = this.children.filter(listItem => this.dataEqual(listItem.data, dataValue)); } - if (selected.length > 1) { throw Error(`Multiple shortcuts matched ${JSON.stringify(dataValue)}`); } + if (selected.length > 1) { throw Error(`Multiple shortcuts matched ${Serial.stringify(dataValue)}`); } if (selected.length === 1) { const listItem = selected[0]; listItem.select(false); @@ -1214,7 +1214,7 @@ App.RA.options = (function() { loadNewRule() { const text = this.textarea.value; try { - const rule = JSON.parse(text); + const rule = Serial.parse(text); if (Array.isArray(rule)) { rule.forEach(r => { r.ID = generateNewID(); @@ -1385,12 +1385,12 @@ App.RA.options = (function() { class ExportField extends Element { render(...args) { - let element = document.getElementById("exportfield"); + let element = /** @type {HTMLTextAreaElement} */ (document.getElementById("exportfield")); if (element === null) { element = document.createElement("textarea"); element.id = "exportfield"; } - element.value = JSON.stringify(args, null, 2); + element.value = Serial.stringify(args, null, 2); return element; } } @@ -4548,7 +4548,7 @@ App.RA.options = (function() { } else { selected = this.children.filter(listItem => this.dataEqual(listItem.data, dataValue)); } - if (selected.length > 1) { throw Error(`Multiple shortcuts matched ${JSON.stringify(dataValue)}`); } + if (selected.length > 1) { throw Error(`Multiple shortcuts matched ${Serial.stringify(dataValue)}`); } if (selected.length === 1) { const listItem = selected[0]; listItem.select(false); diff --git a/src/js/rulesAssistantSummary.js b/src/js/rulesAssistantSummary.js index aaac0045430..c1720ceaec5 100644 --- a/src/js/rulesAssistantSummary.js +++ b/src/js/rulesAssistantSummary.js @@ -104,10 +104,10 @@ App.RA.summary = function() { } else if (v.hasOwnProperty('min') && v.hasOwnProperty('max')) { return `${v.min} to ${v.max}`; } else { - return JSON.stringify(v); + return Serial.stringify(v); } } else if (Array.isArray(v)) { - return JSON.stringify(v); + return Serial.stringify(v); } return `${v}`; } diff --git a/src/js/states/001-GenePoolRecord.js b/src/js/states/001-GenePoolRecord.js index 68a157eca9d..b09d57dbb79 100644 --- a/src/js/states/001-GenePoolRecord.js +++ b/src/js/states/001-GenePoolRecord.js @@ -26,7 +26,7 @@ globalThis.getGenePoolRecord = (key, missingOkay=false, write=false) => { } else if (typeof key === "object" && "ID" in key) { ID = String(key.ID); } else { - throw new Error(`key must be an FC.HumanState object or valid HumanState.ID! Got: ${JSON.stringify(key)}`); + throw new Error(`key must be an FC.HumanState object or valid HumanState.ID! Got: ${Serial.stringify(key)}`); } if (ID === "0") { console.warn(new Error("getGenePoolRecord: actors with an ID equal to 0 cannot exist in the gene pool")); @@ -94,7 +94,7 @@ globalThis.isInGenePool = (key) => { } else if (typeof key === "object" && "ID" in key) { ID = String(key.ID); } else { - throw new Error(`key must be an FC.HumanState object or valid HumanState.ID! Got: ${JSON.stringify(key)}`); + throw new Error(`key must be an FC.HumanState object or valid HumanState.ID! Got: ${Serial.stringify(key)}`); } if (ID in V.genePool) { return true; @@ -169,7 +169,7 @@ globalThis.addToGenePool = (actor) => { continue; } if (key in template) { - if (JSON.stringify(obj[key]) === JSON.stringify(template[key])) { + if (Serial.stringify(obj[key]) === Serial.stringify(template[key])) { delete obj[key]; } else if (obj[key] && typeof obj[key] === "object" && !Array.isArray(obj[key])) { if (template[key] && typeof template[key] === "object" && !Array.isArray(template[key])) { diff --git a/src/js/storyJS.js b/src/js/storyJS.js index 8704a782666..cbb8e0bca46 100644 --- a/src/js/storyJS.js +++ b/src/js/storyJS.js @@ -459,7 +459,7 @@ globalThis.bodyguardSuccessorEligible = function(slave) { * @returns {string} */ globalThis.toJson = function(obj) { - let jsontext = JSON.stringify(obj); + let jsontext = Serial.stringify(obj); jsontext = jsontext.replace(/^{/, ""); jsontext = jsontext.replace(/}$/, ""); return jsontext; diff --git a/src/js/utilsSlave.js b/src/js/utilsSlave.js index c4fc5638987..d568e58f5d3 100644 --- a/src/js/utilsSlave.js +++ b/src/js/utilsSlave.js @@ -3831,7 +3831,7 @@ globalThis.getSlave = function(ID) { */ globalThis.overwriteSlave = function(ID, slave) { if (!slave || !(typeof slave === "object") || slave === null || Array.isArray(slave)) { - throw new Error(`Passed object is not a SlaveState object. Object: ${JSON.stringify(slave)}`); + throw new Error(`Passed object is not a SlaveState object. Object: ${Serial.stringify(slave)}`); } const index = V.slaveIndices[ID]; if (index !== undefined) { diff --git a/src/npc/importSlave.js b/src/npc/importSlave.js index 507504b57bb..7754d3e6291 100644 --- a/src/npc/importSlave.js +++ b/src/npc/importSlave.js @@ -44,7 +44,7 @@ App.UI.SlaveInteract.importSlaveFromCharacterCard = () => { const pngAb = await pngFile.arrayBuffer(); const allTextContent = App.UI.SlaveInteract.SlaveBot.Png.Parse(pngAb); - const slaveBotObj = JSON.parse(allTextContent); + const slaveBotObj = Serial.parse(allTextContent); /** * Parser returns the stuff we care about under "data". * @type {FC.SlaveBot.CharacterBook} @@ -95,7 +95,7 @@ App.UI.SlaveInteract.importSlaveFromString = (slaveSrc, div) => { if (slaveSrc[0] !== "{") { slaveSrc = "{" + slaveSrc; } if (slaveSrc.slice(-1) !== "}") { slaveSrc += "}"; } // generate slave - let slave = JSON.parse(slaveSrc); + let slave = Serial.parse(slaveSrc); slave.ID = generateSlaveID(); App.Verify.slaveState("<imported>", slave, "none", div); if (slave?.assignment) { @@ -112,7 +112,7 @@ App.UI.SlaveInteract.exportSlave = function(slave) { const exportSlave = _.cloneDeep(slave); App.Verify.slaveState("<exported>", exportSlave, "none"); exportSlave.ID = 0; - return JSON.stringify(exportSlave, null, 2); + return Serial.stringify(exportSlave, null, 2); }; /** diff --git a/src/npc/slaveBot/generateSlaveBot.js b/src/npc/slaveBot/generateSlaveBot.js index 9c8af462b0a..ab60f0e75a2 100644 --- a/src/npc/slaveBot/generateSlaveBot.js +++ b/src/npc/slaveBot/generateSlaveBot.js @@ -23,7 +23,7 @@ App.UI.SlaveInteract.SlaveBot.createSlaveBot = (slave) => { /** - * + * * @param {File} pngFile File from <input type="file" /> */ App.UI.SlaveInteract.SlaveBot.importSlavePNG = async (pngFile) => { @@ -34,7 +34,7 @@ App.UI.SlaveInteract.SlaveBot.importSlavePNG = async (pngFile) => { /** * @type {FC.SlaveBot.CharacterBook} */ - const slaveBotData = JSON.parse(allTextContent); + const slaveBotData = Serial.parse(allTextContent); if (!slaveBotData.extensions.freecitiesJSON) { alert("No Free Cities data found from this character card. Maybe it is corrupted?"); @@ -297,7 +297,7 @@ App.UI.SlaveInteract.SlaveBot.downloadFile = (file) => { * @returns {File} */ App.UI.SlaveInteract.SlaveBot.exportJsonFile = (characterCard) => { - const file = new File([JSON.stringify(characterCard, undefined, '\t')], `${characterCard.data.name || 'character'}.card.json`, { type: 'application/json;charset=utf-8' }); + const file = new File([Serial.stringify(characterCard, undefined, '\t')], `${characterCard.data.name || 'character'}.card.json`, {type: 'application/json;charset=utf-8'}); return file; }; @@ -312,7 +312,7 @@ App.UI.SlaveInteract.SlaveBot.exportFile = async (slaveState) => { if (V.aiCachingStrategy === 'static') { const displayedIdx = slaveState.custom.aiDisplayImageIdx; const imageDbId = slaveState.custom.aiImageIds[displayedIdx]; - const { data } = await App.Art.GenAI.staticImageDB.getImage(imageDbId); + const {data} = await App.Art.GenAI.staticImageDB.getImage(imageDbId); imageUrl = data; } else { @@ -335,23 +335,23 @@ App.UI.SlaveInteract.SlaveBot.exportFile = async (slaveState) => { - const json = JSON.stringify(characterCardObj, undefined, '\t'); + const json = Serial.stringify(characterCardObj, undefined, '\t'); const png = App.UI.SlaveInteract.Png.Generate(imageArrayBuffer, json); - const file = new File([png], `${characterCardObj.data.name || 'character'}.card.png`, { type: 'image/png' }); + const file = new File([png], `${characterCardObj.data.name || 'character'}.card.png`, {type: 'image/png'}); return file; } catch (e) { - const { fallbackImage, createCharacterDataFromSlave } = App.UI.SlaveInteract.SlaveBot; + const {fallbackImage, createCharacterDataFromSlave} = App.UI.SlaveInteract.SlaveBot; const imageRes = await fetch(fallbackImage); const imageArrayBuffer = await imageRes.arrayBuffer(); const characterCardObj = createCharacterDataFromSlave(slaveState); - const json = JSON.stringify(characterCardObj, undefined, '\t'); + const json = Serial.stringify(characterCardObj, undefined, '\t'); const png = App.UI.SlaveInteract.SlaveBot.Png.Generate(imageArrayBuffer, json); - const file = new File([png], `${characterCardObj.data.name || 'character'}.card.png`, { type: 'image/png' }); + const file = new File([png], `${characterCardObj.data.name || 'character'}.card.png`, {type: 'image/png'}); return file; } }; @@ -428,7 +428,7 @@ App.UI.SlaveInteract.SlaveBot.createCharacterDataFromSlave = (slave) => { */ App.UI.SlaveInteract.SlaveBot.Generate.description = (slave) => { let r = []; - const { he, his } = getPronouns(slave); + const {he, his} = getPronouns(slave); let descParts = []; // NAME @@ -869,7 +869,7 @@ App.UI.SlaveInteract.SlaveBot.Generate.standardPrompt = () => { */ App.UI.SlaveInteract.SlaveBot.Generate.firstMessage = (slave) => { let r = []; - const { He, His, he, his } = getPronouns(slave); + const {He, His, he, his} = getPronouns(slave); // Set up basic scenario r.push("I am sitting in my office as {{char}} arrives for inspection.\r\n"); @@ -1319,7 +1319,7 @@ App.UI.SlaveInteract.SlaveBot.Generate.lorebookHeadGirl = (startId) => { keys: ["Head Girl", "headgirl", S.HeadGirl.slaveName], // either/or title, first name secondary_keys: [], // not used comment: "HeadGirl", - content: App.UI.SlaveInteract.SlaveBot.Generate.description(S.HeadGirl) + "/nThe head girl manages the health, training, and wellbeing of all slaves in your penthouse, and ensures your businesses are running smoothly.",// slave description minus relationships + content: App.UI.SlaveInteract.SlaveBot.Generate.description(S.HeadGirl) + "/nThe head girl manages the health, training, and wellbeing of all slaves in your penthouse, and ensures your businesses are running smoothly.", // slave description minus relationships constant: false, // selectively applied selective: false, insertion_order: 100, -- GitLab