From 902e2126c9ba69dc53e2fcb3d011cf207abf4b08 Mon Sep 17 00:00:00 2001
From: Enno Rehling <enno.rehling@gmail.com>
Date: Thu, 21 Sep 2017 16:26:53 +0200
Subject: [PATCH] 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 <util/bsdstring.h>
 #include <util/event.h>
 #include <util/functions.h>
+#include <util/gamedata.h>
 #include <util/log.h>
 #include <util/parser.h>
 #include <util/resolve.h>
@@ -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 <kernel/types.h>
-#include <util/variant.h>
+#include <util/resolve.h>
 
 #include <stddef.h>
 #include <stdbool.h>
@@ -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 <util/resolve.h>
 #include <modules/score.h>
+
 #include <stdbool.h>
 
 #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 <stddef.h>
-#include <stdbool.h>
+#include <util/resolve.h>
+
 #include "types.h"
 #include "direction.h"
 
+#include <stddef.h>
+#include <stdbool.h>
+
 #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) ((version<UIDHASH_VERSION)?resolve_region_coor:resolve_region_id)
+    int read_region_reference(struct gamedata *data, void **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 4eed34656..064983127 100644
--- a/src/kernel/save.c
+++ b/src/kernel/save.c
@@ -399,8 +399,7 @@ static void read_alliances(gamedata *data)
             READ_INT(store, &al->flags);
         }
         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 <util/variant.h>
+#include <util/resolve.h>
 #include "types.h"
 #include "skills.h"
 #include <stddef.h>
@@ -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 <corwin@amber.kn-bremen.de>
  |                   |  Enno Rehling <enno@eressea.de>
  | Eressea PBEM host |  Katja Zedel <katze@felidae.kn-bremen.de>
@@ -14,7 +14,7 @@
 #include <kernel/config.h>
 #include "xmas.h"
 
-/* kernel includes */
+ /* kernel includes */
 #include <kernel/building.h>
 #include <kernel/faction.h>
 #include <kernel/item.h>
@@ -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 = {