import { ManaPlusApp } from "./manaApp/manaApp.interface";
import { ManaPlusAppWindows } from "./manaApp/windows";
import * as os from "os";
import { join } from "path";
import * as fs from "fs-extra";
import { ipcMain, shell, dialog } from "electron";
import { Status, EventEmitter } from "../status";
import { ManaPlusAppLinux } from "./manaApp/linux";
import { getUserDataPath } from "../util/app_constants";
import { execFile } from "child_process";
let ManaPlusInstance: ManaPlusApp;
let CurrentServer: { serverID: string; address: string } = null;
export namespace ManaPlus {
export const ERRORS = {
NOT_INITILIZED_YET_ERROR: new Error(
"The ManaPlus updater wasn't initilized"
)
};
export function init() {
if (os.platform() == "win32") {
ManaPlusInstance = new ManaPlusAppWindows();
console.log("GameDir:" + ManaPlusInstance.getGameDir());
}
if (os.platform() == "linux") {
ManaPlusInstance = new ManaPlusAppLinux();
console.log("startCommand:" + ManaPlusInstance.startCommand);
}
}
export async function update() {
if (!wasInitilized()) throw ERRORS.NOT_INITILIZED_YET_ERROR;
return await ManaPlusInstance.update();
}
export async function start(args: any) {
CurrentServer = {
serverID: args.serverID,
address: args.address
};
let params: string[];
try {
params = await makeParams(
args.address,
args.port,
args.engine,
args.username,
args.password
);
//params = ['-v'];// DEBUG: This option is to disable manaplus for testing (open it just for getting the version)
} catch (e) {
console.log(e);
Status.showError(
"Launch Preperation Failed (LPF_PARMS)",
e.message,
"Launch preparation failed"
);
Status.setPlaying(false);
return;
}
let willUpdate: boolean = false;
// check if it is installed
if (ManaPlusInstance.isInstalled()) {
// Check if update is available and ask if the user wants to update
try {
let version = await ManaPlusInstance.updateAvailable();
// console.log({version})
willUpdate =
!version.isNewVersion && (await updateDialog(version.newestVersion));
} catch (e) {
console.log(e);
Status.showError(
"Launch Preperation Failed (LPF_Update): This error can also mean that you are offline, \
please check you network connection first.",
e.message,
"Launch preparation failed"
);
Status.setPlaying(false);
return;
}
} else {
// Not installed will install it
willUpdate = true;
}
// Install/Update the gameclient if needed
if (willUpdate) {
try {
await update();
} catch (error) {
Status.setPlaying(false);
throw error;
}
}
//IDEA have client data updated here to, if needed
// Run it
Status.setGameRunning(true);
EventEmitter.emit("closeWindow");
EventEmitter.emit("openTray");
await runManaProgram(params, ManaPlusInstance.startCommand, args.address);
// On Close
Status.setGameStatus({ server: "Launcher" });
Status.setGameRunning(false);
Status.setPlaying(false);
Status.removeActivity();
EventEmitter.emit("reopenWindow");
EventEmitter.emit("closeTray");
CurrentServer = null;
}
}
ipcMain.handle("getScreenshots", async (_event: any, arg: string) => {
const screenshotsDir = join(getUserDataPath(), "/screenshots/", `${arg}/`);
(await fs.existsSync(screenshotsDir)) || (await fs.mkdirSync(screenshotsDir));
const dir = await fs.readdir(screenshotsDir);
let screenshots: string[] = [];
for (var i = 0, path; (path = dir[i]); i++) {
screenshots.push(path);
}
return {
dir: screenshotsDir,
screenshots: screenshots.reverse().slice(0, 24)
};
});
EventEmitter.on("Mana:openScreenshotDir", () => {
shell.openPath(
join(getUserDataPath(), `/screenshots/${CurrentServer.address}/`)
);
});
function wasInitilized() {
return (
typeof ManaPlusInstance !== "undefined" &&
typeof ManaPlusInstance !== "undefined"
);
}
async function makeParams(
server: any,
port: any,
engine: any,
username?: any,
password?: any
): Promise<string[]> {
let parameters: string[] = [];
if (server && engine && port && server != "noServer") {
parameters.push(...["-s", server, "-y", engine, "-p", port]);
if (username && password) {
parameters.push(...["-U", username, "-P", password]);
}
}
// Setup Paths and stuff
const configDir = join(getUserDataPath(), "/mana_config");
const localDataDir = join(getUserDataPath(), "/mana_local_data");
const screenshotsDir = join(getUserDataPath(), `/screenshots/${server}`);
await fs.ensureDir(configDir);
await fs.ensureDir(localDataDir);
await fs.ensureDir(screenshotsDir);
parameters.push(
...["-C", configDir, "-L", localDataDir, "--screenshot-dir", screenshotsDir]
);
//console.log(parameters);
return parameters;
}
let manaplusInstance: any = null;
function runManaProgram(
parameters: string[],
gameExe: string,
server?: string
): Promise<any> {
return new Promise<void>(async (resolve, reject) => {
if (server) {
Status.setActivity(`Preparing Launch`);
await setSkipUpdateWindows(server);
}
Status.setActivity(`Starting ManaPlus`);
//console.log(gameExe, parameters);
const child = execFile(
gameExe,
parameters,
{
env: {
...process.env,
APPIMAGELAUNCHER_DISABLE: "true"
}
},
function (err: Error, data: any) {
console.log(err);
console.log(data.toString());
Status.setActivity(`ManaPlus is running`);
}
);
child.on("close", () => {
manaplusInstance = null;
resolve();
});
child.on("error", () => {
manaplusInstance = null;
resolve();
//// TODO: Handle Error
});
manaplusInstance = child;
});
}
EventEmitter.on("Mana:killMana", () => {
if (manaplusInstance && manaplusInstance !== null)
manaplusInstance.kill("SIGINT");
});
async function updateDialog(newestVersion: string): Promise<boolean> {
const options = {
type: "info",
title: `ManaPlus Update available: ${newestVersion}`,
message:
"Do you want to update now? Please note that you'll have to update eventually to ensure further compability with the servers",
buttons: ["Nah, LATER", "Update NOW"]
};
let { response } = await dialog.showMessageBox(null, options);
console.log("....", response);
return response === 1;
}
const default_server_config =
'<?xml version="1.0"?>\
<configuration>\
<option name="updateType" value="1"/>\
<list name="player"/>\
</configuration>';
const parseString = require("xml2js").parseString,
xml2js = require("xml2js");
async function setSkipUpdateWindows(server: string) {
const serverConfigXML = join(
getUserDataPath(),
`/mana_config/${server}/config.xml`
);
if (fs.existsSync(serverConfigXML)) {
//add to this file
try {
let data = await fs.readFile(serverConfigXML, "utf8");
data = await editXML(data);
await fs.outputFile(serverConfigXML, data);
} catch (err) {
console.log(err);
}
} else {
//create the file
fs.outputFile(serverConfigXML, default_server_config);
}
return;
}
function editXML(xml: string): Promise<string> {
return new Promise((res, rej) => {
parseString(xml, function (err: any, result: any) {
if (err) console.log(err);
var json = result;
const updaterVar = json.configuration.option.find(
(item: any) => item.$.name == "updateType"
);
if (updaterVar) {
if (updaterVar.$.value === 1) {
return rej(new Error("Has allready the right value"));
}
updaterVar.$.value = 1;
} else {
json.configuration.option.push({ $: { name: "updateType", value: 1 } });
}
var builder = new xml2js.Builder();
res(builder.buildObject(json));
});
});
}