Add 'use' functionality; remove most global vars

This commit is contained in:
John Alanbrook 2024-02-27 16:09:15 +00:00
parent 4351b4bf20
commit de74b42be2
19 changed files with 365 additions and 382 deletions

View file

@ -287,7 +287,7 @@ cdb: tools/cdb.c tools/libcdb.a
source/engine/core.cdb.h: core.cdb source/engine/core.cdb.h: core.cdb
xxd -i $< > $@ xxd -i $< > $@
SCRIPTS := $(shell ls scripts/*.js) SCRIPTS := $(shell ls scripts/*.js*)
SCRIPT_O := $(addsuffix o, $(SCRIPTS)) SCRIPT_O := $(addsuffix o, $(SCRIPTS))
CORE != (ls icons/* fonts/*) CORE != (ls icons/* fonts/*)
CORE := $(CORE) $(SCRIPTS) CORE := $(CORE) $(SCRIPTS)
@ -301,7 +301,7 @@ CDB_C != find $(CDB) -name *.c
packer: tools/packer.c tools/libcdb.a packer: tools/packer.c tools/libcdb.a
cc $^ -I$(CDB) -o packer cc $^ -I$(CDB) -o packer
jso: tools/jso.c tools/libquickjs.a jsc: tools/jso.c tools/libquickjs.a
$(CC) $^ -lm -Iquickjs -o $@ $(CC) $^ -lm -Iquickjs -o $@
tools/libquickjs.a: tools/libquickjs.a:
@ -309,10 +309,6 @@ tools/libquickjs.a:
make -C quickjs OPT=$(OPT) AR=$(AR) libquickjs.a make -C quickjs OPT=$(OPT) AR=$(AR) libquickjs.a
cp -f quickjs/libquickjs.a tools cp -f quickjs/libquickjs.a tools
%.jso: %.js jso
@echo Making $@ from $<
./jso $< > $@
WINCC = x86_64-w64-mingw32-gcc WINCC = x86_64-w64-mingw32-gcc
#WINCC = i686-w64-mingw32-g++ #WINCC = i686-w64-mingw32-g++
.PHONY: crosswin .PHONY: crosswin
@ -329,7 +325,7 @@ crossmac:
clean: clean:
@echo Cleaning project @echo Cleaning project
@rm -rf bin dist @rm -rf bin dist
@rm -f shaders/*.sglsl.h shaders/*.metal core.cdb jso cdb packer scripts/*.jso TAGS @rm -f shaders/*.sglsl.h shaders/*.metal core.cdb jso cdb packer TAGS
@make -C quickjs clean @make -C quickjs clean
docs: doc/prosperon.org docs: doc/prosperon.org

View file

@ -48,20 +48,35 @@ The scripting language used in Prosperon is Javascript, with QuickJS. It is [[ht
Javascript is used here mostly to set up objects and tear them down. Although computationally expensive tasks can be done using QuickJS, Prosperon makes it easy to extend with raw C. Javascript is used here mostly to set up objects and tear them down. Although computationally expensive tasks can be done using QuickJS, Prosperon makes it easy to extend with raw C.
#+end_scholium #+end_scholium
*** How Prosperon games are structued *** How Prosperon games are structured
Prosperon schews the CommonJS and ES module systems for a custom one suitable for a computer game actor model. It is more restricted than either system, while retaining their full power.
Prosperon games are structured into two types of source files: Prosperon games are structured into two types of source files:
- scripts - scripts
- actors - actors
When any source file is executed, it is executed in its own space. Global properties are accessible, but any declared variables and functions are not automatically added to the global space. To add obejcts to the global space, it must be explicitly done, by assigning them to ~global~ or ~globalThis~. Scripts end with a return statement. A script can return a function, an object of functions, or any other sort of value.
#+begin_scholium
It is a common requirement to add some amount of functionality to an object. It can be easily done with a script file.
#+begin_src #+begin_src
global.hellofn = function() { say("Hello, world!"); }; // hellofn is now callable anywhere *script.js*
function hello() { say("hello"); };
return hello;
#+end_src #+end_src
#+begin_src
var o = {};
o.use("hello.js");
o.hello();
#+end_src
The ~use~ function on any object loads a module, and ~assign~s its return to the object.
#+end_scholium
When a *script* is loaded, its statements are executed in order, in the context of the containing source. The containing source is accessible via the ~$~ variable. When ~load~ is called, an optional object is permitted to be supplied as the ~$~. This makes writing scripts with mixin functionality simple. Scripts are loaded into memory only once. Further ~use~ statements only generate references to the statements. Because *scripts* are executed in a lambda environment, any ~var~ declared inside the script files are effectively private variables, persistent variables.
The parameter ~$$~ is given to a persistent object that is available whenever a script is executing, per script. In a *script*, ~this~ refers to ~undefined~. It is nothng.
In an *actor* source file, ~this~ refers to the actor. Actors do not end in a ~return~ statement. *actor* source is intended to set up a new agent in your game. Set up the new entity by loading modules and assigning functions to ~this~.
*** Script entry points *** Script entry points
The first way you can customize Prosperon is by adding scripts to the folder you're running it from. Any file ending with *.js* is a *script* which can be ran by Prosperon. The first way you can customize Prosperon is by adding scripts to the folder you're running it from. Any file ending with *.js* is a *script* which can be ran by Prosperon.
@ -92,9 +107,11 @@ The fundamental tool for building in Prosperon is the actor system. Actors run i
The most masterful actor is the *Empyrean*. The first actor you create will have the Empyrean as its master. Subsequent actors can use any other actor as its master. The most masterful actor is the *Empyrean*. The first actor you create will have the Empyrean as its master. Subsequent actors can use any other actor as its master.
| fn | description | | fn | description |
|--------------------+----------------------------------------------------------| |---------------------+----------------------------------------------------------|
| delay(fn, seconds) | Calls 'fn' after 'seconds' with the context of the actor | | spawn(text, config) | Creates an actor as the padawan of this one, using text |
| kill() | Kills an actor |
| delay(fn, seconds) | Calls 'fn' after 'seconds' with the context of the actor |
*** Actor Lifetime *** Actor Lifetime
When an actor dies, all of the actors that have it as their master[fn::What a mouthful!] will die as well. When an actor dies, all of the actors that have it as their master[fn::What a mouthful!] will die as well.
@ -103,7 +120,6 @@ When an actor dies, all of the actors that have it as their master[fn::What a mo
Actors get fragments of time called a *turn*. Actors which belong to different systems can have different lengths of turns. Actors get fragments of time called a *turn*. Actors which belong to different systems can have different lengths of turns.
*** Actor files *** Actor files
Actor files end with the extension *.jso*[fn::"Javascript object".]. They list a series of functions to call on a newly formed actor. Actors have a number of useful functions which are called as defined. Actor files end with the extension *.jso*[fn::"Javascript object".]. They list a series of functions to call on a newly formed actor. Actors have a number of useful functions which are called as defined.
@ -168,6 +184,8 @@ Game worlds are made of entities. Entities are a type of actor with a number of
The first and most masterful entity is the Primum. The Primum has no components, and its rotation and position are zero. It defines the center of the game. The first and most masterful entity is the Primum. The Primum has no components, and its rotation and position are zero. It defines the center of the game.
#+end_scholium #+end_scholium
In editor mode, when an entity moves, all of its *padawans* also move. When the game is actively simulating, this only holds if there are physical constraints between them.
*** Adding Components *** Adding Components
Entities can have *components*. Components are essentially javascript wrappers over C code into the engine. Scripting is done to set the components up on entities, after which most of the work is done by the C plugin. Entities can have *components*. Components are essentially javascript wrappers over C code into the engine. Scripting is done to set the components up on entities, after which most of the work is done by the C plugin.

View file

@ -572,6 +572,16 @@ Object.defineProperty(Object.prototype, 'obscure', {
} }
}); });
Object.defineProperty(Object.prototype, 'mixin', {
value: function(obj) {
if (typeof obj === 'string') {
obj = use(obj);
if (!obj) return;
}
Object.assign(this, obj);
},
});
Object.defineProperty(Object.prototype, 'hasOwn', { Object.defineProperty(Object.prototype, 'hasOwn', {
value: function(x) { return this.hasOwnProperty(x); } value: function(x) { return this.hasOwnProperty(x); }
}); });
@ -1329,7 +1339,7 @@ Math.randomint = function(max) { return Math.clamp(Math.floor(Math.random() * ma
/* BOUNDINGBOXES */ /* BOUNDINGBOXES */
var bbox = {}; var bbox = {};
function cwh2bb(c, wh) { bbox.fromcwh = function(c, wh) {
return { return {
t: c.y+(wh.y/2), t: c.y+(wh.y/2),
b: c.y-(wh.y/2), b: c.y-(wh.y/2),
@ -1338,7 +1348,7 @@ function cwh2bb(c, wh) {
}; };
}; };
function points2bb(points) { bbox.frompoints = function(points) {
var b= {t:0,b:0,l:0,r:0}; var b= {t:0,b:0,l:0,r:0};
points.forEach(function(x) { points.forEach(function(x) {
@ -1351,7 +1361,7 @@ function points2bb(points) {
return b; return b;
}; };
function bb2points(bb) bbox.topoints = function(bb)
{ {
return [ return [
[bb.l,bb.t], [bb.l,bb.t],
@ -1361,20 +1371,7 @@ function bb2points(bb)
]; ];
} }
function points2cwh(start,end) bbox.tocwh = function(bb) {
{
var c = [];
c[0] = (end[0] - start[0]) / 2;
c[0] += start[0];
c[1] = (end[1] - start[1]) / 2;
c[1] += start[1];
var wh = [];
wh[0] = Math.abs(end[0] - start[0]);
wh[1] = Math.abs(end[1] - start[1]);
return {c: c, wh: wh};
}
function bb2cwh(bb) {
if (!bb) return undefined; if (!bb) return undefined;
var cwh = {}; var cwh = {};
@ -1386,7 +1383,11 @@ function bb2cwh(bb) {
return cwh; return cwh;
}; };
function pointinbb(bb, p) bbox.towh = function(bb) {
return [bb.r-bb.l, bb.t-bb.b];
};
bbox.pointin = function(bb, p)
{ {
if (bb.t < p.y || bb.b > p.y || bb.l > p.x || bb.r < p.x) if (bb.t < p.y || bb.b > p.y || bb.l > p.x || bb.r < p.x)
return false; return false;
@ -1394,7 +1395,7 @@ function pointinbb(bb, p)
return true; return true;
} }
function movebb(bb, pos) { bbox.move = function(bb, pos) {
var newbb = Object.assign({}, bb); var newbb = Object.assign({}, bb);
newbb.t += pos.y; newbb.t += pos.y;
newbb.b += pos.y; newbb.b += pos.y;
@ -1403,7 +1404,7 @@ function movebb(bb, pos) {
return newbb; return newbb;
}; };
function bb_expand(oldbb, x) { bbox.expand = function(oldbb, x) {
if (!oldbb || !x) return; if (!oldbb || !x) return;
var bb = {}; var bb = {};
Object.assign(bb, oldbb); Object.assign(bb, oldbb);
@ -1416,7 +1417,7 @@ function bb_expand(oldbb, x) {
return bb; return bb;
}; };
function bl2bb(bl, wh) bbox.blwh = function(bl,wh)
{ {
return { return {
b: bl.y, b: bl.y,
@ -1426,17 +1427,15 @@ function bl2bb(bl, wh)
}; };
} }
function bb_from_objects(objs) { bbox.blwh.doc = "Bounding box from (bottom left, width height)";
bbox.fromobjs = function(objs)
{
var bb = objs[0].boundingbox; var bb = objs[0].boundingbox;
objs.forEach(function(obj) { bb = bb_expand(bb, obj.boundingbox); }); objs.forEach(function(obj) { bb = bbox.expand(bb, obj.boundingbox); });
return bb; return bb;
}; };
var Boundingbox = {};
Boundingbox.width = function(bb) { return bb.r - bb.l; };
Boundingbox.height = function(bb) { return bb.t - bb.b; };
Boundingbox.bl = function(bb) { return [bb.l, bb.b] };
/* VECTORS */ /* VECTORS */
var Vector = { var Vector = {
length(v) { length(v) {
@ -1527,3 +1526,12 @@ Math.sortpointsccw = function(points)
return ccw.map(function(x) { return x.add(cm); }); return ccw.map(function(x) { return x.add(cm); });
} }
return {
convert,
time,
json,
Vector,
bbox
};

View file

@ -197,3 +197,9 @@ ColorMap.doc = {
}; };
Object.freeze(ColorMap); Object.freeze(ColorMap);
return {
Color,
esc,
ColorMap
}

View file

@ -367,7 +367,7 @@ component.polygon2d = Object.copy(collider2d, {
flipy: false, flipy: false,
boundingbox() { boundingbox() {
return points2bb(this.spoints()); return bbox.frompoints(this.spoints());
}, },
hides: ['id', 'shape', 'gameobject'], hides: ['id', 'shape', 'gameobject'],
@ -538,7 +538,7 @@ component.edge2d = Object.copy(collider2d, {
return Spline.sample_angle(this.type, spoints, this.angle); return Spline.sample_angle(this.type, spoints, this.angle);
}, },
boundingbox() { return points2bb(this.points.map(x => x.scale(this.gameobject.scale))); }, boundingbox() { return bbox.frompoints(this.points.map(x => x.scale(this.gameobject.scale))); },
hides: ['gameobject', 'id', 'shape'], hides: ['gameobject', 'id', 'shape'],
_enghook: make_edge2d, _enghook: make_edge2d,
@ -822,3 +822,5 @@ component.circle2d.impl = Object.mix({
set pos(x) { this.offset = x; }, set pos(x) { this.offset = x; },
}, collider2d.impl); }, collider2d.impl);
return {component};

View file

@ -93,7 +93,7 @@ var Debug = {
boundingbox(bb, color) { boundingbox(bb, color) {
color ??= Color.white; color ??= Color.white;
cmd_points(0, bb2points(bb), color); cmd_points(0, bbox.topoints(bb), color);
}, },
numbered_point(pos, n, color) { numbered_point(pos, n, color) {
@ -211,8 +211,6 @@ Object.assign(profile, {
get fps() { return sys_cmd(8); }, get fps() { return sys_cmd(8); },
}); });
profile.test = { profile.test = {
barecall() { profile(0); }, barecall() { profile(0); },
unpack_num(n) { profile(1,n); }, unpack_num(n) { profile(1,n); },
@ -419,3 +417,8 @@ Debug.api.print_doc = function(name)
return mdoc; return mdoc;
} }
return {
Debug,
Time,
}

View file

@ -1,114 +1,5 @@
function deep_copy(from) { return json.decode(json.encode(from)); } function deep_copy(from) { return json.decode(json.encode(from)); }
var walk_up_get_prop = function(obj, prop, endobj) {
var props = [];
var cur = obj;
while (cur !== Object.prototype) {
if (cur.hasOwn(prop))
props.push(cur[prop]);
cur = cur.__proto__;
}
return props;
};
/* Deeply remove source keys from target, not removing objects */
function unmerge(target, source) {
for (var key in source) {
if (typeof source[key] === 'object' && !Array.isArray(source[key]))
unmerge(target[key], source[key]);
else
delete target[key];
}
};
/* Deeply merge two objects, not clobbering objects on target with objects on source */
function deep_merge(target, source)
{
console.warn("Doing a deep merge ...");
for (var key in source) {
if (typeof source[key] === 'object' && !Array.isArray(source[key])) {
console.warn(`Deeper merge on ${key}`);
deep_merge(target[key], source[key]);
}
else {
console.warn(`Setting key ${key}`);
target[key] = source[key];
}
}
};
function equal(x,y) {
if (typeof x === 'object')
return json.encode(x) === json.encode(y);
return x === y;
};
function diffassign(target, from) {
if (Object.empty(from)) return;
for (var e in from) {
if (typeof from[e] === 'object') {
if (!target.hasOwnProperty(e))
target[e] = from[e];
else
diffassign(target[e], from[e]);
} else {
if (from[e] === "DELETE") {
delete target[e];
} else {
target[e] = from[e];
}
}
}
};
function objdiff(from,to)
{
var ret = {};
if (!to)
return ediff(from,{});
Object.entries(from).forEach(function([key,v]) {
if (typeof v === 'function') return;
if (typeof v === 'undefined') return;
if (Array.isArray(v)) {
if (!Array.isArray(to[key]) || v.length !== to[key].length)
ret[key] = Object.values(ediff(v, []));
var diff = ediff(from[key], to[key]);
if (diff && !Object.empty(diff))
ret[key] = Object.values(ediff(v,[]));
return;
}
if (typeof v === 'object') {
var diff = ediff(v, to[key]);
if (diff && !Object.empty(diff))
ret[key] = diff;
return;
}
if (typeof v === 'number') {
if (!to || v !== to[key])
ret[key] = v;
return;
}
if (!to || v !== to[key])
ret[key] = v;
});
if (Object.empty(ret)) return undefined;
return ret;
}
function valdiff(from,to) function valdiff(from,to)
{ {
if (typeof from !== typeof to) return from; if (typeof from !== typeof to) return from;
@ -129,17 +20,6 @@ function valdiff(from,to)
return undefined; return undefined;
} }
/* Returns the json encoded object, assuming it has an implementation it must check through */
function impl_json(obj)
{
}
function ndiff(from,to)
{
}
function ediff(from,to) function ediff(from,to)
{ {
var ret = {}; var ret = {};
@ -189,13 +69,6 @@ function ediff(from,to)
ediff.doc = "Given a from and to object, returns an object that, if applied to from, will make it the same as to. Does not include deletion; it is only additive."; ediff.doc = "Given a from and to object, returns an object that, if applied to from, will make it the same as to. Does not include deletion; it is only additive.";
function subdiff(from,to)
{
}
subdiff.doc = "Given a from and to object, returns a list of properties that must be deleted from the 'from' object to make it like the 'to' object.";
function samediff(from, to) function samediff(from, to)
{ {
var same = []; var same = [];
@ -225,6 +98,8 @@ function samediff(from, to)
samediff.doc = "Given a from and to object, returns an array of keys that are the same on from as on to."; samediff.doc = "Given a from and to object, returns an array of keys that are the same on from as on to.";
function cleandiff(from, to) return {
{ deep_copy,
ediff,
samediff,
} }

View file

@ -2,7 +2,7 @@
Editor-only variables on objects Editor-only variables on objects
selectable selectable
*/ */
prototypes.generate_ur('.'); //prototypes.generate_ur('.');
var editor = { var editor = {
toString() { return "editor"; }, toString() { return "editor"; },
@ -166,7 +166,7 @@ var editor = {
}, },
zoom_to_bb(bb) { zoom_to_bb(bb) {
var cwh = bb2cwh(bb); var cwh = bbox.tocwh(bb);
var xscale = cwh.wh.x / Window.width; var xscale = cwh.wh.x / Window.width;
var yscale = cwh.wh.y / Window.height; var yscale = cwh.wh.y / Window.height;
@ -221,7 +221,7 @@ var editor = {
editor.cbs.push(Register.gui.register(editor.gui.bind(editor))); editor.cbs.push(Register.gui.register(editor.gui.bind(editor)));
editor.cbs.push(Register.draw.register(editor.draw.bind(editor))); editor.cbs.push(Register.draw.register(editor.draw.bind(editor)));
editor.cbs.push(Register.debug.register(editor.ed_debug.bind(editor))); editor.cbs.push(Register.debug.register(editor.ed_debug.bind(editor)));
editor.cbs.push(Register.update.register(gui_controls.update, gui_controls)); editor.cbs.push(Register.update.register(GUI.controls.update, GUI.controls));
this.desktop = Primum.spawn(ur.arena); this.desktop = Primum.spawn(ur.arena);
Primum.rename_obj(this.desktop.toString(), "desktop"); Primum.rename_obj(this.desktop.toString(), "desktop");
@ -377,7 +377,7 @@ var editor = {
x.gizmo(); x.gizmo();
}); });
render.line(bb2points(cwh2bb([0,0],[Game.native.x,Game.native.y])).wrapped(1), Color.yellow); render.line(bbox.topoints(bbox.fromcwh([0,0],[Game.native.x,Game.native.y])).wrapped(1), Color.yellow);
/* Draw selection box */ /* Draw selection box */
if (this.sel_start) { if (this.sel_start) {
@ -390,9 +390,9 @@ var editor = {
var wh = []; var wh = [];
wh[0] = Math.abs(endpos[0] - this.sel_start[0]); wh[0] = Math.abs(endpos[0] - this.sel_start[0]);
wh[1] = Math.abs(endpos[1] - this.sel_start[1]); wh[1] = Math.abs(endpos[1] - this.sel_start[1]);
var bb = cwh2bb(c,wh); var bb = bbox.fromcwh(c,wh);
Debug.boundingbox(bb, Color.Editor.select.alpha(0.1)); Debug.boundingbox(bb, Color.Editor.select.alpha(0.1));
render.line(bb2points(bb).wrapped(1), Color.white); render.line(bbox.topoints(bb).wrapped(1), Color.white);
} }
}, },
@ -718,7 +718,7 @@ editor.inputs.q.doc = "Toggle help for the selected component.";
editor.inputs.f = function() { editor.inputs.f = function() {
if (editor.selectlist.length === 0) return; if (editor.selectlist.length === 0) return;
var bb = editor.selectlist[0].boundingbox(); var bb = editor.selectlist[0].boundingbox();
editor.selectlist.forEach(function(obj) { bb = bb_expand(bb, obj.boundingbox()); }); editor.selectlist.forEach(function(obj) { bb = bbox.expand(bb, obj.boundingbox()); });
editor.zoom_to_bb(bb); editor.zoom_to_bb(bb);
}; };
editor.inputs.f.doc = "Find the selected objects."; editor.inputs.f.doc = "Find the selected objects.";
@ -972,11 +972,9 @@ editor.inputs.lm.released = function() {
var sel = editor.try_select(); var sel = editor.try_select();
if (sel) selects.push(sel); if (sel) selects.push(sel);
} else { } else {
var box = points2cwh(editor.sel_start, Mouse.worldpos); var box = bbox.frompoints([editor.sel_start, Mouse.worldpos]);
box.pos = box.c; var hits = physics.box_query(bbox.tocwh(box));
var hits = physics.box_query(box);
hits.forEach(function(x, i) { hits.forEach(function(x, i) {
var obj = editor.do_select(x); var obj = editor.do_select(x);
@ -1466,10 +1464,10 @@ inputpanel.inputs['C-k'] = function() {
inputpanel.inputs.lm = function() inputpanel.inputs.lm = function()
{ {
gui_controls.check_submit(); GUI.controls.check_submit();
} }
load("scripts/textedit.js"); //load("scripts/textedit.js");
var replpanel = Object.copy(inputpanel, { var replpanel = Object.copy(inputpanel, {
title: "", title: "",
@ -1998,3 +1996,7 @@ if (io.exists("editor.config"))
Game.stop(); Game.stop();
Game.editor_mode(true); Game.editor_mode(true);
Debug.draw_phys(true); Debug.draw_phys(true);
return {
editor
}

View file

@ -1,44 +1,54 @@
"use math"; "use math";
globalThis.global = globalThis; globalThis.global = globalThis;
function eval_env(script, env) function use(file)
{
if (use.files[file]) return use.files[file];
var c = io.slurp(file);
var script = `(function() { ${c} })();`;
use.files[file] = cmd(123,script,global,file);
return use.files[file];
}
use.files = {};
function eval_env(script, env, file)
{ {
env ??= {}; env ??= {};
// script = `function() { ${script} }.call();`; file ??= "SCRIPT";
// script = `(function() { ${script} })();`;
eval(`(function() { ${script} }).call(env);`);
// cmd(123,script,global,file);
// return eval(script); // return eval(script);
return function(str) { return eval(str); }.call(env, script); // return function(str) { return eval(str); }.call(env, script);
} }
eval_env.dov = `Counterpart to /load_env/, but with a string.`; eval_env.dov = `Counterpart to /load_env/, but with a string.`;
function load_env(file,env) function load_env(file,env)
{ {
env ??= global; env ??= global;
// var script = io.slurp(file);
var script = io.slurp(file); var script = io.slurp(file);
eval_env(script, env); eval_env(script, env, file);
// cmd(16, file, env); // cmd(16, file, env);
// var script = io.slurp(file); // var script = io.slurp(file);
// cmd(123, script, env, file); // cmd(123, script, env, file);
} }
load_env.doc = `Load a given file with 'env' as **this**. Does not add to the global namespace.`; load_env.doc = `Load a given file with 'env' as **this**. Does not add to the global namespace.`;
function load(file) { return load_env(file);} var load = use;
load.doc = `Load a given script file into the global namespace.`;
Object.assign(global, use("scripts/base.js"));
global.obscure('global');
global.mixin(use("scripts/std.js"));
global.mixin(use("scripts/diff.js"));
load("scripts/base.js");
load("scripts/std.js");
load("scripts/diff.js");
console.level = 1; console.level = 1;
load("scripts/color.js"); global.mixin(use("scripts/color.js"));
function bb2wh(bb) {
return [bb.r-bb.l, bb.t-bb.b];
};
var prosperon = {}; var prosperon = {};
prosperon.version = cmd(255); prosperon.version = cmd(255);
@ -94,7 +104,7 @@ Range is given by a semantic versioning number, prefixed with nothing, a ~, or a
^ means that MAJOR must match exactly, but any MINOR and PATCH greater or equal is valid.`; ^ means that MAJOR must match exactly, but any MINOR and PATCH greater or equal is valid.`;
load("scripts/gui.js"); global.mixin(use("scripts/gui.js"));
var timer = { var timer = {
update(dt) { update(dt) {
@ -170,11 +180,11 @@ render.device = {
render.device.doc = `Device resolutions given as [x,y,inches diagonal].`; render.device.doc = `Device resolutions given as [x,y,inches diagonal].`;
load("scripts/physics.js"); global.mixin(use("scripts/physics.js"));
load("scripts/input.js"); global.mixin(use("scripts/input.js"));
load("scripts/sound.js"); global.mixin(use("scripts/sound.js"));
load("scripts/ai.js"); global.mixin(use("scripts/ai.js"));
load("scripts/geometry.js"); global.mixin(use("scripts/geometry.js"));
var Register = { var Register = {
kbm_input(mode, btn, state, ...args) { kbm_input(mode, btn, state, ...args) {
@ -310,18 +320,21 @@ var Window = {
}; };
Window.screen2world = function(screenpos) { Window.screen2world = function(screenpos) {
if (Game.camera) // if (Game.camera)
return Game.camera.view2world(screenpos); // return Game.camera.view2world(screenpos);
return screenpos; return screenpos;
} }
Window.world2screen = function(worldpos) { return Game.camera.world2view(worldpos); } Window.world2screen = function(worldpos) {
return worldpos;
return Game.camera.world2view(worldpos);
}
Window.icon = function(path) { cmd(90, path); }; Window.icon = function(path) { cmd(90, path); };
Window.icon.doc = "Set the icon of the window using the PNG image at path."; Window.icon.doc = "Set the icon of the window using the PNG image at path.";
load("scripts/debug.js"); global.mixin(use("scripts/debug.js"));
load('scripts/spline.js'); global.mixin(use("scripts/spline.js"));
load("scripts/components.js"); global.mixin(use("scripts/components.js"));
var Game = { var Game = {
engine_start(fn) { engine_start(fn) {
@ -355,7 +368,10 @@ var Game = {
}, },
quit() { sys_cmd(0); }, quit() {
sys_cmd(0);
return;
},
pause() { sys_cmd(3); }, pause() { sys_cmd(3); },
stop() { Game.pause(); }, stop() { Game.pause(); },
step() { sys_cmd(4);}, step() { sys_cmd(4);},
@ -404,7 +420,7 @@ Window.doc.boundingbox = "Boundingbox of the window, with top and right being it
Register.update.register(Game.exec, Game); Register.update.register(Game.exec, Game);
load("scripts/entity.js"); global.mixin(use("scripts/entity.js"));
function world_start() { function world_start() {
globalThis.Primum = Object.create(gameobject); globalThis.Primum = Object.create(gameobject);
@ -424,9 +440,11 @@ function world_start() {
gameobject.body = make_gameobject(); gameobject.body = make_gameobject();
cmd(113,gameobject.body, gameobject); cmd(113,gameobject.body, gameobject);
Object.hide(gameobject, 'timescale'); Object.hide(gameobject, 'timescale');
global.world = Primum;
} }
load("scripts/physics.js"); global.mixin(use("scripts/physics.js"));
Game.view_camera = function(cam) Game.view_camera = function(cam)
{ {
@ -434,6 +452,10 @@ Game.view_camera = function(cam)
cmd(61, Game.camera.body); cmd(61, Game.camera.body);
} }
prototypes.generate_ur('scripts/camera.jso');
Window.title(`Prosperon v${prosperon.version}`); Window.title(`Prosperon v${prosperon.version}`);
Window.width = 1280; Window.width = 1280;
Window.height = 720; Window.height = 720;

View file

@ -12,34 +12,37 @@ prosperon.obj_unique_name = function(name, obj)
} }
var actor = {}; var actor = {};
var a_db = {};
actor.spawn = function(script, config){ actor.spawn = function(script, config){
if (typeof script !== 'string') return; if (typeof script !== 'string') return undefined;
if (!a_db[script]) a_db[script] = io.slurp(script);
var padawan = Object.create(actor); var padawan = Object.create(actor);
eval_env(script, padawan); eval_env(a_db[script], padawan);
if (typeof config === 'object') if (typeof config === 'object')
Object.merge(padawan, config); Object.merge(padawan,config);
padawan.padawans = []; padawan.padawans = [];
padawan.timers = []; padawan.timers = [];
padawan.master = this; padawan.master = this;
Object.hide(padawan, "master","timers"); Object.hide(padawan, "master","timers", "padawans");
this.padawans.push(padawan); this.padawans.push(padawan);
return padawan; return padawan;
}; };
actor.spawn.doc = `Create a new actor, using this actor as the master, initializing it with 'script' and with data (as a JSON or Nota file) from 'config'.`; actor.spawn.doc = `Create a new actor, using this actor as the master, initializing it with 'script' and with data (as a JSON or Nota file) from 'config'.`;
actor.die = function(e){
e.kill();
};
actor.timers = []; actor.timers = [];
actor.kill = function(){ actor.kill = function(){
if (this.__dead__) return;
this.timers.forEach(t => t.kill()); this.timers.forEach(t => t.kill());
delete this.master[this.toString()]; if (this.master)
delete this.master[this.toString()];
this.padawans.forEach(p => p.kill()); this.padawans.forEach(p => p.kill());
this.padawans = [];
this.__dead__ = true; this.__dead__ = true;
if (typeof this.die === 'function') this.die();
}; };
actor.kill.doc = `Remove this actor and all its padawans from existence.`; actor.kill.doc = `Remove this actor and all its padawans from existence.`;
@ -73,6 +76,13 @@ actor.remaster = function(to){
to.padawans.push(this); to.padawans.push(this);
}; };
global.app = Object.create(actor);
app.die = function()
{
Game.quit();
}
var gameobject_impl = { var gameobject_impl = {
get pos() { get pos() {
Debug.assert(this.level, `Entity ${this.toString()} has no level.`); Debug.assert(this.level, `Entity ${this.toString()} has no level.`);
@ -88,6 +98,7 @@ var gameobject_impl = {
Debug.assert(this.level, `No level set on ${this.toString()}`); Debug.assert(this.level, `No level set on ${this.toString()}`);
return this.worldangle() - this.level.worldangle(); return this.worldangle() - this.level.worldangle();
}, },
set angle(x) { set angle(x) {
var diff = x - this.angle; var diff = x - this.angle;
@ -329,8 +340,10 @@ var gameobject = {
spawn(ur, data) { spawn(ur, data) {
ur ??= gameobject; ur ??= gameobject;
if (typeof ur === 'string') if (typeof ur === 'string') {
ur = prototypes.get_ur(ur); //ur = prototypes.get_ur(ur);
}
var go = ur.make(this, data); var go = ur.make(this, data);
Object.hide(this, go.toString()); Object.hide(this, go.toString());
@ -502,11 +515,11 @@ var gameobject = {
var bb = boxes.shift(); var bb = boxes.shift();
boxes.forEach(function(x) { bb = bb_expand(bb, x); }); boxes.forEach(function(x) { bb = bbox.expand(bb, x); });
bb = movebb(bb, this.pos); bb = bbox.move(bb, this.pos);
return bb ? bb : cwh2bb([0,0], [0,0]); return bb ? bb : bbox.fromcwh([0,0], [0,0]);
}, },
/* The unique components of this object. Its diff. */ /* The unique components of this object. Its diff. */
@ -606,7 +619,7 @@ var gameobject = {
right() { return [1,0].rotate(this.angle);}, right() { return [1,0].rotate(this.angle);},
left() { return [-1,0].rotate(this.angle); }, left() { return [-1,0].rotate(this.angle); },
make(level, data) { make() {
var obj = Object.create(this); var obj = Object.create(this);
obj.make = undefined; obj.make = undefined;
@ -998,3 +1011,10 @@ prototypes.ur_pullout_folder = function(ur)
if (io.exists(p)) if (io.exists(p))
*/ */
} }
return {
gameobject,
actor,
prototypes,
ur
}

View file

@ -38,7 +38,7 @@ var GUI = {
color ??= Color.black; color ??= Color.black;
var wh = cmd(64,path); var wh = cmd(64,path);
gui_img(path,pos, [1.0,1.0], 0.0, 0.0, [0.0,0.0], 0.0, Color.black); gui_img(path,pos, [1.0,1.0], 0.0, 0.0, [0.0,0.0], 0.0, Color.black);
return cwh2bb([0,0], wh); return bbox.fromcwh([0,0], wh);
}, },
input_lmouse_pressed() { input_lmouse_pressed() {
@ -69,11 +69,11 @@ var GUI = {
} }
}; };
var gui_controls = {}; GUI.controls = {};
gui_controls.toString = function() { return "GUI controls"; }; GUI.controls.toString = function() { return "GUI controls"; };
gui_controls.update = function() { }; GUI.controls.update = function() { };
gui_controls.set_mum = function(mum) GUI.controls.set_mum = function(mum)
{ {
mum.selected = true; mum.selected = true;
@ -82,22 +82,22 @@ gui_controls.set_mum = function(mum)
this.selected = mum; this.selected = mum;
} }
gui_controls.check_bb = function(mum) GUI.controls.check_bb = function(mum)
{ {
if (pointinbb(mum.bb, Mouse.pos)) if (bbox.pointin(mum.bb, Mouse.pos))
gui_controls.set_mum(mum); GUI.controls.set_mum(mum);
} }
gui_controls.inputs = {}; GUI.controls.inputs = {};
gui_controls.inputs.fallthru = false; GUI.controls.inputs.fallthru = false;
gui_controls.inputs.mouse = {}; GUI.controls.inputs.mouse = {};
gui_controls.inputs.mouse.move = function(pos,dpos) GUI.controls.inputs.mouse.move = function(pos,dpos)
{ {
} }
gui_controls.inputs.mouse.scroll = function(scroll) GUI.controls.inputs.mouse.scroll = function(scroll)
{ {
} }
gui_controls.check_submit = function() { GUI.controls.check_submit = function() {
if (this.selected && this.selected.action) if (this.selected && this.selected.action)
this.selected.action(this.selected); this.selected.action(this.selected);
} }
@ -159,7 +159,7 @@ Mum.text = Mum.extend({
draw(cursor, cnt) { draw(cursor, cnt) {
cnt ??= Mum; cnt ??= Mum;
if (this.hide) return; if (this.hide) return;
if (this.selectable) gui_controls.check_bb(this); if (this.selectable) GUI.controls.check_bb(this);
this.caret ??= -1; this.caret ??= -1;
/* if (!this.bb) /* if (!this.bb)
@ -179,14 +179,14 @@ Mum.text = Mum.extend({
}, },
update_bb(cursor) { update_bb(cursor) {
this.bb = movebb(this.bb, cursor.sub(this.wh.scale(this.anchor))); this.bb = bbox.move(this.bb, cursor.sub(this.wh.scale(this.anchor)));
}, },
calc_bb(cursor) { calc_bb(cursor) {
var bb = cmd(118,this.str, this.font_size, this.width); var bb = cmd(118,this.str, this.font_size, this.width);
this.wh = bb2wh(bb); this.wh = bbox.towh(bb);
var pos = cursor.add(this.wh.scale([0,1].sub(this.anchor))).add(this.offset); var pos = cursor.add(this.wh.scale([0,1].sub(this.anchor))).add(this.offset);
this.bb = movebb(bb,pos.add([this.wh.x/2,0])); this.bb = bbox.move(bb,pos.add([this.wh.x/2,0]));
}, },
start() { start() {
this.calc_bb([0,0]); this.calc_bb([0,0]);
@ -205,17 +205,17 @@ Mum.button = Mum.text._int.extend({
Mum.window = Mum.extend({ Mum.window = Mum.extend({
start() { start() {
this.wh = [this.width, this.height]; this.wh = [this.width, this.height];
this.bb = cwh2bb([0,0], this.wh); this.bb = bbox.fromcwh([0,0], this.wh);
}, },
draw(cursor, cnt) { draw(cursor, cnt) {
cnt ??= Mum; cnt ??= Mum;
var p = cursor.sub(this.wh.scale(this.anchor)).add(this.padding); var p = cursor.sub(this.wh.scale(this.anchor)).add(this.padding);
GUI.window(p,this.wh, this.color); GUI.window(p,this.wh, this.color);
this.bb = bl2bb(p, this.wh); this.bb = bbox.blwh(p, this.wh);
GUI.flush(); GUI.flush();
GUI.scissor(p.x,p.y,this.wh.x,this.wh.y); GUI.scissor(p.x,p.y,this.wh.x,this.wh.y);
this.max_width = this.width; this.max_width = this.width;
if (this.selectable) gui_controls.check_bb(this); if (this.selectable) GUI.controls.check_bb(this);
var pos = [this.bb.l, this.bb.t].add(this.padding); var pos = [this.bb.l, this.bb.t].add(this.padding);
this.items.forEach(function(item) { this.items.forEach(function(item) {
if (item.hide) return; if (item.hide) return;
@ -249,8 +249,8 @@ Mum.image = Mum.extend({
}, },
calc_bb(pos) { calc_bb(pos) {
this.bb = cwh2bb(this.wh.scale([0.5,0.5]), wh); this.bb = bbox.fromcwh(this.wh.scale([0.5,0.5]), wh);
this.bb = movebb(this.bb, pos.sub(this.wh.scale(this.anchor))); this.bb = bbox.move(this.bb, pos.sub(this.wh.scale(this.anchor)));
} }
}); });
@ -287,3 +287,8 @@ Mum.debug_colors = {
}; };
Object.values(Mum.debug_colors).forEach(function(v) { v.a = 100; }); Object.values(Mum.debug_colors).forEach(function(v) { v.a = 100; });
return {
GUI,
Mum
};

View file

@ -1,8 +1,3 @@
var input = {
setgame() { cmd(77); },
setnuke() { cmd(78); },
};
var Mouse = { var Mouse = {
get pos() { return cmd(45); }, get pos() { return cmd(45); },
screenpos() { return cmd(45); }, screenpos() { return cmd(45); },
@ -55,6 +50,8 @@ var Keys = {
super() { return cmd(50, 343); }, super() { return cmd(50, 343); },
}; };
var input = {};
input.state2str = function(state) { input.state2str = function(state) {
if (typeof state === 'string') return state; if (typeof state === 'string') return state;
switch (state) { switch (state) {
@ -229,3 +226,10 @@ Player.uncontrol.doc = "Uncontrol a previously controlled object.";
Player.print_pawns.doc = "Print out a list of the current pawn control stack."; Player.print_pawns.doc = "Print out a list of the current pawn control stack.";
Player.doc = {}; Player.doc = {};
Player.doc.players = "A list of current players."; Player.doc.players = "A list of current players.";
return {
Mouse,
Keys,
input,
Player,
};

View file

@ -71,3 +71,7 @@ physics.warp.damp = function() { return cmd(254); }
physics.gravity = physics.warp.gravity(); physics.gravity = physics.warp.gravity();
physics.damp = physics.warp.damp(); physics.damp = physics.warp.damp();
return {
physics
}

View file

@ -144,30 +144,11 @@ console.doc = {
/* /*
io path rules. Starts with, meaning: io path rules. Starts with, meaning:
"@": playerpath "@": user path
"/": game room "/": game path
"#": Force look locally (instead of in db first)
- This is combined with others. #/, #@, etc
"": Local path relative to script defined in
*/ */
var io = { io.mixin({
exists(file) { return cmd(65, file);},
slurp(file) {
if (io.exists(file))
return cmd(38,file);
else
throw new Error(`File ${file} does not exist; can't slurp`);
},
slurpbytes(file) {
return cmd(81, file);
},
slurpwrite(file, data) {
if (data.byteLength)
cmd(60, data, file);
else
return cmd(39, data, file);
},
extensions(ext) { extensions(ext) {
var paths = io.ls(); var paths = io.ls();
paths = paths.filter(function(str) { return str.ext() === ext; }); paths = paths.filter(function(str) { return str.ext() === ext; });
@ -179,20 +160,7 @@ var io = {
run_bytecode(byte_file) { run_bytecode(byte_file) {
return cmd(261, byte_file); return cmd(261, byte_file);
}, },
ls() { return cmd(66); },
/* Only works on text files currently */
cp(f1, f2) {
cmd(166, f1, f2);
},
mv(f1, f2) {
return cmd(163, f1, f2);
},
rm(f) {
return cmd(f);
},
mkdir(dir) {
cmd(258, dir);
},
glob(pat) { glob(pat) {
var paths = io.ls(); var paths = io.ls();
pat = pat.replaceAll(/([\[\]\(\)\^\$\.\|\+])/g, "\\$1"); pat = pat.replaceAll(/([\[\]\(\)\^\$\.\|\+])/g, "\\$1");
@ -203,7 +171,7 @@ var io = {
var regex = new RegExp("^"+pat+"$", ""); var regex = new RegExp("^"+pat+"$", "");
return paths.filter(str => str.match(regex)); return paths.filter(str => str.match(regex));
}, },
}; });
io.doc = { io.doc = {
doc: "Functions for filesystem input/output commands.", doc: "Functions for filesystem input/output commands.",
@ -245,8 +213,8 @@ Cmdline.register_order("edit", function() {
} }
Game.engine_start(function() { Game.engine_start(function() {
load("scripts/editor.js"); global.mixin(use("scripts/editor.js"));
load("editorconfig.js"); use("editorconfig.js");
editor.enter_editor(); editor.enter_editor();
}); });
}, "Edit the project in this folder. Give it the name of an UR to edit that specific object.", "?UR?"); }, "Edit the project in this folder. Give it the name of an UR to edit that specific object.", "?UR?");
@ -283,7 +251,6 @@ Cmdline.register_order("play", function() {
load("game.js"); load("game.js");
if (project.icon) Window.icon(project.icon); if (project.icon) Window.icon(project.icon);
if (project.title) Window.title(project.title); if (project.title) Window.title(project.title);
say(project.title);
}); });
}, "Play the game present in this folder."); }, "Play the game present in this folder.");
@ -446,3 +413,12 @@ Cmdline.register_order("clean", function(argv) {
Cmdline.register_cmd("l", function(n) { Cmdline.register_cmd("l", function(n) {
console.level = n; console.level = n;
}, "Set log level."); }, "Set log level.");
return {
console,
Resources,
say,
io,
Cmdline,
cmd_args
};

View file

@ -828,18 +828,6 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
id2sprite(js2int(argv[1]))->t.pos = js2vec2(argv[2]); id2sprite(js2int(argv[1]))->t.pos = js2vec2(argv[2]);
break; break;
case 38:
str = JS_ToCString(js, argv[1]);
d1 = slurp_text(str,NULL);
ret = JS_NewString(js, d1);
break;
case 39:
str = JS_ToCStringLen(js, &plen, argv[1]);
str2 = JS_ToCString(js, argv[2]);
ret = JS_NewInt64(js, slurp_write(str, str2, plen));
break;
case 40: case 40:
js2gameobject(argv[1])->filter.categories = js2bitmask(argv[2]); js2gameobject(argv[1])->filter.categories = js2bitmask(argv[2]);
gameobject_apply(js2gameobject(argv[1])); gameobject_apply(js2gameobject(argv[1]));
@ -910,13 +898,6 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
ret = JS_NewInt64(js, point2segindex(js2vec2(argv[1]), v1, js2number(argv[3]))); ret = JS_NewInt64(js, point2segindex(js2vec2(argv[1]), v1, js2number(argv[3])));
break; break;
case 60:
str = JS_GetArrayBuffer(js, &plen, argv[1]);
str2 = JS_ToCString(js, argv[2]);
ret = JS_NewInt64(js, slurp_write(str, str2, plen));
str = NULL;
break;
case 61: case 61:
set_cam_body(js2gameobject(argv[1])->body); set_cam_body(js2gameobject(argv[1])->body);
break; break;
@ -934,11 +915,6 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
ret = vec2js(tex_get_dimensions(texture_pullfromfile(str))); ret = vec2js(tex_get_dimensions(texture_pullfromfile(str)));
break; break;
case 65:
str = JS_ToCString(js, argv[1]);
ret = JS_NewBool(js, fexists(str));
break;
case 66: case 66:
ret = strarr2js(ls(",")); ret = strarr2js(ls(","));
break; break;
@ -993,12 +969,6 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
arrfree(ids); arrfree(ids);
break; break;
case 81:
str = JS_ToCString(js, argv[1]);
d1 = slurp_file(str, &plen);
ret = JS_NewArrayBufferCopy(js, d1, plen);
break;
case 82: case 82:
gameobject_draw_debug(js2gameobject(argv[1])); gameobject_draw_debug(js2gameobject(argv[1]));
break; break;
@ -1114,13 +1084,11 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
case 121: case 121:
ret = number2js(get_timescale()); ret = number2js(get_timescale());
break; break;
case 122:
break;
case 123: case 123:
str = JS_ToCString(js, argv[1]); str = JS_ToCString(js, argv[1]);
str2 = JS_ToCString(js, argv[3]); str2 = JS_ToCString(js, argv[3]);
script_eval_w_env(str, argv[2], str2); ret = eval_file_env(str, str2, argv[2]);
break; break;
case 124: case 124:
@ -1264,21 +1232,11 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
str = JS_ToCString(js, argv[1]); str = JS_ToCString(js, argv[1]);
ret = int2js(remove(str)); ret = int2js(remove(str));
break; break;
case 163:
str = JS_ToCString(js,argv[1]);
str2 = JS_ToCString(js,argv[2]);
ret = int2js(rename(str, str2));
break;
case 164: case 164:
unplug_node(js2ptr(argv[1])); unplug_node(js2ptr(argv[1]));
break; break;
case 165:
break;
case 166:
str = js2str(argv[1]);
str2 = js2str(argv[2]);
ret = int2js(cp(str, str2));
break;
case 168: case 168:
js2gameobject(argv[1])->timescale = js2number(argv[2]); js2gameobject(argv[1])->timescale = js2number(argv[2]);
break; break;
@ -1470,10 +1428,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
case 257: case 257:
engine_start(argv[1]); engine_start(argv[1]);
break; break;
case 258:
str = js2str(argv[1]);
ret = int2js(mkdir(str, 0777));
break;
case 259: case 259:
script_gc(); script_gc();
break; break;
@ -1945,6 +1900,111 @@ static const JSCFunctionListEntry js_os_funcs[] = {
MIST_CFUNC_DEF("env", 1, js_os_env), MIST_CFUNC_DEF("env", 1, js_os_env),
}; };
JSValue js_io_exists(JSContext *js, JSValueConst this, int argc, JSValue *argv)
{
char *file = JS_ToCString(js, argv[0]);
JSValue ret = JS_NewBool(js, fexists(file));
JS_FreeCString(js,file);
return ret;
}
JSValue js_io_ls(JSContext *js, JSValueConst this)
{
return strarr2js(ls(","));
}
JSValue js_io_cp(JSContext *js, JSValueConst this, int argc, JSValue *argv)
{
char *f1, f2;
f1 = JS_ToCString(js, argv[0]);
f2 = JS_ToCString(js, argv[1]);
JSValue ret = int2js(cp(f1,f2));
JS_FreeCString(js,f1);
JS_FreeCString(js,f2);
return ret;
}
JSValue js_io_mv(JSContext *js, JSValueConst this, int argc, JSValue *argv)
{
char *f1, f2;
f1 = JS_ToCString(js, argv[0]);
f2 = JS_ToCString(js, argv[1]);
JSValue ret = int2js(rename(f1,f2));
JS_FreeCString(js,f1);
JS_FreeCString(js,f2);
return ret;
}
JSValue js_io_rm(JSContext *js, JSValueConst this, int argc, JSValue *argv)
{
char *file = JS_ToCString(js, argv[0]);
JS_FreeCString(js,file);
return JS_UNDEFINED;
}
JSValue js_io_mkdir(JSContext *js, JSValueConst this, int argc, JSValue *argv)
{
char *f = js2str(argv[0]);
JSValue ret = int2js(mkdir(f,0777));
JS_FreeCString(js,f);
return ret;
}
JSValue js_io_slurpbytes(JSContext *js, JSValueConst this, int argc, JSValue *argv)
{
char *f = js2str(argv[0]);
size_t len;
char *d = slurp_file(f,&len);
JSValue ret = JS_NewArrayBufferCopy(js,d,len);
JS_FreeCString(js,f);
free(d);
return ret;
}
JSValue js_io_slurp(JSContext *js, JSValueConst this, int argc, JSValue *argv)
{
char *f = js2str(argv[0]);
size_t len;
char *s = slurp_text(f,&len);
JS_FreeCString(js,f);
if (!s) return JS_UNDEFINED;
JSValue ret = JS_NewStringLen(js, s, len);
free(s);
return ret;
}
JSValue js_io_slurpwrite(JSContext *js, JSValueConst this, int argc, JSValue *argv)
{
char *f = js2str(argv[0]);
size_t len;
char *data;
JSValue ret;
if (JS_IsString(argv[1])) {
data = JS_ToCStringLen(js, &len, argv[1]);
ret = int2js(slurp_write(data, f, len));
JS_FreeCString(js,data);
} else {
data = JS_GetArrayBuffer(js, &len, argv[1]);
ret = int2js(slurp_write(data, f, len));
}
return ret;
}
static const JSCFunctionListEntry js_io_funcs[] = {
MIST_CFUNC_DEF("exists", 1, js_io_exists),
MIST_CFUNC_DEF("ls", 0, js_io_ls),
MIST_CFUNC_DEF("cp", 2, js_io_cp),
MIST_CFUNC_DEF("mv", 2, js_io_mv),
MIST_CFUNC_DEF("rm", 1, js_io_rm),
MIST_CFUNC_DEF("mkdir", 1, js_io_mkdir),
MIST_CFUNC_DEF("slurp", 1, js_io_slurp),
MIST_CFUNC_DEF("slurpbytes", 1, js_io_slurpbytes),
MIST_CFUNC_DEF("slurpwrite", 2, js_io_slurpwrite),
};
static const JSCFunctionListEntry js_emitter_funcs[] = { static const JSCFunctionListEntry js_emitter_funcs[] = {
CGETSET_ADD(emitter, life), CGETSET_ADD(emitter, life),
CGETSET_ADD(emitter, life_var), CGETSET_ADD(emitter, life_var),
@ -2202,6 +2262,7 @@ void ffi_load() {
QJSCLASSPREP_FUNCS(constraint); QJSCLASSPREP_FUNCS(constraint);
QJSGLOBALCLASS(os); QJSGLOBALCLASS(os);
QJSGLOBALCLASS(io);
} }
void ffi_stop() void ffi_stop()

View file

@ -97,6 +97,7 @@ static int ls_ftw(const char *path, const struct stat *sb, int typeflag)
return 0; return 0;
} }
// TODO: Not reentrant
char **ls(const char *path) char **ls(const char *path)
{ {
if (ls_paths) { if (ls_paths) {

View file

@ -105,6 +105,7 @@ JSValue num_cache[100] = {0};
const char *msg = JS_ToCString(js, JS_GetPropertyStr(js, exception, "message")); const char *msg = JS_ToCString(js, JS_GetPropertyStr(js, exception, "message"));
const char *stack = JS_ToCString(js, val); const char *stack = JS_ToCString(js, val);
YughLog(LOG_SCRIPT, LOG_ERROR, "%s :: %s\n%s", name, msg,stack); YughLog(LOG_SCRIPT, LOG_ERROR, "%s :: %s\n%s", name, msg,stack);
js_stacktrace();
JS_FreeCString(js, name); JS_FreeCString(js, name);
JS_FreeCString(js, msg); JS_FreeCString(js, msg);
@ -223,30 +224,11 @@ void script_eval_w_env(const char *s, JSValue env, const char *file) {
JS_FreeValue(js, v); JS_FreeValue(js, v);
} }
struct callenv { JSValue eval_file_env(const char *script, const char *file, JSValue env)
JSValue v;
const char *eval;
};
struct callenv *calls;
void call_stack()
{ {
for (int i = 0; i < arrlen(calls); i++) { JSValue v = JS_EvalThis(js, env, script, strlen(script), file, JS_EVAL_FLAGS);
JSValue v = JS_EvalThis(js, calls[i].v, calls[i].eval, strlen(calls[i].eval), calls[i].eval, JS_EVAL_FLAGS); js_print_exception(v);
js_print_exception(v); return v;
JS_FreeValue(js, v);
}
arrfree(calls);
}
void call_env(JSValue env, const char *eval)
{
if (!JS_IsObject(env)) { YughWarn("NOT AN ENV"); return; };
struct callenv c;
c.v = env;
c.eval = eval;
arrpush(calls, c);
} }
void file_eval_env(const char *file, JSValue env) void file_eval_env(const char *file, JSValue env)

View file

@ -23,7 +23,6 @@ extern struct callee stacktrace_callee;
extern JSValue num_cache[100]; extern JSValue num_cache[100];
JSValue jstr(const char *str); JSValue jstr(const char *str);
void call_stack();
void js_stacktrace(); void js_stacktrace();
void script_startup(); void script_startup();
void script_stop(); void script_stop();
@ -32,6 +31,7 @@ void script_evalf(const char *format, ...);
int script_dofile(const char *file); int script_dofile(const char *file);
time_t jso_file(const char *file); time_t jso_file(const char *file);
JSValue script_runfile(const char *file); JSValue script_runfile(const char *file);
JSValue eval_file_env(const char *script, const char *file, JSValue env);
void script_update(double dt); void script_update(double dt);
void script_draw(); void script_draw();
void free_callee(struct callee c); void free_callee(struct callee c);
@ -48,7 +48,6 @@ void call_callee(struct callee *c);
void script_callee(struct callee c, int argc, JSValue *argv); void script_callee(struct callee c, int argc, JSValue *argv);
int script_has_sym(void *sym); int script_has_sym(void *sym);
void script_eval_w_env(const char *s, JSValue env, const char *file); void script_eval_w_env(const char *s, JSValue env, const char *file);
void call_env(JSValue env, const char *eval);
void file_eval_env(const char *file, JSValue env); void file_eval_env(const char *file, JSValue env);
time_t file_mod_secs(const char *file); time_t file_mod_secs(const char *file);

View file

@ -110,7 +110,6 @@ static void process_frame()
{ {
double elapsed = stm_sec(stm_laptime(&frame_t)); double elapsed = stm_sec(stm_laptime(&frame_t));
script_evalf("Register.appupdate.broadcast(%g);", elapsed); script_evalf("Register.appupdate.broadcast(%g);", elapsed);
call_stack();
input_poll(0); input_poll(0);
/* Timers all update every frame - once per monitor refresh */ /* Timers all update every frame - once per monitor refresh */
timer_update(elapsed, timescale); timer_update(elapsed, timescale);