cepheid

An Aurora 4X clone
Log | Files | Refs | README

commit c83721c6593c8ee66d1b99fe3abc0a6d3b0e6ea4
parent e49272570ff63ab0afbd4a74f3a97ab4f150fb07
Author: hhvn <dev@hhvn.uk>
Date:   Sun, 30 Oct 2022 11:55:04 +0000

Load systems using dbgettree()

Diffstat:
Msrc/body.c | 15+++++++++++++++
Msrc/db.c | 129+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/main.h | 9+++++++--
Msrc/save.c | 5+++--
Msrc/str.c | 30++++++++++++++++++++++++++++++
Msrc/struct.h | 9++++++---
Msrc/system.c | 208+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/tree.c | 1+
8 files changed, 278 insertions(+), 128 deletions(-)

diff --git a/src/body.c b/src/body.c @@ -1,5 +1,6 @@ #include <stdlib.h> #include <raylib.h> +#include <math.h> #include "main.h" static char *bodytype_names[BODY_LAST] = { @@ -39,6 +40,20 @@ bodytype_strify(Body *body) { (body->parent ? body->parent->type : 0)]; } +Body * +body_init(char *name) { + Body *ret; + + ret = malloc(sizeof(Body)); + if (!ret) return NULL; + ret->name = nstrdup(name); + ret->t = NULL; + ret->parent = NULL; + ret->polar = (Polar) { INFINITY, INFINITY }; + + return ret; +} + int body_cmp(Body *b1, Body *b2) { float v1, v2; diff --git a/src/db.c b/src/db.c @@ -82,47 +82,124 @@ dbgetfloat(char *dir, char *group, char *key) { return ret; } +static int +dbtree_concat(char *path[TREEMAX], size_t depth, char *group, int index) { + size_t sl = PATH_MAX; + size_t i, len; + char *sp = group; + + for (i = 0; i <= depth; i++) { + len = strlen(path[i]); + if (len + (index ? strlen("index") : 0) >= sl) { + warning("insufficient space to concatenate tree path\n"); + return -1; + } + + memcpy(sp, path[i], len); + if (i != depth || index) + sp[len] = '/'; + else + sp[len] = '\0'; + sp += len + 1; + sl -= len + 1; + } + if (index) { + len = strlen("index"); + memcpy(sp, "index", len + 1); + } + + return 0; +} + int dbsettree(char *dir, Tree *t, Treesetter func) { char *path[TREEMAX]; char group[PATH_MAX]; - char *sp; - size_t sl, i, len; int depth; Tree *p; int ret = 0; for (p = NULL; tree_iter(t, TREEMAX, &p, &depth) != -1; ) { -next: path[depth] = p->name; if (p->data) { - sl = sizeof(group); - sp = group; - for (i = 0; i <= depth; i++) { - len = strlen(path[i]); - if (len + (p->d ? strlen("index") : 0) >= sl) { - ret = -1; - warning("insufficient space to concatenate tree path\n"); - goto next; - } - - memcpy(sp, path[i], len); - if (i != depth || p->d) - sp[len] = '/'; - else - sp[len] = '\0'; - sp += len + 1; - sl -= len + 1; - } - if (p->d) { - len = strlen("index"); - memcpy(sp, "index", len + 1); + if (dbtree_concat(path, depth, group, p->d != NULL) == -1) { + ret = -1; + continue; } - - func(dir, group, depth, p); + func(dir, group, p->name, depth, p); } } return ret; } + +int +dbgettree(char *dir, Tree *r, Treegetter func) { + char *ppath, *path; + char *psplit[TREEMAX], *split[TREEMAX]; + char **groups; + char group[PATH_MAX]; + char *name; + size_t glen, pslen, slen; + size_t common, up; + int index; + int i, j; + Tree *t, *p; + + glen = dblistgroups(&groups, dir); + slen = 0; + memset(&split, 0, sizeof(split)); + + for (i = 0, ppath = path = NULL, t = r; i < glen; i++) { + free(ppath); + ppath = path; + path = strdup(groups[i]); + + memcpy(&psplit, split, sizeof(split)); + pslen = slen; + slen = strsplit(path, "/", split, TREEMAX); + + if (streq(split[slen - 1], "index")) { + index = 1; + slen--; + } else { + index = 0; + } + + common = strlistcmp(psplit, pslen, split, slen); + up = pslen - common; + + if (up && (float)up <= (float)((float)pslen / 2.0f)) { + for (j = 0; j < up; j++) + t = t->u; + j = common; + } else if (common == pslen) { + j = common; + } else { + t = r; + j = 0; + } + + for (; j < slen; j++) { +nchild: + name = split[j]; + + for (p = t->d; p; p = p->n) { + if (streq(p->name, name)) { + t = p; + goto nchild; + } + } + + /* Since name is a part of split[], it will be + * corrupted later. The Treegetter function is + * therefore responsible for allocating the name + * and returning it */ + t = tree_add_child(t, name, 0, NULL, NULL); + dbtree_concat(split, j, group, index || j != slen - 1); + if (!t->data) + t->name = func(dir, group, name, j + 1, t); + } + } +} diff --git a/src/main.h b/src/main.h @@ -37,6 +37,8 @@ int strprefix(char *str, char *prefix); char * strsuffix(char *str, char *suffix); int strlistpos(char *str, char **list, size_t len); float strnum(char *str); +size_t strlistcmp(char **l1, size_t s1, char **l2, size_t s2); +size_t strsplit(char *str, char *sep, char **list, size_t len); void edittrunc(wchar_t *str, int *len, int *cur); void editrm(wchar_t *str, int *len, int *cur); void editins(wchar_t *str, int *len, int *cur, int size, wchar_t c); @@ -144,14 +146,16 @@ Polar sys_sum_polar(Polar absolute, Polar relative); Vector2 sys_get_vector(Body *body); Polar sys_get_polar(Body *body); System *sys_init(char *name); -System *sys_load(System *s, char *name); -void sys_tree_setter(char *dir, char *group, int depth, Tree *t); +void sys_tree_load(void); +char * sys_tree_getter(char *dir, char *group, char *name, int depth, Tree *t); +void sys_tree_setter(char *dir, char *group, char *name, int depth, Tree *t); System *sys_get(char *name); System *sys_default(void); /* body.c */ int bodytype_enumify(char *name); char * bodytype_strify(Body *body); +Body * body_init(char *name); int body_cmp(Body *b1, Body *b2); void body_sort(Body **bodies, size_t n); @@ -187,6 +191,7 @@ int vdbgetf(char *dir, char *group, char *key, char *fmt, va_list args); int dbgetf(char *dir, char *group, char *key, char *fmt, ...); int dbgetint(char *dir, char *group, char *key); float dbgetfloat(char *dir, char *group, char *key); +int dbgettree(char *dir, Tree *t, Treegetter func); int dbsettree(char *dir, Tree *t, Treesetter func); /* loading.c */ diff --git a/src/save.c b/src/save.c @@ -43,8 +43,9 @@ save_read(char *name) { save->db.races = smprintf("%s/Races", dir); save->db.systems = smprintf("%s/Systems", dir); save->db.fleets = smprintf("%s/Fleets", dir); - if ((str = dbget(save->db.dir, "index", "homesystem"))) - save->homesys = sys_get(str); + /* if ((str = dbget(save->db.dir, "index", "homesystem"))) */ + /* save->homesys = sys_get(str); */ + sys_tree_load(); return; }; diff --git a/src/str.c b/src/str.c @@ -177,6 +177,36 @@ strnum(char *str) { return strtof(str, NULL); } +size_t +strlistcmp(char **l1, size_t s1, char **l2, size_t s2) { + size_t i; + + for (i = 0; i < s1 && i < s2; i++) { + if (!streq(l1[i], l2[i])) + break; + } + + return i; +} + +size_t +strsplit(char *str, char *sep, char **list, size_t len) { + char *save; + size_t i; + + if (!str) + return 0; + + for (i = 0; i < len; i++) { + list[i] = strtok_r(i == 0 ? str : NULL, sep, &save); + + if (!list[i]) + break; + } + + return i; +} + void edittrunc(wchar_t *str, int *len, int *cur) { *len = *cur = 0; diff --git a/src/struct.h b/src/struct.h @@ -16,8 +16,8 @@ struct Tree { Tree *n; /* next */ }; -/* typedef void (*Treegetter)(char *dir, char *group, int depth, Tree *t); */ -typedef void (*Treesetter)(char *dir, char *group, int depth, Tree *t); +typedef char * (*Treegetter)(char *dir, char *group, char *name, int depth, Tree *t); +typedef void (*Treesetter)(char *dir, char *group, char *name, int depth, Tree *t); /* system.c */ enum { @@ -51,7 +51,10 @@ enum BodyType { typedef struct Body Body; struct Body { Tree *t; - Body *parent; + union { + Body *parent; + char *pname; /* used during sys_tree_load() */ + }; Polar polar; Vector2 vector; Vector2 pxloc; /* used by ui functions */ diff --git a/src/system.c b/src/system.c @@ -96,41 +96,96 @@ filter_bodyinsystem(void *data, char *path) { return 0; } -/* If s is true, ignore name and load the system. - * If s is NULL, call sys_init(name); */ -System * -sys_load(System *s, char *name) { - char *dir, *tmp; - Body **bodies; - char **bname; - char **bparent; - size_t blen, i; - int pos; - - if (!s) s = sys_init(name); - - s->lypos.x = dbgetfloat(save->db.systems, name, "x"); - s->lypos.y = dbgetfloat(save->db.systems, name, "y"); - - dir = smprintf("%s/", s->name); - blen = dblistgroups_f(&bname, save->db.systems, &filter_bodyinsystem, dir); - if (!bname) return NULL; - bparent = malloc(sizeof(char *) * blen); - bodies = malloc(sizeof(Body *) * blen); - - if (!bparent || !bodies) - return NULL; - - /* first pass: init bodies and parents */ - for (i = 0; i < blen; i++) { - bodies[i] = malloc(sizeof(Body)); - bodies[i]->name = nstrdup(bname[i] + strlen(dir)); - bparent[i] = nstrdup(dbget(save->db.systems, bname[i], "parent")); - - tmp = dbget(save->db.systems, bname[i], "type"); - bodies[i]->type = bodytype_enumify(tmp); - - switch (bodies[i]->type) { +void +sys_tree_load(void) { + Tree *t, *bt; + System *s; + char **bn; + Body **bp; + int bl, i, n, pos; + + /* initialize systems and bodies */ + dbgettree(save->db.systems, &save->systems, sys_tree_getter); + + /* bn & bp are only free'd at the end to avoid excess (re)allocations */ + bl = 10; + bn = malloc(bl * sizeof(char *)); + bp = malloc(bl * sizeof(char *)); + + for (t = save->systems.d; t; t = t->n) { + s = t->data; + + /* first pass: init names & pointer arrays */ + for (i = 0, bt = t->d; bt; bt = bt->n, i++) { + if (i == bl - 1) { + bl += 10; + bn = realloc(bn, bl * sizeof(char *)); + bp = realloc(bp, bl * sizeof(char *)); + } + + bn[i] = bt->name; + bp[i] = bt->data; + } + + n = i; + + /* second pass: assign parent pointer */ + for (i = 0; i < n; i++) { + if ((pos = strlistpos(bp[i]->pname, bn, n)) != -1) { + free(bp[i]->pname); + bp[i]->parent = bp[pos]; + } else { + bp[i]->parent = NULL; + } + } + + /* third pass: get coords (needs parent ptr from second pass) */ + for (i = 0; i < n; i++) { + sys_get_polar(bp[i]); /* Builds the cache for us: this + is more efficient as it can + cache the parent too */ + bp[i]->vector = sys_vectorize(bp[i]->polar); + + /* This could deal with moons, but that's probably not + * useful. What about multiple stars in a system? That + * may need to be addressed in future */ + if (bp[i]->parent && bp[i]->parent->type == BODY_STAR && (!s->furthest_body || + (bp[i]->type == BODY_COMET ? bp[i]->maxdist : bp[i]->dist) > + (s->furthest_body->type == BODY_COMET ? s->furthest_body->maxdist : s->furthest_body->dist))) + s->furthest_body = bp[i]; + } + + body_sort(bp, n); + } + + free(bp); + free(bn); +} + +char * +sys_tree_getter(char *dir, char *group, char *name, int depth, Tree *t) { + System *s; + Body *b; + + if (depth == 1) { + s = sys_init(name); + s->t = t; + + s->lypos.x = dbgetfloat(dir, group, "x"); + s->lypos.y = dbgetfloat(dir, group, "y"); + + t->type = SYSTREE_SYS; + t->data = s; + return s->name; + } else { + s = t->u->data; /* parent should be a system */ + b = body_init(name); + b->t = t; + + b->pname = nstrdup(dbget(dir, group, "parent")); + + b->type = bodytype_enumify(dbget(dir, group, "type")); + switch (b->type) { case BODY_STAR: s->num.stars++; break; case BODY_PLANET: s->num.planets++; break; case BODY_DWARF: s->num.dwarfs++; break; @@ -139,74 +194,31 @@ sys_load(System *s, char *name) { case BODY_MOON: s->num.moons++; break; } - bodies[i]->radius = strnum(dbget(save->db.systems, bname[i], "radius")); - bodies[i]->mass = strnum(dbget(save->db.systems, bname[i], "mass")); - bodies[i]->orbdays = strnum(dbget(save->db.systems, bname[i], "orbdays")); - if (bodies[i]->type == BODY_COMET) { + b->radius = dbgetfloat(dir, group, "radius"); + b->mass = dbgetfloat(dir, group, "mass"); + b->orbdays = dbgetfloat(dir, group, "orbdays"); + if (b->type == BODY_COMET) { /* mindist is on opposite side of parent */ - bodies[i]->mindist = 0 - strnum(dbget(save->db.systems, bname[i], "mindist")); - bodies[i]->maxdist = strnum(dbget(save->db.systems, bname[i], "maxdist")); - bodies[i]->curdist = strnum(dbget(save->db.systems, bname[i], "curdist")); - bodies[i]->theta = strnum(dbget(save->db.systems, bname[i], "theta")); - bodies[i]->inward = strnum(dbget(save->db.systems, bname[i], "inward")); + b->mindist = 0 - dbgetfloat(dir, group, "mindist"); + b->maxdist = dbgetfloat(dir, group, "maxdist"); + b->curdist = dbgetfloat(dir, group, "curdist"); + b->theta = dbgetfloat(dir, group, "theta"); + b->inward = dbgetfloat(dir, group, "inward"); } else { - bodies[i]->dist = strnum(dbget(save->db.systems, bname[i], "dist")); - bodies[i]->curtheta = strnum(dbget(save->db.systems, bname[i], "curtheta")); + b->dist = dbgetfloat(dir, group, "dist"); + b->curtheta = dbgetfloat(dir, group, "curtheta"); } - /* so sys_get_polar() knows if it's usable */ - bodies[i]->polar = (Polar) { INFINITY, INFINITY }; + t->type = SYSTREE_BODY; + t->data = b; + return b->name; } - - /* second pass: assign parents (needs bparent[] from first pass) */ - for (i = 0; i < blen; i++) { - tmp = smprintf("%s%s", dir, bparent[i]); - if ((pos = strlistpos(tmp, bname, blen)) != -1) - bodies[i]->parent = bodies[pos]; - else - bodies[i]->parent = NULL; - free(tmp); - } - - /* third pass: get coords (needs parent ptr from second pass) */ - for (i = 0; i < blen; i++) { - sys_get_polar(bodies[i]); /* Builds the cache for us: this is more - efficient as it can cache the parent too */ - bodies[i]->vector = sys_vectorize(bodies[i]->polar); - - /* This could deal with moons, but that's probably not useful. - * What about multiple stars in a system? That may need to be - * addressed in future */ - if (bodies[i]->parent && bodies[i]->parent->type == BODY_STAR && (!s->furthest_body || - (bodies[i]->type == BODY_COMET ? bodies[i]->maxdist : bodies[i]->dist) > - (s->furthest_body->type == BODY_COMET ? s->furthest_body->maxdist : s->furthest_body->dist))) - s->furthest_body = bodies[i]; - } - - for (i = 0; i < blen; i++) { - free(bparent[i]); - } - free(bparent); - dblistfree(bname, blen); - free(dir); - - body_sort(bodies, blen); - - tree_add_child(&save->systems, s->name, SYSTREE_SYS, s, &s->t); - for (i = 0; i < blen; i++) - tree_add_child(s->t, bodies[i]->name, SYSTREE_BODY, bodies[i], &bodies[i]->t); - - /* The bodies are attached to the systree now, so don't need to be freed */ - free(bodies); - - return s; } void -sys_tree_setter(char *dir, char *group, int depth, Tree *t) { +sys_tree_setter(char *dir, char *group, char *name, int depth, Tree *t) { System *s; Body *b; - char *parent; switch (t->type) { case SYSTREE_SYS: @@ -237,13 +249,19 @@ sys_tree_setter(char *dir, char *group, int depth, Tree *t) { System * sys_get(char *name) { - /* For now, call sys_load. In future, get the system via save. */ - return sys_load(NULL, name); + Tree *t; + + for (t = save->systems.d; t; t = t->n) + if (streq(t->name, name)) + return t->data; + + return NULL; } System * sys_default(void) { char *str; + if (view_main.sys) return view_main.sys; else if ((str = dbget(save->db.dir, "index", "selsystem"))) diff --git a/src/tree.c b/src/tree.c @@ -20,6 +20,7 @@ tree_add_child(Tree *t, char *name, int type, void *data, Tree **ptr) { e->type = type; e->data = data; e->u = t; + e->collapsed = 0; if (!t->d) { t->d = e;