aboutsummaryrefslogtreecommitdiff
path: root/src/room.c
diff options
context:
space:
mode:
authorFranklin Wei <frankhwei536@gmail.com>2016-01-31 19:53:45 -0500
committerFranklin Wei <frankhwei536@gmail.com>2016-01-31 19:53:45 -0500
commit0730fc3924dd4e04efbe51287d1d69850404d05f (patch)
tree495d79d0dc26e39c9065c6ceb7d16b9a3e76561d /src/room.c
parent8405274a91e3652ee98a423608a8496ead1edc05 (diff)
downloadnetcosm-0.5.0-rc1.zip
netcosm-0.5.0-rc1.tar.gz
netcosm-0.5.0-rc1.tar.bz2
netcosm-0.5.0-rc1.tar.xz
bump version to 0.5.0-rc10.5.0-rc1
* implements objects using reference counts rather than copying * implements both room-local and global verbs * refactors the world_* functions into a separate module * numerous other changes
Diffstat (limited to 'src/room.c')
-rw-r--r--src/room.c286
1 files changed, 39 insertions, 247 deletions
diff --git a/src/room.c b/src/room.c
index de0950d..58563a8 100644
--- a/src/room.c
+++ b/src/room.c
@@ -22,17 +22,7 @@
#include "server.h"
#include "room.h"
#include "userdb.h"
-
-/* processed world data */
-
-static struct room_t *world;
-static size_t world_sz;
-static char *world_name;
-
-struct room_t *room_get(room_id id)
-{
- return world + id;
-}
+#include "world.h"
bool room_user_add(room_id id, struct child_data *child)
{
@@ -61,276 +51,78 @@ bool room_user_del(room_id id, struct child_data *child)
return false;
}
-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);
- for(unsigned i = 0; i < world_sz; ++i)
- {
- write_roomid(fd, &world[i].id);
- /* unique ID never changes */
- //write_string(fd, world[i].data.uniq_id);
- write_string(fd, world[i].data.name);
- write_string(fd, world[i].data.desc);
- /* adjacency strings not serialized, only adjacent IDs */
-
- /* callbacks are static, so are not serialized */
-
- write(fd, world[i].adjacent, sizeof(world[i].adjacent));
-
- /* now we serialize all the objects in this room */
-
- size_t n_objects = room_obj_count(i);
- write(fd, &n_objects, sizeof(n_objects));
-
- room_id id = i;
- void *save;
- while(1)
- {
- struct object_t *obj = room_obj_iterate(id, &save);
- if(!obj)
- break;
- id = ROOM_NONE;
- obj_write(fd, obj);
- }
- }
- close(fd);
-}
-
-static void room_free(struct room_t *room)
+void room_free(struct room_t *room)
{
hash_free(room->users);
room->users = NULL;
- hash_setfreedata_cb(room->objects, obj_free);
+
hash_free(room->objects);
room->objects = NULL;
+
+ hash_free(room->verbs);
+ room->verbs = NULL;
+
free(room->data.name);
free(room->data.desc);
}
-void world_free(void)
-{
- if(world)
- {
- if(world_name)
- free(world_name);
- for(unsigned i = 0; i < world_sz; ++i)
- {
- room_free(world + i);
- }
- free(world);
- world = NULL;
- }
-}
-
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
-
-/* initialize the room's hash tables */
-static void room_init_maps(struct room_t *room)
+struct object_t *room_obj_iterate(room_id room, void **save)
{
- room->users = hash_init((userdb_size() / 2) + 1, hash_djb, compare_strings);
-
- room->objects = hash_init(OBJMAP_SIZE, hash_djb, compare_strings);
- hash_setfreedata_cb(room->objects, obj_free);
+ if(room != ROOM_NONE)
+ return hash_iterate(room_get(room)->objects, save, NULL);
+ else
+ return hash_iterate(NULL, save, NULL);
}
-/**
- * Loads a world using data on disk and in memory.
- *
- * @param fname world file
- * @param data world module data
- * @param data_sz number of rooms in world module
- */
-bool world_load(const char *fname, const struct roomdata_t *data, size_t data_sz, const char *name)
+struct object_t *room_obj_get(room_id room, const char *name)
{
- int fd = open(fname, O_RDONLY);
- if(fd < 0)
- return false;
-
- if(read_uint32(fd) != WORLD_MAGIC)
- return false;
-
- if(world)
- world_free();
-
- read(fd, &world_sz, sizeof(world_sz));
-
- if(world_sz != data_sz)
- return false;
-
- world = calloc(world_sz, sizeof(struct room_t));
-
- world_name = read_string(fd);
- if(strcmp(name, world_name))
- {
- free(world_name);
- debugf("Incompatible world state.\n");
- return false;
- }
-
- for(unsigned i = 0; i < world_sz; ++i)
- {
- room_init_maps(world + i);
-
- world[i].id = read_roomid(fd);
- memcpy(&world[i].data, data + i, sizeof(struct roomdata_t));
- world[i].data.name = read_string(fd);
- world[i].data.desc = read_string(fd);
- if(read(fd, world[i].adjacent, sizeof(world[i].adjacent)) < 0)
- return false;
-
- size_t n_objects;
- if(read(fd, &n_objects, sizeof(n_objects)) != sizeof(n_objects))
- error("world file corrupt");
-
- for(unsigned j = 0; j < n_objects; ++j)
- {
- struct object_t *obj = obj_read(fd);
-
- if(!room_obj_add(i, obj))
- error("duplicate object name in room '%s'", world[i].data.name);
- }
- }
-
- close(fd);
- return true;
+ return hash_lookup(room_get(room)->objects, name);
}
-static SIMP_HASH(enum direction_t, dir_hash);
-static SIMP_EQUAL(enum direction_t, dir_equal);
-
-/* loads room data (supplied by the world module) into our internal format */
-void world_init(const struct roomdata_t *data, size_t sz, const char *name)
+size_t room_obj_count(room_id room)
{
- debugf("Loading world with %lu rooms.\n", sz);
- world = calloc(sz, sizeof(struct room_t));
- world_sz = 0;
- world_name = strdup(name);
-
- void *map = hash_init(sz / 2 + 1, hash_djb, compare_strings);
-
- for(size_t i = 0; i < sz; ++i)
- {
- world[i].id = i;
- memcpy(&world[i].data, &data[i], sizeof(data[i]));
-
- /* have to strdup these strings so they can be freed later */
- //world[i].uniq_id = strdup(world[i].uniq_id);
- world[i].data.name = strdup(world[i].data.name);
- world[i].data.desc = strdup(world[i].data.desc);
- debugf("Loading room '%s'\n", world[i].data.uniq_id);
-
- if(hash_insert(map, world[i].data.uniq_id, world + i))
- error("Duplicate room ID '%s'", world[i].data.uniq_id);
-
- for(int dir = 0; dir < NUM_DIRECTIONS; ++dir)
- {
- const char *adjacent_room = world[i].data.adjacent[dir];
- if(adjacent_room)
- {
- struct room_t *room = hash_lookup(map, adjacent_room);
- if(room)
- world[i].adjacent[dir] = room->id;
- }
- }
- room_init_maps(world + i);
-
- world_sz = i + 1;
- }
-
- /* second pass to fill in missing references */
- for(size_t i = 0; i < sz; ++i)
- {
- for(int dir = 0; dir < NUM_DIRECTIONS; ++dir)
- {
- const char *adjacent_room = world[i].data.adjacent[dir];
- if(adjacent_room)
- {
- struct room_t *room = hash_lookup(map, adjacent_room);
- if(room)
- world[i].adjacent[dir] = room->id;
- else
- error("unknown room '%s' referenced from '%s'",
- adjacent_room, world[i].data.uniq_id);
- }
- else
- world[i].adjacent[dir] = ROOM_NONE;
- }
- }
+ return hash_size(room_get(room)->objects);
+}
- struct direction_pair {
- enum direction_t dir, opp;
- } pairs[] = {
- { DIR_N, DIR_S },
- { DIR_NE, DIR_SW },
- { DIR_E, DIR_W },
- { DIR_SE, DIR_NW },
- { DIR_UP, DIR_DN },
- { DIR_IN, DIR_OT },
- };
+bool room_obj_del(room_id room, const char *name)
+{
+ return hash_remove(room_get(room)->objects, name);
+}
- void *dir_map = hash_init(ARRAYLEN(pairs) * 2, dir_hash, dir_equal);
- for(int n = 0; n < 2; ++n)
- {
- for(unsigned i = 0; i < ARRAYLEN(pairs); ++i)
- {
- if(!n)
- hash_insert(dir_map, &pairs[i].dir, &pairs[i].opp);
- else
- hash_insert(dir_map, &pairs[i].opp, &pairs[i].dir);
- }
- }
+#define OBJMAP_SIZE 8
+#define VERBMAP_SZ 8
- /* third pass to call all the init handlers and check accessibility */
- for(room_id i = 0; i < (int)world_sz; ++i)
- {
- if(world[i].data.hook_init)
- world[i].data.hook_init(world[i].id);
- /* check that all rooms are accessible */
- for(enum direction_t j = 0; j < NUM_DIRECTIONS; ++j)
- {
- if(world[i].adjacent[j] != ROOM_NONE)
- {
- enum direction_t *opp = hash_lookup(dir_map, &j);
- struct room_t *adj = room_get(world[i].adjacent[j]);
- if(adj->adjacent[*opp] != i)
- debugf("WARNING: Rooms '%s' and '%s' are one-way\n",
- world[i].data.uniq_id, adj->data.uniq_id);
- }
- }
- }
+/* initialize the room's hash tables */
+void room_init_maps(struct room_t *room)
+{
+ room->users = hash_init((userdb_size() / 2) + 1, hash_djb, compare_strings);
- hash_free(dir_map);
+ room->objects = hash_init(OBJMAP_SIZE, hash_djb, compare_strings);
+ hash_setfreedata_cb(room->objects, obj_free);
- hash_free(map);
-}
+ room->verbs = hash_init(VERBMAP_SZ,
+ hash_djb,
+ compare_strings);
-struct object_t *room_obj_iterate(room_id room, void **save)
-{
- if(room != ROOM_NONE)
- return hash_iterate(room_get(room)->objects, save, NULL);
- else
- return hash_iterate(NULL, save, NULL);
+ hash_setfreedata_cb(room->verbs, verb_free);
}
-struct object_t *room_obj_get(room_id room, const char *name)
+void *room_verb_map(room_id id)
{
- return hash_lookup(room_get(room)->objects, name);
+ return room_get(id)->verbs;
}
-size_t room_obj_count(room_id room)
+bool room_verb_add(room_id id, struct verb_t *verb)
{
- return hash_size(room_get(room)->objects);
+ return !hash_insert(room_get(id)->verbs, verb->name, verb);
}
-bool room_obj_del(room_id room, const char *name)
+bool room_verb_del(room_id id, const char *name)
{
- return hash_remove(room_get(room)->objects, name);
+ return hash_remove(room_get(id), name);
}