2005-10-09 10:53:36 +02:00
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
#include "gm-world.h"
|
|
|
|
#include "gm-app.h"
|
2005-11-06 17:01:48 +01:00
|
|
|
#include "mcp/gm-mcp-session.h"
|
2005-10-09 10:53:36 +02:00
|
|
|
#include "gm-triggers.h"
|
|
|
|
#include "gm-marshal.h"
|
|
|
|
#include "gm-net.h"
|
|
|
|
#include "gm-bogus.h"
|
|
|
|
#include "gm-support.h"
|
|
|
|
#include "debug.h"
|
|
|
|
|
|
|
|
#define GM_WORLD_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), GM_TYPE_WORLD, GmWorldPrivate))
|
|
|
|
|
|
|
|
void gm_world_save_input_history(GmWorld *world);
|
|
|
|
void gm_world_load_input_history(GmWorld *world);
|
|
|
|
void gm_world_load_triggers(GmWorld *world);
|
|
|
|
|
|
|
|
void on_gm_world_net_state_changing(GmNet *net, GmNetState state,
|
|
|
|
GmWorld *world);
|
|
|
|
void on_gm_world_net_net_error(GmNet *net, gchar *error, gint code,
|
|
|
|
GmWorld *world);
|
|
|
|
void on_gm_world_net_bytes_recv(GmNet *net, gchar *text, gint len,
|
|
|
|
GmWorld *world);
|
|
|
|
void on_gm_world_options_option_changed(GmOptions *options, gchar *key,
|
|
|
|
GmWorld *world);
|
|
|
|
|
|
|
|
struct _GmWorldPrivate {
|
|
|
|
gchar *path;
|
|
|
|
gboolean loaded;
|
|
|
|
gboolean active;
|
|
|
|
guint activity;
|
|
|
|
gchar *buffer;
|
|
|
|
|
|
|
|
GmOptions *options;
|
|
|
|
GmTriggers *triggers;
|
|
|
|
GmNet *net;
|
2005-11-06 17:01:48 +01:00
|
|
|
GmMcpSession *mcp;
|
2005-10-09 10:53:36 +02:00
|
|
|
GList *history;
|
|
|
|
GList *editors;
|
|
|
|
GmWorldInfo info;
|
|
|
|
GmEditingInfo editing_info;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Signals */
|
|
|
|
|
|
|
|
enum {
|
|
|
|
ACTIVATE_REQUEST,
|
|
|
|
LOAD,
|
|
|
|
UNLOAD,
|
|
|
|
STATE_CHANGING,
|
|
|
|
WORLD_ERROR,
|
|
|
|
TEXT_RECEIVED,
|
|
|
|
EDITOR_ADDED,
|
|
|
|
EDITOR_REMOVED,
|
|
|
|
NAME_CHANGED,
|
|
|
|
ACTIVE_CHANGED,
|
|
|
|
ACTIVITY_CHANGED,
|
|
|
|
DELETE,
|
|
|
|
NUM_SIGNALS
|
|
|
|
};
|
|
|
|
|
|
|
|
static guint world_signals[NUM_SIGNALS] = {0};
|
|
|
|
|
|
|
|
G_DEFINE_TYPE(GmWorld, gm_world, G_TYPE_OBJECT)
|
|
|
|
|
|
|
|
static void
|
|
|
|
gm_world_finalize(GObject *object) {
|
|
|
|
GmWorld *world = GM_WORLD(object);
|
|
|
|
gchar *tmp_dir;
|
|
|
|
|
2005-10-11 11:45:35 +02:00
|
|
|
if (world->priv->path) {
|
|
|
|
gm_options_save(world->priv->options);
|
|
|
|
gm_world_save_input_history(world);
|
|
|
|
gm_triggers_save(world->priv->triggers);
|
|
|
|
|
|
|
|
// Removing all tmp files
|
|
|
|
tmp_dir = g_strconcat(world->priv->path, "/tmp", NULL);
|
|
|
|
gm_directory_remove_all(tmp_dir, FALSE);
|
|
|
|
g_free(tmp_dir);
|
|
|
|
}
|
2005-10-09 10:53:36 +02:00
|
|
|
|
|
|
|
g_list_free_simple(world->priv->history);
|
|
|
|
|
|
|
|
g_free(world->priv->path);
|
|
|
|
g_free(world->priv->buffer);
|
|
|
|
|
|
|
|
g_free(world->priv->editing_info.name);
|
|
|
|
g_free(world->priv->editing_info.upload);
|
|
|
|
g_list_free(world->priv->editing_info.lines);
|
|
|
|
|
|
|
|
g_object_unref(world->priv->triggers);
|
|
|
|
g_object_unref(world->priv->options);
|
|
|
|
g_object_unref(world->priv->net);
|
2005-11-06 17:01:48 +01:00
|
|
|
g_object_unref(world->priv->mcp);
|
|
|
|
|
2005-10-09 10:53:36 +02:00
|
|
|
G_OBJECT_CLASS(gm_world_parent_class)->finalize(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gm_world_class_init(GmWorldClass *klass) {
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS(klass);
|
|
|
|
|
|
|
|
object_class->finalize = gm_world_finalize;
|
|
|
|
|
|
|
|
world_signals[ACTIVATE_REQUEST] =
|
|
|
|
g_signal_new("activate_request",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, activate_request),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
0);
|
|
|
|
|
|
|
|
world_signals[LOAD] =
|
|
|
|
g_signal_new("load",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, load),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
0);
|
|
|
|
|
|
|
|
world_signals[UNLOAD] =
|
|
|
|
g_signal_new("unload",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, unload),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
0);
|
|
|
|
|
|
|
|
world_signals[STATE_CHANGING] =
|
|
|
|
g_signal_new("state_changing",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, state_changing),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__UINT,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
1,
|
|
|
|
G_TYPE_UINT);
|
|
|
|
|
|
|
|
world_signals[WORLD_ERROR] =
|
|
|
|
g_signal_new("world_error",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, world_error),
|
|
|
|
NULL, NULL,
|
|
|
|
gm_marshal_VOID__STRING_INT,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
2,
|
|
|
|
G_TYPE_STRING,
|
|
|
|
G_TYPE_INT);
|
|
|
|
|
|
|
|
world_signals[TEXT_RECEIVED] =
|
|
|
|
g_signal_new("text_received",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, text_received),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__STRING,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
1,
|
|
|
|
G_TYPE_STRING);
|
|
|
|
|
|
|
|
world_signals[EDITOR_ADDED] =
|
|
|
|
g_signal_new("editor_added",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, editor_added),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__OBJECT,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
1,
|
|
|
|
G_TYPE_OBJECT);
|
|
|
|
|
|
|
|
world_signals[EDITOR_REMOVED] =
|
|
|
|
g_signal_new("editor_removed",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, editor_removed),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__OBJECT,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
1,
|
|
|
|
G_TYPE_OBJECT);
|
|
|
|
|
|
|
|
world_signals[NAME_CHANGED] =
|
|
|
|
g_signal_new("name_changed",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, name_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__STRING,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
1,
|
|
|
|
G_TYPE_STRING);
|
|
|
|
|
|
|
|
world_signals[ACTIVE_CHANGED] =
|
|
|
|
g_signal_new("active_changed",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, active_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__BOOLEAN,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
1,
|
|
|
|
G_TYPE_BOOLEAN);
|
|
|
|
|
|
|
|
world_signals[ACTIVITY_CHANGED] =
|
|
|
|
g_signal_new("activity_changed",
|
|
|
|
G_OBJECT_CLASS_TYPE(object_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET(GmWorldClass, activity_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__INT,
|
|
|
|
G_TYPE_NONE,
|
|
|
|
1,
|
|
|
|
G_TYPE_INT);
|
|
|
|
|
|
|
|
g_type_class_add_private(object_class, sizeof(GmWorldPrivate));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_create_default_settings(GmWorld *world) {
|
|
|
|
const gchar *loc = gm_default_charset();
|
|
|
|
|
|
|
|
world->priv->options = gm_options_new();
|
|
|
|
|
|
|
|
gm_options_set(world->priv->options, "name", "");
|
|
|
|
gm_options_set(world->priv->options, "autoload", "0");
|
|
|
|
gm_options_set(world->priv->options, "host", "");
|
|
|
|
gm_options_set(world->priv->options, "port", "1111");
|
|
|
|
gm_options_set(world->priv->options, "player_name", "");
|
|
|
|
gm_options_set(world->priv->options, "reconnect", "0");
|
|
|
|
gm_options_set(world->priv->options, "password", "");
|
|
|
|
gm_options_set(world->priv->options, "charset", (gchar *)loc);
|
|
|
|
gm_options_set(world->priv->options, "history_length", "500");
|
|
|
|
|
|
|
|
// Non configurable options
|
|
|
|
gm_options_set(world->priv->options, "pane_position", "150");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gm_world_init(GmWorld *world) {
|
|
|
|
world->priv = GM_WORLD_GET_PRIVATE(world);
|
|
|
|
|
|
|
|
gm_world_create_default_settings(world);
|
|
|
|
world->priv->path = NULL;
|
|
|
|
world->priv->loaded = FALSE;
|
|
|
|
world->priv->history = NULL;
|
|
|
|
world->priv->activity = 0;
|
|
|
|
world->priv->triggers = gm_triggers_new();
|
|
|
|
world->priv->net = gm_net_new();
|
2005-11-06 17:01:48 +01:00
|
|
|
world->priv->mcp = gm_mcp_session_new(G_OBJECT(world));
|
2005-10-09 10:53:36 +02:00
|
|
|
world->priv->buffer = NULL;
|
|
|
|
world->priv->editing_info.is_editing = FALSE;
|
|
|
|
|
|
|
|
g_signal_connect(world->priv->net, "state_changing",
|
|
|
|
G_CALLBACK(on_gm_world_net_state_changing), world);
|
|
|
|
g_signal_connect(world->priv->net, "net_error",
|
|
|
|
G_CALLBACK(on_gm_world_net_net_error), world);
|
|
|
|
g_signal_connect(world->priv->net, "bytes_recv",
|
|
|
|
G_CALLBACK(on_gm_world_net_bytes_recv), world);
|
|
|
|
g_signal_connect(world->priv->options, "option_changed",
|
|
|
|
G_CALLBACK(on_gm_world_options_option_changed), world);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_load_input_history(GmWorld *world) {
|
|
|
|
FILE *f;
|
|
|
|
gchar line[1024], *filename;
|
|
|
|
GString *str;
|
|
|
|
|
|
|
|
filename = g_strconcat(world->priv->path, G_DIR_SEPARATOR_S, "history",
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
debug_msg(1, "GmWorld.LoadInputHistory: loading history (%s)!", filename);
|
|
|
|
|
|
|
|
if ((f = fopen(filename, "r")) != NULL) {
|
|
|
|
str = g_string_new("");
|
|
|
|
|
|
|
|
while (fgets(line, 1024 - 1, f) != NULL) {
|
|
|
|
g_string_append(str, line);
|
|
|
|
if (line[strlen(line) - 1] == '\n') {
|
|
|
|
if (line[1] != '\0') { // Empty lines, we don't need to process those
|
|
|
|
world->priv->history = g_list_append(world->priv->history,
|
|
|
|
g_strndup(str->str, strlen(str->str) - 1));
|
|
|
|
}
|
|
|
|
g_string_erase(str, 0, -1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_string_free(str, TRUE);
|
|
|
|
fclose(f);
|
|
|
|
} else {
|
|
|
|
debug_msg(1, "GmWorld.LoadInputHistory: could not retrieve contents of "
|
|
|
|
"file %s (%s)", filename, strerror(errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free(filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_save_input_history(GmWorld *world) {
|
|
|
|
FILE *f;
|
|
|
|
gchar *filename;
|
|
|
|
GList *elem;
|
|
|
|
|
|
|
|
if (world->priv->path == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
filename = g_strconcat(world->priv->path, G_DIR_SEPARATOR_S, "history", NULL);
|
|
|
|
f = fopen(filename, "w");
|
|
|
|
|
|
|
|
if (f) {
|
|
|
|
debug_msg(1, "GmWorld.SaveInputHistory: saving input history to %s",
|
|
|
|
filename);
|
|
|
|
|
|
|
|
for (elem = world->priv->history; elem; elem = elem->next) {
|
|
|
|
fprintf(f, "%s\n", (gchar *) (elem->data));
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
chmod(filename, 0660);
|
|
|
|
} else {
|
|
|
|
debug_msg(1, "GmWorld.SaveInputHistory: couldn't open history file (%s)"
|
|
|
|
" for saving: %s", filename, strerror(errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free(filename);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_load_triggers(GmWorld *world) {
|
|
|
|
gchar *path;
|
|
|
|
|
|
|
|
if (world->priv->triggers) {
|
|
|
|
g_object_unref(world->priv->triggers);
|
|
|
|
}
|
|
|
|
|
|
|
|
path = g_strconcat(world->priv->path, G_DIR_SEPARATOR_S, "triggers", NULL);
|
|
|
|
world->priv->triggers = gm_triggers_new_from_file(path);
|
|
|
|
g_free(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Public */
|
|
|
|
GmWorld *
|
|
|
|
gm_world_new(gchar *path) {
|
|
|
|
GmWorld *world = GM_WORLD(g_object_new(GM_TYPE_WORLD, NULL));
|
|
|
|
gchar *options_path;
|
|
|
|
|
|
|
|
if (path != NULL) {
|
|
|
|
options_path = g_strconcat(path, "/settings", NULL);
|
|
|
|
|
|
|
|
debug_msg(1, "GmWorld.new: creating new world for %s", path);
|
|
|
|
world->priv->path = g_strdup(path);
|
|
|
|
|
|
|
|
debug_msg(1, "GmWorld.new: creating default world settings for %s", path);
|
|
|
|
gm_options_load(world->priv->options, options_path);
|
|
|
|
|
|
|
|
if (strlen(gm_options_get(world->priv->options, "charset")) == 0) {
|
|
|
|
gm_options_set(world->priv->options, "charset",
|
|
|
|
gm_default_charset());
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free(options_path);
|
|
|
|
|
|
|
|
gm_world_load_input_history(world);
|
|
|
|
gm_world_load_triggers(world);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* CHECK: all done? */
|
|
|
|
|
|
|
|
return world;
|
|
|
|
}
|
|
|
|
|
|
|
|
GmWorld *
|
|
|
|
gm_world_dup(GmWorld *source) {
|
|
|
|
GmWorld *copy = gm_world_new(NULL);
|
|
|
|
|
|
|
|
g_object_unref(copy->priv->options);
|
|
|
|
|
|
|
|
copy->priv->options = gm_options_dup(source->priv->options);
|
|
|
|
copy->priv->triggers = gm_triggers_dup(source->priv->triggers);
|
|
|
|
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_load(GmWorld *world) {
|
|
|
|
if (world->priv->loaded) {
|
|
|
|
g_signal_emit(world, world_signals[ACTIVATE_REQUEST], 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
world->priv->loaded = TRUE;
|
|
|
|
g_signal_emit(world, world_signals[LOAD], 0);
|
|
|
|
g_signal_emit(world, world_signals[ACTIVATE_REQUEST], 0);
|
|
|
|
gm_world_connect(world);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_unload(GmWorld *world) {
|
|
|
|
//GList *w;
|
|
|
|
|
|
|
|
if (world->priv->loaded) {
|
|
|
|
world->priv->loaded = FALSE;
|
|
|
|
gm_world_disconnect(world);
|
|
|
|
|
|
|
|
//TODO: Destroy editors
|
|
|
|
//editors_close(wld);
|
|
|
|
|
|
|
|
g_signal_emit(world, world_signals[UNLOAD], 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GmTriggers *
|
|
|
|
gm_world_triggers(GmWorld *world) {
|
|
|
|
return world->priv->triggers;
|
|
|
|
}
|
|
|
|
|
|
|
|
GmOptions *
|
|
|
|
gm_world_options(GmWorld *world) {
|
|
|
|
return world->priv->options;
|
|
|
|
}
|
|
|
|
|
|
|
|
const gchar *
|
|
|
|
gm_world_name(GmWorld *world) {
|
|
|
|
return gm_options_get(world->priv->options, "name");
|
|
|
|
}
|
|
|
|
|
|
|
|
const gchar *
|
|
|
|
gm_world_path(GmWorld *world) {
|
|
|
|
return world->priv->path;
|
|
|
|
}
|
|
|
|
|
|
|
|
GList **
|
|
|
|
gm_world_history(GmWorld *world) {
|
|
|
|
return &(world->priv->history);
|
|
|
|
}
|
|
|
|
|
|
|
|
GmWorldInfo
|
|
|
|
gm_world_info(GmWorld *world) {
|
|
|
|
return world->priv->info;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gm_world_loaded(GmWorld *world) {
|
|
|
|
return world->priv->loaded;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gm_world_connected(GmWorld *world) {
|
|
|
|
return gm_net_state(world->priv->net) == GM_NET_STATE_CONNECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gm_world_disconnected(GmWorld *world) {
|
|
|
|
return gm_net_state(world->priv->net) == GM_NET_STATE_DISCONNECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
GmNetState
|
|
|
|
gm_world_state(GmWorld *world) {
|
|
|
|
return gm_net_state(world->priv->net);
|
|
|
|
}
|
|
|
|
|
|
|
|
const gchar *
|
|
|
|
gm_world_current_host(GmWorld *world) {
|
|
|
|
return gm_net_current_host(world->priv->net);
|
|
|
|
}
|
|
|
|
|
|
|
|
const gchar *
|
|
|
|
gm_world_current_port(GmWorld *world) {
|
|
|
|
return gm_net_current_port(world->priv->net);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_connect(GmWorld *world) {
|
|
|
|
/*if (strlen(gm_options_get(world->priv->options, "host")) == 0) {
|
|
|
|
g_signal_emit(world, world_signals[WORLD_ERROR], 0,
|
|
|
|
_("World has no host, please fill in a host first"));
|
|
|
|
} else if (strlen(gm_options_get(world->priv->options, "port")) == 0) {
|
|
|
|
g_signal_emit(world, world_signals[WORLD_ERROR], 0,
|
|
|
|
_("World has no port, please fill in a port first"));
|
|
|
|
} else {*/
|
|
|
|
gm_net_connect(world->priv->net,
|
|
|
|
gm_options_get(world->priv->options, "host"),
|
|
|
|
gm_options_get(world->priv->options, "port"));
|
|
|
|
//}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_connect_to(GmWorld *world, gchar *host, gchar *port) {
|
|
|
|
gm_net_connect(world->priv->net, host, port);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_disconnect(GmWorld *world) {
|
|
|
|
gm_net_disconnect(world->priv->net);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_log(GmWorld *world, GmLogType type, gchar *text) {
|
|
|
|
FILE *f;
|
|
|
|
GString *s;
|
|
|
|
gchar *start, *log, *no_ansi;
|
|
|
|
struct tm *timet;
|
|
|
|
time_t timer;
|
|
|
|
|
|
|
|
timer = time(0);
|
|
|
|
timet = localtime(&timer);
|
|
|
|
|
|
|
|
log = g_strdup_printf("%s/logs/%04d-%02d-%02d.log", world->priv->path,
|
|
|
|
timet->tm_year + 1900, timet->tm_mon + 1, timet->tm_mday);
|
|
|
|
|
|
|
|
f = fopen(log, "a");
|
|
|
|
g_free(log);
|
|
|
|
|
|
|
|
if (!f) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
start = g_strdup_printf("[%02d:%02d:%02d] ", timet->tm_hour, timet->tm_min,
|
|
|
|
timet->tm_sec);
|
|
|
|
|
|
|
|
s = g_string_new(start);
|
|
|
|
g_free(start);
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case LOG_IN:
|
|
|
|
s = g_string_append_c(s, '<');
|
|
|
|
break;
|
|
|
|
case LOG_OUT:
|
|
|
|
s = g_string_append_c(s, '>');
|
|
|
|
break;
|
|
|
|
case LOG_MCP_IN:
|
|
|
|
s = g_string_append(s, "[MCP] <");
|
|
|
|
break;
|
|
|
|
case LOG_MCP_OUT:
|
|
|
|
s = g_string_append(s, "[MCP] >");
|
|
|
|
break;
|
|
|
|
case LOG_STATUS:
|
|
|
|
s = g_string_append_c(s, '#');
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
s = g_string_append(s, " ");
|
|
|
|
s = g_string_append(s, text);
|
|
|
|
|
|
|
|
//no_ansi = gm_ansi_strip(g_strdup(s->str));
|
|
|
|
no_ansi = g_strdup(s->str);
|
|
|
|
|
|
|
|
if (no_ansi[strlen(no_ansi) - 1] != '\n') {
|
|
|
|
fputs(no_ansi, f);
|
|
|
|
fputc('\n', f);
|
|
|
|
} else {
|
|
|
|
fputs(no_ansi, f);
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
g_free(no_ansi);
|
|
|
|
g_string_free(s, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_parse_legacy_editing_start(GmWorld *world, gchar *line) {
|
|
|
|
gchar *name_start, *upload_start;
|
|
|
|
GmEditingInfo *einfo = &(world->priv->editing_info);
|
|
|
|
|
|
|
|
name_start = strstr(line, "name: ");
|
|
|
|
|
|
|
|
if (!name_start) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
upload_start = strstr(line, " upload: ");
|
|
|
|
|
|
|
|
if (!upload_start) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
einfo->is_editing = TRUE;
|
|
|
|
einfo->name = g_strndup(name_start + 6, (upload_start - name_start) - 6);
|
|
|
|
einfo->upload = g_strndup(upload_start + 9, (upload_start - line) + 9);
|
|
|
|
einfo->lines = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_process_line(GmWorld *world, gchar *line) {
|
|
|
|
gchar *non_text_start = NULL;
|
|
|
|
GmEditingInfo *einfo = &(world->priv->editing_info);
|
|
|
|
|
|
|
|
if (strncmp(line, "\x1B[0m", 4) == 0) {
|
|
|
|
non_text_start = g_strdup(line + 4);
|
|
|
|
} else {
|
|
|
|
non_text_start = g_strdup(line);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (einfo->is_editing) {
|
|
|
|
if (strcmp(non_text_start, ".") == 0) {
|
|
|
|
//TODO: implementation, create new editor object, invoke signal
|
|
|
|
gm_world_add_editor(world, gm_editor_new(einfo->name, einfo->upload,
|
|
|
|
einfo->lines));
|
|
|
|
|
|
|
|
einfo->is_editing = FALSE;
|
|
|
|
g_free(einfo->name);
|
|
|
|
einfo->name = NULL;
|
|
|
|
g_free(einfo->upload);
|
|
|
|
einfo->upload = NULL;
|
|
|
|
g_list_free(einfo->lines);
|
|
|
|
einfo->lines = NULL;
|
|
|
|
} else {
|
|
|
|
einfo->lines = g_list_append(einfo->lines, g_strdup(non_text_start));
|
|
|
|
}
|
|
|
|
} else if (strncmp(non_text_start, "#$#", 3) == 0) {
|
|
|
|
if (strncasecmp(non_text_start + 3, " edit ", 6) == 0) {
|
|
|
|
gm_world_parse_legacy_editing_start(world, non_text_start + 9);
|
|
|
|
} else {
|
2005-11-06 17:01:48 +01:00
|
|
|
gm_mcp_session_handle_oob(world->priv->mcp, non_text_start + 3);
|
2005-10-09 10:53:36 +02:00
|
|
|
//gm_world_log(world, LOG_MCP_IN, non_text_start);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!gm_world_active(world)) {
|
|
|
|
gm_world_set_activity(world, world->priv->activity + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strncmp(non_text_start, "#$\"", 3) == 0) {
|
|
|
|
if (strlen(non_text_start) != strlen(line)) {
|
|
|
|
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, "\x1B[0m");
|
|
|
|
}
|
|
|
|
|
|
|
|
gm_world_log(world, LOG_IN, non_text_start + 3);
|
|
|
|
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, non_text_start + 3);
|
|
|
|
} else {
|
|
|
|
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, line);
|
|
|
|
gm_world_log(world, LOG_IN, line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free(non_text_start);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_process_input(GmWorld *world, gchar *text) {
|
|
|
|
#ifdef HAVE_RUBY
|
|
|
|
gchar *space, *script, *argstr;
|
|
|
|
gboolean script_ran = FALSE;
|
|
|
|
|
|
|
|
if (g_utf8_strlen(text, -1) > 1) {
|
|
|
|
if (text[0] == '/' && text[1] != '/') {
|
|
|
|
space = strstr(text, " ");
|
|
|
|
|
|
|
|
if (space == NULL) {
|
|
|
|
script = g_strdup(text + 1);
|
|
|
|
argstr = g_strdup("");
|
|
|
|
} else {
|
|
|
|
script = g_strndup(text + 1, (space - text) - 1);
|
|
|
|
argstr = g_strdup(space + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
debug_msg(1, "GmWorld.ProcessInput: Trying script %s (%s)", script,
|
|
|
|
argstr);
|
|
|
|
script_ran = gm_scripts_run(gm_app_scripts(gm_app_instance()),
|
|
|
|
world, script, argstr);
|
|
|
|
|
|
|
|
g_free(script);
|
|
|
|
g_free(argstr);
|
|
|
|
|
|
|
|
if (script_ran) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} else if (text[0] == '/' && text[1] == '/') {
|
|
|
|
text = text + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
gm_world_sendln(world, text);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_writeln(GmWorld *world, gchar *text) {
|
|
|
|
gchar *newline = g_strconcat(text, "\n", NULL);
|
|
|
|
g_signal_emit(world, world_signals[TEXT_RECEIVED], 0, newline);
|
|
|
|
|
|
|
|
g_free(newline);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_remove_editor(GmWorld *world, GmEditor *editor) {
|
|
|
|
g_return_if_fail(g_list_find(world->priv->editors, editor) != NULL);
|
|
|
|
|
|
|
|
world->priv->editors = g_list_remove(world->priv->editors, editor);
|
|
|
|
g_signal_emit(world, world_signals[EDITOR_REMOVED], 0, G_OBJECT(editor));
|
|
|
|
|
|
|
|
g_object_unref(editor);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_add_editor(GmWorld *world, GmEditor *editor) {
|
|
|
|
world->priv->editors = g_list_append(world->priv->editors, editor);
|
|
|
|
|
|
|
|
g_signal_emit(world, world_signals[EDITOR_ADDED], 0, G_OBJECT(editor));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_sendln(GmWorld *world, gchar *text) {
|
|
|
|
gchar *normal;
|
|
|
|
|
|
|
|
// Convert text from utf-8 to the correct locale
|
2005-11-06 17:01:48 +01:00
|
|
|
normal = gm_to_utf8_with_fallback(text, -1,
|
|
|
|
gm_options_get(world->priv->options, "charset"), "?");
|
2005-10-09 10:53:36 +02:00
|
|
|
|
|
|
|
if (!normal) {
|
2005-11-06 17:01:48 +01:00
|
|
|
debug_msg(1, "GmWorld.Send: conversion failed!");
|
2005-10-09 10:53:36 +02:00
|
|
|
normal = g_strdup(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
gm_world_log(world, LOG_OUT, text);
|
|
|
|
gm_net_send_line(world->priv->net, normal);
|
|
|
|
g_free(normal);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_set_active(GmWorld *world, gboolean active) {
|
|
|
|
world->priv->active = active;
|
|
|
|
|
|
|
|
g_signal_emit(world, world_signals[ACTIVE_CHANGED], 0, active);
|
|
|
|
|
|
|
|
if (active) {
|
|
|
|
gm_world_set_activity(world, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
gm_world_active(GmWorld *world) {
|
|
|
|
return world->priv->active;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_set_activity(GmWorld *world, gint activity) {
|
|
|
|
world->priv->activity = activity;
|
|
|
|
|
|
|
|
g_signal_emit(world, world_signals[ACTIVITY_CHANGED], 0, activity);
|
|
|
|
}
|
|
|
|
|
|
|
|
gint
|
|
|
|
gm_world_activity(GmWorld *world) {
|
|
|
|
return world->priv->activity;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gm_world_name_changed(GmWorld *world) {
|
|
|
|
gchar *tmp_path = world->priv->path ? g_strdup(world->priv->path) : NULL;
|
|
|
|
gchar *new_path = g_strconcat(gm_app_worlds_path(gm_app_instance()), "/",
|
|
|
|
gm_options_get(world->priv->options, "name"), NULL);
|
|
|
|
|
|
|
|
if (tmp_path && strcmp(tmp_path, new_path) == 0) {
|
|
|
|
g_free(new_path);
|
|
|
|
g_free(tmp_path);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free(world->priv->path);
|
|
|
|
world->priv->path = new_path;
|
|
|
|
|
|
|
|
if (tmp_path && g_file_test(tmp_path, G_FILE_TEST_EXISTS)) {
|
|
|
|
// Then! rename the old_path to the new_path
|
|
|
|
rename(tmp_path, world->priv->path);
|
|
|
|
} else if (!g_file_test(world->priv->path, G_FILE_TEST_EXISTS)) {
|
|
|
|
// There was no old path, so a new dir should be made
|
|
|
|
mkdir(world->priv->path, 0755);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free(tmp_path);
|
|
|
|
|
|
|
|
tmp_path = g_strconcat(world->priv->path, G_DIR_SEPARATOR_S, "settings",
|
|
|
|
NULL);
|
|
|
|
gm_options_save_as(world->priv->options, tmp_path);
|
|
|
|
g_free(tmp_path);
|
|
|
|
|
|
|
|
tmp_path = g_strconcat(world->priv->path, G_DIR_SEPARATOR_S, "triggers",
|
|
|
|
NULL);
|
|
|
|
gm_triggers_save_as(world->priv->triggers, tmp_path);
|
|
|
|
g_free(tmp_path);
|
|
|
|
|
|
|
|
g_signal_emit(world, world_signals[NAME_CHANGED], 0,
|
|
|
|
gm_options_get(world->priv->options, "name"));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Callbacks */
|
|
|
|
|
|
|
|
void
|
|
|
|
on_gm_world_net_state_changing(GmNet *net, GmNetState state, GmWorld *world) {
|
|
|
|
g_signal_emit(world, world_signals[STATE_CHANGING], 0, state);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
on_gm_world_net_net_error(GmNet *net, gchar *error, gint code,
|
|
|
|
GmWorld *world) {
|
|
|
|
g_signal_emit(world, world_signals[WORLD_ERROR], 0, error, code);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
on_gm_world_net_bytes_recv(GmNet *net, gchar *text, gint len,
|
|
|
|
GmWorld *world) {
|
|
|
|
gchar *all, *utext, *ptr, *line, *p;
|
|
|
|
gint i;
|
|
|
|
|
2005-11-06 17:01:48 +01:00
|
|
|
utext = gm_to_utf8_with_fallback(text, len,
|
|
|
|
gm_options_get(world->priv->options, "charset"), "?");
|
2005-10-09 10:53:36 +02:00
|
|
|
|
|
|
|
if (!utext) {
|
2005-11-06 17:01:48 +01:00
|
|
|
debug_msg(1, "GmWorld.NetBytesRecv: conversion failed!");
|
2005-10-09 10:53:36 +02:00
|
|
|
utext = g_strndup(text, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (world->priv->buffer != NULL) {
|
|
|
|
all = g_strconcat(world->priv->buffer, utext, NULL);
|
|
|
|
g_free(utext);
|
|
|
|
g_free(world->priv->buffer);
|
|
|
|
world->priv->buffer = NULL;
|
|
|
|
} else {
|
|
|
|
all = utext;
|
|
|
|
}
|
|
|
|
|
|
|
|
line = (gchar *)(malloc((strlen(all) * sizeof(gchar)) + 1));
|
|
|
|
i = 0;
|
|
|
|
p = all;
|
|
|
|
|
|
|
|
/* Find lines in `all' and process them */
|
|
|
|
for (ptr = all; *ptr != '\0'; ptr++) {
|
|
|
|
if (*ptr == '\n') {
|
|
|
|
line[i] = '\n';
|
|
|
|
line[i + 1] = '\0';
|
2005-10-11 11:45:35 +02:00
|
|
|
|
2005-10-09 10:53:36 +02:00
|
|
|
gm_world_process_line(world, line);
|
|
|
|
p = ptr + 1;
|
|
|
|
i = 0;
|
|
|
|
} else if (*ptr != '\r') {
|
|
|
|
line[i] = *ptr;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i > 0) {
|
|
|
|
world->priv->buffer = g_strdup(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free(all);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
on_gm_world_options_option_changed(GmOptions *options, gchar *key,
|
|
|
|
GmWorld *world) {
|
|
|
|
if (strcmp(key, "name") == 0) {
|
|
|
|
gm_world_name_changed(world);
|
|
|
|
}
|
|
|
|
}
|