diff options
Diffstat (limited to 'src/engine')
| -rw-r--r-- | src/engine/client/client.c | 200 | ||||
| -rw-r--r-- | src/engine/compression.c | 22 | ||||
| -rw-r--r-- | src/engine/config.c | 15 | ||||
| -rw-r--r-- | src/engine/datafile.c | 12 | ||||
| -rw-r--r-- | src/engine/datafile.h | 2 | ||||
| -rw-r--r-- | src/engine/interface.h | 10 | ||||
| -rw-r--r-- | src/engine/server/server.c | 216 | ||||
| -rw-r--r-- | src/engine/snapshot.c | 4 |
8 files changed, 314 insertions, 167 deletions
diff --git a/src/engine/client/client.c b/src/engine/client/client.c index 72f73741..d07c3aca 100644 --- a/src/engine/client/client.c +++ b/src/engine/client/client.c @@ -18,12 +18,26 @@ #include <mastersrv/mastersrv.h> +/* + Server Time + Client Mirror Time + Client Predicted Time + + Snapshot Latency + Downstream latency + + Prediction Latency + Upstream latency +*/ static int info_request_begin; static int info_request_end; static int snapshot_part; static int64 local_start_time; static int64 game_start_time; -static float latency = 0; + +static float snapshot_latency = 0; +static float prediction_latency = 0; + static int extra_polating = 0; static int debug_font; static float frametime = 0.0001f; @@ -34,9 +48,25 @@ static int window_must_refocus = 0; static int snaploss = 0; static int snapcrcerrors = 0; +static int current_recv_tick = 0; + +// current time static int current_tick = 0; static float intratick = 0; +// predicted time +static int current_predtick = 0; +static float intrapredtick = 0; + +static struct // TODO: handle input better +{ + int data[MAX_INPUT_SIZE]; // the input data + int tick; // the tick that the input is for + float latency; // prediction latency when we sent this input +} inputs[200]; +static int current_input = 0; + + // --- input snapping --- static int input_data[MAX_INPUT_SIZE] = {0}; static int input_data_size; @@ -100,32 +130,13 @@ static void snap_init() } // ------ time functions ------ -float client_intratick() -{ - return intratick; -} - -int client_tick() -{ - return current_tick; -} - -int client_tickspeed() -{ - return SERVER_TICK_SPEED; -} - -float client_frametime() -{ - return frametime; -} - -float client_localtime() -{ - return (time_get()-local_start_time)/(float)(time_freq()); -} - -int menu_loop(); // TODO: what is this? +float client_intratick() { return intratick; } +float client_intrapredtick() { return intrapredtick; } +int client_tick() { return current_tick; } +int client_predtick() { return current_predtick; } +int client_tickspeed() { return SERVER_TICK_SPEED; } +float client_frametime() { return frametime; } +float client_localtime() { return (time_get()-local_start_time)/(float)(time_freq()); } // ----- send functions ----- int client_send_msg() @@ -176,19 +187,46 @@ static void client_send_error(const char *error) //send_packet(&p); //send_packet(&p); */ -} +} static void client_send_input() { msg_pack_start_system(NETMSG_INPUT, 0); + msg_pack_int(current_predtick); msg_pack_int(input_data_size); + + inputs[current_input].tick = current_predtick; + inputs[current_input].latency = prediction_latency; + int i; for(i = 0; i < input_data_size/4; i++) + { + inputs[current_input].data[i] = input_data[i]; msg_pack_int(input_data[i]); + } + + current_input++; + current_input%=200; + msg_pack_end(); client_send_msg(); } +/* TODO: OPT: do this alot smarter! */ +int *client_get_input(int tick) +{ + int i; + int best = -1; + for(i = 0; i < 200; i++) + { + if(inputs[i].tick <= tick && (best == -1 || inputs[best].tick < inputs[i].tick)) + best = i; + } + + if(best != -1) + return (int *)inputs[best].data; + return 0; +} // ------ server browse ---- static struct @@ -337,7 +375,17 @@ void client_connect(const char *server_address_str) netclient_connect(net, &server_address); client_set_state(CLIENTSTATE_CONNECTING); - current_tick = 0; + + current_recv_tick = 0; + + // reset input + int i; + for(i = 0; i < 200; i++) + inputs[i].tick = -1; + current_input = 0; + + snapshot_latency = 0; + prediction_latency = 0; } void client_disconnect() @@ -375,11 +423,12 @@ static void client_debug_render() static float frametime_avg = 0; frametime_avg = frametime_avg*0.9f + frametime*0.1f; char buffer[512]; - sprintf(buffer, "send: %6d recv: %6d snaploss: %d latency: %4.0f %c mem %dk gfxmem: %dk fps: %3d", + sprintf(buffer, "send: %6d recv: %6d snaploss: %d snaplatency: %4.2f %c predlatency: %4.2f mem %dk gfxmem: %dk fps: %3d", (current.send_bytes-prev.send_bytes)*10, (current.recv_bytes-prev.recv_bytes)*10, snaploss, - latency*1000.0f, extra_polating?'E':' ', + snapshot_latency*1000.0f, extra_polating?'E':' ', + prediction_latency*1000.0f, mem_allocated()/1024, gfx_memory_usage()/1024, (int)(1.0f/frametime_avg)); @@ -526,10 +575,12 @@ static void client_process_packet(NETPACKET *packet) //dbg_msg("client/network", "got snapshot"); int game_tick = msg_unpack_int(); int delta_tick = game_tick-msg_unpack_int(); + int input_predtick = msg_unpack_int(); + int time_left = msg_unpack_int(); int num_parts = 1; int part = 0; int part_size = 0; - int crc; + int crc = 0; if(msg != NETMSG_SNAPEMPTY) { @@ -537,7 +588,25 @@ static void client_process_packet(NETPACKET *packet) part_size = msg_unpack_int(); } - if(snapshot_part == part && game_tick > current_tick) + /* TODO: adjust our prediction time */ + if(time_left) + { + int k; + for(k = 0; k < 200; k++) /* TODO: do this better */ + { + if(inputs[k].tick == input_predtick) + { + float wanted_latency = inputs[k].latency - time_left/1000.0f + 0.01f; + prediction_latency = prediction_latency*0.95f + wanted_latency*0.05f; + //dbg_msg("DEBUG", "predlatency=%f", prediction_latency); + break; + } + } + } + + //dbg_msg("DEBUG", "new predlatency=%f", prediction_latency); + + if(snapshot_part == part && game_tick > current_recv_tick) { // TODO: clean this up abit const char *d = (const char *)msg_unpack_raw(part_size); @@ -568,6 +637,7 @@ static void client_process_packet(NETPACKET *packet) dbg_msg("client", "error, couldn't find the delta snapshot"); // ack snapshot + // TODO: combine this with the input message msg_pack_start_system(NETMSG_SNAPACK, 0); msg_pack_int(-1); msg_pack_end(); @@ -637,9 +707,9 @@ static void client_process_packet(NETPACKET *packet) recived_snapshots++; - if(current_tick > 0) - snaploss += game_tick-current_tick-1; - current_tick = game_tick; + if(current_recv_tick > 0) + snaploss += game_tick-current_recv_tick-1; + current_recv_tick = game_tick; // we got two snapshots until we see us self as connected if(recived_snapshots == 2) @@ -661,7 +731,7 @@ static void client_process_packet(NETPACKET *packet) int64 wanted = game_start_time+(game_tick*time_freq())/50; float current_latency = (now-wanted)/(float)time_freq(); - latency = latency*0.95f+current_latency*0.05f; + snapshot_latency = snapshot_latency*0.95f+current_latency*0.05f; // ack snapshot msg_pack_start_system(NETMSG_SNAPACK, 0); @@ -693,7 +763,6 @@ static void client_pump_network() // check for errors if(client_state() != CLIENTSTATE_OFFLINE && netclient_state(net) == NETSTATE_OFFLINE) { - // TODO: add message to the user there client_set_state(CLIENTSTATE_OFFLINE); dbg_msg("client", "offline error='%s'", netclient_error_string(net)); } @@ -754,9 +823,6 @@ static void client_run(const char *direct_connect_server) if(direct_connect_server) client_connect(direct_connect_server); - int64 game_starttime = time_get(); - int64 last_input = game_starttime; - int64 reporttime = time_get(); int64 reportinterval = time_freq()*1; int frames = 0; @@ -771,14 +837,15 @@ static void client_run(const char *direct_connect_server) // switch snapshot if(recived_snapshots >= 3) { + int repredict = 0; int64 now = time_get(); while(1) { SNAPSTORAGE_HOLDER *cur = snapshots[SNAP_CURRENT]; int64 tickstart = game_start_time + (cur->tick+1)*time_freq()/50; int64 t = tickstart; - if(latency > 0) - t += (int64)(time_freq()*(latency*1.1f)); + if(snapshot_latency > 0) + t += (int64)(time_freq()*(snapshot_latency*1.1f)); if(t < now) { @@ -787,8 +854,15 @@ static void client_run(const char *direct_connect_server) { snapshots[SNAP_PREV] = snapshots[SNAP_CURRENT]; snapshots[SNAP_CURRENT] = next; + + // set tick + current_tick = snapshots[SNAP_CURRENT]->tick; + if(snapshots[SNAP_CURRENT] && snapshots[SNAP_PREV]) + { modc_newsnapshot(); + repredict = 1; + } } else { @@ -806,31 +880,33 @@ static void client_run(const char *direct_connect_server) if(snapshots[SNAP_CURRENT] && snapshots[SNAP_PREV]) { int64 curtick_start = game_start_time + (snapshots[SNAP_CURRENT]->tick+1)*time_freq()/50; - if(latency > 0) - curtick_start += (int64)(time_freq()*(latency*1.1f)); + if(snapshot_latency > 0) + curtick_start += (int64)(time_freq()*(snapshot_latency*1.1f)); int64 prevtick_start = game_start_time + (snapshots[SNAP_PREV]->tick+1)*time_freq()/50; - if(latency > 0) - prevtick_start += (int64)(time_freq()*(latency*1.1f)); + if(snapshot_latency > 0) + prevtick_start += (int64)(time_freq()*(snapshot_latency*1.1f)); intratick = (now - prevtick_start) / (float)(curtick_start-prevtick_start); - } - } - // send input - if(client_state() == CLIENTSTATE_ONLINE) - { - if(config.stress&1 && client_localtime() > 10.0f) - client_disconnect(); - - if(input_is_changed || time_get() > last_input+time_freq()) - { - client_send_input(); - input_is_changed = 0; - last_input = time_get(); + // 25 frames ahead + int new_predtick = current_tick+prediction_latency*SERVER_TICK_SPEED; + if(new_predtick > current_predtick) + { + //dbg_msg("") + current_predtick = new_predtick; + repredict = 1; + + // send input + client_send_input(); + } } + + if(repredict) + modc_predict(); } - + + // STRESS TEST: join the server again if(client_state() == CLIENTSTATE_OFFLINE && config.stress && (frames%100) == 0) client_connect(config.cl_stress_server); @@ -838,8 +914,6 @@ static void client_run(const char *direct_connect_server) inp_update(); // refocus - // TODO: fixme - if(!gfx_window_active()) { if(window_must_refocus == 0) diff --git a/src/engine/compression.c b/src/engine/compression.c index 2f3e37ca..e89cdadf 100644 --- a/src/engine/compression.c +++ b/src/engine/compression.c @@ -1,23 +1,23 @@ #include "system.h" #include <string.h> -// Format: ESDDDDDD EDDDDDDD EDD... Extended, Data, Sign +/* Format: ESDDDDDD EDDDDDDD EDD... Extended, Data, Sign */ unsigned char *vint_pack(unsigned char *dst, int i) { - *dst = (i>>25)&0x40; // set sign bit if i<0 - i = i^(i>>31); // if(i<0) i = ~i + *dst = (i>>25)&0x40; /* set sign bit if i<0 */ + i = i^(i>>31); /* if(i<0) i = ~i */ - *dst |= i&0x3F; // pack 6bit into dst - i >>= 6; // discard 6 bits + *dst |= i&0x3F; /* pack 6bit into dst */ + i >>= 6; /* discard 6 bits */ if(i) { - *dst |= 0x80; // set extend bit + *dst |= 0x80; /* set extend bit */ while(1) { dst++; - *dst = i&(0x7F); // pack 7bit - i >>= 7; // discard 7 bits - *dst |= (i!=0)<<7; // set extend bit (may branch) + *dst = i&(0x7F); /* pack 7bit */ + i >>= 7; /* discard 7 bits */ + *dst |= (i!=0)<<7; /* set extend bit (may branch) */ if(!i) break; } @@ -52,7 +52,7 @@ const unsigned char *vint_unpack(const unsigned char *src, int *i) } while(0); src++; - *i ^= -sign; // if(sign) *i = ~(*i) + *i ^= -sign; /* if(sign) *i = ~(*i) */ return src; } @@ -85,7 +85,7 @@ long intpack_compress(const void *src_, int size, void *dst_) } -// +/* */ long zerobit_compress(const void *src_, int size, void *dst_) { unsigned char *src = (unsigned char *)src_; diff --git a/src/engine/config.c b/src/engine/config.c index 59c07f3e..ba46d073 100644 --- a/src/engine/config.c +++ b/src/engine/config.c @@ -7,7 +7,7 @@ #include "config.h" -// buffered stream for reading lines, should perhaps be something smaller +/* buffered stream for reading lines, should perhaps be something smaller */ typedef struct { char buffer[4*1024]; @@ -33,9 +33,9 @@ char *linereader_get(LINEREADER *lr) { if(lr->buffer_pos >= lr->buffer_size) { - // fetch more + /* fetch more */ - // move the remaining part to the front + /* move the remaining part to the front */ unsigned left = lr->buffer_size - line_start; if(line_start > lr->buffer_size) left = 0; @@ -43,7 +43,7 @@ char *linereader_get(LINEREADER *lr) mem_move(lr->buffer, &lr->buffer[line_start], left); lr->buffer_pos = left; - // fill the buffer + /* fill the buffer */ unsigned read = io_read(lr->io, &lr->buffer[lr->buffer_pos], lr->buffer_max_size-lr->buffer_pos); lr->buffer_size = left + read; line_start = 0; @@ -52,20 +52,20 @@ char *linereader_get(LINEREADER *lr) { if(left) { - lr->buffer[left] = 0; // return the last line + lr->buffer[left] = 0; /* return the last line */ lr->buffer_pos = left; lr->buffer_size = left; return lr->buffer; } else - return 0x0; // we are done! + return 0x0; /* we are done! */ } } else { if(lr->buffer[lr->buffer_pos] == '\n' || lr->buffer[lr->buffer_pos] == '\r') { - // line found + /* line found */ lr->buffer[lr->buffer_pos] = 0; lr->buffer_pos++; return &lr->buffer[line_start]; @@ -176,7 +176,6 @@ void config_save(const char *filename) dbg_msg("config/save", "saving config to %s", filename); - //file_stream file; IOHANDLE file = io_open(filename, IOFLAG_WRITE); if(file) diff --git a/src/engine/datafile.c b/src/engine/datafile.c index ce835b46..fddd522d 100644 --- a/src/engine/datafile.c +++ b/src/engine/datafile.c @@ -100,9 +100,6 @@ DATAFILE *datafile_load(const char *filename) return 0; } - //if(DEBUG) - //dbg_msg("datafile", "loading. size=%d", datafile.size); - /* read in the rest except the data */ int size = 0; size += header.num_item_types*sizeof(DATAFILE_ITEM_TYPE); @@ -112,8 +109,8 @@ DATAFILE *datafile_load(const char *filename) size += header.item_size; int allocsize = size; - allocsize += sizeof(DATAFILE); // add space for info structure - allocsize += header.num_raw_data*sizeof(void*); // add space for data pointers + allocsize += sizeof(DATAFILE); /* add space for info structure */ + allocsize += header.num_raw_data*sizeof(void*); /* add space for data pointers */ df = (DATAFILE*)mem_alloc(allocsize, 1); df->header = header; @@ -207,9 +204,6 @@ int datafile_num_data(DATAFILE *df) /* always returns the size in the file */ int datafile_get_datasize(DATAFILE *df, int index) { - //if(df->header.version == 4) - // return df->info.data_sizes[index]; - if(index == df->header.num_raw_data-1) return df->header.data_size-df->info.data_offsets[index]; return df->info.data_offsets[index+1]-df->info.data_offsets[index]; @@ -217,7 +211,7 @@ int datafile_get_datasize(DATAFILE *df, int index) void *datafile_get_data(DATAFILE *df, int index) { - // load it if needed + /* load it if needed */ if(!df->data_ptrs[index]) { /* fetch the data size */ diff --git a/src/engine/datafile.h b/src/engine/datafile.h index e0f5380e..e83aa3c5 100644 --- a/src/engine/datafile.h +++ b/src/engine/datafile.h @@ -5,7 +5,7 @@ typedef struct DATAFILE_t DATAFILE; /* read access */ DATAFILE *datafile_load(const char *filename); DATAFILE *datafile_load_old(const char *filename); -void *datafile_get_data(DATAFILE *df, int index); // automaticly load the data for the item +void *datafile_get_data(DATAFILE *df, int index); int datafile_get_datasize(DATAFILE *df, int index); void datafile_unload_data(DATAFILE *df, int index); void *datafile_get_item(DATAFILE *df, int index, int *type, int *id); diff --git a/src/engine/interface.h b/src/engine/interface.h index a00fb81d..e1608cff 100644 --- a/src/engine/interface.h +++ b/src/engine/interface.h @@ -706,15 +706,13 @@ int modmenu_render(int ingame); /* undocumented callbacks */ void modc_message(int msg); +void modc_predict(); void mods_message(int msg, int client_id); + const char *modc_net_version(); const char *mods_net_version(); -// unused -// const char *modc_version(); -// const char *mods_version(); - /* server */ int server_getclientinfo(int client_id, CLIENT_INFO *info); int server_tick(); @@ -769,14 +767,16 @@ int client_send_msg(); /* client */ int client_tick(); +int client_predtick(); float client_intratick(); +float client_intrapredtick(); int client_tickspeed(); float client_frametime(); float client_localtime(); int client_state(); const char *client_error_string(); - +int *client_get_input(int tick); void client_connect(const char *address); void client_disconnect(); diff --git a/src/engine/server/server.c b/src/engine/server/server.c index ddc51c1d..edb3f644 100644 --- a/src/engine/server/server.c +++ b/src/engine/server/server.c @@ -20,7 +20,9 @@ static SNAPBUILD builder; -static int64 lasttick; +static int64 game_start_time; +static int current_tick = 0; + static int64 lastheartbeat; static NETADDR4 master_server; @@ -36,11 +38,11 @@ void *snap_new_item(int type, int id, int size) typedef struct { short next; - short state; // 0 = free, 1 = alloced, 2 = timed + short state; /* 0 = free, 1 = alloced, 2 = timed */ int timeout_tick; } SNAP_ID; -static const int MAX_IDS = 8*1024; // should be lowered +static const int MAX_IDS = 8*1024; /* should be lowered */ static SNAP_ID snap_ids[8*1024]; static int snap_first_free_id; static int snap_first_timed_id; @@ -49,6 +51,42 @@ static int snap_id_usage; static int snap_id_inusage; static int snap_id_inited = 0; + +enum +{ + SRVCLIENT_STATE_EMPTY = 0, + SRVCLIENT_STATE_CONNECTING = 1, + SRVCLIENT_STATE_INGAME = 2, +}; + +typedef struct +{ + int data[MAX_INPUT_SIZE]; + int pred_tick; /* tick that the client predicted for the input */ + int game_tick; /* the tick that was chosen for the input */ + int64 timeleft; /* how much time in ms there were left before this should be applied */ +} CLIENT_INPUT; + +/* */ +typedef struct +{ + /* connection state info */ + int state; + int latency; + + int last_acked_snapshot; + SNAPSTORAGE snapshots; + + CLIENT_INPUT inputs[200]; /* TODO: handle input better */ + int current_input; + + char name[MAX_NAME_LENGTH]; + char clan[MAX_CLANNAME_LENGTH]; +} CLIENT; + +static CLIENT clients[MAX_CLIENTS]; +static NETSERVER *net; + static void snap_init_id() { int i; @@ -72,17 +110,17 @@ int snap_new_id() { dbg_assert(snap_id_inited == 1, "requesting id too soon"); - // process timed ids + /* process timed ids */ while(snap_first_timed_id != -1 && snap_ids[snap_first_timed_id].timeout_tick < server_tick()) { int next_timed = snap_ids[snap_first_timed_id].next; - // add it to the free list + /* add it to the free list */ snap_ids[snap_first_timed_id].next = snap_first_free_id; snap_ids[snap_first_timed_id].state = 0; snap_first_free_id = snap_first_timed_id; - // remove it from the timed list + /* remove it from the timed list */ snap_first_timed_id = next_timed; if(snap_first_timed_id == -1) snap_last_timed_id = -1; @@ -120,36 +158,16 @@ void snap_free_id(int id) } } -enum -{ - SRVCLIENT_STATE_EMPTY = 0, - SRVCLIENT_STATE_CONNECTING = 1, - SRVCLIENT_STATE_INGAME = 2, -}; - -// -typedef struct -{ - // connection state info - int state; - int latency; - - int last_acked_snapshot; - SNAPSTORAGE snapshots; - - char name[MAX_NAME_LENGTH]; - char clan[MAX_CLANNAME_LENGTH]; -} CLIENT; - -static CLIENT clients[MAX_CLIENTS]; -static int current_tick = 0; -static NETSERVER *net; - int server_tick() { return current_tick; } +int64 server_tick_start_time(int tick) +{ + return game_start_time + (time_freq()*tick)/SERVER_TICK_SPEED; +} + int server_tickspeed() { return SERVER_TICK_SPEED; @@ -201,7 +219,7 @@ int server_send_msg(int client_id) if(client_id == -1) { - // broadcast + /* broadcast */ int i; for(i = 0; i < MAX_CLIENTS; i++) if(clients[i].state == SRVCLIENT_STATE_INGAME) @@ -224,10 +242,10 @@ static void server_do_tick() static void server_do_snap() { + int i, k; mods_presnap(); - int i; - for( i = 0; i < MAX_CLIENTS; i++) + for(i = 0; i < MAX_CLIENTS; i++) { if(clients[i].state == SRVCLIENT_STATE_INGAME) { @@ -237,18 +255,18 @@ static void server_do_snap() snapbuild_init(&builder); mods_snap(i); - // finish snapshot + /* finish snapshot */ int snapshot_size = snapbuild_finish(&builder, data); int crc = snapshot_crc((SNAPSHOT*)data); - // remove old snapshos - // keep 1 seconds worth of snapshots + /* remove old snapshos */ + /* keep 1 seconds worth of snapshots */ snapstorage_purge_until(&clients[i].snapshots, current_tick-SERVER_TICK_SPEED); - // save it the snapshot + /* save it the snapshot */ snapstorage_add(&clients[i].snapshots, current_tick, time_get(), snapshot_size, data); - // find snapshot that we can preform delta against + /* find snapshot that we can preform delta against */ static SNAPSHOT emptysnap; emptysnap.data_size = 0; emptysnap.num_items = 0; @@ -262,12 +280,24 @@ static void server_do_snap() delta_tick = clients[i].last_acked_snapshot; } - // create delta + int input_predtick = -1; + int64 timeleft = 0; + for(k = 0; k < 200; k++) // TODO: do this better + { + if(clients[i].inputs[k].game_tick == current_tick) + { + timeleft = clients[i].inputs[k].timeleft; + input_predtick = clients[i].inputs[k].pred_tick; + break; + } + } + + /* create delta */ int deltasize = snapshot_create_delta(deltashot, (SNAPSHOT*)data, deltadata); if(deltasize) { - // compress it + /* compress it */ unsigned char intdata[MAX_SNAPSHOT_SIZE]; int intsize = intpack_compress(deltadata, deltasize, intdata); @@ -288,7 +318,9 @@ static void server_do_snap() msg_pack_start_system(NETMSG_SNAP, 0); msg_pack_int(current_tick); - msg_pack_int(current_tick-delta_tick); // compressed with + msg_pack_int(current_tick-delta_tick); /* compressed with */ + msg_pack_int(input_predtick); + msg_pack_int((timeleft*1000)/time_freq()); msg_pack_int(crc); msg_pack_int(chunk); msg_pack_raw(&compdata[n*max_size], chunk); @@ -300,7 +332,9 @@ static void server_do_snap() { msg_pack_start_system(NETMSG_SNAPEMPTY, 0); msg_pack_int(current_tick); - msg_pack_int(current_tick-delta_tick); // compressed with + msg_pack_int(current_tick-delta_tick); /* compressed with */ + msg_pack_int(input_predtick); + msg_pack_int((timeleft*1000)/time_freq()); msg_pack_end(); server_send_msg(i); } @@ -313,9 +347,19 @@ static void server_do_snap() static int new_client_callback(int cid, void *user) { + int i; clients[cid].state = SRVCLIENT_STATE_CONNECTING; clients[cid].name[0] = 0; clients[cid].clan[0] = 0; + + /* reset input */ + for(i = 0; i < 200; i++) + { + clients[cid].inputs[i].game_tick = -1; + clients[cid].inputs[i].pred_tick = -1; + } + clients[cid].current_input = 0; + snapstorage_purge_all(&clients[cid].snapshots); clients[cid].last_acked_snapshot = -1; return 0; @@ -359,14 +403,14 @@ static void server_process_client_packet(NETPACKET *packet) int msg = msg_unpack_start(packet->data, packet->data_size, &sys); if(sys) { - // system message + /* system message */ if(msg == NETMSG_INFO) { char version[64]; strncpy(version, msg_unpack_string(), 64); if(strcmp(version, mods_net_version()) != 0) { - // OH FUCK! wrong version, drop him + /* OH FUCK! wrong version, drop him */ char reason[256]; sprintf(reason, "wrong version. server is running %s.", mods_net_version()); netserver_drop(net, cid, reason); @@ -377,7 +421,7 @@ static void server_process_client_packet(NETPACKET *packet) strncpy(clients[cid].clan, msg_unpack_string(), MAX_CLANNAME_LENGTH); const char *password = msg_unpack_string(); const char *skin = msg_unpack_string(); - (void)password; // ignore these variables + (void)password; /* ignore these variables */ (void)skin; server_send_map(cid); } @@ -392,12 +436,29 @@ static void server_process_client_packet(NETPACKET *packet) } else if(msg == NETMSG_INPUT) { - int input[MAX_INPUT_SIZE]; + int tick = msg_unpack_int(); int size = msg_unpack_int(); int i; + + CLIENT_INPUT *input = &clients[cid].inputs[clients[cid].current_input]; + input->timeleft = server_tick_start_time(tick)-time_get(); + input->pred_tick = tick; + + if(tick < server_tick()) + { + /* TODO: how should we handle this */ + dbg_msg("server", "input got in late for=%d cur=%d", tick, server_tick()); + tick = server_tick()+1; + } + + input->game_tick = tick; + for(i = 0; i < size/4; i++) - input[i] = msg_unpack_int(); - mods_client_input(cid, input); + input->data[i] = msg_unpack_int(); + + //time_get() + clients[cid].current_input++; + clients[cid].current_input %= 200; } else if(msg == NETMSG_SNAPACK) { @@ -413,7 +474,7 @@ static void server_process_client_packet(NETPACKET *packet) } else { - // game message + /* game message */ mods_message(msg, cid); } } @@ -427,7 +488,7 @@ static void server_send_serverinfo(NETADDR4 *addr) packer_add_raw(&p, SERVERBROWSE_INFO, sizeof(SERVERBROWSE_INFO)); packer_add_string(&p, config.sv_name, 128); packer_add_string(&p, config.sv_map, 128); - packer_add_int(&p, netserver_max_clients(net)); // max_players + packer_add_int(&p, netserver_max_clients(net)); /* max_players */ int c = 0; int i; for(i = 0; i < MAX_CLIENTS; i++) @@ -435,7 +496,7 @@ static void server_send_serverinfo(NETADDR4 *addr) if(!clients[i].state != SRVCLIENT_STATE_EMPTY) c++; } - packer_add_int(&p, c); // num_players + packer_add_int(&p, c); /* num_players */ packet.client_id = -1; packet.address = *addr; @@ -461,13 +522,13 @@ static void server_pump_network() { netserver_update(net); - // process packets + /* process packets */ NETPACKET packet; while(netserver_recv(net, &packet)) { if(packet.client_id == -1) { - // stateless + /* stateless */ if(packet.data_size == sizeof(SERVERBROWSE_GETINFO) && memcmp(packet.data, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO)) == 0) { @@ -501,23 +562,23 @@ static int server_run() { biggest_snapshot = 0; - net_init(); // For Windows compatibility. + net_init(); /* For Windows compatibility. */ snap_init_id(); - // load map + /* load map */ if(!map_load(config.sv_map)) { dbg_msg("server", "failed to load map. mapname='%s'", config.sv_map); return -1; } - // start server + /* start server */ NETADDR4 bindaddr; if(strlen(config.sv_bindaddr) && net_host_lookup(config.sv_bindaddr, config.sv_port, &bindaddr) != 0) { - // sweet! + /* sweet! */ } else { @@ -536,19 +597,16 @@ static int server_run() dbg_msg("server", "server name is '%s'", config.sv_name); dbg_msg("server", "masterserver is '%s'", config.masterserver); - if (net_host_lookup(config.masterserver, MASTERSERVER_PORT, &master_server) != 0) + if(net_host_lookup(config.masterserver, MASTERSERVER_PORT, &master_server) != 0) { - // TODO: fix me - //master_server = netaddr4(0, 0, 0, 0, 0); + /* TODO: fix me */ + /*master_server = netaddr4(0, 0, 0, 0, 0); */ } mods_init(); dbg_msg("server", "version %s", mods_net_version()); - int64 time_per_tick = time_freq()/SERVER_TICK_SPEED; int64 time_per_heartbeat = time_freq() * 30; - int64 starttime = time_get(); - lasttick = starttime; lastheartbeat = 0; int64 reporttime = time_get(); @@ -558,28 +616,48 @@ static int server_run() int64 snaptime = 0; int64 networktime = 0; int64 totaltime = 0; + + game_start_time = time_get(); if(config.debug) - dbg_msg("server", "baseline memory usage %dk", mem_allocated()/1024); + dbg_msg("server", "baseline memory usage %dk", mem_allocated()/1024); while(1) { int64 t = time_get(); - if(t-lasttick > time_per_tick) + if(t > server_tick_start_time(current_tick+1)) { + /* apply new input */ + { + int c, i; + for(c = 0; c < MAX_CLIENTS; c++) + { + if(clients[c].state == SRVCLIENT_STATE_EMPTY) + continue; + for(i = 0; i < 200; i++) + { + if(clients[c].inputs[i].game_tick == server_tick()) + { + mods_client_input(c, clients[c].inputs[i].data); + break; + } + } + } + } + + /* progress game */ { int64 start = time_get(); server_do_tick(); simulationtime += time_get()-start; } + /* snap game */ { int64 start = time_get(); server_do_snap(); snaptime += time_get()-start; } - - lasttick += time_per_tick; } if(config.sv_sendheartbeats) @@ -652,7 +730,7 @@ int main(int argc, char **argv) config_load(config_filename); - // parse arguments + /* parse arguments */ for(i = 1; i < argc; i++) config_set(argv[i]); diff --git a/src/engine/snapshot.c b/src/engine/snapshot.c index b9c832a2..b42b0157 100644 --- a/src/engine/snapshot.c +++ b/src/engine/snapshot.c @@ -21,7 +21,7 @@ int snapshot_get_item_datasize(SNAPSHOT *snap, int index) int snapshot_get_item_index(SNAPSHOT *snap, int key) { - /* TODO: this should not be a linear search. very bad */ + /* TODO: OPT: this should not be a linear search. very bad */ int i; for(i = 0; i < snap->num_items; i++) { @@ -135,6 +135,8 @@ static void undiff_item(int *past, int *diff, int *out, int size) } } + +// TODO: OPT: this should be made much faster int snapshot_create_delta(SNAPSHOT *from, SNAPSHOT *to, void *dstdata) { SNAPSHOT_DELTA *delta = (SNAPSHOT_DELTA *)dstdata; |