aboutsummaryrefslogtreecommitdiff
path: root/modding
diff options
context:
space:
mode:
authorMinteck <nekostarfan@gmail.com>2021-06-05 19:27:48 +0200
committerMinteck <nekostarfan@gmail.com>2021-06-05 19:27:48 +0200
commit8cf5cefe6e91a5a1ed6eeaae4d94760d84c304a6 (patch)
tree7096b67b189c0220826123c7d5b121752545d140 /modding
downloadkartik-client-8cf5cefe6e91a5a1ed6eeaae4d94760d84c304a6.tar.gz
kartik-client-8cf5cefe6e91a5a1ed6eeaae4d94760d84c304a6.tar.bz2
kartik-client-8cf5cefe6e91a5a1ed6eeaae4d94760d84c304a6.zip
Presque sortie du jeu
Diffstat (limited to 'modding')
-rw-r--r--modding/hooks.js201
-rw-r--r--modding/parser.js277
-rw-r--r--modding/resources.js65
3 files changed, 543 insertions, 0 deletions
diff --git a/modding/hooks.js b/modding/hooks.js
new file mode 100644
index 0000000..d0ee779
--- /dev/null
+++ b/modding/hooks.js
@@ -0,0 +1,201 @@
+function hook_Music(mod, type, hname) {
+ hook = mod["Hook"][hname];
+ names = Object.keys(hook);
+
+ for (i in names) {
+ name = names[i];
+ if (name !== "Music.Start" && name !== "Music.Prepare" && name !== "Music.Title" && name !== "Music.Credits" && name !== "Music.Win" && name !== "Music.Game1" && name !== "Music.Game2" && name !== "Music.Game3" && name !== "Music.Game4" && name !== "Music.Game5" && name !== "Music.Game6" && name !== "Music.Game7" && name !== "Music.Game8" && name !== "Music.Game9") {
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": hook " + hname + " (" + type + "): invalid hook data, EXITING"
+ }
+ )
+ process.exit(2);
+ } else {
+ switch (name) {
+ case "Music.Start":
+ resources.music['start'].file = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ resources.music['start'].original = false;
+ break;
+ case "Music.Title":
+ resources.music['title'].file = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ resources.music['title'].original = false;
+ break;
+ case "Music.Credits":
+ resources.music['credits'].file = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ resources.music['credits'].original = false;
+ break;
+ case "Music.Win":
+ resources.music['win'].file = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ resources.music['win'].original = false;
+ break;
+ case "Music.Prepare":
+ resources.music['prepare'].file = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ resources.music['prepare'].original = false;
+ break;
+ case "Music.Game1":
+ resources.music['game1'].file = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ resources.music['game1'].original = false;
+ break;
+ case "Music.Game2":
+ resources.music['game2'].file = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ resources.music['game2'].original = false;
+ break;
+ case "Music.Game3":
+ resources.music['game3'].file = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ resources.music['game3'].original = false;
+ break;
+ case "Music.Game4":
+ resources.music['game4'].file = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ resources.music['game4'].original = false;
+ break;
+ case "Music.Game5":
+ resources.music['game5'].file = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ resources.music['game5'].original = false;
+ break;
+ case "Music.Game6":
+ resources.music['game6'].file = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ resources.music['game6'].original = false;
+ break;
+ case "Music.Game7":
+ resources.music['game7'].file = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ resources.music['game7'].original = false;
+ break;
+ case "Music.Game8":
+ resources.music['game8'].file = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ resources.music['game8'].original = false;
+ break;
+ case "Music.Game9":
+ resources.music['game9'].file = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ resources.music['game9'].original = false;
+ break;
+ }
+ }
+ }
+}
+
+function hook_SoundFX(mod, type, hname) {
+ hook = mod["Hook"][hname];
+ names = Object.keys(hook);
+
+ for (i in names) {
+ name = names[i];
+ if (name !== "SFX.Click" && name !== "SFX.Crash" && name !== "SFX.Intro" && name !== "SFX.Last" && name !== "SFX.Menu" && name !== "SFX.Pass" && name !== "SFX.Pause" && name !== "SFX.Start" && name !== "SFX.Win") {
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": hook " + hname + " (" + type + "): invalid hook data, EXITING"
+ }
+ )
+ process.exit(2);
+ } else {
+ switch (name) {
+ case "SFX.Click":
+ resources.sfx['click'] = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ break;
+ case "SFX.Crash":
+ resources.sfx['crash'] = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ break;
+ case "SFX.Intro":
+ resources.sfx['intro'] = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ break;
+ case "SFX.Last":
+ resources.sfx['last'] = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ break;
+ case "SFX.Menu":
+ resources.sfx['menu'] = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ break;
+ case "SFX.Pass":
+ resources.sfx['pass'] = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ break;
+ case "SFX.Pause":
+ resources.sfx['pause'] = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ break;
+ case "SFX.Start":
+ resources.sfx['start'] = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ break;
+ case "SFX.Win":
+ resources.sfx['win'] = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ break;
+ }
+ }
+ }
+}
+
+function hook_Car(mod, type, hname) {
+ hook = mod["Hook"][hname];
+ names = Object.keys(hook);
+
+ for (i in names) {
+ name = names[i];
+
+ if (name.startsWith("Car.")) {
+ resources.cars[name.substr(4)] = mod["_Path"] + "/" + mod["Hook"][hname][name];
+ } else {
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": hook " + hname + " (" + type + "): invalid hook data, EXITING"
+ }
+ )
+ process.exit(2);
+ }
+ }
+}
+
+function hook_Circuit(mod, type, hname) {
+ hook = mod["Hook"][hname];
+ names = Object.keys(hook);
+
+ for (i in names) {
+ name = names[i];
+
+ if (name.startsWith("Circuit.")) {
+ resources.races[name.substr(4)] = mod["_Path"] + "/" + mod["Hook"][hname][name] + ".html";
+ } else {
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": hook " + hname + " (" + type + "): invalid hook data, EXITING"
+ }
+ )
+ process.exit(2);
+ }
+ }
+}
+
+module.exports = (mod, type, name) => {
+ hook = mod["Hook"][name];
+
+ if (type !== "Kartik.Music" && type !== "Kartik.SoundFX" && type !== "Kartik.Circuit" && type !== "Kartik.Car") {
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": invalid hook type, EXITING"
+ }
+ )
+ process.exit(2);
+ }
+
+ switch (type) {
+ case "Kartik.Music":
+ hook_Music(mod, type, name);
+ break;
+ case "Kartik.SoundFX":
+ hook_SoundFX(mod, type, name);
+ break;
+ case "Kartik.Car":
+ hook_Car(mod, type, name);
+ break;
+ break;
+ case "Kartik.Circuit":
+ hook_Circuit(mod, type, name);
+ break;
+ }
+}
diff --git a/modding/parser.js b/modding/parser.js
new file mode 100644
index 0000000..26f5320
--- /dev/null
+++ b/modding/parser.js
@@ -0,0 +1,277 @@
+const fs = require('fs');
+const os = require('os');
+const ini = require('ini');
+const YAML = require('yaml');
+const { dialog } = require('electron');
+const semver = require('semver');
+
+function unload(arr) {
+ var what, a = arguments, L = a.length, ax;
+ while (L > 1 && arr.length) {
+ what = a[--L];
+ while ((ax= arr.indexOf(what)) !== -1) {
+ arr.splice(ax, 1);
+ }
+ }
+ return arr;
+}
+
+list = fs.readdirSync(homedir + "/.kartik/mods");
+
+for (index in list) {
+ item = list[index];
+
+ if (!fs.existsSync(homedir + "/.kartik/mods/" + item + "/kartik.ini") && !fs.existsSync(homedir + "/.kartik/mods/" + item + "/kartik.yml")) {
+ unload(list, item);
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": no kartik.ini or kartik.yml file found"
+ }
+ )
+ }
+}
+
+for (index in list) {
+ item = list[index];
+
+ parts = item.split(".");
+ if (parts.length < 2 || parts[0].length > 5 || item.length > 49 || parts.length > 5 || !/^[a-zA-Z0-9.]*$/gm.test(item)) {
+ unload(list, item);
+ if (parts.length < 2) {
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": invalid package name: not enough parts"
+ }
+ )
+ }
+ if (parts[0].length > 5) {
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": invalid package name: tld too long"
+ }
+ )
+ }
+ if (item.length > 49) {
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": invalid package name: too long"
+ }
+ )
+ }
+ if (parts.length > 5) {
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": invalid package name: too many parts"
+ }
+ )
+ }
+ if (!/^[a-zA-Z0-9.]*$/gm.test(item)) {
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": invalid package name: invalid format"
+ }
+ )
+ }
+ }
+}
+
+for (index in list) {
+ item = list[index];
+
+ if (fs.existsSync(homedir + "/.kartik/mods/" + item + "/kartik.ini") && fs.existsSync(homedir + "/.kartik/mods/" + item + "/kartik.yml")) {
+ unload(list, item);
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": both kartik.ini and kartik.yml found"
+ }
+ )
+ }
+}
+
+global.moddata = {};
+
+for (index in list) {
+ if (fs.existsSync(homedir + "/.kartik/mods/" + item + "/kartik.ini")) {
+ try {
+ moddata[list] = ini.parse(fs.readFileSync(homedir + "/.kartik/mods/" + item + "/kartik.ini", "utf-8"));
+ } catch (e) {
+ unload(list, item);
+ console.error(e);
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": ini parser error"
+ }
+ )
+ }
+ } else {
+ try {
+ moddata[list] = YAML.parse(fs.readFileSync(homedir + "/.kartik/mods/" + item + "/kartik.yml", "utf-8"));
+ } catch (e) {
+ unload(list, item);
+ console.error(e);
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": yaml parser error"
+ }
+ )
+ }
+ }
+}
+
+for (index in list) {
+ item = list[index];
+ mod = moddata[item];
+
+ roots = Object.keys(mod);
+
+ for (i1 in roots) {
+ r = roots[i1];
+ if (r !== "Meta" && r !== "Hook") {
+ unload(list, item);
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": invalid root section: " + r
+ }
+ )
+ }
+ }
+
+ for (i2 in Object.keys(mod["Meta"])) {
+ r = Object.keys(mod["Meta"])[i2];
+ if (r !== "Properties" && r !== "Hooks") {
+ unload(list, item);
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": invalid meta section: " + r
+ }
+ )
+ }
+ }
+
+ if (Object.keys(mod["Meta"]).length < 2) {
+ unload(list, item);
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": meta sections incomplete"
+ }
+ )
+ }
+
+ meta = mod["Meta"];
+
+ for (i3 in Object.keys(meta["Properties"])) {
+ r = Object.keys(meta["Properties"])[i3];
+ if (r !== "Mod.Name" && r !== "Mod.Version" && r !== "Mod.Author" && r !== "Mod.Required") {
+ unload(list, item);
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": invalid property: " + r
+ }
+ )
+ }
+ }
+
+ if (Object.keys(meta["Properties"]).length < 4) {
+ unload(list, item);
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": properties incomplete"
+ }
+ )
+ }
+
+ props = meta.Properties;
+
+ if (props["Mod.Required"].trim() !== "*") {
+ sver = require('../package.json').version.split(".").map((i) => { if (!isNaN((i - 1 + 1))) { return (i - 1 + 1).toString(); } else { return i; } }).join(".");
+ if (semver.valid(sver)) {
+ if (!semver.satisfies(sver, props["Mod.Required"].trim())) {
+ unload(list, item);
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": mod made for another version of Kartik"
+ }
+ )
+ }
+ } else {
+ if (require('../package.json').channel !== "git" && require('../package.json').channel !== "nightly") {
+ unload(list, item);
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": invalid game version"
+ }
+ )
+ }
+ }
+ }
+
+ hooks = meta["Hooks"];
+ hname = Object.keys(hooks);
+
+ for (i4 in hname) {
+ hookn = hname[i4];
+ hook = hooks[hookn];
+ if (typeof mod["Hook"][hook] === "undefined") {
+ unload(list, item);
+ dialog.showMessageBoxSync(
+ {
+ type: "error",
+ title: "Illegal Instruction",
+ message: "On package " + item + ": block " + hook + " required by hook " + hookn + " not found"
+ }
+ )
+ }
+ }
+}
+
+for (index in list) {
+ item = list[index];
+ mod = moddata[item];
+ meta = mod["Meta"];
+
+ hooks = meta["Hooks"];
+ hname = Object.keys(hooks);
+
+ for (i4 in hname) {
+ hookn = hname[i4];
+ hook = hooks[hookn];
+
+ mod["_Path"] = homedir + "/.kartik/mods/" + item;
+
+ require('./hooks')(mod, hookn, hook);
+ }
+}
+
+global.mods = list;
diff --git a/modding/resources.js b/modding/resources.js
new file mode 100644
index 0000000..7301901
--- /dev/null
+++ b/modding/resources.js
@@ -0,0 +1,65 @@
+const fs = require('fs');
+
+global.resources = {
+ music: {},
+ sfx: {},
+ races: {},
+ cars: {},
+ scenario: {
+ voice: {},
+ averi: {}
+ }
+};
+
+music_list = fs.readdirSync("./music");
+for (index in music_list) {
+ music = music_list[index];
+ name = music.split(".")[0];
+ resources.music[name] = {
+ file: KartikRoot + "/music/" + music,
+ original: true
+ };
+}
+
+sfx_list = fs.readdirSync("./sfx");
+for (index in sfx_list) {
+ sfx = sfx_list[index];
+ name = sfx.split(".")[0];
+ if (sfx.split(".")[1] === "mp3") {
+ resources.sfx[name] = KartikRoot + "/sfx/" + sfx;
+ }
+}
+
+races_list = fs.readdirSync("./race/circuits");
+for (index in races_list) {
+ races = races_list[index];
+ name = races.split(".")[0];
+ if (races.split(".")[1] === "html") {
+ resources.races[name] = "./race/circuits/" + races;
+ }
+}
+
+cars_list = fs.readdirSync("./race/models");
+for (index in cars_list) {
+ cars = cars_list[index];
+ name = cars.split(".")[0];
+ resources.cars[name] = KartikRoot + "/race/models/" + cars;
+}
+
+scvoice_list = fs.readdirSync("./scenario/voice");
+for (index in scvoice_list) {
+ scvoice = scvoice_list[index];
+ name = scvoice.split(".")[0];
+ resources.scenario.voice[name] = KartikRoot + "/scenario/voice/" + scvoice;
+}
+
+scchar_list = fs.readdirSync("./scenario/character");
+for (index in scchar_list) {
+ scchar = scchar_list[index];
+ name = scchar.split(".")[0];
+ resources.scenario.averi[name] = KartikRoot + "/scenario/character/" + scchar;
+}
+
+if (typeof building !== "undefined" && building) {
+ global.targetResources = JSON.stringify(resources);
+}