diff --git a/docs/reference/wmud/wmud-docs.sgml b/docs/reference/wmud/wmud-docs.sgml
index 9506fb8..02f2355 100644
--- a/docs/reference/wmud/wmud-docs.sgml
+++ b/docs/reference/wmud/wmud-docs.sgml
@@ -18,24 +18,28 @@
wMUD hackers' guide
-
+
+
+
+
+
-
+
API Index
-
+
diff --git a/docs/reference/wmud/wmud-sections.txt b/docs/reference/wmud/wmud-sections.txt
index 43939f4..ff42dae 100644
--- a/docs/reference/wmud/wmud-sections.txt
+++ b/docs/reference/wmud/wmud-sections.txt
@@ -1,21 +1,45 @@
-Data types
+wMUD's Data Types
types
-wmudClientState
-wmudClient
-wmudPlayer
-Utilities and uncategorized functions
+
utils
random_number
wmud_random_string
-Networking
-networking
+
+configuration
+WMUD_CONFIG_ERROR
+wmudConfigError
+ConfigData
+active_config
+wmud_config_init
+
+
+
+
+maintenance-thread
+wmud_maintenance_init
+
+
+
+
+game-thread
+wmudClientState
+wmudClient
+elapsed_seconds
+elapsed_cycle
+game_context
+wmud_game_init
+
+
+
+
+game-networking
TELNET_IAC
TELNET_WILL
TELNET_WONT
@@ -26,7 +50,7 @@ wmud_client_send
-Command interpreter
+
interpreter
wmudCommandFunc
wmudCommand
@@ -35,7 +59,7 @@ wmud_interpret_game_command
-Database handling
+
db
WMUD_DB_ERROR
wmudDbError
@@ -45,12 +69,17 @@ wmud_db_save_player
-Player handling
+
player
+wmudPlayer
players
wmud_player_dup
wmud_player_free
-wmud_player_exists
wmud_player_auth
+wmud_player_exists
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 2b58d81..acbf9da 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,5 @@
bin_PROGRAMS = wmud
AM_CPPFLAGS = -DWMUD_STATEDIR=\""$(localstatedir)"\" -DWMUD_CONFDIR=\""$(sysconfdir)"\" $(MEMCACHED_CFLAGS) $(GLIB_CFLAGS) $(GIO_CFLAGS) $(GTHREAD_CFLAGS) $(SQLITE3_CFLAGS)
-wmud_SOURCES = main.c game-networking.c interpreter.c db.c players.c maintenance.c
+wmud_SOURCES = main.c game-networking.c interpreter.c db.c players.c maintenance.c game.c configuration.c world.c
wmud_LDADD = $(MEMCACHED_LIBS) $(GLIB_LIBS) $(GIO_LIBS) $(GTHREAD_LIBS) $(SQLITE3_LIBS)
diff --git a/src/configuration.c b/src/configuration.c
new file mode 100644
index 0000000..56ec439
--- /dev/null
+++ b/src/configuration.c
@@ -0,0 +1,169 @@
+/* wMUD - Yet another MUD codebase by W00d5t0ck
+ * Copyright (C) 2012 - Gergely POLONKAI
+ *
+ * configuration.c: configuration file related functions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include
+
+#include "wmud-types.h"
+#include "configuration.h"
+
+/**
+ * SECTION:configuration
+ * @short_description: Configuration file handling functions
+ * @title: Configuration file handling functions
+ *
+ */
+
+/**
+ * WMUD_CONFIG_ERROR:
+ *
+ * the GQuark for the config error GError
+ */
+GQuark WMUD_CONFIG_ERROR = 0;
+/**
+ * active_config:
+ *
+ * the currently active configuration directives
+ */
+ConfigData *active_config = NULL;
+
+/**
+ * wmud_configdata_free:
+ * @config_data: pointer to the ConfigData struct to free
+ *
+ * Correctly free a ConfigData struct with all its members
+ */
+void
+wmud_configdata_free(ConfigData **config_data)
+{
+ if ((*config_data)->admin_email)
+ g_free((*config_data)->admin_email);
+
+ if ((*config_data)->database_file)
+ g_free((*config_data)->database_file);
+
+ g_free(*config_data);
+ *config_data = NULL;
+}
+
+/**
+ * wmud_config_init:
+ * @config_data: a pointer to a ConfigData struct. This will be filled with the
+ * configuration file's data
+ * @err: The GError in which the config handling status should be returned
+ *
+ * Parses the default configuration file, and sets different variables
+ * according to it.
+ *
+ * Return value: %TRUE if parsing was successful. %FALSE otherwise.
+ */
+gboolean
+wmud_config_init(ConfigData **config_data, GError **err)
+{
+ GString *config_file = g_string_new(WMUD_CONFDIR);
+ GKeyFile *config;
+ GError *in_err = NULL;
+
+ if (!config_data)
+ return FALSE;
+
+ if (!*config_data)
+ {
+ g_clear_error(err);
+ g_set_error(err, WMUD_CONFIG_ERROR, WMUD_CONFIG_ERROR_REUSE, "Configuration pointer reuse. Please file a bug report!");
+ return FALSE;
+ }
+
+ *config_data = g_new0(ConfigData, 1);
+
+ g_string_append(config_file, "/wmud.conf");
+
+ config = g_key_file_new();
+ /* TODO: Error checking */
+ g_key_file_load_from_file(config, config_file->str, 0, &in_err);
+
+ if (!g_key_file_has_group(config, "global"))
+ {
+ g_set_error(err, WMUD_CONFIG_ERROR, WMUD_CONFIG_ERROR_NOGLOBAL, "Config file (%s) does not contain a [global] group", config_file->str);
+ g_key_file_free(config);
+ g_string_free(config_file, TRUE);
+
+ return FALSE;
+ }
+
+ g_clear_error(&in_err);
+ (*config_data)->port = g_key_file_get_integer(config, "global", "port", &in_err);
+ if (in_err)
+ {
+ if (g_error_matches(in_err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND))
+ {
+ (*config_data)->port = DEFAULT_PORT;
+ }
+ else if (g_error_matches(in_err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE))
+ {
+ g_set_error(err, WMUD_CONFIG_ERROR, WMUD_CONFIG_ERROR_BADPORT, "Config file (%s) contains an invalid port number", config_file->str);
+ g_key_file_free(config);
+ g_string_free(config_file, TRUE);
+ (*config_data)->port = 0;
+
+ return FALSE;
+ }
+
+ return FALSE;
+ }
+
+ g_clear_error(&in_err);
+ (*config_data)->database_file = g_key_file_get_string(config, "global", "world file", &in_err);
+ if (in_err)
+ {
+ if (g_error_matches(in_err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND))
+ {
+ g_set_error(err, WMUD_CONFIG_ERROR, WMUD_CONFIG_ERROR_NOWORLD, "Config file (%s) does not contain a world file path", config_file->str);
+ g_key_file_free(config);
+ g_string_free(config_file, TRUE);
+ wmud_configdata_free(config_data);
+
+ return FALSE;
+ }
+ }
+
+ g_clear_error(&in_err);
+ (*config_data)->admin_email = g_key_file_get_string(config, "global", "admin email", &in_err);
+ if (in_err)
+ {
+ if (g_error_matches(in_err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND))
+ {
+ g_set_error(err, WMUD_CONFIG_ERROR, WMUD_CONFIG_ERROR_NOEMAIL, "Config file (%s) does not contain an admin e-mail address", config_file->str);
+ g_key_file_free(config);
+ g_string_free(config_file, TRUE);
+ wmud_configdata_free(config_data);
+
+ return FALSE;
+ }
+ }
+
+ g_key_file_free(config);
+ g_string_free(config_file, TRUE);
+
+ return TRUE;
+}
+
diff --git a/src/configuration.h b/src/configuration.h
new file mode 100644
index 0000000..e0329f9
--- /dev/null
+++ b/src/configuration.h
@@ -0,0 +1,48 @@
+#ifndef __WMUD_CONFIGURATION_H__
+#define __WMUD_CONFIGURATION_H__
+
+#include
+
+extern GQuark WMUD_CONFIG_ERROR;
+
+/**
+ * wmudConfigError:
+ * @WMUD_CONFIG_ERROR_NOGLOBAL: Indicates that the config file read doesn't
+ * contain a [global] section
+ * @WMUD_CONFIG_ERROR_BADPORT: Indicates that the config file contains and
+ * invalid port number
+ * @WMUD_CONFIG_ERROR_NOWORLD: Indicates that the config file doesn't contain a
+ * world database file
+ * @WMUD_CONFIG_ERROR_NOEMAIL: Indicates that the config file doesn't contain
+ * an administrator e-mail address
+ * @WMUD_CONFIG_ERROR_REUSE: configuration data is reused (non-NULL)
+ *
+ * Error codes returned by configuration file parsing functions.
+ */
+typedef enum {
+ WMUD_CONFIG_ERROR_NOGLOBAL,
+ WMUD_CONFIG_ERROR_BADPORT,
+ WMUD_CONFIG_ERROR_NOWORLD,
+ WMUD_CONFIG_ERROR_NOEMAIL,
+ WMUD_CONFIG_ERROR_REUSE
+} wmudConfigError;
+
+/**
+ * ConfigData:
+ * @port: the port number of the game interface to listen on
+ * @database_file: the database file of the world associated with this
+ * configuration
+ * @admin_email: the world administrator's e-mail address
+ */
+typedef struct _ConfigData {
+ guint port;
+ gchar *database_file;
+ gchar *admin_email;
+} ConfigData;
+
+extern ConfigData *active_config;
+
+gboolean wmud_config_init(ConfigData **config_data, GError **err);
+
+#endif /* __WMUD_CONFIGURATION_H__ */
+
diff --git a/src/db.c b/src/db.c
index 0fd3614..bc21163 100644
--- a/src/db.c
+++ b/src/db.c
@@ -16,12 +16,14 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
+
#include
#include
#include "main.h"
#include "db.h"
#include "players.h"
+#include "configuration.h"
/**
* SECTION:db
@@ -30,7 +32,13 @@
*
*/
-sqlite3 *dbh = NULL;
+/**
+ * WMUD_DB_ERROR:
+ *
+ * the GQuark for the database error GError
+ */
+GQuark WMUD_DB_ERROR = 0;
+static sqlite3 *dbh = NULL;
/**
* wmud_db_init:
@@ -44,7 +52,7 @@ wmud_db_init(GError **err)
GString *db_file = g_string_new(WMUD_STATEDIR);
int sqlite_code;
- g_string_append_printf(db_file, "/%s", database_file);
+ g_string_append_printf(db_file, "/%s", active_config->database_file);
if ((sqlite_code = sqlite3_open(db_file->str, &dbh)) != SQLITE_OK)
{
@@ -170,3 +178,39 @@ wmud_db_save_player(wmudPlayer *player, GError **err)
return TRUE;
}
+gboolean
+wmud_db_load_planes(GSList **planes, GError **err)
+{
+ return FALSE;
+}
+
+gboolean
+wmud_db_load_planets(GSList **planets, GError **err)
+{
+ return FALSE;
+}
+
+gboolean
+wmud_db_load_directions(GSList **directions, GError **err)
+{
+ return FALSE;
+}
+
+gboolean
+wmud_db_load_areas(GSList **areas, GError **err)
+{
+ return FALSE;
+}
+
+gboolean
+wmud_db_load_rooms(GSList **rooms, GError **err)
+{
+ return FALSE;
+}
+
+gboolean
+wmud_db_load_exits(GSList **exits, GError **err)
+{
+ return FALSE;
+}
+
diff --git a/src/db.h b/src/db.h
index d6c5ad4..38da5ca 100644
--- a/src/db.h
+++ b/src/db.h
@@ -23,9 +23,17 @@
#include "wmud-types.h"
+extern GQuark WMUD_DB_ERROR;
+
gboolean wmud_db_init(GError **err);
gboolean wmud_db_players_load(GError **err);
gboolean wmud_db_save_player(wmudPlayer *player, GError **err);
+gboolean wmud_db_load_planes(GSList **planes, GError **err);
+gboolean wmud_db_load_planets(GSList **planets, GError **err);
+gboolean wmud_db_load_directions(GSList **directions, GError **err);
+gboolean wmud_db_load_areas(GSList **areas, GError **err);
+gboolean wmud_db_load_rooms(GSList **rooms, GError **err);
+gboolean wmud_db_load_exits(GSList **exits, GError **err);
#endif /* __WMUD__DB_H__ */
diff --git a/src/game-networking.c b/src/game-networking.c
index f2b244d..51544a7 100644
--- a/src/game-networking.c
+++ b/src/game-networking.c
@@ -30,9 +30,10 @@
#include "interpreter.h"
#include "players.h"
#include "db.h"
+#include "configuration.h"
/**
- * SECTION:networking
+ * SECTION:game-networking
* @short_description: Game related networking code
*
* Functions to handle game connections
@@ -85,6 +86,8 @@ static gboolean
wmud_client_callback(GSocket *client_socket, GIOCondition condition, wmudClient *client)
{
GError *err = NULL;
+ /* TODO: Error checking */
+ GRegex *email_regex = g_regex_new("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}$", G_REGEX_CASELESS, 0, NULL);
if (condition & G_IO_HUP)
{
@@ -135,7 +138,32 @@ wmud_client_callback(GSocket *client_socket, GIOCondition condition, wmudClient
{
case WMUD_CLIENT_STATE_FRESH:
if (*(client->buffer->str))
- wmud_client_start_login(client);
+ {
+ wmudPlayer *player;
+
+ if ((player = wmud_player_exists(client->buffer->str)) != NULL)
+ {
+ g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Trying to login with playername '%s'\n", client->buffer->str);
+ if (player->cpassword == NULL)
+ {
+ wmud_client_send(client, "Your registration is not finished yet.\r\n");
+ wmud_client_close(client, TRUE);
+ }
+ else
+ {
+ client->state = WMUD_CLIENT_STATE_PASSWAIT;
+ client->player = player;
+ wmud_client_send(client, "Please provide us your password: %c%c%c", TELNET_IAC, TELNET_WILL, TELNET_ECHO);
+ }
+ }
+ else
+ {
+ client->player = g_new0(wmudPlayer, 1);
+ client->player->player_name = g_strdup(client->buffer->str);
+ client->state = WMUD_CLIENT_STATE_NEWCHAR;
+ wmud_client_send(client, "Is %s new to this game? [Y/N] ", client->buffer->str);
+ }
+ }
break;
case WMUD_CLIENT_STATE_PASSWAIT:
if (*(client->buffer->str))
@@ -144,7 +172,7 @@ wmud_client_callback(GSocket *client_socket, GIOCondition condition, wmudClient
{
wmud_client_send(client, "%c%c%cLogin"
" successful.\r\n", TELNET_IAC,
- TELNET_WILL, TELNET_ECHO);
+ TELNET_WONT, TELNET_ECHO);
client->authenticated = TRUE;
/* TODO: Send fail count if non-zero */
client->state = WMUD_CLIENT_STATE_MENU;
@@ -158,7 +186,7 @@ wmud_client_callback(GSocket *client_socket, GIOCondition condition, wmudClient
" password doesn't seem to be valid."
" Let's try it again...\r\nBy what"
" name would you like to be called? ",
- TELNET_IAC, TELNET_WILL, TELNET_ECHO);
+ TELNET_IAC, TELNET_WONT, TELNET_ECHO);
client->state = WMUD_CLIENT_STATE_FRESH;
client->login_try_count++;
if (client->login_try_count == 3)
@@ -170,7 +198,7 @@ wmud_client_callback(GSocket *client_socket, GIOCondition condition, wmudClient
wmud_client_close(client, TRUE);
/* TODO: Increase IP fail count, and ban IP if it's too high */
}
- /* TODO: Increase and save player fail count */
+ /* TODO: Increase and save login fail count */
client->player = NULL;
}
}
@@ -190,13 +218,68 @@ wmud_client_callback(GSocket *client_socket, GIOCondition condition, wmudClient
//wmud_interpret_quit_answer(client);
break;
case WMUD_CLIENT_STATE_NEWCHAR:
- wmud_client_interpret_newplayer_answer(client);
+ if (g_ascii_strcasecmp(client->buffer->str, "n") == 0)
+ {
+ wmud_client_send(client, "What is your player-name, then? ");
+ client->state = WMUD_CLIENT_STATE_FRESH;
+ }
+ else if (g_ascii_strcasecmp(client->buffer->str, "y") == 0)
+ {
+ g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Creating new player\n");
+ wmud_client_send(client, "Welcome to this MUD!\r\nPlease enter your e-mail address: ");
+ client->state = WMUD_CLIENT_STATE_REGISTERING;
+ }
+ else
+ {
+ wmud_client_send(client, "Sorry, but for this question I only understand 'Y' or 'N'.\r\nIs %s a new player here? [Y/N] ", client->player->player_name);
+ }
break;
case WMUD_CLIENT_STATE_REGISTERING:
- wmud_client_interpret_newplayer_email(client);
+ if (!*(client->buffer->str))
+ {
+ if (client->bademail)
+ {
+ wmud_client_close(client, TRUE);
+ }
+ }
+
+ if (g_regex_match(email_regex, client->buffer->str, 0, NULL))
+ {
+ client->player->email = g_strdup(client->buffer->str);
+ client->state = WMUD_CLIENT_STATE_REGEMAIL_CONFIRM;
+ wmud_client_send(client, "It seems to be a valid address to me, but could you write it again? ");
+ }
+ else
+ {
+ wmud_client_send(client, "\r\nSorry, but this e-mail address doesn't seem to be valid to me.\r\n\r\nIf you think this is a valid address, simply press enter to quit, and send an e-mail to %s from that address, so we can fix our e-mail validation code.\r\n\r\nIf you just mistyped your address, type it now: ", active_config->admin_email);
+ if (*(client->buffer->str))
+ client->bademail = TRUE;
+ }
break;
case WMUD_CLIENT_STATE_REGEMAIL_CONFIRM:
- wmud_client_interpret_newplayer_mailconfirm(client);
+ if (g_ascii_strcasecmp(client->player->email, client->buffer->str) == 0)
+ {
+ g_clear_error(&err);
+ if (wmud_db_save_player(client->player, &err))
+ {
+ wmud_client_send(client, "Good. We will generate the password for this player name, and send it to you\r\nvia e-mail. Please come back to us, if you get that code, so you can log\r\nin.\r\n");
+ players = g_slist_prepend(players, wmud_player_dup(client->player));
+ }
+ else
+ {
+ g_critical("wmud_db_save_player() error: %s", err->message);
+ wmud_client_send(client, "There was an error during the database update. Please try again later!\r\n");
+ }
+ wmud_client_close(client, TRUE);
+ }
+ else
+ {
+ g_free(client->player->email);
+ client->player->email = NULL;
+
+ wmud_client_send(client, "This is not the same as you entered before.\r\nLet's just try it again: ");
+ client->state = WMUD_CLIENT_STATE_REGISTERING;
+ }
break;
}
g_string_erase(client->buffer, 0, -1);
@@ -263,6 +346,7 @@ game_source_callback(GSocket *socket, GIOCondition condition, struct AcceptData
/**
* wmud_networking_init:
* @port_number: the port number on which the game listener should listen
+ * @game_context: the #GMainContext of the game thread
* @err: the GError in which possible errors will be reported
*
* Initializes the game network listener
@@ -271,7 +355,7 @@ game_source_callback(GSocket *socket, GIOCondition condition, struct AcceptData
* err is set accordingly (if not NULL)
*/
gboolean
-wmud_networking_init(guint port_number, GError **err)
+wmud_networking_init(guint port_number, GMainContext *game_context, GError **err)
{
struct AcceptData *accept_data;
GSocketListener *game_listener;
@@ -405,136 +489,3 @@ wmud_client_send(wmudClient *client, const gchar *fmt, ...)
g_string_free(buf, TRUE);
}
-/**
- * wmud_client_start_login:
- * @client: the client from which the login name came from
- *
- * This function is currently called when the freshly connected client sends a
- * non-empty string (a player name).
- */
-void
-wmud_client_start_login(wmudClient *client)
-{
- wmudPlayer *player;
-
- if ((player = wmud_player_exists(client->buffer->str)) != NULL)
- {
- g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Trying to login with playername '%s'\n", client->buffer->str);
- if (player->cpassword == NULL)
- {
- wmud_client_send(client, "Your registration is not finished yet.\r\n");
- wmud_client_close(client, TRUE);
- }
- else
- {
- client->state = WMUD_CLIENT_STATE_PASSWAIT;
- client->player = player;
- wmud_client_send(client, "Please provide us your password: %c%c%c", TELNET_IAC, TELNET_WONT, TELNET_ECHO);
- }
- }
- else
- {
- client->player = g_new0(wmudPlayer, 1);
- client->player->player_name = g_strdup(client->buffer->str);
- client->state = WMUD_CLIENT_STATE_NEWCHAR;
- wmud_client_send(client, "Is %s new to this game? [Y/N] ", client->buffer->str);
- }
-}
-
-/**
- * wmud_client_interpret_newplayer_answer:
- * @client: the client from which the answer came from
- *
- * Interprets a yes/no answer from the client to the question if they are new
- * to the game.
- */
-void
-wmud_client_interpret_newplayer_answer(wmudClient *client)
-{
- if (g_ascii_strcasecmp(client->buffer->str, "n") == 0)
- {
- wmud_client_send(client, "What is your player-name, then? ");
- client->state = WMUD_CLIENT_STATE_FRESH;
- }
- else if (g_ascii_strcasecmp(client->buffer->str, "y") == 0)
- {
- g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Creating new player\n");
- wmud_client_send(client, "Welcome to this MUD!\r\nPlease enter your e-mail address: ");
- client->state = WMUD_CLIENT_STATE_REGISTERING;
- }
- else
- {
- wmud_client_send(client, "Sorry, but for this question I only understand 'Y' or 'N'.\r\nIs %s a new player here? [Y/N] ", client->player->player_name);
- }
-}
-
-/**
- * wmud_client_interpret_newplayer_email:
- * @client: the client from which the e-mail address arrived from
- *
- * Checks for the validity of the new player's e-mail address
- */
-void
-wmud_client_interpret_newplayer_email(wmudClient *client)
-{
- /* TODO: Error checking */
- GRegex *email_regex = g_regex_new("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}$", G_REGEX_CASELESS, 0, NULL);
-
- if (!*(client->buffer->str))
- {
- if (client->bademail)
- {
- wmud_client_close(client, TRUE);
- }
- }
-
- if (g_regex_match(email_regex, client->buffer->str, 0, NULL))
- {
- client->player->email = g_strdup(client->buffer->str);
- client->state = WMUD_CLIENT_STATE_REGEMAIL_CONFIRM;
- wmud_client_send(client, "It seems to be a valid address to me, but could you write it again? ");
- }
- else
- {
- wmud_client_send(client, "\r\nSorry, but this e-mail address doesn't seem to be valid to me.\r\n\r\nIf you think this is a valid address, simply press enter to quit, and send an e-mail to %s from that address, so we can fix our e-mail validation code.\r\n\r\nIf you just mistyped your address, type it now: ", admin_email);
- if (*(client->buffer->str))
- client->bademail = TRUE;
- }
-}
-
-/**
- * wmud_client_interpret_newplayer_mailconfirm:
- * @client: the client from which the confirmation e-mail arrived
- *
- * Check if the confirmed e-mail address is the same as the previously entered
- * one.
- */
-void
-wmud_client_interpret_newplayer_mailconfirm(wmudClient *client)
-{
- GError *err = NULL;
-
- if (g_ascii_strcasecmp(client->player->email, client->buffer->str) == 0)
- {
- if (wmud_db_save_player(client->player, &err))
- {
- wmud_client_send(client, "Good. We will generate the password for this player name, and send it to you\r\nvia e-mail. Please come back to us, if you get that code, so you can log\r\nin.\r\n");
- players = g_slist_prepend(players, wmud_player_dup(client->player));
- }
- else
- {
- g_critical("wmud_db_save_player() error: %s", err->message);
- wmud_client_send(client, "There was an error during the database update. Please try again later!\r\n");
- }
- wmud_client_close(client, TRUE);
- }
- else
- {
- g_free(client->player->email);
- client->player->email = NULL;
-
- wmud_client_send(client, "This is not the same as you entered before.\r\nLet's just try it again: ");
- client->state = WMUD_CLIENT_STATE_REGISTERING;
- }
-}
-
diff --git a/src/game-networking.h b/src/game-networking.h
index dfdda0b..4a63bd3 100644
--- a/src/game-networking.h
+++ b/src/game-networking.h
@@ -50,10 +50,7 @@
extern GSList *clients;
-gboolean wmud_networking_init(guint port_number, GError **err);
+gboolean wmud_networking_init(guint port_number, GMainContext *game_context, GError **err);
void wmud_client_send(wmudClient *client, const gchar *fmt, ...);
-void wmud_client_start_login(wmudClient *client);
-void wmud_client_interpret_newplayer_answer(wmudClient *client);
-void wmud_client_interpret_newplayer_email(wmudClient *client);
#endif
diff --git a/src/game.c b/src/game.c
new file mode 100644
index 0000000..f1908ae
--- /dev/null
+++ b/src/game.c
@@ -0,0 +1,123 @@
+/* wMUD - Yet another MUD codebase by W00d5t0ck
+ * Copyright (C) 2012 - Gergely POLONKAI
+ *
+ * game.c: Game Thread related functions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+
+#include "main.h"
+#include "game.h"
+
+/**
+ * SECTION:game-thread
+ * @short_description: Game related functions
+ * @title: The Game Thread
+ *
+ * The game thread is supposed to serve game client connections. Also,
+ * maintaining the loaded game world is the objective ot this thread.
+ *
+ * This thread has to serve all the game clients after a connection is
+ * estabilished. Player login, menu interaction and play are both the tasks of
+ * this thread.
+ *
+ * The other main objective is to maintain the loaded world. Moving and
+ * resetting the mobs, cleaning up areas and many other things belong here.
+ */
+
+/**
+ * elapsed_seconds:
+ *
+ * the number of seconds elapsed since game boot. May be inaccurate, as it
+ * simply gets updated by a timeout function which should run every second
+ */
+guint32 elapsed_seconds = 0;
+
+/**
+ * elapsed_cycle:
+ *
+ * yes, I'm optimistic. This counter is increased if, for some reason,
+ * #elapsed_seconds reaches the maximum value
+ */
+guint32 elapsed_cycle = 0;
+
+/**
+ *
+ * rl_sec_elapsed:
+ * @user_data: non-used pointer to callback's user data
+ *
+ * Keeps track of elapsed real-world time. It is inaccurate by design, but it
+ * doesn't actually matter.
+ */
+gboolean
+rl_sec_elapsed(gpointer user_data)
+{
+ elapsed_seconds++;
+ if (elapsed_seconds == G_MAXUINT32)
+ {
+ elapsed_seconds = 0;
+ elapsed_cycle++;
+ }
+
+ if (elapsed_seconds % 30 == 0)
+ {
+ g_log(G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, "Heartbeat");
+ }
+
+ return TRUE;
+}
+
+/**
+ * game_thread_func:
+ * @game_loop: the main loop to be associated with the game thread
+ *
+ * The game thread's main function.
+ *
+ * Return value: This function always returns %NULL.
+ */
+gpointer
+game_thread_func(GMainLoop *game_loop)
+{
+ /* Run the game loop */
+ g_main_loop_run(game_loop);
+
+ return NULL;
+}
+
+gboolean
+wmud_game_init(GThread **game_thread, GMainContext **game_context)
+{
+ GMainLoop *game_loop;
+ GSource *timeout_source;
+ GError *err = NULL;
+
+ /* Create the game context and main loop */
+ *game_context = g_main_context_new();
+ game_loop = g_main_loop_new(*game_context, FALSE);
+
+ /* Create the timeout source which keeps track of elapsed real-world
+ * time */
+ timeout_source = g_timeout_source_new(1000);
+ g_source_set_callback(timeout_source, rl_sec_elapsed, NULL, NULL);
+ g_source_attach(timeout_source, *game_context);
+ g_source_unref(timeout_source);
+
+ g_clear_error(&err);
+ *game_thread = g_thread_create((GThreadFunc)game_thread_func, game_loop, TRUE, &err);
+
+ return TRUE;
+}
+
diff --git a/src/game.h b/src/game.h
new file mode 100644
index 0000000..8ad8f92
--- /dev/null
+++ b/src/game.h
@@ -0,0 +1,25 @@
+/* wMUD - Yet another MUD codebase by W00d5t0ck
+ * Copyright (C) 2012 - Gergely POLONKAI
+ *
+ * game.h: Game Thread related functions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#ifndef __WMUD_GAME_H__
+#define __WMUD_GAME_H__
+
+gboolean wmud_game_init(GThread **game_thread, GMainContext **game_context);
+
+#endif /* __WMUD_GAME_H__ */
+
diff --git a/src/main.c b/src/main.c
index 9f40b78..9e97241 100644
--- a/src/main.c
+++ b/src/main.c
@@ -33,6 +33,8 @@
#include "db.h"
#include "players.h"
#include "maintenance.h"
+#include "game.h"
+#include "configuration.h"
/**
* SECTION:utils
@@ -51,88 +53,6 @@ struct {
int line;
} debug_context_loc = {NULL, 0};
-/**
- * game_context:
- *
- * the game thread's main context
- */
-GMainContext *game_context;
-/**
- * elapsed_seconds:
- *
- * the number of seconds elapsed since game boot. May be inaccurate, as it
- * simply gets updated by a timeout function which should run every second
- */
-guint32 elapsed_seconds = 0;
-/**
- * elapsed_cycle:
- *
- * yes, I'm optimistic. This counter is increased if, for some reason,
- * #elapsed_seconds reaches the maximum value
- */
-guint32 elapsed_cycle = 0;
-/**
- * main_rand:
- *
- * the main random generator
- */
-GRand *main_rand = NULL;
-/**
- * WMUD_CONFIG_ERROR:
- *
- * the GQuark for the config error GError
- */
-GQuark WMUD_CONFIG_ERROR = 0;
-/**
- * WMUD_DB_ERROR:
- *
- * the GQuark for the database error GError
- */
-GQuark WMUD_DB_ERROR = 0;
-/**
- * port:
- *
- * the port number to listen on
- */
-guint port = 0;
-/**
- * database_file:
- *
- * the filename of the world database
- */
-gchar *database_file = NULL;
-/**
- * admin_email:
- *
- * e-mail address of the MUD's administrator
- */
-gchar *admin_email = NULL;
-
-/**
- * rl_sec_elapsed:
- * @user_data: non-used pointer to callback's user data
- *
- * Keeps track of elapsed real-world time. It is inaccurate by design, but it
- * doesn't actually matter.
- */
-gboolean
-rl_sec_elapsed(gpointer user_data)
-{
- elapsed_seconds++;
- if (elapsed_seconds == G_MAXUINT32)
- {
- elapsed_seconds = 0;
- elapsed_cycle++;
- }
-
- if (elapsed_seconds % 30 == 0)
- {
- g_log(G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, "Heartbeat");
- }
-
- return TRUE;
-}
-
/**
* wmud_random_string:
* @len: the desired length of the generated random string
@@ -203,111 +123,6 @@ wmud_type_init(void)
WMUD_DB_ERROR = g_quark_from_string("wmud_db_error");
}
-/**
- * wmud_config_init:
- * @err: The GError in which the config handling status should be returned
- *
- * Parses the default configuration file, and sets different variables
- * according to it.
- *
- * Return value: %TRUE if parsing was successful. %FALSE otherwise.
- */
-gboolean
-wmud_config_init(GError **err)
-{
- GString *config_file = g_string_new(WMUD_CONFDIR);
- GKeyFile *config;
- GError *in_err = NULL;
-
- g_string_append(config_file, "/wmud.conf");
-
- config = g_key_file_new();
- /* TODO: Error checking */
- g_key_file_load_from_file(config, config_file->str, 0, &in_err);
-
- if (!g_key_file_has_group(config, "global"))
- {
- g_set_error(err, WMUD_CONFIG_ERROR, WMUD_CONFIG_ERROR_NOGLOBAL, "Config file (%s) does not contain a [global] group", config_file->str);
- g_key_file_free(config);
- g_string_free(config_file, TRUE);
-
- return FALSE;
- }
-
- g_clear_error(&in_err);
- port = g_key_file_get_integer(config, "global", "port", &in_err);
- if (in_err)
- {
- if (g_error_matches(in_err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND))
- {
- port = DEFAULT_PORT;
- }
- else if (g_error_matches(in_err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE))
- {
- g_set_error(err, WMUD_CONFIG_ERROR, WMUD_CONFIG_ERROR_BADPORT, "Config file (%s) contains an invalid port number", config_file->str);
- g_key_file_free(config);
- g_string_free(config_file, TRUE);
- port = 0;
-
- return FALSE;
- }
-
- return FALSE;
- }
-
- g_clear_error(&in_err);
- database_file = g_key_file_get_string(config, "global", "world file", &in_err);
- if (in_err)
- {
- if (g_error_matches(in_err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND))
- {
- g_set_error(err, WMUD_CONFIG_ERROR, WMUD_CONFIG_ERROR_NOWORLD, "Config file (%s) does not contain a world file path", config_file->str);
- g_key_file_free(config);
- g_string_free(config_file, TRUE);
- database_file = NULL;
-
- return FALSE;
- }
- }
-
- g_clear_error(&in_err);
- admin_email = g_key_file_get_string(config, "global", "admin email", &in_err);
- if (in_err)
- {
- if (g_error_matches(in_err, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND))
- {
- g_set_error(err, WMUD_CONFIG_ERROR, WMUD_CONFIG_ERROR_NOEMAIL, "Config file (%s) does not contain an admin e-mail address", config_file->str);
- g_key_file_free(config);
- g_string_free(config_file, TRUE);
- admin_email = NULL;
-
- return FALSE;
- }
- }
-
- g_key_file_free(config);
- g_string_free(config_file, TRUE);
-
- return TRUE;
-}
-
-/**
- * game_thread_func:
- * @game_loop: the main loop to be associated with the game thread
- *
- * The game thread's main function.
- *
- * Return value: This function always returns %NULL.
- */
-gpointer
-game_thread_func(GMainLoop *game_loop)
-{
- /* Run the game loop */
- g_main_loop_run(game_loop);
-
- return NULL;
-}
-
/**
* main:
* @argc: The number of arguments on the command line
@@ -318,10 +133,9 @@ game_thread_func(GMainLoop *game_loop)
int
main(int argc, char **argv)
{
- GMainLoop *game_loop;
- GSource *timeout_source;
GError *err = NULL;
GThread *game_thread;
+ GMainContext *game_context;
/* Initialize the thread and type system */
g_thread_init(NULL);
@@ -329,24 +143,9 @@ main(int argc, char **argv)
wmud_type_init();
/* TODO: Command line parsing */
-
- /* Initialize random number generator */
- main_rand = g_rand_new();
-
- /* Create the game context and main loop */
- game_context = g_main_context_new();
- game_loop = g_main_loop_new(game_context, FALSE);
-
- /* Create the timeout source which keeps track of elapsed real-world
- * time */
- timeout_source = g_timeout_source_new(1000);
- g_source_set_callback(timeout_source, rl_sec_elapsed, NULL, NULL);
- g_source_attach(timeout_source, game_context);
- g_source_unref(timeout_source);
-
/* TODO: Create signal handlers! */
- if (!wmud_config_init(&err))
+ if (!wmud_config_init(&active_config, &err))
{
if (err)
{
@@ -360,9 +159,6 @@ main(int argc, char **argv)
return 1;
}
- g_assert(port != 0);
- g_assert(database_file != NULL);
-
g_clear_error(&err);
if (!wmud_db_init(&err))
{
@@ -377,28 +173,28 @@ main(int argc, char **argv)
return 1;
}
- g_clear_error(&err);
- if (!wmud_networking_init(port, &err))
- {
- if (err)
- {
- g_critical("Database initialization error: %s", err->message);
- }
- else
- {
- g_critical("Database initialization error!");
- }
-
- return 1;
- }
g_clear_error(&err);
wmud_db_players_load(&err);
/* Initialization ends here */
+ wmud_game_init(&game_thread, &game_context);
+
g_clear_error(&err);
- game_thread = g_thread_create((GThreadFunc)game_thread_func, game_loop, TRUE, &err);
+ if (!wmud_networking_init(active_config->port, game_context, &err))
+ {
+ if (err)
+ {
+ g_critical("Database initialization error: %s", err->message);
+ }
+ else
+ {
+ g_critical("Database initialization error!");
+ }
+
+ return 1;
+ }
wmud_maintenance_init();
diff --git a/src/main.h b/src/main.h
index 2a25ed5..a9a7560 100644
--- a/src/main.h
+++ b/src/main.h
@@ -5,10 +5,6 @@
extern GMainContext *game_context;
extern guint32 elapsed_seconds;
-extern GRand *main_rand;
-extern gchar *database_file;
-extern GQuark WMUD_DB_ERROR;
-extern gchar *admin_email;
/**
* random_number:
@@ -17,7 +13,7 @@ extern gchar *admin_email;
*
* Generates a random number between min and max
*/
-#define random_number(min, max) g_rand_int_range(main_rand, (min), (max) + 1)
+#define random_number(min, max) g_random_int_range((min), (max) + 1)
gchar *wmud_random_string(gint len);
diff --git a/src/maintenance.c b/src/maintenance.c
index ba7940e..25bd038 100644
--- a/src/maintenance.c
+++ b/src/maintenance.c
@@ -30,6 +30,13 @@
#include "main.h"
#include "players.h"
+/**
+ * SECTION:maintenance-thread
+ * @short_description: Runtime maintenance functions
+ * @title: Runtime maintenance functions
+ *
+ */
+
/**
* wmud_maintenance_check_new_players:
* @player: #wmudPLayer structure of the player record to check
diff --git a/src/wmud-types.h b/src/wmud-types.h
index 52e2232..ed6a93b 100644
--- a/src/wmud-types.h
+++ b/src/wmud-types.h
@@ -40,7 +40,7 @@
* @WMUD_CLIENT_STATE_INGAME: Character login was successful, player is now
* in-game
* @WMUD_CLIENT_STATE_QUITWAIT: Player entered the in-game QUIT command, and we
- * are now waiting for an answer if they reallz want to quit
+ * are now waiting for an answer if they really want to quit
* Will be removed soon, this should work totally different (TODO)
* @WMUD_CLIENT_STATE_NEWCHAR: Player name entered on the login screen was
* invalid. Waiting for answer if this is a new player
@@ -66,7 +66,7 @@ typedef enum {
* wmudPlayer:
* @id: Player's database ID
* @player_name: Player's login name
- * @cpassword: crzpt()ed password of the player. This is NULL for newly
+ * @cpassword: crypt()ed password of the player. This is NULL for newly
* registered players, who have no password generated for them by the
* maintenance loop
* @email: E-mail address of the player
@@ -109,26 +109,6 @@ typedef struct _wmudClient {
gint login_try_count;
} wmudClient;
-/**
- * wmudConfigError:
- * @WMUD_CONFIG_ERROR_NOGLOBAL: Indicates that the config file read doesn't
- * contain a [global] section
- * @WMUD_CONFIG_ERROR_BADPORT: Indicates that the config file contains and
- * invalid port number
- * @WMUD_CONFIG_ERROR_NOWORLD: Indicates that the config file doesn't contain a
- * world database file
- * @WMUD_CONFIG_ERROR_NOEMAIL: Indicates that the config file doesn't contain
- * an administrator e-mail address
- *
- * Error codes returned by configuration file parsing functions.
- */
-typedef enum {
- WMUD_CONFIG_ERROR_NOGLOBAL,
- WMUD_CONFIG_ERROR_BADPORT,
- WMUD_CONFIG_ERROR_NOWORLD,
- WMUD_CONFIG_ERROR_NOEMAIL
-} wmudConfigError;
-
/**
* wmudDbError:
* @WMUD_DB_ERROR_CANTOPEN: Database file cannot be opened
diff --git a/src/world.c b/src/world.c
new file mode 100644
index 0000000..5e71402
--- /dev/null
+++ b/src/world.c
@@ -0,0 +1,155 @@
+/* wMUD - Yet another MUD codebase by W00d5t0ck
+ * Copyright (C) 2012 - Gergely POLONKAI
+ *
+ * world.c: world loading and building functions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+
+#include "world.h"
+#include "db.h"
+
+/**
+ * SECTION:world
+ * @short_description: World loading and building functions
+ * @title: Game world manipulation
+ *
+ */
+
+gboolean
+wmud_world_check_planes(GSList *planes, GError **err)
+{
+ return FALSE;
+}
+
+gboolean
+wmud_world_check_planets(GSList *planets, GError **err)
+{
+ return FALSE;
+}
+
+gboolean
+wmud_world_check_areas(GSList *areas, GError **err)
+{
+ return FALSE;
+}
+
+gboolean
+wmud_world_check_exits(GSList *exits, GError **err)
+{
+ return FALSE;
+}
+
+gboolean
+wmud_world_assoc_planets_planes(GSList *planets, GSList *planes, GError **err)
+{
+ return FALSE;
+}
+
+gboolean
+wmud_world_assoc_rooms_areas(GSList *rooms, GSList *areas, GError **err)
+{
+ return FALSE;
+}
+
+gboolean
+wmud_world_assoc_rooms_planets(GSList *rooms, GSList *planets, GError **err)
+{
+ return FALSE;
+}
+
+gboolean
+wmud_world_assoc_exits_rooms(GSList *exits, GSList *rooms, GError **err)
+{
+ return FALSE;
+}
+
+
+/**
+ * wmud_world_load:
+ * @err: a #GError to put error messages into
+ *
+ * Load the world from the database backend without activating it.
+ */
+gboolean
+wmud_world_load(GError **err)
+{
+ GSList *planes = NULL,
+ *planets = NULL,
+ *directions = NULL,
+ *areas = NULL,
+ *rooms = NULL,
+ *exits = NULL;
+ GError *in_err = NULL;
+
+ /* Load directions from the database */
+ wmud_db_load_directions(&directions, &in_err);
+
+ /* Load planes from the database */
+ wmud_db_load_planes(&planes, &in_err);
+
+ /* Check if the loaded planes conform to the rules */
+ g_clear_error(&in_err);
+ wmud_world_check_planes(planes, &in_err);
+
+ /* Load planets from the database */
+ g_clear_error(&in_err);
+ wmud_db_load_planets(&planets, &in_err);
+
+ /* Check if the planets conform to the rules */
+ g_clear_error(&in_err);
+ wmud_world_check_planets(planets, &in_err);
+
+ /* 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 */
+ g_clear_error(&in_err);
+ wmud_world_assoc_rooms_areas(rooms, areas, &in_err);
+
+ /* Associate rooms with 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 */
+ g_clear_error(&in_err);
+ wmud_world_assoc_exits_rooms(exits, rooms, &in_err);
+
+ g_clear_error(&in_err);
+ return TRUE;
+}
+
diff --git a/src/world.h b/src/world.h
new file mode 100644
index 0000000..4063902
--- /dev/null
+++ b/src/world.h
@@ -0,0 +1,33 @@
+/* wMUD - Yet another MUD codebase by W00d5t0ck
+ * Copyright (C) 2012 - Gergely POLONKAI
+ *
+ * world.h: world loading and building functions
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#ifndef __WMUD_WORLD_H__
+#define __WMUD_WORLD_H__
+
+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_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);
+gboolean wmud_world_assoc_exits_rooms(GSList *exits, GSList *rooms, GError **err);
+
+#endif /* __WMUD_WORLD_H__ */
+