diff options
Diffstat (limited to 'src/engine/client/client.c')
| -rw-r--r-- | src/engine/client/client.c | 980 |
1 files changed, 980 insertions, 0 deletions
diff --git a/src/engine/client/client.c b/src/engine/client/client.c new file mode 100644 index 00000000..ab4b7109 --- /dev/null +++ b/src/engine/client/client.c @@ -0,0 +1,980 @@ + +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <math.h> + +#include <engine/system.h> +#include <engine/interface.h> +#include "ui.h" + +#include <engine/versions.h> + +#include <engine/protocol.h> +#include <engine/snapshot.h> +#include <engine/compression.h> +#include <engine/network.h> +#include <engine/config.h> +#include <engine/packer.h> + +#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; + +// --- input snapping --- +static int input_data[MAX_INPUT_SIZE] = {0}; +static int input_data_size; +static int input_is_changed = 1; +void snap_input(void *data, int size) +{ + if(input_data_size != size || memcmp(input_data, data, size)) + input_is_changed = 1; + mem_copy(input_data, data, size); + input_data_size = size; +} + +// -- snapshot handling --- +enum +{ + NUM_SNAPSHOT_TYPES=2, +}; + +SNAPSTORAGE snapshot_storage; +static SNAPSTORAGE_HOLDER *snapshots[NUM_SNAPSHOT_TYPES]; +static int recived_snapshots; +static char snapshot_incomming_data[MAX_SNAPSHOT_SIZE]; + +// --- + +const void *snap_get_item(int snapid, int index, SNAP_ITEM *item) +{ + 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); +} + +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; +} + +int snap_num_items(int snapid) +{ + dbg_assert(snapid >= 0 && snapid < NUM_SNAPSHOT_TYPES, "invalid snapid"); + return snapshots[snapid]->snap->num_items; +} + +static void snap_init() +{ + snapshots[SNAP_CURRENT] = 0; + snapshots[SNAP_PREV] = 0; + recived_snapshots = 0; + game_start_time = -1; + +} + +// ------ 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? + +// ----- send functions ----- +int client_send_msg() +{ + const MSG_INFO *info = msg_get_info(); + NETPACKET packet; + mem_zero(&packet, sizeof(NETPACKET)); + + packet.client_id = 0; + packet.data = info->data; + packet.data_size = info->size; + + if(info->flags&MSGFLAG_VITAL) + packet.flags = PACKETFLAG_VITAL; + + netclient_send(net, &packet); + return 0; +} + +static void client_send_info() +{ + recived_snapshots = 0; + game_start_time = -1; + + msg_pack_start_system(NETMSG_INFO, MSGFLAG_VITAL); + msg_pack_string(TEEWARS_NETVERSION_STRING, 64); + 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; + +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; +} + +void client_serverbrowse_refresh(int lan) +{ + serverlist_lan = lan; + + if(serverlist_lan) + { + if(config.debug) + dbg_msg("client", "broadcasting for servers"); + NETPACKET packet; + packet.client_id = -1; + mem_zero(&packet, sizeof(packet)); + 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); + + // reset the list + servers.num = 0; + } + else + { + if(config.debug) + dbg_msg("client", "requesting server list"); + NETPACKET packet; + mem_zero(&packet, sizeof(packet)); + 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); + + // 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) +{ + 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; +} + +void client_disconnect() +{ + client_send_error("disconnected"); + netclient_disconnect(net, "disconnected"); + client_set_state(CLIENTSTATE_OFFLINE); + map_unload(); +} + +static int client_load_data() +{ + debug_font = gfx_load_texture("data/debug_font.png"); + return 1; +} + +static void client_debug_render() +{ + if(!config.debug) + return; + + gfx_blend_normal(); + gfx_texture_set(debug_font); + gfx_mapscreen(0,0,gfx_screenwidth(),gfx_screenheight()); + + static NETSTATS prev, current; + static int64 last_snap = 0; + if(time_get()-last_snap > time_freq()/10) + { + last_snap = time_get(); + prev = current; + netclient_stats(net, ¤t); + } + + static float frametime_avg = 0; + frametime_avg = frametime_avg*0.9f + frametime*0.1f; + char buffer[512]; + sprintf(buffer, "send: %6d recv: %6d snaploss: %4d latency: %4.0f %c gfxmem: %6dk fps: %3d", + (current.send_bytes-prev.send_bytes)*10, + (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); + +} + +void client_quit() +{ + client_set_state(CLIENTSTATE_QUITING); +} + +const char *client_error_string() +{ + return netclient_error_string(net); +} + +static void client_render() +{ + gfx_clear(0.0f,0.0f,0.0f); + modc_render(); + client_debug_render(); +} + +static void client_error(const char *msg) +{ + dbg_msg("client", "error: %s", msg); + client_send_error(msg); + client_set_state(CLIENTSTATE_QUITING); +} + +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); + + info_request_begin = 0; + info_request_end = 0; + + 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; +#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); + } + } + + if(packet->data_size >= (int)sizeof(SERVERBROWSE_INFO) && + memcmp(packet->data, SERVERBROWSE_INFO, sizeof(SERVERBROWSE_INFO)) == 0) + { + // 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) + { + if(servers.num != MAX_SERVERS) + { + 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); + servers.infos[i].latency = 0; + + sprintf(servers.infos[i].address, "%d.%d.%d.%d:%d", + 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"); + servers.num++; + + } + } + else + { + int i; + for(i = 0; i < servers.num; i++) + { + 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); + servers.infos[i].latency = ((time_get() - servers.request_times[i])*1000)/time_freq(); + if(config.debug) + dbg_msg("client", "got server info"); + break; + } + } + } + } + } + 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); + + if(map_load(map)) + { + modc_entergame(); + client_send_entergame(); + dbg_msg("client/network", "loading done"); + // now we will wait for two snapshots + // to finish the connection + } + else + { + client_error("failure to load map"); + } + } + else if(msg == NETMSG_SNAP || msg == NETMSG_SNAPEMPTY) //|| msg == NETMSG_SNAPSMALL || msg == NETMSG_SNAPEMPTY) + { + //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) + { + // TODO: clean this up abit + const char *d = (const char *)msg_unpack_raw(part_size); + mem_copy((char*)snapshot_incomming_data + part*MAX_SNAPSHOT_PACKSIZE, d, part_size); + snapshot_part++; + + if(snapshot_part == num_parts) + { + snapshot_part = 0; + + // find snapshot that we should use as delta + static SNAPSHOT emptysnap; + emptysnap.data_size = 0; + emptysnap.num_items = 0; + + SNAPSHOT *deltashot = &emptysnap; + + // find delta + if(delta_tick >= 0) + { + //void *delta_data; + + int deltashot_size = snapstorage_get(&snapshot_storage, delta_tick, 0, &deltashot); + + if(deltashot_size < 0) + { + // 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; + } + } + + // 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; + } + + //dbg_msg("UNPACK", "%d unpacked with %d", game_tick, delta_tick); + + unsigned char tmpbuffer3[MAX_SNAPSHOT_SIZE]; + int snapsize = snapshot_unpack_delta(deltashot, (SNAPSHOT*)tmpbuffer3, deltadata, deltasize); + + // 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); + //client_snapshot_purge_until(game_tick-50); + + // 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); + + //int ncrc = snapshot_crc((snapshot*)tmpbuffer3); + //if(crc != ncrc) + // dbg_msg("client", "client snapshot crc failure %d %d", crc, ncrc); + + // apply snapshot, cycle pointers + recived_snapshots++; + + + if(current_tick > 0) + snaploss += game_tick-current_tick-1; + current_tick = game_tick; + + // 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; + local_start_time = time_get(); + client_set_state(CLIENTSTATE_ONLINE); + } + + 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"); + 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; + + // ack snapshot + msg_pack_start_system(NETMSG_SNAPACK, 0); + msg_pack_int(game_tick); + msg_pack_end(); + client_send_msg(); + } + } + else + { + dbg_msg("client", "snapshot reset!"); + snapshot_part = 0; + } + } + } + else + { + // game message + modc_message(msg); + } + } +} + + +static void client_pump_network() +{ + netclient_update(net); + + // 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)); + } + + // + if(client_state() == CLIENTSTATE_CONNECTING && netclient_state(net) == NETSTATE_ONLINE) + { + // we switched to online + dbg_msg("client", "connected, sending info"); + client_set_state(CLIENTSTATE_LOADING); + client_send_info(); + } + + // process packets + NETPACKET packet; + while(netclient_recv(net, &packet)) + client_process_packet(&packet); +} + +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(); + + // 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; + } + } + + // screenshot button + if(inp_key_down(config.key_screenshot)) + gfx_screenshot(); + + // panic button + 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')) + break; + + if(inp_key_pressed(KEY_F5)) + { + // 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(); +} + + +int editor_main(int argc, char **argv); + +//client main_client; + +int main(int argc, char **argv) +{ + dbg_msg("client", "starting..."); + + config_reset(); + +#ifdef CONF_PLATFORM_MACOSX + const char *config_filename = "~/.teewars"; +#else + const char *config_filename = "default.cfg"; +#endif + + 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; + snd_set_master_volume(config.volume / 255.0f); + int editor = 0; + + // init network, need to be done first so we can do lookups + net_init(); + + // parse arguments + for(i = 1; i < argc; i++) + { + if(argv[i][0] == '-' && argv[i][1] == 'c' && argv[i][2] == 0 && argc - i > 1) + { + // -c SERVER:PORT + i++; + direct_connect_server = argv[i]; + } + else if(argv[i][0] == '-' && argv[i][1] == 'e' && argv[i][2] == 0) + { + editor = 1; + } + else + config_set(argv[i]); + } + + if(editor) + editor_main(argc, argv); + else + { + // start the client + client_run(direct_connect_server); + } + return 0; +} |