diff options
| -rw-r--r-- | src/engine/client/ec_client.c | 32 | ||||
| -rw-r--r-- | src/engine/e_if_mods.h | 16 | ||||
| -rw-r--r-- | src/engine/e_if_server.h | 1 | ||||
| -rw-r--r-- | src/engine/e_network.c | 5 | ||||
| -rw-r--r-- | src/engine/e_network.h | 1 | ||||
| -rw-r--r-- | src/engine/e_protocol.h | 2 | ||||
| -rw-r--r-- | src/engine/e_system.c | 22 | ||||
| -rw-r--r-- | src/engine/e_system.h | 1 | ||||
| -rw-r--r-- | src/engine/server/es_server.c | 19 | ||||
| -rw-r--r-- | src/game/client/gc_client.cpp | 2 | ||||
| -rw-r--r-- | src/game/client/gc_client.h | 14 | ||||
| -rw-r--r-- | src/game/client/gc_console.cpp | 4 | ||||
| -rw-r--r-- | src/game/client/gc_hooks.cpp | 28 | ||||
| -rw-r--r-- | src/game/client/gc_render.cpp | 12 | ||||
| -rw-r--r-- | src/game/client/gc_render_obj.cpp | 7 | ||||
| -rw-r--r-- | src/game/g_protocol.h | 2 | ||||
| -rw-r--r-- | src/game/g_version.h | 4 | ||||
| -rw-r--r-- | src/game/server/gs_common.h | 11 | ||||
| -rw-r--r-- | src/game/server/gs_server.cpp | 186 |
19 files changed, 330 insertions, 39 deletions
diff --git a/src/engine/client/ec_client.c b/src/engine/client/ec_client.c index 627791bb..dfc16ec3 100644 --- a/src/engine/client/ec_client.c +++ b/src/engine/client/ec_client.c @@ -60,6 +60,9 @@ static int snapcrcerrors = 0; static int ack_game_tick = -1; static int current_recv_tick = 0; +/* pinging */ +static int64 ping_start_time = 0; + /* current time */ static int current_tick = 0; static float intratick = 0; @@ -687,6 +690,14 @@ static void client_process_packet(NETPACKET *packet) client_disconnect_with_reason(error); } } + else if(msg == NETMSG_PING) + { + msg_pack_start_system(NETMSG_PING_REPLY, 0); + msg_pack_end(); + client_send_msg(); + } + else if(msg == NETMSG_PING_REPLY) + dbg_msg("client/network", "latency %.2f", (time_get() - ping_start_time)*1000 / (float)time_freq()); else if(msg == NETMSG_SNAP || msg == NETMSG_SNAPSINGLE || msg == NETMSG_SNAPEMPTY) { /*dbg_msg("client/network", "got snapshot"); */ @@ -1209,28 +1220,37 @@ static void client_run() snd_shutdown(); } -static void connect_command(void *result, void *user_data) +static void con_connect(void *result, void *user_data) { const char *address; console_result_string(result, 1, &address); client_connect(address); } -static void disconnect_command(void *result, void *user_data) +static void con_disconnect(void *result, void *user_data) { client_disconnect(); } -static void quit_command(void *result, void *user_data) +static void con_quit(void *result, void *user_data) { client_quit(); } +static void con_ping(void *result, void *user_data) +{ + msg_pack_start_system(NETMSG_PING, 0); + msg_pack_end(); + client_send_msg(); + ping_start_time = time_get(); +} + static void client_register_commands() { - MACRO_REGISTER_COMMAND("quit", "", quit_command, 0x0); - MACRO_REGISTER_COMMAND("connect", "s", connect_command, 0x0); - MACRO_REGISTER_COMMAND("disconnect", "", disconnect_command, 0x0); + MACRO_REGISTER_COMMAND("quit", "", con_quit, 0x0); + MACRO_REGISTER_COMMAND("connect", "s", con_connect, 0x0); + MACRO_REGISTER_COMMAND("disconnect", "", con_disconnect, 0x0); + MACRO_REGISTER_COMMAND("ping", "", con_ping, 0x0); } int editor_main(int argc, char **argv); diff --git a/src/engine/e_if_mods.h b/src/engine/e_if_mods.h index eff909f3..08d0ec37 100644 --- a/src/engine/e_if_mods.h +++ b/src/engine/e_if_mods.h @@ -51,7 +51,7 @@ void mods_client_enter(int cid); void mods_client_drop(int cid); /* - Function: mods_client_input + Function: mods_client_direct_input Called when the server recives new input from a client. Arguments: @@ -59,7 +59,19 @@ void mods_client_drop(int cid); input - Pointer to the input data. size - Size of the data. (NOT IMPLEMENTED YET) */ -void mods_client_input(int cid, void *input); +void mods_client_direct_input(int cid, void *input); + +/* + Function: mods_client_predicted_input + Called when the server applys the predicted input on the client. + + Arguments: + cid - Client ID. Is 0 - MAX_CLIENTS. + input - Pointer to the input data. + size - Size of the data. (NOT IMPLEMENTED YET) +*/ +void mods_client_predicted_input(int cid, void *input); + /* Function: mods_tick diff --git a/src/engine/e_if_server.h b/src/engine/e_if_server.h index c9572b76..c9775d90 100644 --- a/src/engine/e_if_server.h +++ b/src/engine/e_if_server.h @@ -36,6 +36,7 @@ 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 */ + /* Function: server_latestinput TODO diff --git a/src/engine/e_network.c b/src/engine/e_network.c index 689e45ab..3e242618 100644 --- a/src/engine/e_network.c +++ b/src/engine/e_network.c @@ -799,6 +799,11 @@ void netserver_stats(NETSERVER *s, NETSTATS *stats) } } +NETSOCKET netserver_socket(NETSERVER *s) +{ + return s->socket; +} + int netserver_client_addr(NETSERVER *s, int client_id, NETADDR4 *addr) { *addr = s->slots[client_id].conn.peeraddr; diff --git a/src/engine/e_network.h b/src/engine/e_network.h index 96a49692..29843849 100644 --- a/src/engine/e_network.h +++ b/src/engine/e_network.h @@ -46,6 +46,7 @@ int netserver_recv(NETSERVER *s, NETPACKET *packet); int netserver_send(NETSERVER *s, NETPACKET *packet); int netserver_close(NETSERVER *s); int netserver_update(NETSERVER *s); +NETSOCKET netserver_socket(NETSERVER *s); int netserver_drop(NETSERVER *s, int client_id, const char *reason); int netserver_client_addr(NETSERVER *s, int client_id, NETADDR4 *addr); int netserver_max_clients(NETSERVER *s); diff --git a/src/engine/e_protocol.h b/src/engine/e_protocol.h index 0e8a63f4..65d76350 100644 --- a/src/engine/e_protocol.h +++ b/src/engine/e_protocol.h @@ -46,6 +46,8 @@ enum NETMSG_CMD, /* sent by both */ + NETMSG_PING, + NETMSG_PING_REPLY, NETMSG_ERROR }; diff --git a/src/engine/e_system.c b/src/engine/e_system.c index 1472b3d6..ab7323f9 100644 --- a/src/engine/e_system.c +++ b/src/engine/e_system.c @@ -733,6 +733,28 @@ void swap_endian(void *data, unsigned elem_size, unsigned num) } } +int net_socket_read_wait(NETSOCKET sock, int time) +{ +#if defined(CONF_FAMILY_WINDOWS) + #error Not implemented +#else + struct timeval tv; + fd_set readfds; + + tv.tv_sec = 0; + tv.tv_usec = 1000*time; + + FD_ZERO(&readfds); + FD_SET(sock, &readfds); + + /* don't care about writefds and exceptfds */ + select(sock+1, &readfds, NULL, NULL, &tv); + if(FD_ISSET(sock, &readfds)) + return 1; + return 0; +#endif +} + #if defined(__cplusplus) } #endif diff --git a/src/engine/e_system.h b/src/engine/e_system.h index 69fa5c63..f271d71a 100644 --- a/src/engine/e_system.h +++ b/src/engine/e_system.h @@ -512,6 +512,7 @@ int fs_listdir(const char *dir, fs_listdir_callback cb, void *user); int fs_storage_path(const char *appname, char *path, int max); int fs_makedir(const char *path); int net_addr4_cmp(const NETADDR4 *a, const NETADDR4 *b); +int net_socket_read_wait(NETSOCKET sock, int time); void mem_debug_dump(); int mem_allocated(); diff --git a/src/engine/server/es_server.c b/src/engine/server/es_server.c index 8d805e42..9c2aac41 100644 --- a/src/engine/server/es_server.c +++ b/src/engine/server/es_server.c @@ -642,6 +642,9 @@ static void server_process_client_packet(NETPACKET *packet) clients[cid].current_input++; clients[cid].current_input %= 200; + + /* call the mod with the fresh input data */ + mods_client_direct_input(cid, clients[cid].latestinput.data); } else if(msg == NETMSG_CMD) { @@ -653,6 +656,12 @@ static void server_process_client_packet(NETPACKET *packet) console_execute(cmd); } } + else if(msg == NETMSG_PING) + { + msg_pack_start_system(NETMSG_PING_REPLY, 0); + msg_pack_end(); + server_send_msg(cid); + } else { dbg_msg("server", "strange message cid=%d msg=%d data_size=%d", cid, msg, packet->data_size); @@ -948,7 +957,7 @@ static int server_run() { if(clients[c].inputs[i].game_tick == server_tick()) { - mods_client_input(c, clients[c].inputs[i].data); + mods_client_predicted_input(c, clients[c].inputs[i].data); break; } } @@ -986,7 +995,7 @@ static int server_run() lastheartbeat = t+time_per_heartbeat; } } - + { static PERFORMACE_INFO scope = {"net", 0}; perf_start(&scope); @@ -1025,6 +1034,10 @@ static int server_run() config.sv_status = 0; } + /* wait for incomming data */ + net_socket_read_wait(netserver_socket(net), 5); + + /* if(config.dbg_hitch) { thread_sleep(config.dbg_hitch); @@ -1032,7 +1045,7 @@ static int server_run() } else thread_sleep(1); - + */ } } diff --git a/src/game/client/gc_client.cpp b/src/game/client/gc_client.cpp index 7032637f..d891ec84 100644 --- a/src/game/client/gc_client.cpp +++ b/src/game/client/gc_client.cpp @@ -25,7 +25,7 @@ extern "C" { #include "gc_console.h" struct data_container *data = 0; -static int64 debug_firedelay = 0; +int64 debug_firedelay = 0; player_input input_data = {0}; int input_target_lock = 0; diff --git a/src/game/client/gc_client.h b/src/game/client/gc_client.h index 63c74d77..857a9088 100644 --- a/src/game/client/gc_client.h +++ b/src/game/client/gc_client.h @@ -36,6 +36,20 @@ extern int picked_up_weapon; extern player_input input_data; extern int input_target_lock; +// debug +extern int64 debug_firedelay; + +// extra projs +enum +{ + MAX_EXTRA_PROJECTILES=32, +}; + +extern obj_projectile extraproj_projectiles[MAX_EXTRA_PROJECTILES]; +extern int extraproj_num; + +void extraproj_reset(); + // chat enum { diff --git a/src/game/client/gc_console.cpp b/src/game/client/gc_console.cpp index c04477a1..1f596e79 100644 --- a/src/game/client/gc_console.cpp +++ b/src/game/client/gc_console.cpp @@ -265,14 +265,14 @@ void console_render() gfx_texture_set(data->images[IMAGE_CONSOLE_BG].id); gfx_quads_begin(); - gfx_setcolor(0.2f, 0.2f, 0.2f,0.8f); + gfx_setcolor(0.2f, 0.2f, 0.2f,0.9f); gfx_quads_setsubset(0,-console_height*0.075f,screen.w*0.075f*0.5f,0); gfx_quads_drawTL(0,0,screen.w,console_height); gfx_quads_end(); gfx_texture_set(data->images[IMAGE_CONSOLE_BAR].id); gfx_quads_begin(); - gfx_setcolor(1.0f, 1.0f, 1.0f, 0.8f); + gfx_setcolor(1.0f, 1.0f, 1.0f, 0.9f); gfx_quads_setsubset(0,0.1f,screen.w*0.015f,1-0.1f); gfx_quads_drawTL(0,console_height-10.0f,screen.w,10.0f); gfx_quads_end(); diff --git a/src/game/client/gc_hooks.cpp b/src/game/client/gc_hooks.cpp index f04af5cb..4ab5cf6a 100644 --- a/src/game/client/gc_hooks.cpp +++ b/src/game/client/gc_hooks.cpp @@ -394,6 +394,15 @@ extern "C" void modc_statechange(int state, int old) } } + +obj_projectile extraproj_projectiles[MAX_EXTRA_PROJECTILES]; +int extraproj_num; + +void extraproj_reset() +{ + extraproj_num = 0; +} + extern "C" void modc_message(int msg) { if(msg == MSG_CHAT) @@ -409,6 +418,23 @@ extern "C" void modc_message(int msg) else snd_play(CHN_GUI, data->sounds[SOUND_CHAT_SERVER].sounds[0].id, 0); } + else if(msg == MSG_EXTRA_PROJECTILE) + { + int num = msg_unpack_int(); + + for(int k = 0; k < num; k++) + { + obj_projectile proj; + for(unsigned i = 0; i < sizeof(obj_projectile)/sizeof(int); i++) + ((int *)&proj)[i] = msg_unpack_int(); + + if(extraproj_num != MAX_EXTRA_PROJECTILES) + { + extraproj_projectiles[extraproj_num] = proj; + extraproj_num++; + } + } + } else if(msg == MSG_SETINFO) { int cid = msg_unpack_int(); @@ -487,8 +513,8 @@ extern "C" void modc_connected() //tilemap_init(); chat_reset(); - particle_reset(); + extraproj_reset(); clear_object_pointers(); last_new_predicted_tick = -1; diff --git a/src/game/client/gc_render.cpp b/src/game/client/gc_render.cpp index f201a87c..1d276ec3 100644 --- a/src/game/client/gc_render.cpp +++ b/src/game/client/gc_render.cpp @@ -370,6 +370,18 @@ static void render_items() render_flag((const obj_flag *)prev, (const obj_flag *)data); } } + + // render extra projectiles + for(int i = 0; i < extraproj_num; i++) + { + if(extraproj_projectiles[i].start_tick < client_tick()) + { + extraproj_projectiles[i] = extraproj_projectiles[extraproj_num-1]; + extraproj_num--; + } + else + render_projectile(&extraproj_projectiles[i], 0); + } } diff --git a/src/game/client/gc_render_obj.cpp b/src/game/client/gc_render_obj.cpp index 39705444..cedfc129 100644 --- a/src/game/client/gc_render_obj.cpp +++ b/src/game/client/gc_render_obj.cpp @@ -13,13 +13,12 @@ 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); + int64 delay = time_get()-debug_firedelay; + dbg_msg("game", "firedelay=%.2f ms", delay/(float)time_freq()*1000.0f); debug_firedelay = 0; - }*/ + } gfx_texture_set(data->images[IMAGE_GAME].id); gfx_quads_begin(); diff --git a/src/game/g_protocol.h b/src/game/g_protocol.h index ada685bb..f4878729 100644 --- a/src/game/g_protocol.h +++ b/src/game/g_protocol.h @@ -44,6 +44,8 @@ enum MSG_SOUND_GLOBAL, MSG_TUNE_PARAMS, MSG_KILL, + MSG_EXTRA_PROJECTILE, // server -> client + }; enum diff --git a/src/game/g_version.h b/src/game/g_version.h index d77410dd..c10af7af 100644 --- a/src/game/g_version.h +++ b/src/game/g_version.h @@ -1,4 +1,4 @@ /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ #include "generated/nethash.c" -#define TEEWARS_VERSION "0.3.3" -#define TEEWARS_NETVERSION "0.3 " TEEWARS_NETVERSION_HASH +#define TEEWARS_VERSION "0.4.0-dev" +#define TEEWARS_NETVERSION "0.4 " TEEWARS_NETVERSION_HASH diff --git a/src/game/server/gs_common.h b/src/game/server/gs_common.h index 838b192f..194751b2 100644 --- a/src/game/server/gs_common.h +++ b/src/game/server/gs_common.h @@ -186,11 +186,6 @@ public: enum { PROJECTILE_FLAGS_EXPLODE = 1 << 0, - - WEAPON_PROJECTILETYPE_GUN = 0, - WEAPON_PROJECTILETYPE_ROCKET = 1, - WEAPON_PROJECTILETYPE_SHOTGUN = 2, - WEAPON_PROJECTILETYPE_SNIPER = 6, }; vec2 vel; @@ -208,6 +203,9 @@ public: projectile(int type, int owner, vec2 pos, vec2 vel, int span, entity* powner, int damage, int flags, float force, int sound_impact, int weapon); + + void fill_info(obj_projectile *proj); + virtual void reset(); virtual void tick(); virtual void snap(int snapping_client); @@ -333,6 +331,9 @@ public: int handle_weapons(); int handle_ninja(); + + void on_direct_input(player_input *input); + void fire_weapon(); virtual void tick(); virtual void tick_defered(); diff --git a/src/game/server/gs_server.cpp b/src/game/server/gs_server.cpp index b9f78996..bcab00e5 100644 --- a/src/game/server/gs_server.cpp +++ b/src/game/server/gs_server.cpp @@ -437,6 +437,16 @@ void projectile::tick() } } +void projectile::fill_info(obj_projectile *proj) +{ + proj->x = (int)pos.x; + proj->y = (int)pos.y; + proj->vx = (int)vel.x; + proj->vy = (int)vel.y; + proj->start_tick = start_tick; + proj->type = type; +} + void projectile::snap(int snapping_client) { float ct = (server_tick()-start_tick)/(float)server_tickspeed(); @@ -446,12 +456,7 @@ void projectile::snap(int snapping_client) return; obj_projectile *proj = (obj_projectile *)snap_new_item(OBJTYPE_PROJECTILE, id, sizeof(obj_projectile)); - proj->x = (int)pos.x; - proj->y = (int)pos.y; - proj->vx = (int)vel.x; - proj->vy = (int)vel.y; - proj->start_tick = start_tick; - proj->type = type; + fill_info(proj); } @@ -940,6 +945,138 @@ int player::handle_ninja() return 0; } +void player::fire_weapon() +{ + if(reload_timer != 0) + return; + + vec2 direction = normalize(vec2(latest_input.target_x, latest_input.target_y)); + + bool fullauto = false; + if(active_weapon == WEAPON_GRENADE || active_weapon == WEAPON_SHOTGUN) + fullauto = true; + + //if(count_input(latest_previnput.fire, latest_input.fire).presses) || ((fullauto && latest_input.fire&1) && weapons[active_weapon].ammo)) + if(!count_input(latest_previnput.fire, latest_input.fire).presses) + return; + + // check for ammo + if(!weapons[active_weapon].ammo) + { + create_sound(pos, SOUND_WEAPON_NOAMMO); + return; + } + + + switch(active_weapon) + { + case WEAPON_HAMMER: + { + // reset objects hit + numobjectshit = 0; + create_sound(pos, SOUND_HAMMER_FIRE); + break; + } + + case WEAPON_GUN: + { + projectile *proj = new projectile(WEAPON_GUN, + client_id, + pos+vec2(0,0), + direction*tuning.gun_speed, + server_tickspeed(), + this, + 1, 0, 0, -1, WEAPON_GUN); + + // pack the projectile and send it to the client directly + obj_projectile p; + proj->fill_info(&p); + + msg_pack_start(MSG_EXTRA_PROJECTILE, 0); + msg_pack_int(1); + for(unsigned i = 0; i < sizeof(obj_projectile)/sizeof(int); i++) + msg_pack_int(((int *)&p)[i]); + msg_pack_end(); + server_send_msg(client_id); + + create_sound(pos, SOUND_GUN_FIRE); + break; + } + case WEAPON_GRENADE: + { + projectile *proj = new projectile(WEAPON_GRENADE, + client_id, + pos+vec2(0,0), + direction*tuning.grenade_speed, + 100, + this, + 1, projectile::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_GRENADE); + + // pack the projectile and send it to the client directly + obj_projectile p; + proj->fill_info(&p); + + msg_pack_start(MSG_EXTRA_PROJECTILE, 0); + msg_pack_int(1); + for(unsigned i = 0; i < sizeof(obj_projectile)/sizeof(int); i++) + msg_pack_int(((int *)&p)[i]); + msg_pack_end(); + server_send_msg(client_id); + + create_sound(pos, SOUND_GRENADE_FIRE); + break; + } + case WEAPON_SHOTGUN: + { + int shotspread = 2; + + msg_pack_start(MSG_EXTRA_PROJECTILE, 0); + msg_pack_int(shotspread*2+1); + + for(int i = -shotspread; i <= shotspread; i++) + { + float spreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f}; + float a = get_angle(direction); + float v = 1.0f-fabs(i/(float)shotspread); + a += spreading[i+2]; + float speed = mix((float)tuning.shotgun_speed_wide, (float)tuning.shotgun_speed_center, v); + projectile *proj = new projectile(WEAPON_SHOTGUN, + client_id, + pos+vec2(0,0), + vec2(cosf(a), sinf(a))*speed, + (int)(server_tickspeed()*0.25f), + this, + 1, 0, 0, -1, WEAPON_SHOTGUN); + + // pack the projectile and send it to the client directly + obj_projectile p; + proj->fill_info(&p); + + for(unsigned i = 0; i < sizeof(obj_projectile)/sizeof(int); i++) + msg_pack_int(((int *)&p)[i]); + } + + msg_pack_end(); + server_send_msg(client_id); + + create_sound(pos, SOUND_SHOTGUN_FIRE); + break; + } + + case WEAPON_RIFLE: + { + new laser(pos, direction, tuning.laser_reach, this); + create_sound(pos, SOUND_RIFLE_FIRE); + break; + } + + } + + weapons[active_weapon].ammo--; + attack_tick = server_tick(); + reload_timer = data->weapons[active_weapon].firedelay * server_tickspeed() / 1000; +} + int player::handle_weapons() { vec2 direction = normalize(vec2(latest_input.target_x, latest_input.target_y)); @@ -1011,8 +1148,10 @@ int player::handle_weapons() } } - if(reload_timer == 0) - { + //if(reload_timer == 0) + fire_weapon(); + //} + /* bool fullauto = false; if(active_weapon == WEAPON_GRENADE || active_weapon == WEAPON_SHOTGUN) fullauto = true; @@ -1096,7 +1235,7 @@ int player::handle_weapons() create_sound(pos, SOUND_WEAPON_NOAMMO); } } - } + }*/ // Update weapons if (active_weapon == WEAPON_HAMMER && reload_timer > 0) @@ -1178,11 +1317,19 @@ int player::handle_weapons() return 0; } +void player::on_direct_input(player_input *new_input) +{ + mem_copy(&latest_previnput, &latest_input, sizeof(latest_input)); + mem_copy(&latest_input, new_input, sizeof(latest_input)); + fire_weapon(); +} + void player::tick() { server_setclientscore(client_id, score); // grab latest input + /* { int size = 0; int *input = server_latestinput(client_id, &size); @@ -1191,7 +1338,7 @@ void player::tick() 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 @@ -1434,7 +1581,7 @@ void player::snap(int snaping_client) { obj_player_info *info = (obj_player_info *)snap_new_item(OBJTYPE_PLAYER_INFO, client_id, sizeof(obj_player_info)); - info->latency = latency_avg; + info->latency = latency_min; info->latency_flux = latency_max-latency_min; info->local = 0; info->clientid = client_id; @@ -1892,7 +2039,21 @@ void mods_snap(int client_id) events.snap(client_id); } -void mods_client_input(int client_id, void *input) +void mods_client_direct_input(int client_id, void *input) +{ + if(!world->paused) + players[client_id].on_direct_input((player_input *)input); + + /* + if(i->fire) + { + msg_pack_start(MSG_EXTRA_PROJECTILE, 0); + msg_pack_end(); + server_send_msg(client_id); + }*/ +} + +void mods_client_predicted_input(int client_id, void *input) { if(!world->paused) { @@ -1905,7 +2066,6 @@ void mods_client_input(int client_id, void *input) if(players[client_id].input.target_x == 0 && players[client_id].input.target_y == 0) players[client_id].input.target_y = -1; - } } |