Skip to content
This repository has been archived by the owner on Oct 11, 2024. It is now read-only.

Portable mode #6

Merged
merged 2 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ node_modules/
config.json
bin/emulator/
gameinfo/
portable
out/
9 changes: 6 additions & 3 deletions libs/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ const fs = require('node:fs');
const path = require('node:path');

module.exports.Config = class Config {
#cfgfile = path.join(__dirname, '../config.json');
#cfgfile = undefined;
#default = {
emu_path: path.join(__dirname, '../bin/emulator'),
emu_path: undefined,
update_channel: 'release',
update_freq: 'weekly',
inpadcolor: '#3B3E95',
Expand Down Expand Up @@ -32,7 +32,10 @@ module.exports.Config = class Config {
#callbacks = [];
#data = null;

constructor() {
constructor(userdir) {
this.#cfgfile = path.join(userdir, '/config.json');
this.#default.emu_path = path.join(userdir, '/bin/emulator');

try {
this.#data = JSON.parse(fs.readFileSync(this.#cfgfile, { encoding: 'utf-8' }));

Expand Down
104 changes: 77 additions & 27 deletions main.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const { app, BrowserWindow, Menu, ipcMain, dialog } = require('electron');
const Convert = require('ansi-to-html');
const { Worker } = require('node:worker_threads');
const { spawn, exec, execSync } = require('node:child_process');
const { spawn, exec } = require('node:child_process');
const path = require('node:path');
const fs = require('node:fs');
const { Config } = require('./libs/settings.js');
Expand All @@ -11,31 +11,17 @@ const SCE_PIC_PATH = '/sce_sys/pic0.png';
const SCE_TROPHY_PATH = '/sce_sys/trophy/trophy00.trp';
const SCE_BGA_PATH = '/sce_sys/snd0.at9';
const LISTAUDIO_PATH = path.join(__dirname, '/bin/listaudio.exe');

let win = null;
let player = null;
let settwin = null;
let gameproc = null;
let updateWorker = null;
const PORTABLE_PATH = path.join(__dirname, '/portable');

let win = undefined;
let player = undefined;
let config = undefined;
let gipath = undefined;
let settwin = undefined;
let gameproc = undefined;
let updateWorker = undefined;
let binname = 'psoff.exe';

const config = new Config();

const emupath = config.getValue('emu_path');
const gipath = path.join(__dirname, '/gameinfo');

fs.mkdirSync(gipath, { recursive: true });

try {
const testfile = path.join(emupath, '/test');
fs.mkdirSync(emupath, { recursive: true });
fs.writeFileSync(testfile, 'test');
fs.unlinkSync(testfile);
} catch (e) {
console.error('Emulator directory is not writeable anymore, resetting to default one: ', e.toString());
config.resetValue('emu_path');
}

const converter = new Convert({
newline: true
});
Expand All @@ -61,6 +47,7 @@ const _runDownloadingProcess = (retry = false) => {

const loadTrophiesData = (gid) => {
try {
const emupath = config.getValue('emu_path');
const tfile = fs.readFileSync(`${emupath}/GAMEFILES/${gid}/tropinfo.${config.getInitialUser()}`);
const trophies = [];
const count = tfile.readUint32LE(0);
Expand Down Expand Up @@ -120,7 +107,7 @@ const updateGameSummary = (gid, update, loadtrophies = false) => {

const updateBinaryPath = (path, checkfirst = false) => {
binname = path ?? binname;
exec(`"${binname}" -h`, { cwd: emupath }).on('close', (code) => {
exec(`"${binname}" -h`, { cwd: config.getValue('emu_path') }).on('close', (code) => {
if (code === 0 || code === 4294967295) config.reloadEmulatorSettings();
else throw new Error('Failed to make a test emulator run!');
});
Expand Down Expand Up @@ -249,6 +236,7 @@ const commandHandler = (channel, cmd, info) => {
const patch = getGameSummary(info, false).patch;
if (patch) emuargs.push(`--update=${patch}`);

const emupath = config.getValue('emu_path');
gameproc = spawn(path.join(emupath, binname), emuargs, { cwd: emupath });
gameproc.stdout.on('data', terminalListener);
gameproc.stderr.on('data', terminalListener);
Expand Down Expand Up @@ -348,12 +336,35 @@ const commandHandler = (channel, cmd, info) => {
}
};

app.whenReady().then(() => {
const main = (userdir = __dirname) => {
fs.mkdirSync(userdir, { recursive: true });
config = new Config(userdir);

const emupath = config.getValue('emu_path');

gipath = path.join(userdir, '/gameinfo');
fs.mkdirSync(gipath, { recursive: true });

try {
const testfile = path.join(emupath, '/test');
fs.mkdirSync(emupath, { recursive: true });
fs.writeFileSync(testfile, 'test');
fs.unlinkSync(testfile);
} catch (e) {
console.error('Emulator directory is not writeable anymore, resetting to default one: ', e.toString());
config.resetValue('emu_path');
}

ipcMain.on('command', commandHandler);

ipcMain.handle('reqcfg', () => config.getFullConfig());

ipcMain.handle('reqadev', () => JSON.parse(execSync(`"${LISTAUDIO_PATH}"`, { cwd: emupath })));
ipcMain.handle('reqadev', () => new Promise((resolve, reject) => {
exec(`"${LISTAUDIO_PATH}"`, { cwd: emupath }, (err, stdout) => {
if (err) return reject(err);
resolve(JSON.parse(stdout));
});
}));

ipcMain.handle('opendir', async () => {
const { canceled, filePaths } = await dialog.showOpenDialog(win, { properties: ['openDirectory'] });
Expand Down Expand Up @@ -574,4 +585,43 @@ app.whenReady().then(() => {
});

win.loadFile('webroot/index.html');
};

const guessLaunch = () => {
if (fs.readFileSync(PORTABLE_PATH).readUint8(0) === 1) { // portable
return main();
}

return main(path.join(process.env.LOCALAPPDATA, '/psoff-advlaunch/'));
};

app.whenReady().then(() => {
try {
guessLaunch();
} catch (e) {
if (e.code === 'ENOENT') {
const portask = new BrowserWindow({
width: 550,
height: 154,
resizable: false,
frame: false,
webPreferences: {
allowRunningInsecureContent: false,
preload: path.join(__dirname, 'preload.js')
}
});

ipcMain.once('set-portable', (ev, value) => {
fs.writeFileSync(PORTABLE_PATH, value ? '\x01' : '\x00');
});

portask.on('closed', () => guessLaunch());

portask.loadFile('webroot/portable.html');
return;
}

// Rethrow if something else errored
throw e;
}
});
1 change: 1 addition & 0 deletions preload.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ contextBridge.exposeInMainWorld('electronAPI', {
requestAudioDevices: () => ipcRenderer.invoke('reqadev'),
requestConfig: () => ipcRenderer.invoke('reqcfg'),
selectFolder: () => ipcRenderer.invoke('opendir'),
setPortable: (state) => ipcRenderer.send('set-portable', state)
});
1 change: 1 addition & 0 deletions services/gamescanner.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ const walker = (wpath, ents, depth, maxdepth) => {

if (paramsfostat.isFile()) {
const sfo_data = readSFO(fs.readFileSync(paramsfopath));
if (!sfo_data) return;
let icon = null;
let troph = false;

Expand Down
2 changes: 1 addition & 1 deletion services/updater.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ const commandHandler = async (msg) => {
validateEmulatorPath();
await download(newverinfo.url, newverinfo.tag).then(({ fpath, version }) => {
execSync('del *.dll *.exe', { cwd: emupath });
execSync(`"${path.join(emupath, '../7z.exe')}" x -y -aoa -o"${emupath}" "${fpath}"`);
execSync(`"${path.join(__dirname, '../bin/7z.exe')}" x -y -aoa -o"${emupath}" "${fpath}"`);
parentPort.postMessage({ resp: 'done', executable: path.basename(searchBinary()) });
updateVersionFile(version);
fs.unlinkSync(fpath);
Expand Down
11 changes: 11 additions & 0 deletions webroot/css/portable.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#wrapper {
text-align: center;
}

h4 a {
color: green;
}

#buttons {
width: 100%;
}
2 changes: 1 addition & 1 deletion webroot/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ window._onLangReady = (() => {
} else if (tgc.contains('minimize')) {
window.electronAPI.sendCommand('minimize');
} else if (tgc.contains('legal')) {
window.open('legal.html', '_blank', 'frame=no,minWidth=630,minHeight=380,maxWidth=630,maxHeight=380,width=630,height=380');
window.open('legal.html', '_blank', 'frame=no,resizable=no,width=630,height=380');
}
});

Expand Down
7 changes: 7 additions & 0 deletions webroot/js/portable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
(() => {
$('#buttons').on('click', ({ target }) => {
if (target.tagName !== 'BUTTON') return;
window.electronAPI.setPortable(target.dataset.portable === '1');
window.close();
});
})();
28 changes: 28 additions & 0 deletions webroot/portable.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>

<head>
<meta http-equiv="Content-Security-Policy"
content="default-src 'none'; style-src 'self'; script-src 'self'; font-src 'self';">
<link rel="stylesheet" href="css/shared.css" />
<link rel="stylesheet" href="css/portable.css" />
<script src="js/vars.js"></script>
</head>

<body>
<div id="wrapper">
<h3>Do you want to run the Advanced Launcher in portable mode?</h3>
<h4>In non-portable mode the Advanced Launcher will save its <a title="Playtime, launcher settings etc.">data</a>*
to
<a>%LOCALAPPDATA%\psoff-advlaunch</a> folder.
</h4>
<div id="buttons">
<button data-portable="1">Portable mode</button>
<button data-portable="0">Non-portable mode</button>
</div>
</div>

<script src="js/portable.js"></script>
</body>

</html>