diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 96491fc8c..148f0f477 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -241,6 +241,7 @@ static void client_send_info() game_start_time = -1; msg_pack_start_system(NETMSG_INFO, MSGFLAG_VITAL); + msg_pack_string(TEEWARS_NETVERSION_STRING, 64); msg_pack_string(config.player_name, 128); msg_pack_string(config.clan_name, 128); msg_pack_string(config.password, 128); @@ -380,22 +381,15 @@ static void client_serverbrowse_update() } // ------ state handling ----- -enum -{ - STATE_OFFLINE, - STATE_CONNECTING, - STATE_LOADING, - STATE_ONLINE, - STATE_BROKEN, - STATE_QUIT, -}; - static int state; -static int client_get_state() { return state; } +int client_state() { return state; } static void client_set_state(int s) { dbg_msg("game", "state change. last=%d current=%d", state, s); + int old = state; state = s; + if(old != s) + modc_statechange(state, old); } @@ -424,14 +418,14 @@ void client_connect(const char *server_address_str) dbg_msg("client", "could not find the address of %s, connecting to localhost", buf); net.connect(&server_address); - client_set_state(STATE_CONNECTING); + client_set_state(CLIENTSTATE_CONNECTING); } void client_disconnect() { client_send_error("disconnected"); net.disconnect("disconnected"); - client_set_state(STATE_OFFLINE); + client_set_state(CLIENTSTATE_OFFLINE); map_unload(); } @@ -472,66 +466,28 @@ static void client_debug_render() } +void client_quit() +{ + client_set_state(CLIENTSTATE_QUITING); +} + +const char *client_error_string() +{ + return net.error_string(); +} + static void client_render() { gfx_clear(0.0f,0.0f,0.0f); - - // this should be moved around abit - // TODO: clean this shit up! - if(client_get_state() == STATE_ONLINE) - { - modc_render(); - - // debug render stuff - client_debug_render(); - - } - else if (client_get_state() != STATE_CONNECTING && client_get_state() != STATE_LOADING) - { - //netaddr4 server_address; - int status = modmenu_render(); - if (status == -1) - client_set_state(STATE_QUIT); - } - else if (client_get_state() == STATE_CONNECTING || client_get_state() == STATE_LOADING) - { - static int64 start = time_get(); - static int tee_texture; - static int connecting_texture; - static bool inited = false; - - if (!inited) - { - tee_texture = gfx_load_texture("data/gui_tee.png"); - connecting_texture = gfx_load_texture("data/gui_connecting.png"); - - inited = true; - } - - gfx_mapscreen(0,0,400.0f,300.0f); - - float t = (time_get() - start) / (double)time_freq(); - - float speed = 2*sin(t); - - speed = 1.0f; - - float x = 208 + sin(t*speed) * 32; - float w = sin(t*speed + 3.149) * 64; - - ui_do_image(tee_texture, x, 95, w, 64); - ui_do_image(connecting_texture, 88, 150, 256, 64); - - if(inp_key_down(input::esc)) - client_disconnect(); - } + modc_render(); + client_debug_render(); } static void client_error(const char *msg) { dbg_msg("game", "error: %s", msg); client_send_error(msg); - client_set_state(STATE_BROKEN); + client_set_state(CLIENTSTATE_QUITING); } static void client_process_packet(NETPACKET *packet) @@ -621,7 +577,7 @@ static void client_process_packet(NETPACKET *packet) { const char *map = msg_unpack_string(); dbg_msg("client/network", "connection accepted, map=%s", map); - client_set_state(STATE_LOADING); + client_set_state(CLIENTSTATE_LOADING); if(map_load(map)) { @@ -729,7 +685,7 @@ static void client_process_packet(NETPACKET *packet) if(recived_snapshots == 2) { local_start_time = time_get(); - client_set_state(STATE_ONLINE); + client_set_state(CLIENTSTATE_ONLINE); } int64 now = time_get(); @@ -777,18 +733,19 @@ static void client_pump_network() net.update(); // check for errors - if(client_get_state() != STATE_OFFLINE && net.state() == NETSTATE_OFFLINE) + if(client_state() != CLIENTSTATE_OFFLINE && net.state() == NETSTATE_OFFLINE) { // TODO: add message to the user there - client_set_state(STATE_OFFLINE); + client_set_state(CLIENTSTATE_OFFLINE); + dbg_msg("client", "offline error='%s'", net.error_string()); } // - if(client_get_state() == STATE_CONNECTING && net.state() == NETSTATE_ONLINE) + if(client_state() == CLIENTSTATE_CONNECTING && net.state() == NETSTATE_ONLINE) { // we switched to online dbg_msg("client", "connected, sending info"); - client_set_state(STATE_LOADING); + client_set_state(CLIENTSTATE_LOADING); client_send_info(); } @@ -824,7 +781,7 @@ static void client_run(const char *direct_connect_server) modc_init(); // init menu - modmenu_init(); + modmenu_init(); // TODO: remove // open socket net.open(0, 0); @@ -888,7 +845,7 @@ static void client_run(const char *direct_connect_server) } // send input - if(client_get_state() == STATE_ONLINE) + if(client_state() == CLIENTSTATE_ONLINE) { if(server_spam_address) client_disconnect(); @@ -901,7 +858,7 @@ static void client_run(const char *direct_connect_server) } } - if(client_get_state() == STATE_OFFLINE && server_spam_address) + if(client_state() == CLIENTSTATE_OFFLINE && server_spam_address) client_connect(server_spam_address); // update input @@ -943,7 +900,7 @@ static void client_run(const char *direct_connect_server) gfx_swap(); // check conditions - if(client_get_state() == STATE_BROKEN || client_get_state() == STATE_QUIT) + if(client_state() == CLIENTSTATE_QUITING) break; // be nice @@ -958,10 +915,6 @@ static void client_run(const char *direct_connect_server) reporttime += reportinterval; } - /*if (input::pressed(input::esc)) - if (get_state() == STATE_CONNECTING || get_state() == STATE_ONLINE) - disconnect();*/ - // update frametime frametime = (time_get()-frame_start_time)/(float)time_freq(); } diff --git a/src/engine/interface.h b/src/engine/interface.h index 6a4953ac0..5d3e2fe69 100644 --- a/src/engine/interface.h +++ b/src/engine/interface.h @@ -21,6 +21,12 @@ enum /* IMG_BGR, IMG_BGRA,*/ + + CLIENTSTATE_OFFLINE=0, + CLIENTSTATE_CONNECTING, + CLIENTSTATE_LOADING, + CLIENTSTATE_ONLINE, + CLIENTSTATE_QUITING, }; struct snap_item @@ -667,6 +673,12 @@ void modc_shutdown(); */ void modc_render(); +/* + Function: modc_statechange + Called every time client changes state. +*/ +void modc_statechange(int new_state, int old_state); + /* @@ -748,6 +760,8 @@ int client_send_msg(); int client_tick(); float client_intratick(); int client_tickspeed(); +int client_state(); +const char *client_error_string(); void gfx_pretty_text(float x, float y, float size, const char *text); float gfx_pretty_text_width(float size, const char *text, int length = -1); @@ -771,6 +785,7 @@ struct server_info void client_connect(const char *address); void client_disconnect(); +void client_quit(); void client_serverbrowse_refresh(int lan); int client_serverbrowse_getlist(server_info **servers); diff --git a/src/engine/network.cpp b/src/engine/network.cpp index 93f4e158d..838c5f5da 100644 --- a/src/engine/network.cpp +++ b/src/engine/network.cpp @@ -1,4 +1,5 @@ #include +#include #include "network.h" #include "ringbuffer.h" @@ -87,7 +88,7 @@ struct NETCONNECTION int64 last_recv_time; int64 last_send_time; - const char *error_string; + char error_string[256]; NETADDR4 peeraddr; NETSOCKET socket; @@ -133,7 +134,7 @@ static void conn_reset(NETCONNECTION *conn) } conn->state = NETWORK_CONNSTATE_OFFLINE; - conn->error_string = 0; + mem_zero(conn->error_string, sizeof(conn->error_string)); conn->last_send_time = 0; conn->last_recv_time = 0; conn->token = -1; @@ -145,6 +146,12 @@ static const char *conn_error(NETCONNECTION *conn) { return conn->error_string; } + +static void conn_set_error(NETCONNECTION *conn, const char *str) +{ + strcpy(conn->error_string, str); +} + /* static int conn_state(NETCONNECTION *conn) { @@ -243,9 +250,12 @@ static int conn_connect(NETCONNECTION *conn, NETADDR4 *addr) return 0; } -static void conn_disconnect(NETCONNECTION *conn) +static void conn_disconnect(NETCONNECTION *conn, const char *reason) { - conn_send(conn, NETWORK_PACKETFLAG_CLOSE, 0, 0); + if(reason) + conn_send(conn, NETWORK_PACKETFLAG_CLOSE, strlen(reason)+1, reason); + else + conn_send(conn, NETWORK_PACKETFLAG_CLOSE, 0, 0); conn_reset(conn); } @@ -258,6 +268,11 @@ static int conn_feed(NETCONNECTION *conn, NETPACKETDATA *p, NETADDR4 *addr) if(p->flags&NETWORK_PACKETFLAG_CLOSE) { conn_reset(conn); + if(p->data_size) + conn_set_error(conn, (char *)p->data); + else + conn_set_error(conn, "no reason given"); + dbg_msg("conn", "closed reason='%s'", conn_error(conn)); return 0; } @@ -360,10 +375,10 @@ static int conn_feed(NETCONNECTION *conn, NETPACKETDATA *p, NETADDR4 *addr) -static void conn_update(NETCONNECTION *conn) +static int conn_update(NETCONNECTION *conn) { if(conn->state == NETWORK_CONNSTATE_OFFLINE || conn->state == NETWORK_CONNSTATE_ERROR) - return; + return 0; // check for timeout if(conn->state != NETWORK_CONNSTATE_OFFLINE && @@ -372,7 +387,7 @@ static void conn_update(NETCONNECTION *conn) { //dbg_msg("connection", "state = %d->%d", conn->state, NETWORK_CONNSTATE_ERROR); conn->state = NETWORK_CONNSTATE_ERROR; - conn->error_string = "timeout"; + conn_set_error(conn, "timeout"); } // check for large buffer errors @@ -380,7 +395,7 @@ static void conn_update(NETCONNECTION *conn) { //dbg_msg("connection", "state = %d->%d", conn->state, NETWORK_CONNSTATE_ERROR); conn->state = NETWORK_CONNSTATE_ERROR; - conn->error_string = "too weak connection (out of buffer)"; + conn_set_error(conn, "too weak connection (out of buffer)"); } if(conn->buffer.first()) @@ -390,7 +405,7 @@ static void conn_update(NETCONNECTION *conn) { //dbg_msg("connection", "state = %d->%d", conn->state, NETWORK_CONNSTATE_ERROR); conn->state = NETWORK_CONNSTATE_ERROR; - conn->error_string = "too weak connection (not acked for 3 seconds)"; + conn_set_error(conn, "too weak connection (not acked for 3 seconds)"); } } @@ -494,7 +509,8 @@ int net_server_drop(NETSERVER *s, int client_id, const char *reason) { // TODO: insert lots of checks here dbg_msg("net_server", "client dropped. cid=%d reason=\"%s\"", client_id, reason); - conn_reset(&s->slots[client_id].conn); + conn_disconnect(&s->slots[client_id].conn, reason); + //conn_reset(&s->slots[client_id].conn); return 0; } @@ -503,7 +519,7 @@ int net_server_update(NETSERVER *s) for(int i = 0; i < NETWORK_MAX_CLIENTS; i++) { conn_update(&s->slots[i].conn); - if(conn_error(&s->slots[i].conn)) + if(s->slots[i].conn.state == NETWORK_CONNSTATE_ERROR) net_server_drop(s, i, conn_error(&s->slots[i].conn)); } return 0; @@ -674,7 +690,7 @@ int net_client_update(NETCLIENT *c) { // TODO: implement me conn_update(&c->conn); - if(conn_error(&c->conn)) + if(c->conn.state == NETWORK_CONNSTATE_ERROR) net_client_disconnect(c, conn_error(&c->conn)); return 0; } @@ -683,7 +699,7 @@ int net_client_disconnect(NETCLIENT *c, const char *reason) { // TODO: do this more graceful dbg_msg("net_client", "disconnected. reason=\"%s\"", reason); - conn_disconnect(&c->conn); + conn_disconnect(&c->conn, 0); return 0; } @@ -786,3 +802,8 @@ void net_client_stats(NETCLIENT *c, NETSTATS *stats) { *stats = c->conn.stats; } + +const char *net_client_error_string(NETCLIENT *c) +{ + return conn_error(&c->conn); +} diff --git a/src/engine/network.h b/src/engine/network.h index e251f13e3..adcd6d383 100644 --- a/src/engine/network.h +++ b/src/engine/network.h @@ -56,6 +56,7 @@ int net_client_close(NETCLIENT *c); int net_client_update(NETCLIENT *c); int net_client_state(NETCLIENT *c); void net_client_stats(NETCLIENT *c, NETSTATS *stats); +const char *net_client_error_string(NETCLIENT *c); // wrapper classes for c++ @@ -99,6 +100,8 @@ public: int send(NETPACKET *packet) { return net_client_send(ptr, packet); } int update() { return net_client_update(ptr); } + const char *error_string() { return net_client_error_string(ptr); } + int state() { return net_client_state(ptr); } void stats(NETSTATS *stats) { net_client_stats(ptr, stats); } }; diff --git a/src/engine/packet.h b/src/engine/packet.h index 1700665d6..79c969c2d 100644 --- a/src/engine/packet.h +++ b/src/engine/packet.h @@ -11,6 +11,10 @@ enum { NETMSG_NULL=0, + // the first thing sent by the client + // contains the version info for the client + NETMSG_INFO=1, + // sent by server NETMSG_MAP, NETMSG_SNAP, @@ -18,7 +22,6 @@ enum NETMSG_SNAPSMALL, // sent by client - NETMSG_INFO, NETMSG_ENTERGAME, NETMSG_INPUT, NETMSG_SNAPACK, diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index c20821ebb..6a2b7b8fe 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -397,6 +397,18 @@ public: // system message if(msg == NETMSG_INFO) { + char version[64]; + strncpy(version, msg_unpack_string(), 64); + if(strcmp(version, TEEWARS_NETVERSION_STRING) != 0) + //if(strcmp(version, "ERROR") != 0) + { + // OH FUCK! wrong version, drop him + char reason[256]; + sprintf(reason, "wrong version. server is running %s.", TEEWARS_NETVERSION_STRING); + net.drop(cid, reason); + return; + } + strncpy(clients[cid].name, msg_unpack_string(), MAX_NAME_LENGTH); strncpy(clients[cid].clan, msg_unpack_string(), MAX_CLANNAME_LENGTH); const char *password = msg_unpack_string(); diff --git a/src/engine/versions.h b/src/engine/versions.h index 7b4fdc2a4..34d8d79da 100644 --- a/src/engine/versions.h +++ b/src/engine/versions.h @@ -1,3 +1,3 @@ #define TEEWARS_NETVERSION 0xffffffff -//#define TEEWARS_NETVERSION_STRING "dev v2" +#define TEEWARS_NETVERSION_STRING "0.2-dev" #define TEEWARS_VERSION "0.2.0-dev" diff --git a/src/game/client/game_client.cpp b/src/game/client/game_client.cpp index 57618202d..8fdf9adea 100644 --- a/src/game/client/game_client.cpp +++ b/src/game/client/game_client.cpp @@ -127,7 +127,7 @@ void select_sprite(int id, int flags=0, int sx=0, int sy=0) select_sprite(&data->sprites[id], flags, sx, sy); } -static void draw_sprite(float x, float y, float size) +void draw_sprite(float x, float y, float size) { gfx_quads_draw(x, y, size*sprite_w_scale, size*sprite_h_scale); } @@ -830,7 +830,7 @@ static void render_tee(animstate *anim, int skin, vec2 dir, vec2 pos) gfx_quads_end(); } -static void draw_round_rect(float x, float y, float w, float h, float r) +void draw_round_rect(float x, float y, float w, float h, float r) { int num = 8; for(int i = 0; i < num; i+=2) @@ -1194,7 +1194,7 @@ void ingamemenu_render() } -void modc_render() +void render_game() { animstate idlestate; anim_eval(&data->animations[ANIM_BASE], 0, &idlestate); @@ -1394,8 +1394,8 @@ void modc_render() { float parallax_amount = 0.55f; select_sprite(cloud_sprites[i]); - gfx_quads_drawTL((cloud_pos[i].x+fmod(client_localtime()*cloud_speed[i]+i*100.0f, 1700.0f))+screen_x*parallax_amount, - cloud_pos[i].y+screen_y*parallax_amount, 300, 300); + draw_sprite((cloud_pos[i].x+fmod(client_localtime()*cloud_speed[i]+i*100.0f, 1700.0f))+screen_x*parallax_amount, + cloud_pos[i].y+screen_y*parallax_amount, 300); } gfx_quads_end(); @@ -1829,6 +1829,68 @@ void modc_render() } } +void modc_render() +{ + // this should be moved around abit + if(client_state() == CLIENTSTATE_ONLINE) + { + render_game(); + } + else // if (client_state() != CLIENTSTATE_CONNECTING && client_state() != CLIENTSTATE_LOADING) + { + //netaddr4 server_address; + if(modmenu_render() == -1) + client_quit(); + + } + /* + else if (client_state() == CLIENTSTATE_CONNECTING || client_state() == CLIENTSTATE_LOADING) + { + static int64 start = time_get(); + static int tee_texture; + static int connecting_texture; + static bool inited = false; + + // TODO: ugly, remove this + if (!inited) + { + tee_texture = gfx_load_texture("data/gui_tee.png"); + connecting_texture = gfx_load_texture("data/gui_connecting.png"); + + inited = true; + } + + gfx_mapscreen(0,0,400.0f,300.0f); + + float t = (time_get() - start) / (double)time_freq(); + + float speed = 2*sin(t); + + speed = 1.0f; + + float x = 208 + sin(t*speed) * 32; + float w = sin(t*speed + 3.149) * 64; + + ui_do_image(tee_texture, x, 95, w, 64); + ui_do_image(connecting_texture, 88, 150, 256, 64); + + if(inp_key_down(input::esc)) + client_disconnect(); + }*/ +} + + +void menu_do_disconnected(); +void menu_do_connecting(); + +void modc_statechange(int state, int old) +{ + if(state == CLIENTSTATE_OFFLINE) + menu_do_disconnected(); + if(state == CLIENTSTATE_CONNECTING) + menu_do_connecting(); +} + void modc_message(int msg) { if(msg == MSG_CHAT) diff --git a/src/game/client/menu.cpp b/src/game/client/menu.cpp index d74282ffd..41ef9307a 100644 --- a/src/game/client/menu.cpp +++ b/src/game/client/menu.cpp @@ -143,6 +143,7 @@ extern pretty_font *current_font; extern void render_sun(float x, float y); extern void select_sprite(int id, int flags=0, int sx=0, int sy=0); +extern void draw_sprite(float x, float y, float size); void draw_background(float t) { @@ -156,11 +157,11 @@ void draw_background(float t) gfx_texture_set(data->images[IMAGE_CLOUDS].id); gfx_quads_begin(); select_sprite(SPRITE_CLOUD1); - gfx_quads_drawTL(3500 - fmod(t * 20 + 2000, 4524), 0, 512, 512); + draw_sprite(3500 - fmod(t * 20 + 2000, 4524), 250, 512); select_sprite(SPRITE_CLOUD2); - gfx_quads_drawTL(3000 - fmod(t * 50 + 2000, 4024), 150, 512, 512); + draw_sprite(3000 - fmod(t * 50 + 2000, 4024), 150+250, 512); select_sprite(SPRITE_CLOUD3); - gfx_quads_drawTL(4000 - fmod(t * 60 + 500, 4512), 300, 256, 256); + draw_sprite(4000 - fmod(t * 60 + 500, 4512), 300+130, 256); gfx_quads_end(); gfx_texture_set(data->images[IMAGE_MENU_BACKGROUND].id); @@ -681,6 +682,8 @@ static int do_server_list(float x, float y, int *scroll_index, int *selected_ind enum { SCREEN_MAIN, + SCREEN_DISCONNECTED, + SCREEN_CONNECTING, SCREEN_SETTINGS_GENERAL, SCREEN_SETTINGS_CONTROLS, SCREEN_SETTINGS_VIDEO, @@ -704,6 +707,8 @@ const float row5_y = row4_y + 40; const float row6_y = row5_y + 40; const float row7_y = row6_y + 40; +static char address[128] = "localhost:8303"; + static int main_render() { static bool inited = false; @@ -718,8 +723,6 @@ static int main_render() int last_selected_index = selected_index; do_server_list(20, 160, &scoll_index, &selected_index, 8); - static char address[32] = "localhost:8303"; - ui_do_edit_box(address, 280, 425, 300, 36, address, sizeof(address)); if (last_selected_index != selected_index && selected_index != -1) @@ -1176,6 +1179,74 @@ static int kerning_render() return 0; } +extern void draw_round_rect(float x, float y, float w, float h, float r); + +static int render_popup(const char *caption, const char *text, const char *button_text) +{ + float tw; + + float w = 700; + float h = 300; + float x = 800/2-w/2; + float y = 600/2-h/2; + + gfx_blend_normal(); + + gfx_texture_set(-1); + gfx_quads_begin(); + gfx_quads_setcolor(0,0,0,0.50f); + draw_round_rect(x, y, w, h, 40.0f); + gfx_quads_end(); + + tw = gfx_pretty_text_width(48.0f, caption); + ui_do_label(x+w/2-tw/2, y+20, caption, 48.0f); + + tw = gfx_pretty_text_width(32.0f, text); + ui_do_label(x+w/2-tw/2, y+130, text, 32.0f); + + static int back_button = 0; + if(ui_do_button(&back_button, button_text, 0, x+w/2-100, y+220, 200, 48, draw_teewars_button)) + return 1; + + return 0; +} + +static int disconnected_render() +{ + if(strlen(client_error_string()) == 0) + screen = SCREEN_MAIN; + else + { + if(render_popup("Disconnected", client_error_string(), "Back")) + screen = SCREEN_MAIN; + } + return 0; +} + +static int connecting_render() +{ + char buf[256]; + sprintf(buf, "Server: %s", address); + if(render_popup("Connecting", buf, "Abort")) + { + client_disconnect(); + screen = SCREEN_MAIN; + } + return 0; +} + + +void menu_do_disconnected() +{ + screen = SCREEN_DISCONNECTED; +} + + +void menu_do_connecting() +{ + screen = SCREEN_CONNECTING; +} + static int menu_render() { // background color @@ -1201,6 +1272,8 @@ static int menu_render() switch (screen) { case SCREEN_MAIN: return main_render(); + case SCREEN_DISCONNECTED: return disconnected_render(); + case SCREEN_CONNECTING: return connecting_render(); case SCREEN_SETTINGS_GENERAL: case SCREEN_SETTINGS_CONTROLS: case SCREEN_SETTINGS_VIDEO: @@ -1282,6 +1355,8 @@ int modmenu_render() input::clear_char(); input::clear_key(); + + //if(r) return r; }