From 1c1677f02300e5ab10bca9c74ce7f49d4605b9d6 Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Sat, 12 Jan 2008 12:08:26 +0000 Subject: [PATCH] merged 0.3.3 changes over to trunk --- src/engine/client/ec_client.c | 23 ++++- src/engine/client/ec_gfx.c | 34 ++++--- src/engine/client/ec_inp.c | 71 +++++++++----- src/engine/client/ec_snd.c | 27 +++++- src/engine/client/ec_srvbrowse.c | 6 ++ src/engine/e_config_variables.h | 5 + src/engine/e_interface.h | 21 +++- src/engine/server/es_server.c | 14 ++- src/game/client/gc_client.cpp | 135 +++++++++++++++++--------- src/game/client/gc_menu.cpp | 159 ++++++++++++++++++++----------- src/game/g_variables.h | 2 +- src/game/g_version.h | 2 +- src/game/server/gs_common.h | 5 + src/game/server/gs_server.cpp | 39 +++++--- 14 files changed, 380 insertions(+), 163 deletions(-) diff --git a/src/engine/client/ec_client.c b/src/engine/client/ec_client.c index d35121dea..b07edf781 100644 --- a/src/engine/client/ec_client.c +++ b/src/engine/client/ec_client.c @@ -304,6 +304,24 @@ int client_connection_problems() return netclient_gotproblems(net); } +void client_direct_input(int *input, int size) +{ + int i; + msg_pack_start_system(NETMSG_INPUT, 0); + msg_pack_int(ack_game_tick); + msg_pack_int(current_predtick); + msg_pack_int(size); + + for(i = 0; i < size/4; i++) + msg_pack_int(input[i]); + + msg_pack_end(); + client_send_msg(); + + dbg_msg("client", "sent direct input"); +} + + static void client_send_input() { int64 now = time_get(); @@ -312,7 +330,7 @@ static void client_send_input() if(current_predtick <= 0) return; - /* fetch input */ + /* fetch input */ size = modc_snap_input(inputs[current_input].data); msg_pack_start_system(NETMSG_INPUT, 0); @@ -1006,6 +1024,9 @@ static void client_run() /* update input */ inp_update(); + + /* update sound */ + snd_update(); /* refocus */ if(!gfx_window_active()) diff --git a/src/engine/client/ec_gfx.c b/src/engine/client/ec_gfx.c index 0562a24f9..70712dede 100644 --- a/src/engine/client/ec_gfx.c +++ b/src/engine/client/ec_gfx.c @@ -489,20 +489,22 @@ int gfx_load_texture_raw(int w, int h, int format, const void *data, int store_f gluBuild2DMipmaps(GL_TEXTURE_2D, store_oglformat, w, h, oglformat, GL_UNSIGNED_BYTE, texdata); /* calculate memory usage */ - int pixel_size = 4; - if(store_format == IMG_RGB) - pixel_size = 3; - else if(store_format == IMG_ALPHA) - pixel_size = 1; - - textures[tex].memsize = w*h*pixel_size; - if(mipmap) { - while(w > 2 && h > 2) + int pixel_size = 4; + if(store_format == IMG_RGB) + pixel_size = 3; + else if(store_format == IMG_ALPHA) + pixel_size = 1; + + textures[tex].memsize = w*h*pixel_size; + if(mipmap) { - w>>=1; - h>>=1; - textures[tex].memsize += w*h*pixel_size; + while(w > 2 && h > 2) + { + w>>=1; + h>>=1; + textures[tex].memsize += w*h*pixel_size; + } } } @@ -544,7 +546,9 @@ int gfx_load_mip_texture_raw(int w, int h, int format, const void *data) int gfx_load_texture(const char *filename, int store_format) { int l = strlen(filename); + int id; IMAGE_INFO img; + if(l < 3) return 0; if(gfx_load_png(&img, filename)) @@ -552,7 +556,7 @@ int gfx_load_texture(const char *filename, int store_format) if (store_format == IMG_AUTO) store_format = img.format; - int id = gfx_load_texture_raw(img.width, img.height, img.format, img.data, store_format); + id = gfx_load_texture_raw(img.width, img.height, img.format, img.data, store_format); mem_free(img.data); return id; } @@ -1101,7 +1105,7 @@ void gfx_pretty_text(float x, float y, float size, const char *text, int max_wid float gfx_pretty_text_width(float size, const char *text_, int length) { return gfx_text_width(gfx_font_set, size, text_, length); - + /* const float spacing = 0.05f; float w = 0.0f; const unsigned char *text = (unsigned char *)text_; @@ -1126,7 +1130,7 @@ float gfx_pretty_text_width(float size, const char *text_, int length) text++; } - return w; + return w;*/ } diff --git a/src/engine/client/ec_inp.c b/src/engine/client/ec_inp.c index 154342f46..cac696694 100644 --- a/src/engine/client/ec_inp.c +++ b/src/engine/client/ec_inp.c @@ -48,19 +48,56 @@ void inp_mouse_relative(int *x, int *y) last_y = ny; } -static char last_c = 0; -static int last_k = 0; +enum +{ + INPUT_BUFFER_SIZE=32 +}; + +static INPUTEVENT input_events[INPUT_BUFFER_SIZE]; +static int num_events = 0; + +static void add_event(char c, int key) +{ + if(num_events != INPUT_BUFFER_SIZE) + { + input_events[num_events].ch = c; + input_events[num_events].key = key; + num_events++; + } +} + +int inp_num_events() +{ + return num_events; +} + +void inp_clear_events() +{ + num_events = 0; +} + +INPUTEVENT inp_get_event(int index) +{ + if(index < 0 || index >= num_events) + { + INPUTEVENT e = {0,0}; + return e; + } + + return input_events[index]; +} + static void char_callback(int character, int action) { if(action == GLFW_PRESS && character < 256) - last_c = (char)character; + add_event((char)character, 0); } static void key_callback(int key, int action) { if(action == GLFW_PRESS) - last_k = key; + add_event(0, key); if(action == GLFW_PRESS) input_count[input_current^1][key].presses++; @@ -72,7 +109,7 @@ static void key_callback(int key, int action) static void mousebutton_callback(int button, int action) { if(action == GLFW_PRESS) - last_k = KEY_MOUSE_FIRST+button; + add_event(0, KEY_MOUSE_FIRST+button); if(action == GLFW_PRESS) input_count[input_current^1][KEY_MOUSE_FIRST+button].presses++; @@ -99,7 +136,7 @@ static void mousewheel_callback(int pos) input_count[input_current^1][KEY_MOUSE_WHEEL_UP].releases++; } - last_k = KEY_MOUSE_WHEEL_UP; + add_event(0, KEY_MOUSE_WHEEL_UP); } else if(pos < 0) { @@ -109,7 +146,7 @@ static void mousewheel_callback(int pos) input_count[input_current^1][KEY_MOUSE_WHEEL_DOWN].releases++; } - last_k = KEY_MOUSE_WHEEL_DOWN; + add_event(0, KEY_MOUSE_WHEEL_DOWN); } glfwSetMouseWheel(0); } @@ -124,22 +161,6 @@ void inp_init() glfwSetMouseWheelCallback(mousewheel_callback); } -char inp_last_char() -{ - return last_c; -} - -int inp_last_key() -{ - return last_k; -} - -void inp_clear() -{ - last_k = 0; - last_c = 0; -} - void inp_mouse_mode_absolute() { glfwEnable(GLFW_MOUSE_CURSOR); @@ -147,8 +168,8 @@ void inp_mouse_mode_absolute() void inp_mouse_mode_relative() { - //if (!config.gfx_debug_resizable) - //glfwDisable(GLFW_MOUSE_CURSOR); + /*if (!config.gfx_debug_resizable)*/ + glfwDisable(GLFW_MOUSE_CURSOR); } int inp_mouse_doubleclick() diff --git a/src/engine/client/ec_snd.c b/src/engine/client/ec_snd.c index 152eac53e..49f050c97 100644 --- a/src/engine/client/ec_snd.c +++ b/src/engine/client/ec_snd.c @@ -55,6 +55,7 @@ static int center_x = 0; static int center_y = 0; static int mixing_rate = 48000; +static volatile int sound_volume = 100; void snd_set_channel(int cid, float vol, float pan) { @@ -135,10 +136,13 @@ static void mix(short *final_out, unsigned frames) { int mix_buffer[MAX_FRAMES*2] = {0}; int i, s; + int master_vol; /* aquire lock while we are mixing */ lock_wait(sound_lock); + master_vol = sound_volume; + for(i = 0; i < NUM_VOICES; i++) { if(voices[i].snd) @@ -208,12 +212,12 @@ static void mix(short *final_out, unsigned frames) } } + + /* release the lock */ lock_release(sound_lock); { - int master_vol = config.snd_volume; - /* clamp accumulated values */ /* TODO: this seams slow */ for(i = 0; i < frames; i++) @@ -283,6 +287,25 @@ int snd_init() err = Pa_StartStream(stream); sound_enabled = 1; + snd_update(); /* update the volume */ + return 0; +} + +int snd_update() +{ + /* update volume */ + int wanted_volume = config.snd_volume; + + if(!gfx_window_active() && config.snd_nonactive_mute) + wanted_volume = 0; + + if(wanted_volume != sound_volume) + { + lock_wait(sound_lock); + sound_volume = wanted_volume; + lock_release(sound_lock); + } + return 0; } diff --git a/src/engine/client/ec_srvbrowse.c b/src/engine/client/ec_srvbrowse.c index d9b3f4ff7..3a07d86a2 100644 --- a/src/engine/client/ec_srvbrowse.c +++ b/src/engine/client/ec_srvbrowse.c @@ -149,6 +149,10 @@ static void client_serverbrowse_filter() filtered = 1; else if(config.b_filter_pw && serverlist[i]->info.flags&1) filtered = 1; + else if(config.b_filter_ping < serverlist[i]->info.latency) + filtered = 1; + else if(!(config.b_filter_gametype&(1<info.game_type))) + filtered = 1; else if(config.b_filter_string[0] != 0) { if(strstr(serverlist[i]->info.name, config.b_filter_string) == 0) @@ -167,6 +171,8 @@ static int client_serverbrowse_sorthash() i |= config.b_filter_full<<5; i |= config.b_filter_pw<<6; i |= config.b_sort_order<<7; + i |= config.b_filter_gametype<<8; + i |= config.b_filter_ping<<16; return i; } diff --git a/src/engine/e_config_variables.h b/src/engine/e_config_variables.h index 99c10c4b9..c3bbc524f 100644 --- a/src/engine/e_config_variables.h +++ b/src/engine/e_config_variables.h @@ -16,6 +16,9 @@ MACRO_CONFIG_STR(b_filter_string, 64, "") MACRO_CONFIG_INT(b_filter_full, 0, 0, 1) MACRO_CONFIG_INT(b_filter_empty, 0, 0, 1) MACRO_CONFIG_INT(b_filter_pw, 0, 0, 1) +MACRO_CONFIG_INT(b_filter_ping, 999, 0, 999) +MACRO_CONFIG_INT(b_filter_gametype, 0xf, 0, 0xf) + MACRO_CONFIG_INT(b_sort, 0, 0, 256) MACRO_CONFIG_INT(b_sort_order, 0, 0, 1) MACRO_CONFIG_INT(b_max_requests, 10, 0, 1000) @@ -25,6 +28,8 @@ MACRO_CONFIG_INT(snd_enable, 1, 0, 1) MACRO_CONFIG_INT(snd_volume, 100, 0, 100) MACRO_CONFIG_INT(snd_device, -1, 0, 0) +MACRO_CONFIG_INT(snd_nonactive_mute, 0, 0, 1) + MACRO_CONFIG_INT(gfx_screen_width, 800, 0, 0) MACRO_CONFIG_INT(gfx_screen_height, 600, 0, 0) MACRO_CONFIG_INT(gfx_fullscreen, 1, 0, 1) diff --git a/src/engine/e_interface.h b/src/engine/e_interface.h index 3f14745c3..666d15e51 100644 --- a/src/engine/e_interface.h +++ b/src/engine/e_interface.h @@ -396,6 +396,7 @@ void gfx_quads_text(float x, float y, float size, const char *text); /* sound (client) */ int snd_init(); +int snd_update(); void snd_set_channel(int cid, float vol, float pan); @@ -758,6 +759,9 @@ const char *mods_version(); /* server */ int server_getclientinfo(int client_id, CLIENT_INFO *info); const char *server_clientname(int client_id); + +/* grabs the latest input for the client. not withholding anything */ +int *server_latestinput(int client_id, int *size); void server_setclientname(int client_id, const char *name); void server_setclientscore(int client_id, int score); @@ -770,9 +774,19 @@ int server_tickspeed(); /* input */ int inp_key_was_pressed(int key); int inp_key_down(int key); -char inp_last_char(); -int inp_last_key(); -void inp_clear(); + + + +typedef struct +{ + char ch; + int key; +} INPUTEVENT; + +int inp_num_events(); +INPUTEVENT inp_get_event(int index); +void inp_clear_events(); + void inp_update(); void inp_init(); void inp_mouse_mode_absolute(); @@ -831,6 +845,7 @@ float client_intrapredtick(); int client_tickspeed(); float client_frametime(); float client_localtime(); +void client_direct_input(int *input, int size); int client_state(); const char *client_error_string(); diff --git a/src/engine/server/es_server.c b/src/engine/server/es_server.c index 7cdaa0dc0..fda4b5d5b 100644 --- a/src/engine/server/es_server.c +++ b/src/engine/server/es_server.c @@ -89,6 +89,7 @@ typedef struct int last_acked_snapshot; SNAPSTORAGE snapshots; + CLIENT_INPUT latestinput; CLIENT_INPUT inputs[200]; /* TODO: handle input better */ int current_input; @@ -184,6 +185,13 @@ void snap_free_id(int id) } } +int *server_latestinput(int client_id, int *size) +{ + if(client_id < 0 || client_id > MAX_CLIENTS || clients[client_id].state < SRVCLIENT_STATE_READY) + return 0; + return clients[client_id].latestinput.data; +} + const char *server_clientname(int client_id) { if(client_id < 0 || client_id > MAX_CLIENTS || clients[client_id].state < SRVCLIENT_STATE_READY) @@ -489,6 +497,8 @@ static int new_client_callback(int cid, void *user) } clients[cid].current_input = 0; + mem_zero(&clients[cid].latestinput, sizeof(clients[cid].latestinput)); + snapstorage_purge_all(&clients[cid].snapshots); clients[cid].last_acked_snapshot = -1; clients[cid].snap_rate = SRVCLIENT_SNAPRATE_INIT; @@ -624,7 +634,9 @@ static void server_process_client_packet(NETPACKET *packet) for(i = 0; i < size/4; i++) input->data[i] = msg_unpack_int(); - + + mem_copy(clients[cid].latestinput.data, input->data, MAX_INPUT_SIZE*sizeof(int)); + clients[cid].current_input++; clients[cid].current_input %= 200; } diff --git a/src/game/client/gc_client.cpp b/src/game/client/gc_client.cpp index 5598c44fd..68c6db00e 100644 --- a/src/game/client/gc_client.cpp +++ b/src/game/client/gc_client.cpp @@ -33,6 +33,8 @@ data_container *data = 0x0; static player_input input_data = {0}; static int input_target_lock = 0; +static int64 debug_firedelay = 0; + extern void modmenu_render(); extern void menu_init(); @@ -79,8 +81,25 @@ static struct client_data int emoticon_start; player_core predicted; - tee_render_info skin_info; + tee_render_info skin_info; // this is what the server reports + tee_render_info render_info; // this is what we use + void update_render_info() + { + render_info = skin_info; + + // force team colors + if(gameobj && gameobj->gametype != GAMETYPE_DM) + { + const int team_colors[2] = {65387, 10223467}; + if(team >= 0 || team <= 1) + { + render_info.texture = skin_get(skin_id)->color_texture; + render_info.color_body = skin_get_color(team_colors[team]); + render_info.color_feet = skin_get_color(team_colors[team]); + } + } + } } client_datas[MAX_CLIENTS]; class client_effects @@ -915,6 +934,9 @@ extern "C" void modc_newsnapshot() if(item.type == OBJTYPE_PLAYER_INFO) { const obj_player_info *info = (const obj_player_info *)data; + + client_datas[info->clientid].team = info->team; + if(info->local) { local_info = info; @@ -938,6 +960,9 @@ extern "C" void modc_newsnapshot() } } } + + for(int i = 0; i < MAX_CLIENTS; i++) + client_datas[i].update_render_info(); } void send_info(bool start) @@ -963,8 +988,15 @@ void send_emoticon(int emoticon) client_send_msg(); } -static void render_projectile(const obj_projectile *prev, const obj_projectile *current, int itemid) +static void render_projectile(const obj_projectile *current, int itemid) { + if(debug_firedelay) + { + debug_firedelay = time_get()-debug_firedelay; + dbg_msg("game", "firedelay=%.2f ms", debug_firedelay/(float)time_freq()*1000.0f); + debug_firedelay = 0; + } + gfx_texture_set(data->images[IMAGE_GAME].id); gfx_quads_begin(); @@ -1143,10 +1175,10 @@ void anim_eval_add(animstate *state, animation *anim, float time, float amount) anim_add(state, &add, amount); } -static void render_hand(int skin_id, vec2 center_pos, vec2 dir, float angle_offset, vec2 post_rot_offset) +static void render_hand(tee_render_info *info, vec2 center_pos, vec2 dir, float angle_offset, vec2 post_rot_offset) { // for drawing hand - const skin *s = skin_get(skin_id); + //const skin *s = skin_get(skin_id); float basesize = 10.0f; //dir = normalize(hook_pos-pos); @@ -1168,8 +1200,9 @@ static void render_hand(int skin_id, vec2 center_pos, vec2 dir, float angle_offs hand_pos += diry * post_rot_offset.y; //gfx_texture_set(data->images[IMAGE_CHAR_DEFAULT].id); - gfx_texture_set(s->color_texture); + gfx_texture_set(info->texture); gfx_quads_begin(); + gfx_setcolor(info->color_body.r, info->color_body.g, info->color_body.b, info->color_body.a); // two passes for (int i = 0; i < 2; i++) @@ -1382,11 +1415,6 @@ static void render_player( } } - // TODO: proper skin selection - int skin_id = client_datas[info.clientid].skin_id; //charids[info.clientid]; - //if(gametype != GAMETYPE_DM) - //skin_id = info.team*9; // 0 or 9 - vec2 direction = get_direction(player.angle); float angle = player.angle/256.0f; vec2 position = mix(vec2(prev.x, prev.y), vec2(player.x, player.y), intratick); @@ -1463,7 +1491,7 @@ static void render_player( gfx_quads_setrotation(0); gfx_quads_end(); - render_hand(skin_id, position, normalize(hook_pos-pos), -pi/2, vec2(20, 0)); + render_hand(&client_datas[info.clientid].render_info, position, normalize(hook_pos-pos), -pi/2, vec2(20, 0)); } // draw gun @@ -1581,9 +1609,9 @@ static void render_player( switch (player.weapon) { - case WEAPON_GUN: render_hand(skin_id, p, direction, -3*pi/4, vec2(-15, 4)); break; - case WEAPON_SHOTGUN: render_hand(skin_id, p, direction, -pi/2, vec2(-5, 4)); break; - case WEAPON_ROCKET: render_hand(skin_id, p, direction, -pi/2, vec2(-4, 7)); break; + case WEAPON_GUN: render_hand(&client_datas[info.clientid].render_info, p, direction, -3*pi/4, vec2(-15, 4)); break; + case WEAPON_SHOTGUN: render_hand(&client_datas[info.clientid].render_info, p, direction, -pi/2, vec2(-5, 4)); break; + case WEAPON_ROCKET: render_hand(&client_datas[info.clientid].render_info, p, direction, -pi/2, vec2(-4, 7)); break; } } @@ -1592,14 +1620,14 @@ static void render_player( if(info.local && config.debug) { vec2 ghost_position = mix(vec2(prev_char->x, prev_char->y), vec2(player_char->x, player_char->y), client_intratick()); - tee_render_info ghost = client_datas[info.clientid].skin_info; + tee_render_info ghost = client_datas[info.clientid].render_info; ghost.color_body.a = 0.5f; ghost.color_feet.a = 0.5f; render_tee(&state, &ghost, player.emote, direction, ghost_position); // render ghost } // render the tee - render_tee(&state, &client_datas[info.clientid].skin_info, player.emote, direction, position); + render_tee(&state, &client_datas[info.clientid].render_info, player.emote, direction, position); if(player.state == STATE_CHATTING) { @@ -2103,7 +2131,7 @@ void render_scoreboard(float x, float y, float w, int team, const char *title) gfx_quads_end(); } - render_tee(&idlestate, &client_datas[info->clientid].skin_info, EMOTE_NORMAL, vec2(1,0), vec2(x+90, y+28)); + render_tee(&idlestate, &client_datas[info->clientid].render_info, EMOTE_NORMAL, vec2(1,0), vec2(x+90, y+28)); y += 50.0f; @@ -2202,9 +2230,9 @@ void render_world(float center_x, float center_y, float zoom) if(item.type == OBJTYPE_PROJECTILE) { - const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); - if(prev) - render_projectile((const obj_projectile *)prev, (const obj_projectile *)data, item.id); + //const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); + //if(prev) + render_projectile((const obj_projectile *)data, item.id); } else if(item.type == OBJTYPE_POWERUP) { @@ -2235,8 +2263,6 @@ void render_world(float center_x, float center_y, float zoom) const void *prev_info = snap_find_item(SNAP_PREV, OBJTYPE_PLAYER_INFO, item.id); const void *info = snap_find_item(SNAP_CURRENT, OBJTYPE_PLAYER_INFO, item.id); - client_datas[((const obj_player_info *)info)->clientid].team = ((const obj_player_info *)info)->team; - if(prev && prev_info && info) { render_player( @@ -2364,28 +2390,29 @@ void render_game() chat_mode = CHATMODE_NONE; } - int c = inp_last_char(); - int k = inp_last_key(); - - if (!(c >= 0 && c < 32)) + for(int i = 0; i < inp_num_events(); i++) { - if (chat_input_len < sizeof(chat_input) - 1) + INPUTEVENT e = inp_get_event(i); + + if (!(e.ch >= 0 && e.ch < 32)) { - chat_input[chat_input_len] = c; - chat_input[chat_input_len+1] = 0; - chat_input_len++; + if (chat_input_len < sizeof(chat_input) - 1) + { + chat_input[chat_input_len] = e.ch; + chat_input[chat_input_len+1] = 0; + chat_input_len++; + } + } + + if(e.key == KEY_BACKSPACE) + { + if(chat_input_len > 0) + { + chat_input[chat_input_len-1] = 0; + chat_input_len--; + } } } - - if(k == KEY_BACKSPACE) - { - if(chat_input_len > 0) - { - chat_input[chat_input_len-1] = 0; - chat_input_len--; - } - } - } else { @@ -2413,7 +2440,7 @@ void render_game() } if (!menu_active) - inp_clear(); + inp_clear_events(); // fetch new input if(!menu_active && !emoticon_selector_active) @@ -2451,6 +2478,8 @@ void render_game() // update some input if(!menu_active && chat_mode == CHATMODE_NONE) { + bool do_direct = false; + if(!emoticon_selector_active) { if(do_input(&input_data.fire, config.key_fire)) @@ -2460,6 +2489,17 @@ void render_game() input_data.target_x = (int)mouse_pos.x; input_data.target_y = (int)mouse_pos.y; input_target_lock = 1; + + if(inp_key_presses(config.key_fire)) + { + if(config.dbg_firedelay) + { + if(debug_firedelay == 0) + debug_firedelay = time_get(); + } + + do_direct = true; + } } } @@ -2480,6 +2520,9 @@ void render_game() if(inp_key_presses(config.key_weapon5)) input_data.wanted_weapon = 5; if(inp_key_presses(config.key_weapon6)) input_data.wanted_weapon = 6; } + + if(do_direct) // do direct input if wanted + client_direct_input((int *)&input_data, sizeof(input_data)); } @@ -2720,7 +2763,7 @@ void render_game() } } - render_tee(&idlestate, &client_datas[killmsgs[r].victim].skin_info, EMOTE_PAIN, vec2(-1,0), vec2(x, y+28)); + render_tee(&idlestate, &client_datas[killmsgs[r].victim].render_info, EMOTE_PAIN, vec2(-1,0), vec2(x, y+28)); x -= 32.0f; // render weapon @@ -2756,7 +2799,7 @@ void render_game() // render killer tee x -= 24.0f; - render_tee(&idlestate, &client_datas[killmsgs[r].killer].skin_info, EMOTE_ANGRY, vec2(1,0), vec2(x, y+28)); + render_tee(&idlestate, &client_datas[killmsgs[r].killer].render_info, EMOTE_ANGRY, vec2(1,0), vec2(x, y+28)); x -= 32.0f; // render killer name @@ -2913,7 +2956,7 @@ void render_game() const char *name = client_datas[id].name; float w = gfx_pretty_text_width(10, name, -1); gfx_pretty_text(whole-40-5-w, 300-40-15+t*20+2, 10, name, -1); - tee_render_info info = client_datas[id].skin_info; + tee_render_info info = client_datas[id].render_info; info.size = 18.0f; render_tee(&idlestate, &info, EMOTE_NORMAL, vec2(1,0), @@ -3117,6 +3160,8 @@ extern "C" void modc_statechange(int state, int old) menu_do_disconnected(); menu_game_active = false; } + else if(state == CLIENTSTATE_LOADING) + menu_do_connecting(); else if(state == CLIENTSTATE_CONNECTING) menu_do_connecting(); else if (state == CLIENTSTATE_ONLINE) @@ -3171,6 +3216,8 @@ extern "C" void modc_message(int msg) client_datas[cid].skin_info.color_body = vec4(1,1,1,1); client_datas[cid].skin_info.color_feet = vec4(1,1,1,1); } + + client_datas[cid].update_render_info(); } else if(msg == MSG_WEAPON_PICKUP) { diff --git a/src/game/client/gc_menu.cpp b/src/game/client/gc_menu.cpp index 9101fc937..17716bd6b 100644 --- a/src/game/client/gc_menu.cpp +++ b/src/game/client/gc_menu.cpp @@ -451,6 +451,7 @@ static void ui2_draw_checkbox(const void *id, const char *text, int checked, con ui2_draw_checkbox_common(id, text, checked?"X":"", r); } + static void ui2_draw_checkbox_number(const void *id, const char *text, int checked, const RECT *r, void *extra) { char buf[16]; @@ -466,8 +467,6 @@ int ui2_do_edit_box(void *id, const RECT *rect, char *str, int str_size, bool hi if(ui_last_active_item() == id) { - int c = inp_last_char(); - int k = inp_last_key(); int len = strlen(str); if (inside && ui_mouse_button(0)) @@ -489,35 +488,42 @@ int ui2_do_edit_box(void *id, const RECT *rect, char *str, int str_size, bool hi if (at_index > len) at_index = len; - - if (!(c >= 0 && c < 32)) + + for(int i = 0; i < inp_num_events(); i++) { - if (len < str_size - 1 && at_index < str_size - 1) + INPUTEVENT e = inp_get_event(i); + char c = e.ch; + int k = e.key; + + if (!(c >= 0 && c < 32)) { - memmove(str + at_index + 1, str + at_index, len - at_index + 1); - str[at_index] = c; - at_index++; + if (len < str_size - 1 && at_index < str_size - 1) + { + memmove(str + at_index + 1, str + at_index, len - at_index + 1); + str[at_index] = c; + at_index++; + } } - } - if (k == KEY_BACKSPACE && at_index > 0) - { - memmove(str + at_index - 1, str + at_index, len - at_index + 1); - at_index--; + if (k == KEY_BACKSPACE && at_index > 0) + { + memmove(str + at_index - 1, str + at_index, len - at_index + 1); + at_index--; + } + else if (k == KEY_DEL && at_index < len) + memmove(str + at_index, str + at_index + 1, len - at_index); + else if (k == KEY_ENTER) + ui_clear_last_active_item(); + else if (k == KEY_LEFT && at_index > 0) + at_index--; + else if (k == KEY_RIGHT && at_index < len) + at_index++; + else if (k == KEY_HOME) + at_index = 0; + else if (k == KEY_END) + at_index = len; } - else if (k == KEY_DEL && at_index < len) - memmove(str + at_index, str + at_index + 1, len - at_index); - else if (k == KEY_ENTER) - ui_clear_last_active_item(); - else if (k == KEY_LEFT && at_index > 0) - at_index--; - else if (k == KEY_RIGHT && at_index < len) - at_index++; - else if (k == KEY_HOME) - at_index = 0; - else if (k == KEY_END) - at_index = len; - + r = 1; } @@ -698,14 +704,17 @@ int ui2_do_key_reader(void *id, const RECT *rect, int key) if(ui_active_item() == id) { - int k = inp_last_key(); - if (k) + for(int i = 0; i < inp_num_events(); i++) { - if(k != KEY_ESC) - new_key = k; - - ui_set_active_item(0); - mouse_released = false; + INPUTEVENT e = inp_get_event(i); + if(e.key && e.key != KEY_ESC) + { + new_key = e.key; + ui_set_active_item(0); + mouse_released = false; + inp_clear_events(); + break; + } } } else if(ui_hot_item() == id) @@ -912,14 +921,15 @@ static void menu2_render_serverbrowser(RECT main_view) RECT server_scoreboard; //ui2_hsplit_t(&view, 20.0f, &status, &view); - ui2_hsplit_b(&view, 90.0f, &view, &filters); + ui2_hsplit_b(&view, 110.0f, &view, &filters); // split off a piece for details and scoreboard ui2_vsplit_r(&view, 200.0f, &view, &server_details); // server list ui2_hsplit_t(&view, 20.0f, &headers, &view); - ui2_hsplit_b(&view, 5.0f, &view, 0x0); + //ui2_hsplit_b(&view, 110.0f, &view, &filters); + ui2_hsplit_b(&view, 5.0f, &view, 0); ui2_hsplit_b(&view, 20.0f, &view, &status); //ui2_vsplit_r(&filters, 300.0f, &filters, &toolbox); @@ -1031,7 +1041,7 @@ static void menu2_render_serverbrowser(RECT main_view) int num = (int)(view.h/cols[0].rect.h); static int scrollbar = 0; static float scrollvalue = 0; - static int selected_index = -1; + //static int selected_index = -1; ui2_hmargin(&scroll, 5.0f, &scroll); scrollvalue = ui2_do_scrollbar_v(&scrollbar, &scroll, scrollvalue); @@ -1059,8 +1069,8 @@ static void menu2_render_serverbrowser(RECT main_view) RECT original_view = view; view.y -= scrollvalue*scrollnum*cols[0].rect.h; - //int r = -1; - int new_selected = selected_index; + int new_selected = -1; + int selected_index = -1; for (int i = 0; i < num_servers; i++) { @@ -1069,10 +1079,12 @@ static void menu2_render_serverbrowser(RECT main_view) RECT row; RECT select_hit_box; - int l = selected_index==item_index; + int selected = strcmp(item->address, config.ui_server_address) == 0; //selected_index==item_index; - if(l) + if(selected) { + selected_index = i; + // selected server, draw the players on it RECT whole; int h = (item->num_players+2)/3; @@ -1129,13 +1141,9 @@ static void menu2_render_serverbrowser(RECT main_view) select_hit_box.y = original_view.y; } - if(ui2_do_button(item, "", l, &select_hit_box, 0, 0)) + if(ui2_do_button(item, "", selected, &select_hit_box, 0, 0)) { new_selected = item_index; - dbg_msg("dbg", "addr = %s", item->address); - strncpy(config.ui_server_address, item->address, sizeof(config.ui_server_address)); - if(inp_mouse_doubleclick()) - client_connect(config.ui_server_address); } } @@ -1197,21 +1205,20 @@ static void menu2_render_serverbrowser(RECT main_view) else if(item->game_type == GAMETYPE_CTF) type = "CTF"; ui2_do_label(&button, type, 15.0f, 0); } - /* - if(s) - { - new_selected = item_index; - dbg_msg("dbg", "addr = %s", item->address); - strncpy(config.ui_server_address, item->address, sizeof(config.ui_server_address)); - }*/ } } ui2_clip_disable(); - selected_index = new_selected; + if(new_selected != -1) + { + // select the new server + SERVER_INFO *item = client_serverbrowse_sorted_get(new_selected); + strncpy(config.ui_server_address, item->address, sizeof(config.ui_server_address)); + if(inp_mouse_doubleclick()) + client_connect(config.ui_server_address); + } - SERVER_INFO *selected_server = client_serverbrowse_sorted_get(selected_index); RECT server_header; @@ -1267,7 +1274,10 @@ static void menu2_render_serverbrowser(RECT main_view) char temp[16]; - sprintf(temp, "%d%%", selected_server->progression); + if(selected_server->progression < 0) + sprintf(temp, "N/A"); + else + sprintf(temp, "%d%%", selected_server->progression); ui2_hsplit_t(&right_column, 15.0f, &row, &right_column); ui2_do_label(&row, temp, 13.0f, -1); @@ -1304,13 +1314,15 @@ static void menu2_render_serverbrowser(RECT main_view) } } - // render quick search RECT button; + RECT types; ui2_hsplit_t(&filters, 20.0f, &button, &filters); ui2_do_label(&button, "Quick search: ", 14.0f, -1); ui2_vsplit_l(&button, 95.0f, 0, &button); ui2_do_edit_box(&config.b_filter_string, &button, config.b_filter_string, sizeof(config.b_filter_string)); + ui2_vsplit_l(&filters, 180.0f, &filters, &types); + // render filters ui2_hsplit_t(&filters, 20.0f, &button, &filters); if (ui2_do_button(&config.b_filter_empty, "Has people playing", config.b_filter_empty, &button, ui2_draw_checkbox, 0)) @@ -1321,9 +1333,36 @@ static void menu2_render_serverbrowser(RECT main_view) config.b_filter_full ^= 1; ui2_hsplit_t(&filters, 20.0f, &button, &filters); - if (ui2_do_button(&config.b_filter_pw, "Is not password protected", config.b_filter_pw, &button, ui2_draw_checkbox, 0)) + if (ui2_do_button(&config.b_filter_pw, "No password", config.b_filter_pw, &button, ui2_draw_checkbox, 0)) config.b_filter_pw ^= 1; + ui2_hsplit_t(&filters, 2.0f, &button, &filters); // ping + ui2_hsplit_t(&filters, 20.0f, &button, &filters); + { + RECT editbox; + ui2_vsplit_l(&button, 40.0f, &editbox, &button); + ui2_vsplit_l(&button, 5.0f, &button, &button); + + char buf[8]; + sprintf(buf, "%d", config.b_filter_ping); + ui2_do_edit_box(&config.b_filter_ping, &editbox, buf, sizeof(buf)); + config.b_filter_ping = atoi(buf); + + ui2_do_label(&button, "Maximum ping", 14.0f, -1); + } + + ui2_hsplit_t(&types, 20.0f, &button, &types); + if (ui2_do_button(&config.b_filter_gametype, "DM", config.b_filter_gametype&(1<friendly_team != -1 && players[c].team == eval->friendly_team) - continue; + scoremod = 0.5f; float d = distance(pos, players[c].pos); if(d == 0) @@ -734,7 +735,7 @@ bool player::is_grounded() int player::handle_ninja() { - vec2 direction = normalize(vec2(input.target_x, input.target_y)); + vec2 direction = normalize(vec2(latest_input.target_x, latest_input.target_y)); if ((server_tick() - ninja_activationtick) > (data->weapons[WEAPON_NINJA].duration * server_tickspeed() / 1000)) { @@ -746,7 +747,7 @@ int player::handle_ninja() } // Check if it should activate - if (count_input(previnput.fire, input.fire).presses && (server_tick() > currentcooldown)) + if (count_input(latest_previnput.fire, latest_input.fire).presses && (server_tick() > currentcooldown)) { // ok then, activate ninja attack_tick = server_tick(); @@ -958,7 +959,7 @@ int player::handle_bomb() int player::handle_weapons() { - vec2 direction = normalize(vec2(input.target_x, input.target_y)); + vec2 direction = normalize(vec2(latest_input.target_x, latest_input.target_y)); if(config.dbg_stress) { @@ -986,8 +987,8 @@ int player::handle_weapons() } // select weapon - int next = count_input(previnput.next_weapon, input.next_weapon).presses; - int prev = count_input(previnput.prev_weapon, input.prev_weapon).presses; + int next = count_input(latest_previnput.next_weapon, latest_input.next_weapon).presses; + int prev = count_input(latest_previnput.prev_weapon, latest_input.prev_weapon).presses; if(next < 128) // make sure we only try sane stuff { @@ -1009,7 +1010,7 @@ int player::handle_weapons() } } - if(input.wanted_weapon) // direct weapon selection + if(latest_input.wanted_weapon) // direct weapon selection wanted_weapon = input.wanted_weapon-1; if(wanted_weapon < 0 || wanted_weapon >= NUM_WEAPONS) @@ -1041,7 +1042,7 @@ int player::handle_weapons() if(active_weapon == WEAPON_ROCKET || active_weapon == WEAPON_SHOTGUN) fullauto = true; - if(count_input(previnput.fire, input.fire).presses || ((fullauto && input.fire&1) && weapons[active_weapon].ammo)) + if(count_input(latest_previnput.fire, latest_input.fire).presses || ((fullauto && latest_input.fire&1) && weapons[active_weapon].ammo)) { // fire! if(weapons[active_weapon].ammo) @@ -1211,12 +1212,26 @@ int player::handle_weapons() void player::tick() { server_setclientscore(client_id, score); + + // grab latest input + { + int size = 0; + int *input = server_latestinput(client_id, &size); + if(input) + { + mem_copy(&latest_previnput, &latest_input, sizeof(latest_input)); + mem_copy(&latest_input, input, sizeof(latest_input)); + } + } // check if we have enough input // this is to prevent initial weird clicks if(num_inputs < 2) + { + latest_previnput = latest_input; previnput = input; - + } + // do latency stuff { CLIENT_INFO info; @@ -1254,7 +1269,7 @@ void player::tick() // TODO: rework the input to be more robust if(dead) { - if(server_tick()-die_tick >= server_tickspeed()/2 && count_input(previnput.fire, input.fire).presses) + if(server_tick()-die_tick >= server_tickspeed()/2 && count_input(latest_previnput.fire, latest_input.fire).presses) die_tick = -1; if(server_tick()-die_tick >= server_tickspeed()*5) // auto respawn after 3 sec respawn(); @@ -1466,7 +1481,7 @@ void player::snap(int snaping_client) info->local = 1; } - if(health > 0 && distance(players[snaping_client].pos, pos) < 1000.0f) + if(health > 0 && team >= 0 && distance(players[snaping_client].pos, pos) < 1000.0f) { obj_player_character *character = (obj_player_character *)snap_new_item(OBJTYPE_PLAYER_CHARACTER, client_id, sizeof(obj_player_character));