mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2026-04-16 06:18:42 +02:00
* Use Compression Streams API instead of jszip or other libraries. * Remove usage of base64 in the new binary format. * Do not convert binary data to string and back. The type of save data is SaveData, it's either string (old base64 format) or Uint8Array (new binary format). * Proper support for interacting with electron-related code. Electron-related code assumes that save data is in the base64 format. * Proper support for other tools (DevMenu, pretty-save.js). Full support for DevMenu will be added in a follow-up PR. Check the comments in src\DevMenu\ui\SaveFileDev.tsx for details.
60 lines
2.1 KiB
TypeScript
60 lines
2.1 KiB
TypeScript
import { SaveData } from "../types";
|
|
|
|
export abstract class SaveDataError extends Error {
|
|
constructor(message: string) {
|
|
super(message);
|
|
this.name = this.constructor.name;
|
|
}
|
|
}
|
|
|
|
export class UnsupportedSaveData extends SaveDataError {}
|
|
|
|
export class InvalidSaveData extends SaveDataError {}
|
|
|
|
export function canUseBinaryFormat(): boolean {
|
|
return "CompressionStream" in globalThis;
|
|
}
|
|
|
|
async function compress(dataString: string): Promise<Uint8Array> {
|
|
const compressedReadableStream = new Blob([dataString]).stream().pipeThrough(new CompressionStream("gzip"));
|
|
return new Uint8Array(await new Response(compressedReadableStream).arrayBuffer());
|
|
}
|
|
|
|
async function decompress(binaryData: Uint8Array): Promise<string> {
|
|
const decompressedReadableStream = new Blob([binaryData]).stream().pipeThrough(new DecompressionStream("gzip"));
|
|
const reader = decompressedReadableStream.pipeThrough(new TextDecoderStream("utf-8", { fatal: true })).getReader();
|
|
let result = "";
|
|
try {
|
|
for (let { value, done } = await reader.read(); !done; { value, done } = await reader.read()) {
|
|
result += value;
|
|
}
|
|
} catch (error) {
|
|
throw new InvalidSaveData(String(error));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
export async function encodeJsonSaveString(jsonSaveString: string): Promise<SaveData> {
|
|
// Fallback to the base64 format if player's browser does not support Compression Streams API.
|
|
if (canUseBinaryFormat()) {
|
|
return await compress(jsonSaveString);
|
|
} else {
|
|
// The unescape(encodeURIComponent()) pair encodes jsonSaveString into a "binary string" suitable for btoa, despite
|
|
// seeming like a no-op at first glance.
|
|
// Ref: https://stackoverflow.com/a/57713220
|
|
return btoa(unescape(encodeURIComponent(jsonSaveString)));
|
|
}
|
|
}
|
|
|
|
/** Return json save string */
|
|
export async function decodeSaveData(saveData: SaveData): Promise<string> {
|
|
if (saveData instanceof Uint8Array) {
|
|
if (!canUseBinaryFormat()) {
|
|
throw new UnsupportedSaveData("Your browser does not support Compression Streams API");
|
|
}
|
|
return await decompress(saveData);
|
|
} else {
|
|
return decodeURIComponent(escape(atob(saveData)));
|
|
}
|
|
}
|