From 2a63c965d862c5db01cce5c7a857717a927db2ac Mon Sep 17 00:00:00 2001 From: David Thomas Bukowski Date: Thu, 4 Jun 2020 12:48:42 -0500 Subject: [PATCH 01/14] Finished part of code to convert json_objects to objects. --- src/wdl/src/load_wdz_common.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/wdl/src/load_wdz_common.c b/src/wdl/src/load_wdz_common.c index b76e02cf43..57ede1ee3e 100644 --- a/src/wdl/src/load_wdz_common.c +++ b/src/wdl/src/load_wdz_common.c @@ -6,12 +6,24 @@ #include "wdl/load_wdz_internal.h" #include "wdl/wdl_common.h" // to get obj_t +#include "wdl/objstore.h" -obj_t *convert_j_obj_to_game_obj(json_object *j_game_obj, char *j_name) +object_t *convert_j_obj_to_game_obj(json_object *j_game_obj, char *j_name) { - // dummy function for now. - // Waiting on new obj_t implementation before we can write this conversion! + object_t* retobject = malloc(sizeof(object_t)); + /* Loops through all attributes in the object*/ + json_object_object_foreach(j_game_obj, attr_name, j_value) + { + if (attr_name == "id"){ + strcpy(retobject->id, json_object_get_string(j_value)); + } else{ + //Gets type of the object and sets objtype_t based on value returned by + //json_type json_object_get_type (j_value) + + } + + } return NULL; } From 89d37b5359ec48f1f828292d134189305d9a6b8c Mon Sep 17 00:00:00 2001 From: David Thomas Bukowski Date: Fri, 5 Jun 2020 01:06:01 -0500 Subject: [PATCH 02/14] Added getting type, now will have to figure out how to add attributes and test --- src/wdl/src/load_wdz_common.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/wdl/src/load_wdz_common.c b/src/wdl/src/load_wdz_common.c index 57ede1ee3e..b68bea0a41 100644 --- a/src/wdl/src/load_wdz_common.c +++ b/src/wdl/src/load_wdz_common.c @@ -8,10 +8,13 @@ #include "wdl/wdl_common.h" // to get obj_t #include "wdl/objstore.h" +objtype_t get_type_from_name(char* name){ +} object_t *convert_j_obj_to_game_obj(json_object *j_game_obj, char *j_name) { object_t* retobject = malloc(sizeof(object_t)); + retobject->type = get_type_from_name(j_name); /* Loops through all attributes in the object*/ json_object_object_foreach(j_game_obj, attr_name, j_value) { @@ -19,7 +22,11 @@ object_t *convert_j_obj_to_game_obj(json_object *j_game_obj, char *j_name) strcpy(retobject->id, json_object_get_string(j_value)); } else{ //Gets type of the object and sets objtype_t based on value returned by - //json_type json_object_get_type (j_value) + //json_type json_object_get_type (j_value) + if (json_object_is_type(j_value, json_type_boolean)) { + + } + } From 5d73bb50606bca65a0eb76bd09a15f4c16f459dd Mon Sep 17 00:00:00 2001 From: Nam Anh Dinh Date: Fri, 5 Jun 2020 11:01:54 -0500 Subject: [PATCH 03/14] now checks for json path; safer wdz loading - changed obj to object in places - changed TYPE_NONE and TYPE_ERROR - dummy j_obj to game_obj conversion --- include/wdl/load_wdz.h | 6 +- include/wdl/object.h | 16 +++--- src/wdl/src/load_game.c | 17 +++++- src/wdl/src/load_wdz_common.c | 103 +++++++++++++++++++++++++--------- src/wdl/src/load_wdz_lzip.c | 9 +++ src/wdl/src/object.c | 2 +- 6 files changed, 110 insertions(+), 43 deletions(-) diff --git a/include/wdl/load_wdz.h b/include/wdl/load_wdz.h index 7bec3aa44d..41fc955f3a 100644 --- a/include/wdl/load_wdz.h +++ b/include/wdl/load_wdz.h @@ -4,11 +4,7 @@ #include #include -// Dummy forward declarations. Will replace with the proper objstore_t -// and obj_t included from the correct modules later. -typedef int objstore_t; -//typedef int obj_t; // commenting this out to not conflict with old libobj obj_t - +#include "wdl/objstore.h" /* * populate_objstore_from_wdz: diff --git a/include/wdl/object.h b/include/wdl/object.h index 5b5cfc142a..632ed1711f 100644 --- a/include/wdl/object.h +++ b/include/wdl/object.h @@ -18,8 +18,8 @@ */ typedef enum objtype { - TYPE_ERR = -1, - TYPE_NONE = 0, + TYPE_UNDEFINED = -1, + TYPE_OTHER = 0, TYPE_PLAYER = 1, TYPE_ROOM = 2, TYPE_ITEM = 3, @@ -41,7 +41,7 @@ typedef enum assettype ASSET_SOUND = 2 } assettype_t; -typedef struct obj obj_t; // forward declaration so attribute_t can use +typedef struct object object_t; // forward declaration so attribute_t can use /* * a union representing the information that can be stored in an attribute @@ -52,7 +52,7 @@ union attr_data char c; char *s; int i; - obj_t *o; + object_t *o; }; /* @@ -78,9 +78,9 @@ typedef struct attr } obj_attr_t; /* - * obj_t: a struct describing a .json object. + * object_t: a struct describing a .json object. */ -typedef struct obj +typedef struct object { // The id used to identify this object char id[MAXLEN_ID + 1]; @@ -144,7 +144,7 @@ int init_object(object_t *obj, char *id); * returns: * - always returns SUCCESS */ -int obj_free(object_t *obj); +int object_free(object_t *obj); /* * get_object: retrieves an object from a .wdz archive @@ -154,7 +154,7 @@ int obj_free(object_t *obj); * - id: the object's id * * returns: - * - a pointer to the requested object as a obj_t struct member. + * - a pointer to the requested object as a object_t struct member. */ object_t* get_object(char* type, char* id); diff --git a/src/wdl/src/load_game.c b/src/wdl/src/load_game.c index c67a178fc7..6787fbb08b 100644 --- a/src/wdl/src/load_game.c +++ b/src/wdl/src/load_game.c @@ -19,7 +19,6 @@ */ game_t *load_wdl(char *path_to_yaml) { - // WDZ loading monkeypatch. // Intercepts chiventure if wdz file is passed in as CLI argument, // and prints JSON contents for debug. @@ -29,7 +28,21 @@ game_t *load_wdl(char *path_to_yaml) int n_jsons = 0; printf("Detected wdz file. Attempting to load wdz and printing the json files...\n"); printf("Note that loading wdz is not functional right now.\n"); - populate_objstore_from_wdz(NULL, &n_jsons, path_to_yaml); + object_t *obj_store_init_obj = new_object("__empty__"); + /* commenting all this out because new_object always returns NULL for now. */ + // if (!obj_store_init_obj) + // { + // fprintf(stderr,"could not allocate dummy object for objstore\n"); + // return NULL; + // } + // // ideally this should be handled by new_object itself + // obj_store_init_obj->type = TYPE_OTHER; + objstore_t *obj_store = new_objstore(obj_store_init_obj); + + populate_objstore_from_wdz(obj_store, &n_jsons, path_to_yaml); + + /* commenting this out for now because new_object always returns NULL for now. */ + //free_objstore(&obj_store, find_objstore(&obj_store, "__empty__", TYPE_OTHER)); printf("Number of JSON files found: %d\n", n_jsons); return NULL; } diff --git a/src/wdl/src/load_wdz_common.c b/src/wdl/src/load_wdz_common.c index 57ede1ee3e..5c0a880408 100644 --- a/src/wdl/src/load_wdz_common.c +++ b/src/wdl/src/load_wdz_common.c @@ -5,22 +5,76 @@ #include "wdl/load_wdz_internal.h" -#include "wdl/wdl_common.h" // to get obj_t -#include "wdl/objstore.h" +#define SAME_STRING(s1, s2) (strcmp(s1, s2) == (0)) +#define TYPE_PLAYER_STR "player" +#define TYPE_ROOM_STR "rooms" +#define TYPE_ITEM_STR "items" +#define TYPE_ACTION_STR "actions" +#define TYPE_GCONDITION_STR "globalconditions" +#define TYPE_DIALOG_STR "dialog" +#define TYPE_NPC_STR "npcs" + +objtype_t match_j_name_to_game_obj_type(char *j_name) +{ + objtype_t game_obj_type; + if (SAME_STRING(j_name, TYPE_PLAYER_STR)) + { + game_obj_type = TYPE_PLAYER; + } + else if (SAME_STRING(j_name, TYPE_ROOM_STR)) + { + game_obj_type = TYPE_ROOM; + } + else if (SAME_STRING(j_name, TYPE_ITEM_STR)) + { + game_obj_type = TYPE_ITEM; + } + else if (SAME_STRING(j_name, TYPE_ACTION_STR)) + { + game_obj_type = TYPE_ACTION; + } + else if (SAME_STRING(j_name, TYPE_GCONDITION_STR)) + { + game_obj_type = TYPE_GCONDITION; + } + else if (SAME_STRING(j_name, TYPE_NPC_STR)) + { + game_obj_type = TYPE_NPC; + } + else if (SAME_STRING(j_name, TYPE_DIALOG_STR)) + { + game_obj_type = TYPE_DIALOG; + } + else + { + game_obj_type = TYPE_UNDEFINED; + } + + return game_obj_type; +} object_t *convert_j_obj_to_game_obj(json_object *j_game_obj, char *j_name) { - object_t* retobject = malloc(sizeof(object_t)); - /* Loops through all attributes in the object*/ - json_object_object_foreach(j_game_obj, attr_name, j_value) + object_t* game_obj = malloc(sizeof(object_t)); + if (!game_obj) { - if (attr_name == "id"){ - strcpy(retobject->id, json_object_get_string(j_value)); - } else{ - //Gets type of the object and sets objtype_t based on value returned by - //json_type json_object_get_type (j_value) + fprintf(stderr, "Unable to allocate memory for game object\n"); + return NULL; + } + /* First set the game object type (e.g. a room, or an item */ + game_obj->type = match_j_name_to_game_obj_type(j_name); + /* Loops through all attributes in the object */ + json_object_object_foreach(j_game_obj, attr_name, j_value) + { + if (strcmp(attr_name, "id") == 0) + { + strcpy(game_obj->id, json_object_get_string(j_value)); + } + else + { + // awaiting add_attr functions to add a new attribute to object here. } } @@ -28,13 +82,6 @@ object_t *convert_j_obj_to_game_obj(json_object *j_game_obj, char *j_name) } -int add_objstore(objstore_t *obj_store, obj_t *game_obj) -{ - // dummy function for now. - return FAILURE; -} - - /* See load_wdz_internal.h */ bool filename_extension_is(const char *ext, const char *str) { @@ -53,8 +100,9 @@ int load_game_objects_from_json_object json_object *j_obj ) { - // // Commenting this out because we don't have an objstore right now - // // so this is always NULL. + // // Commenting this out because while we have objstore_t init ready, + // // it still depends on object_t init, which always returns NULL, + // // so the objstore ends up always NULL. // if (!obj_store) // { // return FAILURE; @@ -72,12 +120,13 @@ int load_game_objects_from_json_object for (int i = 0; i < n_objects; i++) // for each json_object in the array { json_object *j_game_obj = json_object_array_get_idx(j_value, i); - obj_t *game_obj = convert_j_obj_to_game_obj(j_game_obj, j_name); + object_t *game_obj = convert_j_obj_to_game_obj(j_game_obj, j_name); if (!game_obj) { - return FAILURE; + fprintf(stderr, "Couldn't convert json object %s[%d] into game object\n", j_name, i); + continue; } - add_objstore(obj_store, game_obj); + add_objstore(&obj_store, game_obj); } return SUCCESS; } @@ -85,15 +134,15 @@ int load_game_objects_from_json_object { // The only file with an object-type value as top-level // is players.json. Other special cases can go here, but unlikely. - printf("Found player object.\n"); - json_object *j_player_obj; - json_object_object_get_ex(j_value, j_name, &j_player_obj); - obj_t *player = convert_j_obj_to_game_obj(j_player_obj, j_name); + + object_t *player = convert_j_obj_to_game_obj(j_value, j_name); + printf("Parsed player json.\n"); + if (!player) { return FAILURE; } - add_objstore(obj_store, player); + add_objstore(&obj_store, player); return SUCCESS; } else diff --git a/src/wdl/src/load_wdz_lzip.c b/src/wdl/src/load_wdz_lzip.c index 5cd22efb67..918227ecc7 100644 --- a/src/wdl/src/load_wdz_lzip.c +++ b/src/wdl/src/load_wdz_lzip.c @@ -16,6 +16,8 @@ #include "wdl/load_wdz_internal.h" +#define GAME_DIR "game/" + // maximum buffer size for json file, in bytes. This is currently set to 2 MiB. #define MAXBUFSIZE ((zip_int64_t)0x200000) @@ -102,6 +104,13 @@ int populate_objstore_from_wdz zip_file_t *curr_file = zip_fopen_index(wdz, i, 0); { // Within the context of this opened entry... const char *j_path_and_name = zip_get_name(wdz, i, 0); + + // check for actual correct path game_name/game/ before reading + if (strncmp(strchr(j_path_and_name, '/') + 1, GAME_DIR, strlen(GAME_DIR))) + { + continue; + } + struct json_object *j_obj = get_json_obj_from_zip_file_entry(curr_file, j_path_and_name); diff --git a/src/wdl/src/object.c b/src/wdl/src/object.c index ad95cf6f4a..b54612bced 100644 --- a/src/wdl/src/object.c +++ b/src/wdl/src/object.c @@ -17,7 +17,7 @@ int init_object(object_t *obj, char *id) } /* See wdl/object.h for documentation */ -int obj_free(object_t *obj) +int object_free(object_t *obj) { return 0; } From b1c2630b4cad1a07bdbc882a2654a975f4a90846 Mon Sep 17 00:00:00 2001 From: Nam Anh Dinh Date: Mon, 8 Jun 2020 04:01:05 -0500 Subject: [PATCH 04/14] Polishing + added tests for wdz loading --- src/wdl/src/load_game.c | 15 ++----- src/wdl/src/load_wdz_common.c | 45 ++++++++++++++++---- tests/wdl/CMakeLists.txt | 1 + tests/wdl/test_wdz.c | 79 +++++++++++++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 21 deletions(-) create mode 100644 tests/wdl/test_wdz.c diff --git a/src/wdl/src/load_game.c b/src/wdl/src/load_game.c index 6787fbb08b..2021393f07 100644 --- a/src/wdl/src/load_game.c +++ b/src/wdl/src/load_game.c @@ -28,21 +28,12 @@ game_t *load_wdl(char *path_to_yaml) int n_jsons = 0; printf("Detected wdz file. Attempting to load wdz and printing the json files...\n"); printf("Note that loading wdz is not functional right now.\n"); - object_t *obj_store_init_obj = new_object("__empty__"); - /* commenting all this out because new_object always returns NULL for now. */ - // if (!obj_store_init_obj) - // { - // fprintf(stderr,"could not allocate dummy object for objstore\n"); - // return NULL; - // } - // // ideally this should be handled by new_object itself - // obj_store_init_obj->type = TYPE_OTHER; - objstore_t *obj_store = new_objstore(obj_store_init_obj); + + objstore_t *obj_store = NULL; populate_objstore_from_wdz(obj_store, &n_jsons, path_to_yaml); - /* commenting this out for now because new_object always returns NULL for now. */ - //free_objstore(&obj_store, find_objstore(&obj_store, "__empty__", TYPE_OTHER)); + free_all(&obj_store); printf("Number of JSON files found: %d\n", n_jsons); return NULL; } diff --git a/src/wdl/src/load_wdz_common.c b/src/wdl/src/load_wdz_common.c index b280ff7cbb..33621bb8ce 100644 --- a/src/wdl/src/load_wdz_common.c +++ b/src/wdl/src/load_wdz_common.c @@ -5,6 +5,8 @@ #include "wdl/load_wdz_internal.h" +// Helper macros for the json name -> game object type conversion + #define SAME_STRING(s1, s2) (strcmp(s1, s2) == (0)) #define TYPE_PLAYER_STR "player" #define TYPE_ROOM_STR "rooms" @@ -14,6 +16,17 @@ #define TYPE_DIALOG_STR "dialog" #define TYPE_NPC_STR "npcs" +/* + * match_j_name_to_game_obj_type: + * Converts a raw json filename/top-level key name into + * the corresponding objtype_t enum value. + * + * Parameters: + * - j_name: A string that is the raw name + * + * Returns: + * - An objtype_t value corresponding to that name + */ objtype_t match_j_name_to_game_obj_type(char *j_name) { objtype_t game_obj_type; @@ -106,13 +119,6 @@ int load_game_objects_from_json_object json_object *j_obj ) { - // // Commenting this out because while we have objstore_t init ready, - // // it still depends on object_t init, which always returns NULL, - // // so the objstore ends up always NULL. - // if (!obj_store) - // { - // return FAILURE; - // } if (!j_obj) { return FAILURE; @@ -123,6 +129,8 @@ int load_game_objects_from_json_object if (json_object_is_type(j_value, json_type_array)) { int n_objects = json_object_array_length(j_value); + int omitted = 0; + int added = 0; for (int i = 0; i < n_objects; i++) // for each json_object in the array { json_object *j_game_obj = json_object_array_get_idx(j_value, i); @@ -130,11 +138,30 @@ int load_game_objects_from_json_object if (!game_obj) { fprintf(stderr, "Couldn't convert json object %s[%d] into game object\n", j_name, i); + omitted++; continue; } - add_objstore(&obj_store, game_obj); + if (add_objstore(&obj_store, game_obj) == FAILURE) + { + omitted++; + } + else + { + added++; + } + } + if (omitted > 0) + { + fprintf(stderr, "Omitted import of %d game objects\n", omitted); + } + if (added > 0) + { + return SUCCESS; + } + else + { + return FAILURE; } - return SUCCESS; } else if (json_object_is_type(j_value, json_type_object)) { diff --git a/tests/wdl/CMakeLists.txt b/tests/wdl/CMakeLists.txt index 3893fbd217..5497a0c2e2 100644 --- a/tests/wdl/CMakeLists.txt +++ b/tests/wdl/CMakeLists.txt @@ -6,6 +6,7 @@ add_executable(${TEST_EXE} test_objstore.c test_room.c test_validation.c + test_wdz.c main.c) target_link_libraries(${TEST_EXE} ${CRITERION_LIBRARY}) diff --git a/tests/wdl/test_wdz.c b/tests/wdl/test_wdz.c new file mode 100644 index 0000000000..ebabd8742f --- /dev/null +++ b/tests/wdl/test_wdz.c @@ -0,0 +1,79 @@ +#include +#include "wdl/load_wdz_internal.h" + +/* Checks the file extension checker when format is normal */ +Test(load_wdz, file_extension_normal) +{ + cr_assert_eq(filename_extension_is("wdz", "myfile.wdz"), true, + "File extension was wdz but filename_extension_is returned false"); + + cr_assert_eq(filename_extension_is("wdz", "myfile.zip"), false, + "File extension was NOT wdz but filename_extension_is returned true"); +} + +/* Checks the file extension checker when filename has multiple dots */ +Test(load_wdz, file_extension_multiple_dots) +{ + cr_assert_eq(filename_extension_is("wdz", "myfile.backup.wdz"), true, + "File extension was wdz but filename_extension_is returned false"); + + cr_assert_eq(filename_extension_is("wdz", "myfile.wdz.backup"), false, + "File extension was NOT wdz but filename_extension_is returned true"); +} + +/* Checks the file extension checker when filename has path */ +Test(load_wdz, file_extension_withpath) +{ + cr_assert_eq(filename_extension_is("wdz", "path/to/myfile.wdz"), true, + "File extension was wdz but filename_extension_is returned false"); + + cr_assert_eq(filename_extension_is("wdz", "path/to/myfile.zip"), false, + "File extension was NOT wdz but filename_extension_is returned true"); +} + +#define EMPTY_GAME_OBJ_NAME "__empty_obj__" + +void check_objstore_from_json +( + const char *json_buf, + objtype_t obj_type, + char *expected_id +) +{ + json_object *j_obj = json_tokener_parse(json_buf); + + objstore_t *obj_store = NULL; + + int res = load_game_objects_from_json_object(obj_store, j_obj); + + cr_assert_eq(res, SUCCESS, "Load function returned FAILURE"); + cr_assert_not_null(obj_store, "Object store still empty after load"); + + objstore_t *dummy = find_objstore(&obj_store, EMPTY_GAME_OBJ_NAME, TYPE_OTHER); + cr_assert_not_null(dummy->o, ""); + objstore_t *imported = + find_objstore(&obj_store, expected_id, obj_type); + + + object_t *target; + + cr_assert_not_null(imported, "Could not find the right object store node"); + target = imported->o; + cr_assert_not_null(target, + "Could not get the loaded game object from the object store" + ); + cr_assert_str_eq(target->id, expected_id, "Loaded game object did not have correct ID"); + free_all(&obj_store); +} + +Test(load_wdz, load_game_objs_from_json) +{ + const char *test_json = + "{\"rooms\": \ + [ \ + {\"id\":\"best_room\"}, \ + {\"id\":\"test_room\"} \ + ] \ + }"; + check_objstore_from_json(test_json, TYPE_ROOM, "best_room"); +} \ No newline at end of file From 90e602a3015acd205439c68ff7523d309988c657 Mon Sep 17 00:00:00 2001 From: Nam Anh Dinh Date: Mon, 8 Jun 2020 11:38:37 -0500 Subject: [PATCH 05/14] Implementing conversion from json to object_t --- include/wdl/attributes.h | 2 +- src/wdl/src/load_game.c | 4 +- src/wdl/src/load_wdz_common.c | 149 ++++++++++++++++++++++++++++++---- tests/wdl/test_wdz.c | 4 +- 4 files changed, 138 insertions(+), 21 deletions(-) diff --git a/include/wdl/attributes.h b/include/wdl/attributes.h index eca382a08f..abe72401fb 100644 --- a/include/wdl/attributes.h +++ b/include/wdl/attributes.h @@ -6,7 +6,7 @@ #define INCLUDE_ATTRIBUTES_H #define MAXLEN_ID 60 // ID strings for objects -typedef struct obj object_t; // forward declaration so attribute_t can use +//typedef struct object_t object_t; // forward declaration so attribute_t can use /* * attribute_t: the attributes stored within an object diff --git a/src/wdl/src/load_game.c b/src/wdl/src/load_game.c index 4414cde455..888cb84d92 100644 --- a/src/wdl/src/load_game.c +++ b/src/wdl/src/load_game.c @@ -32,8 +32,8 @@ game_t *load_wdl(char *path_to_yaml) objstore_t *obj_store = NULL; populate_objstore_from_wdz(obj_store, &n_jsons, path_to_yaml); - - free_all(&obj_store); + + free_all_objstore(&obj_store); printf("Number of JSON files found: %d\n", n_jsons); return NULL; } diff --git a/src/wdl/src/load_wdz_common.c b/src/wdl/src/load_wdz_common.c index 33621bb8ce..4189636ceb 100644 --- a/src/wdl/src/load_wdz_common.c +++ b/src/wdl/src/load_wdz_common.c @@ -58,6 +58,10 @@ objtype_t match_j_name_to_game_obj_type(char *j_name) { game_obj_type = TYPE_DIALOG; } + else if (strlen(j_name) == 0) + { + game_obj_type = TYPE_NOTHING; + } else { game_obj_type = TYPE_UNDEFINED; @@ -66,36 +70,151 @@ objtype_t match_j_name_to_game_obj_type(char *j_name) return game_obj_type; } +/* + * make_data_from_j_value + * Recursively converts every JSON object that isn't formatted like a proper + * game object. This works on nested JSON objects and arrays, too. + * Serves to make the void ptr data field for attributes. + * WARNING: This mallocs the data, so they must later be freed. + * + * Parameters: + * - j_value: the json_object to be converted + * + * Returns: + * - a void pointer pointing to allocated memory containing the desired data + */ +void *make_data_from_j_value(json_object *j_value) +{ + json_type j_type = json_object_get_type(j_value); + switch (j_type) + { + case json_type_boolean: + { + json_bool *val = malloc(sizeof(*val)); + *val = json_object_get_boolean(j_value); + return (void*)val; + } + case json_type_double: + { + double *val = malloc(sizeof(*val)); + *val = json_object_get_double(j_value); + return (void*)val; + } + case json_type_int: + { + int *val = malloc(sizeof(*val)); + *val = json_object_get_int(j_value); + return (void*)val; + } + case json_type_string: + { + char *val = malloc(sizeof(*val)); + strcpy(val, json_object_get_string(j_value)); + puts(val); + return (void*)val; + } + case json_type_null: + { + void *val = NULL; + return (void*)val; + } + /* the recursive converters */ + case json_type_object: + { + puts("Trying to add obj"); + object_t *val = new_object("", TYPE_NOTHING); + json_object_object_foreach(j_value, attr_name, attr_val) + { + printf("Adding object key %s value %s\n",attr_name, json_object_to_json_string(attr_val)); + // for each contained key-val pair in the object, + // convert into the attribute table + add_attribute(&(val->attrs), attr_name, + make_data_from_j_value(attr_val)); + } + return (void*)val; + + } + case json_type_array: + { + int arr_len = json_object_array_length(j_value); + if (arr_len == 0) + { + void *val = NULL; + } + object_t *val = new_object("", TYPE_NOTHING); + for (int i = 0; i < arr_len; i++) + { + // var->attrs is the head element + json_object *arr_elt = json_object_array_get_idx(j_value, i); + void *raw_data = make_data_from_j_value(arr_elt); + assert(raw_data != NULL); + append_attr(val->attrs, raw_data); + } + return (void*)val; + } + default: + { + void *val = NULL; + return (void*)val; + } + } + return NULL; +} + object_t *convert_j_obj_to_game_obj(json_object *j_game_obj, char *j_name) { - object_t* game_obj = malloc(sizeof(object_t)); + /* First find game object type (e.g. a room, or an item) */ + objtype_t game_obj_type = match_j_name_to_game_obj_type(j_name); + + /* Then find the game object's ID */ + char game_obj_id[MAXLEN_ID]; + json_object *game_obj_id_j_obj = NULL; + json_object_object_get_ex(j_game_obj, "id", &game_obj_id_j_obj); + if (!game_obj_id_j_obj) + { + // Player object is a one-off obj that doesn't need an id field + // the Other object types also should not require an id field + if ((game_obj_type != TYPE_PLAYER) + && (game_obj_type != TYPE_NOTHING) + && (game_obj_type != TYPE_UNDEFINED)) + { + fprintf(stderr, + "No id key found in the JSON of this game object!\n"); + return NULL; + } + } + if (json_object_is_type(game_obj_id_j_obj, json_type_string)) + { + strncpy(game_obj_id, json_object_get_string(game_obj_id_j_obj), MAXLEN_ID); + } + else + { + fprintf(stderr, + "id key in the JSON of this game object has wrong value type (must\ + be string!)\n"); + return NULL; + } + + /* Once type and id are obtained, create the game object */ + object_t *game_obj = new_object(game_obj_id, game_obj_type); if (!game_obj) { fprintf(stderr, "Unable to allocate memory for game object\n"); return NULL; } - - /* First set the game object type (e.g. a room, or an item */ - game_obj->type = match_j_name_to_game_obj_type(j_name); - /* Loops through all attributes in the object */ + /* Loops through all attributes in the JSON object */ json_object_object_foreach(j_game_obj, attr_name, j_value) { - if (strcmp(attr_name, "id") == 0) + if (SAME_STRING(attr_name, "id")) { - strcpy(game_obj->id, json_object_get_string(j_value)); - } + continue; // we already added the ID above + } else { - // awaiting add_attr functions to add a new attribute to object here. - //Gets type of the object and sets objtype_t based on value returned by - //json_type json_object_get_type (j_value) - if (json_object_is_type(j_value, json_type_boolean)) { - - } + add_attribute(&(game_obj->attrs), attr_name, make_data_from_j_value(j_value)); } - } return NULL; } diff --git a/tests/wdl/test_wdz.c b/tests/wdl/test_wdz.c index ebabd8742f..18a6a128e5 100644 --- a/tests/wdl/test_wdz.c +++ b/tests/wdl/test_wdz.c @@ -49,8 +49,6 @@ void check_objstore_from_json cr_assert_eq(res, SUCCESS, "Load function returned FAILURE"); cr_assert_not_null(obj_store, "Object store still empty after load"); - objstore_t *dummy = find_objstore(&obj_store, EMPTY_GAME_OBJ_NAME, TYPE_OTHER); - cr_assert_not_null(dummy->o, ""); objstore_t *imported = find_objstore(&obj_store, expected_id, obj_type); @@ -63,7 +61,7 @@ void check_objstore_from_json "Could not get the loaded game object from the object store" ); cr_assert_str_eq(target->id, expected_id, "Loaded game object did not have correct ID"); - free_all(&obj_store); + free_all_objstore(&obj_store); } Test(load_wdz, load_game_objs_from_json) From 36656fa307c483cc94a6b8563647185656721bb0 Mon Sep 17 00:00:00 2001 From: Nam Anh Dinh Date: Mon, 8 Jun 2020 12:34:09 -0500 Subject: [PATCH 06/14] conversion now doesn't always return NULL --- src/wdl/src/load_wdz_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wdl/src/load_wdz_common.c b/src/wdl/src/load_wdz_common.c index 4189636ceb..0d09ac5b03 100644 --- a/src/wdl/src/load_wdz_common.c +++ b/src/wdl/src/load_wdz_common.c @@ -216,7 +216,7 @@ object_t *convert_j_obj_to_game_obj(json_object *j_game_obj, char *j_name) add_attribute(&(game_obj->attrs), attr_name, make_data_from_j_value(j_value)); } } - return NULL; + return game_obj; } From 648e37223849273f340b5987b8e423398e03bd7b Mon Sep 17 00:00:00 2001 From: Nam Anh Dinh Date: Mon, 8 Jun 2020 12:51:42 -0500 Subject: [PATCH 07/14] String imports should now work? --- src/wdl/src/load_wdz_common.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/wdl/src/load_wdz_common.c b/src/wdl/src/load_wdz_common.c index 0d09ac5b03..83b5321b73 100644 --- a/src/wdl/src/load_wdz_common.c +++ b/src/wdl/src/load_wdz_common.c @@ -108,7 +108,9 @@ void *make_data_from_j_value(json_object *j_value) } case json_type_string: { - char *val = malloc(sizeof(*val)); + int str_len = json_object_get_string_len(j_value); + char *val = calloc(str_len + 1, sizeof(*val)); + strcpy(val, json_object_get_string(j_value)); puts(val); return (void*)val; From 13761d842ca93695ca9eb166cfbd8acc98eb1a41 Mon Sep 17 00:00:00 2001 From: Nam Anh Dinh Date: Mon, 8 Jun 2020 13:17:52 -0500 Subject: [PATCH 08/14] Change funcs to use double pointers for objstore --- include/wdl/load_wdz.h | 2 +- include/wdl/load_wdz_internal.h | 2 +- include/wdl/object.h | 4 ++-- src/wdl/src/load_game.c | 5 +++-- src/wdl/src/load_wdz_common.c | 23 ++++++++++++++--------- src/wdl/src/load_wdz_lzip.c | 2 +- src/wdl/src/object.c | 2 +- tests/wdl/test_wdz.c | 2 +- 8 files changed, 24 insertions(+), 18 deletions(-) diff --git a/include/wdl/load_wdz.h b/include/wdl/load_wdz.h index 41fc955f3a..5a3158110a 100644 --- a/include/wdl/load_wdz.h +++ b/include/wdl/load_wdz.h @@ -22,7 +22,7 @@ */ int populate_objstore_from_wdz ( - objstore_t *obj_store, + objstore_t **obj_store, int *n_jsons, char *wdz_name ); diff --git a/include/wdl/load_wdz_internal.h b/include/wdl/load_wdz_internal.h index 91504e0284..7d8a9b98cc 100644 --- a/include/wdl/load_wdz_internal.h +++ b/include/wdl/load_wdz_internal.h @@ -38,7 +38,7 @@ bool filename_extension_is(const char *ext, const char *str); */ int load_game_objects_from_json_object ( - objstore_t *obj_store, + objstore_t **obj_store, json_object *j_obj ); diff --git a/include/wdl/object.h b/include/wdl/object.h index 6ce6e03d57..f074db65b2 100644 --- a/include/wdl/object.h +++ b/include/wdl/object.h @@ -16,8 +16,8 @@ */ typedef enum objtype { - TYPE_ERROR = -1, - TYPE_ZERO = 0, + TYPE_ERR = -1, + TYPE_NONE = 0, TYPE_PLAYER = 1, TYPE_ROOM = 2, TYPE_ITEM = 3, diff --git a/src/wdl/src/load_game.c b/src/wdl/src/load_game.c index 888cb84d92..8c4d511bd6 100644 --- a/src/wdl/src/load_game.c +++ b/src/wdl/src/load_game.c @@ -31,8 +31,9 @@ game_t *load_wdl(char *path_to_yaml) objstore_t *obj_store = NULL; - populate_objstore_from_wdz(obj_store, &n_jsons, path_to_yaml); - + populate_objstore_from_wdz(&obj_store, &n_jsons, path_to_yaml); + assert(obj_store != NULL); + puts("Successfully loaded the store"); free_all_objstore(&obj_store); printf("Number of JSON files found: %d\n", n_jsons); return NULL; diff --git a/src/wdl/src/load_wdz_common.c b/src/wdl/src/load_wdz_common.c index 83b5321b73..205bc03cf9 100644 --- a/src/wdl/src/load_wdz_common.c +++ b/src/wdl/src/load_wdz_common.c @@ -15,6 +15,7 @@ #define TYPE_GCONDITION_STR "globalconditions" #define TYPE_DIALOG_STR "dialog" #define TYPE_NPC_STR "npcs" +#define TYPE_CUSTOM_SCRIPT_STR "customscripts" /* * match_j_name_to_game_obj_type: @@ -58,13 +59,17 @@ objtype_t match_j_name_to_game_obj_type(char *j_name) { game_obj_type = TYPE_DIALOG; } + else if (SAME_STRING(j_name, TYPE_CUSTOM_SCRIPT_STR)) + { + game_obj_type = TYPE_CUSTOM_SCRIPT; + } else if (strlen(j_name) == 0) { - game_obj_type = TYPE_NOTHING; + game_obj_type = TYPE_NONE; } else { - game_obj_type = TYPE_UNDEFINED; + game_obj_type = TYPE_ERR; } return game_obj_type; @@ -124,7 +129,7 @@ void *make_data_from_j_value(json_object *j_value) case json_type_object: { puts("Trying to add obj"); - object_t *val = new_object("", TYPE_NOTHING); + object_t *val = new_object("", TYPE_NONE); json_object_object_foreach(j_value, attr_name, attr_val) { printf("Adding object key %s value %s\n",attr_name, json_object_to_json_string(attr_val)); @@ -143,7 +148,7 @@ void *make_data_from_j_value(json_object *j_value) { void *val = NULL; } - object_t *val = new_object("", TYPE_NOTHING); + object_t *val = new_object("", TYPE_NONE); for (int i = 0; i < arr_len; i++) { // var->attrs is the head element @@ -178,8 +183,8 @@ object_t *convert_j_obj_to_game_obj(json_object *j_game_obj, char *j_name) // Player object is a one-off obj that doesn't need an id field // the Other object types also should not require an id field if ((game_obj_type != TYPE_PLAYER) - && (game_obj_type != TYPE_NOTHING) - && (game_obj_type != TYPE_UNDEFINED)) + && (game_obj_type != TYPE_NONE) + && (game_obj_type != TYPE_ERR)) { fprintf(stderr, "No id key found in the JSON of this game object!\n"); @@ -236,7 +241,7 @@ bool filename_extension_is(const char *ext, const char *str) /* See load_wdz_internal.h */ int load_game_objects_from_json_object ( - objstore_t *obj_store, + objstore_t **obj_store, json_object *j_obj ) { @@ -262,7 +267,7 @@ int load_game_objects_from_json_object omitted++; continue; } - if (add_objstore(&obj_store, game_obj) == FAILURE) + if (add_objstore(obj_store, game_obj) == FAILURE) { omitted++; } @@ -296,7 +301,7 @@ int load_game_objects_from_json_object { return FAILURE; } - add_objstore(&obj_store, player); + add_objstore(obj_store, player); return SUCCESS; } else diff --git a/src/wdl/src/load_wdz_lzip.c b/src/wdl/src/load_wdz_lzip.c index 918227ecc7..a342319f4d 100644 --- a/src/wdl/src/load_wdz_lzip.c +++ b/src/wdl/src/load_wdz_lzip.c @@ -74,7 +74,7 @@ struct json_object *get_json_obj_from_zip_file_entry /* See load_wdz.h */ int populate_objstore_from_wdz ( - objstore_t *obj_store, + objstore_t **obj_store, int *n_jsons, char *wdz_name ) diff --git a/src/wdl/src/object.c b/src/wdl/src/object.c index 56f52b8845..7d4dcde252 100644 --- a/src/wdl/src/object.c +++ b/src/wdl/src/object.c @@ -150,6 +150,6 @@ objtype_t str_to_objtype(char *type) { return TYPE_DIALOG; } else { - return TYPE_UNDEFINED; + return TYPE_ERR; } } diff --git a/tests/wdl/test_wdz.c b/tests/wdl/test_wdz.c index 18a6a128e5..5d58a1d0d2 100644 --- a/tests/wdl/test_wdz.c +++ b/tests/wdl/test_wdz.c @@ -44,7 +44,7 @@ void check_objstore_from_json objstore_t *obj_store = NULL; - int res = load_game_objects_from_json_object(obj_store, j_obj); + int res = load_game_objects_from_json_object(&obj_store, j_obj); cr_assert_eq(res, SUCCESS, "Load function returned FAILURE"); cr_assert_not_null(obj_store, "Object store still empty after load"); From cf290e857798843071a6f77a173d873f5bfaf60b Mon Sep 17 00:00:00 2001 From: Nam Anh Dinh Date: Mon, 8 Jun 2020 14:07:28 -0500 Subject: [PATCH 09/14] Made libzip and json-c available for wdl tests on CSIL --- tests/wdl/CMakeLists.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/wdl/CMakeLists.txt b/tests/wdl/CMakeLists.txt index 525033bbf2..b6081691fc 100644 --- a/tests/wdl/CMakeLists.txt +++ b/tests/wdl/CMakeLists.txt @@ -10,11 +10,14 @@ add_executable(${TEST_EXE} test_wdz.c main.c) -target_link_libraries(${TEST_EXE} ${CRITERION_LIBRARY}) + target_link_libraries(${TEST_EXE} ${CRITERION_LIBRARY} ${JSONC_LIBRARIES} ${LIBZIP_LIBRARIES}) foreach(module ${CHIVENTURE_MODULES}) target_link_libraries(${TEST_EXE} ${module}) endforeach(module) +target_include_directories(${TEST_EXE} PRIVATE ${LIBZIP_INCLUDE_DIR}) +target_include_directories(${TEST_EXE} PRIVATE ${JSONC_INCLUDE_DIR}) + add_test(NAME ${TEST_EXE} - COMMAND ${TEST_EXE}) \ No newline at end of file + COMMAND ${TEST_EXE}) From 7933e4666f4eb77dc9f947a94a007bcc39996aee Mon Sep 17 00:00:00 2001 From: Nam Anh Dinh Date: Mon, 8 Jun 2020 14:09:49 -0500 Subject: [PATCH 10/14] Added tests for the objstore populate function --- include/wdl/load_wdz_internal.h | 2 ++ src/wdl/src/load_game.c | 2 +- src/wdl/src/load_wdz_common.c | 14 +++++------- tests/wdl/test_wdz.c | 40 +++++++++++++++++++++++++++------ 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/include/wdl/load_wdz_internal.h b/include/wdl/load_wdz_internal.h index 7d8a9b98cc..0789528a0d 100644 --- a/include/wdl/load_wdz_internal.h +++ b/include/wdl/load_wdz_internal.h @@ -8,6 +8,8 @@ #include "load_wdz.h" // Re-export the public header for internal use as well +#define DEFAULT_PLAYER_OBJ_ID "player" + /* * filename_extension_is: Checks if a filename string has a certain extension * diff --git a/src/wdl/src/load_game.c b/src/wdl/src/load_game.c index 8c4d511bd6..f39e9feb1f 100644 --- a/src/wdl/src/load_game.c +++ b/src/wdl/src/load_game.c @@ -27,7 +27,7 @@ game_t *load_wdl(char *path_to_yaml) { int n_jsons = 0; printf("Detected wdz file. Attempting to load wdz and printing the json files...\n"); - printf("Note that loading wdz is not functional right now.\n"); + printf("Note that loading wdz works but does not currently register any game objects into the playable game itself.\n"); objstore_t *obj_store = NULL; diff --git a/src/wdl/src/load_wdz_common.c b/src/wdl/src/load_wdz_common.c index 205bc03cf9..3d26b30190 100644 --- a/src/wdl/src/load_wdz_common.c +++ b/src/wdl/src/load_wdz_common.c @@ -117,7 +117,6 @@ void *make_data_from_j_value(json_object *j_value) char *val = calloc(str_len + 1, sizeof(*val)); strcpy(val, json_object_get_string(j_value)); - puts(val); return (void*)val; } case json_type_null: @@ -128,13 +127,10 @@ void *make_data_from_j_value(json_object *j_value) /* the recursive converters */ case json_type_object: { - puts("Trying to add obj"); object_t *val = new_object("", TYPE_NONE); json_object_object_foreach(j_value, attr_name, attr_val) { - printf("Adding object key %s value %s\n",attr_name, json_object_to_json_string(attr_val)); - // for each contained key-val pair in the object, - // convert into the attribute table + printf("Adding object key \"%s\" value %s\n",attr_name, json_object_to_json_string(attr_val)); add_attribute(&(val->attrs), attr_name, make_data_from_j_value(attr_val)); } @@ -176,6 +172,7 @@ object_t *convert_j_obj_to_game_obj(json_object *j_game_obj, char *j_name) /* Then find the game object's ID */ char game_obj_id[MAXLEN_ID]; + strncpy(game_obj_id, DEFAULT_PLAYER_OBJ_ID, MAXLEN_ID); json_object *game_obj_id_j_obj = NULL; json_object_object_get_ex(j_game_obj, "id", &game_obj_id_j_obj); if (!game_obj_id_j_obj) @@ -191,15 +188,15 @@ object_t *convert_j_obj_to_game_obj(json_object *j_game_obj, char *j_name) return NULL; } } - if (json_object_is_type(game_obj_id_j_obj, json_type_string)) + if ((!json_object_is_type(game_obj_id_j_obj, json_type_null)) + && json_object_is_type(game_obj_id_j_obj, json_type_string)) { strncpy(game_obj_id, json_object_get_string(game_obj_id_j_obj), MAXLEN_ID); } else { fprintf(stderr, - "id key in the JSON of this game object has wrong value type (must\ - be string!)\n"); + "id key in the JSON of this game object has wrong value type (must be string!)\n"); return NULL; } @@ -295,7 +292,6 @@ int load_game_objects_from_json_object // is players.json. Other special cases can go here, but unlikely. object_t *player = convert_j_obj_to_game_obj(j_value, j_name); - printf("Parsed player json.\n"); if (!player) { diff --git a/tests/wdl/test_wdz.c b/tests/wdl/test_wdz.c index 5d58a1d0d2..164226682d 100644 --- a/tests/wdl/test_wdz.c +++ b/tests/wdl/test_wdz.c @@ -31,8 +31,7 @@ Test(load_wdz, file_extension_withpath) "File extension was NOT wdz but filename_extension_is returned true"); } -#define EMPTY_GAME_OBJ_NAME "__empty_obj__" - +/* Test helper function */ void check_objstore_from_json ( const char *json_buf, @@ -64,14 +63,41 @@ void check_objstore_from_json free_all_objstore(&obj_store); } +/* This test should cover everything from load_game_objs_from_json to + * the conversion function convert_j_obj_to_game_obj, which also invokes + * the make_data_from_j_value function. If this works, all of them work. + */ Test(load_wdz, load_game_objs_from_json) { const char *test_json = - "{\"rooms\": \ - [ \ - {\"id\":\"best_room\"}, \ - {\"id\":\"test_room\"} \ - ] \ + "{\"rooms\": \ + [ \ + {\"id\":\"best_room\", \"number\":123}, \ + {\"id\":\"test_room\", \"can_enter\":false} \ + ] \ }"; check_objstore_from_json(test_json, TYPE_ROOM, "best_room"); + check_objstore_from_json(test_json, TYPE_ROOM, "test_room"); +} + +/* A test that simulates what would actually happen on chiventure startup */ +#define RELATIVE_FILE_PATH "../../../src/wdl/examples/wdz/test_game.wdz" +Test(load_wdz, load_from_wdz_file) +{ + objstore_t *obj_store = NULL; + int n_jsons; + populate_objstore_from_wdz(&obj_store, &n_jsons, RELATIVE_FILE_PATH); + cr_assert_not_null(obj_store, "Object store is empty after load"); + cr_assert_not_null(find_objstore(&obj_store, DEFAULT_PLAYER_OBJ_ID, TYPE_PLAYER), + "Player object not loaded"); + // Find a representative object from each type + cr_assert_not_null(find_objstore(&obj_store, "greenlever", TYPE_ITEM), + "Item greenlever not loaded"); + cr_assert_not_null(find_objstore(&obj_store, "action_normal_pull", TYPE_ACTION), + "Action action_normal_pull not loaded"); + cr_assert_not_null(find_objstore(&obj_store, "globcond_unlock", TYPE_GCONDITION), + "Global condition globcond_unlock not loaded"); + cr_assert_not_null(find_objstore(&obj_store, "purpleroom", TYPE_ROOM), + "Room purpleroom not loaded"); + free_all_objstore(&obj_store); } \ No newline at end of file From e58aebc7cc8529a2c3b4be7c7e3a496235a72335 Mon Sep 17 00:00:00 2001 From: Nam Anh Dinh Date: Mon, 8 Jun 2020 15:28:57 -0500 Subject: [PATCH 11/14] Fixed all tests and now frees void* data --- src/wdl/src/attributes.c | 1 + src/wdl/src/load_wdz_common.c | 47 +++++++++++++++++++++++++---------- tests/wdl/test_attributes.c | 11 ++++++-- tests/wdl/test_wdz.c | 26 +++++++++++++++++-- 4 files changed, 68 insertions(+), 17 deletions(-) diff --git a/src/wdl/src/attributes.c b/src/wdl/src/attributes.c index 9c5dca210b..60c4fe933a 100644 --- a/src/wdl/src/attributes.c +++ b/src/wdl/src/attributes.c @@ -98,6 +98,7 @@ int free_attr(obj_attr_t *head, obj_attr_t *a) return FAILURE; } DL_DELETE(head, a); + free(a->data); free(a); return SUCCESS; } diff --git a/src/wdl/src/load_wdz_common.c b/src/wdl/src/load_wdz_common.c index 3d26b30190..5adc262daf 100644 --- a/src/wdl/src/load_wdz_common.c +++ b/src/wdl/src/load_wdz_common.c @@ -172,36 +172,50 @@ object_t *convert_j_obj_to_game_obj(json_object *j_game_obj, char *j_name) /* Then find the game object's ID */ char game_obj_id[MAXLEN_ID]; - strncpy(game_obj_id, DEFAULT_PLAYER_OBJ_ID, MAXLEN_ID); + strncpy(game_obj_id, "", MAXLEN_ID); json_object *game_obj_id_j_obj = NULL; json_object_object_get_ex(j_game_obj, "id", &game_obj_id_j_obj); if (!game_obj_id_j_obj) { - // Player object is a one-off obj that doesn't need an id field - // the Other object types also should not require an id field - if ((game_obj_type != TYPE_PLAYER) - && (game_obj_type != TYPE_NONE) - && (game_obj_type != TYPE_ERR)) + /* Player object is a one-off obj that doesn't need an id field + * the Other object types also should not require an id field + */ + if (game_obj_type == TYPE_PLAYER) + { + puts("detected player object"); + strncpy(game_obj_id, DEFAULT_PLAYER_OBJ_ID, MAXLEN_ID); + puts(game_obj_id); + } + else if ((game_obj_type != TYPE_NONE) + && (game_obj_type != TYPE_ERR)) { fprintf(stderr, "No id key found in the JSON of this game object!\n"); return NULL; } } - if ((!json_object_is_type(game_obj_id_j_obj, json_type_null)) - && json_object_is_type(game_obj_id_j_obj, json_type_string)) + if (json_object_is_type(game_obj_id_j_obj, json_type_string)) { strncpy(game_obj_id, json_object_get_string(game_obj_id_j_obj), MAXLEN_ID); } else { - fprintf(stderr, - "id key in the JSON of this game object has wrong value type (must be string!)\n"); - return NULL; + if ((game_obj_type != TYPE_PLAYER) + && (game_obj_type != TYPE_NONE) + && (game_obj_type != TYPE_ERR)) + { + fprintf(stderr, + "id key in the JSON of this game object has wrong value type (must be string!)\n"); + return NULL; + } } /* Once type and id are obtained, create the game object */ object_t *game_obj = new_object(game_obj_id, game_obj_type); + if (game_obj_type == TYPE_PLAYER) + { + puts("Type is player"); + } if (!game_obj) { fprintf(stderr, "Unable to allocate memory for game object\n"); @@ -211,6 +225,10 @@ object_t *convert_j_obj_to_game_obj(json_object *j_game_obj, char *j_name) /* Loops through all attributes in the JSON object */ json_object_object_foreach(j_game_obj, attr_name, j_value) { + if (game_obj_type == TYPE_PLAYER) + { + puts(attr_name); + } if (SAME_STRING(attr_name, "id")) { continue; // we already added the ID above @@ -290,9 +308,12 @@ int load_game_objects_from_json_object { // The only file with an object-type value as top-level // is players.json. Other special cases can go here, but unlikely. - + json_object *test_string_inplayer; + json_object_object_get_ex(j_value, "start_room", &test_string_inplayer); + puts(json_object_get_string(test_string_inplayer)); object_t *player = convert_j_obj_to_game_obj(j_value, j_name); - + printf("Trying to convert player obj, name %s. Player is %p\n", j_name, (void*)player); + if (!player) { return FAILURE; diff --git a/tests/wdl/test_attributes.c b/tests/wdl/test_attributes.c index 69ab9e56a8..1562f43b3f 100644 --- a/tests/wdl/test_attributes.c +++ b/tests/wdl/test_attributes.c @@ -158,13 +158,20 @@ Test(attributes, count) cr_assert_eq(res, 2, "count_attr_list() failed"); } +#define MAX_TEST_DATA_LENGTH 20 + Test(attributes, free) { - obj_attr_t *item1 = new_attr("class", "adventurer"); + char *data1, *data2; + data1 = calloc(MAX_TEST_DATA_LENGTH, sizeof(*data1)); + data2 = calloc(MAX_TEST_DATA_LENGTH, sizeof(*data2)); + strncpy(data1, "adventurer", MAX_TEST_DATA_LENGTH); + strncpy(data2, "stick", MAX_TEST_DATA_LENGTH); + obj_attr_t *item1 = new_attr("class", data1); cr_assert_not_null(item1, "new_attr() failed to init & alloc attr"); obj_attr_t *head = init_attr_list(item1); - obj_attr_t *item2 = new_attr("weapon", "stick"); + obj_attr_t *item2 = new_attr("weapon", data2); append_attr(head, item2); int res = free_attr(head, item2); diff --git a/tests/wdl/test_wdz.c b/tests/wdl/test_wdz.c index 164226682d..7e81800535 100644 --- a/tests/wdl/test_wdz.c +++ b/tests/wdl/test_wdz.c @@ -67,7 +67,7 @@ void check_objstore_from_json * the conversion function convert_j_obj_to_game_obj, which also invokes * the make_data_from_j_value function. If this works, all of them work. */ -Test(load_wdz, load_game_objs_from_json) +Test(load_wdz, load_room_objs_from_json) { const char *test_json = "{\"rooms\": \ @@ -80,6 +80,20 @@ Test(load_wdz, load_game_objs_from_json) check_objstore_from_json(test_json, TYPE_ROOM, "test_room"); } +/* Same as above, but the special player object needs some more attention */ +Test(load_wdz, load_player_from_json) +{ + const char *test_json = + "{\"player\": \ + { \ + \"intro_text\":\"my intro text\", \ + \"start_room\":\"whiteroom\" \ + } \ + }"; + check_objstore_from_json(test_json, TYPE_PLAYER, DEFAULT_PLAYER_OBJ_ID); +} + + /* A test that simulates what would actually happen on chiventure startup */ #define RELATIVE_FILE_PATH "../../../src/wdl/examples/wdz/test_game.wdz" Test(load_wdz, load_from_wdz_file) @@ -88,12 +102,20 @@ Test(load_wdz, load_from_wdz_file) int n_jsons; populate_objstore_from_wdz(&obj_store, &n_jsons, RELATIVE_FILE_PATH); cr_assert_not_null(obj_store, "Object store is empty after load"); + cr_log_warn("There are %d\n items in objstore", HASH_COUNT(obj_store)); + + objstore_t *el, *tmp; + HASH_ITER(hh, obj_store, el, tmp) + { + cr_log_warn("object has ID %s and type %d\n",el->key.id, el->key.type); + } + cr_assert_not_null(find_objstore(&obj_store, DEFAULT_PLAYER_OBJ_ID, TYPE_PLAYER), "Player object not loaded"); // Find a representative object from each type cr_assert_not_null(find_objstore(&obj_store, "greenlever", TYPE_ITEM), "Item greenlever not loaded"); - cr_assert_not_null(find_objstore(&obj_store, "action_normal_pull", TYPE_ACTION), + cr_assert_not_null(find_objstore(&obj_store, "action_normal_pull ", TYPE_ACTION), "Action action_normal_pull not loaded"); cr_assert_not_null(find_objstore(&obj_store, "globcond_unlock", TYPE_GCONDITION), "Global condition globcond_unlock not loaded"); From dce0de31d5d731d7ed4a681d870966a24d34f14d Mon Sep 17 00:00:00 2001 From: Nam Anh Dinh Date: Mon, 8 Jun 2020 15:37:56 -0500 Subject: [PATCH 12/14] Cleaned up printouts --- src/wdl/src/load_wdz_common.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/wdl/src/load_wdz_common.c b/src/wdl/src/load_wdz_common.c index cfd24fa229..1eb0ac4a7b 100644 --- a/src/wdl/src/load_wdz_common.c +++ b/src/wdl/src/load_wdz_common.c @@ -130,7 +130,7 @@ void *make_data_from_j_value(json_object *j_value) object_t *val = new_object("", TYPE_NONE); json_object_object_foreach(j_value, attr_name, attr_val) { - printf("Adding object key \"%s\" value %s\n",attr_name, json_object_to_json_string(attr_val)); + printf("Adding nested object key \"%s\" value %s\n",attr_name, json_object_to_json_string(attr_val)); add_attribute(&(val->attrs), attr_name, make_data_from_j_value(attr_val)); } @@ -182,9 +182,7 @@ object_t *convert_j_obj_to_game_obj(json_object *j_game_obj, char *j_name) */ if (game_obj_type == TYPE_PLAYER) { - puts("detected player object"); strncpy(game_obj_id, DEFAULT_PLAYER_OBJ_ID, MAXLEN_ID); - puts(game_obj_id); } else if ((game_obj_type != TYPE_NONE) && (game_obj_type != TYPE_ERR)) @@ -212,10 +210,7 @@ object_t *convert_j_obj_to_game_obj(json_object *j_game_obj, char *j_name) /* Once type and id are obtained, create the game object */ object_t *game_obj = new_object(game_obj_id, game_obj_type); - if (game_obj_type == TYPE_PLAYER) - { - puts("Type is player"); - } + if (!game_obj) { fprintf(stderr, "Unable to allocate memory for game object\n"); @@ -225,10 +220,6 @@ object_t *convert_j_obj_to_game_obj(json_object *j_game_obj, char *j_name) /* Loops through all attributes in the JSON object */ json_object_object_foreach(j_game_obj, attr_name, j_value) { - if (game_obj_type == TYPE_PLAYER) - { - puts(attr_name); - } if (SAME_STRING(attr_name, "id")) { continue; // we already added the ID above From 44bd5e7e384e17f3c622a4ef7ac158426ee8d14d Mon Sep 17 00:00:00 2001 From: Nam Anh Dinh Date: Mon, 8 Jun 2020 15:44:50 -0500 Subject: [PATCH 13/14] Updated convert function docs --- src/wdl/src/load_wdz_common.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/wdl/src/load_wdz_common.c b/src/wdl/src/load_wdz_common.c index 1eb0ac4a7b..202f2d190f 100644 --- a/src/wdl/src/load_wdz_common.c +++ b/src/wdl/src/load_wdz_common.c @@ -147,7 +147,7 @@ void *make_data_from_j_value(json_object *j_value) object_t *val = new_object("", TYPE_NONE); for (int i = 0; i < arr_len; i++) { - // var->attrs is the head element + /* var->attrs is the head element */ json_object *arr_elt = json_object_array_get_idx(j_value, i); void *raw_data = make_data_from_j_value(arr_elt); assert(raw_data != NULL); @@ -164,7 +164,27 @@ void *make_data_from_j_value(json_object *j_value) return NULL; } - +/* convert_j_obj_to_game_obj + * Converts a JSON object of the form + * { + * "key_name":[ INDIVIDUAL NESTED OBJECTS HERE ] + * } + * + * or + * { + * "key_name":{ ATTRIBS HERE } + * } + * + * into the right internal object_t representation. + * + * Parameters: + * - j_game_obj: The JSON object to convert + * - j_name: The name of the top-level container of j_game_obj. E.g. "rooms" + * (NOT the id of j_game_obj itself!) + * This is also the filename of the JSON file that contains this JSON. + * Returns: + * - A pointer to the resulting object_t + */ object_t *convert_j_obj_to_game_obj(json_object *j_game_obj, char *j_name) { /* First find game object type (e.g. a room, or an item) */ From b01f37727613fdd70414f7a5ac46adf0dab46157 Mon Sep 17 00:00:00 2001 From: Nam Anh Dinh Date: Tue, 9 Jun 2020 12:44:59 -0500 Subject: [PATCH 14/14] Fixed segfault on _get_idx --- src/wdl/src/load_wdz_common.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/src/wdl/src/load_wdz_common.c b/src/wdl/src/load_wdz_common.c index 202f2d190f..ab8f0df031 100644 --- a/src/wdl/src/load_wdz_common.c +++ b/src/wdl/src/load_wdz_common.c @@ -128,9 +128,12 @@ void *make_data_from_j_value(json_object *j_value) case json_type_object: { object_t *val = new_object("", TYPE_NONE); - json_object_object_foreach(j_value, attr_name, attr_val) + json_object_iter j_iterator; + json_object_object_foreachC(j_value, j_iterator) { - printf("Adding nested object key \"%s\" value %s\n",attr_name, json_object_to_json_string(attr_val)); + char* attr_name = j_iterator.key; + json_object *attr_val = j_iterator.val; + add_attribute(&(val->attrs), attr_name, make_data_from_j_value(attr_val)); } @@ -238,8 +241,11 @@ object_t *convert_j_obj_to_game_obj(json_object *j_game_obj, char *j_name) } /* Loops through all attributes in the JSON object */ - json_object_object_foreach(j_game_obj, attr_name, j_value) + json_object_iter j_iterator; + json_object_object_foreachC(j_game_obj, j_iterator) { + char *attr_name = j_iterator.key; + json_object *j_value = j_iterator.val; if (SAME_STRING(attr_name, "id")) { continue; // we already added the ID above @@ -276,16 +282,24 @@ int load_game_objects_from_json_object return FAILURE; } - json_object_object_foreach(j_obj, j_name, j_value) + json_object_iter j_iterator; + json_object_object_foreachC(j_obj, j_iterator) { + char *j_name = j_iterator.key; + json_object *j_value = j_iterator.val; if (json_object_is_type(j_value, json_type_array)) { int n_objects = json_object_array_length(j_value); int omitted = 0; int added = 0; + array_list *j_array = json_object_get_array(j_value); + for (int i = 0; i < n_objects; i++) // for each json_object in the array { - json_object *j_game_obj = json_object_array_get_idx(j_value, i); + /* Using internal array_list because the public interface + * functions cause weird segfault on _get_idx + */ + json_object *j_game_obj = array_list_get_idx(j_array, i); object_t *game_obj = convert_j_obj_to_game_obj(j_game_obj, j_name); if (!game_obj) { @@ -302,6 +316,7 @@ int load_game_objects_from_json_object added++; } } + if (omitted > 0) { fprintf(stderr, "Omitted import of %d game objects\n", omitted); @@ -317,8 +332,9 @@ int load_game_objects_from_json_object } else if (json_object_is_type(j_value, json_type_object)) { - // The only file with an object-type value as top-level - // is players.json. Other special cases can go here, but unlikely. + /* The only file with an object-type value as top-level + * is players.json. Other special cases can go here, but unlikely. + */ object_t *player = convert_j_obj_to_game_obj(j_value, j_name); if (!player) @@ -333,7 +349,7 @@ int load_game_objects_from_json_object return FAILURE; } } - // If no return yet by now then it failed. + /* If no return yet by now then it failed. */ return FAILURE; }