diff --git a/scripts/base.js b/scripts/base.js index a8934a1..a0db6e5 100644 --- a/scripts/base.js +++ b/scripts/base.js @@ -333,7 +333,8 @@ Object.defineProperty(String.prototype, 'ext', { Object.defineProperty(String.prototype, 'set_ext', { value: function(val) { - return this.dir() + this.name() + val; + var s = this.strip_ext(); + return s + val; } }); @@ -356,10 +357,16 @@ Object.defineProperty(String.prototype, 'dir', { value: function() { var e = this.lastIndexOf('/'); if (e === -1) return ""; - return this.slice(0, e+1); + return this.slice(0, e); } }); +Object.defineProperty(String.prototype, 'updir', { + value: function() { + var dir = this.dir(); + return dir.dir(); + } +}); /* ARRAY DEFS */ diff --git a/scripts/components.js b/scripts/components.js index 11a0b2e..cba1ebb 100644 --- a/scripts/components.js +++ b/scripts/components.js @@ -22,15 +22,46 @@ var component = { extend(spec) { return Object.copy(this, spec); }, + + /* Given a relative path, return the full path */ + resani(path) { + if (!this.gameobject) return path; + if (path[0] === '/') return path.slice(1); + var res = this.gameobject.ur.toString(); + res = res.replaceAll('.', '/'); + var restry = res + "/" + path; + while (!IO.exists(restry)) { + res = res.updir() + "/"; + if (res === "/") + return path; + + restry = res + path; + } + return restry; + }, + + /* Given the full path, return the most relative path */ + resavi(path) { + if (!this.gameobject) return path; + if (path[0] === '/') return path; + + var res = this.gameobject.ur.toString(); + res = res.replaceAll('.', '/'); + if (!path.startsWith(res)) + return path; + + return path.replace(res, "").slice(1); + }, }; -component.toJSON = ur_json; +//component.toJSON = ur_json; component.sprite = { pos:[0,0], color:[1,1,1], layer:0, enabled:true, + path: "", toString() { return "sprite"; }, make(go) { var nsprite = Object.create(component.sprite.maker); @@ -42,7 +73,13 @@ component.sprite = { }; component.sprite.maker = Object.copy(component, { - set path(x) { cmd(12,this.id,x,this.rect); }, + set path(x) { + x = this.resani(x); + cmd(12,this.id,x,this.rect); + }, + get path() { + return cmd(116,this.id); + }, get visible() { return this.enabled; }, set visible(x) { this.enabled = x; }, asset(str) { this.path = str; }, @@ -690,6 +727,8 @@ component.circle2d = Object.copy(collider2d, { var circle = Object.create(this); circle.gameobject = go; Object.assign(circle, make_circle2d(go.body, circle.radius, circle.offset)); + Object.merge(circle, this.ur); + return circle; }, diff --git a/scripts/editor.js b/scripts/editor.js index b9f4a9e..f0f27be 100644 --- a/scripts/editor.js +++ b/scripts/editor.js @@ -73,91 +73,6 @@ var editor = { programmode: false, - delete_empty_reviver(key, val) { - if (typeof val === 'object' && val.empty) - return undefined; - - return val; - }, - - save_proto() { - if (this.selectlist.length !== 1) return; - Log.warn(`Saving prototype ${this.selectlist[0].toString()}`); - var protos = JSON.parse(IO.slurp("proto.json")); - - var tobj = this.selectlist[0].prop_obj(); - var pobj = this.selectlist[0].__proto__.prop_obj(); - - Log.warn("Going to deep merge."); - deep_merge(pobj, tobj); - Log.warn("Finished deep merge."); - - pobj.from = this.selectlist[0].__proto__.from; - - protos[this.selectlist[0].__proto__.name] = pobj; - Log.warn(JSON.stringify(protos)); - slurpwrite(JSON.stringify(protos, undefined, 2), "proto.json"); - - /* Save object changes to parent */ - Object.dainty_assign(this.selectlist[0].__proto__, tobj); - - /* Remove the local from this object */ - unmerge(this.selectlist[0], tobj); - - /* Now sync all objects */ - Game.objects.forEach(x => x.sync()); - - }, - - /* Save the selected object as a new prototype, extending the chain */ - save_proto_as(name) { - if (name in gameobjects) { - Log.info("Already an object with name '" + name + "'. Choose another one."); - return; - } - var newp = this.selectlist[0].__proto__.clone(name); - - for (var key in newp) - if (typeof newp[key] === 'object' && 'clone' in newp[key]) - newp[key] = newp[key].clone(); - - Object.dainty_assign(newp, this.selectlist[0].prop_obj()); - this.selectlist[0].kill(); - var gopos = this.selectlist[0].pos; - this.unselect(); - var proto = this.edit_level.spawn(gameobjects[name]); - this.selectlist.push(proto); - this.save_proto(); - proto.pos = gopos; - }, - - /* Save selected object as a new prototype, replacing the current prototype */ - save_type_as(name) { - if (name in gameobjects) { - Log.info("Already an object with name '" + name + "'. Choose another one."); - -return; - } - - var newp = this.selectlist[0].__proto__.__proto__.clone(name); - - for (var key in newp) - if (typeof newp[key] === 'object' && 'clone' in newp[key]) - newp[key] = newp[key].clone(); - - var tobj = this.selectlist[0].prop_obj(); - var pobj = this.selectlist[0].__proto__.prop_obj(); - deep_merge(pobj, tobj); - - - Object.dainty_assign(newp, pobj); - this.selectlist[0].kill(); - this.unselect(); - var proto = this.edit_level.spawn(gameobjects[name]); - this.selectlist.push(proto); - this.save_proto(); - }, - dup_objects(x) { var objs = x.slice(); var duped = []; @@ -504,7 +419,7 @@ return; this.selectlist.forEach(function(x) { var color = x.color ? x.color : Color.white; var sname = x.ur.toString(); - if (!x.save_obj().empty) + if (!x.json_obj().empty) x.dirty = true; else x.dirty = false; @@ -668,15 +583,6 @@ return; editor.selectlist[0].angle = t.angle; } }, - - saveas(file) { - if (!file) return; - - Log.info("made it"); - - this.edit_level.file = file; - this.save_current(); - }, } editor.inputs = {}; @@ -864,10 +770,11 @@ editor.inputs.escape.doc = "Quit editor."; editor.inputs['C-s'] = function() { if (editor.selectlist.length !== 1 || !editor.selectlist[0].dirty) return; - Log.warn(`Saving ur for ${editor.selectlist[0].toString()}`); - Object.merge(editor.selectlist[0].ur, editor.selectlist[0].json_obj()); - IO.slurpwrite(JSON.stringify(editor.selectlist[0].ur,null,1), editor.selectlist[0].toString() + ".json"); + var path = editor.selectlist[0].toString(); + path = path.replaceAll('.','/'); + path = path + "/" + path.name() + ".json"; + IO.slurpwrite(JSON.stringify(editor.selectlist[0].ur,null,1), path); return; if (editor.edit_level.level) { @@ -1715,13 +1622,6 @@ var groupsaveaspanel = Object.copy(inputpanel, { action() { editor.groupsaveas(editor.selectlist, this.value); } }); -var saveprototypeas = Object.copy(inputpanel, { - title: "save prototype as", - action() { - editor.save_proto_as(this.value); - }, -}); - var savetypeas = Object.copy(inputpanel, { title: "save type as", action() { diff --git a/scripts/entity.js b/scripts/entity.js index dc45f82..1bf17e5 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -94,20 +94,11 @@ var gameobject = { return bb.t-bb.b; }, - save_obj() { - var json = JSON.stringify(this); - if (!json) return {}; - var o = JSON.parse(json); - delete o.pos; - delete o.angle; - return o; - }, - /* Make a unique object the same as its prototype */ revert() { - var save = this.save_obj(); - for (var key in save) - this[key] = this.ur[key]; + var t = this.transform(); + Object.totalmerge(this,this.ur); + Object.merge(this,t); }, gui() { @@ -368,12 +359,11 @@ var gameobject = { if ('ur' in p) { obj[prop] = obj.spawn(prototypes.get_ur(p.ur)); obj.$[prop] = obj[prop]; - } else if ('make' in p) { - obj[prop] = p.make(obj); - obj.components[prop] = obj[prop]; } else if ('comp' in p) { obj[prop] = component[p.comp].make(obj); obj.components[prop] = obj[prop]; + obj[prop].ur = Object.create(obj[prop].ur); + Object.totalmerge(obj[prop].ur, p); } }; @@ -483,8 +473,14 @@ prototypes.from_file = function(file) if (IO.exists(jsfile)) script = IO.slurp(jsfile); } - if (IO.exists(jsonfile)) - json = JSON.parse(IO.slurp(jsonfile)); + if (IO.exists(jsonfile)) { + try { + json = JSON.parse(IO.slurp(jsonfile)); + } + catch(e) { + Log.warn(`JSON in file ${jsonfile} is malformed.`); + } + } else { jsonfile = urpath + "/" + path.at(-1) + ".json"; if (IO.exists(jsonfile)) json = JSON.parse(IO.slurp(jsonfile)); @@ -555,7 +551,6 @@ prototypes.get_ur = function(name) if (!prototypes.ur[urpath]) { var ur = prototypes.from_file(urpath); - Log.warn(`tried to make ${urpath}`); if (ur) return ur; else { diff --git a/source/engine/2dphysics.c b/source/engine/2dphysics.c index 41e7bba..e6b1a4c 100644 --- a/source/engine/2dphysics.c +++ b/source/engine/2dphysics.c @@ -201,6 +201,7 @@ struct phys2d_circle *Make2DCircle(int go) { new->shape.shape = cpSpaceAddShape(space, cpCircleShapeNew(id2go(go)->body, new->radius, cpvzero)); new->shape.debugdraw = phys2d_dbgdrawcircle; new->shape.moi = phys2d_circle_moi; + new->shape.apply = phys2d_applycircle; init_phys2dshape(&new->shape, go, new); return new; diff --git a/source/engine/2dphysics.h b/source/engine/2dphysics.h index a814546..1bdbab3 100644 --- a/source/engine/2dphysics.h +++ b/source/engine/2dphysics.h @@ -21,13 +21,13 @@ extern struct rgba kinematic_color; extern struct rgba static_color; extern struct rgba sleep_color; - struct phys2d_shape { cpShape *shape; int go; void *data; void (*debugdraw)(void *data); float (*moi)(void *data, float mass); + void (*apply)(void *data); }; /* Circles are the fastest collier type */ diff --git a/source/engine/ffi.c b/source/engine/ffi.c index f69873b..fa7dda7 100644 --- a/source/engine/ffi.c +++ b/source/engine/ffi.c @@ -707,6 +707,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) case 36: id2go(js2int(argv[1]))->scale = js2number(argv[2]); + gameobject_apply(id2go(js2int(argv[1]))); cpSpaceReindexShapesForBody(space, id2go(js2int(argv[1]))->body); return JS_NULL; diff --git a/source/engine/gameobject.c b/source/engine/gameobject.c index 403362c..c8cfb93 100644 --- a/source/engine/gameobject.c +++ b/source/engine/gameobject.c @@ -95,6 +95,10 @@ void go_shape_apply(cpBody *body, cpShape *shape, struct gameobject *go) { filter.categories = CP_ALL_CATEGORIES;//1<layer; filter.mask = CP_ALL_CATEGORIES;//category_masks[go->layer]; cpShapeSetFilter(shape, filter); + + struct phys2d_shape *ape = cpShapeGetUserData(shape); + if (ape) + ape->apply(ape->data); } void go_shape_moi(cpBody *body, cpShape *shape, struct gameobject *go) { diff --git a/source/engine/resources.c b/source/engine/resources.c index 94566eb..cbe47e5 100644 --- a/source/engine/resources.c +++ b/source/engine/resources.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "font.h" @@ -248,8 +249,34 @@ char *slurp_text(const char *filename, size_t *size) return retstr; } +void rek_mkdir(char *path) { + char *sep = strrchr(path, '/'); + if(sep != NULL) { + *sep = 0; + rek_mkdir(path); + *sep = '/'; + } +#if defined __WIN32 + if(mkdir(path) && errno != EEXIST) +#else + if (mkdir(path, 0777) && errno != EEXIST) +#endif + printf("error while trying to create '%s'\n%m\n", path); +} + +FILE *fopen_mkdir(char *path, char *mode) { + char *sep = strrchr(path, '/'); + if(sep) { + char *path0 = strdup(path); + path0[ sep - path ] = 0; + rek_mkdir(path0); + free(path0); + } + return fopen(path,mode); +} + int slurp_write(const char *txt, const char *filename) { - FILE *f = fopen(filename, "w"); + FILE *f = fopen_mkdir(filename, "w"); if (!f) return 1; fputs(txt, f);