aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--SOURCES1
-rw-r--r--src/auth.c27
-rw-r--r--src/client.c20
-rw-r--r--src/hash.c23
-rw-r--r--src/hash.h2
-rw-r--r--src/room.c111
-rw-r--r--src/room.h47
-rw-r--r--src/server.c1
-rw-r--r--src/server_reqs.c79
-rw-r--r--src/server_reqs.h2
-rw-r--r--src/userdb.c94
-rw-r--r--src/userdb.h2
-rw-r--r--src/util.c48
-rw-r--r--src/util.h11
-rw-r--r--worlds/test.c2
16 files changed, 270 insertions, 202 deletions
diff --git a/Makefile b/Makefile
index f8d92db..c6dbca5 100644
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,7 @@ INCLUDES = -I src/ -I export/include/
WARNFLAGS = -Wall -Wextra -Wshadow -fno-strict-aliasing
-OPTFLAGS = -O3
+OPTFLAGS = -Og
DEBUGFLAGS = -g
CFLAGS = $(OPTFLAGS) $(DEBUGFLAGS) $(WARNFLAGS) -std=c99 $(INCLUDES)
diff --git a/SOURCES b/SOURCES
index 7ca5dd3..9cf792b 100644
--- a/SOURCES
+++ b/SOURCES
@@ -2,6 +2,7 @@ src/auth.c
src/client.c
src/hash.c
src/main.c
+src/obj.c
src/room.c
src/server.c
src/server_reqs.c
diff --git a/src/auth.c b/src/auth.c
index 2018273..b7af56d 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -77,15 +77,12 @@ static void add_user_internal(const char *name, const char *pass, int authlevel)
struct userdata_t userdata;
strncpy(userdata.username, name, sizeof(userdata.username));
-
memcpy(userdata.passhash, hexhash, sizeof(userdata.passhash));
free(hexhash);
userdata.priv = authlevel;
-
userdata.last_login = time(0);
-
memcpy(userdata.salt, salt, sizeof(salt));
userdb_request_add(&userdata);
@@ -229,27 +226,5 @@ struct userdata_t *auth_check(const char *name2, const char *pass2)
void auth_user_list(void)
{
- FILE *f = fopen(USERFILE, "r");
-
- flock(fileno(f), LOCK_SH);
-
- while(1)
- {
- char *line = NULL;
- char *save;
- size_t len = 0;
- if(getline(&line, &len, f) < 0)
- {
- free(line);
- fclose(f);
- return;
- }
- char *user = strdup(strtok_r(line, ":\r\n", &save));
- strtok_r(NULL, ":\r\n", &save);
- strtok_r(NULL, ":\r\n", &save);
- int priv = strtol(strtok_r(NULL, ":\r\n", &save), NULL, 0);
- out("User %s priv %d\n", user, priv);
- free(user);
- free(line);
- }
+ /* FIXME: todo */
}
diff --git a/src/client.c b/src/client.c
index 260d73d..3fab9cb 100644
--- a/src/client.c
+++ b/src/client.c
@@ -425,6 +425,17 @@ void client_look_at(char *obj)
send_master(REQ_LOOKAT, obj, strlen(obj) + 1);
}
+void client_take(char *obj)
+{
+ all_lower(obj);
+ send_master(REQ_TAKE, obj, strlen(obj) + 1);
+}
+
+void client_inventory(void)
+{
+ send_master(REQ_PRINTINVENTORY, NULL, 0);
+}
+
#define WSPACE " \t\r\n"
void client_main(int fd, struct sockaddr_in *addr, int total, int to, int from)
@@ -703,6 +714,15 @@ auth:
client_look_at(what);
}
}
+ else if(!strcmp(tok, "INVENTORY"))
+ {
+ client_inventory();
+ }
+ else if(!strcmp(tok, "TAKE"))
+ {
+ char *what = strtok_r(NULL, " ", &save);
+ client_take(what);
+ }
else if(!strcmp(tok, "WAIT"))
{
send_master(REQ_WAIT, NULL, 0);
diff --git a/src/hash.c b/src/hash.c
index a34e530..da15157 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -260,3 +260,26 @@ size_t hash_size(void *ptr)
struct hash_map *map = ptr;
return map->n_entries;
}
+
+void *hash_dup(void *ptr)
+{
+ struct hash_map *map = ptr;
+
+ struct hash_map *ret = calloc(1, sizeof(struct hash_map));
+ memcpy(ret, map, sizeof(*ret));
+
+ ret->table = calloc(ret->table_sz, sizeof(struct hash_node*));
+ ret->n_entries = 0;
+
+ void *save;
+ while(1)
+ {
+ void *key;
+ void *data = hash_iterate(ptr, &save, &key);
+ if(!data)
+ break;
+ ptr = NULL;
+ hash_insert(ret, key, data);
+ }
+ return ret;
+}
diff --git a/src/hash.h b/src/hash.h
index 4def8fc..c2ed749 100644
--- a/src/hash.h
+++ b/src/hash.h
@@ -87,3 +87,5 @@ void *hash_getkeyptr(void*, const void *key);
}
size_t hash_size(void*);
+
+void *hash_dup(void*);
diff --git a/src/room.c b/src/room.c
index d3f306a..df819a6 100644
--- a/src/room.c
+++ b/src/room.c
@@ -61,40 +61,6 @@ bool room_user_del(room_id id, struct child_data *child)
return false;
}
-void write_roomid(int fd, room_id *id)
-{
- write(fd, id, sizeof(*id));
-}
-
-void write_string(int fd, const char *str)
-{
- size_t len = strlen(str);
- write(fd, &len, sizeof(len));
- write(fd, str, len);
-}
-
-room_id read_roomid(int fd)
-{
- room_id ret;
- if(read(fd, &ret, sizeof(ret)) < 0)
- return ROOM_NONE;
- return ret;
-}
-
-char *read_string(int fd)
-{
- size_t sz;
- read(fd, &sz, sizeof(sz));
- char *ret = malloc(sz + 1);
- if(read(fd, ret, sz) < 0)
- {
- free(ret);
- return NULL;
- }
- ret[sz] = '\0';
- return ret;
-}
-
void world_save(const char *fname)
{
int fd = open(fname, O_CREAT | O_WRONLY, 0644);
@@ -129,13 +95,6 @@ void world_save(const char *fname)
break;
id = ROOM_NONE;
- write_string(fd, obj->class->class_name);
- write_string(fd, obj->name);
- write(fd, &obj->can_take, sizeof(obj->can_take));
- write(fd, &obj->list, sizeof(obj->list));
-
- if(obj->class->hook_serialize)
- obj->class->hook_serialize(fd, obj);
}
}
close(fd);
@@ -166,59 +125,28 @@ void world_free(void)
}
}
-/* map of class names -> object classes */
-static void *obj_class_map = NULL;
-
-struct object_t *obj_new(const char *class_name)
-{
- if(!obj_class_map)
- {
- extern const struct obj_class_t netcosm_obj_classes[];
- extern const size_t netcosm_obj_classes_sz;
- obj_class_map = hash_init(netcosm_obj_classes_sz / 2 + 1,
- hash_djb,
- compare_strings);
- for(unsigned i = 0; i < netcosm_obj_classes_sz; ++i)
- {
- if(hash_insert(obj_class_map,
- netcosm_obj_classes[i].class_name,
- netcosm_obj_classes + i))
- error("duplicate object class name");
- }
- }
-
- struct object_t *obj = calloc(1, sizeof(struct object_t));
-
- obj->class = hash_lookup(obj_class_map, class_name);
- if(!obj->class)
- {
- free(obj);
- error("unknown object class '%s'", class_name);
- }
- else
- return obj;
-}
-
-bool obj_add(room_id room, struct object_t *obj)
+bool room_obj_add(room_id room, struct object_t *obj)
{
return !hash_insert(room_get(room)->objects, obj->name, obj);
}
#define OBJMAP_SIZE 8
+static void free_obj(void *ptr)
+{
+ struct object_t *obj = ptr;
+ if(obj->class->hook_destroy)
+ obj->class->hook_destroy(obj);
+ free(obj);
+}
+
/* initialize the room's hash tables */
static void room_init_maps(struct room_t *room)
{
room->users = hash_init((userdb_size() / 2) + 1, hash_djb, compare_strings);
- room->objects = hash_init(OBJMAP_SIZE, hash_djb, compare_strings);
-}
-bool read_bool(int fd)
-{
- bool ret;
- if(read(fd, &ret, sizeof(ret)) != sizeof(ret))
- error("unexpected EOF");
- return ret;
+ room->objects = hash_init(OBJMAP_SIZE, hash_djb, compare_strings);
+ hash_setfreedata_cb(room->objects, free_obj);
}
/**
@@ -273,15 +201,9 @@ bool world_load(const char *fname, const struct roomdata_t *data, size_t data_sz
for(unsigned j = 0; j < n_objects; ++j)
{
- const char *class_name = read_string(fd);
- struct object_t *obj = obj_new(class_name);
- obj->name = read_string(fd);
- obj->can_take = read_bool(fd);
- obj->list = read_bool(fd);
- if(obj->class->hook_deserialize)
- obj->class->hook_deserialize(fd, obj);
-
- if(!obj_add(i, obj))
+ struct object_t *obj = obj_read(fd);
+
+ if(!room_obj_add(i, obj))
error("duplicate object name in room '%s'", world[i].data.name);
}
}
@@ -416,3 +338,8 @@ size_t room_obj_count(room_id room)
{
return hash_size(room_get(room)->objects);
}
+
+bool room_obj_del(room_id room, const char *name)
+{
+ return hash_remove(room_get(room)->objects, name);
+}
diff --git a/src/room.h b/src/room.h
index 3738c83..88de823 100644
--- a/src/room.h
+++ b/src/room.h
@@ -18,6 +18,10 @@
#pragma once
+#include "globals.h"
+
+#include "obj.h"
+
/* Our world is an array of rooms, each having a list of objects in
them, as well as actions that can be performed in the room. Objects
are added by hooks in rooms, which are provided by the world
@@ -29,36 +33,6 @@ typedef struct child_data user_t;
enum direction_t { DIR_N = 0, DIR_NE, DIR_E, DIR_SE, DIR_S, DIR_SW, DIR_W, DIR_NW, DIR_UP, DIR_DN, DIR_IN, DIR_OT, NUM_DIRECTIONS };
-/* Objects belong to an object class. Objects define their object
- * class through the class name, which is converted to a class ID
- * internally.
- */
-
-struct object_t;
-
-struct obj_class_t {
- const char *class_name;
-
- void (*hook_serialize)(int fd, struct object_t*);
- void (*hook_deserialize)(int fd, struct object_t*);
- bool (*hook_take)(struct object_t*, user_t *user);
- void (*hook_drop)(struct object_t*, user_t *user);
- void (*hook_use)(struct object_t*, user_t *user);
- void (*hook_destroy)(struct object_t*);
- const char* (*hook_desc)(struct object_t*, user_t*);
-};
-
-struct object_t {
- struct obj_class_t *class;
-
- const char *name; /* no articles: "a", "an", "the" */
-
- bool can_take;
- bool list;
-
- void *userdata;
-};
-
/* the data we get from a world module */
struct roomdata_t {
/* the non-const pointers can be modified by the world module */
@@ -103,22 +77,21 @@ struct room_t *room_get(room_id id);
bool room_user_add(room_id id, struct child_data *child);
bool room_user_del(room_id id, struct child_data *child);
-/* returns a new object of class 'c' */
-struct object_t *obj_new(const char *c);
-
-/* new should point to a new object allocated with obj_new(), with
- * 'name' properly set */
-bool obj_add(room_id room, struct object_t *obj);
-
/* on the first call, room should be a valid room id, and *save should
* point to a void pointer. On subsequent calls, room should be
* ROOM_NONE, and *save should remain unchanged from the previous
* call */
struct object_t *room_obj_iterate(room_id room, void **save);
+/* new should point to a new object allocated with obj_new(), with
+ * 'name' properly set */
+bool room_obj_add(room_id room, struct object_t *obj);
+
/* obj should be all lowercase */
struct object_t *room_obj_get(room_id room, const char *obj);
size_t room_obj_count(room_id room);
+bool room_obj_del(room_id room, const char *name);
+
void world_free(void);
diff --git a/src/server.c b/src/server.c
index 105b648..d81075c 100644
--- a/src/server.c
+++ b/src/server.c
@@ -243,6 +243,7 @@ static void new_connection_cb(EV_P_ ev_io *w, int revents)
{
/* child */
are_child = true;
+
close(readpipe[0]);
close(outpipe[1]);
close(server_socket);
diff --git a/src/server_reqs.c b/src/server_reqs.c
index 0c4c710..689c2be 100644
--- a/src/server_reqs.c
+++ b/src/server_reqs.c
@@ -272,6 +272,51 @@ static void req_look_at(unsigned char *data, size_t datalen, struct child_data *
}
}
+static void req_take(unsigned char *data, size_t datalen, struct child_data *sender)
+{
+ (void) datalen;
+ struct object_t *obj = room_obj_get(sender->room, (const char*)data);
+ if(obj)
+ {
+ struct object_t *dup = obj_dup(obj);
+ hash_insert(userdb_lookup(sender->user)->objects,
+ dup->name, dup);
+
+ room_obj_del(sender->room, (const char*)data);
+
+ world_save(WORLDFILE);
+ }
+ else
+ {
+ const char *msg = "I don't know what that is.\n";
+ send_packet(sender, REQ_BCASTMSG, (void*)msg, strlen(msg));
+ }
+}
+
+static void req_inventory(unsigned char *data, size_t datalen, struct child_data *sender)
+{
+ (void) datalen;
+ (void) data;
+
+ void *ptr = userdb_lookup(sender->user)->objects, *save;
+ char buf[MSG_MAX] = "You currently have:\n";
+
+ send_packet(sender, REQ_BCASTMSG, (void*)buf, strlen(buf));
+
+ while(1)
+ {
+ struct object_t *obj = hash_iterate(ptr, &save, NULL);
+ if(!obj)
+ break;
+ ptr = NULL;
+ int len = snprintf(buf, sizeof(buf), "A %s\n", obj->name);
+ send_packet(sender, REQ_BCASTMSG, (void*)buf, len);
+ }
+ const char *msg = "Nothing!\n";
+ if(ptr)
+ send_packet(sender, REQ_BCASTMSG, (void*)msg, strlen(msg));
+}
+
static const struct child_request {
unsigned char code;
@@ -286,22 +331,24 @@ static const struct child_request {
void (*finalize)(unsigned char *data, size_t len, struct child_data *sender);
} requests[] = {
- { REQ_NOP, false, CHILD_NONE, NULL, NULL, },
- { REQ_BCASTMSG, true, CHILD_ALL, req_pass_msg, NULL, },
- { REQ_LISTCLIENTS, false, CHILD_ALL, req_send_clientinfo, req_send_geninfo, },
- { REQ_CHANGESTATE, true, CHILD_SENDER, req_change_state, NULL, },
- { REQ_CHANGEUSER, true, CHILD_SENDER, req_change_user, NULL, },
- { REQ_KICK, true, CHILD_ALL, req_kick_client, NULL, },
- { REQ_WAIT, false, CHILD_NONE, NULL, req_wait, },
- { REQ_GETROOMDESC, false, CHILD_NONE, NULL, req_send_desc, },
- { REQ_GETROOMNAME, false, CHILD_NONE, NULL, req_send_roomname, },
- { REQ_SETROOM, true, CHILD_NONE, NULL, req_set_room, },
- { REQ_MOVE, true, CHILD_NONE, NULL, req_move_room, },
- { REQ_GETUSERDATA, true, CHILD_NONE, NULL, req_send_user, },
- { REQ_DELUSERDATA, true, CHILD_NONE, NULL, req_del_user, },
- { REQ_ADDUSERDATA, true, CHILD_NONE, NULL, req_add_user, },
- { REQ_KICKALL, true, CHILD_ALL_BUT_SENDER, req_kick_always, NULL, },
- { REQ_LOOKAT, true, CHILD_NONE, NULL, req_look_at, },
+ { REQ_NOP, false, CHILD_NONE, NULL, NULL, },
+ { REQ_BCASTMSG, true, CHILD_ALL, req_pass_msg, NULL, },
+ { REQ_LISTCLIENTS, false, CHILD_ALL, req_send_clientinfo, req_send_geninfo, },
+ { REQ_CHANGESTATE, true, CHILD_SENDER, req_change_state, NULL, },
+ { REQ_CHANGEUSER, true, CHILD_SENDER, req_change_user, NULL, },
+ { REQ_KICK, true, CHILD_ALL, req_kick_client, NULL, },
+ { REQ_WAIT, false, CHILD_NONE, NULL, req_wait, },
+ { REQ_GETROOMDESC, false, CHILD_NONE, NULL, req_send_desc, },
+ { REQ_GETROOMNAME, false, CHILD_NONE, NULL, req_send_roomname, },
+ { REQ_SETROOM, true, CHILD_NONE, NULL, req_set_room, },
+ { REQ_MOVE, true, CHILD_NONE, NULL, req_move_room, },
+ { REQ_GETUSERDATA, true, CHILD_NONE, NULL, req_send_user, },
+ { REQ_DELUSERDATA, true, CHILD_NONE, NULL, req_del_user, },
+ { REQ_ADDUSERDATA, true, CHILD_NONE, NULL, req_add_user, },
+ { REQ_KICKALL, true, CHILD_ALL_BUT_SENDER, req_kick_always, NULL, },
+ { REQ_LOOKAT, true, CHILD_NONE, NULL, req_look_at, },
+ { REQ_TAKE, true, CHILD_NONE, NULL, req_take },
+ { REQ_PRINTINVENTORY, false, CHILD_NONE, NULL, req_inventory },
//{ REQ_ROOMMSG, true, CHILD_ALL, req_send_room_msg, NULL, },
};
diff --git a/src/server_reqs.h b/src/server_reqs.h
index f148c3e..8b455ce 100644
--- a/src/server_reqs.h
+++ b/src/server_reqs.h
@@ -39,6 +39,8 @@
#define REQ_ALLDONE 17 /* child: break out of send_master() */
#define REQ_KICKALL 18 /* server: kick everyone except the sender */
#define REQ_LOOKAT 19 /* server: send object description */
+#define REQ_TAKE 20 /* server: add object to user inventory */
+#define REQ_PRINTINVENTORY 21 /* server: print user inventory */
/* child states, sent as an int to the master */
#define STATE_INIT 0 /* initial state */
diff --git a/src/userdb.c b/src/userdb.c
index 3a7ebbc..e107a6c 100644
--- a/src/userdb.c
+++ b/src/userdb.c
@@ -26,51 +26,58 @@
static void *map = NULL;
static char *db_file = NULL;
+static void free_userdata(void *ptr)
+{
+ struct userdata_t *data = ptr;
+ hash_free(data->objects);
+ free(data);
+}
+
/*
- * the user DB is stored on disk as an ASCII database
+ * the user DB is stored on disk as an binary flat file
*
* this is then loaded into fixed-sized hash map at init
- * TODO: implement with B-tree
+ * TODO: re-implement with B-tree
*/
void userdb_init(const char *file)
{
db_file = strdup(file);
- /* FILE* for getline() */
- FILE *f = fopen(file, "r");
+ int fd = open(file, O_RDONLY);
map = hash_init(256, hash_djb, compare_strings);
- hash_setfreedata_cb(map, free);
+ hash_setfreedata_cb(map, free_userdata);
- char *format;
- asprintf(&format, "%%%d[a-z0-9 ]:%%%d[A-Z]:%%%ds:%%d:%%ld\n",
- MAX_NAME_LEN, SALT_LEN, AUTH_HASHLEN * 2);
-
- if(f)
+ /* 0 is a valid fd */
+ if(fd >= 0)
{
while(1)
{
struct userdata_t *data = calloc(1, sizeof(*data));
- int ret = fscanf(f, format,
- data->username,
- data->salt,
- data->passhash,
- &data->priv,
- &data->last_login);
+ if(read(fd, data, sizeof(*data)) != sizeof(*data))
+ break;
- if(ret != 5)
- {
- free(data);
+ size_t n_objects;
+ if(read(fd, &n_objects, sizeof(n_objects)) != sizeof(n_objects))
break;
+
+ data->objects = hash_init(MIN(8, n_objects),
+ hash_djb,
+ compare_strings);
+
+ debugf("READING %d OBJECTS INTO INVENTORY\n", n_objects);
+
+ for(unsigned i = 0; i < n_objects; ++i)
+ {
+ struct object_t *obj = obj_read(fd);
+ hash_insert(data->objects, obj->name, obj);
}
hash_insert(map, data->username, data);
}
- fclose(f);
+ close(fd);
}
-
- free(format);
}
void userdb_write(const char *file)
@@ -83,12 +90,34 @@ void userdb_write(const char *file)
ptr = NULL;
if(!user)
break;
- dprintf(fd, "%s:%*s:%*s:%d:%ld\n",
- user->username,
- SALT_LEN, user->salt,
- AUTH_HASHLEN*2, user->passhash,
- user->priv,
- user->last_login);
+
+ write(fd, user, sizeof(*user));
+
+ size_t n_objects;
+ if(user->objects)
+ n_objects = hash_size(user->objects);
+ else
+ n_objects = 0;
+
+ write(fd, &n_objects, sizeof(n_objects));
+
+ debugf("WRITING %d OBJECTS\n", n_objects);
+
+ /* write objects */
+
+ if(n_objects)
+ {
+ void *objptr = user->objects, *objsave;
+ while(1)
+ {
+ struct object_t *obj = hash_iterate(objptr, &objsave, NULL);
+ if(!obj)
+ break;
+ objptr = NULL;
+ debugf("WRITING OBJECT %s\n", obj->name);
+ obj_write(fd, obj);
+ }
+ }
}
close(fd);
}
@@ -114,6 +143,13 @@ struct userdata_t *userdb_add(struct userdata_t *data)
struct userdata_t *new = calloc(1, sizeof(*new)); /* only in C! */
memcpy(new, data, sizeof(*new));
+ /* don't overwrite their inventory */
+ struct userdata_t *old = userdb_lookup(new->username);
+ if(old && old->objects)
+ new->objects = hash_dup(old->objects);
+ else
+ new->objects = hash_init(8, hash_djb, compare_strings);
+
struct userdata_t *ret;
if((ret = hash_insert(map, new->username, new))) /* already exists */
@@ -129,7 +165,7 @@ struct userdata_t *userdb_add(struct userdata_t *data)
void userdb_shutdown(void)
{
- if(map && db_file)
+ if(map && db_file && !are_child)
userdb_write(db_file);
if(map)
{
diff --git a/src/userdb.h b/src/userdb.h
index f499b78..c4705a9 100644
--- a/src/userdb.h
+++ b/src/userdb.h
@@ -36,6 +36,8 @@ struct userdata_t {
priv_t priv;
room_id room;
time_t last_login;
+
+ void *objects; /* hash of object names -> objects */
};
/* call before using anything else */
diff --git a/src/util.c b/src/util.c
index e681ca0..a349d5a 100644
--- a/src/util.c
+++ b/src/util.c
@@ -66,3 +66,51 @@ void all_lower(char *s)
s++;
}
}
+
+void write_roomid(int fd, room_id *id)
+{
+ write(fd, id, sizeof(*id));
+}
+
+void write_string(int fd, const char *str)
+{
+ size_t len = strlen(str);
+ write(fd, &len, sizeof(len));
+ write(fd, str, len);
+}
+
+room_id read_roomid(int fd)
+{
+ room_id ret;
+ if(read(fd, &ret, sizeof(ret)) < 0)
+ return ROOM_NONE;
+ return ret;
+}
+
+char *read_string(int fd)
+{
+ size_t sz;
+ read(fd, &sz, sizeof(sz));
+ char *ret = malloc(sz + 1);
+ if(read(fd, ret, sz) < 0)
+ {
+ free(ret);
+ return NULL;
+ }
+ ret[sz] = '\0';
+ return ret;
+}
+
+bool read_bool(int fd)
+{
+ bool ret;
+ if(read(fd, &ret, sizeof(ret)) != sizeof(ret))
+ error("unexpected EOF");
+ return ret;
+}
+
+void write_bool(int fd, bool b)
+{
+ if(write(fd, &b, sizeof(b)) != sizeof(b))
+ error("write failed");
+}
diff --git a/src/util.h b/src/util.h
index 0f05a89..fefd735 100644
--- a/src/util.h
+++ b/src/util.h
@@ -19,9 +19,20 @@
/* You should use #pragma once everywhere. */
#pragma once
+#include "room.h"
+
/* utility functions */
void __attribute__((noreturn,format(printf,1,2))) error(const char *fmt, ...);
void __attribute__((format(printf,4,5))) debugf_real(const char*, int, const char*, const char *fmt, ...);
void remove_cruft(char*);
void all_upper(char*);
void all_lower(char*);
+
+void write_string(int fd, const char *str);
+char *read_string(int fd);
+
+void write_roomid(int fd, room_id *id);
+room_id read_roomid(int fd);
+
+void write_bool(int fd, bool b);
+bool read_bool(int fd);
diff --git a/worlds/test.c b/worlds/test.c
index d009e2c..3f43a7a 100644
--- a/worlds/test.c
+++ b/worlds/test.c
@@ -14,7 +14,7 @@ static void portal_init(room_id id)
new->userdata = malloc(sizeof(double));
double p = 3.14159265358979323846L;
memcpy(new->userdata, &p, sizeof(p));
- obj_add(id, new);
+ room_obj_add(id, new);
}
const struct roomdata_t netcosm_world[] = {