2022-10-10 00:42:14 +02:00
|
|
|
import { Player } from "@player";
|
2022-01-18 18:21:53 +01:00
|
|
|
import { Router } from "./ui/GameRoot";
|
2023-06-26 10:24:37 +02:00
|
|
|
import { Page } from "./ui/Router";
|
2022-01-05 01:09:34 +01:00
|
|
|
import { Terminal } from "./Terminal";
|
2023-06-12 06:34:20 +02:00
|
|
|
import { SnackbarEvents } from "./ui/React/Snackbar";
|
|
|
|
import { ToastVariant } from "@enums";
|
2024-03-28 05:08:09 +01:00
|
|
|
import { IReturnStatus, SaveData } from "./types";
|
2022-01-06 13:04:03 +01:00
|
|
|
import { GetServer } from "./Server/AllServers";
|
2024-03-28 05:08:09 +01:00
|
|
|
import { ImportPlayerData, ElectronGameData, saveObject } from "./SaveObject";
|
2022-01-18 18:21:53 +01:00
|
|
|
import { exportScripts } from "./Terminal/commands/download";
|
|
|
|
import { CONSTANTS } from "./Constants";
|
|
|
|
import { hash } from "./hash/hash";
|
FILES: Path rework & typesafety (#479)
* Added new types for various file paths, all in the Paths folder.
* TypeSafety and other helper functions related to these types
* Added basic globbing support with * and ?. Currently only implemented for Script/Text, on nano and download terminal commands
* Enforcing the new types throughout the codebase, plus whatever rewrites happened along the way
* Server.textFiles is now a map
* TextFile no longer uses a fn property, now it is filename
* Added a shared ContentFile interface for shared functionality between TextFile and Script.
* related to ContentFile change above, the player is now allowed to move a text file to a script file and vice versa.
* File paths no longer conditionally start with slashes, and all directory names other than root have ending slashes. The player is still able to provide paths starting with / but this now indicates that the player is specifying an absolute path instead of one relative to root.
* Singularized the MessageFilename and LiteratureName enums
* Because they now only accept correct types, server.writeToXFile functions now always succeed (the only reasons they could fail before were invalid filepath).
* Fix several issues with tab completion, which included pretty much a complete rewrite
* Changed the autocomplete display options so there's less chance it clips outside the display area.
* Turned CompletedProgramName into an enum.
* Got rid of programsMetadata, and programs and DarkWebItems are now initialized immediately instead of relying on initializers called from the engine.
* For any executable (program, cct, or script file) pathing can be used directly to execute without using the run command (previously the command had to start with ./ and it wasn't actually using pathing).
2023-04-24 16:26:57 +02:00
|
|
|
import { resolveFilePath } from "./Paths/FilePath";
|
|
|
|
import { hasScriptExtension } from "./Paths/ScriptFilePath";
|
2021-11-27 21:07:25 +01:00
|
|
|
|
2022-04-19 02:47:33 +02:00
|
|
|
interface IReturnWebStatus extends IReturnStatus {
|
|
|
|
data?: Record<string, unknown>;
|
|
|
|
}
|
|
|
|
|
|
|
|
declare global {
|
|
|
|
interface Window {
|
|
|
|
appNotifier: {
|
|
|
|
terminal: (message: string, type?: string) => void;
|
|
|
|
toast: (message: string, type: ToastVariant, duration?: number) => void;
|
|
|
|
};
|
|
|
|
appSaveFns: {
|
|
|
|
triggerSave: () => Promise<void>;
|
|
|
|
triggerGameExport: () => void;
|
|
|
|
triggerScriptsExport: () => void;
|
2024-03-28 05:08:09 +01:00
|
|
|
getSaveData: () => Promise<{ save: SaveData; fileName: string }>;
|
|
|
|
getSaveInfo: (saveData: SaveData) => Promise<ImportPlayerData | undefined>;
|
|
|
|
pushSaveData: (saveData: SaveData, automatic?: boolean) => void;
|
2022-04-19 02:47:33 +02:00
|
|
|
};
|
|
|
|
electronBridge: {
|
|
|
|
send: (channel: string, data?: unknown) => void;
|
2022-07-20 05:26:21 +02:00
|
|
|
receive: (channel: string, func: (...args: unknown[]) => void) => void;
|
2022-04-19 02:47:33 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
interface Document {
|
|
|
|
getFiles: () => IReturnWebStatus;
|
|
|
|
deleteFile: (filename: string) => IReturnWebStatus;
|
|
|
|
saveFile: (filename: string, code: string) => IReturnWebStatus;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-27 21:07:25 +01:00
|
|
|
export function initElectron(): void {
|
2022-01-03 16:33:58 +01:00
|
|
|
const userAgent = navigator.userAgent.toLowerCase();
|
2023-05-05 09:55:59 +02:00
|
|
|
if (userAgent.includes(" electron/")) {
|
2022-01-03 16:33:58 +01:00
|
|
|
// Electron-specific code
|
2022-04-19 02:47:33 +02:00
|
|
|
document.achievements = [];
|
2022-01-03 16:33:58 +01:00
|
|
|
initWebserver();
|
|
|
|
initAppNotifier();
|
2022-01-18 18:21:53 +01:00
|
|
|
initSaveFunctions();
|
|
|
|
initElectronBridge();
|
2022-01-03 16:33:58 +01:00
|
|
|
}
|
2021-11-27 21:07:25 +01:00
|
|
|
}
|
2021-12-21 19:41:11 +01:00
|
|
|
|
|
|
|
function initWebserver(): void {
|
2022-04-19 02:47:33 +02:00
|
|
|
document.getFiles = function (): IReturnWebStatus {
|
2022-01-20 09:03:07 +01:00
|
|
|
const home = GetServer("home");
|
FILES: Path rework & typesafety (#479)
* Added new types for various file paths, all in the Paths folder.
* TypeSafety and other helper functions related to these types
* Added basic globbing support with * and ?. Currently only implemented for Script/Text, on nano and download terminal commands
* Enforcing the new types throughout the codebase, plus whatever rewrites happened along the way
* Server.textFiles is now a map
* TextFile no longer uses a fn property, now it is filename
* Added a shared ContentFile interface for shared functionality between TextFile and Script.
* related to ContentFile change above, the player is now allowed to move a text file to a script file and vice versa.
* File paths no longer conditionally start with slashes, and all directory names other than root have ending slashes. The player is still able to provide paths starting with / but this now indicates that the player is specifying an absolute path instead of one relative to root.
* Singularized the MessageFilename and LiteratureName enums
* Because they now only accept correct types, server.writeToXFile functions now always succeed (the only reasons they could fail before were invalid filepath).
* Fix several issues with tab completion, which included pretty much a complete rewrite
* Changed the autocomplete display options so there's less chance it clips outside the display area.
* Turned CompletedProgramName into an enum.
* Got rid of programsMetadata, and programs and DarkWebItems are now initialized immediately instead of relying on initializers called from the engine.
* For any executable (program, cct, or script file) pathing can be used directly to execute without using the run command (previously the command had to start with ./ and it wasn't actually using pathing).
2023-04-24 16:26:57 +02:00
|
|
|
if (home === null) return { res: false, msg: "Home server does not exist." };
|
2022-01-20 09:03:07 +01:00
|
|
|
return {
|
|
|
|
res: true,
|
|
|
|
data: {
|
2023-04-18 09:19:45 +02:00
|
|
|
files: [...home.scripts.values()].map((script) => ({
|
2022-01-20 09:03:07 +01:00
|
|
|
filename: script.filename,
|
2022-01-22 05:49:12 +01:00
|
|
|
code: script.code,
|
2022-01-26 06:58:02 +01:00
|
|
|
ramUsage: script.ramUsage,
|
|
|
|
})),
|
|
|
|
},
|
|
|
|
};
|
2022-01-20 09:03:07 +01:00
|
|
|
};
|
|
|
|
|
2022-04-19 02:47:33 +02:00
|
|
|
document.deleteFile = function (filename: string): IReturnWebStatus {
|
FILES: Path rework & typesafety (#479)
* Added new types for various file paths, all in the Paths folder.
* TypeSafety and other helper functions related to these types
* Added basic globbing support with * and ?. Currently only implemented for Script/Text, on nano and download terminal commands
* Enforcing the new types throughout the codebase, plus whatever rewrites happened along the way
* Server.textFiles is now a map
* TextFile no longer uses a fn property, now it is filename
* Added a shared ContentFile interface for shared functionality between TextFile and Script.
* related to ContentFile change above, the player is now allowed to move a text file to a script file and vice versa.
* File paths no longer conditionally start with slashes, and all directory names other than root have ending slashes. The player is still able to provide paths starting with / but this now indicates that the player is specifying an absolute path instead of one relative to root.
* Singularized the MessageFilename and LiteratureName enums
* Because they now only accept correct types, server.writeToXFile functions now always succeed (the only reasons they could fail before were invalid filepath).
* Fix several issues with tab completion, which included pretty much a complete rewrite
* Changed the autocomplete display options so there's less chance it clips outside the display area.
* Turned CompletedProgramName into an enum.
* Got rid of programsMetadata, and programs and DarkWebItems are now initialized immediately instead of relying on initializers called from the engine.
* For any executable (program, cct, or script file) pathing can be used directly to execute without using the run command (previously the command had to start with ./ and it wasn't actually using pathing).
2023-04-24 16:26:57 +02:00
|
|
|
const path = resolveFilePath(filename);
|
|
|
|
if (!path) return { res: false, msg: "Invalid file path." };
|
2021-12-21 19:41:11 +01:00
|
|
|
const home = GetServer("home");
|
FILES: Path rework & typesafety (#479)
* Added new types for various file paths, all in the Paths folder.
* TypeSafety and other helper functions related to these types
* Added basic globbing support with * and ?. Currently only implemented for Script/Text, on nano and download terminal commands
* Enforcing the new types throughout the codebase, plus whatever rewrites happened along the way
* Server.textFiles is now a map
* TextFile no longer uses a fn property, now it is filename
* Added a shared ContentFile interface for shared functionality between TextFile and Script.
* related to ContentFile change above, the player is now allowed to move a text file to a script file and vice versa.
* File paths no longer conditionally start with slashes, and all directory names other than root have ending slashes. The player is still able to provide paths starting with / but this now indicates that the player is specifying an absolute path instead of one relative to root.
* Singularized the MessageFilename and LiteratureName enums
* Because they now only accept correct types, server.writeToXFile functions now always succeed (the only reasons they could fail before were invalid filepath).
* Fix several issues with tab completion, which included pretty much a complete rewrite
* Changed the autocomplete display options so there's less chance it clips outside the display area.
* Turned CompletedProgramName into an enum.
* Got rid of programsMetadata, and programs and DarkWebItems are now initialized immediately instead of relying on initializers called from the engine.
* For any executable (program, cct, or script file) pathing can be used directly to execute without using the run command (previously the command had to start with ./ and it wasn't actually using pathing).
2023-04-24 16:26:57 +02:00
|
|
|
if (!home) return { res: false, msg: "Home server does not exist." };
|
|
|
|
return home.removeFile(path);
|
2022-01-20 09:03:07 +01:00
|
|
|
};
|
|
|
|
|
2022-04-19 02:47:33 +02:00
|
|
|
document.saveFile = function (filename: string, code: string): IReturnWebStatus {
|
FILES: Path rework & typesafety (#479)
* Added new types for various file paths, all in the Paths folder.
* TypeSafety and other helper functions related to these types
* Added basic globbing support with * and ?. Currently only implemented for Script/Text, on nano and download terminal commands
* Enforcing the new types throughout the codebase, plus whatever rewrites happened along the way
* Server.textFiles is now a map
* TextFile no longer uses a fn property, now it is filename
* Added a shared ContentFile interface for shared functionality between TextFile and Script.
* related to ContentFile change above, the player is now allowed to move a text file to a script file and vice versa.
* File paths no longer conditionally start with slashes, and all directory names other than root have ending slashes. The player is still able to provide paths starting with / but this now indicates that the player is specifying an absolute path instead of one relative to root.
* Singularized the MessageFilename and LiteratureName enums
* Because they now only accept correct types, server.writeToXFile functions now always succeed (the only reasons they could fail before were invalid filepath).
* Fix several issues with tab completion, which included pretty much a complete rewrite
* Changed the autocomplete display options so there's less chance it clips outside the display area.
* Turned CompletedProgramName into an enum.
* Got rid of programsMetadata, and programs and DarkWebItems are now initialized immediately instead of relying on initializers called from the engine.
* For any executable (program, cct, or script file) pathing can be used directly to execute without using the run command (previously the command had to start with ./ and it wasn't actually using pathing).
2023-04-24 16:26:57 +02:00
|
|
|
const path = resolveFilePath(filename);
|
|
|
|
if (!path) return { res: false, msg: "Invalid file path." };
|
|
|
|
if (!hasScriptExtension(path)) return { res: false, msg: "Invalid file extension: must be a script" };
|
2021-12-21 19:41:11 +01:00
|
|
|
|
2024-03-28 05:08:09 +01:00
|
|
|
code = decodeURIComponent(escape(atob(code)));
|
2022-01-20 09:03:07 +01:00
|
|
|
const home = GetServer("home");
|
FILES: Path rework & typesafety (#479)
* Added new types for various file paths, all in the Paths folder.
* TypeSafety and other helper functions related to these types
* Added basic globbing support with * and ?. Currently only implemented for Script/Text, on nano and download terminal commands
* Enforcing the new types throughout the codebase, plus whatever rewrites happened along the way
* Server.textFiles is now a map
* TextFile no longer uses a fn property, now it is filename
* Added a shared ContentFile interface for shared functionality between TextFile and Script.
* related to ContentFile change above, the player is now allowed to move a text file to a script file and vice versa.
* File paths no longer conditionally start with slashes, and all directory names other than root have ending slashes. The player is still able to provide paths starting with / but this now indicates that the player is specifying an absolute path instead of one relative to root.
* Singularized the MessageFilename and LiteratureName enums
* Because they now only accept correct types, server.writeToXFile functions now always succeed (the only reasons they could fail before were invalid filepath).
* Fix several issues with tab completion, which included pretty much a complete rewrite
* Changed the autocomplete display options so there's less chance it clips outside the display area.
* Turned CompletedProgramName into an enum.
* Got rid of programsMetadata, and programs and DarkWebItems are now initialized immediately instead of relying on initializers called from the engine.
* For any executable (program, cct, or script file) pathing can be used directly to execute without using the run command (previously the command had to start with ./ and it wasn't actually using pathing).
2023-04-24 16:26:57 +02:00
|
|
|
if (!home) return { res: false, msg: "Home server does not exist." };
|
|
|
|
|
|
|
|
const { overwritten } = home.writeToScriptFile(path, code);
|
|
|
|
const script = home.scripts.get(path);
|
|
|
|
if (!script) return { res: false, msg: "Somehow failed to get script after writing it. This is a bug." };
|
|
|
|
|
|
|
|
const ramUsage = script.getRamUsage(home.scripts);
|
|
|
|
return { res: true, data: { overwritten, ramUsage } };
|
2021-12-21 19:41:11 +01:00
|
|
|
};
|
|
|
|
}
|
2022-01-03 16:32:01 +01:00
|
|
|
|
|
|
|
// Expose certain alert functions to allow the wrapper to sends message to the game
|
|
|
|
function initAppNotifier(): void {
|
|
|
|
const funcs = {
|
|
|
|
terminal: (message: string, type?: string) => {
|
2022-10-03 18:12:16 +02:00
|
|
|
const typesFn: Record<string, (s: string) => void> = {
|
2022-01-03 16:32:01 +01:00
|
|
|
info: Terminal.info,
|
|
|
|
warn: Terminal.warn,
|
|
|
|
error: Terminal.error,
|
2022-01-05 01:09:34 +01:00
|
|
|
success: Terminal.success,
|
2022-01-03 16:32:01 +01:00
|
|
|
};
|
|
|
|
let fn;
|
|
|
|
if (type) fn = typesFn[type];
|
|
|
|
if (!fn) fn = Terminal.print;
|
|
|
|
fn.bind(Terminal)(message);
|
|
|
|
},
|
2022-04-13 07:50:35 +02:00
|
|
|
toast: (message: string, type: ToastVariant, duration = 2000) => SnackbarEvents.emit(message, type, duration),
|
2022-01-05 01:09:34 +01:00
|
|
|
};
|
2022-01-03 16:32:01 +01:00
|
|
|
|
2022-08-19 13:38:46 +02:00
|
|
|
// Will be consumed by the electron wrapper.
|
2022-04-19 02:47:33 +02:00
|
|
|
window.appNotifier = funcs;
|
2022-01-18 18:21:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function initSaveFunctions(): void {
|
|
|
|
const funcs = {
|
|
|
|
triggerSave: (): Promise<void> => saveObject.saveGame(true),
|
|
|
|
triggerGameExport: (): void => {
|
|
|
|
try {
|
|
|
|
saveObject.exportGame();
|
|
|
|
} catch (error) {
|
2022-07-10 07:37:36 +02:00
|
|
|
console.error(error);
|
2022-10-04 12:40:10 +02:00
|
|
|
SnackbarEvents.emit("Could not export game.", ToastVariant.ERROR, 2000);
|
2022-01-18 18:21:53 +01:00
|
|
|
}
|
|
|
|
},
|
|
|
|
triggerScriptsExport: (): void => exportScripts("*", Player.getHomeComputer()),
|
2024-03-28 05:08:09 +01:00
|
|
|
getSaveData: async (): Promise<{ save: SaveData; fileName: string }> => {
|
2022-01-18 18:21:53 +01:00
|
|
|
return {
|
2024-03-28 05:08:09 +01:00
|
|
|
save: await saveObject.getSaveData(),
|
2022-01-18 18:21:53 +01:00
|
|
|
fileName: saveObject.getSaveFileName(),
|
|
|
|
};
|
|
|
|
},
|
2024-03-28 05:08:09 +01:00
|
|
|
getSaveInfo: async (saveData: SaveData): Promise<ImportPlayerData | undefined> => {
|
2022-01-18 18:21:53 +01:00
|
|
|
try {
|
2024-03-28 05:08:09 +01:00
|
|
|
const importData = await saveObject.getImportDataFromSaveData(saveData);
|
|
|
|
return importData.playerData;
|
2022-01-18 18:21:53 +01:00
|
|
|
} catch (error) {
|
|
|
|
console.error(error);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
},
|
2024-03-28 05:08:09 +01:00
|
|
|
pushSaveData: (saveData: SaveData, automatic = false): void =>
|
|
|
|
Router.toPage(Page.ImportSave, { saveData, automatic }),
|
2022-01-18 18:21:53 +01:00
|
|
|
};
|
|
|
|
|
2022-08-19 13:38:46 +02:00
|
|
|
// Will be consumed by the electron wrapper.
|
2022-04-19 02:47:33 +02:00
|
|
|
window.appSaveFns = funcs;
|
2022-01-18 18:21:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
function initElectronBridge(): void {
|
2022-04-19 02:47:33 +02:00
|
|
|
const bridge = window.electronBridge;
|
2022-01-18 18:21:53 +01:00
|
|
|
if (!bridge) return;
|
|
|
|
|
2024-03-28 05:08:09 +01:00
|
|
|
bridge.receive("get-save-data-request", async () => {
|
|
|
|
const saveData = await window.appSaveFns.getSaveData();
|
|
|
|
bridge.send("get-save-data-response", saveData);
|
2022-01-18 18:21:53 +01:00
|
|
|
});
|
2024-03-28 05:08:09 +01:00
|
|
|
bridge.receive("get-save-info-request", async (saveData: unknown) => {
|
|
|
|
if (typeof saveData !== "string" && !(saveData instanceof Uint8Array)) {
|
|
|
|
throw new Error("Error while trying to get save info");
|
|
|
|
}
|
|
|
|
const saveInfo = await window.appSaveFns.getSaveInfo(saveData);
|
|
|
|
bridge.send("get-save-info-response", saveInfo);
|
2022-01-18 18:21:53 +01:00
|
|
|
});
|
2022-07-20 05:26:21 +02:00
|
|
|
bridge.receive("push-save-request", (params: unknown) => {
|
|
|
|
if (typeof params !== "object") throw new Error("Error trying to push save request");
|
|
|
|
const { save, automatic = false } = params as { save: string; automatic: boolean };
|
2022-04-19 02:47:33 +02:00
|
|
|
window.appSaveFns.pushSaveData(save, automatic);
|
2022-01-18 18:21:53 +01:00
|
|
|
});
|
|
|
|
bridge.receive("trigger-save", () => {
|
2022-04-19 02:47:33 +02:00
|
|
|
return window.appSaveFns
|
2022-01-18 18:21:53 +01:00
|
|
|
.triggerSave()
|
|
|
|
.then(() => {
|
|
|
|
bridge.send("save-completed");
|
|
|
|
})
|
2022-04-19 02:47:33 +02:00
|
|
|
.catch((error: unknown) => {
|
2022-07-10 07:37:36 +02:00
|
|
|
console.error(error);
|
2022-10-04 12:40:10 +02:00
|
|
|
SnackbarEvents.emit("Could not save game.", ToastVariant.ERROR, 2000);
|
2022-01-18 18:21:53 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
bridge.receive("trigger-game-export", () => {
|
|
|
|
try {
|
2022-04-19 02:47:33 +02:00
|
|
|
window.appSaveFns.triggerGameExport();
|
2022-01-18 18:21:53 +01:00
|
|
|
} catch (error) {
|
2022-07-10 07:37:36 +02:00
|
|
|
console.error(error);
|
2022-10-04 12:40:10 +02:00
|
|
|
SnackbarEvents.emit("Could not export game.", ToastVariant.ERROR, 2000);
|
2022-01-18 18:21:53 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
bridge.receive("trigger-scripts-export", () => {
|
|
|
|
try {
|
2022-04-19 02:47:33 +02:00
|
|
|
window.appSaveFns.triggerScriptsExport();
|
2022-01-18 18:21:53 +01:00
|
|
|
} catch (error) {
|
2022-07-10 07:37:36 +02:00
|
|
|
console.error(error);
|
2022-10-04 12:40:10 +02:00
|
|
|
SnackbarEvents.emit("Could not export scripts.", ToastVariant.ERROR, 2000);
|
2022-01-18 18:21:53 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2024-03-28 05:08:09 +01:00
|
|
|
export function pushGameSaved(data: ElectronGameData): void {
|
2022-04-19 02:47:33 +02:00
|
|
|
const bridge = window.electronBridge;
|
2022-01-18 18:21:53 +01:00
|
|
|
if (!bridge) return;
|
|
|
|
|
|
|
|
bridge.send("push-game-saved", data);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function pushGameReady(): void {
|
2022-04-19 02:47:33 +02:00
|
|
|
const bridge = window.electronBridge;
|
2022-01-18 18:21:53 +01:00
|
|
|
if (!bridge) return;
|
|
|
|
|
|
|
|
// Send basic information to the electron wrapper
|
|
|
|
bridge.send("push-game-ready", {
|
|
|
|
player: {
|
|
|
|
identifier: Player.identifier,
|
|
|
|
playtime: Player.totalPlaytime,
|
|
|
|
lastSave: Player.lastSave,
|
|
|
|
},
|
|
|
|
game: {
|
|
|
|
version: CONSTANTS.VersionString,
|
|
|
|
hash: hash(),
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
export function pushImportResult(wasImported: boolean): void {
|
2022-04-19 02:47:33 +02:00
|
|
|
const bridge = window.electronBridge;
|
2022-01-18 18:21:53 +01:00
|
|
|
if (!bridge) return;
|
|
|
|
|
|
|
|
bridge.send("push-import-result", { wasImported });
|
|
|
|
pushDisableRestore();
|
|
|
|
}
|
|
|
|
|
|
|
|
export function pushDisableRestore(): void {
|
2022-04-19 02:47:33 +02:00
|
|
|
const bridge = window.electronBridge;
|
2022-01-18 18:21:53 +01:00
|
|
|
if (!bridge) return;
|
|
|
|
|
|
|
|
bridge.send("push-disable-restore", { duration: 1000 * 60 });
|
2022-01-03 16:32:01 +01:00
|
|
|
}
|