2007-05-22 15:03:32 +00:00
|
|
|
|
|
|
|
#include <string.h>
|
2007-05-24 10:57:18 +00:00
|
|
|
#include <stdarg.h>
|
2007-05-27 00:47:07 +00:00
|
|
|
#include <stdlib.h>
|
2007-07-13 13:40:04 +00:00
|
|
|
#include <stdio.h>
|
2007-05-22 15:03:32 +00:00
|
|
|
#include <math.h>
|
|
|
|
|
2007-08-22 07:52:33 +00:00
|
|
|
#include <engine/system.h>
|
|
|
|
#include <engine/interface.h>
|
2007-05-22 15:03:32 +00:00
|
|
|
#include "ui.h"
|
|
|
|
|
2007-08-22 07:52:33 +00:00
|
|
|
#include <engine/protocol.h>
|
|
|
|
#include <engine/snapshot.h>
|
2007-07-13 13:40:04 +00:00
|
|
|
#include <engine/compression.h>
|
2007-07-30 19:46:31 +00:00
|
|
|
#include <engine/network.h>
|
2007-06-01 11:17:10 +00:00
|
|
|
#include <engine/config.h>
|
2007-08-22 07:52:33 +00:00
|
|
|
#include <engine/packer.h>
|
2007-09-27 23:55:59 +00:00
|
|
|
#include <engine/memheap.h>
|
2007-05-22 18:18:41 +00:00
|
|
|
|
2007-07-21 18:07:27 +00:00
|
|
|
#include <mastersrv/mastersrv.h>
|
|
|
|
|
2007-09-25 21:53:14 +00:00
|
|
|
const int prediction_margin = 5;
|
|
|
|
|
2007-09-09 18:21:14 +00:00
|
|
|
/*
|
|
|
|
Server Time
|
|
|
|
Client Mirror Time
|
|
|
|
Client Predicted Time
|
|
|
|
|
|
|
|
Snapshot Latency
|
|
|
|
Downstream latency
|
|
|
|
|
|
|
|
Prediction Latency
|
|
|
|
Upstream latency
|
|
|
|
*/
|
2007-07-30 19:46:31 +00:00
|
|
|
static int snapshot_part;
|
|
|
|
static int64 local_start_time;
|
2007-09-09 18:21:14 +00:00
|
|
|
|
2007-07-30 19:46:31 +00:00
|
|
|
static int extra_polating = 0;
|
|
|
|
static int debug_font;
|
|
|
|
static float frametime = 0.0001f;
|
2007-08-22 07:52:33 +00:00
|
|
|
static NETCLIENT *net;
|
|
|
|
static NETADDR4 master_server;
|
|
|
|
static NETADDR4 server_address;
|
2007-08-07 18:28:51 +00:00
|
|
|
static int window_must_refocus = 0;
|
2007-08-14 18:37:16 +00:00
|
|
|
static int snaploss = 0;
|
2007-08-22 21:21:20 +00:00
|
|
|
static int snapcrcerrors = 0;
|
2007-08-14 18:37:16 +00:00
|
|
|
|
2007-09-23 18:27:04 +00:00
|
|
|
static int ack_game_tick = -1;
|
|
|
|
|
2007-09-09 18:21:14 +00:00
|
|
|
static int current_recv_tick = 0;
|
|
|
|
|
|
|
|
// current time
|
2007-08-14 18:37:16 +00:00
|
|
|
static int current_tick = 0;
|
|
|
|
static float intratick = 0;
|
|
|
|
|
2007-09-09 18:21:14 +00:00
|
|
|
// 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
|
2007-09-23 18:27:04 +00:00
|
|
|
int64 game_time; // prediction latency when we sent this input
|
|
|
|
int64 time;
|
2007-09-09 18:21:14 +00:00
|
|
|
} inputs[200];
|
|
|
|
static int current_input = 0;
|
|
|
|
|
2007-09-23 18:27:04 +00:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
GRAPH_MAX=256,
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
float min, max;
|
|
|
|
float values[GRAPH_MAX];
|
|
|
|
int index;
|
|
|
|
} GRAPH;
|
|
|
|
|
|
|
|
static void graph_add(GRAPH *g, float v)
|
|
|
|
{
|
|
|
|
g->values[g->index] = v;
|
|
|
|
g->index = (g->index+1)&(GRAPH_MAX-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void graph_render(GRAPH *g, float x, float y, float w, float h)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
gfx_texture_set(-1);
|
|
|
|
|
|
|
|
gfx_quads_begin();
|
|
|
|
gfx_setcolor(0, 0, 0, 1);
|
|
|
|
gfx_quads_drawTL(x, y, w, h);
|
|
|
|
gfx_quads_end();
|
|
|
|
|
|
|
|
gfx_lines_begin();
|
|
|
|
gfx_setcolor(0.5f, 0.5f, 0.5f, 1);
|
|
|
|
gfx_lines_draw(x, y+(h*3)/4, x+w, y+(h*3)/4);
|
|
|
|
gfx_lines_draw(x, y+h/2, x+w, y+h/2);
|
|
|
|
gfx_lines_draw(x, y+h/4, x+w, y+h/4);
|
|
|
|
for(i = 1; i < GRAPH_MAX; i++)
|
|
|
|
{
|
|
|
|
float a0 = (i-1)/(float)GRAPH_MAX;
|
|
|
|
float a1 = i/(float)GRAPH_MAX;
|
|
|
|
int i0 = (g->index+i-1)&(GRAPH_MAX-1);
|
|
|
|
int i1 = (g->index+i)&(GRAPH_MAX-1);
|
|
|
|
|
|
|
|
float v0 = g->values[i0];
|
|
|
|
float v1 = g->values[i1];
|
|
|
|
|
|
|
|
gfx_setcolor(0, 1, 0, 1);
|
|
|
|
gfx_lines_draw(x+a0*w, y+h-v0*h, x+a1*w, y+h-v1*h);
|
|
|
|
}
|
|
|
|
gfx_lines_end();
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
int64 snap;
|
|
|
|
int64 current;
|
|
|
|
int64 target;
|
|
|
|
|
|
|
|
int64 rlast;
|
|
|
|
int64 tlast;
|
|
|
|
GRAPH graph;
|
|
|
|
} SMOOTHTIME;
|
|
|
|
|
|
|
|
static void st_init(SMOOTHTIME *st, int64 target)
|
|
|
|
{
|
|
|
|
st->snap = time_get();
|
|
|
|
st->current = target;
|
|
|
|
st->target = target;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int64 st_get(SMOOTHTIME *st, int64 now)
|
|
|
|
{
|
|
|
|
int64 c = st->current + (now - st->snap);
|
|
|
|
int64 t = st->target + (now - st->snap);
|
|
|
|
|
|
|
|
// it's faster to adjust upward instead of downward
|
|
|
|
// we might need to adjust these abit
|
|
|
|
float adjust_speed = 0.3f;
|
|
|
|
if(t < c)
|
|
|
|
adjust_speed *= 5.0f;
|
|
|
|
|
|
|
|
float a = ((now-st->snap)/(float)time_freq())*adjust_speed;
|
|
|
|
if(a > 1)
|
|
|
|
a = 1;
|
|
|
|
|
|
|
|
int64 r = c + (int64)((t-c)*a);
|
|
|
|
|
|
|
|
{
|
|
|
|
int64 drt = now - st->rlast;
|
|
|
|
int64 dtt = r - st->tlast;
|
|
|
|
|
|
|
|
st->rlast = now;
|
|
|
|
st->tlast = r;
|
|
|
|
|
|
|
|
if(drt == 0)
|
|
|
|
graph_add(&st->graph, 0.5f);
|
|
|
|
else
|
|
|
|
graph_add(&st->graph, (((dtt/(float)drt)-1.0f)*2.5f)+0.5f);
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void st_update(SMOOTHTIME *st, int64 target)
|
|
|
|
{
|
|
|
|
int64 now = time_get();
|
|
|
|
st->current = st_get(st, now);
|
|
|
|
st->snap = now;
|
|
|
|
st->target = target;
|
|
|
|
}
|
|
|
|
|
|
|
|
SMOOTHTIME game_time;
|
|
|
|
SMOOTHTIME predicted_time;
|
|
|
|
|
|
|
|
GRAPH intra_graph;
|
2007-09-09 18:21:14 +00:00
|
|
|
|
2007-05-22 15:03:32 +00:00
|
|
|
// --- input snapping ---
|
2007-07-13 13:40:04 +00:00
|
|
|
static int input_data[MAX_INPUT_SIZE] = {0};
|
2007-05-22 15:03:32 +00:00
|
|
|
static int input_data_size;
|
2007-05-24 10:57:18 +00:00
|
|
|
static int input_is_changed = 1;
|
2007-05-22 15:03:32 +00:00
|
|
|
void snap_input(void *data, int size)
|
|
|
|
{
|
2007-05-24 10:57:18 +00:00
|
|
|
if(input_data_size != size || memcmp(input_data, data, size))
|
|
|
|
input_is_changed = 1;
|
2007-05-22 15:03:32 +00:00
|
|
|
mem_copy(input_data, data, size);
|
|
|
|
input_data_size = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -- snapshot handling ---
|
|
|
|
enum
|
|
|
|
{
|
2007-07-26 19:09:31 +00:00
|
|
|
NUM_SNAPSHOT_TYPES=2,
|
2007-05-22 15:03:32 +00:00
|
|
|
};
|
|
|
|
|
2007-08-22 07:52:33 +00:00
|
|
|
SNAPSTORAGE snapshot_storage;
|
|
|
|
static SNAPSTORAGE_HOLDER *snapshots[NUM_SNAPSHOT_TYPES];
|
2007-05-22 15:03:32 +00:00
|
|
|
static int recived_snapshots;
|
2007-07-26 19:09:31 +00:00
|
|
|
static char snapshot_incomming_data[MAX_SNAPSHOT_SIZE];
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-30 19:46:31 +00:00
|
|
|
// ---
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-08-22 07:52:33 +00:00
|
|
|
const void *snap_get_item(int snapid, int index, SNAP_ITEM *item)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
|
|
|
dbg_assert(snapid >= 0 && snapid < NUM_SNAPSHOT_TYPES, "invalid snapid");
|
2007-08-22 07:52:33 +00:00
|
|
|
SNAPSHOT_ITEM *i = snapshot_get_item(snapshots[snapid]->snap, index);
|
|
|
|
item->type = snapitem_type(i);
|
|
|
|
item->id = snapitem_id(i);
|
|
|
|
return (void *)snapitem_data(i);
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-31 06:23:24 +00:00
|
|
|
const void *snap_find_item(int snapid, int type, int id)
|
|
|
|
{
|
|
|
|
// TODO: linear search. should be fixed.
|
2007-08-22 07:52:33 +00:00
|
|
|
int i;
|
|
|
|
for(i = 0; i < snapshots[snapid]->snap->num_items; i++)
|
2007-07-31 06:23:24 +00:00
|
|
|
{
|
2007-08-22 07:52:33 +00:00
|
|
|
SNAPSHOT_ITEM *itm = snapshot_get_item(snapshots[snapid]->snap, i);
|
|
|
|
if(snapitem_type(itm) == type && snapitem_id(itm) == id)
|
|
|
|
return (void *)snapitem_data(itm);
|
2007-07-31 06:23:24 +00:00
|
|
|
}
|
|
|
|
return 0x0;
|
|
|
|
}
|
|
|
|
|
2007-05-22 15:03:32 +00:00
|
|
|
int snap_num_items(int snapid)
|
|
|
|
{
|
|
|
|
dbg_assert(snapid >= 0 && snapid < NUM_SNAPSHOT_TYPES, "invalid snapid");
|
2007-07-26 19:09:31 +00:00
|
|
|
return snapshots[snapid]->snap->num_items;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-30 19:46:31 +00:00
|
|
|
// ------ time functions ------
|
2007-09-09 18:21:14 +00:00
|
|
|
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()); }
|
2007-05-24 10:57:18 +00:00
|
|
|
|
2007-07-30 19:46:31 +00:00
|
|
|
// ----- send functions -----
|
2007-07-13 13:40:04 +00:00
|
|
|
int client_send_msg()
|
2007-05-24 10:57:18 +00:00
|
|
|
{
|
2007-08-22 07:52:33 +00:00
|
|
|
const MSG_INFO *info = msg_get_info();
|
2007-07-13 13:40:04 +00:00
|
|
|
NETPACKET packet;
|
2007-07-21 19:02:47 +00:00
|
|
|
mem_zero(&packet, sizeof(NETPACKET));
|
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
packet.client_id = 0;
|
|
|
|
packet.data = info->data;
|
|
|
|
packet.data_size = info->size;
|
|
|
|
|
|
|
|
if(info->flags&MSGFLAG_VITAL)
|
|
|
|
packet.flags = PACKETFLAG_VITAL;
|
2007-05-24 10:57:18 +00:00
|
|
|
|
2007-08-22 07:52:33 +00:00
|
|
|
netclient_send(net, &packet);
|
2007-07-13 13:40:04 +00:00
|
|
|
return 0;
|
2007-05-24 10:57:18 +00:00
|
|
|
}
|
|
|
|
|
2007-07-30 19:46:31 +00:00
|
|
|
static void client_send_info()
|
|
|
|
{
|
|
|
|
msg_pack_start_system(NETMSG_INFO, MSGFLAG_VITAL);
|
2007-08-22 21:13:33 +00:00
|
|
|
msg_pack_string(modc_net_version(), 128);
|
2007-07-30 19:46:31 +00:00
|
|
|
msg_pack_string(config.player_name, 128);
|
|
|
|
msg_pack_string(config.clan_name, 128);
|
|
|
|
msg_pack_string(config.password, 128);
|
|
|
|
msg_pack_string("myskin", 128);
|
|
|
|
msg_pack_end();
|
|
|
|
client_send_msg();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void client_send_entergame()
|
|
|
|
{
|
|
|
|
msg_pack_start_system(NETMSG_ENTERGAME, MSGFLAG_VITAL);
|
|
|
|
msg_pack_end();
|
|
|
|
client_send_msg();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void client_send_error(const char *error)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
packet p(NETMSG_CLIENT_ERROR);
|
|
|
|
p.write_str(error);
|
|
|
|
send_packet(&p);
|
|
|
|
//send_packet(&p);
|
|
|
|
//send_packet(&p);
|
|
|
|
*/
|
2007-09-09 18:21:14 +00:00
|
|
|
}
|
2007-07-30 19:46:31 +00:00
|
|
|
|
2007-09-09 21:47:25 +00:00
|
|
|
|
2007-09-23 21:00:57 +00:00
|
|
|
void client_rcon(const char *cmd)
|
|
|
|
{
|
|
|
|
msg_pack_start_system(NETMSG_CMD, MSGFLAG_VITAL);
|
|
|
|
msg_pack_string(config.rcon_password, 32);
|
|
|
|
msg_pack_string(cmd, 256);
|
|
|
|
msg_pack_end();
|
|
|
|
client_send_msg();
|
|
|
|
}
|
|
|
|
|
2007-07-30 19:46:31 +00:00
|
|
|
static void client_send_input()
|
|
|
|
{
|
2007-09-23 18:27:04 +00:00
|
|
|
if(current_predtick <= 0)
|
|
|
|
return;
|
|
|
|
|
2007-07-30 19:46:31 +00:00
|
|
|
msg_pack_start_system(NETMSG_INPUT, 0);
|
2007-09-23 18:27:04 +00:00
|
|
|
msg_pack_int(ack_game_tick);
|
2007-09-09 18:21:14 +00:00
|
|
|
msg_pack_int(current_predtick);
|
2007-07-30 19:46:31 +00:00
|
|
|
msg_pack_int(input_data_size);
|
2007-09-23 18:27:04 +00:00
|
|
|
|
|
|
|
int64 now = time_get();
|
2007-09-09 18:21:14 +00:00
|
|
|
inputs[current_input].tick = current_predtick;
|
2007-09-23 18:27:04 +00:00
|
|
|
inputs[current_input].game_time = st_get(&predicted_time, now);
|
|
|
|
inputs[current_input].time = now;
|
2007-09-09 18:21:14 +00:00
|
|
|
|
2007-08-22 07:52:33 +00:00
|
|
|
int i;
|
|
|
|
for(i = 0; i < input_data_size/4; i++)
|
2007-09-09 18:21:14 +00:00
|
|
|
{
|
|
|
|
inputs[current_input].data[i] = input_data[i];
|
2007-07-30 19:46:31 +00:00
|
|
|
msg_pack_int(input_data[i]);
|
2007-09-09 18:21:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
current_input++;
|
|
|
|
current_input%=200;
|
|
|
|
|
2007-07-30 19:46:31 +00:00
|
|
|
msg_pack_end();
|
|
|
|
client_send_msg();
|
|
|
|
}
|
|
|
|
|
2007-09-09 18:21:14 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
2007-07-30 19:46:31 +00:00
|
|
|
|
2007-09-30 11:48:06 +00:00
|
|
|
/* ------ server browse ---- */
|
|
|
|
/* TODO: move all this to a separate file */
|
|
|
|
|
2007-09-27 23:55:59 +00:00
|
|
|
typedef struct SERVERENTRY_t SERVERENTRY;
|
|
|
|
struct SERVERENTRY_t
|
2007-07-21 18:07:27 +00:00
|
|
|
{
|
2007-09-27 23:55:59 +00:00
|
|
|
NETADDR4 addr;
|
|
|
|
int64 request_time;
|
2007-09-30 11:48:06 +00:00
|
|
|
int got_info;
|
2007-09-27 23:55:59 +00:00
|
|
|
SERVER_INFO info;
|
|
|
|
|
|
|
|
SERVERENTRY *next_ip; // ip hashed list
|
|
|
|
|
|
|
|
SERVERENTRY *prev_req; // request list
|
|
|
|
SERVERENTRY *next_req;
|
|
|
|
};
|
|
|
|
|
2007-09-30 11:48:06 +00:00
|
|
|
static HEAP *serverlist_heap = 0;
|
|
|
|
static SERVERENTRY **serverlist = 0;
|
|
|
|
static int *sorted_serverlist = 0;
|
|
|
|
|
|
|
|
static SERVERENTRY *serverlist_ip[256] = {0}; // ip hash list
|
2007-09-27 23:55:59 +00:00
|
|
|
|
2007-09-30 11:48:06 +00:00
|
|
|
static SERVERENTRY *first_req_server = 0; // request list
|
|
|
|
static SERVERENTRY *last_req_server = 0;
|
|
|
|
static int num_requests = 0;
|
2007-09-27 23:55:59 +00:00
|
|
|
|
2007-09-30 11:48:06 +00:00
|
|
|
static int num_sorted_servers = 0;
|
|
|
|
static int num_sorted_servers_capacity = 0;
|
|
|
|
static int num_servers = 0;
|
|
|
|
static int num_server_capacity = 0;
|
2007-09-27 23:55:59 +00:00
|
|
|
|
2007-09-30 11:48:06 +00:00
|
|
|
static int sorthash = 0;
|
2007-08-22 07:52:33 +00:00
|
|
|
|
2007-07-22 09:15:34 +00:00
|
|
|
static int serverlist_lan = 1;
|
2007-07-21 18:07:27 +00:00
|
|
|
|
2007-09-30 11:48:06 +00:00
|
|
|
int client_serverbrowse_num() { return num_servers; }
|
|
|
|
|
2007-09-27 23:55:59 +00:00
|
|
|
SERVER_INFO *client_serverbrowse_get(int index)
|
|
|
|
{
|
|
|
|
if(index < 0 || index >= num_servers)
|
|
|
|
return 0;
|
|
|
|
return &serverlist[index]->info;
|
|
|
|
}
|
|
|
|
|
2007-09-30 11:48:06 +00:00
|
|
|
int client_serverbrowse_sorted_num() { return num_sorted_servers; }
|
|
|
|
|
|
|
|
SERVER_INFO *client_serverbrowse_sorted_get(int index)
|
2007-07-21 18:07:27 +00:00
|
|
|
{
|
2007-09-30 11:48:06 +00:00
|
|
|
if(index < 0 || index >= num_sorted_servers)
|
|
|
|
return 0;
|
|
|
|
return &serverlist[sorted_serverlist[index]]->info;
|
2007-07-21 18:07:27 +00:00
|
|
|
}
|
|
|
|
|
2007-09-30 11:48:06 +00:00
|
|
|
|
|
|
|
int client_serverbrowse_num_requests()
|
2007-07-21 18:07:27 +00:00
|
|
|
{
|
2007-09-30 11:48:06 +00:00
|
|
|
return num_requests;
|
2007-09-27 23:55:59 +00:00
|
|
|
}
|
|
|
|
|
2007-09-30 11:48:06 +00:00
|
|
|
static void client_serverbrowse_init()
|
|
|
|
{
|
|
|
|
}
|
2007-09-29 13:16:00 +00:00
|
|
|
|
|
|
|
static int client_serverbrowse_sort_compare_name(const void *ai, const void *bi)
|
|
|
|
{
|
2007-09-30 11:48:06 +00:00
|
|
|
SERVERENTRY *a = serverlist[*(const int*)ai];
|
|
|
|
SERVERENTRY *b = serverlist[*(const int*)bi];
|
|
|
|
return strcmp(a->info.name, b->info.name);
|
2007-09-29 13:16:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int client_serverbrowse_sort_compare_map(const void *ai, const void *bi)
|
|
|
|
{
|
2007-09-30 11:48:06 +00:00
|
|
|
SERVERENTRY *a = serverlist[*(const int*)ai];
|
|
|
|
SERVERENTRY *b = serverlist[*(const int*)bi];
|
|
|
|
return strcmp(a->info.map, b->info.map);
|
2007-09-29 13:16:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int client_serverbrowse_sort_compare_ping(const void *ai, const void *bi)
|
|
|
|
{
|
2007-09-30 11:48:06 +00:00
|
|
|
SERVERENTRY *a = serverlist[*(const int*)ai];
|
|
|
|
SERVERENTRY *b = serverlist[*(const int*)bi];
|
|
|
|
return a->info.latency > b->info.latency;
|
2007-09-29 13:16:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int client_serverbrowse_sort_compare_numplayers(const void *ai, const void *bi)
|
|
|
|
{
|
2007-09-30 11:48:06 +00:00
|
|
|
SERVERENTRY *a = serverlist[*(const int*)ai];
|
|
|
|
SERVERENTRY *b = serverlist[*(const int*)bi];
|
|
|
|
return a->info.num_players > b->info.num_players;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void client_serverbrowse_filter()
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
num_sorted_servers = 0;
|
|
|
|
|
|
|
|
/* allocate the sorted list */
|
|
|
|
if(num_sorted_servers_capacity < num_servers)
|
|
|
|
{
|
|
|
|
if(sorted_serverlist)
|
|
|
|
mem_free(sorted_serverlist);
|
|
|
|
num_sorted_servers_capacity = num_servers;
|
|
|
|
sorted_serverlist = mem_alloc(num_sorted_servers_capacity*sizeof(int), 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* filter the servers */
|
|
|
|
for(i = 0; i < num_servers; i++)
|
|
|
|
{
|
|
|
|
int filtered = 0;
|
|
|
|
|
|
|
|
if(config.b_filter_empty && serverlist[i]->info.num_players == 0)
|
|
|
|
filtered = 1;
|
|
|
|
else if(config.b_filter_full && serverlist[i]->info.num_players == serverlist[i]->info.max_players)
|
|
|
|
filtered = 1;
|
|
|
|
else if(config.b_filter_pw && serverlist[i]->info.flags&1)
|
|
|
|
filtered = 1;
|
|
|
|
|
|
|
|
if(filtered == 0)
|
|
|
|
sorted_serverlist[num_sorted_servers++] = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int client_serverbrowse_sorthash()
|
|
|
|
{
|
|
|
|
int i = config.b_sort&3;
|
|
|
|
i |= config.b_filter_empty<<4;
|
|
|
|
i |= config.b_filter_full<<5;
|
|
|
|
i |= config.b_filter_pw<<6;
|
|
|
|
return i;
|
2007-09-29 13:16:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void client_serverbrowse_sort()
|
|
|
|
{
|
2007-09-30 11:48:06 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
/* create filtered list */
|
|
|
|
client_serverbrowse_filter();
|
|
|
|
|
|
|
|
/* sort */
|
|
|
|
if(config.b_sort == BROWSESORT_NAME)
|
|
|
|
qsort(sorted_serverlist, num_sorted_servers, sizeof(int), client_serverbrowse_sort_compare_name);
|
|
|
|
else if(config.b_sort == BROWSESORT_PING)
|
|
|
|
qsort(sorted_serverlist, num_sorted_servers, sizeof(int), client_serverbrowse_sort_compare_ping);
|
|
|
|
else if(config.b_sort == BROWSESORT_MAP)
|
|
|
|
qsort(sorted_serverlist, num_sorted_servers, sizeof(int), client_serverbrowse_sort_compare_map);
|
|
|
|
else if(config.b_sort == BROWSESORT_NUMPLAYERS)
|
|
|
|
qsort(sorted_serverlist, num_sorted_servers, sizeof(int), client_serverbrowse_sort_compare_numplayers);
|
|
|
|
|
|
|
|
/* set indexes */
|
|
|
|
for(i = 0; i < num_sorted_servers; i++)
|
|
|
|
serverlist[sorted_serverlist[i]]->info.sorted_index = i;
|
|
|
|
|
|
|
|
sorthash = client_serverbrowse_sorthash();
|
2007-09-29 13:16:00 +00:00
|
|
|
}
|
|
|
|
|
2007-09-30 11:48:06 +00:00
|
|
|
static void client_serverbrowse_remove_request(SERVERENTRY *entry)
|
2007-09-29 13:16:00 +00:00
|
|
|
{
|
2007-09-30 11:48:06 +00:00
|
|
|
if(entry->prev_req || entry->next_req || first_req_server == entry)
|
|
|
|
{
|
|
|
|
if(entry->prev_req)
|
|
|
|
entry->prev_req->next_req = entry->next_req;
|
|
|
|
else
|
|
|
|
first_req_server = entry->next_req;
|
|
|
|
|
|
|
|
if(entry->next_req)
|
|
|
|
entry->next_req->prev_req = entry->prev_req;
|
|
|
|
else
|
|
|
|
last_req_server = entry->prev_req;
|
|
|
|
|
|
|
|
entry->prev_req = 0;
|
|
|
|
entry->next_req = 0;
|
|
|
|
num_requests--;
|
|
|
|
}
|
2007-09-29 13:16:00 +00:00
|
|
|
}
|
|
|
|
|
2007-09-27 23:55:59 +00:00
|
|
|
static void client_serverbrowse_set(NETADDR4 *addr, int request, SERVER_INFO *info)
|
|
|
|
{
|
|
|
|
int hash = addr->ip[0];
|
|
|
|
SERVERENTRY *entry = serverlist_ip[hash];
|
|
|
|
while(entry)
|
|
|
|
{
|
|
|
|
if(net_addr4_cmp(&entry->addr, addr) == 0)
|
|
|
|
{
|
|
|
|
/* update the server that we already have */
|
|
|
|
entry->info = *info;
|
|
|
|
if(!request)
|
2007-09-30 11:48:06 +00:00
|
|
|
{
|
2007-09-27 23:55:59 +00:00
|
|
|
entry->info.latency = (time_get()-entry->request_time)*1000/time_freq();
|
2007-09-30 11:48:06 +00:00
|
|
|
client_serverbrowse_remove_request(entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
entry->got_info = 1;
|
2007-09-29 13:16:00 +00:00
|
|
|
client_serverbrowse_sort();
|
2007-09-27 23:55:59 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
entry = entry->next_ip;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create new entry */
|
|
|
|
entry = (SERVERENTRY *)memheap_allocate(serverlist_heap, sizeof(SERVERENTRY));
|
|
|
|
mem_zero(entry, sizeof(SERVERENTRY));
|
|
|
|
|
|
|
|
/* set the info */
|
|
|
|
entry->addr = *addr;
|
|
|
|
entry->info = *info;
|
|
|
|
|
|
|
|
/* add to the hash list */
|
|
|
|
entry->next_ip = serverlist_ip[hash];
|
|
|
|
serverlist_ip[hash] = entry;
|
|
|
|
|
2007-09-30 11:48:06 +00:00
|
|
|
if(num_servers == num_server_capacity)
|
2007-09-27 23:55:59 +00:00
|
|
|
{
|
2007-09-30 11:48:06 +00:00
|
|
|
num_server_capacity += 100;
|
|
|
|
SERVERENTRY **newlist = mem_alloc(num_server_capacity*sizeof(SERVERENTRY*), 1);
|
2007-09-27 23:55:59 +00:00
|
|
|
memcpy(newlist, serverlist, num_servers*sizeof(SERVERENTRY*));
|
|
|
|
mem_free(serverlist);
|
|
|
|
serverlist = newlist;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add to list */
|
|
|
|
serverlist[num_servers] = entry;
|
2007-09-30 11:48:06 +00:00
|
|
|
entry->info.server_index = num_servers;
|
2007-09-27 23:55:59 +00:00
|
|
|
num_servers++;
|
|
|
|
|
|
|
|
/* */
|
|
|
|
if(request)
|
|
|
|
{
|
|
|
|
/* add it to the list of servers that we should request info from */
|
|
|
|
entry->prev_req = last_req_server;
|
|
|
|
if(last_req_server)
|
|
|
|
last_req_server->next_req = entry;
|
|
|
|
else
|
|
|
|
first_req_server = entry;
|
|
|
|
last_req_server = entry;
|
2007-09-30 11:48:06 +00:00
|
|
|
|
|
|
|
num_requests++;
|
2007-09-27 23:55:59 +00:00
|
|
|
}
|
2007-09-29 13:16:00 +00:00
|
|
|
|
|
|
|
client_serverbrowse_sort();
|
2007-07-21 18:07:27 +00:00
|
|
|
}
|
|
|
|
|
2007-07-23 21:21:30 +00:00
|
|
|
void client_serverbrowse_refresh(int lan)
|
2007-07-22 09:15:34 +00:00
|
|
|
{
|
2007-09-27 23:55:59 +00:00
|
|
|
/* clear out everything */
|
|
|
|
if(serverlist_heap)
|
|
|
|
memheap_destroy(serverlist_heap);
|
|
|
|
serverlist_heap = memheap_create();
|
|
|
|
num_servers = 0;
|
2007-09-30 11:48:06 +00:00
|
|
|
num_sorted_servers = 0;
|
2007-09-27 23:55:59 +00:00
|
|
|
mem_zero(serverlist_ip, sizeof(serverlist_ip));
|
|
|
|
first_req_server = 0;
|
|
|
|
last_req_server = 0;
|
2007-09-30 11:48:06 +00:00
|
|
|
num_requests = 0;
|
|
|
|
|
2007-09-27 23:55:59 +00:00
|
|
|
|
|
|
|
/* */
|
2007-07-23 21:21:30 +00:00
|
|
|
serverlist_lan = lan;
|
|
|
|
|
2007-07-22 09:15:34 +00:00
|
|
|
if(serverlist_lan)
|
|
|
|
{
|
2007-08-14 18:37:16 +00:00
|
|
|
if(config.debug)
|
|
|
|
dbg_msg("client", "broadcasting for servers");
|
2007-07-22 09:15:34 +00:00
|
|
|
NETPACKET packet;
|
|
|
|
packet.client_id = -1;
|
2007-08-14 18:37:16 +00:00
|
|
|
mem_zero(&packet, sizeof(packet));
|
2007-07-22 09:15:34 +00:00
|
|
|
packet.address.ip[0] = 0;
|
|
|
|
packet.address.ip[1] = 0;
|
|
|
|
packet.address.ip[2] = 0;
|
|
|
|
packet.address.ip[3] = 0;
|
|
|
|
packet.address.port = 8303;
|
|
|
|
packet.flags = PACKETFLAG_CONNLESS;
|
|
|
|
packet.data_size = sizeof(SERVERBROWSE_GETINFO);
|
|
|
|
packet.data = SERVERBROWSE_GETINFO;
|
2007-08-22 07:52:33 +00:00
|
|
|
netclient_send(net, &packet);
|
2007-07-22 09:15:34 +00:00
|
|
|
|
|
|
|
// reset the list
|
2007-09-27 23:55:59 +00:00
|
|
|
//servers.num = 0;
|
2007-07-22 09:15:34 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-08-14 18:37:16 +00:00
|
|
|
if(config.debug)
|
|
|
|
dbg_msg("client", "requesting server list");
|
2007-07-22 09:15:34 +00:00
|
|
|
NETPACKET packet;
|
2007-08-14 18:37:16 +00:00
|
|
|
mem_zero(&packet, sizeof(packet));
|
2007-07-22 09:15:34 +00:00
|
|
|
packet.client_id = -1;
|
|
|
|
packet.address = master_server;
|
|
|
|
packet.flags = PACKETFLAG_CONNLESS;
|
|
|
|
packet.data_size = sizeof(SERVERBROWSE_GETLIST);
|
|
|
|
packet.data = SERVERBROWSE_GETLIST;
|
2007-08-22 07:52:33 +00:00
|
|
|
netclient_send(net, &packet);
|
2007-07-22 09:15:34 +00:00
|
|
|
|
|
|
|
// reset the list
|
2007-09-27 23:55:59 +00:00
|
|
|
//servers.num = 0;
|
2007-07-22 09:15:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-30 19:46:31 +00:00
|
|
|
|
2007-09-27 23:55:59 +00:00
|
|
|
static void client_serverbrowse_request(SERVERENTRY *entry)
|
2007-07-30 19:46:31 +00:00
|
|
|
{
|
2007-08-14 18:37:16 +00:00
|
|
|
if(config.debug)
|
|
|
|
{
|
|
|
|
dbg_msg("client", "requesting server info from %d.%d.%d.%d:%d",
|
2007-09-27 23:55:59 +00:00
|
|
|
entry->addr.ip[0], entry->addr.ip[1], entry->addr.ip[2],
|
|
|
|
entry->addr.ip[3], entry->addr.port);
|
2007-08-14 18:37:16 +00:00
|
|
|
}
|
2007-09-27 23:55:59 +00:00
|
|
|
|
|
|
|
NETPACKET p;
|
|
|
|
p.client_id = -1;
|
|
|
|
p.address = entry->addr;
|
|
|
|
p.flags = PACKETFLAG_CONNLESS;
|
|
|
|
p.data_size = sizeof(SERVERBROWSE_GETINFO);
|
|
|
|
p.data = SERVERBROWSE_GETINFO;
|
|
|
|
netclient_send(net, &p);
|
|
|
|
entry->request_time = time_get();
|
2007-07-30 19:46:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void client_serverbrowse_update()
|
|
|
|
{
|
|
|
|
int64 timeout = time_freq();
|
|
|
|
int64 now = time_get();
|
2007-09-27 23:55:59 +00:00
|
|
|
int count;
|
2007-07-30 19:46:31 +00:00
|
|
|
|
2007-09-27 23:55:59 +00:00
|
|
|
SERVERENTRY *entry, *next;
|
|
|
|
|
|
|
|
/* do timeouts */
|
|
|
|
entry = first_req_server;
|
|
|
|
while(1)
|
|
|
|
{
|
|
|
|
if(!entry) // no more entries
|
|
|
|
break;
|
|
|
|
|
|
|
|
next = entry->next_req;
|
|
|
|
|
|
|
|
if(entry->request_time && entry->request_time+timeout < now)
|
|
|
|
{
|
|
|
|
/* timeout */
|
2007-09-30 11:48:06 +00:00
|
|
|
client_serverbrowse_remove_request(entry);
|
|
|
|
num_requests--;
|
2007-09-27 23:55:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
entry = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* do timeouts */
|
|
|
|
entry = first_req_server;
|
|
|
|
count = 0;
|
|
|
|
while(1)
|
|
|
|
{
|
|
|
|
if(!entry) // no more entries
|
|
|
|
break;
|
|
|
|
|
2007-09-30 11:48:06 +00:00
|
|
|
if(count == config.b_max_requests) // no more then 10 concurrent requests
|
2007-09-27 23:55:59 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
if(entry->request_time == 0)
|
|
|
|
client_serverbrowse_request(entry);
|
|
|
|
|
|
|
|
count++;
|
|
|
|
entry = entry->next_req;
|
|
|
|
}
|
2007-09-30 11:48:06 +00:00
|
|
|
|
|
|
|
/* check if we need to resort */
|
|
|
|
if(sorthash != client_serverbrowse_sorthash())
|
|
|
|
client_serverbrowse_sort();
|
2007-07-30 19:46:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ------ state handling -----
|
2007-07-21 18:07:27 +00:00
|
|
|
static int state;
|
2007-08-04 18:23:26 +00:00
|
|
|
int client_state() { return state; }
|
2007-07-30 19:46:31 +00:00
|
|
|
static void client_set_state(int s)
|
2007-07-21 18:07:27 +00:00
|
|
|
{
|
2007-08-14 18:37:16 +00:00
|
|
|
if(config.debug)
|
|
|
|
dbg_msg("client", "state change. last=%d current=%d", state, s);
|
2007-08-04 18:23:26 +00:00
|
|
|
int old = state;
|
2007-07-21 18:07:27 +00:00
|
|
|
state = s;
|
2007-08-04 18:23:26 +00:00
|
|
|
if(old != s)
|
|
|
|
modc_statechange(state, old);
|
2007-07-21 18:07:27 +00:00
|
|
|
}
|
|
|
|
|
2007-09-23 22:54:31 +00:00
|
|
|
/* called when the map is loaded and we should init for a new round */
|
|
|
|
static void client_on_enter_game()
|
|
|
|
{
|
|
|
|
// reset input
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < 200; i++)
|
|
|
|
inputs[i].tick = -1;
|
|
|
|
current_input = 0;
|
|
|
|
|
|
|
|
// reset snapshots
|
|
|
|
snapshots[SNAP_CURRENT] = 0;
|
|
|
|
snapshots[SNAP_PREV] = 0;
|
|
|
|
snapstorage_purge_all(&snapshot_storage);
|
|
|
|
recived_snapshots = 0;
|
|
|
|
current_predtick = 0;
|
|
|
|
current_recv_tick = 0;
|
|
|
|
}
|
2007-07-21 18:07:27 +00:00
|
|
|
|
|
|
|
void client_connect(const char *server_address_str)
|
|
|
|
{
|
2007-07-22 09:15:34 +00:00
|
|
|
dbg_msg("client", "connecting to '%s'", server_address_str);
|
2007-07-21 18:07:27 +00:00
|
|
|
char buf[512];
|
|
|
|
strncpy(buf, server_address_str, 512);
|
|
|
|
|
|
|
|
const char *port_str = 0;
|
2007-08-22 07:52:33 +00:00
|
|
|
int k;
|
|
|
|
for(k = 0; buf[k]; k++)
|
2007-07-21 18:07:27 +00:00
|
|
|
{
|
|
|
|
if(buf[k] == ':')
|
|
|
|
{
|
|
|
|
port_str = &(buf[k+1]);
|
|
|
|
buf[k] = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int port = 8303;
|
|
|
|
if(port_str)
|
|
|
|
port = atoi(port_str);
|
|
|
|
|
|
|
|
if(net_host_lookup(buf, port, &server_address) != 0)
|
|
|
|
dbg_msg("client", "could not find the address of %s, connecting to localhost", buf);
|
|
|
|
|
2007-08-22 07:52:33 +00:00
|
|
|
netclient_connect(net, &server_address);
|
2007-08-04 18:23:26 +00:00
|
|
|
client_set_state(CLIENTSTATE_CONNECTING);
|
2007-07-22 11:53:15 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-30 19:46:31 +00:00
|
|
|
void client_disconnect()
|
2007-07-22 11:53:15 +00:00
|
|
|
{
|
2007-07-30 19:46:31 +00:00
|
|
|
client_send_error("disconnected");
|
2007-08-22 07:52:33 +00:00
|
|
|
netclient_disconnect(net, "disconnected");
|
2007-08-04 18:23:26 +00:00
|
|
|
client_set_state(CLIENTSTATE_OFFLINE);
|
2007-07-22 11:53:15 +00:00
|
|
|
map_unload();
|
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-08-22 07:52:33 +00:00
|
|
|
static int client_load_data()
|
2007-07-22 11:53:15 +00:00
|
|
|
{
|
|
|
|
debug_font = gfx_load_texture("data/debug_font.png");
|
2007-08-22 07:52:33 +00:00
|
|
|
return 1;
|
2007-07-22 11:53:15 +00:00
|
|
|
}
|
2007-07-30 19:46:31 +00:00
|
|
|
|
|
|
|
static void client_debug_render()
|
2007-07-22 11:53:15 +00:00
|
|
|
{
|
2007-07-26 19:09:31 +00:00
|
|
|
if(!config.debug)
|
|
|
|
return;
|
|
|
|
|
2007-07-22 11:53:15 +00:00
|
|
|
gfx_blend_normal();
|
|
|
|
gfx_texture_set(debug_font);
|
|
|
|
gfx_mapscreen(0,0,gfx_screenwidth(),gfx_screenheight());
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-22 11:53:15 +00:00
|
|
|
static NETSTATS prev, current;
|
|
|
|
static int64 last_snap = 0;
|
|
|
|
if(time_get()-last_snap > time_freq()/10)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-22 11:53:15 +00:00
|
|
|
last_snap = time_get();
|
|
|
|
prev = current;
|
2007-08-22 07:52:33 +00:00
|
|
|
netclient_stats(net, ¤t);
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-29 13:21:33 +00:00
|
|
|
static float frametime_avg = 0;
|
|
|
|
frametime_avg = frametime_avg*0.9f + frametime*0.1f;
|
2007-07-22 11:53:15 +00:00
|
|
|
char buffer[512];
|
2007-09-23 18:27:04 +00:00
|
|
|
sprintf(buffer, "ticks: %8d %8d send: %6d recv: %6d snaploss: %d %c mem %dk gfxmem: %dk fps: %3d",
|
|
|
|
current_tick, current_predtick,
|
2007-07-22 11:53:15 +00:00
|
|
|
(current.send_bytes-prev.send_bytes)*10,
|
2007-07-26 19:09:31 +00:00
|
|
|
(current.recv_bytes-prev.recv_bytes)*10,
|
2007-08-14 18:37:16 +00:00
|
|
|
snaploss,
|
2007-09-23 18:27:04 +00:00
|
|
|
extra_polating?'E':' ',
|
2007-08-25 08:48:24 +00:00
|
|
|
mem_allocated()/1024,
|
2007-07-30 19:46:31 +00:00
|
|
|
gfx_memory_usage()/1024,
|
|
|
|
(int)(1.0f/frametime_avg));
|
2007-07-29 13:21:33 +00:00
|
|
|
gfx_quads_text(2, 2, 16, buffer);
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-09-23 18:27:04 +00:00
|
|
|
|
|
|
|
// render graphs
|
|
|
|
gfx_mapscreen(0,0,400.0f,300.0f);
|
|
|
|
graph_render(&game_time.graph, 300, 10, 90, 50);
|
|
|
|
graph_render(&predicted_time.graph, 300, 10+50+10, 90, 50);
|
|
|
|
graph_render(&intra_graph, 300, 10+50+10+50+10, 90, 50);
|
2007-07-22 11:53:15 +00:00
|
|
|
}
|
|
|
|
|
2007-08-04 18:23:26 +00:00
|
|
|
void client_quit()
|
2007-07-22 11:53:15 +00:00
|
|
|
{
|
2007-08-04 18:23:26 +00:00
|
|
|
client_set_state(CLIENTSTATE_QUITING);
|
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-08-04 18:23:26 +00:00
|
|
|
const char *client_error_string()
|
|
|
|
{
|
2007-08-22 07:52:33 +00:00
|
|
|
return netclient_error_string(net);
|
2007-08-04 18:23:26 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-08-04 18:23:26 +00:00
|
|
|
static void client_render()
|
|
|
|
{
|
|
|
|
gfx_clear(0.0f,0.0f,0.0f);
|
|
|
|
modc_render();
|
|
|
|
client_debug_render();
|
2007-07-22 11:53:15 +00:00
|
|
|
}
|
|
|
|
|
2007-07-30 19:46:31 +00:00
|
|
|
static void client_error(const char *msg)
|
2007-07-22 11:53:15 +00:00
|
|
|
{
|
2007-08-14 18:37:16 +00:00
|
|
|
dbg_msg("client", "error: %s", msg);
|
2007-07-30 19:46:31 +00:00
|
|
|
client_send_error(msg);
|
2007-08-04 18:23:26 +00:00
|
|
|
client_set_state(CLIENTSTATE_QUITING);
|
2007-07-30 19:46:31 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-30 19:46:31 +00:00
|
|
|
static void client_process_packet(NETPACKET *packet)
|
|
|
|
{
|
|
|
|
if(packet->client_id == -1)
|
|
|
|
{
|
|
|
|
// connectionlesss
|
|
|
|
if(packet->data_size >= (int)sizeof(SERVERBROWSE_LIST) &&
|
|
|
|
memcmp(packet->data, SERVERBROWSE_LIST, sizeof(SERVERBROWSE_LIST)) == 0)
|
|
|
|
{
|
2007-09-27 23:55:59 +00:00
|
|
|
int size = packet->data_size-sizeof(SERVERBROWSE_LIST);
|
|
|
|
int num = size/sizeof(NETADDR4);
|
|
|
|
NETADDR4 *addrs = (NETADDR4 *)((char*)packet->data+sizeof(SERVERBROWSE_LIST));
|
|
|
|
|
|
|
|
int i;
|
|
|
|
for(i = 0; i < num; i++)
|
|
|
|
{
|
|
|
|
NETADDR4 addr = addrs[i];
|
|
|
|
SERVER_INFO info = {0};
|
2007-09-30 11:48:06 +00:00
|
|
|
|
|
|
|
#if defined(CONF_ARCH_ENDIAN_BIG)
|
|
|
|
const char *tmp = (const char *)&addr.port;
|
|
|
|
addr.port = (tmp[1]<<8) | tmp[0];
|
|
|
|
#endif
|
2007-09-27 23:55:59 +00:00
|
|
|
|
|
|
|
info.latency = 999;
|
|
|
|
sprintf(info.address, "%d.%d.%d.%d:%d",
|
|
|
|
addr.ip[0], addr.ip[1], addr.ip[2],
|
|
|
|
addr.ip[3], addr.port);
|
2007-09-30 11:48:06 +00:00
|
|
|
sprintf(info.name, "\255%d.%d.%d.%d:%d", /* the \255 is to make sure that it's sorted last */
|
2007-09-27 23:55:59 +00:00
|
|
|
addr.ip[0], addr.ip[1], addr.ip[2],
|
|
|
|
addr.ip[3], addr.port);
|
|
|
|
|
|
|
|
client_serverbrowse_set(addrs+i, 1, &info);
|
|
|
|
}
|
2007-07-30 19:46:31 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-30 19:46:31 +00:00
|
|
|
if(packet->data_size >= (int)sizeof(SERVERBROWSE_INFO) &&
|
|
|
|
memcmp(packet->data, SERVERBROWSE_INFO, sizeof(SERVERBROWSE_INFO)) == 0)
|
2007-07-26 19:09:31 +00:00
|
|
|
{
|
2007-07-30 19:46:31 +00:00
|
|
|
// we got ze info
|
2007-08-22 07:52:33 +00:00
|
|
|
UNPACKER up;
|
|
|
|
unpacker_reset(&up, (unsigned char*)packet->data+sizeof(SERVERBROWSE_INFO), packet->data_size-sizeof(SERVERBROWSE_INFO));
|
2007-09-27 23:55:59 +00:00
|
|
|
SERVER_INFO info = {0};
|
|
|
|
|
|
|
|
strncpy(info.version, unpacker_get_string(&up), 32);
|
|
|
|
strncpy(info.name, unpacker_get_string(&up), 64);
|
|
|
|
strncpy(info.map, unpacker_get_string(&up), 32);
|
|
|
|
info.game_type = atol(unpacker_get_string(&up));
|
|
|
|
info.flags = atol(unpacker_get_string(&up));
|
|
|
|
info.progression = atol(unpacker_get_string(&up));
|
|
|
|
info.num_players = atol(unpacker_get_string(&up));
|
|
|
|
info.max_players = atol(unpacker_get_string(&up));
|
2007-07-30 19:46:31 +00:00
|
|
|
|
2007-09-27 23:55:59 +00:00
|
|
|
int i;
|
|
|
|
for(i = 0; i < info.num_players; i++)
|
2007-07-21 18:07:27 +00:00
|
|
|
{
|
2007-09-27 23:55:59 +00:00
|
|
|
strncpy(info.player_names[i], unpacker_get_string(&up), 48);
|
|
|
|
info.player_scores[i] = atol(unpacker_get_string(&up));
|
2007-07-22 11:53:15 +00:00
|
|
|
}
|
2007-09-27 23:55:59 +00:00
|
|
|
|
|
|
|
/* TODO: unpack players aswell */
|
|
|
|
client_serverbrowse_set(&packet->address, 0, &info);
|
2007-07-22 11:53:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
|
|
|
|
int sys;
|
|
|
|
int msg = msg_unpack_start(packet->data, packet->data_size, &sys);
|
|
|
|
if(sys)
|
|
|
|
{
|
|
|
|
// system message
|
|
|
|
if(msg == NETMSG_MAP)
|
|
|
|
{
|
|
|
|
const char *map = msg_unpack_string();
|
|
|
|
dbg_msg("client/network", "connection accepted, map=%s", map);
|
2007-08-04 18:23:26 +00:00
|
|
|
client_set_state(CLIENTSTATE_LOADING);
|
2007-07-22 11:53:15 +00:00
|
|
|
|
|
|
|
if(map_load(map))
|
|
|
|
{
|
|
|
|
modc_entergame();
|
2007-07-30 19:46:31 +00:00
|
|
|
client_send_entergame();
|
2007-07-22 11:53:15 +00:00
|
|
|
dbg_msg("client/network", "loading done");
|
|
|
|
// now we will wait for two snapshots
|
|
|
|
// to finish the connection
|
2007-09-23 22:54:31 +00:00
|
|
|
|
|
|
|
client_on_enter_game();
|
2007-07-22 11:53:15 +00:00
|
|
|
}
|
2007-07-22 09:15:34 +00:00
|
|
|
else
|
|
|
|
{
|
2007-07-30 19:46:31 +00:00
|
|
|
client_error("failure to load map");
|
2007-07-14 13:09:42 +00:00
|
|
|
}
|
2007-07-13 13:40:04 +00:00
|
|
|
}
|
2007-09-23 22:54:31 +00:00
|
|
|
else if(msg == NETMSG_SNAP || msg == NETMSG_SNAPEMPTY)
|
2007-07-13 13:40:04 +00:00
|
|
|
{
|
2007-07-22 11:53:15 +00:00
|
|
|
//dbg_msg("client/network", "got snapshot");
|
|
|
|
int game_tick = msg_unpack_int();
|
|
|
|
int delta_tick = game_tick-msg_unpack_int();
|
2007-09-09 18:21:14 +00:00
|
|
|
int input_predtick = msg_unpack_int();
|
|
|
|
int time_left = msg_unpack_int();
|
2007-07-22 11:53:15 +00:00
|
|
|
int num_parts = 1;
|
|
|
|
int part = 0;
|
|
|
|
int part_size = 0;
|
2007-09-09 18:21:14 +00:00
|
|
|
int crc = 0;
|
2007-07-22 11:53:15 +00:00
|
|
|
|
|
|
|
if(msg != NETMSG_SNAPEMPTY)
|
2007-08-22 21:21:20 +00:00
|
|
|
{
|
|
|
|
crc = msg_unpack_int();
|
2007-07-22 11:53:15 +00:00
|
|
|
part_size = msg_unpack_int();
|
2007-08-22 21:21:20 +00:00
|
|
|
}
|
2007-07-22 11:53:15 +00:00
|
|
|
|
2007-09-09 18:21:14 +00:00
|
|
|
/* 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)
|
|
|
|
{
|
2007-09-23 18:27:04 +00:00
|
|
|
//-1000/50
|
|
|
|
int64 target = inputs[k].game_time + (time_get() - inputs[k].time);
|
2007-09-25 21:53:14 +00:00
|
|
|
st_update(&predicted_time, target - (int64)(((time_left-prediction_margin)/1000.0f)*time_freq()));
|
2007-09-09 18:21:14 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(snapshot_part == part && game_tick > current_recv_tick)
|
2007-07-14 13:09:42 +00:00
|
|
|
{
|
2007-07-22 11:53:15 +00:00
|
|
|
// TODO: clean this up abit
|
|
|
|
const char *d = (const char *)msg_unpack_raw(part_size);
|
2007-07-26 19:09:31 +00:00
|
|
|
mem_copy((char*)snapshot_incomming_data + part*MAX_SNAPSHOT_PACKSIZE, d, part_size);
|
2007-07-22 11:53:15 +00:00
|
|
|
snapshot_part++;
|
|
|
|
|
|
|
|
if(snapshot_part == num_parts)
|
2007-07-21 18:07:27 +00:00
|
|
|
{
|
2007-08-14 18:37:16 +00:00
|
|
|
snapshot_part = 0;
|
|
|
|
|
2007-07-22 11:53:15 +00:00
|
|
|
// find snapshot that we should use as delta
|
2007-08-22 07:52:33 +00:00
|
|
|
static SNAPSHOT emptysnap;
|
2007-07-22 11:53:15 +00:00
|
|
|
emptysnap.data_size = 0;
|
|
|
|
emptysnap.num_items = 0;
|
|
|
|
|
2007-08-22 07:52:33 +00:00
|
|
|
SNAPSHOT *deltashot = &emptysnap;
|
2007-08-14 18:37:16 +00:00
|
|
|
|
|
|
|
// find delta
|
2007-07-22 11:53:15 +00:00
|
|
|
if(delta_tick >= 0)
|
|
|
|
{
|
2007-08-22 07:52:33 +00:00
|
|
|
int deltashot_size = snapstorage_get(&snapshot_storage, delta_tick, 0, &deltashot);
|
|
|
|
|
|
|
|
if(deltashot_size < 0)
|
2007-07-14 13:09:42 +00:00
|
|
|
{
|
2007-08-14 18:37:16 +00:00
|
|
|
// couldn't find the delta snapshots that the server used
|
|
|
|
// to compress this snapshot. force the server to resync
|
|
|
|
if(config.debug)
|
|
|
|
dbg_msg("client", "error, couldn't find the delta snapshot");
|
|
|
|
|
|
|
|
// ack snapshot
|
2007-09-09 18:21:14 +00:00
|
|
|
// TODO: combine this with the input message
|
2007-09-23 18:27:04 +00:00
|
|
|
ack_game_tick = -1;
|
2007-08-14 18:37:16 +00:00
|
|
|
return;
|
2007-07-14 13:09:42 +00:00
|
|
|
}
|
2007-07-13 13:40:04 +00:00
|
|
|
}
|
2007-07-29 22:09:15 +00:00
|
|
|
|
2007-08-14 18:37:16 +00:00
|
|
|
// decompress snapshot
|
|
|
|
void *deltadata = snapshot_empty_delta();
|
|
|
|
int deltasize = sizeof(int)*3;
|
|
|
|
|
|
|
|
unsigned char tmpbuffer[MAX_SNAPSHOT_SIZE];
|
|
|
|
unsigned char tmpbuffer2[MAX_SNAPSHOT_SIZE];
|
|
|
|
if(part_size)
|
|
|
|
{
|
|
|
|
int compsize = zerobit_decompress(snapshot_incomming_data, part_size, tmpbuffer);
|
|
|
|
int intsize = intpack_decompress(tmpbuffer, compsize, tmpbuffer2);
|
|
|
|
deltadata = tmpbuffer2;
|
|
|
|
deltasize = intsize;
|
|
|
|
}
|
|
|
|
|
2007-07-29 22:09:15 +00:00
|
|
|
//dbg_msg("UNPACK", "%d unpacked with %d", game_tick, delta_tick);
|
2007-07-26 19:09:31 +00:00
|
|
|
|
|
|
|
unsigned char tmpbuffer3[MAX_SNAPSHOT_SIZE];
|
2007-08-22 07:52:33 +00:00
|
|
|
int snapsize = snapshot_unpack_delta(deltashot, (SNAPSHOT*)tmpbuffer3, deltadata, deltasize);
|
2007-09-23 18:27:04 +00:00
|
|
|
if(msg != NETMSG_SNAPEMPTY && snapshot_crc((SNAPSHOT*)tmpbuffer3) != crc)
|
2007-08-22 21:21:20 +00:00
|
|
|
{
|
|
|
|
if(config.debug)
|
2007-09-23 22:54:31 +00:00
|
|
|
dbg_msg("client", "snapshot crc error %d", snapcrcerrors);
|
2007-08-22 21:21:20 +00:00
|
|
|
snapcrcerrors++;
|
2007-09-23 22:54:31 +00:00
|
|
|
if(snapcrcerrors > 10)
|
2007-08-22 21:21:20 +00:00
|
|
|
{
|
|
|
|
// to many errors, send reset
|
2007-09-23 18:27:04 +00:00
|
|
|
ack_game_tick = -1;
|
2007-09-23 22:54:31 +00:00
|
|
|
client_send_input();
|
2007-08-22 21:21:20 +00:00
|
|
|
snapcrcerrors = 0;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(snapcrcerrors)
|
|
|
|
snapcrcerrors--;
|
|
|
|
}
|
2007-07-26 19:09:31 +00:00
|
|
|
|
|
|
|
// purge old snapshots
|
|
|
|
int purgetick = delta_tick;
|
|
|
|
if(snapshots[SNAP_PREV] && snapshots[SNAP_PREV]->tick < purgetick)
|
|
|
|
purgetick = snapshots[SNAP_PREV]->tick;
|
|
|
|
if(snapshots[SNAP_CURRENT] && snapshots[SNAP_CURRENT]->tick < purgetick)
|
|
|
|
purgetick = snapshots[SNAP_PREV]->tick;
|
2007-08-22 07:52:33 +00:00
|
|
|
snapstorage_purge_until(&snapshot_storage, purgetick);
|
2007-07-26 19:09:31 +00:00
|
|
|
//client_snapshot_purge_until(game_tick-50);
|
2007-07-22 11:53:15 +00:00
|
|
|
|
|
|
|
// add new
|
2007-08-22 07:52:33 +00:00
|
|
|
snapstorage_add(&snapshot_storage, game_tick, time_get(), snapsize, (SNAPSHOT*)tmpbuffer3);
|
|
|
|
//SNAPSTORAGE_HOLDER *snap = client_snapshot_add(game_tick, time_get(), tmpbuffer3, snapsize);
|
2007-07-22 11:53:15 +00:00
|
|
|
|
2007-07-29 22:09:15 +00:00
|
|
|
//int ncrc = snapshot_crc((snapshot*)tmpbuffer3);
|
|
|
|
//if(crc != ncrc)
|
2007-07-30 19:46:31 +00:00
|
|
|
// dbg_msg("client", "client snapshot crc failure %d %d", crc, ncrc);
|
2007-07-29 22:09:15 +00:00
|
|
|
|
2007-07-22 11:53:15 +00:00
|
|
|
// apply snapshot, cycle pointers
|
|
|
|
recived_snapshots++;
|
|
|
|
|
2007-08-14 18:37:16 +00:00
|
|
|
|
2007-09-09 18:21:14 +00:00
|
|
|
if(current_recv_tick > 0)
|
|
|
|
snaploss += game_tick-current_recv_tick-1;
|
|
|
|
current_recv_tick = game_tick;
|
2007-08-14 18:37:16 +00:00
|
|
|
|
2007-07-22 11:53:15 +00:00
|
|
|
// we got two snapshots until we see us self as connected
|
|
|
|
if(recived_snapshots == 2)
|
|
|
|
{
|
2007-09-23 18:27:04 +00:00
|
|
|
// start at 200ms and work from there
|
|
|
|
st_init(&predicted_time, (game_tick+10)*time_freq()/50);
|
2007-09-25 21:53:14 +00:00
|
|
|
st_init(&game_time, (game_tick-1)*time_freq()/50);
|
2007-08-22 07:52:33 +00:00
|
|
|
snapshots[SNAP_PREV] = snapshot_storage.first;
|
|
|
|
snapshots[SNAP_CURRENT] = snapshot_storage.last;
|
2007-07-22 11:53:15 +00:00
|
|
|
local_start_time = time_get();
|
2007-08-04 18:23:26 +00:00
|
|
|
client_set_state(CLIENTSTATE_ONLINE);
|
2007-07-22 11:53:15 +00:00
|
|
|
}
|
2007-09-23 18:27:04 +00:00
|
|
|
|
2007-09-25 21:53:14 +00:00
|
|
|
st_update(&game_time, (game_tick-1)*time_freq()/50);
|
2007-07-26 19:09:31 +00:00
|
|
|
|
2007-07-22 11:53:15 +00:00
|
|
|
// ack snapshot
|
2007-09-23 18:27:04 +00:00
|
|
|
ack_game_tick = game_tick;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
2007-07-14 13:09:42 +00:00
|
|
|
}
|
2007-07-22 11:53:15 +00:00
|
|
|
else
|
|
|
|
{
|
2007-09-23 18:27:04 +00:00
|
|
|
dbg_msg("client", "snapsht reset!");
|
2007-07-22 11:53:15 +00:00
|
|
|
snapshot_part = 0;
|
|
|
|
}
|
2007-07-21 18:07:27 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
2007-07-22 11:53:15 +00:00
|
|
|
else
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-22 11:53:15 +00:00
|
|
|
// game message
|
|
|
|
modc_message(msg);
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
2007-07-22 11:53:15 +00:00
|
|
|
}
|
|
|
|
}
|
2007-07-13 13:40:04 +00:00
|
|
|
|
2007-07-30 19:46:31 +00:00
|
|
|
static void client_pump_network()
|
2007-07-22 11:53:15 +00:00
|
|
|
{
|
2007-08-22 07:52:33 +00:00
|
|
|
netclient_update(net);
|
2007-07-22 11:53:15 +00:00
|
|
|
|
|
|
|
// check for errors
|
2007-08-22 07:52:33 +00:00
|
|
|
if(client_state() != CLIENTSTATE_OFFLINE && netclient_state(net) == NETSTATE_OFFLINE)
|
2007-07-22 11:53:15 +00:00
|
|
|
{
|
2007-08-04 18:23:26 +00:00
|
|
|
client_set_state(CLIENTSTATE_OFFLINE);
|
2007-08-22 07:52:33 +00:00
|
|
|
dbg_msg("client", "offline error='%s'", netclient_error_string(net));
|
2007-07-22 11:53:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
2007-08-22 07:52:33 +00:00
|
|
|
if(client_state() == CLIENTSTATE_CONNECTING && netclient_state(net) == NETSTATE_ONLINE)
|
2007-07-22 11:53:15 +00:00
|
|
|
{
|
|
|
|
// we switched to online
|
|
|
|
dbg_msg("client", "connected, sending info");
|
2007-08-04 18:23:26 +00:00
|
|
|
client_set_state(CLIENTSTATE_LOADING);
|
2007-07-30 19:46:31 +00:00
|
|
|
client_send_info();
|
2007-07-22 11:53:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// process packets
|
|
|
|
NETPACKET packet;
|
2007-08-22 07:52:33 +00:00
|
|
|
while(netclient_recv(net, &packet))
|
2007-07-30 19:46:31 +00:00
|
|
|
client_process_packet(&packet);
|
2007-07-22 11:53:15 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-30 19:46:31 +00:00
|
|
|
static void client_run(const char *direct_connect_server)
|
|
|
|
{
|
|
|
|
local_start_time = time_get();
|
|
|
|
snapshot_part = 0;
|
|
|
|
|
|
|
|
client_serverbrowse_init();
|
|
|
|
|
|
|
|
// init graphics and sound
|
|
|
|
if(!gfx_init())
|
|
|
|
return;
|
|
|
|
|
|
|
|
snd_init(); // sound is allowed to fail
|
|
|
|
|
|
|
|
// load data
|
|
|
|
if(!client_load_data())
|
|
|
|
return;
|
|
|
|
|
2007-08-14 18:37:16 +00:00
|
|
|
// init menu
|
|
|
|
modmenu_init(); // TODO: remove
|
|
|
|
|
2007-07-30 19:46:31 +00:00
|
|
|
// init the mod
|
|
|
|
modc_init();
|
2007-08-22 21:13:33 +00:00
|
|
|
dbg_msg("client", "version %s", modc_net_version());
|
2007-07-30 19:46:31 +00:00
|
|
|
|
|
|
|
// open socket
|
2007-08-05 14:19:13 +00:00
|
|
|
NETADDR4 bindaddr;
|
|
|
|
mem_zero(&bindaddr, sizeof(bindaddr));
|
2007-08-22 07:52:33 +00:00
|
|
|
net = netclient_open(bindaddr, 0);
|
2007-07-30 19:46:31 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
net_host_lookup(config.masterserver, MASTERSERVER_PORT, &master_server);
|
|
|
|
|
|
|
|
// connect to the server if wanted
|
|
|
|
if(direct_connect_server)
|
|
|
|
client_connect(direct_connect_server);
|
|
|
|
|
|
|
|
int64 reporttime = time_get();
|
|
|
|
int64 reportinterval = time_freq()*1;
|
|
|
|
int frames = 0;
|
|
|
|
|
2007-08-22 07:52:33 +00:00
|
|
|
inp_mouse_mode_relative();
|
2007-07-30 19:46:31 +00:00
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
frames++;
|
|
|
|
int64 frame_start_time = time_get();
|
|
|
|
|
|
|
|
// switch snapshot
|
|
|
|
if(recived_snapshots >= 3)
|
|
|
|
{
|
2007-09-09 18:21:14 +00:00
|
|
|
int repredict = 0;
|
2007-09-23 18:27:04 +00:00
|
|
|
//int64 now = time_get();
|
|
|
|
int64 now = st_get(&game_time, time_get());
|
2007-07-30 19:46:31 +00:00
|
|
|
while(1)
|
|
|
|
{
|
2007-08-22 07:52:33 +00:00
|
|
|
SNAPSTORAGE_HOLDER *cur = snapshots[SNAP_CURRENT];
|
2007-09-23 18:27:04 +00:00
|
|
|
int64 tickstart = (cur->tick)*time_freq()/50;
|
2007-07-30 19:46:31 +00:00
|
|
|
|
2007-09-23 18:27:04 +00:00
|
|
|
if(tickstart < now)
|
2007-07-30 19:46:31 +00:00
|
|
|
{
|
2007-08-22 07:52:33 +00:00
|
|
|
SNAPSTORAGE_HOLDER *next = snapshots[SNAP_CURRENT]->next;
|
2007-07-30 19:46:31 +00:00
|
|
|
if(next)
|
|
|
|
{
|
|
|
|
snapshots[SNAP_PREV] = snapshots[SNAP_CURRENT];
|
|
|
|
snapshots[SNAP_CURRENT] = next;
|
2007-09-09 18:21:14 +00:00
|
|
|
|
|
|
|
// set tick
|
|
|
|
current_tick = snapshots[SNAP_CURRENT]->tick;
|
|
|
|
|
2007-08-14 18:37:16 +00:00
|
|
|
if(snapshots[SNAP_CURRENT] && snapshots[SNAP_PREV])
|
2007-09-09 18:21:14 +00:00
|
|
|
{
|
2007-08-14 18:37:16 +00:00
|
|
|
modc_newsnapshot();
|
2007-09-09 18:21:14 +00:00
|
|
|
repredict = 1;
|
|
|
|
}
|
2007-07-30 19:46:31 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
extra_polating = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
extra_polating = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-09-23 18:27:04 +00:00
|
|
|
|
|
|
|
//tg_add(&game_time_graph, now, extra_polating);
|
2007-08-14 18:37:16 +00:00
|
|
|
|
|
|
|
if(snapshots[SNAP_CURRENT] && snapshots[SNAP_PREV])
|
|
|
|
{
|
2007-09-23 18:27:04 +00:00
|
|
|
int64 curtick_start = (snapshots[SNAP_CURRENT]->tick)*time_freq()/50;
|
|
|
|
int64 prevtick_start = (snapshots[SNAP_PREV]->tick)*time_freq()/50;
|
2007-08-14 18:37:16 +00:00
|
|
|
intratick = (now - prevtick_start) / (float)(curtick_start-prevtick_start);
|
2007-09-09 21:47:25 +00:00
|
|
|
|
2007-09-23 18:27:04 +00:00
|
|
|
graph_add(&intra_graph, intratick*0.25f);
|
2007-09-09 21:47:25 +00:00
|
|
|
|
2007-09-23 18:27:04 +00:00
|
|
|
int64 pred_now = st_get(&predicted_time, time_get());
|
|
|
|
//tg_add(&predicted_time_graph, pred_now, 0);
|
|
|
|
int prev_pred_tick = (int)(pred_now*50/time_freq());
|
|
|
|
int new_pred_tick = prev_pred_tick+1;
|
|
|
|
curtick_start = new_pred_tick*time_freq()/50;
|
|
|
|
prevtick_start = prev_pred_tick*time_freq()/50;
|
|
|
|
intrapredtick = (pred_now - prevtick_start) / (float)(curtick_start-prevtick_start);
|
2007-09-09 21:47:25 +00:00
|
|
|
|
2007-09-23 18:27:04 +00:00
|
|
|
if(new_pred_tick > current_predtick)
|
2007-09-09 18:21:14 +00:00
|
|
|
{
|
2007-09-23 18:27:04 +00:00
|
|
|
current_predtick = new_pred_tick;
|
2007-09-09 18:21:14 +00:00
|
|
|
repredict = 1;
|
|
|
|
|
|
|
|
// send input
|
|
|
|
client_send_input();
|
|
|
|
}
|
2007-07-30 19:46:31 +00:00
|
|
|
}
|
2007-09-09 18:21:14 +00:00
|
|
|
|
2007-09-09 21:47:25 +00:00
|
|
|
//intrapredtick = current_predtick
|
2007-09-23 18:27:04 +00:00
|
|
|
|
|
|
|
// only do sane predictions
|
2007-09-09 18:21:14 +00:00
|
|
|
if(repredict)
|
2007-09-23 18:27:04 +00:00
|
|
|
{
|
|
|
|
if(current_predtick > current_tick && current_predtick < current_tick+50)
|
|
|
|
modc_predict();
|
|
|
|
}
|
2007-07-30 19:46:31 +00:00
|
|
|
}
|
2007-09-09 18:21:14 +00:00
|
|
|
|
|
|
|
// STRESS TEST: join the server again
|
2007-08-14 18:37:16 +00:00
|
|
|
if(client_state() == CLIENTSTATE_OFFLINE && config.stress && (frames%100) == 0)
|
|
|
|
client_connect(config.cl_stress_server);
|
2007-07-30 19:46:31 +00:00
|
|
|
|
|
|
|
// update input
|
|
|
|
inp_update();
|
|
|
|
|
2007-08-07 18:28:51 +00:00
|
|
|
// refocus
|
|
|
|
if(!gfx_window_active())
|
|
|
|
{
|
|
|
|
if(window_must_refocus == 0)
|
2007-08-22 07:52:33 +00:00
|
|
|
inp_mouse_mode_absolute();
|
2007-08-07 18:28:51 +00:00
|
|
|
window_must_refocus = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(window_must_refocus && gfx_window_active())
|
|
|
|
{
|
|
|
|
if(window_must_refocus < 3)
|
|
|
|
{
|
2007-08-22 07:52:33 +00:00
|
|
|
inp_mouse_mode_absolute();
|
2007-08-07 18:28:51 +00:00
|
|
|
window_must_refocus++;
|
|
|
|
}
|
|
|
|
|
2007-08-22 07:52:33 +00:00
|
|
|
if(inp_key_pressed(KEY_MOUSE_1))
|
2007-08-07 18:28:51 +00:00
|
|
|
{
|
2007-08-22 07:52:33 +00:00
|
|
|
inp_mouse_mode_relative();
|
2007-08-07 18:28:51 +00:00
|
|
|
window_must_refocus = 0;
|
|
|
|
}
|
|
|
|
}
|
2007-07-30 19:46:31 +00:00
|
|
|
|
2007-08-04 09:20:59 +00:00
|
|
|
// screenshot button
|
2007-08-15 10:18:01 +00:00
|
|
|
if(inp_key_down(config.key_screenshot))
|
2007-08-04 09:20:59 +00:00
|
|
|
gfx_screenshot();
|
|
|
|
|
2007-07-30 19:46:31 +00:00
|
|
|
// panic button
|
2007-08-04 22:02:38 +00:00
|
|
|
if(config.debug)
|
2007-07-30 19:46:31 +00:00
|
|
|
{
|
2007-08-22 07:52:33 +00:00
|
|
|
if(inp_key_pressed(KEY_F1))
|
|
|
|
inp_mouse_mode_absolute();
|
|
|
|
if(inp_key_pressed(KEY_F2))
|
|
|
|
inp_mouse_mode_relative();
|
2007-08-07 18:28:51 +00:00
|
|
|
|
2007-08-22 07:52:33 +00:00
|
|
|
if(inp_key_pressed(KEY_LCTRL) && inp_key_pressed('Q'))
|
2007-08-04 22:02:38 +00:00
|
|
|
break;
|
|
|
|
|
2007-08-22 07:52:33 +00:00
|
|
|
if(inp_key_pressed(KEY_F5))
|
2007-08-04 22:02:38 +00:00
|
|
|
{
|
2007-09-23 18:27:04 +00:00
|
|
|
ack_game_tick = -1;
|
|
|
|
client_send_input();
|
|
|
|
/*
|
2007-08-04 22:02:38 +00:00
|
|
|
// ack snapshot
|
|
|
|
msg_pack_start_system(NETMSG_SNAPACK, 0);
|
|
|
|
msg_pack_int(-1);
|
|
|
|
msg_pack_end();
|
|
|
|
client_send_msg();
|
2007-09-23 18:27:04 +00:00
|
|
|
*/
|
2007-08-04 22:02:38 +00:00
|
|
|
}
|
2007-07-30 19:46:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// pump the network
|
|
|
|
client_pump_network();
|
|
|
|
|
|
|
|
// update the server browser
|
|
|
|
client_serverbrowse_update();
|
|
|
|
|
|
|
|
// render
|
2007-08-14 18:37:16 +00:00
|
|
|
if(config.stress)
|
|
|
|
{
|
|
|
|
if((frames%10) == 0)
|
|
|
|
{
|
|
|
|
client_render();
|
|
|
|
gfx_swap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
client_render();
|
|
|
|
gfx_swap();
|
|
|
|
}
|
2007-07-30 19:46:31 +00:00
|
|
|
|
|
|
|
// check conditions
|
2007-08-04 18:23:26 +00:00
|
|
|
if(client_state() == CLIENTSTATE_QUITING)
|
2007-07-30 19:46:31 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
// be nice
|
2007-08-07 18:28:51 +00:00
|
|
|
if(config.cpu_throttle || !gfx_window_active())
|
2007-07-30 19:46:31 +00:00
|
|
|
thread_sleep(1);
|
|
|
|
|
|
|
|
if(reporttime < time_get())
|
|
|
|
{
|
2007-08-14 18:37:16 +00:00
|
|
|
if(config.debug)
|
|
|
|
{
|
|
|
|
dbg_msg("client/report", "fps=%.02f netstate=%d",
|
2007-08-22 07:52:33 +00:00
|
|
|
frames/(float)(reportinterval/time_freq()), netclient_state(net));
|
2007-08-14 18:37:16 +00:00
|
|
|
}
|
2007-07-30 19:46:31 +00:00
|
|
|
frames = 0;
|
|
|
|
reporttime += reportinterval;
|
|
|
|
}
|
|
|
|
|
|
|
|
// update frametime
|
|
|
|
frametime = (time_get()-frame_start_time)/(float)time_freq();
|
|
|
|
}
|
|
|
|
|
|
|
|
modc_shutdown();
|
|
|
|
client_disconnect();
|
|
|
|
|
|
|
|
modmenu_shutdown(); // TODO: remove this
|
|
|
|
|
|
|
|
gfx_shutdown();
|
|
|
|
snd_shutdown();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-15 13:25:10 +00:00
|
|
|
int editor_main(int argc, char **argv);
|
|
|
|
|
2007-07-30 19:46:31 +00:00
|
|
|
//client main_client;
|
2007-07-22 11:53:15 +00:00
|
|
|
|
2007-05-24 20:54:08 +00:00
|
|
|
int main(int argc, char **argv)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
|
|
|
dbg_msg("client", "starting...");
|
2007-07-13 13:40:04 +00:00
|
|
|
|
2007-06-01 02:21:46 +00:00
|
|
|
config_reset();
|
2007-08-14 18:37:16 +00:00
|
|
|
|
2007-08-05 15:23:23 +00:00
|
|
|
#ifdef CONF_PLATFORM_MACOSX
|
2007-08-14 18:37:16 +00:00
|
|
|
const char *config_filename = "~/.teewars";
|
2007-08-05 15:23:23 +00:00
|
|
|
#else
|
2007-08-14 18:37:16 +00:00
|
|
|
const char *config_filename = "default.cfg";
|
2007-08-05 15:23:23 +00:00
|
|
|
#endif
|
2007-06-01 02:21:46 +00:00
|
|
|
|
2007-08-22 07:52:33 +00:00
|
|
|
int i;
|
|
|
|
for(i = 1; i < argc; i++)
|
2007-08-14 18:37:16 +00:00
|
|
|
{
|
|
|
|
if(argv[i][0] == '-' && argv[i][1] == 'f' && argv[i][2] == 0 && argc - i > 1)
|
|
|
|
{
|
|
|
|
config_filename = argv[i+1];
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
config_load(config_filename);
|
|
|
|
|
2007-07-21 18:07:27 +00:00
|
|
|
const char *direct_connect_server = 0x0;
|
2007-07-21 17:43:00 +00:00
|
|
|
snd_set_master_volume(config.volume / 255.0f);
|
2007-08-22 07:52:33 +00:00
|
|
|
int editor = 0;
|
2007-05-22 15:03:32 +00:00
|
|
|
|
|
|
|
// init network, need to be done first so we can do lookups
|
|
|
|
net_init();
|
|
|
|
|
|
|
|
// parse arguments
|
2007-08-22 07:52:33 +00:00
|
|
|
for(i = 1; i < argc; i++)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
|
|
|
if(argv[i][0] == '-' && argv[i][1] == 'c' && argv[i][2] == 0 && argc - i > 1)
|
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
// -c SERVER:PORT
|
2007-05-22 15:03:32 +00:00
|
|
|
i++;
|
2007-07-21 18:07:27 +00:00
|
|
|
direct_connect_server = argv[i];
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
2007-07-15 13:25:10 +00:00
|
|
|
else if(argv[i][0] == '-' && argv[i][1] == 'e' && argv[i][2] == 0)
|
|
|
|
{
|
2007-08-22 07:52:33 +00:00
|
|
|
editor = 1;
|
2007-07-15 13:25:10 +00:00
|
|
|
}
|
2007-08-14 18:37:16 +00:00
|
|
|
else
|
|
|
|
config_set(argv[i]);
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-15 13:25:10 +00:00
|
|
|
if(editor)
|
|
|
|
editor_main(argc, argv);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// start the client
|
2007-07-30 19:46:31 +00:00
|
|
|
client_run(direct_connect_server);
|
2007-07-15 13:25:10 +00:00
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
return 0;
|
|
|
|
}
|