From 0524050959ffa14808f30954b0793568f1c073fb Mon Sep 17 00:00:00 2001 From: Tom Stellard Date: Wed, 23 Dec 2020 17:36:49 -0800 Subject: [PATCH] Add json interface This adds an initial version of a json interface to bygfoot. This is still in development so the interface may change in the future. This interface can be used for writing tests or for communication between a client and server. To use the interface, you can pass a json file with commands to bygfoot using the --json option. --- .github/workflows/package.yml | 20 +- CMakeLists.txt | 28 +- src/bygfoot.c | 20 + src/bygfoot.h | 6 + src/bygfoot_struct.h | 6 +- src/file.h | 3 + src/json_compat.h | 5 + src/json_interface.c | 663 ++++++++++++++++++++++++++++++++++ src/json_interface.h | 12 + src/json_serialize.c | 284 +++++++++++++++ src/json_serialize.h | 27 ++ src/main.c | 49 +++ test/test-country-defs.sh | 86 +++++ test/test-load-save.sh | 36 ++ 14 files changed, 1242 insertions(+), 3 deletions(-) create mode 100644 src/json_compat.h create mode 100644 src/json_interface.c create mode 100644 src/json_interface.h create mode 100644 src/json_serialize.c create mode 100644 src/json_serialize.h create mode 100644 test/test-country-defs.sh create mode 100644 test/test-load-save.sh diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 8f3856c6..18fd9323 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -9,6 +9,20 @@ jobs: package-linux: runs-on: - ubuntu-16.04 + strategy: + fail-fast: false + matrix: + build-type: + - full + - minimal + include: + - build-type: full + extra-deps: libjson-c-dev + build-suffix: "" + - build-type: minimal + extra-deps: "" + build-suffix: -minimal + steps: - name: Checkout sources uses: actions/checkout@v2 @@ -16,13 +30,17 @@ jobs: - name: Install dependencies run: sudo apt-get install libglib2.0-dev libgtk2.0-dev libpango1.0-dev libatk1.0-dev libfreetype6-dev ninja-build + - name: Install extra dependencies + if: ${{ matrix.extra-deps != '' }} + run: sudo apt-get install ${{ matrix.extra-deps }} + - name: Package Bygfoot run: ./scripts/package.sh . - name: Upload artifact uses: actions/upload-artifact@v2 with: - name: "bygfoot-${{ env.BYGFOOT_VERSION }}-linux" + name: "bygfoot-${{ env.BYGFOOT_VERSION }}-linux${{ matrix.build-suffix }}" path: "*.bz2" package-windows: diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d971918..b266e44a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,31 @@ include(GNUInstallDirs) add_definitions("-DPACKAGE_DATA_DIR=\"${CMAKE_INSTALL_FULL_DATADIR}\"") add_definitions("-DPACKAGE=\"${PROJECT_NAME}\"") +find_package(JSON-C) + +if (JSON-C_FOUND) + set(JSON-C_LIBRARIES json-c::json-c) +else() + pkg_check_modules(JSON-C json-c) +endif() + +if (JSON-C_FOUND) + set(JSON_FILES src/json_interface.c src/json_serialize.c) + add_definitions("-DENABLE_JSON") + include_directories (${JSON-C_INCLUDE_DIRS}) + link_directories (${JSON-C_LIBRARY_DIRS}) + + include(CheckSymbolExists) + set(CMAKE_REQUIRED_LIBRARIES ${JSON-C_LIBRARIES}) + check_symbol_exists(json_object_new_array_ext "json-c/json.h" + HAVE_JSON_OBJECT_NEW_ARRAY_EXT) + if (HAVE_JSON_OBJECT_NEW_ARRAY_EXT) + add_definitions("-DHAVE_JSON_OBJECT_NEW_ARRAY_EXT") + endif() + + +endif() + add_executable(bygfoot WIN32 src/bet.c src/bet.h src/bet_struct.h src/bygfoot.c src/bygfoot.h @@ -111,13 +136,14 @@ add_executable(bygfoot WIN32 src/youth_academy.c src/youth_academy.h src/zip/unzip.c src/zip/unzip.h src/zip/zip.c src/zip/zip.h + ${JSON_FILES} ) # Some gtk headers use deprecated glib features, so disable this warning # since we can't do anything about it. target_compile_options(bygfoot PRIVATE -Wno-deprecated-declarations) # Link the target to the GTK+ libraries target_link_libraries (bygfoot ${GTK2_LIBRARIES} ${GLIB_LIBRARIES} m - ${ZLIB_LIBRARIES}) + ${ZLIB_LIBRARIES} ${JSON-C_LIBRARIES}) install(TARGETS bygfoot) diff --git a/src/bygfoot.c b/src/bygfoot.c index d3d7bdd7..ef3e3abf 100644 --- a/src/bygfoot.c +++ b/src/bygfoot.c @@ -1,9 +1,12 @@ #include "bygfoot.h" +#include "file.h" +#include "load_save.h" #include "gui.h" #include "misc.h" #include "start_end.h" #include "user.h" +#include "start_end.h" #include "xml_country.h" void @@ -19,6 +22,23 @@ bygfoot_init(Bygfoot *bygfoot, enum BygfootFrontend frontend) } } +void +bygfoot_load_bygfoot(Bygfoot *bygfoot, const gchar *id) +{ + char save_dir[256]; + char save_path[256]; + /* FIXME: This is not secure */ + file_get_bygfoot_dir(save_dir); + /* FIXME: There should be a helper function for this */ + sprintf(save_path, "%s%ssaves%s%s", save_dir, G_DIR_SEPARATOR_S, G_DIR_SEPARATOR_S, id); +} + +Country *bygfoot_load_country(Bygfoot *bygfoot, const gchar *country_name) +{ + xml_country_read(country_name, NULL); + return &country; +} + User *bygfoot_add_user(Bygfoot *bygfoot, const gchar *username, Team *tm) { User new_user = user_new(); diff --git a/src/bygfoot.h b/src/bygfoot.h index 94c4e515..df6aa43f 100644 --- a/src/bygfoot.h +++ b/src/bygfoot.h @@ -205,7 +205,13 @@ typedef struct gint paned_pos; } Windows; +typedef struct { + gchar *json_filename; +} CommandLineArgs; + void bygfoot_init(Bygfoot *bygfoot, enum BygfootFrontend frontend); +void bygfoot_load_bygfoot(Bygfoot *bygfoot, const gchar *id); +Country *bygfoot_load_country(Bygfoot *bygfoot, const gchar *country_name); User *bygfoot_add_user(Bygfoot *bygfoot, const gchar *username, Team *tm); void bygfoot_start_game(Bygfoot *bygfoot); void bygfoot_show_progress(const Bygfoot *bygfoot, gfloat value, const gchar *text, gint pictype); diff --git a/src/bygfoot_struct.h b/src/bygfoot_struct.h index 2bdc755b..01a22c03 100644 --- a/src/bygfoot_struct.h +++ b/src/bygfoot_struct.h @@ -1,8 +1,11 @@ #ifndef BYGFOOT_STRUCT_H #define BYGFOOT_STRUCT_H +#include + enum BygfootFrontend { - BYGFOOT_FRONTEND_GTK2 + BYGFOOT_FRONTEND_GTK2, + BYGFOOT_FRONTEND_CONSOLE, }; /** This struct holds all of the global state for a bygfoot game. The goal @@ -20,4 +23,5 @@ typedef struct /* @} */ } Bygfoot; + #endif diff --git a/src/file.h b/src/file.h index cb95d712..390f1105 100644 --- a/src/file.h +++ b/src/file.h @@ -71,6 +71,9 @@ file_load_user_conf_file(User *user); gboolean file_check_home_dir(void); +void +file_check_home_dir_create_dirs(void); + void file_check_home_dir_get_conf_files(GPtrArray **files_to_copy); diff --git a/src/json_compat.h b/src/json_compat.h new file mode 100644 index 00000000..da789841 --- /dev/null +++ b/src/json_compat.h @@ -0,0 +1,5 @@ + + +#ifndef HAVE_JSON_OBJECT_NEW_ARRAY_EXT + #define json_object_new_array_ext(size) json_object_new_array(); +#endif diff --git a/src/json_interface.c b/src/json_interface.c new file mode 100644 index 00000000..84c0e583 --- /dev/null +++ b/src/json_interface.c @@ -0,0 +1,663 @@ + +#include +#include +#include +#include "json_interface.h" +#include "json_serialize.h" +#include "user.h" +#include "league_struct.h" +#include "load_save.h" +#include "misc.h" +#include "team.h" +#include "option.h" +#include "start_end.h" + +static int bygfoot_json_do_commands(Bygfoot *bygfoot, const json_object *commands); +static int bygfoot_json_do_add_user(Bygfoot *bygfoot, const json_object *args); +static struct json_object *bygfoot_json_call_load_bygfoot(Bygfoot *bygfoot, const json_object *args); +static struct json_object *bygfoot_json_call_save_bygfoot(Bygfoot *bygfoot, const json_object *args); +static struct json_object *bygfoot_json_call_add_country(Bygfoot *bygfoot, const json_object *args); +static struct json_object *bygfoot_json_call_add_user(Bygfoot *bygfoot, const json_object *args); +static struct json_object *bygfoot_json_call_start_bygfoot(Bygfoot *bygfoot, const json_object *args); +static struct json_object *bygfoot_json_call_simulate_games(Bygfoot *bygfoot, + const json_object *args); +static struct json_object *bygfoot_json_call_get_tables(Bygfoot *bygfoot, + const json_object *args); +static struct json_object *bygfoot_json_call_get_players(Bygfoot *bygfoot, + const json_object *args); +static struct json_object *bygfoot_json_call_get_fixtures(Bygfoot *bygfoot, + const json_object *args); +static struct json_object *bygfoot_json_call_get_cups(Bygfoot *bygfoot, + const json_object *args); +static struct json_object *bygfoot_json_response_error(const char *command, + const char *error); +static json_object * +bygfoot_json_fixture_to_json(const Fixture *fixture); +static json_object * bygfoot_json_player_to_json(const Player *player); +static json_object *bygfoot_json_user_to_json(const User *user); +static json_object *bygfoot_json_table_to_json(const Table *table); + +struct json_field { + const gchar *name; + enum json_type type; +}; + +static gboolean +bygfoot_json_validate_arg_types(const struct json_object *args, + const struct json_field *fields) +{ + const struct json_field *field; + + for (field = fields; field->name; field++ ) { + struct json_object *value; + if (!json_object_object_get_ex(args, field->name, &value)) + continue; + if (!json_object_is_type(value, field->type)) + return FALSE; + } + return TRUE; +} + +int bygfoot_json_main(Bygfoot *bygfoot, const CommandLineArgs *cl_args) +{ + gchar *contents; + GError *error; + struct json_object *json; + enum json_tokener_error json_error; + + /* Disable option to skip rounds without user games, so the simulate_games + * command works correctly. */ + opt_set_int("int_opt_skip", 0); + + if (!g_file_get_contents(cl_args->json_filename, &contents, NULL, &error)) { + misc_print_error(&error, FALSE); + return 1; + } + + json = json_tokener_parse_verbose(contents, &json_error); + if (!json) { + fprintf(stderr, "Failed to parse json %s:\n", cl_args->json_filename); + fprintf(stderr, "%s\n", + json_tokener_error_desc(json_error)); + return 1; + } + + /* Handle configuration options */ + /* TODO: Get option from json */ + //bygfoot_set_save_dir(bygfoot, NULL); + + json_object_object_foreach(json, key, val) { + if (!strcmp("commands", key)) + return bygfoot_json_do_commands(bygfoot, val); + } + fprintf(stderr, "commands key is not present"); + return 1; +} + +static int bygfoot_json_do_commands(Bygfoot *bygfoot, const json_object *commands) +{ + size_t i, num_commands; + + static const struct json_func { + const gchar *command; + json_object* (*func)(Bygfoot *, const json_object *); + } json_funcs[] = { + { "load_bygfoot", bygfoot_json_call_load_bygfoot }, + { "save_bygfoot", bygfoot_json_call_save_bygfoot }, + { "add_country", bygfoot_json_call_add_country }, + { "add_user", bygfoot_json_call_add_user }, + { "start_bygfoot", bygfoot_json_call_start_bygfoot }, + { "simulate_games", bygfoot_json_call_simulate_games }, + { "get_tables", bygfoot_json_call_get_tables }, + { "get_players", bygfoot_json_call_get_players }, + { "get_fixtures", bygfoot_json_call_get_fixtures }, + { "cups", bygfoot_json_call_get_cups }, + { NULL, NULL} + }; + + if (!json_object_is_type(commands, json_type_array)) { + fprintf(stderr, "json commands should be in an array\n"); + return 1; + } + + num_commands = json_object_array_length(commands); + for (i = 0; i < num_commands; i++) { + const json_object *command = json_object_array_get_idx(commands, i); + struct json_object *response = NULL; + // TODO: CHECK COMMAND SIZE + + json_object_object_foreach(command, key, val) { + const struct json_func *json_func; + for (json_func = json_funcs; json_func->command; json_func++) { + if (!strcmp(json_func->command, key)) { + response = json_func->func(bygfoot, val); + break; + } + } + + if (!response) { + response = bygfoot_json_response_error("commands", "command not recognized"); + } + fprintf(stderr, "%s\n", json_object_to_json_string_ext(response, JSON_C_TO_STRING_PRETTY)); + json_object_put(response); + } + } + return 0; +} + +static const gchar * +bygfoot_json_validate_bygfoot_id(const json_object *args, json_object **error) +{ + const gchar *id; + /* Get the id field */ + json_object *id_obj = json_object_object_get(args, "id"); + + if (id_obj) { + if(!json_object_is_type(id_obj, json_type_string)) { + *error = bygfoot_json_response_error("", + "field 'id' must be a string"); + return NULL; + } + return json_object_get_string(id_obj); + } + + *error = bygfoot_json_response_error("", "field 'id' is missing or NULL"); + return NULL; +} + +static struct json_object * +bygfoot_json_call_load_bygfoot(Bygfoot *bygfoot, const json_object *args) +{ + const gchar *id = NULL; + struct json_object *filename_obj; + const gchar *filename; + static const struct json_field fields [] = { + { "filename", json_type_string } + }; + + if (!bygfoot_json_validate_arg_types(args, fields)) + return bygfoot_json_response_error("load_bygfoot", + "wrong type for argument"); + + if (!json_object_object_get_ex(args, "filename", &filename_obj)) + return bygfoot_json_response_error("load_bygfoot", + "filename argument is required"); + + filename = json_object_get_string(filename_obj); + if (!g_file_test(filename, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) + return bygfoot_json_response_error("load_bygfoot", "file not found"); + + load_save_load_game(bygfoot, filename, FALSE); + return json_object_new_object(); +} + +static struct json_object * +bygfoot_json_call_save_bygfoot(Bygfoot *bygfoot, const json_object *args) +{ + const gchar *id = NULL; + struct json_object *filename_obj; + const gchar *filename; + static const struct json_field fields [] = { + { "filename", json_type_string } + }; + + if (!bygfoot_json_validate_arg_types(args, fields)) + return bygfoot_json_response_error("save_bygfoot", + "wrong type for argument"); + + if (!json_object_object_get_ex(args, "filename", &filename_obj)) + return bygfoot_json_response_error("save_bygfoot", + "filename argument is required"); + + filename = json_object_get_string(filename_obj); + + load_save_save_game(bygfoot, filename); + return json_object_new_object(); +} + +static json_object * +bygfoot_json_call_add_country(Bygfoot *bygfoot, const json_object *args) +{ + gchar const *country_name = NULL; + static const struct json_field fields [] = { + { "name", json_type_string }, + { NULL, json_type_null } + }; + const struct json_field *field; + + for (field = fields; field->name; field++ ) { + struct json_object *value = json_object_object_get(args, field->name); + if (!value) + continue; + if (!json_object_is_type(value, field->type)) + continue; + + if (!strcmp(field->name, "name")) + country_name = json_object_get_string(value); + } + + if (!country_name) + return bygfoot_json_response_error("add_country", "field 'country' is required"); + + bygfoot_load_country(bygfoot, country_name); + return json_object_new_string("success"); +} + +static json_object *bygfoot_json_call_add_user(Bygfoot *bygfoot, const json_object *args) +{ + const char *command = "add_user"; + const char *username = NULL; + const char *country_name = NULL; + const char *team_name = NULL; + struct json_object *response; + Country *country; + Team *tm; + User *user; + json_object_object_foreach(args, key, val) { + if (!strcmp("username", key)) { + if (!json_object_is_type(val, json_type_string)) { + return bygfoot_json_response_error(command, "username must be of type string"); + } + username = json_object_get_string(val); + } + if (!strcmp("country", key)) { + if (!json_object_is_type(val, json_type_string)) { + return bygfoot_json_response_error(command, "country must be of type string"); + } + country_name = json_object_get_string(val); + } + if (!strcmp("team", key)) { + if (!json_object_is_type(val, json_type_string)) { + return bygfoot_json_response_error(command, "team must be of type string"); + } + team_name = json_object_get_string(val); + } + } + + if (!username) { + return bygfoot_json_response_error(command, "field 'username' is required"); + } + if (!country_name) { + return bygfoot_json_response_error(command, "field 'country' is required"); + } + if (!team_name) { + return bygfoot_json_response_error(command, "field 'team' is required"); + } + + country = bygfoot_load_country(bygfoot, country_name); + tm = team_of_sid(team_name, country); + user = bygfoot_add_user(bygfoot, username, tm); + + response = json_object_new_object(); + json_object_object_add(response, "success", bygfoot_json_user_to_json(user)); + return response; +} + +static json_object *bygfoot_json_call_start_bygfoot(Bygfoot *bygfoot, + const json_object *args) +{ + unsigned i; + bygfoot_start_game(bygfoot); + + /* FIXME: We should really be doing this when the user is added, but + * the user options get loaded during the bygfoot_start_bygfoot() call and w + * can't add options before that. + */ + for (i = 0; i < users->len; i++) { + /* We need to set this option to avoid activating the GUI. + * FIXME: More work is needed to separate the logic from the GUI */ + option_set_int("int_opt_user_show_live_game", &usr(i).options, 0); + } + return json_object_new_string("success"); +} + +static void simulate_weeks(Bygfoot *bygfoot, gint weeks) +{ + gint num_weeks = 0; + gint current_week = week; + while (num_weeks < weeks) { + do { + end_week_round(bygfoot); + } while (current_week == week); + current_week = week; + num_weeks++; + } +} + +static struct json_object *bygfoot_json_call_simulate_games(Bygfoot *bygfoot, + const json_object *args) +{ + int32_t rounds = 0; + int32_t weeks = 0; + int32_t seasons = 0; + unsigned i; + json_object_object_foreach(args, key, val) { + if (!strcmp("rounds", key)) { + rounds = json_object_get_int(val); + for (i = 0; i < rounds; i++) { + end_week_round(bygfoot); + } + } else if (!strcmp("weeks", key)) { + weeks = json_object_get_int(val); + simulate_weeks(bygfoot, weeks); + } else if (!strcmp("seasons", key)) { + gint num_seasons = 0; + gint start_week = week; + gint current_season = season; + seasons = json_object_get_int(val); + while (num_seasons < seasons) { + do { + end_week_round(bygfoot); + } while (current_season == season); + current_season = season; + num_seasons++; + } + simulate_weeks(bygfoot, start_week); + } + } + + return json_object_new_string("success"); +} + +static json_object * +bygfoot_json_call_get_fixtures(Bygfoot *bygfoot, const json_object *args) +{ + struct json_object *fixtures_obj = json_object_new_array(); + struct json_object *response, *data; + int i; + for (i = 0; i < country.leagues->len; i++) { + const League *league = &g_array_index(country.leagues, League, i); + int j; + for (j = 0; j < league->fixtures->len; j++) { + const Fixture *fixture = &g_array_index(league->fixtures, Fixture, j); + json_object_array_add(fixtures_obj, bygfoot_json_fixture_to_json(fixture)); + } + } + for (i = 0; i < country.cups->len; i++) { + const Cup *cup = &g_array_index(country.cups, Cup, i); + int j; + for (j = 0; j < cup->fixtures->len; j++) { + const Fixture *fixture = &g_array_index(cup->fixtures, Fixture, j); + json_object_array_add(fixtures_obj, bygfoot_json_fixture_to_json(fixture)); + } + } + + data = json_object_new_object(); + response = json_object_new_object(); + + json_object_object_add(data, "fixtures", fixtures_obj); + json_object_object_add(response, "success", data); + return response; +} + +static json_object * +bygfoot_json_call_get_tables(Bygfoot *bygfoot, const json_object *args) +{ + gchar const *country_name = NULL; + static const struct json_field fields [] = { + { NULL, json_type_null } + }; + const struct json_field *field; + int i; + struct json_object *response, *data, *tables; + + for (field = fields; field->name; field++ ) { + struct json_object *value = json_object_object_get(args, field->name); + if (!value) + continue; + if (!json_object_is_type(value, field->type)) + continue; + } + + tables = json_object_new_array(); + //GArray *leagues, *cups; + for (i = 0; i < country.leagues->len; i++) { + const League *league = &g_array_index(country.leagues, League, i); + int j; + for (j = 0; j < league->tables->len; j++) { + const Table *table = &g_array_index(league->tables, Table, j); + json_object_array_add(tables, bygfoot_json_table_to_json(table)); + } + } + response = json_object_new_object(); + data = json_object_new_object(); + json_object_object_add(data, "tables", tables); + json_object_object_add(response, "success", data); + return response; +} + +static json_object * +bygfoot_json_call_get_players(Bygfoot *bygfoot, const json_object *args) +{ + struct json_object *players_obj = json_object_new_array(); + struct json_object *response, *data; + int i; + for (i = 0; i < country.leagues->len; i++) { + const League *league = &g_array_index(country.leagues, League, i); + int j; + for (j = 0; j < league->teams->len; j++) { + const Team *team = &g_array_index(league->teams, Team, j); + int k; + for (k = 0; k < team->players->len; k++) { + const Player *player = &g_array_index(team->players, Player, k); + json_object_array_add(players_obj, bygfoot_json_player_to_json(player)); + } + + } + } + response = json_object_new_object(); + data = json_object_new_object(); + json_object_object_add(data, "players", players_obj); + json_object_object_add(response, "success", data); + return response; +} + +static json_object * +bygfoot_json_call_get_cups(Bygfoot *bygfoot, const json_object *args) +{ + + struct json_object *cups_obj = json_object_new_array_ext(country.cups->len); + + int i; + + for (i = 0; i < country.cups->len; i++) { + const Cup *cup = &g_array_index(country.cups, Cup, i); + json_object_array_add(cups_obj, bygfoot_json_serialize_cup(cup, NULL)); + } + + return cups_obj; +} + + +static json_object * +bygfoot_json_live_game_stats_to_json(const LiveGameStats *stats, gint team_index) +{ + +} + +static json_object * +bygfoot_json_fixture_stats_to_json(const Fixture *fixture, gint team_index) +{ + struct json_object *team_obj = json_object_new_object(); + struct json_object *stats_obj = json_object_new_object(); + + static const struct key_index { + const gchar *key; + gint index; + } result_fields[] = { + { "goals_regulation", 0 }, + { "goals_extra_time", 1 }, + { "goals_penalty_shootout", 2 }, + { NULL, 0 } + }; + + static const struct key_index live_stats_fields[] = { + { "goals_regular", LIVE_GAME_STAT_VALUE_GOALS_REGULAR }, + { "shots", LIVE_GAME_STAT_VALUE_SHOTS }, + { "shot_percentage", LIVE_GAME_STAT_VALUE_SHOT_PERCENTAGE }, + { "possession", LIVE_GAME_STAT_VALUE_POSSESSION }, + { "penalties", LIVE_GAME_STAT_VALUE_PENALTIES }, + { "fouls", LIVE_GAME_STAT_VALUE_FOULS }, + { "cards", LIVE_GAME_STAT_VALUE_CARDS }, + { "reds", LIVE_GAME_STAT_VALUE_REDS } , + { "injuries", LIVE_GAME_STAT_VALUE_INJURIES }, + { NULL, LIVE_GAME_STAT_VALUE_END } + }; + + const struct key_index *iter; + + if (!fixture->live_game) + return stats_obj; + + for (iter = result_fields; iter->key; iter++) { + gint value = fixture->result[team_index][iter->index]; + json_object_object_add(stats_obj, iter->key, json_object_new_int64(value)); + } + + /* Note it seems like fixture->live_game does not persist when the game is + * over, so that is why we are not including it in the json. */ + return stats_obj; +} + +static json_object * +bygfoot_json_fixture_to_json(const Fixture *fixture) +{ + struct json_object *fixture_obj = json_object_new_object(); + struct json_object *home_team_obj = json_object_new_object(); + struct json_object *away_team_obj = json_object_new_object(); + json_object_object_add(fixture_obj, "id", json_object_new_int64(fixture->id)); + json_object_object_add(fixture_obj, "league_id", json_object_new_int64(fixture->clid)); + json_object_object_add(fixture_obj, "round", json_object_new_int64(fixture->round)); + json_object_object_add(fixture_obj, "replay_number", json_object_new_int64(fixture->replay_number)); + json_object_object_add(fixture_obj, "week", json_object_new_int64(fixture->week_number)); + json_object_object_add(fixture_obj, "round", json_object_new_int64(fixture->week_round_number)); + + json_object_object_add(home_team_obj, "id", json_object_new_int64(fixture->team_ids[0])); + json_object_object_add(home_team_obj, "stats", + bygfoot_json_fixture_stats_to_json(fixture, 0)); + json_object_object_add(fixture_obj, "home_team", home_team_obj); + + json_object_object_add(away_team_obj, "id", json_object_new_int64(fixture->team_ids[1])); + json_object_object_add(away_team_obj, "stats", + bygfoot_json_fixture_stats_to_json(fixture, 1)); + json_object_object_add(fixture_obj, "away_team", away_team_obj); + + return fixture_obj; +} + +static json_object * +bygfoot_json_player_games_goals_to_json(const GArray *stats) +{ + int i; + struct json_object *stats_obj = json_object_new_array_ext(stats->len); + for (i = 0; i < stats->len; i++) { + const PlayerGamesGoals *league_stats = &g_array_index(stats, + PlayerGamesGoals, i); + struct json_object *league_stats_obj = json_object_new_object(); + json_object_object_add(league_stats_obj, "league_id", + json_object_new_int64(league_stats->clid)); + json_object_object_add(league_stats_obj, "games", + json_object_new_int64(league_stats->games)); + json_object_object_add(league_stats_obj, "goals", + json_object_new_int64(league_stats->goals)); + json_object_object_add(league_stats_obj, "shots", + json_object_new_int64(league_stats->shots)); + json_object_array_add(stats_obj, league_stats_obj); + } + return stats_obj; +} + +static json_object * +bygfoot_json_player_to_json(const Player *player) +{ + struct json_object *player_obj = json_object_new_object(); + json_object_object_add(player_obj, "name", json_object_new_string(player->name)); + json_object_object_add(player_obj, "season_stats", + bygfoot_json_player_games_goals_to_json(player->games_goals)); + + return player_obj; +} + +static json_object * +bygfoot_json_team_to_json(const Team *team) +{ + struct json_object *team_obj = json_object_new_object(); + + json_object_object_add(team_obj, "name", + json_object_new_string(team->name)); + return team_obj; +} + +static json_object * +bygfoot_json_table_element_to_json(const TableElement *element) +{ + struct json_object *element_obj = json_object_new_object(); + + json_object_object_add(element_obj, "team", + bygfoot_json_team_to_json(element->team)); + json_object_object_add(element_obj, "old_rank", + json_object_new_int64(element->old_rank)); + json_object_object_add(element_obj, "played", + json_object_new_int64(element->values[TABLE_PLAYED])); + json_object_object_add(element_obj, "won", + json_object_new_int64(element->values[TABLE_WON])); + json_object_object_add(element_obj, "draw", + json_object_new_int64(element->values[TABLE_DRAW])); + json_object_object_add(element_obj, "lost", + json_object_new_int64(element->values[TABLE_LOST])); + json_object_object_add(element_obj, "gf", + json_object_new_int64(element->values[TABLE_GF])); + json_object_object_add(element_obj, "ga", + json_object_new_int64(element->values[TABLE_GA])); + json_object_object_add(element_obj, "gd", + json_object_new_int64(element->values[TABLE_GD])); + json_object_object_add(element_obj, "pts", + json_object_new_int64(element->values[TABLE_PTS])); + return element_obj; +} + +static json_object * +bygfoot_json_table_to_json(const Table *table) +{ + struct json_object *table_obj = json_object_new_object(); + struct json_object *elements_obj = json_object_new_array_ext(table->elements->len); + int i; + + json_object_object_add(table_obj, "name", json_object_new_string(table->name)); + json_object_object_add(table_obj, "id", json_object_new_int64(table->clid)); + json_object_object_add(table_obj, "round", json_object_new_int64(table->round)); + + + for (i = 0; i < table->elements->len; i++) { + const TableElement *element = &g_array_index(table->elements, + TableElement, i); + json_object_array_add(elements_obj, + bygfoot_json_table_element_to_json(element)); + } + json_object_object_add(table_obj, "elements", elements_obj); + return table_obj; +} + +static json_object *bygfoot_json_user_to_json(const User *user) +{ + struct json_object *json = json_object_new_object(); + struct json_object *user_obj = json_object_new_object(); + json_object_object_add(user_obj, "name", json_object_new_string(user->name)); + json_object_object_add(json, "user", user_obj); + return json; +} + +static struct json_object *bygfoot_json_response_error(const char *command, + const char *error) +{ + struct json_object *json = json_object_new_object(); + json_object_object_add(json, "message", json_object_new_string(error)); + return json; +} + +static void bygfoot_json_error_to_console(const char *command, const char *error) +{ + struct json_object *json = bygfoot_json_response_error(command, error); + fprintf(stderr, "%s\n", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY)); + json_object_put(json); +} diff --git a/src/json_interface.h b/src/json_interface.h new file mode 100644 index 00000000..bb69dac6 --- /dev/null +++ b/src/json_interface.h @@ -0,0 +1,12 @@ +#ifndef JSON_INTERFACE_H +#define JSON_INTERFACE_H + +#include +#include "bygfoot.h" + + +int bygfoot_json_main(Bygfoot *bygfoot, const CommandLineArgs *cl_args); + +struct json_object *bygfoot_json_call_get_countries(Bygfoot *bygfoot, const json_object *args); + +#endif diff --git a/src/json_serialize.c b/src/json_serialize.c new file mode 100644 index 00000000..b671767f --- /dev/null +++ b/src/json_serialize.c @@ -0,0 +1,284 @@ +/** \file json_serialize.c + * + * + * This contains functions for converting Bygfoot objects to json. The general + * strategy is to only serialize values that are unchanged during a Bygfoot + * game. + * + * Object members that can change as the result of game play should be + * queried with functions directly. + * + * Parent: Full, Child: Full : Fields == NULL, recursive = TRUE + * Parent: Full, Child: ID: Fields == NULL, recursive = FALSE + * Parent: ID: Fields == IDs + * Child field in filter: IDs + * Child field in filter, recursive = TRUE: FULL + * + */ + +#include +#include +#include "json_serialize.h" +#include "league_struct.h" + +static void +serialize_gchar_array_callback(gpointer string, gpointer user_data) +{ + struct json_object *obj = (struct json_object*)user_data; + json_object_array_add(obj, json_object_new_string(string)); +} + +static struct json_object* +serialize_gchar_array(GPtrArray* ptr_array) +{ + struct json_object *array_obj = json_object_new_array_ext(ptr_array->len); + int i; + + g_ptr_array_foreach(ptr_array, serialize_gchar_array_callback, array_obj); + + return array_obj; +} + + +static GHashTable* +fields_to_hash_table(gchar **fields) +{ + gchar *field; + GHashTable *hash_table; + + if (!fields) + return NULL; + + hash_table = g_hash_table_new(g_str_hash, g_str_equal); + for (field = *fields; field; field++) { + g_hash_table_add(hash_table, field); + } + return hash_table; +} +struct json_object * +bygfoot_json_serialize_country_list(GPtrArray *country_list) +{ + return serialize_gchar_array(country_list); +} + + + +#define SERIALIZE_OBJECT_FIELD_FILTER(json_object, object, field, \ + serialize_func, field_list) \ + if (!field_list || g_hash_table_contains(field_list, #field)) { \ + json_object_object_add(json_object, #field, serialize_func(object->field)); \ + } + +#define SERIALIZE_OBJECT_FIELD_STRUCT(json_object, object, field, \ + serialize_func, field_list) \ + if (!field_list || g_hash_table_contains(field_list, #field)) { \ + json_object_object_add(json_object, #field, serialize_func(object->field, field_list)); \ + } + +#define SERIALIZE_OBJECT_FIELD(json_object, object, field, serialize_func) \ + SERIALIZE_OBJECT_FIELD_FILTER(json_object, object, field, serialize_func, NULL) + +struct json_object * +bygfoot_json_serialize_country(const Country *country) +{ + struct json_object *country_obj = json_object_new_object(); + + #define SERIALIZE_COUNTRY_FIELD(field, serialize_func) \ + SERIALIZE_OBJECT_FIELD(country_obj, country, field, serialize_func) + SERIALIZE_COUNTRY_FIELD(name, json_object_new_string); + SERIALIZE_COUNTRY_FIELD(symbol, json_object_new_string); + SERIALIZE_COUNTRY_FIELD(sid, json_object_new_string); + SERIALIZE_COUNTRY_FIELD(rating, json_object_new_int64); + SERIALIZE_COUNTRY_FIELD(reserve_promotion_rules, json_object_new_int64); +// SERIALIZE_COUNTRY_FIELD(leagues, bygfoot_json_serialize_league_array); +// SERIALIZE_COUNTRY_FIELD(cups, bygfoot_json_serialize_cup_array); +// SERIALIZE_COUNTRY_FIELD(allcups, bygfoot_json_serialize_cup_ptr_array); + + #undef SERIALIZE_COUNTRY_FIELD + + return country_obj; +} + +struct json_object * +bygfoot_json_serialize_league_array(const GArray *league_array) +{ + struct json_object *league_array_obj = + json_object_new_array_ext(league_array->len); + gint i; + for (i = 0; i < league_array->len; i++) { + const League *league = &g_array_index(league_array, League, i); + json_object_array_add(league_array_obj, + bygfoot_json_serialize_league(league)); + } + return league_array_obj; +} + +struct json_object * +bygfoot_json_serialize_league(const League *league) +{ + struct json_object *league_obj = json_object_new_object(); + + #define SERIALIZE_LEAGUE_FIELD(field, serialize_func) \ + SERIALIZE_OBJECT_FIELD(league_obj, league, field, serialize_func); + + SERIALIZE_LEAGUE_FIELD(name, json_object_new_string); + SERIALIZE_LEAGUE_FIELD(short_name, json_object_new_string); + SERIALIZE_LEAGUE_FIELD(sid, json_object_new_string); + SERIALIZE_LEAGUE_FIELD(symbol, json_object_new_string); + SERIALIZE_LEAGUE_FIELD(names_file, json_object_new_string); +} + +struct json_object * +bygfoot_json_serialize_stadium(Stadium stadium, GHashTable *fields) +{ + struct json_object *stadium_obj = json_object_new_object(); + Stadium *stadium_ptr = &stadium; + + #define SERIALIZE_STADIUM_FIELD(field, serialize_func) \ + SERIALIZE_OBJECT_FIELD_FILTER(stadium_obj, stadium_ptr, field, serialize_func, fields); + + SERIALIZE_STADIUM_FIELD(name, json_object_new_string); + SERIALIZE_STADIUM_FIELD(capacity, json_object_new_int64); + SERIALIZE_STADIUM_FIELD(average_attendance, json_object_new_int64); + SERIALIZE_STADIUM_FIELD(possible_attendance, json_object_new_int64); + SERIALIZE_STADIUM_FIELD(safety, json_object_new_double); + SERIALIZE_STADIUM_FIELD(ticket_price, json_object_new_double); + + return stadium_obj; +} + +struct json_object * +bygfoot_json_serialize_team(const Team *team, GHashTable *fields) +{ + + struct json_object *team_obj = json_object_new_object(); + + #define SERIALIZE_TEAM_FIELD(field, serialize_func) \ + SERIALIZE_OBJECT_FIELD_FILTER(team_obj, team, field, serialize_func, fields); + #define SERIALIZE_TEAM_FIELD_STRUCT(field, serialize_func) \ + SERIALIZE_OBJECT_FIELD_STRUCT(team_obj, team, field, serialize_func, fields); + + SERIALIZE_TEAM_FIELD(name, json_object_new_string); + SERIALIZE_TEAM_FIELD(symbol, json_object_new_string); + SERIALIZE_TEAM_FIELD(names_file, json_object_new_string); + SERIALIZE_TEAM_FIELD(def_file, json_object_new_string); + SERIALIZE_TEAM_FIELD(strategy_sid, json_object_new_string); + SERIALIZE_TEAM_FIELD(clid, json_object_new_int64); + SERIALIZE_TEAM_FIELD(id, json_object_new_int64); + SERIALIZE_TEAM_FIELD(structure, json_object_new_int64); + SERIALIZE_TEAM_FIELD(style, json_object_new_int64); + SERIALIZE_TEAM_FIELD(boost, json_object_new_int64); + SERIALIZE_TEAM_FIELD(average_talent, json_object_new_double); + SERIALIZE_TEAM_FIELD(luck, json_object_new_double); + SERIALIZE_TEAM_FIELD_STRUCT(stadium, bygfoot_json_serialize_stadium); + //SERIALIZE_TEAM_FIELD_STRUCT(players, bygfoot_json_serialize_players); + SERIALIZE_TEAM_FIELD(first_team_sid, json_object_new_string); + SERIALIZE_TEAM_FIELD(first_team_id, json_object_new_int64); + SERIALIZE_TEAM_FIELD(reserve_level, json_object_new_int64); + + return team_obj; +} + +static void +serialize_team_pointers_callback(gpointer team, gpointer user_data) +{ + gchar *fields[] = { + "name", + "id" + }; + GHashTable *hash_table = fields_to_hash_table(fields); + struct json_object *obj = (struct json_object*)user_data; + json_object_array_add(obj, bygfoot_json_serialize_team((Team*)team, hash_table)); +} + +struct json_object * +bygfoot_json_serialize_team_ptrs(GPtrArray *team_ptrs, GHashTable *fields) +{ + struct json_object *array_obj = json_object_new_array_ext(team_ptrs->len); + + g_ptr_array_foreach(team_ptrs, serialize_team_pointers_callback, array_obj); + + return array_obj; +} + +struct json_object * +bygfoot_json_serialize_cup_round(const CupRound *round, + GHashTable *fields) +{ + struct json_object *cup_round_obj = json_object_new_object(); + + #define SERIALIZE_CUP_ROUND_FIELD(field, serialize_func) \ + SERIALIZE_OBJECT_FIELD_FILTER(cup_round_obj, round, field, serialize_func, fields); + #define SERIALIZE_CUP_ROUND_FIELD_STRUCT(field, serialize_func) \ + SERIALIZE_OBJECT_FIELD_STRUCT(cup_round_obj, round, field, serialize_func, fields); + + SERIALIZE_CUP_ROUND_FIELD(name, json_object_new_string); + SERIALIZE_CUP_ROUND_FIELD(home_away, json_object_new_boolean); + SERIALIZE_CUP_ROUND_FIELD(replay, json_object_new_int64); + SERIALIZE_CUP_ROUND_FIELD(neutral, json_object_new_boolean); + SERIALIZE_CUP_ROUND_FIELD(randomise_teams, json_object_new_boolean); + SERIALIZE_CUP_ROUND_FIELD(round_robin_number_of_groups, json_object_new_int64); + SERIALIZE_CUP_ROUND_FIELD(round_robin_number_of_advance, json_object_new_int64); + SERIALIZE_CUP_ROUND_FIELD(round_robin_number_of_best_advance, json_object_new_int64); + SERIALIZE_CUP_ROUND_FIELD(round_robins, json_object_new_int64); + //SERIALIZE_CUP_ROUND_FIELD(rr_breaks, bygfoot_json_serialize_int_array); + SERIALIZE_CUP_ROUND_FIELD(new_teams, json_object_new_int64); + SERIALIZE_CUP_ROUND_FIELD(byes, json_object_new_int64); + SERIALIZE_CUP_ROUND_FIELD(delay, json_object_new_int64); + //SERIALIZE_CUP_ROUND_FIELD(two_match_weeks, bygfoot_json_serialize_int_int_array); + SERIALIZE_CUP_ROUND_FIELD_STRUCT(team_ptrs, bygfoot_json_serialize_team_ptrs); + //SERIALIZE_CUP_ROUND_FIELD(choose_teams, bygfoot_json_serialize_choose_teams); + //SERIALIZE_CUP_ROUND_FIELD(tables, bygfoot_json_serialize_tables); + //SERIALIZE_CUP_ROUND_FIELD(waits, bygfoot_json_seriialize_waits); + + return cup_round_obj; +} + +struct json_object * +bygfoot_json_serialize_cup_rounds(const GArray *rounds, + GHashTable *fields) +{ + struct json_object *rounds_array_obj = + json_object_new_array_ext(rounds->len); + gint i; + for (i = 0; i < rounds->len; i++) { + const CupRound *round = &g_array_index(rounds, CupRound, i); + json_object_array_add(rounds_array_obj, + bygfoot_json_serialize_cup_round(round, fields)); + } + return rounds_array_obj; +} + +struct json_object * +bygfoot_json_serialize_cup(const Cup *cup, GHashTable *fields) +{ + struct json_object *cup_obj = json_object_new_object(); + + #define SERIALIZE_CUP_FIELD(field, serialize_func) \ + SERIALIZE_OBJECT_FIELD_FILTER(cup_obj, cup, field, serialize_func, fields); + #define SERIALIZE_CUP_FIELD_STRUCT(field, serialize_func) \ + SERIALIZE_OBJECT_FIELD_STRUCT(cup_obj, cup, field, serialize_func, fields); + + SERIALIZE_CUP_FIELD(name, json_object_new_string); + SERIALIZE_CUP_FIELD(short_name, json_object_new_string); + SERIALIZE_CUP_FIELD(symbol, json_object_new_string); + SERIALIZE_CUP_FIELD(sid, json_object_new_string); + SERIALIZE_CUP_FIELD(id, json_object_new_int64); + SERIALIZE_CUP_FIELD(group, json_object_new_int64); + SERIALIZE_CUP_FIELD(last_week, json_object_new_int64); + SERIALIZE_CUP_FIELD(week_gap, json_object_new_int64); + SERIALIZE_CUP_FIELD(add_week, json_object_new_int64); + SERIALIZE_CUP_FIELD(yellow_red, json_object_new_int64); + SERIALIZE_CUP_FIELD(talent_diff, json_object_new_double); + SERIALIZE_CUP_FIELD(next_fixture_update_week, json_object_new_int64); + SERIALIZE_CUP_FIELD(next_fixture_update_week_round, json_object_new_int64); + SERIALIZE_CUP_FIELD(properties, serialize_gchar_array); + SERIALIZE_CUP_FIELD_STRUCT(rounds, bygfoot_json_serialize_cup_rounds); +// SERIALIZE_CUP_FIELD(bye + SERIALIZE_CUP_FIELD_STRUCT(teams, bygfoot_json_serialize_team_ptrs); + SERIALIZE_CUP_FIELD(team_names, serialize_gchar_array); +// SERIALIZE_CUP_FIELD(fixtures, +// SERIALIZE_CUP_FIELD(week_breaks +// SERIALIZE_CUP_FIELD(skip_weeks_with + return cup_obj; +} diff --git a/src/json_serialize.h b/src/json_serialize.h new file mode 100644 index 00000000..8034f9c0 --- /dev/null +++ b/src/json_serialize.h @@ -0,0 +1,27 @@ +#ifndef JSON_SERIALIZE_H +#define JSON_SERIALIZE_H + +#include "bygfoot.h" +#include "cup_struct.h" +#include "league_struct.h" +#include "json_compat.h" + +struct json_object * +bygfoot_json_serialize_country_list(GPtrArray *country_list); + +struct json_object * +bygfoot_json_serialize_country(const Country *country); + +struct json_object * +bygfoot_json_serialize_league_array(const GArray *league_array); + +struct json_object * +bygfoot_json_serialize_league(const League *league); + +struct json_object * +bygfoot_json_serialize_team_ptrs(GPtrArray *team_ptrs, + GHashTable *fields); + +struct json_object * +bygfoot_json_serialize_cup(const Cup *cup, GHashTable *fields); +#endif diff --git a/src/main.c b/src/main.c index eeab9d3a..c6361f1f 100644 --- a/src/main.c +++ b/src/main.c @@ -38,6 +38,9 @@ #include "file.h" #include "free.h" #include "job_struct.h" +#ifdef ENABLE_JSON +#include "json_interface.h" +#endif #include "language.h" #include "lg_commentary.h" #include "live_game.h" @@ -70,6 +73,39 @@ (cl switch -l). */ gboolean load_last_save; +/** Parse command line options used for selecting the frontend or backend to + * use with bygfoot. + */ +static void +main_parse_frontend_backend_cl_arguments(gint *argc, gchar ***argv, CommandLineArgs *args) +{ + GError *error = NULL; + GOptionContext *context = NULL; + GOptionEntry entries[] = { + { "json", 0, 0, G_OPTION_ARG_FILENAME, &args->json_filename, + "JSON file containing commands to run. bygfoot will run the " + "commands in this file and then exit", "FILE"}, + {NULL} + }; + + if(argc == NULL || argv == NULL) + return; + + context = g_option_context_new(_("- a simple and addictive GTK2 football manager")); + g_option_context_set_ignore_unknown_options(context, TRUE); + g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE); + g_option_context_add_group(context, gtk_get_option_group (FALSE)); + g_option_context_parse(context, argc, argv, &error); + g_option_context_free(context); + + if(error != NULL) + { + misc_print_error(&error, FALSE); + return; + } + +} + /** Parse the command line arguments given by the user. */ void main_parse_cl_arguments(gint *argc, gchar ***argv, Bygfoot *bygfoot) @@ -411,6 +447,7 @@ main_init(gint *argc, gchar ***argv, Bygfoot *bygfoot) main (gint argc, gchar *argv[]) { Bygfoot bygfoot; + CommandLineArgs cl_args; #ifdef DEBUG printf("main\n"); #endif @@ -425,6 +462,18 @@ main (gint argc, gchar *argv[]) dup2 (fd1, 1); int fd2 = open ("stderr.log", O_CREAT|O_WRONLY|O_TRUNC, 0666); dup2 (fd2, 2); +#endif + memset(&cl_args, 0, sizeof(cl_args)); +#ifdef ENABLE_JSON + main_parse_frontend_backend_cl_arguments(&argc, &argv, &cl_args); + + if (cl_args.json_filename) { + bygfoot_init(&bygfoot, BYGFOOT_FRONTEND_CONSOLE); + main_init(&argc, &argv, &bygfoot); + file_check_home_dir_create_dirs(); + validate_country_files(); + return bygfoot_json_main(&bygfoot, &cl_args); + } #endif bygfoot_init(&bygfoot, BYGFOOT_FRONTEND_GTK2); gtk_init (&argc, &argv); diff --git a/test/test-country-defs.sh b/test/test-country-defs.sh new file mode 100644 index 00000000..bea6b7df --- /dev/null +++ b/test/test-country-defs.sh @@ -0,0 +1,86 @@ + +bygfoot_bin=$1 +bygfoot_bindir=`dirname $bygfoot_bin` + +status=0 +countries=" \ + albania \ + andorra \ + armenia \ + austria \ + azerbaijan \ + belarus \ + belgium \ + bosnia_herzegovina \ + bulgaria \ + croatia \ + cyprus \ + czech \ + denmark \ + england \ + estonia \ + faroe_islands \ + finland \ + france \ + n_macedonia \ + georgia \ + germany \ + gibraltar \ + greece \ + hungary \ + iceland \ + ireland \ + israel \ + italy \ + kazakhstan \ + kosovo \ + latvia \ + liechtenstein \ + lithuania \ + luxembourg \ + malta \ + moldova \ + montenegro \ + n_ireland \ + netherlands \ + norway \ + poland \ + portugal \ + romania \ + russia \ + san_marino \ + scotland \ + serbia \ + slovakia \ + slovenia \ + spain \ + sweden \ + switzerland \ + turkey \ + ukraine \ + wales" + +json_file=`mktemp` + +pushd $bygfoot_bindir + +for c in $countries; do + cat < $json_file +{ 'commands' : [ + { 'add_country' : { 'name' : '$c' }}, + { 'start_bygfoot' : { }}, + { 'simulate_games' : {'seasons' : 2 }}, +]} +EOF + + tmphome=`mktemp -d` + if HOME=$tmphome ./bygfoot --random-seed=1 --json=$json_file; then + echo "$c: PASS" + else + echo "$c: FAIL" + status=1 + fi +done + + +exit $status diff --git a/test/test-load-save.sh b/test/test-load-save.sh new file mode 100644 index 00000000..04cb6202 --- /dev/null +++ b/test/test-load-save.sh @@ -0,0 +1,36 @@ +set -e + +bygfoot_bin=$1 +bygfoot_bindir=`dirname $bygfoot_bin` + +json_file=`mktemp` +save_dir=`mktemp -d` + +cat < $json_file +{ 'commands' : [ + { 'add_country' : { 'name' : 'faroe_islands' }}, + { 'start_bygfoot' : {}}, + { 'simulate_games' : {'weeks' : 5}}, + { 'save_bygfoot' : {'filename' : '$save_dir/save0.zip'}}, + { 'load_bygfoot' : {'filename' : '$save_dir/save0.zip'}}, + { 'save_bygfoot' : {'filename' : '$save_dir/save1.zip'}}, + { 'simulate_games' : {'years' : 1}}, +]} +EOF + +echo $save_dir +tmphome=`mktemp -d` +pushd $bygfoot_bindir +HOME=$tmphome ./bygfoot --random-seed=1 --json=$json_file + +for f in save0 save1; do + + mkdir -p $save_dir/$f + unzip -q $save_dir/$f.zip -d $save_dir/$f + sed -i "s/${f}___//g" $save_dir/$f/* + for file in `ls $save_dir/$f`; do + new_name=`echo $file | sed "s/${f}___//g"` + mv $save_dir/$f/$file $save_dir/$f/$new_name + done +done +diff -r $save_dir/save0 $save_dir/save1