prosperon/scripts/engine.js

368 lines
8.8 KiB
JavaScript
Raw Normal View History

2023-12-11 16:59:59 -06:00
"use math";
2024-08-06 14:23:21 -05:00
os.mem_limit.doc = "Set the memory limit of the runtime in bytes.";
os.gc_threshold.doc = "Set the threshold before a GC pass is triggered in bytes. This is set to malloc_size + malloc_size>>1 after a GC pass.";
os.max_stacksize.doc = "Set the max stack size in bytes.";
2024-08-05 15:26:18 -05:00
2024-09-26 11:36:09 -05:00
Object.defineProperty(String.prototype, "rm", {
value: function (index, endidx = index + 1) {
return this.slice(0, index) + this.slice(endidx);
},
});
2024-06-18 16:14:23 -05:00
Object.defineProperty(String.prototype, "tolast", {
value: function (val) {
2024-04-01 17:58:29 -05:00
var idx = this.lastIndexOf(val);
if (idx === -1) return this.slice();
2024-06-18 16:14:23 -05:00
return this.slice(0, idx);
},
2024-04-01 17:58:29 -05:00
});
2024-06-18 16:14:23 -05:00
Object.defineProperty(String.prototype, "dir", {
value: function () {
if (!this.includes("/")) return "";
return this.tolast("/");
},
2024-04-01 17:58:29 -05:00
});
2024-06-18 16:14:23 -05:00
Object.defineProperty(String.prototype, "folder", {
value: function () {
var dir = this.dir();
if (!dir) return "";
else return dir + "/";
2024-06-18 16:14:23 -05:00
},
});
2024-04-01 17:58:29 -05:00
globalThis.Resources = {};
2024-09-26 11:36:09 -05:00
Resources.rm_fn = function rm_fn(fn, text) {
var reg = new RegExp(fn.source + "\\s*\\(");
var match;
2024-09-26 11:36:09 -05:00
while ((match = text.match(reg))) {
var last = match.index + match[0].length;
var par = 1;
while (par !== 0) {
2024-09-26 11:36:09 -05:00
if (text[last] === "(") par++;
if (text[last] === ")") par--;
last++;
}
text = text.rm(match.index, last);
}
2024-07-25 16:14:37 -05:00
return text;
2024-09-26 11:36:09 -05:00
};
2024-07-25 16:14:37 -05:00
Resources.rm_fn.doc = "Remove calls to a given function from a given text script.";
Resources.replpath = function replpath(str, path) {
2024-04-01 17:58:29 -05:00
if (!str) return str;
2024-06-18 16:14:23 -05:00
if (str[0] === "/") return str.rm(0);
2024-04-01 17:58:29 -05:00
2024-06-18 16:14:23 -05:00
if (str[0] === "@") return os.prefpath() + "/" + str.rm(0);
2024-04-01 17:58:29 -05:00
if (!path) return str;
2024-06-18 16:14:23 -05:00
2024-04-01 17:58:29 -05:00
var stem = path.dir();
while (stem) {
2024-06-18 16:14:23 -05:00
var tr = stem + "/" + str;
2024-04-01 17:58:29 -05:00
if (io.exists(tr)) return tr;
stem = stem.updir();
}
return str;
2024-06-18 16:14:23 -05:00
};
2024-04-01 17:58:29 -05:00
Resources.replstrs = function replstrs(path) {
2024-04-01 17:58:29 -05:00
if (!path) return;
var script = io.slurp(path);
var regexp = /"[^"\s]*?\.[^"\s]+?"/g;
2024-08-30 14:17:37 -05:00
2024-04-01 17:58:29 -05:00
var stem = path.dir();
2024-08-30 14:17:37 -05:00
2024-09-26 11:36:09 -05:00
if (!console.enabled) script = Resources.rm_fn(/console\.(spam|info|warn|error)/, script);
if (!profile.enabled) script = Resources.rm_fn(/profile\.(cache|frame|endcache|endframe)/, script);
2024-07-25 22:07:22 -05:00
if (!debug.enabled) {
script = Resources.rm_fn(/assert/, script);
script = Resources.rm_fn(/debug\.(build|fn_break)/, script);
}
2024-09-26 11:36:09 -05:00
2024-06-18 16:14:23 -05:00
script = script.replace(regexp, function (str) {
2024-04-01 17:58:29 -05:00
var newstr = Resources.replpath(str.trimchr('"'), path);
return `"${newstr}"`;
});
return script;
2024-06-18 16:14:23 -05:00
};
2024-04-01 17:58:29 -05:00
2024-09-26 11:36:09 -05:00
Resources.is_sound = function (path) {
2024-08-24 18:40:29 -05:00
var ext = path.ext();
return Resources.sounds.any(x => x === ext);
2024-09-26 11:36:09 -05:00
};
Resources.is_animation = function (path) {
if (path.ext() === "gif" && Resources.gif.frames(path) > 1) return true;
if (path.ext() === "ase") return true;
2024-08-24 18:40:29 -05:00
return false;
2024-09-26 11:36:09 -05:00
};
2024-08-24 18:40:29 -05:00
2024-09-26 11:36:09 -05:00
Resources.is_path = function (str) {
2024-08-24 18:40:29 -05:00
return !/[\\\/:*?"<>|]/.test(str);
2024-09-26 11:36:09 -05:00
};
2024-08-24 18:40:29 -05:00
globalThis.json = {};
2024-06-18 16:14:23 -05:00
json.encode = function (value, replacer, space = 1) {
return JSON.stringify(value, replacer, space);
2024-06-18 16:14:23 -05:00
};
2024-06-18 16:14:23 -05:00
json.decode = function (text, reviver) {
if (!text) return undefined;
2024-06-18 16:14:23 -05:00
return JSON.parse(text, reviver);
};
2024-06-18 16:14:23 -05:00
json.readout = function (obj) {
var j = {};
for (var k in obj)
2024-06-18 16:14:23 -05:00
if (typeof obj[k] === "function") j[k] = "function " + obj[k].toString();
else j[k] = obj[k];
return json.encode(j);
2024-06-18 16:14:23 -05:00
};
json.doc = {
doc: "json implementation.",
encode: "Encode a value to json.",
decode: "Decode a json string to a value.",
2024-06-18 16:14:23 -05:00
readout: "Encode an object fully, including function definitions.",
};
Resources.scripts = ["jsoc", "jsc", "jso", "js"];
2024-10-01 18:10:52 -05:00
Resources.images = ["qoi", "png", "gif", "jpg", "jpeg"];
2024-06-18 16:14:23 -05:00
Resources.sounds = ["wav", "flac", "mp3", "qoa"];
2024-10-16 07:53:05 -05:00
Resources.fonts = ["ttf"];
2024-06-18 16:14:23 -05:00
Resources.is_image = function (path) {
var ext = path.ext();
2024-08-24 18:40:29 -05:00
return Resources.images.some(x => x === ext);
2024-06-18 16:14:23 -05:00
};
2024-10-02 09:55:32 -05:00
var res_cache = {};
2024-08-27 13:57:38 -05:00
function find_ext(file, ext, root = "") {
2024-08-24 18:40:29 -05:00
if (!file) return;
2024-08-27 13:57:38 -05:00
2024-08-24 18:40:29 -05:00
var file_ext = file.ext();
if (ext.some(x => x === file_ext)) return file;
for (var e of ext) {
var nf = `${file}.${e}`;
2024-09-26 11:36:09 -05:00
if (io.exists(nf)) return nf;
2024-08-27 13:57:38 -05:00
}
2024-08-30 14:17:37 -05:00
var all_files = io.glob(`**/${file}.*`);
2024-08-27 13:57:38 -05:00
var find = undefined;
for (var e of ext) {
var finds = all_files.filter(x => x.ext() === e);
2024-09-26 11:36:09 -05:00
if (finds.length > 1) console.warn(`Found conflicting files when searching for '${file}': ${json.encode(finds)}. Returning the first one.`);
2024-08-30 14:17:37 -05:00
if (finds.length > 0) {
2024-08-27 13:57:38 -05:00
find = finds[0];
break;
}
}
2024-08-27 13:57:38 -05:00
return find;
}
2024-08-27 13:57:38 -05:00
var hashhit = 0;
var hashmiss = 0;
2024-10-02 09:55:32 -05:00
globalThis.hashifier = {};
hashifier.stats = function()
{
}
2024-09-26 11:36:09 -05:00
Object.defineProperty(Function.prototype, "hashify", {
value: function () {
2024-08-27 13:57:38 -05:00
var hash = new Map();
var fn = this;
function ret() {
2024-09-26 11:36:09 -05:00
if (!hash.has(arguments[0])) hash.set(arguments[0], fn(...arguments));
2024-08-27 13:57:38 -05:00
return hash.get(arguments[0]);
}
return ret;
2024-09-26 11:36:09 -05:00
},
2024-08-27 13:57:38 -05:00
});
Resources.find_image = function (file, root = "") {
return find_ext(file, Resources.images, root);
}.hashify();
Resources.find_sound = function (file, root = "") {
return find_ext(file, Resources.sounds, root);
}.hashify();
Resources.find_script = function (file, root = "") {
return find_ext(file, Resources.scripts, root);
}.hashify();
2024-10-16 07:53:05 -05:00
Resources.find_font = function(file, root = "") {
return find_ext(file, Resources.fonts, root);
}.hashify();
2024-04-03 17:17:32 -05:00
console.transcript = "";
2024-06-18 16:14:23 -05:00
console.say = function (msg) {
msg += "\n";
2024-04-03 17:17:32 -05:00
console.print(msg);
2024-08-24 18:46:21 -05:00
if (debug.termout) console.term_print(msg);
2024-04-03 17:17:32 -05:00
console.transcript += msg;
};
console.log = console.say;
2024-04-15 07:58:23 -05:00
globalThis.say = console.say;
globalThis.print = console.print;
2024-04-03 17:17:32 -05:00
2024-06-18 16:14:23 -05:00
console.pprint = function (msg, lvl = 0) {
if (typeof msg === "object") msg = JSON.stringify(msg, null, 2);
2024-04-03 17:17:32 -05:00
var file = "nofile";
var line = 0;
2024-06-18 16:14:23 -05:00
console.rec(0, msg, file, line);
var caller = new Error().stack.split("\n")[2];
if (caller) {
2024-04-03 17:17:32 -05:00
var md = caller.match(/\((.*)\:/);
var m = md ? md[1] : "SCRIPT";
if (m) file = m;
md = caller.match(/\:(\d*)\)/);
m = md ? md[1] : 0;
if (m) line = m;
}
2024-06-18 16:14:23 -05:00
2024-04-03 17:17:32 -05:00
console.rec(lvl, msg, file, line);
};
2024-06-18 16:14:23 -05:00
console.spam = function (msg) {
console.pprint(msg, 0);
};
console.debug = function (msg) {
console.pprint(msg, 1);
};
console.info = function (msg) {
console.pprint(msg, 2);
};
console.warn = function (msg) {
console.pprint(msg, 3);
};
console.error = function (msg) {
console.pprint(msg + "\n" + console.stackstr(2), 4);
};
console.panic = function (msg) {
console.pprint(msg + "\n" + console.stackstr(2), 5);
};
console.stackstr = function (skip = 0) {
2024-04-03 17:17:32 -05:00
var err = new Error();
2024-06-18 16:14:23 -05:00
var stack = err.stack.split("\n");
return stack.slice(skip, stack.length).join("\n");
2024-04-03 17:17:32 -05:00
};
2024-06-18 16:14:23 -05:00
console.stack = function (skip = 0) {
2024-09-26 11:36:09 -05:00
var stack = console.stackstr(skip + 1);
2024-09-04 13:23:20 -05:00
console.log(stack);
return stack;
2024-06-18 16:14:23 -05:00
};
2024-03-23 09:56:38 -05:00
console.stdout_lvl = 1;
console.trace = console.stack;
console.doc = {
level: "Set level to output logging to console.",
info: "Output info level message.",
warn: "Output warn level message.",
error: "Output error level message, and print stacktrace.",
critical: "Output critical level message, and exit game immediately.",
write: "Write raw text to console.",
say: "Write raw text to console, plus a newline.",
stack: "Output a stacktrace to console.",
console: "Output directly to in game console.",
2024-06-18 16:14:23 -05:00
clear: "Clear console.",
};
2024-02-25 17:31:48 -06:00
globalThis.global = globalThis;
2023-05-24 20:45:50 -05:00
var use_cache = {};
2024-07-24 14:17:32 -05:00
2024-08-05 15:26:18 -05:00
globalThis.use = function use(file) {
file = Resources.find_script(file);
2024-06-18 16:14:23 -05:00
if (use_cache[file]) {
2024-10-02 09:55:32 -05:00
profile.report(`use_${file}`);
2024-08-05 15:26:18 -05:00
var ret = use_cache[file]();
2024-10-02 09:55:32 -05:00
profile.endreport(`use_${file}`);
2024-08-05 15:26:18 -05:00
return ret;
}
2024-10-02 09:55:32 -05:00
profile.report(`compile_${file}`);
2024-08-05 15:26:18 -05:00
var script = Resources.replstrs(file);
2024-04-01 17:58:29 -05:00
script = `(function() { var self = this; ${script}; })`;
2024-06-18 16:14:23 -05:00
var fn = os.eval(file, script);
use_cache[file] = fn;
2024-10-02 09:55:32 -05:00
profile.endreport(`compile_${file}`);
2024-08-05 15:26:18 -05:00
2024-10-02 09:55:32 -05:00
profile.report(`use_${file}`);
var ret = fn();
profile.endreport(`use_${file}`);
return ret;
2024-09-26 11:36:09 -05:00
};
2024-09-26 11:36:09 -05:00
function stripped_use(file, script) {
file = Resources.find_script(file);
2024-07-11 16:37:24 -05:00
if (use_cache[file]) {
2024-08-05 15:26:18 -05:00
var ret = use_cache[file]();
return ret;
2024-07-23 17:21:27 -05:00
}
script ??= Resources.replstrs(file);
2024-07-23 17:21:27 -05:00
script = `(function() { var self = this; ${script}; })`;
var fn = os.eval(file, script);
2024-08-05 15:26:18 -05:00
var ret = fn();
2024-09-26 11:36:09 -05:00
return ret;
2024-07-23 17:21:27 -05:00
}
2024-09-26 11:36:09 -05:00
function bare_use(file) {
var script = io.slurp(file);
2024-07-25 22:07:22 -05:00
if (!script) return;
script = `(function() { var self = this; ${script}; })`;
2024-08-05 15:26:18 -05:00
Object.assign(globalThis, os.eval(file, script)());
2024-04-23 15:58:08 -05:00
}
2024-07-25 22:07:22 -05:00
globalThis.debug = {};
profile.enabled = true;
console.enabled = true;
debug.enabled = true;
2023-11-22 03:51:43 -06:00
bare_use("scripts/base.js");
bare_use("scripts/profile.js");
2023-09-08 12:35:06 -05:00
2024-09-26 11:36:09 -05:00
prosperon.release = function () {
profile.enabled = false;
console.enabled = false;
debug.enabled = false;
2024-09-26 11:36:09 -05:00
};
2024-07-25 22:07:22 -05:00
bare_use("preconfig.js");
2024-09-26 11:36:09 -05:00
if (!profile.enabled) use = stripped_use;
Object.assign(globalThis, use("scripts/prosperon.js"));
2024-09-22 23:10:36 -05:00
app.interval(_ => {
2024-10-02 09:55:32 -05:00
profile.report("hotreload");
2024-09-22 23:10:36 -05:00
actor.hotreload();
render.hotreload();
game.tex_hotreload();
repl.hotreload();
2024-10-02 09:55:32 -05:00
profile.endreport("hotreload");
2024-09-22 23:10:36 -05:00
}, 1);