// ==UserScript==
// @name custom station models
// @namespace http://tampermonkey.net/
// @version 1.0
// @description Use custom station modules client-side
// @author plxyer-x
// @include https://starblast.io/#
// @icon https://starblast.io/static/img/icon64.png
// @grant none
// @license wat, nope
// ==/UserScript==
(async function () {
/*
shortcut (works on all systems, i think.):
* Ctrl + Shift + M to open import prompt
* Ctrl + Shift + Alt + M to toggle preload mode, which allows it to save the URL for preloading later
if it dont work, you must not have:
* ES6 or higher
* Support fetch() function
and if it dont work, well fuck you bitch :D
*/
if (document.querySelector("script#coffeescript") == null) {
let coffee = document.createElement("script");
coffee.id = "coffeescript";
coffee.src = "https://cdn.jsdelivr.net/gh/jashkenas/coffeescript@master/lib/coffeescript-browser-compiler-legacy/coffeescript.js";
document.head.appendChild(coffee)
}
this.SeedRandomizer = (function () {
function SeedRandomizer(_seed, hash) {
this._seed = _seed != null ? _seed : Math.random();
if (hash == null) {
hash = true;
}
if (this._seed === 0) {
this._seed = Math.random();
}
if (this._seed < 1) {
this._seed *= 1 << 30;
}
this.a = 13971;
this.b = 12345;
this.size = 1 << 30;
this.mask = this.size - 1;
this.norm = 1 / this.size;
if (hash) {
this.nextSeed();
this.nextSeed();
this.nextSeed();
}
}
SeedRandomizer.prototype.next = function () {
this._seed = (this._seed * this.a + this.b) & this.mask;
return this._seed * this.norm;
};
SeedRandomizer.prototype.nextInt = function (num) {
return Math.floor(this.next() * num);
};
SeedRandomizer.prototype.nextSeed = function () {
return this._seed = (this._seed * this.a + this.b) & this.mask;
};
SeedRandomizer.prototype.seed = function (_seed) {
this._seed = _seed != null ? _seed : Math.random();
if (this._seed < 1) {
this._seed *= 1 << 30;
}
this.nextSeed();
this.nextSeed();
return this.nextSeed();
};
SeedRandomizer.prototype.clone = function (seed) {
if (seed != null) {
return new SeedRandomizer(seed);
} else {
seed = this._seed;
return new SeedRandomizer(seed, false);
}
};
return SeedRandomizer;
})();
let oldAdd = this.StationModules.prototype.add, names = ["bodies", "wings", "tori"], parse = function (obj) {
let data = Object.assign({}, obj), newValue = {};
for (let key in data) {
let newV = data[key];
if ("object" == typeof newV) {
delete newV.laser;
delete newV.propeller;
newValue[key] = newV
}
}
return newValue
}, generateT = function (modul, args) {
let res = {};
if ("function" == typeof modul.generate) Object.assign(res, modul.generate.apply(modul, args));
let newRes = {};
newRes.rotate = !!res.rotate;
newRes.size = Math.max(res.size, 1) || 1;
for (let name of names) newRes[name] = parse(res[name]);
return newRes
};
this.StationModules.prototype.add = function (modul) {
modul = Object.assign({}, modul);
let type = modul.type, id = modul.id, revertDirection = !!modul.revertDirection, generate = function () {
return generateT(modul, arguments)
}, modl = this.modules.find(v => v && v.type === type && v.id === id);
if (modl) Object.assign(modl, {
generate: generate,
revertDirection: revertDirection
});
else oldAdd.call(this, modl = {
type: type,
id: id,
revertDirection: revertDirection,
generate: generate
});
return modl
}
let STATION_MODULES = new this.StationModules, SM = this.StationModel, __proto__ = SM.prototype, repl = function (func, ind, noEval, exc, flags) {
let res = "(" + String(func).replace(new RegExp('([' + (exc ? "^" : "") + ind + ']\\s*)((\\w+)\\.dir)', flags || ""), "$1(!!STATION_MODULES.types_by_id[$3.type].revertDirection*2+$2)") + ")";
return noEval ? res : eval(res)
};
SM = eval(repl(SM, "*", true).replace(/((\w+)\.dir\s*=\s*(\w+)\.dir)/, "$1,$2.revertDirection=STATION_MODULES.types_by_id[$3.type].revertDirection").replace(/\.generate\(([^\)]+?)\)/, ".generate($1, SeedRandomizer)"));
__proto__.constructor = SM;
SM.prototype = __proto__;
this.StationModel = SM;
let y = TeamBoard.prototype, key = Object.keys(y).find(v => y[v] && String(y[v]).includes("STATION_MODULES")), t = function (t, e) { return this.module.exports.translate(t, e) }.bind(this);
y[key] = repl(y[key], '=');
let stmodel = StationModuleModel;
let carpet = stmodel.prototype.updateCarpet;
stmodel.prototype.updateCarpet = eval("(" + String(carpet).replace(/((\w+\.rotation\.)x.+)}$/, "$1,this.carpet.$2z=!!this.revertDirection*Math.PI}") + ")");
for (let i in stmodel) {
let val = stmodel[i];
if ("function" == typeof val && (val = val.toString()).includes(".generate(")) stmodel[i] = Function(stmodel.name, "return " + val.replace(/\.generate\(([^\)]+?)\)/, ".generate($1, SeedRandomizer)"))(stmodel)
}
this.CustomStationModuleModels = {
console: {
color: "#FFFF00",
name: "CustomStationModuleModelsLoader",
handle: function (action, ...logs) { return console[action](`%c[${this.name}] ` + logs[0], `color: ${this.color}`, ...logs.slice(1)) },
log: function (...logs) { return this.handle("log", ...logs) },
error: function (...logs) { return this.handle("error", ...logs) },
warn: function (...logs) { return this.handle("warn", ...logs) }
},
list: STATION_MODULES,
import: async function (URL) {
if (URL == null) return this.reset();
this.console.log("Importing station module models...");
try {
let data = JSON.parse(await (await window.fetch(URL)).text());
for (let i of data.data) this.set(i.generate, i.type, i.id, true);
this.update();
this.console.log("Imported module models from the pack '" + (data.name || "Unknown") + "' by " + (data.author || "Anonymous") + ".");
return true
}
catch (e) {
this.console.error(`Failed to import the module models (${URL}). Caught error:`, e);
this.reset();
return false
}
},
local: {
prefix: "CustomStationModuleModels_",
data: function (name, val) {
switch (arguments.length) {
case 0: return null;
case 1: return localStorage.getItem(this.prefix + name);
default:
if (val == null) return localStorage.removeItem(this.prefix + name), null;
localStorage.setItem(this.prefix + name, val);
return this.data(name);
}
}
},
reset: async function () {
return await this.import("https://raw.githubusercontent.com/Bhpsngum/starblast-snippets/master/CustomStationModuleModels/Robonuko_RTX/manifest.json")
},
set: function (coffeescript, type, ID, ignoreUpdate) {
let model = {
id: ID,
type: type,
generate: Function("seed", "SeedRandomizer", "return " + CoffeeScript.compile(coffeescript))
}
if (this.list.types_by_id[ID] != null) this.list.types_by_id[ID].generate = model.generate;
else this.list.add(model);
if (!ignoreUpdate) this.update()
},
update: function () {
let data = Object.values(window.module.exports.settings).find(v => v && v.mode), mode = data.mode;
if (mode.id != 'team') return;
let smodel = mode.teams[0].station_model, rev = Object.keys(smodel).find(k => smodel[k] && smodel[k].type == "Group"), add;
for (let i in data) {
if (data[i].seed) {
for (let j in data[i]) {
if (Array.isArray(data[i][j].stations)) {
add = data[i][j];
break;
}
}
break;
}
}
for (let team of mode.teams) team.station_model[rev].remove(...team.station_model.modules.map(i => i[rev]))
add.stations = [];
for (let team of mode.teams) {
team.station_model = new StationModel(team.station_desc, team);
add.addStation(team.station_model);
}
window.StationModuleModel.images_buffer = [];
},
initialize: function () {
let wait = setInterval(function () {
try { CoffeeScript } catch (e) { return }
clearInterval(wait);
let loadURL = this.local.data("importURL");
if (this.local.data("keepURL") == '1' && loadURL != null) this.import(loadURL);
else this.reset();
window.addEventListener('keydown', function (e) {
if (e.ctrlKey && e.shiftKey) switch (e.keyCode) {
case 77: /* M */ {
if (e.altKey) {
let enableSave = !(this.local.data('keepURL') == '1'), status = enableSave ? "ENABLED" : "DISABLED";
this.local.data('keepURL', +enableSave);
alert(`Preload mode for Custom Station Module Modules Loader is ${status}`);
this.console.log(`Preload mode is ${status}`);
break;
}
let res = prompt("Paste manifest file (JSON format) URL here to import station module models (leave blank to reset):");
if (res != null) {
res = res == '' ? null : res;
if (confirm("Do you want to save this URL for preloading later?")) this.local.data("importURL", res);
this.import(res).then(success => {
alert(success ? "Station module models successfully loaded." : "Failed to import station module models. Check DevTools console for more details.")
});
}
break
}
}
}.bind(this));
}.bind(this), 500);
}
}
this.CustomStationModuleModels.initialize();
}).call(window);