From 2c687e77cd9ae3fd01010d7b36c8d0082bb76315 Mon Sep 17 00:00:00 2001 From: Franklin Wei Date: Sat, 20 Feb 2016 20:37:06 -0500 Subject: implements aliases and other assorted features/enhancements --- src/client.c | 2 + src/hash.c | 5 ++ src/multimap.c | 10 +++- src/multimap.h | 2 +- src/obj.c | 70 ++++++++++++++++++++++++++-- src/obj.h | 12 +++++ src/room.c | 89 +++++++++++++++++++++++++++++++++--- src/room.h | 19 ++++++-- src/server.c | 21 +++++---- src/server.h | 1 + src/server_reqs.c | 133 +++++++++++++++++++++++++++++++++--------------------- src/userdb.c | 37 +++++++++++++-- src/userdb.h | 2 + src/util.c | 14 +++++- src/world.c | 29 +++++++++--- 15 files changed, 356 insertions(+), 90 deletions(-) (limited to 'src') diff --git a/src/client.c b/src/client.c index 7ed0df5..a93ae0e 100644 --- a/src/client.c +++ b/src/client.c @@ -40,6 +40,8 @@ bool poll_requests(void); void out_raw(const void *buf, size_t len) { + if(!are_child) + error("out() called from master"); if(!len) return; diff --git a/src/hash.c b/src/hash.c index 70e5d8d..eed4846 100644 --- a/src/hash.c +++ b/src/hash.c @@ -24,6 +24,11 @@ #include #include +/** + * @file + * @brief A simple, chained hash table + */ + struct hash_node { const void *key; const void *data; diff --git a/src/multimap.c b/src/multimap.c index d609d0f..b958db0 100644 --- a/src/multimap.c +++ b/src/multimap.c @@ -203,11 +203,17 @@ size_t multimap_delete(void *ptr, const void *key, const void *val) next = iter->next; if(!map->compare_val(val, iter->val)) { + if(map->free_data) + map->free_data(iter->val); + if(map->free_key) + map->free_key((void*)iter->key); + if(last) last->next = iter->next; else node->list = iter->next; free(iter); + ++deleted; --node->n_pairs; --map->total_pairs; @@ -250,9 +256,9 @@ size_t multimap_delete_all(void *ptr, const void *key) return 0; } -const struct multimap_list *multimap_iterate(void *ptr, void **save, size_t *n_pairs) +const struct multimap_list *multimap_iterate(const void *ptr, void **save, size_t *n_pairs) { - struct multimap_t *map = ptr; + const struct multimap_t *map = ptr; CHECK_SENTINEL(map); struct multimap_node *node; diff --git a/src/multimap.h b/src/multimap.h index 8faa829..3cc345d 100644 --- a/src/multimap.h +++ b/src/multimap.h @@ -53,7 +53,7 @@ size_t multimap_delete_all(void *map, const void *key); /* returns a linked list, NOT individual items of a linked list */ /* set map to NULL after the initial call */ -const struct multimap_list *multimap_iterate(void *map, void **save, size_t *n_pairs); +const struct multimap_list *multimap_iterate(const void *map, void **save, size_t *n_pairs); size_t multimap_size(void *map); diff --git a/src/obj.c b/src/obj.c index 71c534c..293aaff 100644 --- a/src/obj.c +++ b/src/obj.c @@ -19,6 +19,7 @@ #include "globals.h" #include "hash.h" +#include "multimap.h" #include "obj.h" /* map of class names -> object classes */ @@ -50,7 +51,7 @@ struct object_t *obj_new(const char *class_name) if(hash_insert(obj_class_map, netcosm_obj_classes[i].class_name, netcosm_obj_classes + i)) - error("duplicate object class name"); + error("duplicate object class name '%s'", netcosm_obj_classes[i].class_name); } } @@ -66,6 +67,8 @@ struct object_t *obj_new(const char *class_name) obj->id = idcounter++; obj->refcount = 1; + obj->list = true; + obj->default_article = true; return obj; } @@ -78,6 +81,15 @@ void obj_write(int fd, struct object_t *obj) write_string(fd, obj->name); write_bool(fd, obj->list); + write_bool(fd, obj->default_article); + + struct obj_alias_t *iter = obj->alias_list; + while(iter) + { + write_string(fd, iter->alias); + iter = iter->next; + } + write_string(fd, ""); if(obj->class->hook_serialize) obj->class->hook_serialize(fd, obj); @@ -93,6 +105,27 @@ struct object_t *obj_read(int fd) obj->name = read_string(fd); obj->list = read_bool(fd); + obj->default_article = read_bool(fd); + + /* aliases */ + struct obj_alias_t *last = NULL; + while(1) + { + char *alias = read_string(fd); + if(alias[0] == '\0') + { + free(alias); + break; + } + struct obj_alias_t *new = calloc(1, sizeof(*new)); + new->alias = alias; + if(last) + last->next = new; + else + obj->alias_list = new; + last = new; + } + if(obj->class->hook_deserialize) obj->class->hook_deserialize(fd, obj); @@ -104,13 +137,14 @@ struct object_t *obj_copy(struct object_t *obj) struct object_t *ret = obj_new(obj->class->class_name); ret->name = strdup(obj->name); ret->list = obj->list; - ret->userdata = obj->class->hook_dupdata(obj); + if(obj->class->hook_dupdata) + ret->userdata = obj->class->hook_dupdata(obj); return ret; } struct object_t *obj_dup(struct object_t *obj) { - debugf("Adding an object reference for #%lu.\n", obj->id); + debugf("Adding an object reference to #%lu.\n", obj->id); ++obj->refcount; return obj; } @@ -128,6 +162,15 @@ void obj_free(void *ptr) if(obj->class->hook_destroy) obj->class->hook_destroy(obj); + struct obj_alias_t *iter = obj->alias_list; + while(iter) + { + struct obj_alias_t *next = iter->next; + free(iter->alias); + free(iter); + iter = next; + } + free(obj->name); free(obj); } @@ -144,3 +187,24 @@ int obj_compare(const void *a, const void *b) const struct object_t *c = a, *d = b; return !(c->id == d->id); } + +size_t obj_count_noalias(const void *a) +{ + size_t ret = 0; + void *save; + while(1) + { + const struct multimap_list *iter = multimap_iterate(a, &save, NULL); + a = NULL; + if(!iter) + break; + while(iter) + { + struct object_t *obj = iter->val; + if(!strcmp(iter->key, obj->name)) + ++ret; + iter = iter->next; + } + } + return ret; +} diff --git a/src/obj.h b/src/obj.h index c591009..249f9c1 100644 --- a/src/obj.h +++ b/src/obj.h @@ -60,6 +60,11 @@ struct obj_class_t { typedef uint64_t obj_id; +struct obj_alias_t { + char *alias; + struct obj_alias_t *next; +}; + /* world modules should not instantiate this directly, use obj_new() instead */ /* also, members marked with 'protected' should not be modified by the world module */ struct object_t { @@ -72,7 +77,11 @@ struct object_t { struct obj_class_t *class; + size_t n_alias; + struct obj_alias_t *alias_list; + bool list; /* whether to list in room view */ + bool default_article; /* whether or not to use 'a' or 'an' when describing this */ void *userdata; @@ -106,3 +115,6 @@ void obj_set_idcounter(obj_id); /* compare two objects */ int obj_compare(const void *a, const void *b); + +/* count the number of non-alias objects in the given multimap */ +size_t obj_count_noalias(const void *multimap); diff --git a/src/room.c b/src/room.c index 9a92588..23ea5b7 100644 --- a/src/room.c +++ b/src/room.c @@ -62,6 +62,9 @@ bool room_user_del(room_id id, struct child_data *child) void room_free(struct room_t *room) { + if(room->data.hook_destroy) + room->data.hook_destroy(room->id); + hash_free(room->users); room->users = NULL; @@ -77,7 +80,52 @@ void room_free(struct room_t *room) bool room_obj_add(room_id room, struct object_t *obj) { - return !multimap_insert(room_get(room)->objects, obj->name, obj); + bool status = true; + if(!multimap_insert(room_get(room)->objects, obj->name, obj)) + status = false; + struct obj_alias_t *iter = obj->alias_list; + while(iter) + { + if(!multimap_insert(room_get(room)->objects, iter->alias, obj_dup(obj))) + { + status = false; + + debugf("Status is false\n"); + } + iter = iter->next; + } + return status; +} + +bool room_obj_add_alias(room_id room, struct object_t *obj, char *alias) +{ + /* the primary name must be added */ + if(!room_obj_get(room, obj->name)) + room_obj_add(room, obj); + + /* don't add an alias with the same name as the object */ + if(!strcmp(alias, obj->name)) + return false; + + /* make sure this alias isn't already added */ + struct obj_alias_t *iter = obj->alias_list; + while(iter) + { + if(!strcasecmp(iter->alias, alias)) + return false; + iter = iter->next; + } + + struct obj_alias_t *new = calloc(1, sizeof(struct obj_alias_t)); + + new->alias = alias; + + new->next = obj->alias_list; + obj->alias_list = new; + + ++obj->n_alias; + + return multimap_insert(room_get(room)->objects, alias, obj_dup(obj)); } const struct multimap_list *room_obj_iterate(room_id room, void **save, size_t *n_pairs) @@ -103,16 +151,45 @@ size_t room_obj_count(room_id room) return multimap_size(room_get(room)->objects); } -bool room_obj_del(room_id room, const char *name) +size_t room_obj_count_noalias(room_id id) { - return multimap_delete_all(room_get(room)->objects, name); + return obj_count_noalias(room_get(id)->objects); } -bool room_obj_del_id(room_id room, const char *name, obj_id id) +/* delete a specific object and its aliases */ + +bool room_obj_del_by_ptr(room_id room, struct object_t *obj) { + struct obj_alias_t *iter = obj->alias_list; + struct object_t tmp; - tmp.id = id; - return multimap_delete(room_get(room)->objects, name, &tmp); + tmp.id = obj->id; + + while(iter) + { + multimap_delete(room_get(room)->objects, iter->alias, &tmp); + iter = iter->next; + } + + return multimap_delete(room_get(room)->objects, obj->name, &tmp); +} + +/* delete all the objects with a matching name, and all their aliases, + * from a room */ + +bool room_obj_del(room_id room, const char *name) +{ + const struct multimap_list *iter = multimap_lookup(room_get(room)->objects, name, NULL); + if(!iter) + return false; + while(iter) + { + struct multimap_list *next = iter->next; + struct object_t *obj = iter->val; + room_obj_del_by_ptr(room, obj); + iter = next; + } + return true; } #define OBJMAP_SIZE 8 diff --git a/src/room.h b/src/room.h index 7ed720e..e02105c 100644 --- a/src/room.h +++ b/src/room.h @@ -48,6 +48,9 @@ struct roomdata_t { void (* const hook_init)(room_id id); void (* const hook_enter)(room_id room, user_t *user); void (* const hook_leave)(room_id room, user_t *user); + void (* const hook_serialize)(room_id room, int fd); + void (* const hook_deserialize)(room_id room, int fd); + void (* const hook_destroy)(room_id room); }; struct room_t { @@ -60,6 +63,8 @@ struct room_t { void *objects; /* multimap of object name -> object */ void *verbs; void *users; /* username -> child_data */ + + void *userdata; }; /* room/world */ @@ -74,14 +79,18 @@ bool room_user_del(room_id id, struct child_data *child); const struct multimap_list *room_obj_iterate(room_id room, void **save, size_t *n_pairs); /* new should point to a new object allocated with obj_new(), with - * 'name' properly set */ + * 'name' properly set + * returns true if the name is room-unique + */ bool room_obj_add(room_id room, struct object_t *obj); -const struct multimap_list *room_obj_get(room_id room, const char *obj); -const struct multimap_list *room_obj_get_size(room_id room, const char *name, size_t *n_objs); +bool room_obj_add_alias(room_id room, struct object_t *obj, char *alias); bool room_obj_del(room_id room, const char *name); -bool room_obj_del_id(room_id room, const char *name, obj_id id); +bool room_obj_del_alias(room_id room, struct object_t *obj, const char *alias); + +const struct multimap_list *room_obj_get(room_id room, const char *obj); +const struct multimap_list *room_obj_get_size(room_id room, const char *name, size_t *n_objs); size_t room_obj_count(room_id room); @@ -97,3 +106,5 @@ void room_free(struct room_t *room); /* semi-protected, should only be called from world_ */ void room_init_maps(struct room_t *room); + +size_t room_obj_count_noalias(room_id id); diff --git a/src/server.c b/src/server.c index 5f2478a..9e2e465 100644 --- a/src/server.c +++ b/src/server.c @@ -40,17 +40,18 @@ static uint16_t port = DEFAULT_PORT; static int server_socket; -void __attribute__((noreturn)) error(const char *fmt, ...) +#define SAVE_INTERVAL 8 + +/* saves state periodically */ +void server_save_state(bool force) { - char buf[128]; - memset(buf, 0, sizeof(buf)); - va_list ap; - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - perror(buf); - abort(); - exit(EXIT_FAILURE); + static int n = 0; + n = (n + 1) % SAVE_INTERVAL; + if(!n || force) + { + world_save(WORLDFILE); + userdb_write(USERFILE); + } } static void free_child_data(void *ptr) diff --git a/src/server.h b/src/server.h index d7b7419..af7e9fc 100644 --- a/src/server.h +++ b/src/server.h @@ -46,3 +46,4 @@ extern void *child_map; extern bool are_child; int server_main(int argc, char *argv[]); +void server_save_state(bool force); diff --git a/src/server_reqs.c b/src/server_reqs.c index 652c722..167331d 100644 --- a/src/server_reqs.c +++ b/src/server_reqs.c @@ -165,23 +165,30 @@ static void req_send_desc(unsigned char *data, size_t datalen, struct child_data break; const char *name = iter->key; - if(n_objs == 1) - { - char *article = (is_vowel(name[0])?"an":"a"); - strlcat(buf, "There is ", sizeof(buf)); - strlcat(buf, article, sizeof(buf)); - strlcat(buf, " ", sizeof(buf)); - strlcat(buf, name, sizeof(buf)); - strlcat(buf, " here.\n", sizeof(buf)); - } - else + struct object_t *obj = iter->val; + if(!strcmp(name, obj->name)) { - strlcat(buf, "There are ", sizeof(buf)); - char n[32]; - snprintf(n, sizeof(n), "%lu ", n_objs); - strlcat(buf, n, sizeof(buf)); - strlcat(buf, name, sizeof(buf)); - strlcat(buf, "s here.\n", sizeof(buf)); + if(n_objs == 1) + { + char *article = (is_vowel(name[0])?"an":"a"); + strlcat(buf, "There is ", sizeof(buf)); + if(obj->default_article) + { + strlcat(buf, article, sizeof(buf)); + strlcat(buf, " ", sizeof(buf)); + } + strlcat(buf, name, sizeof(buf)); + strlcat(buf, " here.\n", sizeof(buf)); + } + else + { + strlcat(buf, "There are ", sizeof(buf)); + char n[32]; + snprintf(n, sizeof(n), "%lu ", n_objs); + strlcat(buf, n, sizeof(buf)); + strlcat(buf, name, sizeof(buf)); + strlcat(buf, "s here.\n", sizeof(buf)); + } } } @@ -286,18 +293,13 @@ static void req_kick_always(unsigned char *data, size_t datalen, send_packet(child, REQ_KICK, data, datalen); } -static void req_look_at(unsigned char *data, size_t datalen, struct child_data *sender) +static int print_objlist(struct child_data *sender, const struct multimap_list *list, int idx, size_t n_objs) { - (void) datalen; - debugf("Looking at '%s'\n", data); - size_t n_objs; - const struct multimap_list *iter = room_obj_get_size(sender->room, (const char*)data, &n_objs); - if(iter) + if(list) { - int idx = 1; // index of the object - while(iter) + while(list) { - struct object_t *obj = iter->val; + struct object_t *obj = list->val; const char *desc = obj->class->hook_desc(obj, sender); if(n_objs > 1) @@ -305,13 +307,37 @@ static void req_look_at(unsigned char *data, size_t datalen, struct child_data * else send_msg(sender, "%s\n", desc); - iter = iter->next; + list = list->next; } } - else + return idx; +} + +static void req_look_at(unsigned char *data, size_t datalen, struct child_data *sender) +{ + (void) datalen; + debugf("Looking at '%s'\n", data); + size_t n_objs = 0, tmp; + + const struct multimap_list *room_list = room_obj_get_size(sender->room, (const char*)data, &n_objs); + const struct multimap_list *inv_list = multimap_lookup(userdb_lookup(sender->user)->objects, data, &tmp); + + int idx = 1; // index of the object + n_objs += tmp; + + if(room_list) { - send_msg(sender, "I don't know what that is.\n"); + send_msg(sender, "In room:\n"); + idx = print_objlist(sender, room_list, idx, n_objs); } + if(inv_list) + { + send_msg(sender, "In inventory:\n"); + idx = print_objlist(sender, inv_list, idx, n_objs); + } + + if(!room_list && !inv_list) + send_msg(sender, "I don't know what that is.\n"); } static void req_take(unsigned char *data, size_t datalen, struct child_data *sender) @@ -332,9 +358,7 @@ static void req_take(unsigned char *data, size_t datalen, struct child_data *sen return; } - struct object_t *dup = obj_dup(obj); - multimap_insert(userdb_lookup(sender->user)->objects, - dup->name, dup); + userdb_add_obj(sender->user, obj); send_msg(sender, "Taken.\n"); } @@ -345,8 +369,7 @@ static void req_take(unsigned char *data, size_t datalen, struct child_data *sen room_obj_del(sender->room, (const char*)data); - world_save(WORLDFILE); - userdb_write(USERFILE); + server_save_state(false); } else { @@ -377,25 +400,32 @@ static void req_inventory(unsigned char *data, size_t datalen, struct child_data buf[0] = '\0'; const char *name = iter->key; - if(n_objs == 1) - { - char *article = (is_vowel(name[0])?"An":"A"); - strlcat(buf, article, sizeof(buf)); - strlcat(buf, " ", sizeof(buf)); - strlcat(buf, name, sizeof(buf)); - strlcat(buf, "\n", sizeof(buf)); - } - else + struct object_t *obj = iter->val; + if(!strcmp(name, obj->name)) { - char n[32]; - snprintf(n, sizeof(n), "%lu", n_objs); - strlcat(buf, n, sizeof(buf)); - strlcat(buf, " ", sizeof(buf)); - strlcat(buf, name, sizeof(buf)); - strlcat(buf, "s\n", sizeof(buf)); - } + if(n_objs == 1) + { + if(obj->default_article) + { + char *article = (is_vowel(name[0])?"An":"A"); + strlcat(buf, article, sizeof(buf)); + strlcat(buf, " ", sizeof(buf)); + } + strlcat(buf, name, sizeof(buf)); + strlcat(buf, "\n", sizeof(buf)); + } + else + { + char n[32]; + snprintf(n, sizeof(n), "%lu", n_objs); + strlcat(buf, n, sizeof(buf)); + strlcat(buf, " ", sizeof(buf)); + strlcat(buf, name, sizeof(buf)); + strlcat(buf, "s\n", sizeof(buf)); + } - send_packet(sender, REQ_BCASTMSG, buf, strlen(buf)); + send_packet(sender, REQ_BCASTMSG, buf, strlen(buf)); + } } if(ptr) send_msg(sender, "Nothing!\n"); @@ -433,8 +463,7 @@ static void req_drop(unsigned char *data, size_t datalen, struct child_data *sen multimap_delete_all(user->objects, (const char*)data); - world_save(WORLDFILE); - userdb_write(USERFILE); + server_save_state(false); } static void req_listusers(unsigned char *data, size_t datalen, struct child_data *sender) diff --git a/src/userdb.c b/src/userdb.c index 5fc98e0..dde2693 100644 --- a/src/userdb.c +++ b/src/userdb.c @@ -57,7 +57,8 @@ void userdb_init(const char *file) if(fd >= 0) { if(read_uint32(fd) != USERDB_MAGIC) - error("bad userdb magic value"); + error("unknown user file format"); + size_t n_users = read_size(fd); for(size_t u = 0; u < n_users; ++u) { @@ -88,6 +89,13 @@ void userdb_init(const char *file) { struct object_t *obj = obj_read(fd); multimap_insert(data->objects, obj->name, obj); + + struct obj_alias_t *iter = obj->alias_list; + while(iter) + { + multimap_insert(data->objects, iter->alias, obj_dup(obj)); + iter = iter->next; + } } hash_insert(map, data->username, data); @@ -105,6 +113,7 @@ bool userdb_write(const char *file) if(fd < 0) return false; write_uint32(fd, USERDB_MAGIC); + write_size(fd, hash_size(map)); void *save, *ptr = map; while(1) @@ -118,7 +127,7 @@ bool userdb_write(const char *file) size_t n_objects; if(user->objects) - n_objects = multimap_size(user->objects); + n_objects = obj_count_noalias(user->objects); else n_objects = 0; @@ -139,8 +148,12 @@ bool userdb_write(const char *file) while(iter) { - debugf("Writing an object to disk...\n"); - obj_write(fd, iter->val); + struct object_t *obj = iter->val; + if(!strcmp(iter->key, obj->name)) + { + debugf("Writing an object to disk...\n"); + obj_write(fd, iter->val); + } iter = iter->next; } } @@ -254,6 +267,22 @@ struct userdata_t *userdb_iterate(void **save) return hash_iterate(map, save, NULL); } +bool userdb_add_obj(const char *name, struct object_t *obj) +{ + struct userdata_t *user = userdb_lookup(name); + + /* add aliases */ + struct obj_alias_t *alias = obj->alias_list; + while(alias) + { + debugf("userdb adding object alias %s\n", alias->alias); + multimap_insert(user->objects, alias->alias, obj_dup(obj)); + alias = alias->next; + } + + return multimap_insert(user->objects, obj->name, obj_dup(obj)); +} + /*** child request wrappers ***/ /* NOTE: these also work from the master, but it's better to use the * userdb_* funcs instead */ diff --git a/src/userdb.h b/src/userdb.h index d7eb120..52ade12 100644 --- a/src/userdb.h +++ b/src/userdb.h @@ -66,6 +66,8 @@ bool userdb_write(const char*); /* *save should be set to NULL on the first run */ struct userdata_t *userdb_iterate(void **save); +bool userdb_add_obj(const char *name, struct object_t *obj); + /*** child-only functions ***/ struct userdata_t *userdb_request_lookup(const char *name); bool userdb_request_add(struct userdata_t *data); diff --git a/src/util.c b/src/util.c index cf92dc2..29a5399 100644 --- a/src/util.c +++ b/src/util.c @@ -17,7 +17,19 @@ */ #include "globals.h" -#include + +void __attribute__((noreturn)) error(const char *fmt, ...) +{ + char buf[128]; + memset(buf, 0, sizeof(buf)); + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + perror(buf); + abort(); + exit(EXIT_FAILURE); +} void remove_cruft(char *str) { diff --git a/src/world.c b/src/world.c index 256aff1..1516b4c 100644 --- a/src/world.c +++ b/src/world.c @@ -22,7 +22,6 @@ #include "multimap.h" #include "room.h" #include "world.h" -#include "userdb.h" /* processed world data */ @@ -38,10 +37,11 @@ struct room_t *room_get(room_id id) void world_save(const char *fname) { int fd = open(fname, O_CREAT | O_WRONLY, 0644); + write_uint32(fd, WORLD_MAGIC); + write(fd, &world_sz, sizeof(world_sz)); write_string(fd, world_name); - write_uint64(fd, obj_get_idcounter()); /* write all the global verbs */ void *global_verbs = world_verb_map(); @@ -77,7 +77,7 @@ void world_save(const char *fname) /* now we serialize all the objects in this room */ - size_t n_objects = room_obj_count(i); + size_t n_objects = room_obj_count_noalias(i); write(fd, &n_objects, sizeof(n_objects)); room_id id = i; @@ -87,13 +87,15 @@ void world_save(const char *fname) const struct multimap_list *iter = room_obj_iterate(id, &save, NULL); if(!iter) break; + id = ROOM_NONE; while(iter) { struct object_t *obj = iter->val; if(!obj) break; - id = ROOM_NONE; - obj_write(fd, obj); + const char *name = iter->key; + if(!strcmp(name, obj->name)) + obj_write(fd, obj); iter = iter->next; } } @@ -111,7 +113,14 @@ void world_save(const char *fname) verb_map = NULL; verb_write(fd, verb); } + + /* and now user data... */ + if(world[i].data.hook_serialize) + world[i].data.hook_serialize(i, fd); } + + write_uint64(fd, obj_get_idcounter()); + close(fd); } @@ -147,7 +156,7 @@ bool world_load(const char *fname, const struct roomdata_t *data, size_t data_sz return false; if(read_uint32(fd) != WORLD_MAGIC) - return false; + error("unknown world file format"); if(world) world_free(); @@ -167,7 +176,7 @@ bool world_load(const char *fname, const struct roomdata_t *data, size_t data_sz return false; } - obj_set_idcounter(read_uint64(fd)); + obj_set_idcounter(1); size_t n_global_verbs = read_size(fd); for(unsigned i = 0; i < n_global_verbs; ++i) @@ -208,8 +217,14 @@ bool world_load(const char *fname, const struct roomdata_t *data, size_t data_sz error("duplicate verb '%s' in room '%s'", verb->name, world[i].data.name); } + + /* user data, if any */ + if(world[i].data.hook_deserialize) + world[i].data.hook_deserialize(i, fd); } + obj_set_idcounter(read_uint64(fd)); + close(fd); return true; } -- cgit v1.1