From b4fbb99ec4cb066c32233ab55cff129e5f3baa61 Mon Sep 17 00:00:00 2001 From: "Gergely Polonkai (W00d5t0ck)" Date: Thu, 29 Mar 2012 18:51:24 +0200 Subject: [PATCH] Advanced forward with the world loading code. Signed-off-by: Gergely Polonkai (W00d5t0ck) --- wmud/main.c | 14 +- wmud/world.c | 468 ++++++++++++++++++++++++++++++++++++++++++++++----- wmud/world.h | 31 +++- 3 files changed, 468 insertions(+), 45 deletions(-) diff --git a/wmud/main.c b/wmud/main.c index 422b539..6711cb8 100644 --- a/wmud/main.c +++ b/wmud/main.c @@ -35,6 +35,7 @@ #include "maintenance.h" #include "game.h" #include "configuration.h" +#include "world.h" /** * SECTION:utils @@ -120,9 +121,10 @@ debug_context(char *file, int line) void wmud_type_init(void) { - WMUD_CONFIG_ERROR = g_quark_from_string("wmud_config_error"); - WMUD_DB_ERROR = g_quark_from_string("wmud_db_error"); - WMUD_INTERPRETER_ERROR = g_quark_from_string("wmud_interpreter_error"); + WMUD_CONFIG_ERROR = g_quark_from_string("wmud-config-error"); + WMUD_DB_ERROR = g_quark_from_string("wmud-db-error"); + WMUD_INTERPRETER_ERROR = g_quark_from_string("wmud-interpreter-error"); + WMUD_WORLD_ERROR = g_quark_from_string("wmud-world-error"); } /** @@ -178,7 +180,11 @@ main(int argc, char **argv) g_clear_error(&err); wmud_db_load_players(&err); - wmud_world_load(&err); + if (!wmud_world_load(&err)) + { + /* TODO: Send some kind of an error? */ + return 1; + } /* Initialization ends here */ diff --git a/wmud/world.c b/wmud/world.c index 08ae664..f177881 100644 --- a/wmud/world.c +++ b/wmud/world.c @@ -30,6 +30,33 @@ * */ +struct findData { + GSList *list; + guint found; + gchar *last; +}; + +GQuark WMUD_WORLD_ERROR = 0; + +static gint +check_plane_dups2(wmudPlane *plane, gchar *name) +{ + return (g_ascii_strcasecmp(plane->name, name)); +} + +static void +check_plane_dups1(wmudPlane *plane, struct findData *find_data) +{ + if (find_data->last != plane->name) + { + find_data->last = plane->name; + find_data->found = (find_data->found > 1) ? find_data->found : 0; + } + + if (g_slist_find_custom(find_data->list, plane->name, (GCompareFunc)check_plane_dups2)) + find_data->found++; +} + /** * wmud_world_check_planes: * @planes: a #GSList of wmudPlane structs @@ -42,7 +69,35 @@ gboolean wmud_world_check_planes(GSList *planes, GError **err) { - return FALSE; + struct findData find_data = {planes, 0, NULL}; + + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Checking plane names for duplicates"); + + g_slist_foreach(planes, (GFunc)check_plane_dups1, &find_data); + + if (find_data.found > 1) + g_set_error(err, WMUD_WORLD_ERROR, WMUD_WORLD_ERROR_DUPPLANE, "Duplicate plane names found. Please check your database!\n"); + + return (find_data.found < 2); +} + +static gint +check_planet_dups2(wmudPlanet *planet, gchar *name) +{ + return (g_ascii_strcasecmp(planet->name, name)); +} + +static void +check_planet_dups1(wmudPlanet *planet, struct findData *find_data) +{ + if (find_data->last != planet->name) + { + find_data->last = planet->name; + find_data->found = (find_data->found > 1) ? find_data->found : 0; + } + + if (g_slist_find_custom(find_data->list, planet->name, (GCompareFunc)check_planet_dups2)) + find_data->found++; } /** @@ -57,7 +112,35 @@ wmud_world_check_planes(GSList *planes, GError **err) gboolean wmud_world_check_planets(GSList *planets, GError **err) { - return FALSE; + struct findData find_data = {planets, 0, NULL}; + + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Checking planet names for duplicates"); + + g_slist_foreach(planets, (GFunc)check_planet_dups1, &find_data); + + if (find_data.found > 1) + g_set_error(err, WMUD_WORLD_ERROR, WMUD_WORLD_ERROR_DUPPLANET, "Duplicate planet names found. Please check your database!\n"); + + return (find_data.found < 2); +} + +static gint +check_area_dups2(wmudArea *area, gchar *name) +{ + return (g_ascii_strcasecmp(area->name, name)); +} + +static void +check_area_dups1(wmudArea *area, struct findData *find_data) +{ + if (find_data->last != area->name) + { + find_data->last = area->name; + find_data->found = (find_data->found > 1) ? find_data->found : 0; + } + + if (g_slist_find_custom(find_data->list, area->name, (GCompareFunc)check_area_dups2)) + find_data->found++; } /** @@ -72,7 +155,16 @@ wmud_world_check_planets(GSList *planets, GError **err) gboolean wmud_world_check_areas(GSList *areas, GError **err) { - return FALSE; + struct findData find_data = {areas, 0, NULL}; + + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Checking area names for duplicates"); + + g_slist_foreach(areas, (GFunc)check_area_dups1, &find_data); + + if (find_data.found > 1) + g_set_error(err, WMUD_WORLD_ERROR, WMUD_WORLD_ERROR_DUPAREA, "Duplicate area names found. Please check your database!"); + + return (find_data.found < 2); } /** @@ -93,6 +185,53 @@ wmud_world_check_exits(GSList *exits, GSList *directions, GSList *rooms, GError return FALSE; } +static gint +check_room_dups2(wmudRoom *room1, wmudRoom *room2) +{ + if (room1->area_id == room2->area_id) + { + return g_ascii_strcasecmp(room1->name, room2->name); + } + return 1; +} + +static void +check_room_dups1(wmudRoom *room, struct findData *find_data) +{ + if (find_data->last != (gchar *)room) + { + find_data->last = (gchar *)room; + find_data->found = (find_data->found > 1) ? find_data->found : 0; + } + + if (g_slist_find_custom(find_data->list, room, (GCompareFunc)check_room_dups2)) + find_data->found++; +} + +/** + * wmud_world_check_rooms: + * @rooms: a #GSList of wmudRoom structs + * @err: a #GError where this function can send back error messages + * + * Check rooms. + * + * Return value: %TRUE if everything goes well, %FALSE otherwise + */ +gboolean +wmud_world_check_rooms(GSList *rooms, GError **err) +{ + struct findData find_data = {rooms, 0, NULL}; + + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Checking room consistency"); + + g_slist_foreach(rooms, (GFunc)check_room_dups1, &find_data); + + if (find_data.found > 1) + g_set_error(err, WMUD_WORLD_ERROR, WMUD_WORLD_ERROR_DUPROOM, "Duplicate room names found. Please check your database!"); + + return (find_data.found < 2); +} + /** * wmud_world_assoc_planets_planes: * @planets: a #GSList of wmudPlanets @@ -159,6 +298,126 @@ wmud_world_assoc_exits_rooms(GSList *exits, GSList *rooms, GError **err) { } +static void +free_direction(wmudDirection *dir) +{ + if (dir->short_name) + g_free(dir->short_name); + if (dir->name) + g_free(dir->name); + g_free(dir); +} + +void +wmud_world_free_directions(GSList *directions) +{ + if (directions) + { +#if GLIB_CHECK_VERSION(2, 28, 0) + g_slist_free_full(directions, (GDestroyNotify)free_direction); +#else + g_slist_foreach(directions, (GFunc)free_direction, NULL); + g_slist_free(directions); +#endif + } +} + +static void +free_plane(wmudPlane *plane) +{ + if (plane->name) + g_free(plane->name); + + g_free(plane); +} + +void +wmud_world_free_planes(GSList *planes) +{ + if (planes) + { +#if GLIB_CHECK_VERSION(2, 28, 0) + g_slist_free_full(planes, (GDestroyNotify)free_plane); +#else + g_slist_foreach(planes, (GFunc)free_plane, NULL); + g_slist_free(planes); +#endif + } +} + +static void +free_planet(wmudPlanet *planet) +{ + if (planet->name) + g_free(planet->name); + + g_free(planet); +} + +void +wmud_world_free_planets(GSList *planets) +{ + if (planets) + { +#if GLIB_CHECK_VERSION(2, 28, 0) + g_slist_free_full(planets, (GDestroyNotify)free_planet); +#else + g_slist_foreach(planets, (GFunc)free_planet, NULL); + g_slist_free(planets); +#endif + } +} + +static void +free_area(wmudArea *area) +{ + if (area->name) + g_free(area->name); + + g_free(area); +} + +void +wmud_world_free_areas(GSList *areas) +{ + if (areas) + { +#if GLIB_CHECK_VERSION(2, 28, 0) + g_slist_free_full(areas, (GDestroyNotify)free_area); +#else + g_slist_foreach(areas, (GFunc)free_area, NULL); + g_slist_free(areas); +#endif + } +} + +static void +free_room(wmudRoom *room) +{ + if (room->name) + g_free(room->name); + if (room->distant_description) + g_free(room->distant_description); + if (room->close_description) + g_free(room->close_description); + + g_free(room); +} + +void +wmud_world_free_rooms(GSList *rooms) +{ + if (rooms) + { +#if GLIB_CHECK_VERSION(2, 28, 0) + g_slist_free_full(rooms, (GDestroyNotify)free_room); +#else + g_slist_foreach(rooms, (GFunc)free_room, NULL); + g_slist_free(rooms); +#endif + } +} + /** * wmud_world_load: * @err: a #GError to put error messages into @@ -176,62 +435,191 @@ wmud_world_load(GError **err) *exits = NULL; GError *in_err = NULL; - /* Load directions from the database */ - wmud_db_load_directions(&directions, &in_err); + /* Load directions from the database and check them */ + if (!wmud_db_load_directions(&directions, &in_err)) + { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "Could not load directions from database: %s", in_err->message); + wmud_world_free_directions(directions); + g_clear_error(&in_err); - /* Check if the loaded directions conform to the rules */ - g_clear_error(&in_err); - wmud_interpreter_check_directions(directions, &in_err); + return FALSE; + } + if (!directions) + { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "No directions were found in the database!"); + g_clear_error(&in_err); - /* Load planes from the database */ + return FALSE; + } g_clear_error(&in_err); - wmud_db_load_planes(&planes, &in_err); + if (!wmud_interpreter_check_directions(directions, &in_err)) + { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "Direction list pre-flight check error: %s", in_err->message); + wmud_world_free_directions(directions); + g_clear_error(&in_err); - /* Check if the loaded planes conform to the rules */ - g_clear_error(&in_err); - wmud_world_check_planes(planes, &in_err); + return FALSE; + } - /* Load planets from the database */ + /* Load planes from the database and check them */ g_clear_error(&in_err); - wmud_db_load_planets(&planets, &in_err); + if (!wmud_db_load_planes(&planes, &in_err)) + { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "Could not load planes from database: %s", in_err->message); + wmud_world_free_planes(planes); + wmud_world_free_directions(directions); + g_clear_error(&in_err); - /* Check if the planets conform to the rules */ + return FALSE; + } + if (!planes) + { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "No planes were found in the database!"); + wmud_world_free_directions(directions); + g_clear_error(&in_err); + + return FALSE; + } g_clear_error(&in_err); - wmud_world_check_planets(planets, &in_err); + if (!wmud_world_check_planes(planes, &in_err)) + { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "Plane list pre-flight check error: %s", in_err->message); + wmud_world_free_planes(planes); + wmud_world_free_directions(directions); + g_clear_error(&in_err); + + return FALSE; + } + + /* Load planets from the database and check them */ + g_clear_error(&in_err); + if (!wmud_db_load_planets(&planets, &in_err)) + { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "Could not load planets from database: %s", in_err->message); + wmud_world_free_planets(planets); + wmud_world_free_planes(planes); + wmud_world_free_directions(directions); + g_clear_error(&in_err); + + return FALSE; + } + if (!planets) + { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "No planets were found in the database!"); + wmud_world_free_planes(planes); + wmud_world_free_directions(directions); + g_clear_error(&in_err); + + return FALSE; + } + g_clear_error(&in_err); + if (!wmud_world_check_planets(planets, &in_err)) + { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "Planet list pre-flight check error: %s", in_err->message); + wmud_world_free_planets(planets); + wmud_world_free_planes(planes); + wmud_world_free_directions(directions); + g_clear_error(&in_err); + + return FALSE; + } + + /* Load areas from the database and check them */ + g_clear_error(&in_err); + if (!wmud_db_load_areas(&areas, &in_err)) + { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "Could not load areas from database: %s", in_err->message); + wmud_world_free_areas(areas); + wmud_world_free_planets(planets); + wmud_world_free_planes(planes); + wmud_world_free_directions(directions); + g_clear_error(&in_err); + + return FALSE; + } + if (!areas) + { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "No areas were found in the database!"); + wmud_world_free_planets(planets); + wmud_world_free_planes(planes); + wmud_world_free_directions(directions); + g_clear_error(&in_err); + + return FALSE; + } + g_clear_error(&in_err); + if (!wmud_world_check_areas(areas, &in_err)) + { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "Area list pre-flight check error: %s", in_err->message); + wmud_world_free_areas(areas); + wmud_world_free_planets(planets); + wmud_world_free_planes(planes); + wmud_world_free_directions(directions); + g_clear_error(&in_err); + + return FALSE; + } + + /* Load rooms from the database and check them */ + g_clear_error(&in_err); + if (!wmud_db_load_rooms(&rooms, &in_err)) + { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "Could not load areas from database: %s", in_err->message); + wmud_world_free_rooms(rooms); + wmud_world_free_areas(areas); + wmud_world_free_planets(planets); + wmud_world_free_planes(planes); + wmud_world_free_directions(directions); + g_clear_error(&in_err); + + return FALSE; + } + if (!rooms) + { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "No rooms were found in the database!"); + wmud_world_free_areas(areas); + wmud_world_free_planets(planets); + wmud_world_free_planes(planes); + wmud_world_free_directions(directions); + g_clear_error(&in_err); + + return FALSE; + } + g_clear_error(&in_err); + if (!wmud_world_check_rooms(rooms, &in_err)) + { + g_log(G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "Room list pre-flight check error: %s", in_err->message); + wmud_world_free_rooms(rooms); + wmud_world_free_areas(areas); + wmud_world_free_planets(planets); + wmud_world_free_planes(planes); + wmud_world_free_directions(directions); + g_clear_error(&in_err); + + return FALSE; + } + + /* Load room exits from the database and check them */ + g_clear_error(&in_err); + wmud_db_load_exits(&exits, &in_err); + g_clear_error(&in_err); + wmud_world_check_exits(exits, directions, rooms, &in_err); + + /* World loading finished. Now let's tie the parts together... */ /* Put the planets on the planes */ g_clear_error(&in_err); wmud_world_assoc_planets_planes(planets, planes, &in_err); - /* Load areas from the database */ - g_clear_error(&in_err); - wmud_db_load_areas(&areas, &in_err); - - /* Check if the areas conform to the rules */ - g_clear_error(&in_err); - wmud_world_check_areas(areas, &in_err); - - /* Load rooms from the database */ - g_clear_error(&in_err); - wmud_db_load_rooms(&rooms, &in_err); - - /* Associate rooms with the areas */ + /* Generate the areas */ g_clear_error(&in_err); wmud_world_assoc_rooms_areas(rooms, areas, &in_err); - /* Associate rooms with planets */ + /* Teleport the previously built areas to the planets */ g_clear_error(&in_err); wmud_world_assoc_rooms_planets(rooms, planets, &in_err); - /* Load room exits from the database */ - g_clear_error(&in_err); - wmud_db_load_exits(&exits, &in_err); - - /* Check if the exits conform to the rules */ - g_clear_error(&in_err); - wmud_world_check_exits(exits, &in_err); - - /* Associate exits with rooms */ + /* And finally, create the doors between the rooms */ g_clear_error(&in_err); wmud_world_assoc_exits_rooms(exits, rooms, &in_err); diff --git a/wmud/world.h b/wmud/world.h index ac5eff2..2ca4d36 100644 --- a/wmud/world.h +++ b/wmud/world.h @@ -21,11 +21,37 @@ #include +extern GQuark WMUD_WORLD_ERROR; +typedef enum { + WMUD_WORLD_ERROR_DUPPLANE, + WMUD_WORLD_ERROR_DUPPLANET, + WMUD_WORLD_ERROR_DUPAREA, + WMUD_WORLD_ERROR_DUPROOM +} wmudWorldError; + typedef struct _wmudPlane { guint id; gchar *name; } wmudPlane; +typedef struct _wmudPlanet { + guint id; + gchar *name; +} wmudPlanet; + +typedef struct _wmudArea { + guint id; + gchar *name; +} wmudArea; + +typedef struct _wmudRoom { + guint id; + guint area_id; + gchar *name; + gchar *distant_description; + gchar *close_description; +} wmudRoom; + typedef struct _wmudDirection { guint id; gchar *short_name; @@ -35,12 +61,15 @@ typedef struct _wmudDirection { gboolean wmud_world_check_planes(GSList *planes, GError **err); gboolean wmud_world_check_planets(GSList *planets, GError **err); gboolean wmud_world_check_areas(GSList *areas, GError **err); -gboolean wmud_world_check_exits(GSList *exits, GError **err); +gboolean wmud_world_check_rooms(GSList *rooms, GError **err); +gboolean wmud_world_check_exits(GSList *exits, GSList *directions, GSList *rooms, GError **err); gboolean wmud_world_assoc_planets_planes(GSList *planets, GSList *planes, GError **err); gboolean wmud_world_assoc_rooms_areas(GSList *rooms, GSList *areas, GError **err); gboolean wmud_world_assoc_rooms_planets(GSList *rooms, GSList *planets, GError **err); void wmud_world_assoc_exits_rooms(GSList *exits, GSList *rooms, GError **err); +gboolean wmud_world_load(GError **err); + #endif /* __WMUD_WORLD_H__ */