ddnet/src/engine/client/client.c

980 lines
23 KiB
C
Raw Normal View History

2007-05-22 15:03:32 +00:00
#include <string.h>
2007-05-24 10:57:18 +00:00
#include <stdarg.h>
#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>
#include <engine/system.h>
#include <engine/interface.h>
2007-05-22 15:03:32 +00:00
#include "ui.h"
#include <engine/protocol.h>
#include <engine/snapshot.h>
2007-07-13 13:40:04 +00:00
#include <engine/compression.h>
#include <engine/network.h>
2007-06-01 11:17:10 +00:00
#include <engine/config.h>
#include <engine/packer.h>
2007-05-22 18:18:41 +00:00
#include <mastersrv/mastersrv.h>
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 int extra_polating = 0;
static int debug_font;
static float frametime = 0.0001f;
static NETCLIENT *net;
static NETADDR4 master_server;
static NETADDR4 server_address;
static int window_must_refocus = 0;
static int snaploss = 0;
static int current_tick = 0;
static float intratick = 0;
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
};
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-05-22 15:03:32 +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");
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
}
const void *snap_find_item(int snapid, int type, int id)
{
// TODO: linear search. should be fixed.
int i;
for(i = 0; i < snapshots[snapid]->snap->num_items; i++)
{
SNAPSHOT_ITEM *itm = snapshot_get_item(snapshots[snapid]->snap, i);
if(snapitem_type(itm) == type && snapitem_id(itm) == id)
return (void *)snapitem_data(itm);
}
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
}
static void snap_init()
{
2007-07-26 19:09:31 +00:00
snapshots[SNAP_CURRENT] = 0;
snapshots[SNAP_PREV] = 0;
2007-05-22 15:03:32 +00:00
recived_snapshots = 0;
2007-07-26 19:09:31 +00:00
game_start_time = -1;
2007-05-22 15:03:32 +00:00
}
// ------ time functions ------
2007-07-13 13:40:04 +00:00
float client_intratick()
2007-05-22 15:03:32 +00:00
{
return intratick;
2007-05-22 15:03:32 +00:00
}
2007-07-13 13:40:04 +00:00
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());
}
2007-05-22 15:03:32 +00:00
2007-07-13 13:40:04 +00:00
int menu_loop(); // TODO: what is this?
2007-05-24 10:57:18 +00:00
// ----- send functions -----
2007-07-13 13:40:04 +00:00
int client_send_msg()
2007-05-24 10:57:18 +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
netclient_send(net, &packet);
2007-07-13 13:40:04 +00:00
return 0;
2007-05-24 10:57:18 +00:00
}
static void client_send_info()
{
recived_snapshots = 0;
game_start_time = -1;
msg_pack_start_system(NETMSG_INFO, MSGFLAG_VITAL);
2007-08-22 21:13:33 +00:00
msg_pack_string(modc_net_version(), 128);
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);
*/
}
static void client_send_input()
{
msg_pack_start_system(NETMSG_INPUT, 0);
msg_pack_int(input_data_size);
int i;
for(i = 0; i < input_data_size/4; i++)
msg_pack_int(input_data[i]);
msg_pack_end();
client_send_msg();
}
// ------ server browse ----
static struct
{
SERVER_INFO infos[MAX_SERVERS];
int64 request_times[MAX_SERVERS];
NETADDR4 addresses[MAX_SERVERS];
int num;
} servers;
2007-07-22 09:15:34 +00:00
static int serverlist_lan = 1;
int client_serverbrowse_getlist(SERVER_INFO **serverlist)
{
*serverlist = servers.infos;
return servers.num;
}
static void client_serverbrowse_init()
{
servers.num = 0;
}
2007-07-23 21:21:30 +00:00
void client_serverbrowse_refresh(int lan)
2007-07-22 09:15:34 +00:00
{
2007-07-23 21:21:30 +00:00
serverlist_lan = lan;
2007-07-22 09:15:34 +00:00
if(serverlist_lan)
{
if(config.debug)
dbg_msg("client", "broadcasting for servers");
2007-07-22 09:15:34 +00:00
NETPACKET packet;
packet.client_id = -1;
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;
netclient_send(net, &packet);
2007-07-22 09:15:34 +00:00
// reset the list
servers.num = 0;
}
else
{
if(config.debug)
dbg_msg("client", "requesting server list");
2007-07-22 09:15:34 +00:00
NETPACKET packet;
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;
netclient_send(net, &packet);
2007-07-22 09:15:34 +00:00
// reset the list
servers.num = 0;
}
}
static void client_serverbrowse_request(int id)
{
if(config.debug)
{
dbg_msg("client", "requesting server info from %d.%d.%d.%d:%d",
servers.addresses[id].ip[0], servers.addresses[id].ip[1], servers.addresses[id].ip[2],
servers.addresses[id].ip[3], servers.addresses[id].port);
}
NETPACKET packet;
packet.client_id = -1;
packet.address = servers.addresses[id];
packet.flags = PACKETFLAG_CONNLESS;
packet.data_size = sizeof(SERVERBROWSE_GETINFO);
packet.data = SERVERBROWSE_GETINFO;
netclient_send(net, &packet);
servers.request_times[id] = time_get();
}
static void client_serverbrowse_update()
{
int64 timeout = time_freq();
int64 now = time_get();
int max_requests = 10;
// timeout old requests
while(info_request_begin < servers.num && info_request_begin < info_request_end)
{
if(now > servers.request_times[info_request_begin]+timeout)
info_request_begin++;
else
break;
}
// send new requests
while(info_request_end < servers.num && info_request_end-info_request_begin < max_requests)
{
client_serverbrowse_request(info_request_end);
info_request_end++;
}
}
// ------ state handling -----
static int state;
int client_state() { return state; }
static void client_set_state(int s)
{
if(config.debug)
dbg_msg("client", "state change. last=%d current=%d", state, s);
int old = state;
state = s;
if(old != s)
modc_statechange(state, old);
}
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);
char buf[512];
strncpy(buf, server_address_str, 512);
const char *port_str = 0;
int k;
for(k = 0; buf[k]; k++)
{
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);
netclient_connect(net, &server_address);
client_set_state(CLIENTSTATE_CONNECTING);
current_tick = 0;
2007-07-22 11:53:15 +00:00
}
2007-05-22 15:03:32 +00:00
void client_disconnect()
2007-07-22 11:53:15 +00:00
{
client_send_error("disconnected");
netclient_disconnect(net, "disconnected");
client_set_state(CLIENTSTATE_OFFLINE);
2007-07-22 11:53:15 +00:00
map_unload();
}
2007-05-22 15:03:32 +00:00
static int client_load_data()
2007-07-22 11:53:15 +00:00
{
debug_font = gfx_load_texture("data/debug_font.png");
return 1;
2007-07-22 11:53:15 +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;
netclient_stats(net, &current);
2007-05-22 15:03:32 +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];
sprintf(buffer, "send: %6d recv: %6d snaploss: %4d latency: %4.0f %c gfxmem: %6dk fps: %3d",
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,
snaploss,
latency*1000.0f, extra_polating?'E':' ',
gfx_memory_usage()/1024,
(int)(1.0f/frametime_avg));
gfx_quads_text(2, 2, 16, buffer);
2007-05-22 15:03:32 +00:00
2007-07-22 11:53:15 +00:00
}
void client_quit()
2007-07-22 11:53:15 +00:00
{
client_set_state(CLIENTSTATE_QUITING);
}
2007-05-22 15:03:32 +00:00
const char *client_error_string()
{
return netclient_error_string(net);
}
2007-05-22 15:03:32 +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
}
static void client_error(const char *msg)
2007-07-22 11:53:15 +00:00
{
dbg_msg("client", "error: %s", msg);
client_send_error(msg);
client_set_state(CLIENTSTATE_QUITING);
}
2007-05-22 15:03:32 +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)
{
// server listing
int size = packet->data_size-sizeof(SERVERBROWSE_LIST);
mem_copy(servers.addresses, (char*)packet->data+sizeof(SERVERBROWSE_LIST), size);
servers.num = size/sizeof(NETADDR4);
2007-07-22 11:53:15 +00:00
info_request_begin = 0;
info_request_end = 0;
2007-07-22 11:53:15 +00:00
int i;
for(i = 0; i < servers.num; i++)
{
servers.infos[i].num_players = 0;
servers.infos[i].max_players = 0;
servers.infos[i].latency = 999;
2007-08-06 17:52:17 +00:00
#if defined(CONF_ARCH_ENDIAN_BIG)
const char *tmp = (const char *)&servers.addresses[i].port;
servers.addresses[i].port = (tmp[1]<<8) | tmp[0];
#endif
sprintf(servers.infos[i].address, "%d.%d.%d.%d:%d",
servers.addresses[i].ip[0], servers.addresses[i].ip[1], servers.addresses[i].ip[2],
servers.addresses[i].ip[3], servers.addresses[i].port);
sprintf(servers.infos[i].name, "%d.%d.%d.%d:%d",
servers.addresses[i].ip[0], servers.addresses[i].ip[1], servers.addresses[i].ip[2],
servers.addresses[i].ip[3], servers.addresses[i].port);
}
}
2007-05-22 15:03:32 +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
{
// we got ze info
UNPACKER up;
unpacker_reset(&up, (unsigned char*)packet->data+sizeof(SERVERBROWSE_INFO), packet->data_size-sizeof(SERVERBROWSE_INFO));
if(serverlist_lan)
2007-07-26 19:09:31 +00:00
{
if(servers.num != MAX_SERVERS)
2007-07-14 13:09:42 +00:00
{
2007-07-22 11:53:15 +00:00
int i = servers.num;
strncpy(servers.infos[i].name, unpacker_get_string(&up), 128);
strncpy(servers.infos[i].map, unpacker_get_string(&up), 128);
servers.infos[i].max_players = unpacker_get_int(&up);
servers.infos[i].num_players = unpacker_get_int(&up);
2007-07-22 11:53:15 +00:00
servers.infos[i].latency = 0;
sprintf(servers.infos[i].address, "%d.%d.%d.%d:%d",
2007-07-22 11:53:15 +00:00
packet->address.ip[0], packet->address.ip[1], packet->address.ip[2],
packet->address.ip[3], packet->address.port);
if(config.debug)
dbg_msg("client", "got server info");
2007-07-22 11:53:15 +00:00
servers.num++;
2007-07-14 13:09:42 +00:00
}
}
2007-07-22 11:53:15 +00:00
else
{
int i;
for(i = 0; i < servers.num; i++)
2007-07-14 13:09:42 +00:00
{
2007-07-22 11:53:15 +00:00
if(net_addr4_cmp(&servers.addresses[i], &packet->address) == 0)
{
strncpy(servers.infos[i].name, unpacker_get_string(&up), 128);
strncpy(servers.infos[i].map, unpacker_get_string(&up), 128);
servers.infos[i].max_players = unpacker_get_int(&up);
servers.infos[i].num_players = unpacker_get_int(&up);
2007-07-22 11:53:15 +00:00
servers.infos[i].latency = ((time_get() - servers.request_times[i])*1000)/time_freq();
if(config.debug)
dbg_msg("client", "got server info");
2007-07-22 11:53:15 +00:00
break;
2007-07-22 09:15:34 +00:00
}
}
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);
client_set_state(CLIENTSTATE_LOADING);
2007-07-22 11:53:15 +00:00
if(map_load(map))
{
modc_entergame();
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-07-22 09:15:34 +00:00
else
{
client_error("failure to load map");
2007-07-14 13:09:42 +00:00
}
2007-07-13 13:40:04 +00:00
}
2007-07-29 22:09:15 +00:00
else if(msg == NETMSG_SNAP || msg == NETMSG_SNAPEMPTY) //|| msg == NETMSG_SNAPSMALL || 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();
int num_parts = 1;
int part = 0;
int part_size = 0;
if(msg != NETMSG_SNAPEMPTY)
part_size = msg_unpack_int();
if(snapshot_part == part && game_tick > current_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)
{
snapshot_part = 0;
2007-07-22 11:53:15 +00:00
// find snapshot that we should use as delta
static SNAPSHOT emptysnap;
2007-07-22 11:53:15 +00:00
emptysnap.data_size = 0;
emptysnap.num_items = 0;
SNAPSHOT *deltashot = &emptysnap;
// find delta
2007-07-22 11:53:15 +00:00
if(delta_tick >= 0)
{
2007-07-26 19:09:31 +00:00
//void *delta_data;
int deltashot_size = snapstorage_get(&snapshot_storage, delta_tick, 0, &deltashot);
if(deltashot_size < 0)
2007-07-14 13:09:42 +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
msg_pack_start_system(NETMSG_SNAPACK, 0);
msg_pack_int(-1);
msg_pack_end();
client_send_msg();
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
// 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];
int snapsize = snapshot_unpack_delta(deltashot, (SNAPSHOT*)tmpbuffer3, deltadata, deltasize);
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;
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
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)
// 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++;
if(current_tick > 0)
snaploss += game_tick-current_tick-1;
current_tick = game_tick;
2007-07-22 11:53:15 +00:00
// we got two snapshots until we see us self as connected
if(recived_snapshots == 2)
{
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();
client_set_state(CLIENTSTATE_ONLINE);
2007-07-22 11:53:15 +00:00
}
2007-07-26 19:09:31 +00:00
int64 now = time_get();
int64 t = now - game_tick*time_freq()/50;
if(game_start_time == -1 || t < game_start_time)
{
if(config.debug)
dbg_msg("client", "adjusted time");
2007-07-26 19:09:31 +00:00
game_start_time = t;
}
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;
2007-07-22 11:53:15 +00:00
// ack snapshot
msg_pack_start_system(NETMSG_SNAPACK, 0);
msg_pack_int(game_tick);
msg_pack_end();
client_send_msg();
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
{
dbg_msg("client", "snapshot reset!");
snapshot_part = 0;
}
}
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
static void client_pump_network()
2007-07-22 11:53:15 +00:00
{
netclient_update(net);
2007-07-22 11:53:15 +00:00
// check for errors
if(client_state() != CLIENTSTATE_OFFLINE && netclient_state(net) == NETSTATE_OFFLINE)
2007-07-22 11:53:15 +00:00
{
// TODO: add message to the user there
client_set_state(CLIENTSTATE_OFFLINE);
dbg_msg("client", "offline error='%s'", netclient_error_string(net));
2007-07-22 11:53:15 +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");
client_set_state(CLIENTSTATE_LOADING);
client_send_info();
2007-07-22 11:53:15 +00:00
}
// process packets
NETPACKET packet;
while(netclient_recv(net, &packet))
client_process_packet(&packet);
2007-07-22 11:53:15 +00:00
}
2007-05-22 15:03:32 +00:00
static void client_run(const char *direct_connect_server)
{
local_start_time = time_get();
snapshot_part = 0;
info_request_begin = 0;
info_request_end = 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;
// init menu
modmenu_init(); // TODO: remove
// init snapshotting
snap_init();
// init the mod
modc_init();
2007-08-22 21:13:33 +00:00
dbg_msg("client", "version %s", modc_net_version());
// open socket
NETADDR4 bindaddr;
mem_zero(&bindaddr, sizeof(bindaddr));
net = netclient_open(bindaddr, 0);
//
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 game_starttime = time_get();
int64 last_input = game_starttime;
int64 reporttime = time_get();
int64 reportinterval = time_freq()*1;
int frames = 0;
inp_mouse_mode_relative();
while (1)
{
frames++;
int64 frame_start_time = time_get();
// switch snapshot
if(recived_snapshots >= 3)
{
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(t < now)
{
SNAPSTORAGE_HOLDER *next = snapshots[SNAP_CURRENT]->next;
if(next)
{
snapshots[SNAP_PREV] = snapshots[SNAP_CURRENT];
snapshots[SNAP_CURRENT] = next;
if(snapshots[SNAP_CURRENT] && snapshots[SNAP_PREV])
modc_newsnapshot();
}
else
{
extra_polating = 1;
break;
}
}
else
{
extra_polating = 0;
break;
}
}
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));
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));
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();
}
}
if(client_state() == CLIENTSTATE_OFFLINE && config.stress && (frames%100) == 0)
client_connect(config.cl_stress_server);
// update input
inp_update();
// refocus
// TODO: fixme
if(!gfx_window_active())
{
if(window_must_refocus == 0)
inp_mouse_mode_absolute();
window_must_refocus = 1;
}
if(window_must_refocus && gfx_window_active())
{
if(window_must_refocus < 3)
{
inp_mouse_mode_absolute();
window_must_refocus++;
}
if(inp_key_pressed(KEY_MOUSE_1))
{
inp_mouse_mode_relative();
window_must_refocus = 0;
}
}
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();
// panic button
2007-08-04 22:02:38 +00:00
if(config.debug)
{
if(inp_key_pressed(KEY_F1))
inp_mouse_mode_absolute();
if(inp_key_pressed(KEY_F2))
inp_mouse_mode_relative();
if(inp_key_pressed(KEY_LCTRL) && inp_key_pressed('Q'))
2007-08-04 22:02:38 +00:00
break;
if(inp_key_pressed(KEY_F5))
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();
}
}
// pump the network
client_pump_network();
// update the server browser
client_serverbrowse_update();
// render
if(config.stress)
{
if((frames%10) == 0)
{
client_render();
gfx_swap();
}
}
else
{
client_render();
gfx_swap();
}
// check conditions
if(client_state() == CLIENTSTATE_QUITING)
break;
// be nice
if(config.cpu_throttle || !gfx_window_active())
thread_sleep(1);
if(reporttime < time_get())
{
if(config.debug)
{
dbg_msg("client/report", "fps=%.02f netstate=%d",
frames/(float)(reportinterval/time_freq()), netclient_state(net));
}
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);
//client main_client;
2007-07-22 11:53:15 +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();
#ifdef CONF_PLATFORM_MACOSX
const char *config_filename = "~/.teewars";
#else
const char *config_filename = "default.cfg";
#endif
2007-06-01 02:21:46 +00:00
int i;
for(i = 1; i < argc; i++)
{
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);
const char *direct_connect_server = 0x0;
2007-07-21 17:43:00 +00:00
snd_set_master_volume(config.volume / 255.0f);
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
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++;
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)
{
editor = 1;
2007-07-15 13:25:10 +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
client_run(direct_connect_server);
2007-07-15 13:25:10 +00:00
}
2007-05-22 15:03:32 +00:00
return 0;
}