From 902e2126c9ba69dc53e2fcb3d011cf207abf4b08 Mon Sep 17 00:00:00 2001 From: Enno Rehling Date: Thu, 21 Sep 2017 16:26:53 +0200 Subject: [PATCH 1/8] 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 2/8] 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 3/8] 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 4/8] 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 5/8] 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 6/8] 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 7/8] 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 8/8] 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);