From a569ef67e877b5871d04a4b670402063171d803b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 15 Sep 2017 21:52:20 +0200 Subject: [PATCH 01/41] sortiere unit.skills nach id. TODO: binary search statt linear, read_unit optimization https://trello.com/c/ydUTDGgl/616-sort-unitskills-binary-search --- src/kernel/unit.c | 47 +++++++++++++++++++---------------- src/kernel/unit.test.c | 56 ++++++++++++++++++++++++++++++++++++------ src/reports.test.c | 10 ++++---- 3 files changed, 80 insertions(+), 33 deletions(-) diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 44e9445b7..b2eeec055 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -773,7 +773,7 @@ int get_level(const unit * u, skill_t id) assert(id != NOSKILL); if (skill_enabled(id)) { skill *sv = u->skills; - while (sv != u->skills + u->skill_size) { + while (sv != u->skills + u->skill_size && sv->id <= id) { if (sv->id == id) { return sv->level; } @@ -795,7 +795,7 @@ void set_level(unit * u, skill_t sk, int value) remove_skill(u, sk); return; } - while (sv != u->skills + u->skill_size) { + while (sv != u->skills + u->skill_size && sv->id <= sk) { if (sv->id == sk) { sk_set(sv, value); return; @@ -1186,35 +1186,39 @@ void set_number(unit * u, int count) void remove_skill(unit * u, skill_t sk) { - skill *sv = u->skills; - for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { + int i; + skill *sv; + for (i = 0; i != u->skill_size; ++i) { + sv = u->skills + i; if (sv->id == sk) { - skill *sl = u->skills + u->skill_size - 1; - if (sl != sv) { - *sv = *sl; - } + memmove(sv, sv + 1, (u->skill_size - 1) * sizeof(skill)); --u->skill_size; return; } } } -skill *add_skill(unit * u, skill_t id) +skill *add_skill(unit * u, skill_t sk) { - skill *sv = u->skills; -#ifndef NDEBUG - for (sv = u->skills; sv != u->skills + u->skill_size; ++sv) { - assert(sv->id != id); + skill *sv; + int i; + + for (i=0; i != u->skill_size; ++i) { + sv = u->skills+i; + if (sv->id >= sk) break; + } + u->skills = realloc(u->skills, (1 + u->skill_size) * sizeof(skill)); + sv = u->skills + i; + if (i < u->skill_size) { + assert(sv->id != sk); + memmove(sv + 1, sv, sizeof(skill) * (u->skill_size - i)); } -#endif ++u->skill_size; - u->skills = realloc(u->skills, u->skill_size * sizeof(skill)); - sv = (u->skills + u->skill_size - 1); sv->level = 0; sv->weeks = 1; sv->old = 0; - sv->id = id; - if (id == SK_MAGIC && u->faction && !fval(u->faction, FFL_NPC)) { + sv->id = sk; + if (sk == SK_MAGIC && u->faction && !fval(u->faction, FFL_NPC)) { assert(u->number <= 1); assert(max_magicians(u->faction) >= u->number); } @@ -1224,9 +1228,10 @@ skill *add_skill(unit * u, skill_t id) skill *unit_skill(const unit * u, skill_t sk) { skill *sv = u->skills; - while (sv != u->skills + u->skill_size) { - if (sv->id == sk) + while (sv != u->skills + u->skill_size && sv->id <= sk) { + if (sv->id == sk) { return sv; + } ++sv; } return NULL; @@ -1235,7 +1240,7 @@ skill *unit_skill(const unit * u, skill_t sk) bool has_skill(const unit * u, skill_t sk) { skill *sv = u->skills; - while (sv != u->skills + u->skill_size) { + while (sv != u->skills + u->skill_size && sv->id <= sk) { if (sv->id == sk) { return (sv->level > 0); } diff --git a/src/kernel/unit.test.c b/src/kernel/unit.test.c index 2abb8c85c..2e4ce3568 100644 --- a/src/kernel/unit.test.c +++ b/src/kernel/unit.test.c @@ -31,7 +31,7 @@ static void test_remove_empty_units(CuTest *tc) { unit *u; int uid; - test_cleanup(); + test_setup(); test_create_world(); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); @@ -48,7 +48,7 @@ static void test_remove_empty_units_in_region(CuTest *tc) { unit *u; int uid; - test_cleanup(); + test_setup(); test_create_world(); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); @@ -69,7 +69,7 @@ static void test_remove_units_without_faction(CuTest *tc) { unit *u; int uid; - test_cleanup(); + test_setup(); test_create_world(); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); @@ -85,7 +85,7 @@ static void test_remove_units_with_dead_faction(CuTest *tc) { unit *u; int uid; - test_cleanup(); + test_setup(); test_create_world(); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); @@ -101,7 +101,7 @@ static void test_scale_number(CuTest *tc) { unit *u; const struct potion_type *ptype; - test_cleanup(); + test_setup(); test_create_world(); ptype = new_potiontype(it_get_or_create(rt_get_or_create("hodor")), 1); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); @@ -122,7 +122,7 @@ static void test_scale_number(CuTest *tc) { static void test_unit_name(CuTest *tc) { unit *u; - test_cleanup(); + test_setup(); test_create_world(); u = test_create_unit(test_create_faction(test_create_race("human")), findregion(0, 0)); renumber_unit(u, 666); @@ -334,9 +334,50 @@ static void test_inside_building(CuTest *tc) { test_cleanup(); } +static void test_skills(CuTest *tc) { + unit *u; + skill *sv; + test_setup(); + u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); + sv = add_skill(u, SK_ALCHEMY); + CuAssertPtrNotNull(tc, sv); + CuAssertPtrEquals(tc, sv, u->skills); + CuAssertIntEquals(tc, 1, u->skill_size); + CuAssertIntEquals(tc, SK_ALCHEMY, sv->id); + CuAssertIntEquals(tc, 0, sv->level); + CuAssertIntEquals(tc, 1, sv->weeks); + CuAssertIntEquals(tc, 0, sv->old); + sv = add_skill(u, SK_BUILDING); + CuAssertPtrNotNull(tc, sv); + CuAssertIntEquals(tc, 2, u->skill_size); + CuAssertIntEquals(tc, SK_ALCHEMY, u->skills[0].id); + CuAssertIntEquals(tc, SK_BUILDING, u->skills[1].id); + sv = add_skill(u, SK_LONGBOW); + CuAssertPtrNotNull(tc, sv); + CuAssertPtrEquals(tc, sv, unit_skill(u, SK_LONGBOW)); + CuAssertIntEquals(tc, 3, u->skill_size); + CuAssertIntEquals(tc, SK_ALCHEMY, u->skills[0].id); + CuAssertIntEquals(tc, SK_LONGBOW, u->skills[1].id); + CuAssertIntEquals(tc, SK_BUILDING, u->skills[2].id); + CuAssertTrue(tc, !has_skill(u, SK_LONGBOW)); + set_level(u, SK_LONGBOW, 1); + CuAssertTrue(tc, has_skill(u, SK_LONGBOW)); + remove_skill(u, SK_LONGBOW); + CuAssertIntEquals(tc, SK_BUILDING, u->skills[1].id); + CuAssertIntEquals(tc, 2, u->skill_size); + remove_skill(u, SK_LONGBOW); + CuAssertIntEquals(tc, SK_BUILDING, u->skills[1].id); + CuAssertIntEquals(tc, 2, u->skill_size); + remove_skill(u, SK_BUILDING); + CuAssertIntEquals(tc, SK_ALCHEMY, u->skills[0].id); + CuAssertIntEquals(tc, 1, u->skill_size); + CuAssertTrue(tc, !has_skill(u, SK_LONGBOW)); + test_cleanup(); +} + static void test_limited_skills(CuTest *tc) { unit *u; - test_cleanup(); + test_setup(); u = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); CuAssertIntEquals(tc, false, has_limited_skills(u)); set_level(u, SK_ENTERTAINMENT, 1); @@ -592,6 +633,7 @@ CuSuite *get_unit_suite(void) SUITE_ADD_TEST(suite, test_skill_familiar); SUITE_ADD_TEST(suite, test_age_familiar); SUITE_ADD_TEST(suite, test_inside_building); + SUITE_ADD_TEST(suite, test_skills); SUITE_ADD_TEST(suite, test_limited_skills); SUITE_ADD_TEST(suite, test_renumber_unit); SUITE_ADD_TEST(suite, test_name_unit); diff --git a/src/reports.test.c b/src/reports.test.c index 58ac425f1..7c6e8ccf4 100644 --- a/src/reports.test.c +++ b/src/reports.test.c @@ -279,13 +279,13 @@ static void test_bufunit(CuTest *tc) { bufunit(u->faction, u, 0, 0, buffer, sizeof(buffer)); CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv.", buffer); - set_level(u, SK_SAILING, 1); - bufunit(u->faction, u, 0, 0, buffer, sizeof(buffer)); - CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Segeln 1.", buffer); - set_level(u, SK_ALCHEMY, 1); bufunit(u->faction, u, 0, 0, buffer, sizeof(buffer)); - CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Segeln 1, Alchemie 2.", buffer); + CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Alchemie 2.", buffer); + + set_level(u, SK_SAILING, 1); + bufunit(u->faction, u, 0, 0, buffer, sizeof(buffer)); + CuAssertStrEquals(tc, "Hodor (1), 1 human, aggressiv, Talente: Alchemie 2, Segeln 1.", buffer); f = test_create_faction(0); f->locale = get_or_create_locale("de"); From 8b4e3b773887f19117581f7c179de0fa270f1ef8 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 15 Sep 2017 21:55:57 +0200 Subject: [PATCH 02/41] extract write_skills and read_skills functions. --- src/kernel/save.c | 68 ++++++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/src/kernel/save.c b/src/kernel/save.c index 39fab86af..97dbaf77b 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -603,8 +603,7 @@ int current_turn(void) return cturn; } -static void -writeorder(struct gamedata *data, const struct order *ord, +static void writeorder(gamedata *data, const struct order *ord, const struct locale *lang) { char obuf[1024]; @@ -613,7 +612,40 @@ writeorder(struct gamedata *data, const struct order *ord, WRITE_STR(data->store, obuf); } -unit *read_unit(struct gamedata *data) +static void read_skills(gamedata *data, unit *u) +{ + for (;;) { + int n = NOSKILL, level, weeks; + skill_t sk; + READ_INT(data->store, &n); + sk = (skill_t)n; + if (sk == NOSKILL) break; + READ_INT(data->store, &level); + READ_INT(data->store, &weeks); + if (level) { + skill *sv = add_skill(u, sk); + sv->level = sv->old = (unsigned char)level; + sv->weeks = (unsigned char)weeks; + } + } +} + +static void write_skills(gamedata *data, const unit *u) { + int i; + for (i = 0; i != u->skill_size; ++i) { + skill *sv = u->skills + i; + assert(sv->weeks <= sv->level * 2 + 1); + if (sv->level > 0) { + WRITE_INT(data->store, sv->id); + WRITE_INT(data->store, sv->level); + WRITE_INT(data->store, sv->weeks); + } + } + WRITE_INT(data->store, -1); + WRITE_SECTION(data->store); +} + +unit *read_unit(gamedata *data) { unit *u; const race *rc; @@ -760,20 +792,7 @@ unit *read_unit(struct gamedata *data) set_order(&u->thisorder, NULL); assert(u_race(u)); - for (;;) { - int n = NOSKILL, level, weeks; - skill_t sk; - READ_INT(data->store, &n); - sk = (skill_t)n; - if (sk == NOSKILL) break; - READ_INT(data->store, &level); - READ_INT(data->store, &weeks); - if (level) { - skill *sv = add_skill(u, sk); - sv->level = sv->old = (unsigned char)level; - sv->weeks = (unsigned char)weeks; - } - } + read_skills(data, u); read_items(data->store, &u->items); READ_INT(data->store, &u->hp); if (u->hp < u->number) { @@ -787,7 +806,7 @@ unit *read_unit(struct gamedata *data) void write_unit(struct gamedata *data, const unit * u) { order *ord; - int i, p = 0; + int p = 0; unsigned int flags = u->flags & UFL_SAVEMASK; const race *irace = u_irace(u); @@ -835,18 +854,7 @@ void write_unit(struct gamedata *data, const unit * u) WRITE_SECTION(data->store); assert(u_race(u)); - - for (i = 0; i != u->skill_size; ++i) { - skill *sv = u->skills + i; - assert(sv->weeks <= sv->level * 2 + 1); - if (sv->level > 0) { - WRITE_INT(data->store, sv->id); - WRITE_INT(data->store, sv->level); - WRITE_INT(data->store, sv->weeks); - } - } - WRITE_INT(data->store, -1); - WRITE_SECTION(data->store); + write_skills(data, u); write_items(data->store, u->items); WRITE_SECTION(data->store); if (u->hp == 0 && data->version < NORCSPELL_VERSION) { From 860afe855f4e3a14ddde354ed3db884203b02ddd Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 15 Sep 2017 22:03:54 +0200 Subject: [PATCH 03/41] improve the skill read/write code. --- src/kernel/save.c | 51 ++++++++++++++++++++++++++++----------------- src/util/gamedata.h | 5 +++-- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/kernel/save.c b/src/kernel/save.c index 97dbaf77b..586763b0a 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -614,35 +614,48 @@ static void writeorder(gamedata *data, const struct order *ord, static void read_skills(gamedata *data, unit *u) { - for (;;) { - int n = NOSKILL, level, weeks; - skill_t sk; - READ_INT(data->store, &n); - sk = (skill_t)n; - if (sk == NOSKILL) break; - READ_INT(data->store, &level); - READ_INT(data->store, &weeks); - if (level) { - skill *sv = add_skill(u, sk); - sv->level = sv->old = (unsigned char)level; - sv->weeks = (unsigned char)weeks; + if (data->version < SKILLSORT_VERSION) { + for (;;) { + int n = NOSKILL, level, weeks; + skill_t sk; + READ_INT(data->store, &n); + sk = (skill_t)n; + if (sk == NOSKILL) break; + READ_INT(data->store, &level); + READ_INT(data->store, &weeks); + if (level) { + skill *sv = add_skill(u, sk); + sv->level = sv->old = (unsigned char)level; + sv->weeks = (unsigned char)weeks; + } + } + } + else { + int i; + READ_INT(data->store, &u->skill_size); + u->skills = malloc(sizeof(skill)*u->skill_size); + for (i = 0; i != u->skill_size; ++i) { + skill *sv = u->skills + i; + int val; + READ_INT(data->store, &val); + sv->id = (skill_t)val; + READ_INT(data->store, &sv->level); + sv->old = sv->level; + READ_INT(data->store, &sv->weeks); } } } static void write_skills(gamedata *data, const unit *u) { int i; + WRITE_INT(data->store, u->skill_size); for (i = 0; i != u->skill_size; ++i) { skill *sv = u->skills + i; assert(sv->weeks <= sv->level * 2 + 1); - if (sv->level > 0) { - WRITE_INT(data->store, sv->id); - WRITE_INT(data->store, sv->level); - WRITE_INT(data->store, sv->weeks); - } + WRITE_INT(data->store, sv->id); + WRITE_INT(data->store, sv->level); + WRITE_INT(data->store, sv->weeks); } - WRITE_INT(data->store, -1); - WRITE_SECTION(data->store); } unit *read_unit(gamedata *data) diff --git a/src/util/gamedata.h b/src/util/gamedata.h index 058bc3f07..7ff7569ba 100644 --- a/src/util/gamedata.h +++ b/src/util/gamedata.h @@ -36,11 +36,12 @@ #define NOLANDITEM_VERSION 356 /* land_region has no items */ #define NORCSPELL_VERSION 357 /* data contains no RC_SPELL units */ #define SORTKEYS_VERSION 358 /* at_keys is sorted */ -#define FAMILIAR_FIX_VERSION 359 /* at_keys is sorted */ +#define FAMILIAR_FIX_VERSION 359 /* familiar links are fixed */ +#define SKILLSORT_VERSION 360 /* u->skills is sorted */ /* unfinished: */ #define CRYPT_VERSION 400 /* passwords are encrypted */ -#define RELEASE_VERSION FAMILIAR_FIX_VERSION /* current datafile */ +#define RELEASE_VERSION SKILLSORT_VERSION /* current datafile */ #define MIN_VERSION INTPAK_VERSION /* minimal datafile we support */ #define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */ From 8c6362002e400ad38da2737c68ddd66121dd4ec4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 16 Sep 2017 07:37:33 +0200 Subject: [PATCH 04/41] fix some niggles, delete invalid test. --- src/give.c | 6 ++++-- src/kernel/save.c | 5 +++++ src/magic.c | 4 +--- src/magic.test.c | 19 ------------------- 4 files changed, 10 insertions(+), 24 deletions(-) diff --git a/src/give.c b/src/give.c index b55e6687b..18d355031 100644 --- a/src/give.c +++ b/src/give.c @@ -418,10 +418,12 @@ message * give_men(int n, unit * u, unit * u2, struct order *ord) set_racename(&u2->attribs, get_racename(u->attribs)); u_setrace(u2, u_race(u)); u2->irace = u->irace; - if (fval(u, UFL_HERO)) + if (fval(u, UFL_HERO)) { fset(u2, UFL_HERO); - else + } + else { freset(u2, UFL_HERO); + } } /* Einheiten von Schiffen können nicht NACH in von diff --git a/src/kernel/save.c b/src/kernel/save.c index 586763b0a..f1f4f3c60 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -648,10 +648,15 @@ static void read_skills(gamedata *data, unit *u) static void write_skills(gamedata *data, const unit *u) { int i; + skill_t sk = NOSKILL; WRITE_INT(data->store, u->skill_size); for (i = 0; i != u->skill_size; ++i) { skill *sv = u->skills + i; +#ifndef NDEBUG + assert(sv->id > sk); + sk = sv->id; assert(sv->weeks <= sv->level * 2 + 1); +#endif WRITE_INT(data->store, sv->id); WRITE_INT(data->store, sv->level); WRITE_INT(data->store, sv->weeks); diff --git a/src/magic.c b/src/magic.c index f5e7810b4..20054f3e7 100644 --- a/src/magic.c +++ b/src/magic.c @@ -356,9 +356,7 @@ static int read_seenspell(attrib * a, void *owner, struct gamedata *data) } sp = find_spell(token); if (!sp) { - log_warning("read_seenspell: could not find spell '%s'\n", token); - } - if (!sp) { + log_info("read_seenspell: could not find spell '%s'\n", token); return AT_READ_FAIL; } a->data.v = sp; diff --git a/src/magic.test.c b/src/magic.test.c index a1b55b45d..b240ac467 100644 --- a/src/magic.test.c +++ b/src/magic.test.c @@ -445,24 +445,6 @@ static void test_max_spellpoints(CuTest *tc) { test_cleanup(); } -static void test_familiar_mage(CuTest *tc) { - unit *um, *uf, *ut; - test_setup(); - um = test_create_unit(test_create_faction(0), test_create_region(0, 0, 0)); - uf = test_create_unit(um->faction, um->region); - ut = test_create_unit(um->faction, um->region); - set_number(ut, 0); - CuAssertTrue(tc, create_newfamiliar(um, uf)); - CuAssertTrue(tc, is_familiar(uf)); - CuAssertTrue(tc, !is_familiar(um)); - CuAssertPtrEquals(tc, um, get_familiar_mage(uf)); - CuAssertPtrEquals(tc, uf, get_familiar(um)); - - CuAssertPtrEquals(tc, NULL, give_men(1, um, ut, NULL)); - CuAssertPtrEquals(tc, ut, get_familiar_mage(uf)); - test_cleanup(); -} - static void test_illusioncastle(CuTest *tc) { building *b; @@ -502,6 +484,5 @@ CuSuite *get_magic_suite(void) SUITE_ADD_TEST(suite, test_magic_resistance); SUITE_ADD_TEST(suite, test_max_spellpoints); SUITE_ADD_TEST(suite, test_illusioncastle); - DISABLE_TEST(suite, test_familiar_mage); return suite; } From 423fe6537703d21860a9241d082f41f6b1a6ee38 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 16 Sep 2017 07:58:57 +0200 Subject: [PATCH 05/41] move region display to land_region struct, oceans do not have descriptions. --- src/creport.c | 4 +-- src/kernel/region.c | 13 +++++---- src/kernel/region.h | 3 +-- src/kernel/save.c | 64 +++++++++++++++++++++++++-------------------- src/laws.c | 4 +-- src/laws.test.c | 2 +- src/report.c | 6 ++--- src/util/gamedata.h | 1 + 8 files changed, 52 insertions(+), 45 deletions(-) diff --git a/src/creport.c b/src/creport.c index 12cb4e5b5..b68f3e4fe 100644 --- a/src/creport.c +++ b/src/creport.c @@ -1365,8 +1365,8 @@ static void cr_output_region(FILE * F, report_context * ctx, region * r) unit *u; int stealthmod = stealth_modifier(r->seen.mode); - if (r->display && r->display[0]) - fprintf(F, "\"%s\";Beschr\n", r->display); + if (r->land && r->land->display && r->land->display[0]) + fprintf(F, "\"%s\";Beschr\n", r->land->display); if (fval(r->terrain, LAND_REGION)) { assert(r->land); fprintf(F, "%d;Bauern\n", rpeasants(r)); diff --git a/src/kernel/region.c b/src/kernel/region.c index e8da83c50..f770ec089 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -825,8 +825,8 @@ void free_land(land_region * lr) lr->demands = d->next; free(d); } - if (lr->name) - free(lr->name); + free(lr->name); + free(lr->display); free(lr); } @@ -894,7 +894,6 @@ void free_region(region * r) { if (last == r) last = NULL; - free(r->display); if (r->land) free_land(r->land); @@ -1088,7 +1087,6 @@ void terraform_region(region * r, const terrain_type * terrain) terraform_resources(r); if (!fval(terrain, LAND_REGION)) { - region_setinfo(r, NULL); if (r->land) { free_land(r->land); r->land = NULL; @@ -1444,13 +1442,14 @@ faction *update_owners(region * r) void region_setinfo(struct region *r, const char *info) { - free(r->display); - r->display = info ? strdup(info) : 0; + assert(r->land); + free(r->land->display); + r->land->display = info ? strdup(info) : 0; } const char *region_getinfo(const region * r) { - return r->display ? r->display : ""; + return (r->land && r->land->display) ? r->land->display : ""; } void region_setname(struct region *r, const char *name) diff --git a/src/kernel/region.h b/src/kernel/region.h index c81411468..827ddbdab 100644 --- a/src/kernel/region.h +++ b/src/kernel/region.h @@ -96,7 +96,7 @@ extern "C" { typedef struct land_region { char *name; - /* TODO: demand kann nach Konvertierung entfernt werden. */ + char *display; demand *demands; const struct item_type *herbtype; short herbs; @@ -122,7 +122,6 @@ extern "C" { int uid; /* a unique id */ int x, y; struct plane *_plane; /* to access, use rplane(r) */ - char *display; int flags; unsigned short age; struct message_list *msgs; diff --git a/src/kernel/save.c b/src/kernel/save.c index f1f4f3c60..a719cb17b 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -377,7 +377,7 @@ race_t typus2race(unsigned char typus) return NORACE; } -static void read_alliances(struct gamedata *data) +static void read_alliances(gamedata *data) { storage *store = data->store; char pbuf[8]; @@ -492,7 +492,7 @@ void write_planes(storage *store) { } } -void write_alliances(struct gamedata *data) +void write_alliances(gamedata *data) { alliance *al = alliances; while (al) { @@ -524,7 +524,7 @@ static int resolve_owner(variant id, void *address) return result; } -static void read_owner(struct gamedata *data, region_owner ** powner) +static void read_owner(gamedata *data, region_owner ** powner) { int since_turn; @@ -563,7 +563,7 @@ static void read_owner(struct gamedata *data, region_owner ** powner) } } -static void write_owner(struct gamedata *data, region_owner * owner) +static void write_owner(gamedata *data, region_owner * owner) { if (owner) { faction *f; @@ -821,7 +821,7 @@ unit *read_unit(gamedata *data) return u; } -void write_unit(struct gamedata *data, const unit * u) +void write_unit(gamedata *data, const unit * u) { order *ord; int p = 0; @@ -885,7 +885,23 @@ void write_unit(struct gamedata *data, const unit * u) WRITE_SECTION(data->store); } -static region *readregion(struct gamedata *data, int x, int y) +static void read_regioninfo(gamedata *data, region *r) { + if (lomem) { + READ_STR(data->store, NULL, 0); + } + else { + char info[DISPLAYSIZE]; + READ_STR(data->store, info, sizeof(info)); + if (unicode_utf8_trim(info) != 0) { + log_warning("trim region %d info to '%s'", r->uid, info); + } + if (r->land) { + region_setinfo(r, info); + } + } +} + +static region *readregion(gamedata *data, int x, int y) { region *r = findregion(x, y); const terrain_type *terrain; @@ -915,16 +931,8 @@ static region *readregion(struct gamedata *data, int x, int y) } r->land = 0; } - if (lomem) { - READ_STR(data->store, NULL, 0); - } - else { - char info[DISPLAYSIZE]; - READ_STR(data->store, info, sizeof(info)); - if (unicode_utf8_trim(info)!=0) { - log_warning("trim region %d info to '%s'", uid, info); - }; - region_setinfo(r, info); + if (data->version < LANDDISPLAY_VERSION) { + read_regioninfo(data, r); } READ_STR(data->store, name, sizeof(name)); @@ -941,15 +949,18 @@ static region *readregion(struct gamedata *data, int x, int y) if (fval(r->terrain, LAND_REGION)) { r->land = calloc(1, sizeof(land_region)); READ_STR(data->store, name, sizeof(name)); - if (unicode_utf8_trim(name)!=0) { - log_warning("trim region %d name to '%s'", uid, name); - }; + if (unicode_utf8_trim(name) != 0) { + log_warning("trim region %d name to '%s'", uid, name); + }; r->land->name = strdup(name); } if (r->land) { int i; rawmaterial **pres = &r->resources; + if (data->version >= LANDDISPLAY_VERSION) { + read_regioninfo(data, r); + } READ_INT(data->store, &i); if (i < 0) { log_error("number of trees in %s is %d.", regionname(r, NULL), i); @@ -1069,24 +1080,23 @@ region *read_region(gamedata *data) return r; } -void writeregion(struct gamedata *data, const region * r) +void writeregion(gamedata *data, const region * r) { assert(r); assert(data); WRITE_INT(data->store, r->uid); - WRITE_STR(data->store, region_getinfo(r)); WRITE_TOK(data->store, r->terrain->_name); WRITE_INT(data->store, r->flags & RF_SAVEMASK); WRITE_INT(data->store, r->age); WRITE_SECTION(data->store); - if (fval(r->terrain, LAND_REGION)) { + if (r->land) { const item_type *rht; struct demand *demand; rawmaterial *res = r->resources; - assert(r->land); WRITE_STR(data->store, (const char *)r->land->name); + WRITE_STR(data->store, region_getinfo(r)); assert(rtrees(r, 0) >= 0); assert(rtrees(r, 1) >= 0); assert(rtrees(r, 2) >= 0); @@ -1122,11 +1132,9 @@ void writeregion(struct gamedata *data, const region * r) } WRITE_TOK(data->store, "end"); WRITE_SECTION(data->store); -#if RELEASE_VERSION>=REGIONOWNER_VERSION WRITE_INT(data->store, region_get_morale(r)); write_owner(data, r->land->ownership); WRITE_SECTION(data->store); -#endif } write_attribs(data->store, r->attribs, r); WRITE_SECTION(data->store); @@ -1243,7 +1251,7 @@ void _test_write_password(gamedata *data, const faction *f) { write_password(data, f); } -faction *read_faction(struct gamedata * data) +faction *read_faction(gamedata * data) { ally **sfp; int planes, n; @@ -1395,7 +1403,7 @@ faction *read_faction(struct gamedata * data) return f; } -void write_faction(struct gamedata *data, const faction * f) +void write_faction(gamedata *data, const faction * f) { ally *sf; ursprung *ur; @@ -1584,7 +1592,7 @@ void write_ship(gamedata *data, const ship *sh) write_attribs(store, sh->attribs, sh); } -ship *read_ship(struct gamedata *data) +ship *read_ship(gamedata *data) { char name[DISPLAYSIZE]; ship *sh; diff --git a/src/laws.c b/src/laws.c index c3c7d968e..d7f73fa6c 100644 --- a/src/laws.c +++ b/src/laws.c @@ -1559,11 +1559,11 @@ int display_cmd(unit * u, struct order *ord) break; case P_REGION: - if (u->faction != region_get_owner(r)) { + if (!r->land || u->faction != region_get_owner(r)) { cmistake(u, ord, 147, MSG_EVENT); break; } - s = &r->display; + s = &r->land->display; break; default: diff --git a/src/laws.test.c b/src/laws.test.c index 4d6adbfe9..9f7884fc5 100644 --- a/src/laws.test.c +++ b/src/laws.test.c @@ -227,7 +227,7 @@ static void test_display_cmd(CuTest *tc) { ord = create_order(K_DISPLAY, f->locale, "%s Hodor", LOC(f->locale, parameters[P_REGION])); CuAssertIntEquals(tc, 0, display_cmd(u, ord)); - CuAssertPtrEquals(tc, NULL, r->display); + CuAssertPtrEquals(tc, NULL, r->land->display); free_order(ord); test_cleanup(); diff --git a/src/report.c b/src/report.c index 18d48b86b..2dac94011 100644 --- a/src/report.c +++ b/src/report.c @@ -1069,15 +1069,15 @@ void report_region(struct stream *out, const region * r, faction * f) if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - if (r->display && r->display[0]) { + if (r->land && r->land->display && r->land->display[0]) { bytes = (int)strlcpy(bufp, " ", size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - bytes = (int)strlcpy(bufp, r->display, size); + bytes = (int)strlcpy(bufp, r->land->display, size); if (wrptr(&bufp, &size, bytes) != 0) WARN_STATIC_BUFFER(); - n = r->display[strlen(r->display) - 1]; + n = r->land->display[strlen(r->land->display) - 1]; if (n != '!' && n != '?' && n != '.') { bytes = (int)strlcpy(bufp, ".", size); if (wrptr(&bufp, &size, bytes) != 0) diff --git a/src/util/gamedata.h b/src/util/gamedata.h index 7ff7569ba..7d355f86b 100644 --- a/src/util/gamedata.h +++ b/src/util/gamedata.h @@ -38,6 +38,7 @@ #define SORTKEYS_VERSION 358 /* at_keys is sorted */ #define FAMILIAR_FIX_VERSION 359 /* familiar links are fixed */ #define SKILLSORT_VERSION 360 /* u->skills is sorted */ +#define LANDDISPLAY_VERSION 360 /* r.display is now in r.land.display */ /* unfinished: */ #define CRYPT_VERSION 400 /* passwords are encrypted */ From 1b19e8d19c7fbb568382209c6cec28f57648cab5 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 16 Sep 2017 08:42:49 +0200 Subject: [PATCH 06/41] =?UTF-8?q?BUG=202365:=20Ozeane=20sollen=20keine=20B?= =?UTF-8?q?eschreibung=20haben=20k=C3=B6nnen.=20https://trello.com/c/GSeHT?= =?UTF-8?q?8t6/618-why-r-display-not-r-land-display?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/kernel/save.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/kernel/save.c b/src/kernel/save.c index a719cb17b..94a25c07e 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -885,19 +885,15 @@ void write_unit(gamedata *data, const unit * u) WRITE_SECTION(data->store); } -static void read_regioninfo(gamedata *data, region *r) { +static void read_regioninfo(gamedata *data, const region *r, char *info) { if (lomem) { READ_STR(data->store, NULL, 0); } else { - char info[DISPLAYSIZE]; READ_STR(data->store, info, sizeof(info)); if (unicode_utf8_trim(info) != 0) { log_warning("trim region %d info to '%s'", r->uid, info); } - if (r->land) { - region_setinfo(r, info); - } } } @@ -906,6 +902,7 @@ static region *readregion(gamedata *data, int x, int y) region *r = findregion(x, y); const terrain_type *terrain; char name[NAMESIZE]; + char info[DISPLAYSIZE]; int uid = 0; int n; @@ -932,7 +929,7 @@ static region *readregion(gamedata *data, int x, int y) r->land = 0; } if (data->version < LANDDISPLAY_VERSION) { - read_regioninfo(data, r); + read_regioninfo(data, r, info); } READ_STR(data->store, name, sizeof(name)); @@ -959,8 +956,9 @@ static region *readregion(gamedata *data, int x, int y) rawmaterial **pres = &r->resources; if (data->version >= LANDDISPLAY_VERSION) { - read_regioninfo(data, r); + read_regioninfo(data, r, info); } + region_setinfo(r, info); READ_INT(data->store, &i); if (i < 0) { log_error("number of trees in %s is %d.", regionname(r, NULL), i); @@ -1038,7 +1036,11 @@ static region *readregion(gamedata *data, int x, int y) READ_INT(data->store, &n); rsetmoney(r, n); } - + else { + if (info[0]) { + log_error("%s %d has a description: %s", r->terrain->_name, r->uid, info); + } + } assert(r->terrain != NULL); if (r->land) { @@ -1759,6 +1761,9 @@ int read_game(gamedata *data) /* Burgen */ READ_INT(store, &p); + if (p > 0 && !r->land) { + log_error("%s, uid=%d has %d buildings", regionname(r, NULL), r->uid, p); + } bp = &r->buildings; while (--p >= 0) { From 0a3eb9ac7bd04962b4f45b9a3f916407411f1e65 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 16 Sep 2017 09:03:42 +0200 Subject: [PATCH 07/41] fix read/write of regioninfo. --- src/kernel/region.c | 2 +- src/kernel/save.c | 8 ++++---- src/kernel/save.test.c | 4 ++++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/kernel/region.c b/src/kernel/region.c index f770ec089..2d0a601b6 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -1444,7 +1444,7 @@ void region_setinfo(struct region *r, const char *info) { assert(r->land); free(r->land->display); - r->land->display = info ? strdup(info) : 0; + r->land->display = (info && info[0]) ? strdup(info) : 0; } const char *region_getinfo(const region * r) diff --git a/src/kernel/save.c b/src/kernel/save.c index 94a25c07e..629a2f45e 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -885,12 +885,12 @@ void write_unit(gamedata *data, const unit * u) WRITE_SECTION(data->store); } -static void read_regioninfo(gamedata *data, const region *r, char *info) { +static void read_regioninfo(gamedata *data, const region *r, char *info, size_t len) { if (lomem) { READ_STR(data->store, NULL, 0); } else { - READ_STR(data->store, info, sizeof(info)); + READ_STR(data->store, info, len); if (unicode_utf8_trim(info) != 0) { log_warning("trim region %d info to '%s'", r->uid, info); } @@ -929,7 +929,7 @@ static region *readregion(gamedata *data, int x, int y) r->land = 0; } if (data->version < LANDDISPLAY_VERSION) { - read_regioninfo(data, r, info); + read_regioninfo(data, r, info, sizeof(info)); } READ_STR(data->store, name, sizeof(name)); @@ -956,7 +956,7 @@ static region *readregion(gamedata *data, int x, int y) rawmaterial **pres = &r->resources; if (data->version >= LANDDISPLAY_VERSION) { - read_regioninfo(data, r, info); + read_regioninfo(data, r, info, sizeof(info)); } region_setinfo(r, info); READ_INT(data->store, &i); diff --git a/src/kernel/save.test.c b/src/kernel/save.test.c index 9501df896..81d5a507d 100644 --- a/src/kernel/save.test.c +++ b/src/kernel/save.test.c @@ -116,12 +116,15 @@ static void test_readwrite_region(CuTest * tc) gamedata data; storage store; region *r; + const char * lipsum = "Lorem ipsum dolor sit amet"; test_setup(); r = test_create_region(0, 0, 0); free(r->land->name); r->land->name = strdup(" Hodor "); CuAssertStrEquals(tc, " Hodor ", r->land->name); + region_setinfo(r, lipsum); + CuAssertStrEquals(tc, lipsum, r->land->display); mstream_init(&data.strm); gamedata_init(&data, &store, RELEASE_VERSION); write_region(&data, r); @@ -132,6 +135,7 @@ static void test_readwrite_region(CuTest * tc) r = read_region(&data); CuAssertPtrNotNull(tc, r); CuAssertStrEquals(tc, "Hodor", r->land->name); + CuAssertStrEquals(tc, lipsum, r->land->display); regions = r; mstream_done(&data.strm); From 0d0fb493812d95cc924b751a34d84408873d9512 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 16 Sep 2017 09:34:47 +0200 Subject: [PATCH 08/41] attempt to fix valgrind bug --- src/kernel/save.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/kernel/save.c b/src/kernel/save.c index 629a2f45e..e68c726f5 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -931,6 +931,9 @@ static region *readregion(gamedata *data, int x, int y) if (data->version < LANDDISPLAY_VERSION) { read_regioninfo(data, r, info, sizeof(info)); } + else { + info[0] = '\0'; + } READ_STR(data->store, name, sizeof(name)); terrain = get_terrain(name); From 8e0bdbe428eb84728f5024f7cc4e641e3c017d1d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 17 Sep 2017 09:31:43 +0200 Subject: [PATCH 09/41] coverity scan does not understand get_or_create_equipment? --- src/kernel/equipment.c | 25 ++++++++++++++++--------- src/kernel/equipment.h | 1 + src/kernel/messages.h | 6 +++--- src/kernel/xmlreader.c | 6 +++++- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index 11fe594f5..bbd049938 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -214,19 +214,26 @@ equipment *get_equipment(const char *eqname) return eq; } +equipment *create_equipment(const char *eqname) +{ + equipment *eq; + size_t len; + char data[64]; + + eq = (equipment *)calloc(1, sizeof(equipment)); + eq->name = strdup(eqname); + + len = cb_new_kv(eqname, strlen(eqname), &eq, sizeof(eq), data); + assert(len <= sizeof(data)); + cb_insert(&cb_equipments, data, len); + return eq; +} + equipment *get_or_create_equipment(const char *eqname) { equipment *eq = get_equipment(eqname); if (!eq) { - size_t len; - char data[64]; - - eq = (equipment *)calloc(1, sizeof(equipment)); - eq->name = strdup(eqname); - - len = cb_new_kv(eqname, strlen(eqname), &eq, sizeof(eq), data); - assert(len <= sizeof(data)); - cb_insert(&cb_equipments, data, len); + return create_equipment(eqname); } return eq; } diff --git a/src/kernel/equipment.h b/src/kernel/equipment.h index 928182dfb..bc479662d 100644 --- a/src/kernel/equipment.h +++ b/src/kernel/equipment.h @@ -57,6 +57,7 @@ extern "C" { struct equipment *get_or_create_equipment(const char *eqname); struct equipment *get_equipment(const char *eqname); + struct equipment *create_equipment(const char *eqname); void equipment_setitem(struct equipment *eq, const struct item_type *itype, const char *value); diff --git a/src/kernel/messages.h b/src/kernel/messages.h index 4eca65fc1..58558072d 100644 --- a/src/kernel/messages.h +++ b/src/kernel/messages.h @@ -46,10 +46,10 @@ extern "C" { int level; } msglevel; - extern struct message *msg_message(const char *name, const char *sig, ...); - extern struct message *msg_feedback(const struct unit *, struct order *cmd, + struct message *msg_message(const char *name, const char *sig, ...); + struct message *msg_feedback(const struct unit *, struct order *cmd, const char *name, const char *sig, ...); - extern struct message *add_message(struct message_list **pm, + struct message *add_message(struct message_list **pm, struct message *m); void addmessage(struct region *r, struct faction *f, const char *s, msg_t mtype, int level); diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 2ef54b005..57ad5ffad 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -1069,9 +1069,13 @@ static int parse_equipment(xmlDocPtr doc) xmlChar *propName = xmlGetProp(node, BAD_CAST "name"); if (propName != NULL) { - equipment *eq = get_or_create_equipment((const char *)propName); + equipment *eq = get_equipment((const char *)propName); xmlXPathObjectPtr xpathResult; + if (!eq) { + eq = create_equipment((const char *)propName); + } + xpath->node = node; xpathResult = xmlXPathEvalExpression(BAD_CAST "callback", xpath); From 455e03fa0526cff025e2b61d75100080e52cd242 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 17 Sep 2017 20:42:43 +0200 Subject: [PATCH 10/41] try and make coverity understand the equipment trie. shorten names. --- conf/e2/rules.xml | 4 ++-- res/e3a/equipment.xml | 2 +- res/e3a/familiars.xml | 30 +++++++++++++------------- res/eressea/equipment.xml | 40 +++++++++++++++++----------------- res/eressea/familiars.xml | 30 +++++++++++++------------- scripts/eressea/autoseed.lua | 6 +++--- src/battle.c | 2 +- src/economy.c | 1 - src/kernel/equipment.c | 42 ++++++++++++++++++++++-------------- src/monsters.c | 6 +++--- src/spells.c | 2 +- src/teleport.c | 2 +- 12 files changed, 88 insertions(+), 79 deletions(-) diff --git a/conf/e2/rules.xml b/conf/e2/rules.xml index 45b9030d3..22ff8109f 100644 --- a/conf/e2/rules.xml +++ b/conf/e2/rules.xml @@ -25,7 +25,7 @@ - + @@ -38,7 +38,7 @@ - + diff --git a/res/e3a/equipment.xml b/res/e3a/equipment.xml index 9fe133f48..62123766a 100644 --- a/res/e3a/equipment.xml +++ b/res/e3a/equipment.xml @@ -1,7 +1,7 @@ - + diff --git a/res/e3a/familiars.xml b/res/e3a/familiars.xml index 775546099..4a9fad6c8 100644 --- a/res/e3a/familiars.xml +++ b/res/e3a/familiars.xml @@ -2,27 +2,27 @@ - + - + - + - + - + @@ -30,7 +30,7 @@ - + @@ -42,7 +42,7 @@ - + @@ -53,11 +53,11 @@ - + - + @@ -65,7 +65,7 @@ - + @@ -73,14 +73,14 @@ - + - + @@ -88,15 +88,15 @@ - + - + - + diff --git a/res/eressea/equipment.xml b/res/eressea/equipment.xml index efd4f2a3b..3605bb1fd 100644 --- a/res/eressea/equipment.xml +++ b/res/eressea/equipment.xml @@ -2,18 +2,18 @@ - + - + - + @@ -21,30 +21,30 @@ - + - + - + - + - + - + @@ -58,12 +58,12 @@ - + - + @@ -177,7 +177,7 @@ - + @@ -229,22 +229,22 @@ - + - + - + - + @@ -252,24 +252,24 @@ - + - + - + - + diff --git a/res/eressea/familiars.xml b/res/eressea/familiars.xml index 8503123cb..7e9bb75dc 100644 --- a/res/eressea/familiars.xml +++ b/res/eressea/familiars.xml @@ -2,26 +2,26 @@ - + - + - + - + @@ -29,7 +29,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -54,7 +54,7 @@ - + @@ -67,12 +67,12 @@ - + - + @@ -80,7 +80,7 @@ - + @@ -92,7 +92,7 @@ - + @@ -103,7 +103,7 @@ - + @@ -111,19 +111,19 @@ - + - + - + diff --git a/scripts/eressea/autoseed.lua b/scripts/eressea/autoseed.lua index 10a33627f..fc658d1a1 100644 --- a/scripts/eressea/autoseed.lua +++ b/scripts/eressea/autoseed.lua @@ -65,9 +65,9 @@ local function seed(r, email, race, lang) assert(f) local u = unit.create(f, r) assert(u) - equip_unit(u, "autoseed_faction") - equip_unit(u, "autoseed_unit") - equip_unit(u, "autoseed_" .. race, 7) + equip_unit(u, "seed_faction") + equip_unit(u, "seed_unit") + equip_unit(u, "seed_" .. race, 7) unit.create(f, r, 5):set_skill("mining", 30) unit.create(f, r, 5):set_skill("quarrying", 30) f:set_origin(r) diff --git a/src/battle.c b/src/battle.c index be513f288..ad1c0f8da 100644 --- a/src/battle.c +++ b/src/battle.c @@ -927,7 +927,7 @@ void kill_troop(troop dt) if (drops != NULL) { i_merge(&du->items, &drops); } - sprintf(eqname, "%s_spoils", rc->_name); + sprintf(eqname, "spo_%s", rc->_name); eq = get_equipment(eqname); if (eq != NULL) { equip_items(&du->items, eq); diff --git a/src/economy.c b/src/economy.c index 74595a335..7c4b0efd3 100644 --- a/src/economy.c +++ b/src/economy.c @@ -266,7 +266,6 @@ void add_recruits(unit * u, int number, int wanted) strlcpy(equipment, "new_", sizeof(equipment)); strlcat(equipment, u_race(u)->_name, sizeof(equipment)); - strlcat(equipment, "_unit", sizeof(equipment)); equip_unit(unew, get_equipment(equipment)); if (unew != u) { diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index bbd049938..ca2f68a02 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -30,6 +30,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* util includes */ #include #include +#include #include #include @@ -202,31 +203,41 @@ void free_ls(void *arg) { static critbit_tree cb_equipments = { 0 }; +#define EQNAMELEN 16 +typedef struct eq_entry { + char key[EQNAMELEN]; + equipment *value; +} eq_entry; + equipment *get_equipment(const char *eqname) { const char *match; - equipment *eq = NULL; + + assert(strlen(eqname) <= EQNAMELEN); match = cb_find_str(&cb_equipments, eqname); if (match) { - cb_get_kv(match, &eq, sizeof(eq)); + eq_entry *ent = (eq_entry *)match; + return ent->value; } - return eq; + return NULL; } equipment *create_equipment(const char *eqname) { - equipment *eq; - size_t len; - char data[64]; + eq_entry ent; - eq = (equipment *)calloc(1, sizeof(equipment)); - eq->name = strdup(eqname); + if (strlen(eqname) > EQNAMELEN) { + log_error("equipment names should be no longer than %d bytes: %s", EQNAMELEN, eqname); + } + /* OBS: we require the nul-padding property of strncpy here, so do not use strlcpy: */ + strncpy(ent.key, eqname, EQNAMELEN); - len = cb_new_kv(eqname, strlen(eqname), &eq, sizeof(eq), data); - assert(len <= sizeof(data)); - cb_insert(&cb_equipments, data, len); - return eq; + ent.value = (equipment *)calloc(1, sizeof(equipment)); + ent.value->name = strdup(eqname); + + cb_insert(&cb_equipments, &ent, sizeof(ent)); + return ent.value; } equipment *get_or_create_equipment(const char *eqname) @@ -258,10 +269,9 @@ static void free_equipment(equipment *eq) { } static int free_equipment_cb(const void * match, const void * key, size_t keylen, void *cbdata) { - equipment *eq; - cb_get_kv(match, &eq, sizeof(eq)); - free_equipment(eq); - free(eq); + eq_entry * ent = (eq_entry *)match; + free_equipment(ent->value); + free(ent->value); return 0; } diff --git a/src/monsters.c b/src/monsters.c index ddc30ca4d..4cd7fee29 100644 --- a/src/monsters.c +++ b/src/monsters.c @@ -612,7 +612,7 @@ static void recruit_dracoids(unit * dragon, int size) name_unit(un); change_money(dragon, -un->number * 50); - equip_unit(un, get_equipment("recruited_dracoid")); + equip_unit(un, get_equipment("new_dracoid")); setstatus(un, ST_FIGHT); for (weapon = un->items; weapon; weapon = weapon->next) { @@ -863,7 +863,7 @@ static int nrand(int start, int sub) unit *spawn_seaserpent(region *r, faction *f) { unit *u = create_unit(r, f, 1, get_race(RC_SEASERPENT), 0, NULL, NULL); fset(u, UFL_ISNEW | UFL_MOVED); - equip_unit(u, get_equipment("monster_seaserpent")); + equip_unit(u, get_equipment("seed_seaserpent")); return u; } @@ -894,7 +894,7 @@ void spawn_dragons(void) u = create_unit(r, monsters, nrand(30, 20) + 1, get_race(RC_DRAGON), 0, NULL, NULL); } fset(u, UFL_ISNEW | UFL_MOVED); - equip_unit(u, get_equipment("monster_dragon")); + equip_unit(u, get_equipment("seed_dragon")); log_debug("spawning %d %s in %s.\n", u->number, LOC(default_locale, diff --git a/src/spells.c b/src/spells.c index c6860bebe..b516edd26 100644 --- a/src/spells.c +++ b/src/spells.c @@ -519,7 +519,7 @@ static void make_familiar(unit * familiar, unit * mage) const struct equipment *eq; char eqname[64]; const race * rc = u_race(familiar); - snprintf(eqname, sizeof(eqname), "%s_familiar", rc->_name); + snprintf(eqname, sizeof(eqname), "fam_%s", rc->_name); eq = get_equipment(eqname); if (eq != NULL) { equip_items(&familiar->items, eq); diff --git a/src/teleport.c b/src/teleport.c index f81f2f9f0..78098c264 100644 --- a/src/teleport.c +++ b/src/teleport.c @@ -160,7 +160,7 @@ void spawn_braineaters(float chance) unit *u = create_unit(r, f0, 1 + rng_int() % 10 + rng_int() % 10, get_race(RC_HIRNTOETER), 0, NULL, NULL); - equip_unit(u, get_equipment("monster_braineater")); + equip_unit(u, get_equipment("seed_braineater")); next = rng_int() % (int)(chance * 100); } From eca1e5f973f3ef837ce7dc926901c7fbcab6ffc2 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sun, 17 Sep 2017 21:09:23 +0200 Subject: [PATCH 11/41] make keys_size not return 4096 all the time. --- src/attributes/key.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/attributes/key.c b/src/attributes/key.c index 6841bbd71..00f81a80e 100644 --- a/src/attributes/key.c +++ b/src/attributes/key.c @@ -67,8 +67,12 @@ static int keys_size(int n) { assert(n > 0 && n <= 4096); if (n <= 1) return 1; if (n <= 4) return 4; + if (n <= 8) return 8; if (n <= 16) return 16; if (n <= 256) return 256; + if (n <= 512) return 512; + if (n <= 1024) return 1024; + if (n <= 2048) return 2048; return 4096; } From 97dc98862b405b3e14e13f13bab147265f94c6e1 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Sep 2017 07:53:02 +0200 Subject: [PATCH 12/41] do not use strncpy, then --- src/kernel/equipment.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index ca2f68a02..98d6b1e70 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -225,13 +225,15 @@ equipment *get_equipment(const char *eqname) equipment *create_equipment(const char *eqname) { + size_t len = strlen(eqname); eq_entry ent; - if (strlen(eqname) > EQNAMELEN) { + if (len > EQNAMELEN) { log_error("equipment names should be no longer than %d bytes: %s", EQNAMELEN, eqname); + len = EQNAMELEN; } - /* OBS: we require the nul-padding property of strncpy here, so do not use strlcpy: */ - strncpy(ent.key, eqname, EQNAMELEN); + memset(ent.key, 0, EQNAMELEN); + memcpy(ent.key, eqname, len); ent.value = (equipment *)calloc(1, sizeof(equipment)); ent.value->name = strdup(eqname); From c9445ab517acde15a659c0441796c473a077384a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Sep 2017 11:48:42 +0200 Subject: [PATCH 13/41] change resource_type trie storage --- src/kernel/item.c | 56 +++++++++++++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/src/kernel/item.c b/src/kernel/item.c index 8639ac5d1..7f77fc3bb 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -60,6 +60,12 @@ static critbit_tree cb_resources; luxury_type *luxurytypes; potion_type *potiontypes; +#define RTYPENAMELEN 16 +typedef struct rt_entry { + char key[RTYPENAMELEN]; + struct resource_type *value; +} rt_entry; + static int res_changeaura(unit * u, const resource_type * rtype, int delta) { assert(rtype != NULL); @@ -166,13 +172,19 @@ static int num_resources; static void rt_register(resource_type * rtype) { - char buffer[64]; const char * name = rtype->_name; size_t len = strlen(name); + rt_entry ent; - assert(len < sizeof(buffer) - sizeof(rtype)); - len = cb_new_kv(name, len, &rtype, sizeof(rtype), buffer); - cb_insert(&cb_resources, buffer, len); + if (len > RTYPENAMELEN) { + log_error("resource names may not be longer than %d bytes: %s", + RTYPENAMELEN, name); + len = RTYPENAMELEN; + } + ent.value = rtype; + memset(ent.key, 0, RTYPENAMELEN); + memcpy(ent.key, name, len); + cb_insert(&cb_resources, &ent, sizeof(ent)); ++num_resources; } @@ -186,7 +198,6 @@ resource_type *rt_get_or_create(const char *name) { else { rtype->_name = strdup(name); rt_register(rtype); - return rt_find(name); } } return rtype; @@ -390,12 +401,18 @@ const potion_type *resource2potion(const resource_type * rtype) resource_type *rt_find(const char *name) { void * match; - resource_type *result = 0; + size_t len = strlen(name); - if (cb_find_prefix(&cb_resources, name, strlen(name) + 1, &match, 1, 0)) { - cb_get_kv(match, &result, sizeof(result)); + if (len > RTYPENAMELEN) { + log_error("resource name is longer than $d bytes: %s", + RTYPENAMELEN, name); + len = RTYPENAMELEN; } - return result; + if (cb_find_prefix(&cb_resources, name, len, &match, 1, 0)) { + rt_entry *ent = (rt_entry *)match; + return ent->value; + } + return NULL; } item **i_find(item ** i, const item_type * it) @@ -792,14 +809,14 @@ int change_money(unit * u, int v) return 0; } -static int add_resourcename_cb(const void * match, const void * key, size_t keylen, void *data) +static int add_resourcename_cb(const void * match, const void * key, + size_t keylen, void *data) { struct locale * lang = (struct locale *)data; int i = locale_index(lang); critbit_tree * cb = rnames + i; - resource_type *rtype; + resource_type *rtype = ((rt_entry *)match)->value; - cb_get_kv(match, &rtype, sizeof(rtype)); for (i = 0; i != 2; ++i) { char buffer[128]; const char * name = LOC(lang, resourcename(rtype, (i == 0) ? 0 : NMF_PLURAL)); @@ -835,20 +852,20 @@ const resource_type *findresourcetype(const char *name, const struct locale *lan else { log_debug("findresourcetype: transliterate failed for '%s'\n", name); } - return 0; + return NULL; } attrib_type at_showitem = { "showitem" }; -static int add_itemname_cb(const void * match, const void * key, size_t keylen, void *data) +static int add_itemname_cb(const void * match, const void * key, + size_t keylen, void *data) { struct locale * lang = (struct locale *)data; critbit_tree * cb = inames + locale_index(lang); - resource_type *rtype; + resource_type *rtype = ((rt_entry *)match)->value; - cb_get_kv(match, &rtype, sizeof(rtype)); if (rtype->itype) { int i; for (i = 0; i != 2; ++i) { @@ -980,9 +997,10 @@ void free_rtype(resource_type *rtype) { free(rtype); } -int free_rtype_cb(const void * match, const void * key, size_t keylen, void *cbdata) { - resource_type *rtype; - cb_get_kv(match, &rtype, sizeof(rtype)); +static int free_rtype_cb(const void * match, const void * key, + size_t keylen, void *cbdata) +{ + resource_type *rtype = ((rt_entry *)match)->value;; free_rtype(rtype); return 0; } From 1f659327946ef73b70c1cbc839ec4f9c21a1943c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Sep 2017 17:20:09 +0200 Subject: [PATCH 14/41] add a test for get_equipment with substrings. --- src/kernel/equipment.test.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/kernel/equipment.test.c b/src/kernel/equipment.test.c index 1e6bf1819..4ed077fb0 100644 --- a/src/kernel/equipment.test.c +++ b/src/kernel/equipment.test.c @@ -10,7 +10,7 @@ #include #include -void test_equipment(CuTest * tc) +static void test_equipment(CuTest * tc) { equipment * eq; unit * u; @@ -46,9 +46,33 @@ void test_equipment(CuTest * tc) test_cleanup(); } +static void test_get_equipment(CuTest * tc) +{ + equipment * eq; + + test_setup(); + eq = create_equipment("catapultammo"); + CuAssertPtrNotNull(tc, eq); + CuAssertStrEquals(tc, "catapultammo", eq->name); + eq = get_equipment("catapultammo"); + CuAssertPtrNotNull(tc, eq); + CuAssertStrEquals(tc, "catapultammo", eq->name); + eq = get_equipment("catapult"); + CuAssertPtrEquals(tc, NULL, eq); + eq = create_equipment("catapult"); + eq = get_equipment("catapult"); + CuAssertPtrNotNull(tc, eq); + CuAssertStrEquals(tc, "catapult", eq->name); + eq = get_equipment("catapultammo"); + CuAssertPtrNotNull(tc, eq); + CuAssertStrEquals(tc, "catapultammo", eq->name); + test_cleanup(); +} + CuSuite *get_equipment_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_equipment); + SUITE_ADD_TEST(suite, test_get_equipment); return suite; } From 69079ce319da71321874cd5bfe2b598e752fdcb2 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Sep 2017 17:20:58 +0200 Subject: [PATCH 15/41] remove it_register, because it does nothing. --- src/kernel/item.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/kernel/item.c b/src/kernel/item.c index 8639ac5d1..81a0c78cb 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -192,16 +192,6 @@ resource_type *rt_get_or_create(const char *name) { return rtype; } -static void it_register(item_type * itype) -{ - char buffer[64]; - const char * name = itype->rtype->_name; - size_t len = strlen(name); - - assert(len < sizeof(buffer) - sizeof(itype)); - len = cb_new_kv(name, len, &itype, sizeof(itype), buffer); -} - static const char *it_aliases[][2] = { { "Runenschwert", "runesword" }, { "p12", "truthpotion" }, @@ -244,7 +234,6 @@ item_type *it_get_or_create(resource_type *rtype) { rtype->uchange = res_changeitem; rtype->itype = itype; rtype->flags |= RTF_ITEM; - it_register(itype); return itype; } From 7fdbb1b939c8ccbb2392d6d261a45bf7c69e40d6 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Sep 2017 17:26:34 +0200 Subject: [PATCH 16/41] add a test for rt_find to flush out substring matches. --- src/kernel/item.test.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/kernel/item.test.c b/src/kernel/item.test.c index c1c64bf62..c6113ec5d 100644 --- a/src/kernel/item.test.c +++ b/src/kernel/item.test.c @@ -173,12 +173,31 @@ static void test_core_resources(CuTest *tc) { test_cleanup(); } +static void test_get_resource(CuTest *tc) { + resource_type *rtype; + + test_setup(); + + CuAssertPtrEquals(tc, NULL, rt_find("catapultammo")); + rtype = rt_get_or_create("catapultammo"); + CuAssertPtrNotNull(tc, rtype); + CuAssertPtrEquals(tc, rtype, rt_find("catapultammo")); + CuAssertStrEquals(tc, "catapultammo", rtype->_name); + + CuAssertPtrEquals(tc, NULL, rt_find("catapult")); + rtype = rt_get_or_create("catapult"); + CuAssertPtrEquals(tc, rtype, rt_find("catapult")); + CuAssertStrEquals(tc, "catapult", rtype->_name); + test_cleanup(); +} + CuSuite *get_item_suite(void) { CuSuite *suite = CuSuiteNew(); SUITE_ADD_TEST(suite, test_resourcename_no_appearance); SUITE_ADD_TEST(suite, test_resourcename_with_appearance); SUITE_ADD_TEST(suite, test_change_item); + SUITE_ADD_TEST(suite, test_get_resource); SUITE_ADD_TEST(suite, test_resource_type); SUITE_ADD_TEST(suite, test_finditemtype); SUITE_ADD_TEST(suite, test_findresourcetype); From 4cab65d23367a913843a27cac470df3e7b3d15a0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Sep 2017 17:32:39 +0200 Subject: [PATCH 17/41] fail get_equipment test when name is exactly 16 bytes long. --- src/kernel/equipment.c | 1 + src/kernel/equipment.test.c | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index 98d6b1e70..0db84c761 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -204,6 +204,7 @@ void free_ls(void *arg) { static critbit_tree cb_equipments = { 0 }; #define EQNAMELEN 16 + typedef struct eq_entry { char key[EQNAMELEN]; equipment *value; diff --git a/src/kernel/equipment.test.c b/src/kernel/equipment.test.c index 4ed077fb0..cc88fc826 100644 --- a/src/kernel/equipment.test.c +++ b/src/kernel/equipment.test.c @@ -51,12 +51,12 @@ static void test_get_equipment(CuTest * tc) equipment * eq; test_setup(); - eq = create_equipment("catapultammo"); + eq = create_equipment("catapultammo1234"); CuAssertPtrNotNull(tc, eq); - CuAssertStrEquals(tc, "catapultammo", eq->name); - eq = get_equipment("catapultammo"); + CuAssertStrEquals(tc, "catapultammo1234", eq->name); + eq = get_equipment("catapultammo1234"); CuAssertPtrNotNull(tc, eq); - CuAssertStrEquals(tc, "catapultammo", eq->name); + CuAssertStrEquals(tc, "catapultammo1234", eq->name); eq = get_equipment("catapult"); CuAssertPtrEquals(tc, NULL, eq); eq = create_equipment("catapult"); From e2f6ada862e370f2d2cce8cc1cae48da11155731 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Sep 2017 17:46:26 +0200 Subject: [PATCH 18/41] limit equipment names to 15 byte plus nul. --- res/eressea/equipment.xml | 70 +++++++++++++++++-------------------- src/kernel/equipment.c | 8 ++--- src/kernel/equipment.test.c | 12 +++---- src/randenc.c | 16 ++++----- 4 files changed, 51 insertions(+), 55 deletions(-) diff --git a/res/eressea/equipment.xml b/res/eressea/equipment.xml index 3605bb1fd..e4d48aefe 100644 --- a/res/eressea/equipment.xml +++ b/res/eressea/equipment.xml @@ -69,7 +69,7 @@ - + @@ -79,53 +79,53 @@ - + - + - + - + - + - + - + - + - + @@ -136,43 +136,43 @@ - + - - - - + + + + - + - + - + - + - + - + - + @@ -184,9 +184,9 @@ - - - + + + @@ -195,38 +195,34 @@ - + - + - + - + - + - + - - - - - - + + diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index 98d6b1e70..747dd631a 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -213,7 +213,7 @@ equipment *get_equipment(const char *eqname) { const char *match; - assert(strlen(eqname) <= EQNAMELEN); + assert(strlen(eqname) < EQNAMELEN); match = cb_find_str(&cb_equipments, eqname); if (match) { @@ -228,9 +228,9 @@ equipment *create_equipment(const char *eqname) size_t len = strlen(eqname); eq_entry ent; - if (len > EQNAMELEN) { - log_error("equipment names should be no longer than %d bytes: %s", EQNAMELEN, eqname); - len = EQNAMELEN; + if (len >= EQNAMELEN) { + log_error("equipment names should be no longer than %d bytes: %s", EQNAMELEN-1, eqname); + len = EQNAMELEN-1; } memset(ent.key, 0, EQNAMELEN); memcpy(ent.key, eqname, len); diff --git a/src/kernel/equipment.test.c b/src/kernel/equipment.test.c index 4ed077fb0..0398e2141 100644 --- a/src/kernel/equipment.test.c +++ b/src/kernel/equipment.test.c @@ -51,21 +51,21 @@ static void test_get_equipment(CuTest * tc) equipment * eq; test_setup(); - eq = create_equipment("catapultammo"); + eq = create_equipment("catapultammo123"); CuAssertPtrNotNull(tc, eq); - CuAssertStrEquals(tc, "catapultammo", eq->name); - eq = get_equipment("catapultammo"); + CuAssertStrEquals(tc, "catapultammo123", eq->name); + eq = get_equipment("catapultammo123"); CuAssertPtrNotNull(tc, eq); - CuAssertStrEquals(tc, "catapultammo", eq->name); + CuAssertStrEquals(tc, "catapultammo123", eq->name); eq = get_equipment("catapult"); CuAssertPtrEquals(tc, NULL, eq); eq = create_equipment("catapult"); eq = get_equipment("catapult"); CuAssertPtrNotNull(tc, eq); CuAssertStrEquals(tc, "catapult", eq->name); - eq = get_equipment("catapultammo"); + eq = get_equipment("catapultammo123"); CuAssertPtrNotNull(tc, eq); - CuAssertStrEquals(tc, "catapultammo", eq->name); + CuAssertStrEquals(tc, "catapultammo123", eq->name); test_cleanup(); } diff --git a/src/randenc.c b/src/randenc.c index 2b46499e6..b2b282eb1 100644 --- a/src/randenc.c +++ b/src/randenc.c @@ -263,7 +263,7 @@ static void get_villagers(region * r, unit * u) u); leave(newunit, true); fset(newunit, UFL_ISNEW | UFL_MOVED); - equip_unit(newunit, get_equipment("random_villagers")); + equip_unit(newunit, get_equipment("rand_villagers")); } static void get_allies(region * r, unit * u) @@ -282,7 +282,7 @@ static void get_allies(region * r, unit * u) if (get_money(u) / u->number < 100 + rng_int() % 200) return; name = "random_plain_men"; - equip = "random_plain"; + equip = "rand_plain"; number = rng_int() % 8 + 2; break; } @@ -293,7 +293,7 @@ static void get_allies(region * r, unit * u) return; } name = "random_forest_men"; - equip = "random_forest"; + equip = "rand_forest"; number = rng_int() % 6 + 2; } break; @@ -303,7 +303,7 @@ static void get_allies(region * r, unit * u) return; } name = "random_swamp_men"; - equip = "random_swamp"; + equip = "rand_swamp"; number = rng_int() % 6 + 2; break; @@ -312,7 +312,7 @@ static void get_allies(region * r, unit * u) return; } name = "random_desert_men"; - equip = "random_desert"; + equip = "rand_desert"; number = rng_int() % 12 + 2; break; @@ -321,7 +321,7 @@ static void get_allies(region * r, unit * u) return; } name = "random_highland_men"; - equip = "random_highland"; + equip = "rand_highland"; number = rng_int() % 8 + 2; break; @@ -330,7 +330,7 @@ static void get_allies(region * r, unit * u) return; } name = "random_mountain_men"; - equip = "random_mountain"; + equip = "rand_mountain"; number = rng_int() % 6 + 2; break; @@ -339,7 +339,7 @@ static void get_allies(region * r, unit * u) return; } name = "random_glacier_men"; - equip = "random_glacier"; + equip = "rand_glacier"; number = rng_int() % 4 + 2; break; From 2451a8f637a1c3aa94f8881f70e905dfe9a95bdf Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Sep 2017 17:56:27 +0200 Subject: [PATCH 19/41] resource names are max 23 bytes long. fix rt_find nul-termination bug --- clibs | 2 +- src/kernel/equipment.c | 2 +- src/kernel/item.c | 23 ++++++++++++----------- src/kernel/item.test.c | 8 ++++---- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/clibs b/clibs index d286006a2..2a55c27fe 160000 --- a/clibs +++ b/clibs @@ -1 +1 @@ -Subproject commit d286006a28c8aa7cd70ed7fd4cd172b50ade9727 +Subproject commit 2a55c27fedec76845cf82c758b7b7c3fa649c286 diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index 6bc7e1616..73d4e7d3a 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -212,7 +212,7 @@ typedef struct eq_entry { equipment *get_equipment(const char *eqname) { - const char *match; + char *match; assert(strlen(eqname) < EQNAMELEN); diff --git a/src/kernel/item.c b/src/kernel/item.c index 2c38db008..ec162fa7b 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -60,7 +60,7 @@ static critbit_tree cb_resources; luxury_type *luxurytypes; potion_type *potiontypes; -#define RTYPENAMELEN 16 +#define RTYPENAMELEN 24 typedef struct rt_entry { char key[RTYPENAMELEN]; struct resource_type *value; @@ -176,10 +176,10 @@ static void rt_register(resource_type * rtype) size_t len = strlen(name); rt_entry ent; - if (len > RTYPENAMELEN) { - log_error("resource names may not be longer than %d bytes: %s", - RTYPENAMELEN, name); - len = RTYPENAMELEN; + if (len >= RTYPENAMELEN) { + log_error("resource name is longer than %d bytes: %s", + RTYPENAMELEN-1, name); + len = RTYPENAMELEN-1; } ent.value = rtype; memset(ent.key, 0, RTYPENAMELEN); @@ -389,15 +389,16 @@ const potion_type *resource2potion(const resource_type * rtype) resource_type *rt_find(const char *name) { - void * match; + char *match; size_t len = strlen(name); - if (len > RTYPENAMELEN) { - log_error("resource name is longer than $d bytes: %s", - RTYPENAMELEN, name); - len = RTYPENAMELEN; + if (len >= RTYPENAMELEN) { + log_error("resource name is longer than %d bytes: %s", + RTYPENAMELEN-1, name); + return NULL; } - if (cb_find_prefix(&cb_resources, name, len, &match, 1, 0)) { + match = cb_find_str(&cb_resources, name); + if (match) { rt_entry *ent = (rt_entry *)match; return ent->value; } diff --git a/src/kernel/item.test.c b/src/kernel/item.test.c index c6113ec5d..89954c451 100644 --- a/src/kernel/item.test.c +++ b/src/kernel/item.test.c @@ -178,11 +178,11 @@ static void test_get_resource(CuTest *tc) { test_setup(); - CuAssertPtrEquals(tc, NULL, rt_find("catapultammo")); - rtype = rt_get_or_create("catapultammo"); + CuAssertPtrEquals(tc, NULL, rt_find("catapultammo123")); + rtype = rt_get_or_create("catapultammo123"); CuAssertPtrNotNull(tc, rtype); - CuAssertPtrEquals(tc, rtype, rt_find("catapultammo")); - CuAssertStrEquals(tc, "catapultammo", rtype->_name); + CuAssertPtrEquals(tc, rtype, rt_find("catapultammo123")); + CuAssertStrEquals(tc, "catapultammo123", rtype->_name); CuAssertPtrEquals(tc, NULL, rt_find("catapult")); rtype = rt_get_or_create("catapult"); From 6083ff76166693b4a4eadda37a43bda284fbf192 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Sep 2017 19:13:26 +0200 Subject: [PATCH 20/41] get_spellbook has a bug. new clibs version --- clibs | 2 +- src/magic.test.c | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/clibs b/clibs index d286006a2..2a55c27fe 160000 --- a/clibs +++ b/clibs @@ -1 +1 @@ -Subproject commit d286006a28c8aa7cd70ed7fd4cd172b50ade9727 +Subproject commit 2a55c27fedec76845cf82c758b7b7c3fa649c286 diff --git a/src/magic.test.c b/src/magic.test.c index b240ac467..c6866ce47 100644 --- a/src/magic.test.c +++ b/src/magic.test.c @@ -51,7 +51,18 @@ void test_updatespells(CuTest * tc) test_cleanup(); } -void test_spellbooks(CuTest * tc) +static void test_get_spellbook(CuTest * tc) +{ + spellbook *sb; + + test_setup(); + CuAssertPtrNotNull(tc, sb = get_spellbook("hodorhodorhodor")); + CuAssertPtrEquals(tc, sb, get_spellbook("hodorhodorhodor")); + CuAssertTrue(tc, sb != get_spellbook("hodor")); + test_cleanup(); +} + +static void test_spellbooks(CuTest * tc) { spell *sp; spellbook *herp, *derp; @@ -472,6 +483,7 @@ CuSuite *get_magic_suite(void) SUITE_ADD_TEST(suite, test_multi_cast); SUITE_ADD_TEST(suite, test_updatespells); SUITE_ADD_TEST(suite, test_spellbooks); + SUITE_ADD_TEST(suite, test_get_spellbook); SUITE_ADD_TEST(suite, test_pay_spell); SUITE_ADD_TEST(suite, test_pay_spell_failure); SUITE_ADD_TEST(suite, test_getspell_unit); From 02ed1dfe0cf8a5a89d897624bc45d0fc8d5b7aec Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Sep 2017 19:35:37 +0200 Subject: [PATCH 21/41] fix get_spellbook with cb_find_str. --- src/magic.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/magic.c b/src/magic.c index 20054f3e7..b066764a4 100644 --- a/src/magic.c +++ b/src/magic.c @@ -3013,7 +3013,8 @@ spellbook * get_spellbook(const char * name) spellbook * result; void * match; - if (cb_find_prefix(&cb_spellbooks, name, strlen(name), &match, 1, 0) > 0) { + match = cb_find_str(&cb_spellbooks, name); + if (match) { cb_get_kv(match, &result, sizeof(result)); } else { From b4fc7a1ab489b967bb09f6ff98d453a9f5f10c7a Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Sep 2017 19:51:47 +0200 Subject: [PATCH 22/41] fix coverity nag about spellbooks. --- clibs | 2 +- src/kernel/equipment.c | 6 +++--- src/kernel/item.c | 4 ++-- src/magic.c | 44 +++++++++++++++++++++++------------------- 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/clibs b/clibs index 2a55c27fe..da2c0cc39 160000 --- a/clibs +++ b/clibs @@ -1 +1 @@ -Subproject commit 2a55c27fedec76845cf82c758b7b7c3fa649c286 +Subproject commit da2c0cc39b27c98ed8d31b0503426788fc236bd8 diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index 73d4e7d3a..cf2f8ca5c 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -212,13 +212,13 @@ typedef struct eq_entry { equipment *get_equipment(const char *eqname) { - char *match; + const void *match; assert(strlen(eqname) < EQNAMELEN); match = cb_find_str(&cb_equipments, eqname); if (match) { - eq_entry *ent = (eq_entry *)match; + const eq_entry *ent = (const eq_entry *)match; return ent->value; } return NULL; @@ -272,7 +272,7 @@ static void free_equipment(equipment *eq) { } static int free_equipment_cb(const void * match, const void * key, size_t keylen, void *cbdata) { - eq_entry * ent = (eq_entry *)match; + const eq_entry * ent = (const eq_entry *)match; free_equipment(ent->value); free(ent->value); return 0; diff --git a/src/kernel/item.c b/src/kernel/item.c index ec162fa7b..39e72745e 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -389,7 +389,7 @@ const potion_type *resource2potion(const resource_type * rtype) resource_type *rt_find(const char *name) { - char *match; + const void *match; size_t len = strlen(name); if (len >= RTYPENAMELEN) { @@ -399,7 +399,7 @@ resource_type *rt_find(const char *name) } match = cb_find_str(&cb_resources, name); if (match) { - rt_entry *ent = (rt_entry *)match; + const rt_entry *ent = (const rt_entry *)match; return ent->value; } return NULL; diff --git a/src/magic.c b/src/magic.c index b066764a4..f113ca4f1 100644 --- a/src/magic.c +++ b/src/magic.c @@ -3007,31 +3007,36 @@ int cast_spell(struct castorder *co) static critbit_tree cb_spellbooks; +#define SBNAMELEN 16 + +typedef struct sb_entry { + char key[SBNAMELEN]; + spellbook *value; +} sb_entry; + spellbook * get_spellbook(const char * name) { - char buffer[64]; - spellbook * result; - void * match; + size_t len = strlen(name); + const void * match; + + if (len >= SBNAMELEN) { + log_error("spellbook name is longer than %d bytes: %s", SBNAMELEN-1, name); + return NULL; + } match = cb_find_str(&cb_spellbooks, name); - if (match) { - cb_get_kv(match, &result, sizeof(result)); - } - else { - size_t len = strlen(name); - result = create_spellbook(name); - assert(strlen(name) + sizeof(result) < sizeof(buffer)); - len = cb_new_kv(name, len, &result, sizeof(result), buffer); - if (cb_insert(&cb_spellbooks, buffer, len) == CB_EXISTS) { + if (!match) { + sb_entry ent; + memset(ent.key, 0, SBNAMELEN); + memcpy(ent.key, name, len); + ent.value = create_spellbook(name); + if (cb_insert(&cb_spellbooks, &ent, sizeof(ent)) == CB_EXISTS) { log_error("cb_insert failed although cb_find returned nothing for spellbook=%s", name); assert(!"should not happen"); } - result = 0; - if (cb_find_prefix(&cb_spellbooks, name, strlen(name), &match, 1, 0) > 0) { - cb_get_kv(match, &result, sizeof(result)); - } + return ent.value; } - return result; + return ((const sb_entry *)match)->value; } void free_spellbook(spellbook *sb) { @@ -3040,9 +3045,8 @@ void free_spellbook(spellbook *sb) { } static int free_spellbook_cb(const void *match, const void *key, size_t keylen, void *data) { - spellbook *sb; - cb_get_kv(match, &sb, sizeof(sb)); - free_spellbook(sb); + const sb_entry *ent = (const sb_entry *)match; + free_spellbook(ent->value); return 0; } From f43ec9ee0fc31ac736552872d5cc9d37d987adf0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Sep 2017 20:03:23 +0200 Subject: [PATCH 23/41] remove equipment.name, save an allocation. --- src/kernel/equipment.c | 28 ++++++++++++++++++++++++++-- src/kernel/equipment.h | 2 +- src/kernel/equipment.test.c | 8 ++++---- src/kernel/xmlreader.c | 6 +++--- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index cf2f8ca5c..bf22b8054 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -210,6 +210,32 @@ typedef struct eq_entry { equipment *value; } eq_entry; +typedef struct name_cb_data { + const equipment *find; + const char *result; +} name_cb_data; + + +static int equipment_name_cb(const void * match, const void * key, size_t keylen, void *cbdata) { + const eq_entry *ent = (const eq_entry *)match; + name_cb_data *query = (name_cb_data *)cbdata; + if (ent->value == query->find) { + query->result = ent->key; + return 1; + } + return 0; +} + +const char *equipment_name(const struct equipment *eq) +{ + name_cb_data data; + + data.find = eq; + data.result = NULL; + cb_foreach(&cb_equipments, "", 0, equipment_name_cb, &data); + return data.result; +} + equipment *get_equipment(const char *eqname) { const void *match; @@ -237,7 +263,6 @@ equipment *create_equipment(const char *eqname) memcpy(ent.key, eqname, len); ent.value = (equipment *)calloc(1, sizeof(equipment)); - ent.value->name = strdup(eqname); cb_insert(&cb_equipments, &ent, sizeof(ent)); return ent.value; @@ -254,7 +279,6 @@ equipment *get_or_create_equipment(const char *eqname) static void free_equipment(equipment *eq) { int i; - free(eq->name); if (eq->spells) { selist_foreach(eq->spells, free_ls); selist_free(eq->spells); diff --git a/src/kernel/equipment.h b/src/kernel/equipment.h index bc479662d..9fbffe67f 100644 --- a/src/kernel/equipment.h +++ b/src/kernel/equipment.h @@ -45,7 +45,6 @@ extern "C" { } subset; typedef struct equipment { - char *name; struct itemdata *items; char *skills[MAXSKILLS]; struct selist *spells; @@ -55,6 +54,7 @@ extern "C" { void equipment_done(void); + const char *equipment_name(const struct equipment *eq); struct equipment *get_or_create_equipment(const char *eqname); struct equipment *get_equipment(const char *eqname); struct equipment *create_equipment(const char *eqname); diff --git a/src/kernel/equipment.test.c b/src/kernel/equipment.test.c index 0398e2141..7952001fe 100644 --- a/src/kernel/equipment.test.c +++ b/src/kernel/equipment.test.c @@ -53,19 +53,19 @@ static void test_get_equipment(CuTest * tc) test_setup(); eq = create_equipment("catapultammo123"); CuAssertPtrNotNull(tc, eq); - CuAssertStrEquals(tc, "catapultammo123", eq->name); + CuAssertStrEquals(tc, "catapultammo123", equipment_name(eq)); eq = get_equipment("catapultammo123"); CuAssertPtrNotNull(tc, eq); - CuAssertStrEquals(tc, "catapultammo123", eq->name); + CuAssertStrEquals(tc, "catapultammo123", equipment_name(eq)); eq = get_equipment("catapult"); CuAssertPtrEquals(tc, NULL, eq); eq = create_equipment("catapult"); eq = get_equipment("catapult"); CuAssertPtrNotNull(tc, eq); - CuAssertStrEquals(tc, "catapult", eq->name); + CuAssertStrEquals(tc, "catapult", equipment_name(eq)); eq = get_equipment("catapultammo123"); CuAssertPtrNotNull(tc, eq); - CuAssertStrEquals(tc, "catapultammo123", eq->name); + CuAssertStrEquals(tc, "catapultammo123", equipment_name(eq)); test_cleanup(); } diff --git a/src/kernel/xmlreader.c b/src/kernel/xmlreader.c index 57ad5ffad..18bdedebc 100644 --- a/src/kernel/xmlreader.c +++ b/src/kernel/xmlreader.c @@ -960,7 +960,7 @@ static void add_spells(equipment * eq, xmlNodeSetPtr nsetItems) equipment_addspell(eq, name, level); } else { - log_error("spell '%s' for equipment-set '%s' has no level\n", name, eq->name); + log_error("spell '%s' for equipment-set '%s' has no level\n", name, equipment_name(eq)); } xmlFree(propValue); } @@ -980,7 +980,7 @@ static void add_skills(equipment * eq, xmlNodeSetPtr nsetSkills) assert(propValue != NULL); sk = findskill((const char *)propValue); if (sk == NOSKILL) { - log_error("unknown skill '%s' in equipment-set %s\n", (const char *)propValue, eq->name); + log_error("unknown skill '%s' in equipment-set %s\n", (const char *)propValue, equipment_name(eq)); xmlFree(propValue); } else { @@ -1044,7 +1044,7 @@ add_subsets(xmlDocPtr doc, equipment * eq, xmlNodeSetPtr nsetSubsets) } } if (totalChance > 1.0f) { - log_error("total chance exceeds 1.0: %f in equipment set %s.\n", totalChance, eq->name); + log_error("total chance exceeds 1.0: %f in equipment set %s.\n", totalChance, equipment_name(eq)); } } xmlXPathFreeObject(xpathResult); From 832ba5f948b04cf104ce553d519fc5da4f19855d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Sep 2017 20:14:46 +0200 Subject: [PATCH 24/41] relax the limit on shortness of names a bit. --- src/kernel/equipment.c | 9 ++++++--- src/kernel/item.c | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/kernel/equipment.c b/src/kernel/equipment.c index bf22b8054..b87f401dd 100644 --- a/src/kernel/equipment.c +++ b/src/kernel/equipment.c @@ -203,7 +203,7 @@ void free_ls(void *arg) { static critbit_tree cb_equipments = { 0 }; -#define EQNAMELEN 16 +#define EQNAMELEN 24 typedef struct eq_entry { char key[EQNAMELEN]; @@ -240,7 +240,10 @@ equipment *get_equipment(const char *eqname) { const void *match; - assert(strlen(eqname) < EQNAMELEN); + if (strlen(eqname) >= EQNAMELEN) { + log_warning("equipment name is longer than %d bytes: %s", EQNAMELEN - 1, eqname); + return NULL; + } match = cb_find_str(&cb_equipments, eqname); if (match) { @@ -256,7 +259,7 @@ equipment *create_equipment(const char *eqname) eq_entry ent; if (len >= EQNAMELEN) { - log_error("equipment names should be no longer than %d bytes: %s", EQNAMELEN-1, eqname); + log_error("equipment name is longer than %d bytes: %s", EQNAMELEN-1, eqname); len = EQNAMELEN-1; } memset(ent.key, 0, EQNAMELEN); diff --git a/src/kernel/item.c b/src/kernel/item.c index 39e72745e..89c532297 100644 --- a/src/kernel/item.c +++ b/src/kernel/item.c @@ -393,7 +393,7 @@ resource_type *rt_find(const char *name) size_t len = strlen(name); if (len >= RTYPENAMELEN) { - log_error("resource name is longer than %d bytes: %s", + log_warning("resource name is longer than %d bytes: %s", RTYPENAMELEN-1, name); return NULL; } From 4bccc87f2bdae4e13e1870492e3f54a3e59aaccc Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Sep 2017 20:20:13 +0200 Subject: [PATCH 25/41] fix Invalid read (valgrind) in remove_skill --- clibs | 2 +- src/kernel/unit.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clibs b/clibs index da2c0cc39..2a55c27fe 160000 --- a/clibs +++ b/clibs @@ -1 +1 @@ -Subproject commit da2c0cc39b27c98ed8d31b0503426788fc236bd8 +Subproject commit 2a55c27fedec76845cf82c758b7b7c3fa649c286 diff --git a/src/kernel/unit.c b/src/kernel/unit.c index b2eeec055..47345c057 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -1191,7 +1191,7 @@ void remove_skill(unit * u, skill_t sk) for (i = 0; i != u->skill_size; ++i) { sv = u->skills + i; if (sv->id == sk) { - memmove(sv, sv + 1, (u->skill_size - 1) * sizeof(skill)); + memmove(sv, sv + 1, (u->skill_size - i - 1) * sizeof(skill)); --u->skill_size; return; } From fd275341325c2303c20d99e84f6102627b80d295 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Sep 2017 20:23:31 +0200 Subject: [PATCH 26/41] coverity CID 173897 Pointer to local outside scope --- clibs | 2 +- src/reports.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clibs b/clibs index 2a55c27fe..da2c0cc39 160000 --- a/clibs +++ b/clibs @@ -1 +1 @@ -Subproject commit 2a55c27fedec76845cf82c758b7b7c3fa649c286 +Subproject commit da2c0cc39b27c98ed8d31b0503426788fc236bd8 diff --git a/src/reports.c b/src/reports.c index cc11f4006..daf1ffca4 100644 --- a/src/reports.c +++ b/src/reports.c @@ -1701,7 +1701,7 @@ static void var_free_regions(variant x) /*-V524 */ const char *trailinto(const region * r, const struct locale *lang) { - char ref[32]; + static char ref[32]; const char *s; if (r) { const char *tname = terrain_name(r); From 30777e59486efb2fd0d6ecb74935146cfbcdb6c4 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Sep 2017 20:27:34 +0200 Subject: [PATCH 27/41] CID 173898 'Constant' variable guards dead code --- src/kernel/unit.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 47345c057..685da7b42 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -277,6 +277,10 @@ int gift_items(unit * u, int flags) u->items = NULL; break; } + else if (!u3) { + /* pick a last-chance recipient: */ + u3 = u2; + } } } if (u->items && u3) { From d8c063ae506e1cc303c0c674bd167542d57604a0 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Sep 2017 20:33:36 +0200 Subject: [PATCH 28/41] CID 172474 + 173899 Copy into fixed size buffer --- src/keyword.c | 3 ++- src/util/umlaut.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/keyword.c b/src/keyword.c index cb56fe940..a38c91e07 100644 --- a/src/keyword.c +++ b/src/keyword.c @@ -2,6 +2,7 @@ #include #include "keyword.h" +#include #include #include #include @@ -20,7 +21,7 @@ const char * keyword(keyword_t kwd) if (!result[0]) { strcpy(result, "keyword::"); } - strcpy(result + 9, keywords[kwd]); + strlcpy(result + 9, keywords[kwd], sizeof(result) - 9); return result; } diff --git a/src/util/umlaut.c b/src/util/umlaut.c index d29cb78ac..27f7bc67d 100644 --- a/src/util/umlaut.c +++ b/src/util/umlaut.c @@ -21,6 +21,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "assert.h" #include "log.h" +#include "bsdstring.h" #include "unicode.h" #include @@ -211,7 +212,7 @@ void addtoken(tnode ** root, const char *str, variant id) if (lcs == replace[i].ucs) { char zText[1024]; memcpy(zText, replace[i].str, 3); - strcpy(zText + 2, (const char *)str + len); + strlcpy(zText + 2, (const char *)str + len, sizeof(zText)-2); addtoken(root, zText, id); break; } From 5e204083b82aebf4503077c8328f01712356306c Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Mon, 18 Sep 2017 21:43:52 +0200 Subject: [PATCH 29/41] remove noreply email, monster report. --- scripts/tests/process.lua | 11 ++++++----- src/monsters.c | 2 +- src/reports.c | 12 +++++++----- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/scripts/tests/process.lua b/scripts/tests/process.lua index c5515be0b..296b9d5ec 100644 --- a/scripts/tests/process.lua +++ b/scripts/tests/process.lua @@ -18,8 +18,9 @@ local function file_exists(name) if f~=nil then io.close(f) return true else return false end end -local function assert_file(filename) - assert_equal(true, file_exists(filename)) +local function assert_file(filename, exists) + if exists == nil then exists = true end + assert_equal(exists, file_exists(filename)) os.remove(filename) end @@ -30,9 +31,9 @@ function test_process_turn() assert_equal(0, write_reports()) assert_equal(0, eressea.write_game("test.dat")) assert_file("data/test.dat") - assert_file("reports/" .. get_turn() .. "-ii.nr") - assert_file("reports/" .. get_turn() .. "-ii.cr") - assert_file("reports/" .. get_turn() .. "-ii.txt") + assert_file("reports/" .. get_turn() .. "-ii.nr", false) + assert_file("reports/" .. get_turn() .. "-ii.cr", false) + assert_file("reports/" .. get_turn() .. "-ii.txt", false) assert_file("reports/" .. get_turn() .. "-777.nr") assert_file("reports/" .. get_turn() .. "-777.cr") assert_file("reports/" .. get_turn() .. "-777.txt") diff --git a/src/monsters.c b/src/monsters.c index 4cd7fee29..115759d29 100644 --- a/src/monsters.c +++ b/src/monsters.c @@ -1132,7 +1132,7 @@ faction *get_or_create_monsters(void) if (!f) { const race *rc = rc_get_or_create("dragon"); const char *email = config_get("monster.email"); - f = addfaction(email ? email : "noreply@eressea.de", NULL, rc, default_locale, 0); + f = addfaction(email ? email : NULL, NULL, rc, default_locale, 0); renumber_faction(f, MONSTER_ID); faction_setname(f, "Monster"); fset(f, FFL_NPC | FFL_NOIDLEOUT); diff --git a/src/reports.c b/src/reports.c index daf1ffca4..8e91bd3da 100644 --- a/src/reports.c +++ b/src/reports.c @@ -1616,11 +1616,13 @@ int reports(void) } for (f = factions; f; f = f->next) { - int error = write_reports(f, ltime); - if (error) - retval = error; - if (mailit) - write_script(mailit, f); + if (f->email && !fval(f, FFL_NPC)) { + int error = write_reports(f, ltime); + if (error) + retval = error; + if (mailit) + write_script(mailit, f); + } } if (mailit) fclose(mailit); From 89e162c12af51af51d6b672171953261bd4baded Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Tue, 19 Sep 2017 11:42:02 +0200 Subject: [PATCH 30/41] change resolve.h api to use int, not variant. --- src/kernel/building.c | 12 ++++++------ src/kernel/building.h | 4 ++-- src/kernel/curse.c | 7 +------ src/kernel/faction.c | 12 ++++++------ src/kernel/faction.h | 4 ++-- src/kernel/group.c | 6 +++--- src/kernel/plane.c | 17 +++++++++-------- src/kernel/race.c | 12 +++--------- src/kernel/race.h | 2 +- src/kernel/region.c | 24 ++++++++++++++---------- src/kernel/region.h | 6 +++--- src/kernel/save.c | 26 ++++++++++---------------- src/kernel/unit.c | 14 +++++++------- src/kernel/unit.h | 4 ++-- src/magic.c | 12 ++++++------ src/spells.c | 8 ++++---- src/triggers/changefaction.c | 8 ++++---- src/triggers/changerace.c | 4 ++-- src/triggers/createunit.c | 12 ++++++------ src/util/resolve.c | 19 ++++++------------- src/util/resolve.h | 13 +++++-------- src/wormhole.c | 4 ++-- 22 files changed, 104 insertions(+), 126 deletions(-) diff --git a/src/kernel/building.c b/src/kernel/building.c index 45faccdab..7c4453f6a 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -322,12 +322,12 @@ void write_building_reference(const struct building *b, struct storage *store) WRITE_INT(store, (b && b->region) ? b->no : 0); } -int resolve_building(variant id, void *address) +int resolve_building(int id, void *address) { int result = 0; building *b = NULL; - if (id.i != 0) { - b = findbuilding(id.i); + if (id != 0) { + b = findbuilding(id); if (b == NULL) { result = -1; } @@ -336,10 +336,10 @@ int resolve_building(variant id, void *address) return result; } -variant read_building_reference(gamedata * data) +int read_building_reference(gamedata * data) { - variant result; - READ_INT(data->store, &result.i); + int result; + READ_INT(data->store, &result); return result; } diff --git a/src/kernel/building.h b/src/kernel/building.h index 04ad08262..59af83bbe 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -152,10 +152,10 @@ extern "C" { #include "build.h" #define NOBUILDING NULL - int resolve_building(variant data, void *address); + int resolve_building(int id, void *address); void write_building_reference(const struct building *b, struct storage *store); - variant read_building_reference(struct gamedata *data); + int read_building_reference(struct gamedata *data); struct building *findbuilding(int n); diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 9702d7649..1364fb9a1 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -191,12 +191,7 @@ int curse_read(attrib * a, void *owner, gamedata *data) READ_INT(store, &c->duration); READ_FLT(store, &flt); c->vigour = flt; - if (data->version < INTPAK_VERSION) { - ur = resolve_unit(read_int(data->store), &c->magician); - } - else { - ur = read_reference(&c->magician, data, read_unit_reference, resolve_unit); - } + ur = read_reference(&c->magician, data, read_unit_reference, resolve_unit); if (data->version < CURSEFLOAT_VERSION) { READ_INT(store, &n); c->effect = (float)n; diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 736c9f4e6..3188d2299 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -203,12 +203,12 @@ const char *factionname(const faction * f) return ibuf; } -int resolve_faction(variant id, void *address) +int resolve_faction(int id, void *address) { int result = 0; faction *f = NULL; - if (id.i != 0) { - f = findfaction(id.i); + if (id != 0) { + f = findfaction(id); if (f == NULL) { result = -1; } @@ -332,10 +332,10 @@ bool checkpasswd(const faction * f, const char *passwd) return true; } -variant read_faction_reference(gamedata * data) +int read_faction_reference(gamedata * data) { - variant id; - READ_INT(data->store, &id.i); + int id; + READ_INT(data->store, &id); return id; } diff --git a/src/kernel/faction.h b/src/kernel/faction.h index 64832053b..62b3634b2 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -126,8 +126,8 @@ extern "C" { void write_faction_reference(const struct faction *f, struct storage *store); - variant read_faction_reference(struct gamedata *data); - int resolve_faction(variant data, void *addr); + int read_faction_reference(struct gamedata *data); + int resolve_faction(int id, void *addr); void renumber_faction(faction * f, int no); void free_factions(void); diff --git a/src/kernel/group.c b/src/kernel/group.c index 06f2f9f49..61c311c89 100755 --- a/src/kernel/group.c +++ b/src/kernel/group.c @@ -239,12 +239,12 @@ void read_groups(gamedata *data, faction * f) pa = &g->allies; for (;;) { ally *a; - variant fid; + int fid; fid = read_faction_reference(data); - if (fid.i <= 0) + if (fid <= 0) break; - a = ally_add(pa, findfaction(fid.i)); + a = ally_add(pa, findfaction(fid)); READ_INT(store, &a->status); if (!a->faction) ur_add(fid, &a->faction, resolve_faction); diff --git a/src/kernel/plane.c b/src/kernel/plane.c index 0b2fdc0d3..ebf6c64ad 100644 --- a/src/kernel/plane.c +++ b/src/kernel/plane.c @@ -258,12 +258,12 @@ unsigned char index) return (rel + ursprung_y(f, pl, NULL) + plane_center_y(pl)); } -static int resolve_plane(variant id, void *addr) +static int resolve_plane(int id, void *addr) { int result = 0; plane *pl = NULL; - if (id.i != 0) { - pl = getplanebyid(id.i); + if (id != 0) { + pl = getplanebyid(id); if (pl == NULL) { result = -1; } @@ -279,15 +279,16 @@ void write_plane_reference(const plane * u, struct storage *store) int read_plane_reference(plane ** pp, struct storage *store) { - variant id; - READ_INT(store, &id.i); - if (id.i == 0) { + int id; + READ_INT(store, &id); + if (id == 0) { *pp = NULL; return AT_READ_FAIL; } - *pp = getplanebyid(id.i); - if (*pp == NULL) + *pp = getplanebyid(id); + if (*pp == NULL) { ur_add(id, pp, resolve_plane); + } return AT_READ_OK; } diff --git a/src/kernel/race.c b/src/kernel/race.c index 14fb66331..a73c0e699 100644 --- a/src/kernel/race.c +++ b/src/kernel/race.c @@ -561,21 +561,15 @@ void write_race_reference(const race * rc, struct storage *store) WRITE_TOK(store, rc ? rc->_name : "none"); } -variant read_race_reference(struct storage *store) +struct race * read_race_reference(struct storage *store) { - variant result; char zName[20]; READ_TOK(store, zName, sizeof(zName)); if (strcmp(zName, "none") == 0) { - result.v = NULL; - return result; + return NULL; } - else { - result.v = rc_find_i(zName); - } - assert(result.v != NULL); - return result; + return rc_find_i(zName); } void register_race_function(race_func func, const char *name) { diff --git a/src/kernel/race.h b/src/kernel/race.h index 2dec5f06b..2990c2158 100644 --- a/src/kernel/race.h +++ b/src/kernel/race.h @@ -263,7 +263,7 @@ extern "C" { void write_race_reference(const struct race *rc, struct storage *store); - variant read_race_reference(struct storage *store); + struct race *read_race_reference(struct storage *store); const char *raceprefix(const struct unit *u); void register_race_function(race_func, const char *); diff --git a/src/kernel/region.c b/src/kernel/region.c index 2d0a601b6..3ffd0660a 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -1255,9 +1255,11 @@ int production(const region * r) return p; } -int resolve_region_coor(variant id, void *address) +int resolve_region_coor(int id, void *address) { - region *r = findregion(id.sa[0], id.sa[1]); + int x = (id >> 16); + int y = id & 0xFFFF; + region *r = findregion(x, y); if (r) { *(region **)address = r; return 0; @@ -1266,11 +1268,11 @@ int resolve_region_coor(variant id, void *address) return -1; } -int resolve_region_id(variant id, void *address) +int resolve_region_id(int id, void *address) { region *r = NULL; - if (id.i != 0) { - r = findregionbyid(id.i); + if (id != 0) { + r = findregionbyid(id); if (r == NULL) { *(region **)address = NULL; return -1; @@ -1280,19 +1282,21 @@ int resolve_region_id(variant id, void *address) return 0; } -variant read_region_reference(gamedata *data) +int read_region_reference(gamedata *data) { struct storage * store = data->store; - variant result; + int result; if (data->version < UIDHASH_VERSION) { int n; + short x, y; READ_INT(store, &n); - result.sa[0] = (short)n; + x = (short)n; READ_INT(store, &n); - result.sa[1] = (short)n; + y = (short)n; + result = x << 16 | (y & 0xFFFF); } else { - READ_INT(store, &result.i); + READ_INT(store, &result); } return result; } diff --git a/src/kernel/region.h b/src/kernel/region.h index 827ddbdab..ce5d37fa3 100644 --- a/src/kernel/region.h +++ b/src/kernel/region.h @@ -257,9 +257,9 @@ extern "C" { void region_set_morale(region * r, int morale, int turn); void write_region_reference(const struct region *r, struct storage *store); - variant read_region_reference(struct gamedata *data); - int resolve_region_coor(variant id, void *address); - int resolve_region_id(variant id, void *address); + int read_region_reference(struct gamedata *data); + int resolve_region_coor(int id, void *address); + int resolve_region_id(int id, void *address); #define RESOLVE_REGION(version) ((version= 0) { int id; - variant fno; plane *pl; READ_INT(store, &id); @@ -459,8 +458,8 @@ void read_planes(gamedata *data) { else { /* WATCHERS - eliminated in February 2016, ca. turn 966 */ if (data->version < NOWATCH_VERSION) { - fno = read_faction_reference(data); - while (fno.i) { + int fno = read_faction_reference(data); + while (fno) { fno = read_faction_reference(data); } } @@ -509,15 +508,15 @@ void write_alliances(gamedata *data) WRITE_SECTION(data->store); } -static int resolve_owner(variant id, void *address) +static int resolve_owner(int id, void *address) { region_owner *owner = (region_owner *)address; int result = 0; faction *f = NULL; - if (id.i != 0) { - f = findfaction(id.i); + if (id != 0) { + f = findfaction(id); if (f == NULL) { - log_error("region has an invalid owner (%s)", itoa36(id.i)); + log_error("region has an invalid owner (%s)", itoa36(id)); } } owner->owner = f; @@ -1171,9 +1170,7 @@ static ally **addally(const faction * f, ally ** sfp, int aid, int state) sf = ally_add(sfp, af); if (!sf->faction) { - variant id; - id.i = aid; - ur_add(id, &sf->faction, resolve_faction); + ur_add(aid, &sf->faction, resolve_faction); } sf->status = state & HELP_ALL; @@ -1489,7 +1486,7 @@ static int cb_sb_maxlevel(spellbook_entry *sbe, void *cbdata) { int readgame(const char *filename) { - int n; + int n, stream_version; char path[MAX_PATH]; gamedata gdata = { 0 }; storage store; @@ -1506,11 +1503,8 @@ int readgame(const char *filename) return -1; } sz = fread(&gdata.version, sizeof(int), 1, F); - if (sz != sizeof(int) || gdata.version >= INTPAK_VERSION) { - int stream_version; - size_t sz = fread(&stream_version, sizeof(int), 1, F); - assert((sz == 1 && stream_version == STREAM_VERSION) || !"unsupported data format"); - } + sz = fread(&stream_version, sizeof(int), 1, F); + assert((sz == 1 && stream_version == STREAM_VERSION) || !"unsupported data format"); assert(gdata.version >= MIN_VERSION || !"unsupported data format"); assert(gdata.version <= MAX_VERSION || !"unsupported data format"); diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 685da7b42..8d62b98c3 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -751,11 +751,11 @@ void write_unit_reference(const unit * u, struct storage *store) WRITE_INT(store, (u && u->region) ? u->no : 0); } -int resolve_unit(variant id, void *address) +int resolve_unit(int id, void *address) { unit *u = NULL; - if (id.i != 0) { - u = findunit(id.i); + if (id != 0) { + u = findunit(id); if (u == NULL) { *(unit **)address = NULL; return -1; @@ -765,11 +765,11 @@ int resolve_unit(variant id, void *address) return 0; } -variant read_unit_reference(gamedata *data) +int read_unit_reference(gamedata *data) { - variant var; - READ_INT(data->store, &var.i); - return var; + int id; + READ_INT(data->store, &id); + return id; } int get_level(const unit * u, skill_t id) diff --git a/src/kernel/unit.h b/src/kernel/unit.h index dede956b5..e737cea71 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -185,9 +185,9 @@ extern "C" { void make_zombie(unit * u); /* see resolve.h */ - int resolve_unit(variant data, void *address); + int resolve_unit(int id, void *address); void write_unit_reference(const struct unit *u, struct storage *store); - variant read_unit_reference(struct gamedata *data); + int read_unit_reference(struct gamedata *data); bool leave(struct unit *u, bool force); bool can_leave(struct unit *u); diff --git a/src/magic.c b/src/magic.c index f113ca4f1..cefc169e1 100644 --- a/src/magic.c +++ b/src/magic.c @@ -2262,10 +2262,10 @@ bool create_newfamiliar(unit * mage, unit * familiar) return true; } -static int resolve_familiar(variant data, void *addr) +static int resolve_familiar(int id, void *addr) { unit *familiar; - int result = resolve_unit(data, &familiar); + int result = resolve_unit(id, &familiar); if (result == 0 && familiar) { attrib *a = a_find(familiar->attribs, &at_familiarmage); if (a != NULL && a->data.v) { @@ -2346,10 +2346,10 @@ unit *has_clone(unit * mage) return NULL; } -static int resolve_clone(variant data, void *addr) +static int resolve_clone(int id, void *addr) { unit *clone; - int result = resolve_unit(data, &clone); + int result = resolve_unit(id, &clone); if (result == 0 && clone) { attrib *a = a_find(clone->attribs, &at_clonemage); if (a != NULL && a->data.v) { @@ -2372,10 +2372,10 @@ static int read_clone(attrib * a, void *owner, struct gamedata *data) } /* mages */ -static int resolve_mage(variant data, void *addr) +static int resolve_mage(int id, void *addr) { unit *mage; - int result = resolve_unit(data, &mage); + int result = resolve_unit(id, &mage); if (result == 0 && mage) { attrib *a = a_find(mage->attribs, &at_familiar); if (a != NULL && a->data.v) { diff --git a/src/spells.c b/src/spells.c index b516edd26..2fcda4821 100644 --- a/src/spells.c +++ b/src/spells.c @@ -2900,7 +2900,7 @@ static int dc_read_compat(struct attrib *a, void *target, gamedata *data) struct storage *store = data->store; region *r = NULL; unit *u; - variant var; + int id; int duration; float strength; int rx, ry; @@ -2909,8 +2909,8 @@ static int dc_read_compat(struct attrib *a, void *target, gamedata *data) UNUSED_ARG(target); READ_INT(store, &duration); READ_FLT(store, &strength); - READ_INT(store, &var.i); - u = findunit(var.i); + READ_INT(store, &id); + u = findunit(id); /* this only affects really old data. no need to change: */ READ_INT(store, &rx); @@ -2927,7 +2927,7 @@ static int dc_read_compat(struct attrib *a, void *target, gamedata *data) effect, 0); c->data.v = r; if (u == NULL) { - ur_add(var, &c->magician, resolve_unit); + ur_add(id, &c->magician, resolve_unit); } } return AT_READ_FAIL; /* we don't care for the attribute. */ diff --git a/src/triggers/changefaction.c b/src/triggers/changefaction.c index e8b6a4879..09bde22e9 100644 --- a/src/triggers/changefaction.c +++ b/src/triggers/changefaction.c @@ -83,15 +83,15 @@ static void changefaction_write(const trigger * t, struct storage *store) static int changefaction_read(trigger * t, gamedata *data) { - variant var; + int id; changefaction_data *td = (changefaction_data *)t->data.v; read_reference(&td->unit, data, read_unit_reference, resolve_unit); - var = read_faction_reference(data); - if (var.i == 0) { + id = read_faction_reference(data); + if (id == 0) { return AT_READ_FAIL; } - ur_add(var, &td->faction, resolve_faction); + ur_add(id, &td->faction, resolve_faction); return AT_READ_OK; } diff --git a/src/triggers/changerace.c b/src/triggers/changerace.c index a9f282698..ad21e1ec2 100644 --- a/src/triggers/changerace.c +++ b/src/triggers/changerace.c @@ -90,8 +90,8 @@ static int changerace_read(trigger * t, gamedata *data) { changerace_data *td = (changerace_data *)t->data.v; read_reference(&td->u, data, read_unit_reference, resolve_unit); - td->race = (const struct race *)read_race_reference(data->store).v; - td->irace = (const struct race *)read_race_reference(data->store).v; + td->race = read_race_reference(data->store); + td->irace = read_race_reference(data->store); return AT_READ_OK; } diff --git a/src/triggers/createunit.c b/src/triggers/createunit.c index 1148b1d5a..f219ab2c0 100644 --- a/src/triggers/createunit.c +++ b/src/triggers/createunit.c @@ -90,13 +90,13 @@ static void createunit_write(const trigger * t, struct storage *store) static int createunit_read(trigger * t, gamedata *data) { createunit_data *td = (createunit_data *)t->data.v; - variant var; + int id; int result = AT_READ_OK; - var = read_faction_reference(data); - if (var.i > 0) { - td->f = findfaction(var.i); + id = read_faction_reference(data); + if (id > 0) { + td->f = findfaction(id); if (!td->f) { - ur_add(var, &td->f, resolve_faction); + ur_add(id, &td->f, resolve_faction); } } else { @@ -105,7 +105,7 @@ static int createunit_read(trigger * t, gamedata *data) read_reference(&td->r, data, read_region_reference, RESOLVE_REGION(data->version)); - td->race = (const struct race *)read_race_reference(data->store).v; + td->race = read_race_reference(data->store); if (!td->race) { result = AT_READ_FAIL; } diff --git a/src/util/resolve.c b/src/util/resolve.c index 63ef5d933..63146095d 100644 --- a/src/util/resolve.c +++ b/src/util/resolve.c @@ -37,26 +37,19 @@ static unresolved *ur_list; static unresolved *ur_begin; static unresolved *ur_current; -variant read_int(struct storage *store) -{ - variant var; - READ_INT(store, &var.i); - return var; -} - int read_reference(void *address, struct gamedata * data, read_fun reader, resolve_fun resolver) { - variant var = reader(data); - int result = resolver(var, address); + int id = reader(data); + int result = resolver(id, address); if (result != 0) { - ur_add(var, address, resolver); + ur_add(id, address, resolver); } return result; } -void ur_add(variant data, void *ptrptr, resolve_fun fun) +void ur_add(int id, void *ptrptr, resolve_fun fun) { assert(ptrptr); if (ur_list == NULL) { @@ -68,7 +61,7 @@ void ur_add(variant data, void *ptrptr, resolve_fun fun) ur_current->data.v = ur_begin; ur_current = ur_begin; } - ur_current->data = data; + ur_current->data.i = id; ur_current->resolve = fun; ur_current->ptrptr = ptrptr; @@ -88,7 +81,7 @@ void resolve(void) continue; } assert(ur->ptrptr); - ur->resolve(ur->data, ur->ptrptr); + ur->resolve(ur->data.i, ur->ptrptr); ++ur; } free(ur_list); diff --git a/src/util/resolve.h b/src/util/resolve.h index 076b20508..3fe385253 100644 --- a/src/util/resolve.h +++ b/src/util/resolve.h @@ -19,7 +19,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifndef RESOLVE_H #define RESOLVE_H -#include "variant.h" struct storage; struct gamedata; @@ -27,15 +26,13 @@ struct gamedata; extern "C" { #endif - typedef int(*resolve_fun) (variant data, void *address); - typedef variant(*read_fun) (struct gamedata * data); - extern int read_reference(void *address, struct gamedata *data, + typedef int(*resolve_fun) (int id, void *address); + typedef int(*read_fun) (struct gamedata * data); + int read_reference(void *address, struct gamedata *data, read_fun reader, resolve_fun resolver); - extern void ur_add(variant data, void *address, resolve_fun fun); - extern void resolve(void); - - extern variant read_int(struct storage *store); + void ur_add(int id, void *address, resolve_fun fun); + void resolve(void); #ifdef __cplusplus } diff --git a/src/wormhole.c b/src/wormhole.c index 462f4e637..859c4460f 100644 --- a/src/wormhole.c +++ b/src/wormhole.c @@ -97,9 +97,9 @@ static void wormhole_write(const struct attrib *a, const void *owner, struct sto } /** conversion code, turn 573, 2008-05-23 */ -static int resolve_exit(variant id, void *address) +static int resolve_exit(int id, void *address) { - building *b = findbuilding(id.i); + building *b = findbuilding(id); region **rp = address; if (b) { *rp = b->region; From cda17d5379c813535aef688c245e7acc89412f03 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 21 Sep 2017 16:30:29 +0200 Subject: [PATCH 31/41] The minimum data version has actually been 332 for a long time. --- src/kernel/connection.c | 13 ------------- src/spells/borders.c | 4 +--- src/util/gamedata.h | 7 ++----- 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/src/kernel/connection.c b/src/kernel/connection.c index 43caee729..428ee5136 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -660,19 +660,6 @@ int read_borders(gamedata *data) b->id = bid; assert(bid <= nextborder); type->read(b, data); - if (data->version < NOBORDERATTRIBS_VERSION) { - attrib *a = NULL; - int result = read_attribs(data, &a, b); - if (border_convert_cb) { - border_convert_cb(b, a); - } - while (a) { - a_remove(&a, a); - } - if (result < 0) { - return result; - } - } if (!type->write) { log_warning("invalid border '%s' between '%s' and '%s'\n", zText, regionname(from, 0), regionname(to, 0)); } diff --git a/src/spells/borders.c b/src/spells/borders.c index 331e7380f..548e1532b 100644 --- a/src/spells/borders.c +++ b/src/spells/borders.c @@ -94,9 +94,7 @@ static void wall_read(connection * b, gamedata * data) read_reference(&fd->mage, data, read_unit_reference, resolve_unit); READ_INT(data->store, &fd->force); - if (data->version >= NOBORDERATTRIBS_VERSION) { - READ_INT(data->store, &fd->countdown); - } + READ_INT(data->store, &fd->countdown); fd->active = true; } diff --git a/src/util/gamedata.h b/src/util/gamedata.h index 7d355f86b..82df55cc3 100644 --- a/src/util/gamedata.h +++ b/src/util/gamedata.h @@ -5,10 +5,7 @@ #include -#define INTPAK_VERSION 329 /* in binary, ints can get packed. starting with E2/572 */ -#define NOZEROIDS_VERSION 330 /* 2008-05-16 zero is not a valid ID for anything (including factions) */ -#define NOBORDERATTRIBS_VERSION 331 /* 2008-05-17 connection::attribs has been moved to userdata */ -#define UIDHASH_VERSION 332 /* 2008-05-22 borders use the region.uid to store */ +#define UIDHASH_VERSION 332 /* 2008-05-22 = 572 borders use the region.uid to store */ #define REGIONOWNER_VERSION 333 /* 2009-05-14 regions have owners and morale */ #define ALLIANCELEADER_VERSION 333 /* alliances have a leader */ #define CURSEFLOAT_VERSION 334 /* all curse-effects are float */ @@ -43,7 +40,7 @@ #define CRYPT_VERSION 400 /* passwords are encrypted */ #define RELEASE_VERSION SKILLSORT_VERSION /* current datafile */ -#define MIN_VERSION INTPAK_VERSION /* minimal datafile we support */ +#define MIN_VERSION UIDHASH_VERSION /* minimal datafile we support */ #define MAX_VERSION RELEASE_VERSION /* change this if we can need to read the future datafile, and we can do so */ #define STREAM_VERSION 2 /* internal encoding of binary files */ From 59169f3eb1f4abb23235e37ef4ff34b9896cb472 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 21 Sep 2017 17:26:37 +0200 Subject: [PATCH 32/41] simplicate --- src/building_action.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/building_action.c b/src/building_action.c index f72af4412..55a1c0b6a 100644 --- a/src/building_action.c +++ b/src/building_action.c @@ -106,8 +106,7 @@ static int lc_read(struct attrib *a, void *owner, gamedata *data) building *b = (building *)owner; int result = 0; if (data->version < ATTRIBOWNER_VERSION) { - result = read_reference(&b, data, read_building_reference, resolve_building); - assert(b == owner); + READ_INT(data->store, NULL); } READ_TOK(store, name, sizeof(name)); if (strcmp(name, "tunnel_action") == 0) { From 902e2126c9ba69dc53e2fcb3d011cf207abf4b08 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 21 Sep 2017 16:26:53 +0200 Subject: [PATCH 33/41] WIP: change the resolve.h API --- src/attributes/attributes.c | 2 +- src/attributes/follow.c | 2 +- src/attributes/hate.c | 4 +-- src/attributes/targetregion.c | 5 ++- src/building_action.c | 3 +- src/helpers.c | 5 +-- src/kernel/building.c | 33 +++++++++++--------- src/kernel/building.h | 6 ++-- src/kernel/curse.c | 6 ++-- src/kernel/faction.c | 34 +++++++++++---------- src/kernel/faction.h | 7 +++-- src/kernel/group.c | 14 +++------ src/kernel/plane.c | 34 --------------------- src/kernel/plane.h | 2 -- src/kernel/region.c | 57 ++++++++++++++++++----------------- src/kernel/region.h | 13 ++++---- src/kernel/save.c | 26 ++++++++-------- src/kernel/unit.c | 31 ++++++++++--------- src/kernel/unit.h | 8 ++--- src/magic.c | 45 +++++++++------------------ src/modules/xmas.c | 9 ++---- src/spells.c | 7 ++--- src/spells/borders.c | 2 +- src/triggers/changefaction.c | 9 ++---- src/triggers/changerace.c | 2 +- src/triggers/clonedied.c | 4 +-- src/triggers/createcurse.c | 4 +-- src/triggers/createunit.c | 14 +++------ src/triggers/gate.c | 13 +++----- src/triggers/giveitem.c | 5 +-- src/triggers/killunit.c | 4 +-- src/triggers/shock.c | 7 ++--- src/util/resolve.c | 38 +++++++++++------------ src/util/resolve.h | 8 ++--- src/wormhole.c | 30 ++++++++---------- 35 files changed, 203 insertions(+), 290 deletions(-) diff --git a/src/attributes/attributes.c b/src/attributes/attributes.c index 610bea684..f003c2cde 100644 --- a/src/attributes/attributes.c +++ b/src/attributes/attributes.c @@ -96,7 +96,7 @@ static int obs_read(struct attrib *a, void *owner, struct gamedata *data) { obs_data *od = (obs_data *)a->data.v; - read_reference(&od->f, data, read_faction_reference, resolve_faction); + read_faction_reference(data, &od->f, NULL); READ_INT(data->store, &od->skill); READ_INT(data->store, &od->timer); return AT_READ_OK; diff --git a/src/attributes/follow.c b/src/attributes/follow.c index d68fcaebd..e0741646b 100644 --- a/src/attributes/follow.c +++ b/src/attributes/follow.c @@ -30,7 +30,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. static int read_follow(attrib * a, void *owner, gamedata *data) { - read_unit_reference(data); /* skip it */ + READ_INT(data->store, NULL); /* skip it */ return AT_READ_FAIL; } diff --git a/src/attributes/hate.c b/src/attributes/hate.c index 17155fc71..7cba12514 100644 --- a/src/attributes/hate.c +++ b/src/attributes/hate.c @@ -45,9 +45,7 @@ write_hate(const attrib * a, const void *owner, struct storage *store) static int read_hate(attrib * a, void *owner, gamedata *data) { - int result = read_reference(&a->data.v, data, read_unit_reference, - resolve_unit); - if (result == 0 && !a->data.v) { + if (read_unit_reference(data, (unit **)&a->data.v, NULL) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; diff --git a/src/attributes/targetregion.c b/src/attributes/targetregion.c index f61214dfc..f9ab3a798 100644 --- a/src/attributes/targetregion.c +++ b/src/attributes/targetregion.c @@ -36,10 +36,9 @@ write_targetregion(const attrib * a, const void *owner, struct storage *store) static int read_targetregion(attrib * a, void *owner, gamedata *data) { - int result = read_reference(&a->data.v, data, read_region_reference, - RESOLVE_REGION(data->version)); - if (result == 0 && !a->data.v) + if (read_region_reference(data, &a->data.v, NULL) <= 0) { return AT_READ_FAIL; + } return AT_READ_OK; } diff --git a/src/building_action.c b/src/building_action.c index 55a1c0b6a..28cd55a48 100644 --- a/src/building_action.c +++ b/src/building_action.c @@ -86,8 +86,7 @@ static void lc_done(struct attrib *a) free(data); } -static void -lc_write(const struct attrib *a, const void *owner, struct storage *store) +static void lc_write(const struct attrib *a, const void *owner, struct storage *store) { building_action *data = (building_action *)a->data.v; const char *fname = data->fname; diff --git a/src/helpers.c b/src/helpers.c index 7591dba9f..5f73ac542 100644 --- a/src/helpers.c +++ b/src/helpers.c @@ -20,6 +20,7 @@ without prior permission by the authors of Eressea. #include #include #include +#include #include #include #include @@ -290,10 +291,10 @@ use_item_lua(unit *u, const item_type *itype, int amount, struct order *ord) } /* compat code for old data files */ -static int caldera_read(trigger *t, struct gamedata *data) +static int caldera_read(trigger *t, gamedata *data) { UNUSED_ARG(t); - read_building_reference(data); + READ_INT(data->store, NULL); return AT_READ_FAIL; } diff --git a/src/kernel/building.c b/src/kernel/building.c index 7c4453f6a..90adc5300 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -322,25 +322,28 @@ void write_building_reference(const struct building *b, struct storage *store) WRITE_INT(store, (b && b->region) ? b->no : 0); } -int resolve_building(int id, void *address) +#define RESOLVE_BUILDING (TYP_BUILDING << 24) + +void resolve_building(building *b) { - int result = 0; - building *b = NULL; - if (id != 0) { - b = findbuilding(id); - if (b == NULL) { - result = -1; - } - } - *(building **)address = b; - return result; + resolve(RESOLVE_BUILDING | b->no, b); } -int read_building_reference(gamedata * data) +int read_building_reference(gamedata * data, void **bp, resolve_fun fun) { - int result; - READ_INT(data->store, &result); - return result; + int id; + READ_INT(data->store, &id); + if (id > 0) { + *bp = findbuilding(id); + if (*bp == NULL) { + *bp = NULL; + ur_add(RESOLVE_BUILDING | id, bp, fun); + } + } + else { + *bp = NULL; + } + return id; } building *new_building(const struct building_type * btype, region * r, diff --git a/src/kernel/building.h b/src/kernel/building.h index 59af83bbe..c828543bf 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -20,7 +20,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define H_KRNL_BUILDING #include -#include +#include #include #include @@ -152,10 +152,10 @@ extern "C" { #include "build.h" #define NOBUILDING NULL - int resolve_building(int id, void *address); + void resolve_building(building *b); void write_building_reference(const struct building *b, struct storage *store); - int read_building_reference(struct gamedata *data); + int read_building_reference(struct gamedata * data, void **bp, resolve_fun fun); struct building *findbuilding(int n); diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 1364fb9a1..720be386e 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -191,7 +191,7 @@ int curse_read(attrib * a, void *owner, gamedata *data) READ_INT(store, &c->duration); READ_FLT(store, &flt); c->vigour = flt; - ur = read_reference(&c->magician, data, read_unit_reference, resolve_unit); + ur = read_unit_reference(data, &c->magician, NULL); if (data->version < CURSEFLOAT_VERSION) { READ_INT(store, &n); c->effect = (float)n; @@ -226,9 +226,7 @@ int curse_read(attrib * a, void *owner, gamedata *data) READ_INT(store, &c->data.i); } if (c->type->typ == CURSETYP_REGION) { - int rr = - read_reference(&c->data.v, data, read_region_reference, - RESOLVE_REGION(data->version)); + int rr = read_region_reference(data, &c->data.v, NULL); if (ur == 0 && rr == 0 && !c->data.v) { return AT_READ_FAIL; } diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 3188d2299..60c1dd87e 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -203,21 +203,6 @@ const char *factionname(const faction * f) return ibuf; } -int resolve_faction(int id, void *address) -{ - int result = 0; - faction *f = NULL; - if (id != 0) { - f = findfaction(id); - if (f == NULL) { - result = -1; - } - } - assert(address); - *(faction **)address = f; - return result; -} - bool faction_id_is_unused(int id) { return findfaction(id) == NULL; @@ -332,10 +317,27 @@ bool checkpasswd(const faction * f, const char *passwd) return true; } -int read_faction_reference(gamedata * data) +#define RESOLVE_FACTION (TYP_FACTION << 24) + +void resolve_faction(faction *f) +{ + resolve(RESOLVE_FACTION | f->no, f); +} + +int read_faction_reference(gamedata * data, faction **fp, resolve_fun fun) { int id; READ_INT(data->store, &id); + if (id > 0) { + *fp = findfaction(id); + if (*fp == NULL) { + *fp = NULL; + ur_add(RESOLVE_FACTION | id, fp, fun); + } + } + else { + *fp = NULL; + } return id; } diff --git a/src/kernel/faction.h b/src/kernel/faction.h index 62b3634b2..e2272c396 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -21,7 +21,10 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "skill.h" #include "types.h" + +#include #include + #include #ifdef __cplusplus @@ -126,8 +129,8 @@ extern "C" { void write_faction_reference(const struct faction *f, struct storage *store); - int read_faction_reference(struct gamedata *data); - int resolve_faction(int id, void *addr); + int read_faction_reference(struct gamedata *data, struct faction **fp, resolve_fun fun); + void resolve_faction(struct faction *f); void renumber_faction(faction * f, int no); void free_factions(void); diff --git a/src/kernel/group.c b/src/kernel/group.c index 61c311c89..650679b3f 100755 --- a/src/kernel/group.c +++ b/src/kernel/group.c @@ -238,16 +238,12 @@ void read_groups(gamedata *data, faction * f) g = new_group(f, buf, gid); pa = &g->allies; for (;;) { - ally *a; - int fid; - - fid = read_faction_reference(data); - if (fid <= 0) + ally *al; + al = ally_add(pa, NULL); + if (read_faction_reference(data, &al->faction, NULL) <= 0) { break; - a = ally_add(pa, findfaction(fid)); - READ_INT(store, &a->status); - if (!a->faction) - ur_add(fid, &a->faction, resolve_faction); + } + READ_INT(store, &al->status); } read_attribs(data, &g->attribs, g); } diff --git a/src/kernel/plane.c b/src/kernel/plane.c index ebf6c64ad..0dd6793f4 100644 --- a/src/kernel/plane.c +++ b/src/kernel/plane.c @@ -258,40 +258,6 @@ unsigned char index) return (rel + ursprung_y(f, pl, NULL) + plane_center_y(pl)); } -static int resolve_plane(int id, void *addr) -{ - int result = 0; - plane *pl = NULL; - if (id != 0) { - pl = getplanebyid(id); - if (pl == NULL) { - result = -1; - } - } - *(plane **)addr = pl; - return result; -} - -void write_plane_reference(const plane * u, struct storage *store) -{ - WRITE_INT(store, u ? (u->id) : 0); -} - -int read_plane_reference(plane ** pp, struct storage *store) -{ - int id; - READ_INT(store, &id); - if (id == 0) { - *pp = NULL; - return AT_READ_FAIL; - } - *pp = getplanebyid(id); - if (*pp == NULL) { - ur_add(id, pp, resolve_plane); - } - return AT_READ_OK; -} - void free_plane(plane *pl) { free(pl->name); free(pl); diff --git a/src/kernel/plane.h b/src/kernel/plane.h index d06495f34..5b1c71644 100644 --- a/src/kernel/plane.h +++ b/src/kernel/plane.h @@ -69,8 +69,6 @@ extern "C" { struct plane *get_homeplane(void); int rel_to_abs(const struct plane *pl, const struct faction *f, int rel, unsigned char index); - void write_plane_reference(const plane * p, struct storage *store); - int read_plane_reference(plane ** pp, struct storage *store); int plane_width(const plane * pl); int plane_height(const plane * pl); void adjust_coordinates(const struct faction *f, int *x, int *y, const struct plane *pl); diff --git a/src/kernel/region.c b/src/kernel/region.c index 3ffd0660a..ee0eaa781 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -1255,50 +1255,53 @@ int production(const region * r) return p; } -int resolve_region_coor(int id, void *address) +void * resolve_region_coor(int id, void **address) { int x = (id >> 16); int y = id & 0xFFFF; - region *r = findregion(x, y); - if (r) { - *(region **)address = r; - return 0; - } - *(region **)address = NULL; - return -1; + return *(region **)address = findregion(x, y); } -int resolve_region_id(int id, void *address) +#define RESOLVE_REGION_ID (TYP_REGION << 24) +#define RESOLVE_REGION_XY ((TYP_REGION|0x10) << 24) + +void resolve_region(region *r) { - region *r = NULL; - if (id != 0) { - r = findregionbyid(id); - if (r == NULL) { - *(region **)address = NULL; - return -1; - } - } - *(region **)address = r; - return 0; + short x = (short)r->x; + short y = (short)r->y; + int id = x << 16 | (y & 0xFFFF); + + resolve(RESOLVE_REGION_XY | id, r); + resolve(RESOLVE_REGION_ID | r->uid, r); } -int read_region_reference(gamedata *data) +int read_region_reference(gamedata * data, void **rp, resolve_fun fun) { struct storage * store = data->store; - int result; - if (data->version < UIDHASH_VERSION) { + int id = 0; + + if (data->version >= UIDHASH_VERSION) { + READ_INT(store, &id); + *rp = findregionbyid(id); + if (*rp == NULL) { + ur_add(RESOLVE_REGION_ID | id, rp, fun); + } + } + else { int n; short x, y; READ_INT(store, &n); x = (short)n; READ_INT(store, &n); y = (short)n; - result = x << 16 | (y & 0xFFFF); + *rp = findregion(x, y); + if (*rp == NULL) { + id = x << 16 | (y & 0xFFFF); + ur_add(RESOLVE_REGION_XY | id, rp, resolve_region_coor); + } + } - else { - READ_INT(store, &result); - } - return result; + return id; } void write_region_reference(const region * r, struct storage *store) diff --git a/src/kernel/region.h b/src/kernel/region.h index ce5d37fa3..1f2817415 100644 --- a/src/kernel/region.h +++ b/src/kernel/region.h @@ -19,11 +19,14 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifndef H_KRNL_REGION #define H_KRNL_REGION -#include -#include +#include + #include "types.h" #include "direction.h" +#include +#include + #define MAXLUXURIES 16 /* there must be no more than MAXLUXURIES kinds of luxury goods in any game */ #define MAXREGIONS 524287 /* must be prime for hashing. 262139 was a little small */ #define MAXTREES 100 * 1000 * 1000 /* bug 2360: some players are crazy */ @@ -257,10 +260,8 @@ extern "C" { void region_set_morale(region * r, int morale, int turn); void write_region_reference(const struct region *r, struct storage *store); - int read_region_reference(struct gamedata *data); - int resolve_region_coor(int id, void *address); - int resolve_region_id(int id, void *address); -#define RESOLVE_REGION(version) ((versionflags); } if (data->version >= ALLIANCELEADER_VERSION) { - read_reference(&al->_leader, data, read_faction_reference, - resolve_faction); + read_faction_reference(data, &al->_leader, NULL); READ_INT(store, &id); } else { @@ -458,9 +457,10 @@ void read_planes(gamedata *data) { else { /* WATCHERS - eliminated in February 2016, ca. turn 966 */ if (data->version < NOWATCH_VERSION) { - int fno = read_faction_reference(data); + int fno; + READ_INT(data->store, &fno); while (fno) { - fno = read_faction_reference(data); + READ_INT(data->store, &fno); } } } @@ -539,9 +539,7 @@ static void read_owner(gamedata *data, region_owner ** powner) owner->flags = 0; } if (data->version >= OWNER_3_VERSION) { - int id; - READ_INT(data->store, &id); - owner->last_owner = id ? findfaction(id) : NULL; + read_faction_reference(data, &owner->last_owner, NULL); } else if (data->version >= OWNER_2_VERSION) { int id; @@ -554,7 +552,7 @@ static void read_owner(gamedata *data, region_owner ** powner) else { owner->last_owner = NULL; } - read_reference(owner, data, &read_faction_reference, &resolve_owner); + read_faction_reference(data, &owner->owner, NULL); *powner = owner; } else { @@ -817,6 +815,7 @@ unit *read_unit(gamedata *data) u->hp = u->number; } read_attribs(data, &u->attribs, u); + resolve_unit(u); return u; } @@ -1081,6 +1080,7 @@ region *read_region(gamedata *data) READ_INT(store, &x); READ_INT(store, &y); r = readregion(data, x, y); + resolve_region(r); return r; } @@ -1170,7 +1170,7 @@ static ally **addally(const faction * f, ally ** sfp, int aid, int state) sf = ally_add(sfp, af); if (!sf->faction) { - ur_add(aid, &sf->faction, resolve_faction); + ur_add(aid, &sf->faction, NULL); } sf->status = state & HELP_ALL; @@ -1402,6 +1402,7 @@ faction *read_faction(gamedata * data) if (data->version >= REGIONOWNER_VERSION) { read_spellbook(FactionSpells() ? &f->spellbook : 0, data, get_spell_level_faction, (void *)f); } + resolve_faction(f); return f; } @@ -1573,7 +1574,8 @@ struct building *read_building(gamedata *data) { log_error("building too big: %s (%s size %d of %d), fixing.", buildingname(b), b->type->_name, b->size, b->type->maxsize); b->size = b->type->maxsize; } - return b; + resolve_building(b); + return b; } void write_ship(gamedata *data, const ship *sh) @@ -1816,10 +1818,6 @@ int read_game(gamedata *data) } read_borders(data); - /* Unaufgeloeste Zeiger initialisieren */ - log_debug("fixing unresolved references."); - resolve(); - log_debug("updating area information for lighthouses."); for (r = regions; r; r = r->next) { if (r->flags & RF_LIGHTHOUSE) { diff --git a/src/kernel/unit.c b/src/kernel/unit.c index 8d62b98c3..b57b26c34 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -648,9 +648,7 @@ void a_writesiege(const attrib * a, const void *owner, struct storage *store) int a_readsiege(attrib * a, void *owner, gamedata *data) { - int result = read_reference(&a->data.v, data, read_building_reference, - resolve_building); - if (result == 0 && !a->data.v) { + if (read_building_reference(data, &a->data.v, NULL) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; @@ -751,24 +749,27 @@ void write_unit_reference(const unit * u, struct storage *store) WRITE_INT(store, (u && u->region) ? u->no : 0); } -int resolve_unit(int id, void *address) +#define RESOLVE_UNIT (TYP_UNIT << 24) + +void resolve_unit(unit *u) { - unit *u = NULL; - if (id != 0) { - u = findunit(id); - if (u == NULL) { - *(unit **)address = NULL; - return -1; - } - } - *(unit **)address = u; - return 0; + resolve(RESOLVE_UNIT | u->no, u); } -int read_unit_reference(gamedata *data) +int read_unit_reference(gamedata * data, unit **up, resolve_fun fun) { int id; READ_INT(data->store, &id); + if (id > 0) { + *up = findunit(id); + if (*up == NULL) { + *up = NULL; + ur_add(RESOLVE_UNIT | id, up, fun); + } + } + else { + *up = NULL; + } return id; } diff --git a/src/kernel/unit.h b/src/kernel/unit.h index e737cea71..dde183eb4 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -19,7 +19,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #ifndef H_KRNL_UNIT_H #define H_KRNL_UNIT_H -#include +#include #include "types.h" #include "skills.h" #include @@ -182,12 +182,12 @@ extern "C" { #define GIFT_FRIENDS 1<<1 #define GIFT_PEASANTS 1<<2 int gift_items(struct unit *u, int flags); - void make_zombie(unit * u); + void make_zombie(struct unit * u); /* see resolve.h */ - int resolve_unit(int id, void *address); + void resolve_unit(struct unit *u); void write_unit_reference(const struct unit *u, struct storage *store); - int read_unit_reference(struct gamedata *data); + int read_unit_reference(struct gamedata * data, struct unit **up, resolve_fun fun); bool leave(struct unit *u, bool force); bool can_leave(struct unit *u); diff --git a/src/magic.c b/src/magic.c index cefc169e1..d41ce71e4 100644 --- a/src/magic.c +++ b/src/magic.c @@ -2262,26 +2262,21 @@ bool create_newfamiliar(unit * mage, unit * familiar) return true; } -static int resolve_familiar(int id, void *addr) -{ - unit *familiar; - int result = resolve_unit(id, &familiar); - if (result == 0 && familiar) { +static void * resolve_familiar(int id, void *data) { + if (data) { + unit *familiar = (unit *)data; attrib *a = a_find(familiar->attribs, &at_familiarmage); if (a != NULL && a->data.v) { unit *mage = (unit *)a->data.v; set_familiar(mage, familiar); } } - *(unit **)addr = familiar; - return result; + return data; } static int read_familiar(attrib * a, void *owner, struct gamedata *data) { - int result = - read_reference(&a->data.v, data, read_unit_reference, resolve_familiar); - if (result == 0 && a->data.v == NULL) { + if (read_unit_reference(data, (unit **)&a->data.v, resolve_familiar) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; @@ -2346,52 +2341,42 @@ unit *has_clone(unit * mage) return NULL; } -static int resolve_clone(int id, void *addr) -{ - unit *clone; - int result = resolve_unit(id, &clone); - if (result == 0 && clone) { +static void * resolve_clone(int id, void *data) { + if (data) { + unit *clone = (unit *)data; attrib *a = a_find(clone->attribs, &at_clonemage); if (a != NULL && a->data.v) { unit *mage = (unit *)a->data.v; set_clone(mage, clone); } } - *(unit **)addr = clone; - return result; + return data; } static int read_clone(attrib * a, void *owner, struct gamedata *data) { - int result = - read_reference(&a->data.v, data, read_unit_reference, resolve_clone); - if (result == 0 && a->data.v == NULL) { + if (read_unit_reference(data, (unit **)&a->data.v, resolve_clone) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; } /* mages */ -static int resolve_mage(int id, void *addr) -{ - unit *mage; - int result = resolve_unit(id, &mage); - if (result == 0 && mage) { +static void * resolve_mage(int id, void *data) { + if (data) { + unit *mage = (unit *)data; attrib *a = a_find(mage->attribs, &at_familiar); if (a != NULL && a->data.v) { unit *familiar = (unit *)a->data.v; set_familiar(mage, familiar); } } - *(unit **)addr = mage; - return result; + return data; } static int read_magician(attrib * a, void *owner, struct gamedata *data) { - int result = - read_reference(&a->data.v, data, read_unit_reference, resolve_mage); - if (result == 0 && a->data.v == NULL) { + if (read_unit_reference(data, (unit **)&a->data.v, resolve_mage) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; diff --git a/src/modules/xmas.c b/src/modules/xmas.c index 4b90af68e..315a52f07 100644 --- a/src/modules/xmas.c +++ b/src/modules/xmas.c @@ -1,4 +1,4 @@ -/* +/* +-------------------+ Christian Schlittchen | | Enno Rehling | Eressea PBEM host | Katja Zedel @@ -14,7 +14,7 @@ #include #include "xmas.h" -/* kernel includes */ + /* kernel includes */ #include #include #include @@ -50,10 +50,7 @@ static void xmasgate_write(const trigger * t, struct storage *store) static int xmasgate_read(trigger * t, struct gamedata *data) { - int bc = - read_reference(&t->data.v, data, read_building_reference, - resolve_building); - if (bc == 0 && !t->data.v) { + if (read_building_reference(data, &t->data.v, NULL) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; diff --git a/src/spells.c b/src/spells.c index 2fcda4821..52acc54ed 100644 --- a/src/spells.c +++ b/src/spells.c @@ -2922,12 +2922,11 @@ static int dc_read_compat(struct attrib *a, void *target, gamedata *data) curse *c; effect = strength; - c = - create_curse(u, &r->attribs, &ct_deathcloud, strength * 2, duration, - effect, 0); + c = create_curse(u, &r->attribs, &ct_deathcloud, strength * 2, duration, + effect, 0); c->data.v = r; if (u == NULL) { - ur_add(id, &c->magician, resolve_unit); + ur_add(id, &c->magician, NULL); } } return AT_READ_FAIL; /* we don't care for the attribute. */ diff --git a/src/spells/borders.c b/src/spells/borders.c index 548e1532b..d19470230 100644 --- a/src/spells/borders.c +++ b/src/spells/borders.c @@ -92,7 +92,7 @@ static void wall_read(connection * b, gamedata * data) static wall_data dummy; wall_data *fd = b->data.v ? (wall_data *)b->data.v : &dummy; - read_reference(&fd->mage, data, read_unit_reference, resolve_unit); + read_unit_reference(data, &fd->mage, NULL); READ_INT(data->store, &fd->force); READ_INT(data->store, &fd->countdown); fd->active = true; diff --git a/src/triggers/changefaction.c b/src/triggers/changefaction.c index 09bde22e9..fb5805618 100644 --- a/src/triggers/changefaction.c +++ b/src/triggers/changefaction.c @@ -83,15 +83,10 @@ static void changefaction_write(const trigger * t, struct storage *store) static int changefaction_read(trigger * t, gamedata *data) { - int id; changefaction_data *td = (changefaction_data *)t->data.v; - read_reference(&td->unit, data, read_unit_reference, resolve_unit); - id = read_faction_reference(data); - if (id == 0) { - return AT_READ_FAIL; - } - ur_add(id, &td->faction, resolve_faction); + read_unit_reference(data, &td->unit, NULL); + read_faction_reference(data, &td->faction, NULL); return AT_READ_OK; } diff --git a/src/triggers/changerace.c b/src/triggers/changerace.c index ad21e1ec2..1a065fce2 100644 --- a/src/triggers/changerace.c +++ b/src/triggers/changerace.c @@ -89,7 +89,7 @@ static void changerace_write(const trigger * t, struct storage *store) static int changerace_read(trigger * t, gamedata *data) { changerace_data *td = (changerace_data *)t->data.v; - read_reference(&td->u, data, read_unit_reference, resolve_unit); + read_unit_reference(data, &td->u, NULL); td->race = read_race_reference(data->store); td->irace = read_race_reference(data->store); return AT_READ_OK; diff --git a/src/triggers/clonedied.c b/src/triggers/clonedied.c index f3d1fc00b..edcf756f9 100644 --- a/src/triggers/clonedied.c +++ b/src/triggers/clonedied.c @@ -70,9 +70,7 @@ static void clonedied_write(const trigger * t, struct storage *store) static int clonedied_read(trigger * t, gamedata *data) { - int result = - read_reference(&t->data.v, data, read_unit_reference, resolve_unit); - if (result == 0 && t->data.v == NULL) { + if (read_unit_reference(data, (unit **)&t->data.v, NULL) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; diff --git a/src/triggers/createcurse.c b/src/triggers/createcurse.c index 3eb0891ca..2551f7fb5 100644 --- a/src/triggers/createcurse.c +++ b/src/triggers/createcurse.c @@ -98,8 +98,8 @@ static int createcurse_read(trigger * t, gamedata *data) char zText[128]; float flt; - read_reference(&td->mage, data, read_unit_reference, resolve_unit); - read_reference(&td->target, data, read_unit_reference, resolve_unit); + read_unit_reference(data, &td->mage, NULL); + read_unit_reference(data, &td->target, NULL); READ_TOK(data->store, zText, sizeof(zText)); td->type = ct_find(zText); diff --git a/src/triggers/createunit.c b/src/triggers/createunit.c index f219ab2c0..951887860 100644 --- a/src/triggers/createunit.c +++ b/src/triggers/createunit.c @@ -92,19 +92,13 @@ static int createunit_read(trigger * t, gamedata *data) createunit_data *td = (createunit_data *)t->data.v; int id; int result = AT_READ_OK; - id = read_faction_reference(data); - if (id > 0) { - td->f = findfaction(id); - if (!td->f) { - ur_add(id, &td->f, resolve_faction); - } - } - else { + + id = read_faction_reference(data, &td->f, NULL); + if (id <= 0) { result = AT_READ_FAIL; } - read_reference(&td->r, data, read_region_reference, - RESOLVE_REGION(data->version)); + read_region_reference(data, &td->r, NULL); td->race = read_race_reference(data->store); if (!td->race) { result = AT_READ_FAIL; diff --git a/src/triggers/gate.c b/src/triggers/gate.c index c70163a14..a66e0365e 100644 --- a/src/triggers/gate.c +++ b/src/triggers/gate.c @@ -74,16 +74,11 @@ static void gate_write(const trigger * t, struct storage *store) static int gate_read(trigger * t, gamedata *data) { gate_data *gd = (gate_data *)t->data.v; + int bc = read_building_reference(data, &gd->gate, NULL); + int rc = read_region_reference(data, &gd->target, NULL); - int bc = - read_reference(&gd->gate, data, read_building_reference, resolve_building); - int rc = - read_reference(&gd->target, data, read_region_reference, - RESOLVE_REGION(data->version)); - - if (bc == 0 && rc == 0) { - if (!gd->gate || !gd->target) - return AT_READ_FAIL; + if (bc <= 0 && rc <= 0) { + return AT_READ_FAIL; } return AT_READ_OK; } diff --git a/src/triggers/giveitem.c b/src/triggers/giveitem.c index 9bc2c56e1..0442d9295 100644 --- a/src/triggers/giveitem.c +++ b/src/triggers/giveitem.c @@ -86,15 +86,16 @@ static int giveitem_read(trigger * t, gamedata *data) { giveitem_data *td = (giveitem_data *)t->data.v; char zText[128]; + int result; - int result = read_reference(&td->u, data, read_unit_reference, resolve_unit); + result = read_unit_reference(data, &td->u, NULL); READ_INT(data->store, &td->number); READ_TOK(data->store, zText, sizeof(zText)); td->itype = it_find(zText); assert(td->itype); - if (result == 0 && td->u == NULL) { + if (result == 0) { return AT_READ_FAIL; } return AT_READ_OK; diff --git a/src/triggers/killunit.c b/src/triggers/killunit.c index 3e6c9defe..f6613dcb7 100644 --- a/src/triggers/killunit.c +++ b/src/triggers/killunit.c @@ -60,9 +60,7 @@ static void killunit_write(const trigger * t, struct storage *store) static int killunit_read(trigger * t, gamedata *data) { - int result = read_reference(&t->data.v, data, read_unit_reference, - resolve_unit); - if (result == 0 && t->data.v == NULL) { + if (read_unit_reference(data, (unit **)&t->data.v, NULL)) { return AT_READ_FAIL; } return AT_READ_OK; diff --git a/src/triggers/shock.c b/src/triggers/shock.c index 31424e979..ca4ad67df 100644 --- a/src/triggers/shock.c +++ b/src/triggers/shock.c @@ -125,11 +125,8 @@ static void shock_write(const trigger * t, struct storage *store) } } -static int shock_read(trigger * t, gamedata *data) -{ - int result = - read_reference(&t->data.v, data, read_unit_reference, resolve_unit); - if (result == 0 && t->data.v == NULL) { +static int shock_read(trigger * t, gamedata *data) { + if (read_unit_reference(data, (unit **)&t->data.v, NULL) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; diff --git a/src/util/resolve.c b/src/util/resolve.c index 63146095d..577afb98f 100644 --- a/src/util/resolve.c +++ b/src/util/resolve.c @@ -24,7 +24,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "variant.h" typedef struct unresolved { - void *ptrptr; + void **addr; /* address to pass to the resolve-function */ variant data; /* information on how to resolve the missing object */ @@ -37,21 +37,10 @@ static unresolved *ur_list; static unresolved *ur_begin; static unresolved *ur_current; -int -read_reference(void *address, struct gamedata * data, read_fun reader, - resolve_fun resolver) +void ur_add(int id, void **addr, resolve_fun fun) { - int id = reader(data); - int result = resolver(id, address); - if (result != 0) { - ur_add(id, address, resolver); - } - return result; -} - -void ur_add(int id, void *ptrptr, resolve_fun fun) -{ - assert(ptrptr); + assert(addr); + assert(!*addr); if (ur_list == NULL) { ur_list = malloc(BLOCKSIZE * sizeof(unresolved)); ur_begin = ur_current = ur_list; @@ -63,25 +52,32 @@ void ur_add(int id, void *ptrptr, resolve_fun fun) } ur_current->data.i = id; ur_current->resolve = fun; - ur_current->ptrptr = ptrptr; + ur_current->addr = addr; ++ur_current; - ur_current->resolve = NULL; + ur_current->addr = NULL; ur_current->data.v = NULL; } -void resolve(void) +void resolve(int id, void *data) { unresolved *ur = ur_list; + /* TODO: hella slow! hashing is better */ while (ur) { - if (ur->resolve == NULL) { + if (ur->addr == NULL) { ur = ur->data.v; free(ur_list); ur_list = ur; continue; } - assert(ur->ptrptr); - ur->resolve(ur->data.i, ur->ptrptr); + if (id == ur->data.i) { + if (ur->resolve) { + *ur->addr = ur->resolve(id, data); + } + else { + *ur->addr = data; + } + } ++ur; } free(ur_list); diff --git a/src/util/resolve.h b/src/util/resolve.h index 3fe385253..ef33fd67d 100644 --- a/src/util/resolve.h +++ b/src/util/resolve.h @@ -26,13 +26,11 @@ struct gamedata; extern "C" { #endif - typedef int(*resolve_fun) (int id, void *address); + typedef void *(*resolve_fun) (int id, void *data); typedef int(*read_fun) (struct gamedata * data); - int read_reference(void *address, struct gamedata *data, - read_fun reader, resolve_fun resolver); - void ur_add(int id, void *address, resolve_fun fun); - void resolve(void); + void ur_add(int id, void **addr, resolve_fun fun); + void resolve(int id, void *data); #ifdef __cplusplus } diff --git a/src/wormhole.c b/src/wormhole.c index 859c4460f..030c33c06 100644 --- a/src/wormhole.c +++ b/src/wormhole.c @@ -97,35 +97,29 @@ static void wormhole_write(const struct attrib *a, const void *owner, struct sto } /** conversion code, turn 573, 2008-05-23 */ -static int resolve_exit(int id, void *address) +static void * resolve_exit(int id, void *data) { - building *b = findbuilding(id); - region **rp = address; + building *b = (building *)data; if (b) { - *rp = b->region; - return 0; + return b->region; } - *rp = NULL; - return -1; + return NULL; } static int wormhole_read(struct attrib *a, void *owner, struct gamedata *data) { - storage *store = data->store; - resolve_fun resolver = (data->version < UIDHASH_VERSION) - ? resolve_exit : resolve_region_id; - read_fun reader = (data->version < UIDHASH_VERSION) - ? read_building_reference : read_region_reference; + int id; if (data->version < ATTRIBOWNER_VERSION) { - READ_INT(store, NULL); + READ_INT(data->store, NULL); } - if (read_reference(&a->data.v, data, reader, resolver) == 0) { - if (!a->data.v) { - return AT_READ_FAIL; - } + if (data->version < UIDHASH_VERSION) { + id = read_building_reference(data, &a->data.v, resolve_exit); } - return AT_READ_OK; + else { + id = read_region_reference(data, &a->data.v, NULL); + } + return (id <= 0) ? AT_READ_FAIL : AT_READ_OK; } static attrib_type at_wormhole = { From afe45329665bf60749e15318f049d81f14195a1b Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 21 Sep 2017 16:35:18 +0200 Subject: [PATCH 34/41] remove code for unsupported old region references --- src/kernel/connection.c | 22 +++++----------------- src/kernel/region.c | 41 ++++++----------------------------------- src/wormhole.c | 17 +---------------- 3 files changed, 12 insertions(+), 68 deletions(-) diff --git a/src/kernel/connection.c b/src/kernel/connection.c index 428ee5136..6ae173271 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -606,7 +606,7 @@ int read_borders(gamedata *data) { struct storage *store = data->store; for (;;) { - int bid = 0; + int fid, tid, bid; char zText[32]; region *from, *to; border_type *type; @@ -621,22 +621,10 @@ int read_borders(gamedata *data) } READ_INT(store, &bid); - if (data->version < UIDHASH_VERSION) { - int fx, fy, tx, ty; - READ_INT(store, &fx); - READ_INT(store, &fy); - READ_INT(store, &tx); - READ_INT(store, &ty); - from = findregion(fx, fy); - to = findregion(tx, ty); - } - else { - int fid, tid; - READ_INT(store, &fid); - READ_INT(store, &tid); - from = findregionbyid(fid); - to = findregionbyid(tid); - } + READ_INT(store, &fid); + READ_INT(store, &tid); + from = findregionbyid(fid); + to = findregionbyid(tid); if (!to || !from) { log_error("%s connection %d has missing regions", zText, bid); if (type->read) { diff --git a/src/kernel/region.c b/src/kernel/region.c index ee0eaa781..fa2a68464 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -1255,24 +1255,11 @@ int production(const region * r) return p; } -void * resolve_region_coor(int id, void **address) -{ - int x = (id >> 16); - int y = id & 0xFFFF; - return *(region **)address = findregion(x, y); -} - -#define RESOLVE_REGION_ID (TYP_REGION << 24) -#define RESOLVE_REGION_XY ((TYP_REGION|0x10) << 24) +#define RESOLVE_REGION (TYP_REGION << 24) void resolve_region(region *r) { - short x = (short)r->x; - short y = (short)r->y; - int id = x << 16 | (y & 0xFFFF); - - resolve(RESOLVE_REGION_XY | id, r); - resolve(RESOLVE_REGION_ID | r->uid, r); + resolve(RESOLVE_REGION | r->uid, r); } int read_region_reference(gamedata * data, void **rp, resolve_fun fun) @@ -1280,26 +1267,10 @@ int read_region_reference(gamedata * data, void **rp, resolve_fun fun) struct storage * store = data->store; int id = 0; - if (data->version >= UIDHASH_VERSION) { - READ_INT(store, &id); - *rp = findregionbyid(id); - if (*rp == NULL) { - ur_add(RESOLVE_REGION_ID | id, rp, fun); - } - } - else { - int n; - short x, y; - READ_INT(store, &n); - x = (short)n; - READ_INT(store, &n); - y = (short)n; - *rp = findregion(x, y); - if (*rp == NULL) { - id = x << 16 | (y & 0xFFFF); - ur_add(RESOLVE_REGION_XY | id, rp, resolve_region_coor); - } - + READ_INT(store, &id); + *rp = findregionbyid(id); + if (*rp == NULL) { + ur_add(RESOLVE_REGION | id, rp, fun); } return id; } diff --git a/src/wormhole.c b/src/wormhole.c index 030c33c06..e12a053b8 100644 --- a/src/wormhole.c +++ b/src/wormhole.c @@ -96,16 +96,6 @@ static void wormhole_write(const struct attrib *a, const void *owner, struct sto write_region_reference(exit, store); } -/** conversion code, turn 573, 2008-05-23 */ -static void * resolve_exit(int id, void *data) -{ - building *b = (building *)data; - if (b) { - return b->region; - } - return NULL; -} - static int wormhole_read(struct attrib *a, void *owner, struct gamedata *data) { int id; @@ -113,12 +103,7 @@ static int wormhole_read(struct attrib *a, void *owner, struct gamedata *data) if (data->version < ATTRIBOWNER_VERSION) { READ_INT(data->store, NULL); } - if (data->version < UIDHASH_VERSION) { - id = read_building_reference(data, &a->data.v, resolve_exit); - } - else { - id = read_region_reference(data, &a->data.v, NULL); - } + id = read_region_reference(data, &a->data.v, NULL); return (id <= 0) ? AT_READ_FAIL : AT_READ_OK; } From 0c16727d41223b4da10989cf7539603ef889541d Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 22 Sep 2017 09:15:37 +0200 Subject: [PATCH 35/41] hashing implemented with linear probing and tombstones. WIP: this crashes 572 in faction_getmages? --- src/kernel/ally.c | 23 ++++++++++++ src/kernel/ally.h | 3 ++ src/kernel/save.c | 38 +------------------ src/spells.c | 40 +++----------------- src/util/resolve.c | 94 +++++++++++++++++++++++++++------------------- 5 files changed, 88 insertions(+), 110 deletions(-) diff --git a/src/kernel/ally.c b/src/kernel/ally.c index 759d556f4..b4385088a 100644 --- a/src/kernel/ally.c +++ b/src/kernel/ally.c @@ -10,10 +10,33 @@ #include "plane.h" #include +#include + +#include + #include #include #include +void read_allies(gamedata * data, faction *f) +{ + ally **sfp = &f->allies; + for (;;) { + int aid; + ally * al = ally_add(sfp, NULL); + aid = read_faction_reference(data, &al->faction, NULL); + if (aid > 0) { + int state; + READ_INT(data->store, &state); + al->status = state & HELP_ALL; + sfp = &al->next; + } + else { + break; + } + } +} + ally * ally_find(ally *al, const struct faction *f) { for (; al; al = al->next) { if (al->faction == f) return al; diff --git a/src/kernel/ally.h b/src/kernel/ally.h index 58d6ff4a8..d4c41d36c 100644 --- a/src/kernel/ally.h +++ b/src/kernel/ally.h @@ -26,7 +26,9 @@ extern "C" { struct attrib_type; struct plane; struct faction; + struct gamedata; struct unit; + extern struct attrib_type at_npcfaction; typedef struct ally { @@ -35,6 +37,7 @@ extern "C" { int status; } ally; + void read_allies(struct gamedata * data, struct faction *f); ally * ally_find(ally *al, const struct faction *f); ally * ally_add(ally **al_p, struct faction *f); void ally_remove(ally **al_p, struct faction *f); diff --git a/src/kernel/save.c b/src/kernel/save.c index 064983127..d12c6cdaa 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -1152,31 +1152,6 @@ void write_region(gamedata *data, const region *r) writeregion(data, r); } -static ally **addally(const faction * f, ally ** sfp, int aid, int state) -{ - struct faction *af = findfaction(aid); - ally *sf; - - state &= ~HELP_OBSERVE; - state &= ~HELP_TRAVEL; - state &= HelpMask(); - - if (state == 0) - return sfp; - - while (*sfp) { - sfp = &(*sfp)->next; - } - - sf = ally_add(sfp, af); - if (!sf->faction) { - ur_add(aid, &sf->faction, NULL); - } - sf->status = state & HELP_ALL; - - return &sf->next; -} - int get_spell_level_faction(const spell * sp, void * cbdata) { static spellbook * common = 0; @@ -1385,18 +1360,7 @@ faction *read_faction(gamedata * data) f->options &= ~want(O_JSON); } sfp = &f->allies; - for (;;) { - int aid = 0; - READ_INT(data->store, &aid); - if (aid > 0) { - int state; - READ_INT(data->store, &state); - sfp = addally(f, sfp, aid, state); - } - else { - break; - } - } + read_allies(data, f); read_groups(data, f); f->spellbook = 0; if (data->version >= REGIONOWNER_VERSION) { diff --git a/src/spells.c b/src/spells.c index 52acc54ed..9d5481a60 100644 --- a/src/spells.c +++ b/src/spells.c @@ -2892,46 +2892,20 @@ static curse *mk_deathcloud(unit * mage, region * r, double force, int duration) return c; } -#define COMPAT_DEATHCLOUD -#ifdef COMPAT_DEATHCLOUD static int dc_read_compat(struct attrib *a, void *target, gamedata *data) /* return AT_READ_OK on success, AT_READ_FAIL if attrib needs removal */ { struct storage *store = data->store; - region *r = NULL; - unit *u; - int id; - int duration; - float strength; - int rx, ry; UNUSED_ARG(a); UNUSED_ARG(target); - READ_INT(store, &duration); - READ_FLT(store, &strength); - READ_INT(store, &id); - u = findunit(id); - - /* this only affects really old data. no need to change: */ - READ_INT(store, &rx); - READ_INT(store, &ry); - r = findregion(rx, ry); - - if (r != NULL) { - double effect; - curse *c; - - effect = strength; - c = create_curse(u, &r->attribs, &ct_deathcloud, strength * 2, duration, - effect, 0); - c->data.v = r; - if (u == NULL) { - ur_add(id, &c->magician, NULL); - } - } - return AT_READ_FAIL; /* we don't care for the attribute. */ + READ_INT(store, NULL); + READ_FLT(store, NULL); + READ_INT(store, NULL); + READ_INT(store, NULL); + READ_INT(store, NULL); + return AT_READ_DEPR; /* we don't care for the attribute. */ } -#endif /* ------------------------------------------------------------- */ /* Name: Todeswolke @@ -6704,9 +6678,7 @@ void register_spells(void) { register_borders(); -#ifdef COMPAT_DEATHCLOUD at_deprecate("zauber_todeswolke", dc_read_compat); -#endif /* init_firewall(); */ ct_register(&ct_firewall); diff --git a/src/util/resolve.c b/src/util/resolve.c index 577afb98f..5f1787056 100644 --- a/src/util/resolve.c +++ b/src/util/resolve.c @@ -17,69 +17,85 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. **/ #include + +#include + #include #include +#include + #include "resolve.h" #include "storage.h" #include "variant.h" typedef struct unresolved { - void **addr; - /* address to pass to the resolve-function */ - variant data; + int id; /* information on how to resolve the missing object */ resolve_fun resolve; /* function to resolve the unknown object */ + selist *addrs; + /* address to pass to the resolve-function */ } unresolved; -#define BLOCKSIZE 1024 -static unresolved *ur_list; -static unresolved *ur_begin; -static unresolved *ur_current; +#define HASHSIZE 1024 /* must be a power of 2 */ +static unresolved ur_hash[HASHSIZE]; + +int ur_key(int id) { + int h = id ^ (id >> 16); + return h & (HASHSIZE - 1); +} void ur_add(int id, void **addr, resolve_fun fun) { + int h, i; + + assert(id > 0); assert(addr); assert(!*addr); - if (ur_list == NULL) { - ur_list = malloc(BLOCKSIZE * sizeof(unresolved)); - ur_begin = ur_current = ur_list; + + h = ur_key(id); + for (i = 0; i != HASHSIZE; ++i) { + int k = h + i; + if (k >= HASHSIZE) k -= HASHSIZE; + if (ur_hash[k].id <= 0) { + ur_hash[k].id = id; + ur_hash[k].resolve = fun; + selist_push(&ur_hash[k].addrs, addr); + return; + } + if (ur_hash[k].id == id && ur_hash[k].resolve == fun) { + ur_hash[k].resolve = fun; + selist_push(&ur_hash[k].addrs, addr); + return; + } } - else if (ur_current - ur_begin == BLOCKSIZE - 1) { - ur_begin = malloc(BLOCKSIZE * sizeof(unresolved)); - ur_current->data.v = ur_begin; - ur_current = ur_begin; - } - ur_current->data.i = id; - ur_current->resolve = fun; - ur_current->addr = addr; + assert(!"hash table is full"); +} - ++ur_current; - ur_current->addr = NULL; - ur_current->data.v = NULL; +static bool addr_cb(void *data, void *more) { + void **addr = (void **)data; + *addr = more; + return true; } void resolve(int id, void *data) { - unresolved *ur = ur_list; - /* TODO: hella slow! hashing is better */ - while (ur) { - if (ur->addr == NULL) { - ur = ur->data.v; - free(ur_list); - ur_list = ur; - continue; - } - if (id == ur->data.i) { - if (ur->resolve) { - *ur->addr = ur->resolve(id, data); - } - else { - *ur->addr = data; + int h, i; + h = ur_key(id); + + for (i = 0; i != HASHSIZE; ++i) { + int k = h + i; + + if (k >= HASHSIZE) k -= HASHSIZE; + if (ur_hash[k].id == 0) break; + else if (ur_hash[k].id == id) { + if (ur_hash[k].resolve) { + data = ur_hash[k].resolve(id, data); } + selist_foreach_ex(ur_hash[k].addrs, addr_cb, data); + selist_free(ur_hash[k].addrs); + ur_hash[k].addrs = NULL; + ur_hash[k].id = -1; } - ++ur; } - free(ur_list); - ur_list = NULL; } From 3aed0b1ee52ba60ae7a2e2288839f7e69327e56f Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 22 Sep 2017 16:39:46 +0200 Subject: [PATCH 36/41] fix gcc compilation --- src/attributes/targetregion.c | 2 +- src/kernel/building.c | 4 ++-- src/kernel/building.h | 2 +- src/kernel/curse.c | 2 +- src/kernel/faction.c | 2 +- src/kernel/region.c | 4 ++-- src/kernel/region.h | 2 +- src/kernel/save.c | 17 ----------------- src/kernel/unit.c | 4 ++-- src/modules/xmas.c | 2 +- src/wormhole.c | 2 +- 11 files changed, 13 insertions(+), 30 deletions(-) diff --git a/src/attributes/targetregion.c b/src/attributes/targetregion.c index f9ab3a798..29e76f557 100644 --- a/src/attributes/targetregion.c +++ b/src/attributes/targetregion.c @@ -36,7 +36,7 @@ write_targetregion(const attrib * a, const void *owner, struct storage *store) static int read_targetregion(attrib * a, void *owner, gamedata *data) { - if (read_region_reference(data, &a->data.v, NULL) <= 0) { + if (read_region_reference(data, (region **)&a->data.v, NULL) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; diff --git a/src/kernel/building.c b/src/kernel/building.c index 90adc5300..ebb8c3e79 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -329,7 +329,7 @@ void resolve_building(building *b) resolve(RESOLVE_BUILDING | b->no, b); } -int read_building_reference(gamedata * data, void **bp, resolve_fun fun) +int read_building_reference(gamedata * data, building **bp, resolve_fun fun) { int id; READ_INT(data->store, &id); @@ -337,7 +337,7 @@ int read_building_reference(gamedata * data, void **bp, resolve_fun fun) *bp = findbuilding(id); if (*bp == NULL) { *bp = NULL; - ur_add(RESOLVE_BUILDING | id, bp, fun); + ur_add(RESOLVE_BUILDING | id, (void**)bp, fun); } } else { diff --git a/src/kernel/building.h b/src/kernel/building.h index c828543bf..efa00034d 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -155,7 +155,7 @@ extern "C" { void resolve_building(building *b); void write_building_reference(const struct building *b, struct storage *store); - int read_building_reference(struct gamedata * data, void **bp, resolve_fun fun); + int read_building_reference(struct gamedata * data, struct building **bp, resolve_fun fun); struct building *findbuilding(int n); diff --git a/src/kernel/curse.c b/src/kernel/curse.c index 720be386e..499db9e93 100644 --- a/src/kernel/curse.c +++ b/src/kernel/curse.c @@ -226,7 +226,7 @@ int curse_read(attrib * a, void *owner, gamedata *data) READ_INT(store, &c->data.i); } if (c->type->typ == CURSETYP_REGION) { - int rr = read_region_reference(data, &c->data.v, NULL); + int rr = read_region_reference(data, (region **)&c->data.v, NULL); if (ur == 0 && rr == 0 && !c->data.v) { return AT_READ_FAIL; } diff --git a/src/kernel/faction.c b/src/kernel/faction.c index 60c1dd87e..c3f0fa814 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -332,7 +332,7 @@ int read_faction_reference(gamedata * data, faction **fp, resolve_fun fun) *fp = findfaction(id); if (*fp == NULL) { *fp = NULL; - ur_add(RESOLVE_FACTION | id, fp, fun); + ur_add(RESOLVE_FACTION | id, (void **)fp, fun); } } else { diff --git a/src/kernel/region.c b/src/kernel/region.c index fa2a68464..3d4e058ea 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -1262,7 +1262,7 @@ void resolve_region(region *r) resolve(RESOLVE_REGION | r->uid, r); } -int read_region_reference(gamedata * data, void **rp, resolve_fun fun) +int read_region_reference(gamedata * data, region **rp, resolve_fun fun) { struct storage * store = data->store; int id = 0; @@ -1270,7 +1270,7 @@ int read_region_reference(gamedata * data, void **rp, resolve_fun fun) READ_INT(store, &id); *rp = findregionbyid(id); if (*rp == NULL) { - ur_add(RESOLVE_REGION | id, rp, fun); + ur_add(RESOLVE_REGION | id, (void **)rp, fun); } return id; } diff --git a/src/kernel/region.h b/src/kernel/region.h index 1f2817415..057f28729 100644 --- a/src/kernel/region.h +++ b/src/kernel/region.h @@ -260,7 +260,7 @@ extern "C" { void region_set_morale(region * r, int morale, int turn); void write_region_reference(const struct region *r, struct storage *store); - int read_region_reference(struct gamedata *data, void **rp, resolve_fun fun); + int read_region_reference(struct gamedata *data, region **rp, resolve_fun fun); void resolve_region(region *r); const char *regionname(const struct region *r, const struct faction *f); diff --git a/src/kernel/save.c b/src/kernel/save.c index d12c6cdaa..eb072c03d 100644 --- a/src/kernel/save.c +++ b/src/kernel/save.c @@ -508,21 +508,6 @@ void write_alliances(gamedata *data) WRITE_SECTION(data->store); } -static int resolve_owner(int id, void *address) -{ - region_owner *owner = (region_owner *)address; - int result = 0; - faction *f = NULL; - if (id != 0) { - f = findfaction(id); - if (f == NULL) { - log_error("region has an invalid owner (%s)", itoa36(id)); - } - } - owner->owner = f; - return result; -} - static void read_owner(gamedata *data, region_owner ** powner) { int since_turn; @@ -1230,7 +1215,6 @@ void _test_write_password(gamedata *data, const faction *f) { faction *read_faction(gamedata * data) { - ally **sfp; int planes, n; faction *f; char name[DISPLAYSIZE]; @@ -1359,7 +1343,6 @@ faction *read_faction(gamedata * data) /* mistakes were made in the past*/ f->options &= ~want(O_JSON); } - sfp = &f->allies; read_allies(data, f); read_groups(data, f); f->spellbook = 0; diff --git a/src/kernel/unit.c b/src/kernel/unit.c index b57b26c34..b00e1717c 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -648,7 +648,7 @@ void a_writesiege(const attrib * a, const void *owner, struct storage *store) int a_readsiege(attrib * a, void *owner, gamedata *data) { - if (read_building_reference(data, &a->data.v, NULL) <= 0) { + if (read_building_reference(data, (building **)&a->data.v, NULL) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; @@ -764,7 +764,7 @@ int read_unit_reference(gamedata * data, unit **up, resolve_fun fun) *up = findunit(id); if (*up == NULL) { *up = NULL; - ur_add(RESOLVE_UNIT | id, up, fun); + ur_add(RESOLVE_UNIT | id, (void **)up, fun); } } else { diff --git a/src/modules/xmas.c b/src/modules/xmas.c index 315a52f07..b76f14eab 100644 --- a/src/modules/xmas.c +++ b/src/modules/xmas.c @@ -50,7 +50,7 @@ static void xmasgate_write(const trigger * t, struct storage *store) static int xmasgate_read(trigger * t, struct gamedata *data) { - if (read_building_reference(data, &t->data.v, NULL) <= 0) { + if (read_building_reference(data, (building **)&t->data.v, NULL) <= 0) { return AT_READ_FAIL; } return AT_READ_OK; diff --git a/src/wormhole.c b/src/wormhole.c index e12a053b8..b4dfa7068 100644 --- a/src/wormhole.c +++ b/src/wormhole.c @@ -103,7 +103,7 @@ static int wormhole_read(struct attrib *a, void *owner, struct gamedata *data) if (data->version < ATTRIBOWNER_VERSION) { READ_INT(data->store, NULL); } - id = read_region_reference(data, &a->data.v, NULL); + id = read_region_reference(data, (region **)&a->data.v, NULL); return (id <= 0) ? AT_READ_FAIL : AT_READ_OK; } From 0a9705809b0e83cee8fe8d6026b70a332ea26dcd Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 22 Sep 2017 17:19:55 +0200 Subject: [PATCH 37/41] fix some bugs created during conversions (thanks, tests!) --- src/kernel/building.c | 2 -- src/kernel/building.h | 1 + src/kernel/faction.c | 2 -- src/kernel/faction.h | 2 ++ src/kernel/group.c | 9 +++++++-- src/kernel/region.c | 2 -- src/kernel/region.h | 3 ++- src/kernel/unit.c | 2 -- src/kernel/unit.h | 1 + src/triggers/changefaction.c | 3 +-- 10 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/kernel/building.c b/src/kernel/building.c index ebb8c3e79..57b8a91e2 100644 --- a/src/kernel/building.c +++ b/src/kernel/building.c @@ -322,8 +322,6 @@ void write_building_reference(const struct building *b, struct storage *store) WRITE_INT(store, (b && b->region) ? b->no : 0); } -#define RESOLVE_BUILDING (TYP_BUILDING << 24) - void resolve_building(building *b) { resolve(RESOLVE_BUILDING | b->no, b); diff --git a/src/kernel/building.h b/src/kernel/building.h index efa00034d..af29c324b 100644 --- a/src/kernel/building.h +++ b/src/kernel/building.h @@ -152,6 +152,7 @@ extern "C" { #include "build.h" #define NOBUILDING NULL +#define RESOLVE_BUILDING (TYP_BUILDING << 24) void resolve_building(building *b); void write_building_reference(const struct building *b, struct storage *store); diff --git a/src/kernel/faction.c b/src/kernel/faction.c index c3f0fa814..98e49bd84 100755 --- a/src/kernel/faction.c +++ b/src/kernel/faction.c @@ -317,8 +317,6 @@ bool checkpasswd(const faction * f, const char *passwd) return true; } -#define RESOLVE_FACTION (TYP_FACTION << 24) - void resolve_faction(faction *f) { resolve(RESOLVE_FACTION | f->no, f); diff --git a/src/kernel/faction.h b/src/kernel/faction.h index e2272c396..a04acabfa 100644 --- a/src/kernel/faction.h +++ b/src/kernel/faction.h @@ -130,6 +130,8 @@ extern "C" { void write_faction_reference(const struct faction *f, struct storage *store); int read_faction_reference(struct gamedata *data, struct faction **fp, resolve_fun fun); + +#define RESOLVE_FACTION (TYP_FACTION << 24) void resolve_faction(struct faction *f); void renumber_faction(faction * f, int no); diff --git a/src/kernel/group.c b/src/kernel/group.c index 650679b3f..2c6b28bec 100755 --- a/src/kernel/group.c +++ b/src/kernel/group.c @@ -24,6 +24,7 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "ally.h" #include "faction.h" #include "unit.h" +#include "objtypes.h" /* attrib includes */ #include @@ -239,9 +240,13 @@ void read_groups(gamedata *data, faction * f) pa = &g->allies; for (;;) { ally *al; + int id; + READ_INT(store, &id); + if (id == 0) break; al = ally_add(pa, NULL); - if (read_faction_reference(data, &al->faction, NULL) <= 0) { - break; + al->faction = findfaction(id); + if (!al->faction) { + ur_add(RESOLVE_FACTION | id, (void **)&al->faction, NULL); } READ_INT(store, &al->status); } diff --git a/src/kernel/region.c b/src/kernel/region.c index 3d4e058ea..c7e3841fb 100644 --- a/src/kernel/region.c +++ b/src/kernel/region.c @@ -1255,8 +1255,6 @@ int production(const region * r) return p; } -#define RESOLVE_REGION (TYP_REGION << 24) - void resolve_region(region *r) { resolve(RESOLVE_REGION | r->uid, r); diff --git a/src/kernel/region.h b/src/kernel/region.h index 057f28729..7f86f397f 100644 --- a/src/kernel/region.h +++ b/src/kernel/region.h @@ -259,9 +259,10 @@ extern "C" { int region_get_morale(const region * r); void region_set_morale(region * r, int morale, int turn); +#define RESOLVE_REGION (TYP_REGION << 24) + void resolve_region(region *r); void write_region_reference(const struct region *r, struct storage *store); int read_region_reference(struct gamedata *data, region **rp, resolve_fun fun); - void resolve_region(region *r); const char *regionname(const struct region *r, const struct faction *f); diff --git a/src/kernel/unit.c b/src/kernel/unit.c index b00e1717c..2c6378ca1 100644 --- a/src/kernel/unit.c +++ b/src/kernel/unit.c @@ -749,8 +749,6 @@ void write_unit_reference(const unit * u, struct storage *store) WRITE_INT(store, (u && u->region) ? u->no : 0); } -#define RESOLVE_UNIT (TYP_UNIT << 24) - void resolve_unit(unit *u) { resolve(RESOLVE_UNIT | u->no, u); diff --git a/src/kernel/unit.h b/src/kernel/unit.h index dde183eb4..d80c0ec79 100644 --- a/src/kernel/unit.h +++ b/src/kernel/unit.h @@ -185,6 +185,7 @@ extern "C" { void make_zombie(struct unit * u); /* see resolve.h */ +#define RESOLVE_UNIT (TYP_UNIT << 24) void resolve_unit(struct unit *u); void write_unit_reference(const struct unit *u, struct storage *store); int read_unit_reference(struct gamedata * data, struct unit **up, resolve_fun fun); diff --git a/src/triggers/changefaction.c b/src/triggers/changefaction.c index fb5805618..6a2700afa 100644 --- a/src/triggers/changefaction.c +++ b/src/triggers/changefaction.c @@ -86,8 +86,7 @@ static int changefaction_read(trigger * t, gamedata *data) changefaction_data *td = (changefaction_data *)t->data.v; read_unit_reference(data, &td->unit, NULL); - read_faction_reference(data, &td->faction, NULL); - return AT_READ_OK; + return read_faction_reference(data, &td->faction, NULL) > 0 ? AT_READ_OK : AT_READ_FAIL; } trigger_type tt_changefaction = { From 8ebd4c206651ff5b507cd29423576b395a373bb7 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 22 Sep 2017 17:58:10 +0200 Subject: [PATCH 38/41] some more bugs reading objects that are conditional on save-data --- src/kernel/ally.c | 8 ++++++-- src/triggers/killunit.c | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/kernel/ally.c b/src/kernel/ally.c index b4385088a..534b9ff8e 100644 --- a/src/kernel/ally.c +++ b/src/kernel/ally.c @@ -7,6 +7,7 @@ #include "region.h" #include "group.h" #include "faction.h" +#include "objtypes.h" #include "plane.h" #include @@ -23,10 +24,13 @@ void read_allies(gamedata * data, faction *f) ally **sfp = &f->allies; for (;;) { int aid; - ally * al = ally_add(sfp, NULL); - aid = read_faction_reference(data, &al->faction, NULL); + READ_INT(data->store, &aid); if (aid > 0) { + ally * al = ally_add(sfp, NULL); int state; + if ((al->faction = findfaction(aid)) == NULL) { + ur_add(RESOLVE_FACTION | aid, &al->faction, NULL); + } READ_INT(data->store, &state); al->status = state & HELP_ALL; sfp = &al->next; diff --git a/src/triggers/killunit.c b/src/triggers/killunit.c index f6613dcb7..230efa7dc 100644 --- a/src/triggers/killunit.c +++ b/src/triggers/killunit.c @@ -60,7 +60,7 @@ static void killunit_write(const trigger * t, struct storage *store) static int killunit_read(trigger * t, gamedata *data) { - if (read_unit_reference(data, (unit **)&t->data.v, NULL)) { + if (read_unit_reference(data, (unit **)&t->data.v, NULL) == 0) { return AT_READ_FAIL; } return AT_READ_OK; From f350b81d518561d4aa101c039613dc3d3d2d5a69 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 22 Sep 2017 17:59:23 +0200 Subject: [PATCH 39/41] gcc warning --- src/kernel/ally.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernel/ally.c b/src/kernel/ally.c index 534b9ff8e..73f198091 100644 --- a/src/kernel/ally.c +++ b/src/kernel/ally.c @@ -29,7 +29,7 @@ void read_allies(gamedata * data, faction *f) ally * al = ally_add(sfp, NULL); int state; if ((al->faction = findfaction(aid)) == NULL) { - ur_add(RESOLVE_FACTION | aid, &al->faction, NULL); + ur_add(RESOLVE_FACTION | aid, (void **)&al->faction, NULL); } READ_INT(data->store, &state); al->status = state & HELP_ALL; From 1203b6e23a2706df7bf80d31710743fa0abcb064 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Fri, 22 Sep 2017 19:13:42 +0200 Subject: [PATCH 40/41] fix clang build warning --- src/kernel/connection.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/kernel/connection.c b/src/kernel/connection.c index 6ae173271..b630429fe 100644 --- a/src/kernel/connection.c +++ b/src/kernel/connection.c @@ -612,15 +612,16 @@ int read_borders(gamedata *data) border_type *type; READ_TOK(store, zText, sizeof(zText)); - if (!strcmp(zText, "end")) + if (!strcmp(zText, "end")) { break; + } + READ_INT(store, &bid); type = find_bordertype(zText); if (type == NULL) { log_error("[read_borders] connection %d type %s is not registered", bid, zText); assert(type || !"connection type not registered"); } - READ_INT(store, &bid); READ_INT(store, &fid); READ_INT(store, &tid); from = findregionbyid(fid); From 95695c1b540f7006ec679af92b10771d8e1d8195 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Sat, 23 Sep 2017 21:12:50 +0200 Subject: [PATCH 41/41] remove log_orders because I'm never using it and it costs time. reduce memory reserved for balloc. --- src/reports.c | 19 ------------------- src/util/translation.c | 10 ++++------ 2 files changed, 4 insertions(+), 25 deletions(-) diff --git a/src/reports.c b/src/reports.c index 8e91bd3da..1182f89c9 100644 --- a/src/reports.c +++ b/src/reports.c @@ -2147,23 +2147,6 @@ static void eval_int36(struct opstack **stack, const void *userdata) /*** END MESSAGE RENDERING ***/ -#include - -static void log_orders(const struct message *msg) -{ - char buffer[4096]; - int i; - - for (i = 0; i != msg->type->nparameters; ++i) { - if (msg->type->types[i]->copy == &var_copy_order) { - const char *section = nr_section(msg); - nr_render(msg, default_locale, buffer, sizeof(buffer), NULL); - log_debug("MESSAGE [%s]: %s\n", section, buffer); - break; - } - } -} - int stream_printf(struct stream * out, const char *format, ...) { va_list args; @@ -2226,8 +2209,6 @@ void register_reports(void) register_argtype("items", var_free_resources, var_copy_items, VAR_VOIDPTR); register_argtype("regions", var_free_regions, NULL, VAR_VOIDPTR); - msg_log_create = &log_orders; - /* register functions that turn message contents to readable strings */ add_function("alliance", &eval_alliance); add_function("region", &eval_region); diff --git a/src/util/translation.c b/src/util/translation.c index fb89a5af9..290e28c16 100644 --- a/src/util/translation.c +++ b/src/util/translation.c @@ -71,7 +71,7 @@ void opstack_push(opstack ** stackp, variant data) ** static buffer malloc **/ -#define BBUFSIZE 0x20000 +#define BBUFSIZE 0x10000 static struct { char *begin; char *end; @@ -81,16 +81,13 @@ static struct { char *balloc(size_t size) { - static int init = 0; /* STATIC_XCALL: used across calls */ + static int init = 0; if (!init) { init = 1; buffer.current = buffer.begin = malloc(BBUFSIZE * sizeof(char)); buffer.end = buffer.begin + BBUFSIZE; } - if (buffer.current + size > buffer.end) { - /* out of memory! */ - return NULL; - } + assert(buffer.current + size <= buffer.end || !"balloc is out of memory"); buffer.last = buffer.current; buffer.current += size; return buffer.last; @@ -99,6 +96,7 @@ char *balloc(size_t size) void bfree(char *c) /* only release this memory if it was part of the last allocation * that's a joke, but who cares. + * I'm afraid I don't get the joke. */ { if (c >= buffer.last && c < buffer.current)