const fs = require("fs");
const Fuse = require("fuse.js");
const ipcRenderer = require("electron").ipcRenderer;
const lang = require("../../lang");
const events = require("./events");
const popups = require("./popups");
let settings_fuse;
// base settings, and future set settings data
let settings_data = {
nsargs: "",
gamepath: "",
nsupdate: true,
autolang: true,
forcedlang: "en",
autoupdate: true,
originkill: false,
zip: "/northstar.zip",
lang: navigator.language,
excludes: [
"ns_startup_args.txt",
"ns_startup_args_dedi.txt"
]
}
// loads the settings
if (fs.existsSync("viper.json")) {
let iteration = 0;
// loads the config file, it's loaded in an interval like this in
// case the config file is currently being written to, if we were to
// read from the file during that, then it'd be empty or similar.
//
// and because of that, we check if the file is empty when loading
// it, if so we wait 100ms, then check again, and we keep doing that
// hoping it'll become normal again. unless we've checked it 50
// times, then we simply give up, and force the user to re-select
// the gamepath, as this'll make the config file readable again.
//
// ideally it'll never have to check those 50 times, it's only in
// case something terrible has gone awry, like if a write got
// interrupted, or a user messed with the file.
//
// were it to truly be broken, then it'd take up to 5 seconds to
// then reset, this is basically nothing, especially considering
// this should only happen in very rare cases... hopefully!
let config_interval = setInterval(() => {
let gamepath = require("./gamepath");
iteration++;
config = json("viper.json") || {};
// checks whether `settings_data.gamepath` is set, and if so,
// it'll attempt to load ns_startup_args.txt
let parse_settings = () => {
// if gamepath is not set, attempt to set it
if (settings_data.gamepath.length === 0) {
gamepath.set(false);
} else {
// if the gamepath is set, we'll simply tell the main
// process about it, and it'll then show the main
// renderer BrowserWindow
gamepath.set(true);
}
// filepath to Northstar's startup args file
let args = path.join(settings_data.gamepath, "ns_startup_args.txt");
// check file exists, and that no `nsargs` setting was set
if (! settings_data.nsargs && fs.existsSync(args)) {
// load arguments from file into `settings`
settings_data.nsargs = fs.readFileSync(args, "utf8") || "";
}
}
// make sure config isn't empty
if (Object.keys(config).length !== 0) {
// add `config` to `settings_data`
settings.set(config);
parse_settings();
clearInterval(config_interval);
return;
}
// we've attempted to load the config 50 times now, give up
if (iteration >= 50) {
// request a new gamepath be set
gamepath.set(false);
clearInterval(config_interval);
}
}, 100)
} else {
require("./gamepath").set();
}
ipcRenderer.on("changed-settings", (e, new_settings) => {
// attempt to set `settings_data` to `new_settings`
try {
settings.set(new_settings);
}catch(e) {}
})
let settings = {
default: {...settings_data},
data: () => {return settings_data},
// asks the main process to reset the config/settings file
reset: () => {
ipcRenderer.send("reset-config");
},
// merges `object` with `settings_data`, unless `no_merge` is set,
// then it replaces it entirely
set: (object, no_merge) => {
if (no_merge) {
settings_data = object;
return;
}
settings_data = {
...settings_data,
...object
}
},
popup: {}
}
settings.popup.toggle = (state) => {
settings.popup.load();
options.scrollTo(0, 0);
popups.set("#options", state);
}
settings.popup.apply = () => {
settings.set(settings.popup.get());
ipcRenderer.send("save-settings", settings.popup.get());
}
settings.popup.get = () => {
let opts = {};
let options = document.querySelectorAll(".option");
for (let i = 0; i < options.length; i++) {
let optName = options[i].getAttribute("name");
if (options[i].querySelector(".actions input")) {
let input = options[i].querySelector(".actions input").value;
if (options[i].getAttribute("type")) {
opts[optName] = input.split(" ");
} else {
opts[optName] = input;
}
} else if (options[i].querySelector(".actions select")) {
opts[optName] = options[i].querySelector(".actions select").value;
} else if (options[i].querySelector(".actions .switch")) {
if (options[i].querySelector(".actions .switch.on")) {
opts[optName] = true;
} else {
opts[optName] = false;
}
}
}
return opts;
}
settings.popup.load = () => {
// re-opens any closed categories
let categories = document.querySelectorAll("#options details");
for (let i = 0; i < categories.length; i++) {
categories[i].setAttribute("open", true);
// hide categories that aren't for the current platform
let for_platform = categories[i].getAttribute("platform");
if (for_platform && process.platform != for_platform) {
categories[i].style.display = "none";
categories[i].setAttribute("perma-hidden", true);
}
}
let options = document.querySelectorAll(".option");
for (let i = 0; i < options.length; i++) {
// hide options that aren't for the current platform
let for_platform = options[i].getAttribute("platform");
if (for_platform && process.platform != for_platform) {
options[i].style.display = "none";
options[i].setAttribute("perma-hidden", true);
}
let optName = options[i].getAttribute("name");
if (optName == "forcedlang") {
let div = options[i].querySelector("select");
div.innerHTML = "";
let lang_dir = __dirname + "/../../lang";
let langs = fs.readdirSync(lang_dir);
for (let i in langs) {
let lang_file = require(lang_dir + "/" + langs[i]);
let lang_no_extension = langs[i].replace(/\..*$/, "");
if (! lang_file.lang || ! lang_file.lang.title) {
continue;
}
let title = lang_file.lang.title;
if (title) {
div.innerHTML += ``
}
}
div.value = settings_data.forcedlang;
continue;
}
if (settings_data[optName] != undefined) {
// check if setting has a `