aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFranklin Wei <git@fwei.tk>2016-02-20 20:37:06 -0500
committerFranklin Wei <git@fwei.tk>2016-02-28 16:30:21 -0500
commit2c687e77cd9ae3fd01010d7b36c8d0082bb76315 (patch)
treeb8cd58cea075a3c94cb2f1417e6eaea27865b827 /src
parent02de31c48c021742c6245b711790f6d853866c36 (diff)
downloadnetcosm-2c687e77cd9ae3fd01010d7b36c8d0082bb76315.zip
netcosm-2c687e77cd9ae3fd01010d7b36c8d0082bb76315.tar.gz
netcosm-2c687e77cd9ae3fd01010d7b36c8d0082bb76315.tar.bz2
netcosm-2c687e77cd9ae3fd01010d7b36c8d0082bb76315.tar.xz
implements aliases and other assorted features/enhancements
Diffstat (limited to 'src')
-rw-r--r--src/client.c2
-rw-r--r--src/hash.c5
-rw-r--r--src/multimap.c10
-rw-r--r--src/multimap.h2
-rw-r--r--src/obj.c70
-rw-r--r--src/obj.h12
-rw-r--r--src/room.c89
-rw-r--r--src/room.h19
-rw-r--r--src/server.c21
-rw-r--r--src/server.h1
-rw-r--r--src/server_reqs.c133
-rw-r--r--src/userdb.c37
-rw-r--r--src/userdb.h2
-rw-r--r--src/util.c14
-rw-r--r--src/world.c29
15 files changed, 356 insertions, 90 deletions
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 <stdlib.h>
#include <string.h>
+/**
+ * @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 <sys/resource.h>
+
+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;
}