diff options
| author | Franklin Wei <git@fwei.tk> | 2016-01-25 16:10:46 -0500 |
|---|---|---|
| committer | Franklin Wei <git@fwei.tk> | 2016-01-25 16:10:46 -0500 |
| commit | a1acf425cfb00a41c7862c915eb024207658c814 (patch) | |
| tree | fcee7cf8a1c204b779ab50a3545e8671012d7643 /src | |
| parent | d351bb34ba256d6fbf0869485bcf75ec46646e74 (diff) | |
| download | netcosm-a1acf425cfb00a41c7862c915eb024207658c814.zip netcosm-a1acf425cfb00a41c7862c915eb024207658c814.tar.gz netcosm-a1acf425cfb00a41c7862c915eb024207658c814.tar.bz2 netcosm-a1acf425cfb00a41c7862c915eb024207658c814.tar.xz | |
inventory works
Diffstat (limited to 'src')
| -rw-r--r-- | src/auth.c | 27 | ||||
| -rw-r--r-- | src/client.c | 20 | ||||
| -rw-r--r-- | src/hash.c | 23 | ||||
| -rw-r--r-- | src/hash.h | 2 | ||||
| -rw-r--r-- | src/room.c | 111 | ||||
| -rw-r--r-- | src/room.h | 47 | ||||
| -rw-r--r-- | src/server.c | 1 | ||||
| -rw-r--r-- | src/server_reqs.c | 79 | ||||
| -rw-r--r-- | src/server_reqs.h | 2 | ||||
| -rw-r--r-- | src/userdb.c | 94 | ||||
| -rw-r--r-- | src/userdb.h | 2 | ||||
| -rw-r--r-- | src/util.c | 48 | ||||
| -rw-r--r-- | src/util.h | 11 |
13 files changed, 267 insertions, 200 deletions
@@ -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); @@ -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; +} @@ -87,3 +87,5 @@ void *hash_getkeyptr(void*, const void *key); } size_t hash_size(void*); + +void *hash_dup(void*); @@ -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); +} @@ -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 */ @@ -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"); +} @@ -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); |