diff options
| -rw-r--r-- | default.bam | 67 | ||||
| -rw-r--r-- | src/editor/editor.cpp (renamed from src/editor.cpp) | 0 | ||||
| -rw-r--r-- | src/engine/client/client.cpp (renamed from src/client.cpp) | 17 | ||||
| -rw-r--r-- | src/engine/client/gfx.cpp (renamed from src/gfx.cpp) | 8 | ||||
| -rw-r--r-- | src/engine/client/snd.cpp (renamed from src/snd.cpp) | 5 | ||||
| -rw-r--r-- | src/engine/client/ui.cpp (renamed from src/ui.cpp) | 2 | ||||
| -rw-r--r-- | src/engine/client/ui.h (renamed from src/ui.h) | 0 | ||||
| -rw-r--r-- | src/engine/datafile.cpp (renamed from src/datafile.cpp) | 0 | ||||
| -rw-r--r-- | src/engine/datafile.h (renamed from src/datafile.h) | 0 | ||||
| -rw-r--r-- | src/engine/interface.h (renamed from src/interface.h) | 0 | ||||
| -rw-r--r-- | src/engine/lzw.cpp (renamed from src/lzw.cpp) | 0 | ||||
| -rw-r--r-- | src/engine/lzw.h (renamed from src/lzw.h) | 0 | ||||
| -rw-r--r-- | src/engine/map.cpp (renamed from src/map.cpp) | 0 | ||||
| -rw-r--r-- | src/engine/packet.h (renamed from src/packet.h) | 5 | ||||
| -rw-r--r-- | src/engine/server/server.cpp | 5 | ||||
| -rw-r--r-- | src/engine/snapshot.h (renamed from src/snapshot.h) | 0 | ||||
| -rw-r--r-- | src/engine/versions.h (renamed from src/versions.h) | 0 | ||||
| -rw-r--r-- | src/game/client/game_client.cpp (renamed from src/game/game_client.cpp) | 2 | ||||
| -rw-r--r-- | src/game/client/mapres_image.cpp (renamed from src/game/mapres_image.cpp) | 4 | ||||
| -rw-r--r-- | src/game/client/mapres_image.h (renamed from src/game/mapres_image.h) | 0 | ||||
| -rw-r--r-- | src/game/client/mapres_tilemap.cpp (renamed from src/game/mapres_tilemap.cpp) | 4 | ||||
| -rw-r--r-- | src/game/client/mapres_tilemap.h (renamed from src/game/mapres_tilemap.h) | 0 | ||||
| -rw-r--r-- | src/game/client/menu.cpp (renamed from src/menu.cpp) | 12 | ||||
| -rw-r--r-- | src/game/game.h | 2 | ||||
| -rw-r--r-- | src/game/mapres_col.cpp | 2 | ||||
| -rw-r--r-- | src/game/server/game_server.cpp (renamed from src/game/game_server.cpp) | 13 | ||||
| -rw-r--r-- | src/server.cpp | 668 |
27 files changed, 72 insertions, 744 deletions
diff --git a/default.bam b/default.bam index 2964cfe8..9da37d2b 100644 --- a/default.bam +++ b/default.bam @@ -31,56 +31,35 @@ function Copy(outputdir, ...) return outputs end -function makemap(output, input) - print("makemap " .. PathFilename(output)) - os.execute("python scripts/tool.py " .. input .. " " .. output) -end - -function MakeMap(output, input) - local output = bam_path_fix(output) - local input = bam_path_fix(input) - bam_add_job("makemap", output, input) - bam_add_dependency(output, input) - return output -end - -- -baselib = Import("../baselib/baselib.bam") +--baselib = Import("src/baselib/baselib.bam") +baselib = Import("../baselib/baselib.bam") settings = NewSettings() -baselib.use(settings) +baselib.apply(settings, "all") + +server_settings = NewSettings() +baselib.apply(server_settings, "network") + settings.cc.debug = 1 settings.cc.optimize = 0 settings.cc.flags = "-Wall" +settings.cc.includes:add("src") +--settings.cc.includes:add("src/baselib/include") -game_src = Collect("src/game/*.cpp") -main_src = Collect("src/*.cpp") -wavpack_src = Collect("src/wavpack/*.c") -exe = Link(settings, "teewars", Compile(settings, game_src, main_src, wavpack_src)) - ---maps = { --- MakeMap("data/test.map", "data_src/test.txt"), --- MakeMap("data/dm1.map", "data_src/dm1.txt"), --- MakeMap("data/ctf1.map", "data_src/ctf1.txt") --- } - ---data_files = Copy("data", --- { --- "data_src/game_main.tga", --- "data_src/game_weapons.tga", --- "data_src/char_teefault.tga", --- "data_src/sun.tga", --- "data_src/debug_font.tga", --- "data_src/dm1.map" --- }) ---audio_files = Copy("data/audio", --- { --- "data_src/audio/Music_Menu.wav", --- "data_src/audio/wp_flump_explo-01.wav", --- "data_src/audio/wp_flump_explo-02.wav", --- "data_src/audio/wp_flump_explo-03.wav" --- }) +--baselib = Compile(settings, Collect("src/baselib/src/*.cpp", "src/baselib/src/*.c")) +engine = Compile(settings, Collect("src/engine/*.cpp")) +client = Compile(settings, Collect("src/engine/client/*.cpp")) +server = Compile(settings, Collect("src/engine/server/*.cpp")) +game_shared = Compile(settings, Collect("src/game/*.cpp")) +game_client = Compile(settings, Collect("src/game/client/*.cpp")) +game_server = Compile(settings, Collect("src/game/server/*.cpp")) +editor = Compile(settings, Collect("src/editor/*.cpp")) -game = PseudoTarget("game", exe) +client_exe = Link(settings, "teewars", engine, client, game_shared, game_client) +server_exe = Link(server_settings, "teewars_srv", engine, server, game_shared, game_server) +-- editor_exe = Link(settings, "editor", engine, game_shared, editor) -Target(game) +Target(PseudoTarget("client", client_exe)) +Target(PseudoTarget("server", server_exe)) +-- Target(PseudoTarget("editor", editor_exe)) diff --git a/src/editor.cpp b/src/editor/editor.cpp index 9b633730..9b633730 100644 --- a/src/editor.cpp +++ b/src/editor/editor.cpp diff --git a/src/client.cpp b/src/engine/client/client.cpp index 2f231117..4aceaf0f 100644 --- a/src/client.cpp +++ b/src/engine/client/client.cpp @@ -7,16 +7,15 @@ #include <string.h> #include <stdarg.h> #include <math.h> -#include "interface.h" +#include <engine/interface.h> - -#include "packet.h" -#include "snapshot.h" +#include <engine/packet.h> +#include <engine/snapshot.h> #include "ui.h" -#include "lzw.h" +#include <engine/lzw.h> -#include "versions.h" +#include <engine/versions.h> using namespace baselib; @@ -477,8 +476,8 @@ public: if (server_address) connect(server_address); - int64 inputs_per_second = 50; - int64 time_per_input = time_freq()/inputs_per_second; + //int64 inputs_per_second = 50; + //int64 time_per_input = time_freq()/inputs_per_second; int64 game_starttime = time_get(); int64 last_input = game_starttime; @@ -668,7 +667,7 @@ public: } }; -int client_main(int argc, char **argv) +int main(int argc, char **argv) { dbg_msg("client", "starting..."); netaddr4 server_address(127, 0, 0, 1, 8303); diff --git a/src/gfx.cpp b/src/engine/client/gfx.cpp index c1e05c9c..a824feac 100644 --- a/src/gfx.cpp +++ b/src/engine/client/gfx.cpp @@ -2,7 +2,7 @@ #include <baselib/vmath.h> #include <baselib/stream/file.h> -#include "interface.h" +#include <engine/interface.h> using namespace baselib; @@ -222,6 +222,8 @@ int gfx_load_tga(image_info *img, const char *filename) bool flipx = (headers[17] >> 4) & 1; bool flipy = !((headers[17] >> 5) & 1); + + (void)flipx; // TODO: make use of this flag if(headers[2] != 2) // needs to be uncompressed RGB { @@ -547,7 +549,7 @@ void gfx_pretty_text(float x, float y, float size, const char *text) while (*text) { - const char c = *text; + const int c = *text; const float width = current_font->m_CharEndTable[c] - current_font->m_CharStartTable[c]; text++; @@ -573,7 +575,7 @@ float gfx_pretty_text_width(float size, const char *text) while (*text) { - const char c = *text++; + const int c = *text++; width += size * (current_font->m_CharEndTable[c] - current_font->m_CharStartTable[c] + spacing); } diff --git a/src/snd.cpp b/src/engine/client/snd.cpp index 42997897..dd6baa9a 100644 --- a/src/snd.cpp +++ b/src/engine/client/snd.cpp @@ -2,7 +2,7 @@ #include <baselib/audio.h> #include <baselib/stream/file.h> -#include "interface.h" +#include <engine/interface.h> using namespace baselib; @@ -181,10 +181,11 @@ public: static mixer mixer; //static sound_data test_sound; +/* extern "C" { #include "wavpack/wavpack.h" -} +}*/ /* static file_stream *read_func_filestream; diff --git a/src/ui.cpp b/src/engine/client/ui.cpp index 7ef19b72..3353feca 100644 --- a/src/ui.cpp +++ b/src/engine/client/ui.cpp @@ -1,4 +1,4 @@ -#include "interface.h" +#include <engine/interface.h> #include "ui.h" /******************************************************** diff --git a/src/ui.h b/src/engine/client/ui.h index 1a420906..1a420906 100644 --- a/src/ui.h +++ b/src/engine/client/ui.h diff --git a/src/datafile.cpp b/src/engine/datafile.cpp index 789aa722..789aa722 100644 --- a/src/datafile.cpp +++ b/src/engine/datafile.cpp diff --git a/src/datafile.h b/src/engine/datafile.h index 4e49fa03..4e49fa03 100644 --- a/src/datafile.h +++ b/src/engine/datafile.h diff --git a/src/interface.h b/src/engine/interface.h index 95ea0252..95ea0252 100644 --- a/src/interface.h +++ b/src/engine/interface.h diff --git a/src/lzw.cpp b/src/engine/lzw.cpp index 80dd1c22..80dd1c22 100644 --- a/src/lzw.cpp +++ b/src/engine/lzw.cpp diff --git a/src/lzw.h b/src/engine/lzw.h index af29665e..af29665e 100644 --- a/src/lzw.h +++ b/src/engine/lzw.h diff --git a/src/map.cpp b/src/engine/map.cpp index 3e76547e..3e76547e 100644 --- a/src/map.cpp +++ b/src/engine/map.cpp diff --git a/src/packet.h b/src/engine/packet.h index ebc5e41e..6dc99043 100644 --- a/src/packet.h +++ b/src/engine/packet.h @@ -55,7 +55,7 @@ protected: void debug_verify_mark(int type, int size) { - if(read_int_raw() == ((type<<16) | size)) + if(read_int_raw() != ((type<<16) | size)) dbg_assert(0, "error during packet disassembly"); } @@ -110,8 +110,9 @@ public: const char *read_str() { debug_verify_mark(DEBUG_TYPE_STR, 0); - const char *s = (const char *)current; int size = read_int_raw(); + const char *s = (const char *)current; + //dbg_msg("packet", "reading string '%s' (%d)", s, size); current += size; return s; } diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp new file mode 100644 index 00000000..d9151a43 --- /dev/null +++ b/src/engine/server/server.cpp @@ -0,0 +1,5 @@ +#include <stdio.h> #include <string.h> #include <baselib/system.h> #include <engine/interface.h> //#include "socket.h" #include <engine/packet.h> #include <engine/snapshot.h> #include <engine/lzw.h> #include <engine/versions.h> namespace baselib {} using namespace baselib; int net_addr4_cmp(const NETADDR4 *a, const NETADDR4 *b) { if( a->ip[0] != b->ip[0] || a->ip[1] != b->ip[1] || a->ip[2] != b->ip[2] || a->ip[3] != b->ip[3] || a->port != b->port ) return 1; return 0; } // --- string handling (MOVE THESE!!) --- void snap_encode_string(const char *src, int *dst, int length, int max_length) { const unsigned char *p = (const unsigned char *)src; // handle whole int for(int i = 0; i < length/4; i++) { *dst = (p[0]<<24|p[1]<<16|p[2]<<8|p[3]); p += 4; dst++; } // take care of the left overs int left = length%4; if(left) { unsigned last = 0; switch(left) { case 3: last |= p[2]<<8; case 2: last |= p[1]<<16; case 1: last |= p[0]<<24; } *dst = last; } } class snapshot_builder { public: static const int MAX_ITEMS = 512; //static const int MAX_DATA_SIZE=1*1024; char data[MAX_SNAPSHOT_SIZE]; int data_size; int offsets[MAX_ITEMS]; int num_items; int top_size; int top_items; int snapnum; snapshot_builder() { top_size = 0; top_items = 0; snapnum = 0; } void start() { data_size = 0; num_items = 0; } int finish(void *snapdata) { snapnum++; // collect some data /* int change = 0; if(data_size > top_size) { change++; top_size = data_size; } if(num_items > top_items) { change++; top_items = num_items; } if(change) { dbg_msg("snapshot", "new top, items=%d size=%d", top_items, top_size); }*/ // flattern and make the snapshot snapshot *snap = (snapshot *)snapdata; snap->num_items = num_items; int offset_size = sizeof(int)*num_items; mem_copy(snap->offsets, offsets, offset_size); mem_copy(snap->data_start(), data, data_size); return sizeof(int) + offset_size + data_size; } void *new_item(int type, int id, int size) { snapshot::item *obj = (snapshot::item *)(data+data_size); obj->type_and_id = (type<<16)|id; offsets[num_items] = data_size; data_size += sizeof(int) + size; num_items++; dbg_assert(data_size < MAX_SNAPSHOT_SIZE, "too much data"); dbg_assert(num_items < MAX_ITEMS, "too many items"); return &obj->data; } }; static snapshot_builder builder; void *snap_new_item(int type, int id, int size) { dbg_assert(type >= 0 && type <=0xffff, "incorrect type"); dbg_assert(id >= 0 && id <=0xffff, "incorrect id"); return builder.new_item(type, id, size); } // class client { public: enum { STATE_EMPTY = 0, STATE_CONNECTING = 1, STATE_INGAME = 2, }; // connection state info int state; // (ticks) if lastactivity > 5 seconds kick him int64 lastactivity; connection conn; char name[MAX_NAME_LENGTH]; char clan[MAX_CLANNAME_LENGTH]; /* client() { state = STATE_EMPTY; name[0] = 0; clan[0] = 0; } ~client() { dbg_assert(state == STATE_EMPTY, "client destoyed while in use"); }*/ bool is_empty() const { return state == STATE_EMPTY; } bool is_ingame() const { return state == STATE_INGAME; } const netaddr4 &address() const { return conn.address(); } }; static client clients[MAX_CLIENTS]; static int current_tick = 0; static int send_heartbeats = 1; int server_tick() { return current_tick; } int server_tickspeed() { return 50; } int server_init() { for(int i = 0; i < MAX_CLIENTS; i++) { clients[i].state = client::STATE_EMPTY; clients[i].name[0] = 0; clients[i].clan[0] = 0; clients[i].lastactivity = 0; } current_tick = 0; return 0; } int server_getclientinfo(int client_id, client_info *info) { dbg_assert(client_id >= 0 && client_id < MAX_CLIENTS, "client_id is not valid"); dbg_assert(info != 0, "info can not be null"); if(clients[client_id].is_ingame()) { info->name = clients[client_id].name; info->latency = 0; return 1; } return 0; } // class server { public: socket_udp4 game_socket; + + const char *map_name; const char *server_name; int64 lasttick; int64 lastheartbeat; netaddr4 master_server; int biggest_snapshot; bool run(const char *servername, const char *mapname) { biggest_snapshot = 0; net_init(); // For Windows compatibility. map_name = mapname; server_name = servername; // load map if(!map_load(mapname)) { dbg_msg("server", "failed to load map. mapname='%s'"); return false; } // start server if(!game_socket.open(8303)) { dbg_msg("network/server", "couldn't open socket"); return false; } for(int i = 0; i < MAX_CLIENTS; i++) dbg_msg("network/server", "\t%d: %d", i, clients[i].state); if (net_host_lookup(MASTER_SERVER_ADDRESS, MASTER_SERVER_PORT, &master_server) != 0) { // TODO: fix me //master_server = netaddr4(0, 0, 0, 0, 0); } mods_init(); int64 time_per_tick = time_freq()/SERVER_TICK_SPEED; int64 time_per_heartbeat = time_freq() * 30; int64 starttime = time_get(); //int64 lasttick = starttime; lasttick = starttime; lastheartbeat = 0; int64 reporttime = time_get(); int64 reportinterval = time_freq()*3; int64 simulationtime = 0; int64 snaptime = 0; int64 networktime = 0; while(1) { int64 t = time_get(); if(t-lasttick > time_per_tick) { { int64 start = time_get(); tick(); simulationtime += time_get()-start; } { int64 start = time_get(); snap(); snaptime += time_get()-start; } // Check for client timeouts for (int i = 0; i < MAX_CLIENTS; i++) { if (clients[i].state != client::STATE_EMPTY) { // check last activity time if (((lasttick - clients[i].lastactivity) / time_freq()) > SERVER_CLIENT_TIMEOUT) client_timeout(i); } } lasttick += time_per_tick; } if(send_heartbeats) { if (t > lastheartbeat+time_per_heartbeat) { if (master_server.port != 0) { int players = 0; for (int i = 0; i < MAX_CLIENTS; i++) if (!clients[i].is_empty()) players++; // TODO: fix me netaddr4 me(127, 0, 0, 0, 8303); send_heartbeat(0, &me, players, MAX_CLIENTS, server_name, mapname); } lastheartbeat = t+time_per_heartbeat; } } { int64 start = time_get(); pump_network(); networktime += time_get()-start; } if(reporttime < time_get()) { int64 totaltime = simulationtime+snaptime+networktime; dbg_msg("server/report", "sim=%.02fms snap=%.02fms net=%.02fms total=%.02fms load=%.02f%%", simulationtime/(float)reportinterval*1000, snaptime/(float)reportinterval*1000, networktime/(float)reportinterval*1000, totaltime/(float)reportinterval*1000, (simulationtime+snaptime+networktime)/(float)reportinterval*100.0f); unsigned sent_total=0, recv_total=0; for (int i = 0; i < MAX_CLIENTS; i++) if (!clients[i].is_empty()) { unsigned s,r; clients[i].conn.counter_get(&s,&r); clients[i].conn.counter_reset(); sent_total += s; recv_total += r; } dbg_msg("server/report", "biggestsnap=%d send=%d recv=%d", biggest_snapshot, sent_total/3, recv_total/3); simulationtime = 0; snaptime = 0; networktime = 0; reporttime += reportinterval; } thread_sleep(1); } mods_shutdown(); map_unload(); } void tick() { current_tick++; mods_tick(); } void snap() { mods_presnap(); for(int i = 0; i < MAX_CLIENTS; i++) { if(clients[i].is_ingame()) { char data[MAX_SNAPSHOT_SIZE]; char compdata[MAX_SNAPSHOT_SIZE]; builder.start(); mods_snap(i); // finish snapshot int snapshot_size = builder.finish(data); // compress it int compsize = lzw_compress(data, snapshot_size, compdata); snapshot_size = compsize; if(snapshot_size > biggest_snapshot) biggest_snapshot = snapshot_size; const int max_size = MAX_SNAPSHOT_PACKSIZE; int numpackets = (snapshot_size+max_size-1)/max_size; for(int n = 0, left = snapshot_size; left; n++) { int chunk = left < max_size ? left : max_size; left -= chunk; packet p(NETMSG_SERVER_SNAP); p.write_int(numpackets); p.write_int(n); p.write_int(chunk); p.write_raw(&compdata[n*max_size], chunk); clients[i].conn.send(&p); } } } mods_postsnap(); } void send_accept(client *client, const char *map) { packet p(NETMSG_SERVER_ACCEPT); p.write_str(map); client->conn.send(&p); } void drop(int cid, const char *reason) { if(clients[cid].state == client::STATE_EMPTY) return; clients[cid].state = client::STATE_EMPTY; mods_client_drop(cid); dbg_msg("game", "player dropped. reason='%s' cid=%x name='%s'", reason, cid, clients[cid].name); } int find_client(const netaddr4 *addr) { // fetch client for(int i = 0; i < MAX_CLIENTS; i++) { if(!clients[i].is_empty() && clients[i].address() == *addr) return i; } return -1; } void client_process_packet(int cid, packet *p) { clients[cid].lastactivity = lasttick; if(p->msg() == NETMSG_CLIENT_DONE) { dbg_msg("game", "player as entered the game. cid=%x", cid); clients[cid].state = client::STATE_INGAME; mods_client_enter(cid); } else if(p->msg() == NETMSG_CLIENT_INPUT) { int input[MAX_INPUT_SIZE]; int size = p->read_int(); for(int i = 0; i < size/4; i++) input[i] = p->read_int(); if(p->is_good()) { //dbg_msg("network/server", "applying input %d %d %d", input[0], input[1], input[2]); mods_client_input(cid, input); } } else if(p->msg() == NETMSG_CLIENT_ERROR) { const char *reason = p->read_str(); if(p->is_good()) dbg_msg("network/server", "client error. cid=%x reason='%s'", cid, reason); else dbg_msg("network/server", "client error. cid=%x", cid); drop(cid, "client error"); } else { dbg_msg("network/server", "invalid message. cid=%x msg=%x", cid, p->msg()); drop(cid, "invalid message"); } } void process_packet(packet *p, netaddr4 *from) { if(p->msg() == NETMSG_CLIENT_CONNECT) { // we got no state for this client yet const char *version; const char *name; const char *clan; const char *password; const char *skin; version = p->read_str(); name = p->read_str(); clan = p->read_str(); password = p->read_str(); skin = p->read_str(); if(p->is_good()) { // check version if(strcmp(version, TEEWARS_NETVERSION) != 0) { dbg_msg("network/server", "wrong version connecting '%s'", version); + // TODO: send error return; } // look for empty slot, linear search int id = -1; for(int i = 0; i < MAX_CLIENTS; i++) if(clients[i].is_empty()) { id = i; break; } if(id != -1) { // slot found // TODO: perform correct copy here mem_copy(clients[id].name, name, MAX_NAME_LENGTH); mem_copy(clients[id].clan, clan, MAX_CLANNAME_LENGTH); clients[id].state = client::STATE_CONNECTING; clients[id].conn.init(&game_socket, from); clients[id].lastactivity = lasttick; clients[id].name[MAX_NAME_LENGTH-1] = 0; clients[id].clan[MAX_CLANNAME_LENGTH-1] = 0; dbg_msg("network/server", "client connected. '%s' on slot %d", name, id); // TODO: return success send_accept(&clients[id], map_name); } else { // no slot found // TODO: send error dbg_msg("network/server", "client connected but server is full"); for(int i = 0; i < MAX_CLIENTS; i++) dbg_msg("network/server", "\t%d: %d", i, clients[i].state); } } } else { int cid = find_client(from); if(cid >= 0) { if(clients[cid].conn.feed(p)) { // packet is ok unsigned msg = p->msg(); // client found, check state if(((msg>>16)&0xff)&clients[cid].state) { // state is ok client_process_packet(cid, p); } else { // invalid state, disconnect the client drop(cid, "invalid message at this state"); } } else { drop(cid, "connection error"); } } else dbg_msg("network/server", "packet from strange address."); } } void client_timeout(int clientId) { drop(clientId, "client timedout"); } void pump_network() { while(1) { packet p; netaddr4 from; //int bytes = net_udp4_recv( int bytes = game_socket.recv(&from, p.data(), p.max_size()); //int bytes = game_socket.recv(&from, p.data(), p.max_size()); if(bytes <= 0) break; process_packet(&p, &from); } // TODO: check for client timeouts } char *write_int(char *buffer, int integer) { *buffer++ = integer >> 24; *buffer++ = integer >> 16; *buffer++ = integer >> 8; *buffer++ = integer; return buffer; } char *write_netaddr4(char *buffer, NETADDR4 *address) { *buffer++ = address->ip[0]; *buffer++ = address->ip[1]; *buffer++ = address->ip[2]; *buffer++ = address->ip[3]; return write_int(buffer, address->port); } void send_heartbeat(int version, netaddr4 *address, int players, int max_players, const char *name, const char *map_name) { char buffer[216] = {0}; char *d = buffer; d = write_int(d, 'TWHB'); d = write_int(d, version); d = write_netaddr4(d, address); d = write_int(d,players); d = write_int(d, max_players); int len = strlen(name); if (len > 128) len = 128; memcpy(d, name, len); d += 128; len = strlen(map_name); if (len > 64) len = 64; memcpy(d, map_name, len); d += 64; + game_socket.send(&master_server, buffer, sizeof(buffer)); } }; int main(int argc, char **argv) { dbg_msg("server", "starting..."); const char *mapname = "data/demo.map"; const char *servername = 0; // parse arguments for(int i = 1; i < argc; i++) { if(argv[i][0] == '-' && argv[i][1] == 'm' && argv[i][2] == 0 && argc - i > 1) { // -m map i++; mapname = argv[i]; } else if(argv[i][0] == '-' && argv[i][1] == 'n' && argv[i][2] == 0 && argc - i > 1) { // -n server name i++; servername = argv[i]; } else if(argv[i][0] == '-' && argv[i][1] == 'p' && argv[i][2] == 0) { // -p (private server) send_heartbeats = 0; } } if(!mapname) { dbg_msg("server", "no map given (-m MAPNAME)"); return 0; } if(!servername) { dbg_msg("server", "no server name given (-n \"server name\")"); return 0; } server_init(); server s; s.run(servername, mapname); return 0; } \ No newline at end of file diff --git a/src/snapshot.h b/src/engine/snapshot.h index 9d803486..9d803486 100644 --- a/src/snapshot.h +++ b/src/engine/snapshot.h diff --git a/src/versions.h b/src/engine/versions.h index d70ee721..d70ee721 100644 --- a/src/versions.h +++ b/src/engine/versions.h diff --git a/src/game/game_client.cpp b/src/game/client/game_client.cpp index 8bbdf0b3..f510e00e 100644 --- a/src/game/game_client.cpp +++ b/src/game/client/game_client.cpp @@ -1,6 +1,6 @@ #include <stdlib.h> #include <stdio.h> -#include "game.h" +#include "../game.h" #include "mapres_image.h" #include "mapres_tilemap.h" diff --git a/src/game/mapres_image.cpp b/src/game/client/mapres_image.cpp index baf7f09b..1c81b309 100644 --- a/src/game/mapres_image.cpp +++ b/src/game/client/mapres_image.cpp @@ -1,7 +1,7 @@ #include <baselib/system.h> -#include "../interface.h" +#include "../../engine/interface.h" #include "mapres_image.h" -#include "mapres.h" +#include "../mapres.h" static int map_textures[64] = {0}; static int count = 0; diff --git a/src/game/mapres_image.h b/src/game/client/mapres_image.h index eab1559a..eab1559a 100644 --- a/src/game/mapres_image.h +++ b/src/game/client/mapres_image.h diff --git a/src/game/mapres_tilemap.cpp b/src/game/client/mapres_tilemap.cpp index 0868d2e4..36302d0a 100644 --- a/src/game/mapres_tilemap.cpp +++ b/src/game/client/mapres_tilemap.cpp @@ -1,7 +1,7 @@ -#include "../interface.h" +#include "../../engine/interface.h" #include "mapres_tilemap.h" #include "mapres_image.h" -#include "mapres.h" +#include "../mapres.h" int tilemap_init() { diff --git a/src/game/mapres_tilemap.h b/src/game/client/mapres_tilemap.h index 6e9d81be..6e9d81be 100644 --- a/src/game/mapres_tilemap.h +++ b/src/game/client/mapres_tilemap.h diff --git a/src/menu.cpp b/src/game/client/menu.cpp index b5794194..88c87526 100644 --- a/src/menu.cpp +++ b/src/game/client/menu.cpp @@ -5,13 +5,13 @@ #include <baselib/mouse.h> #include <baselib/network.h> -#include "interface.h" -#include "ui.h" -#include "versions.h" +#include <engine/interface.h> +#include <engine/versions.h> +#include "../mapres.h" -#include "game/mapres_image.h" -#include "game/mapres_tilemap.h" -#include "game/mapres.h" +#include <engine/client/ui.h> +#include "mapres_image.h" +#include "mapres_tilemap.h" using namespace baselib; diff --git a/src/game/game.h b/src/game/game.h index a1817eea..2696b74d 100644 --- a/src/game/game.h +++ b/src/game/game.h @@ -1,7 +1,7 @@ #include <baselib/system.h> #include <baselib/vmath.h> #include <math.h> -#include "../interface.h" +#include "../engine/interface.h" #include "mapres_col.h" // Don't tweak :) diff --git a/src/game/mapres_col.cpp b/src/game/mapres_col.cpp index 0cf71986..29215d7d 100644 --- a/src/game/mapres_col.cpp +++ b/src/game/mapres_col.cpp @@ -1,5 +1,5 @@ #include <baselib/system.h> -#include "../interface.h" +#include "../engine/interface.h" #include "mapres_col.h" #include "mapres.h" diff --git a/src/game/game_server.cpp b/src/game/server/game_server.cpp index 5e93165a..769a250f 100644 --- a/src/game/game_server.cpp +++ b/src/game/server/game_server.cpp @@ -1,6 +1,6 @@ #include <stdlib.h> #include <string.h> -#include "game.h" +#include "../game.h" using namespace baselib; @@ -646,7 +646,16 @@ public: if (flags & WEAPON_DRAWSAMMO) numammo--; // Create projectile - new projectile(projectileclass, player->client_id, player->pos+vec2(0,projoffsety)+player->direction*projoffsetx, player->direction*projectilevel, projectilespan, player, damage, projectileflags, force, sound_impact_projectile); + new projectile(projectileclass, + player->client_id, + player->pos+vec2(0,projoffsety)+player->direction*projoffsetx, + player->direction*projectilevel, + (int)projectilespan, + player, + damage, + projectileflags, + force, + sound_impact_projectile); // recoil force if any if (recoilforce > 0.0f) { diff --git a/src/server.cpp b/src/server.cpp deleted file mode 100644 index 1de5839b..00000000 --- a/src/server.cpp +++ /dev/null @@ -1,668 +0,0 @@ -#include <stdio.h> -#include <string.h> - -#include <baselib/system.h> -#include <baselib/network.h> - -#include "interface.h" - -//#include "socket.h" -#include "packet.h" -#include "snapshot.h" - -#include "lzw.h" - -#include "versions.h" - -namespace baselib {} -using namespace baselib; - -class snapshot_builder -{ -public: - static const int MAX_ITEMS = 512; - //static const int MAX_DATA_SIZE=1*1024; - - char data[MAX_SNAPSHOT_SIZE]; - int data_size; - - int offsets[MAX_ITEMS]; - int num_items; - - int top_size; - int top_items; - - int snapnum; - - snapshot_builder() - { - top_size = 0; - top_items = 0; - snapnum = 0; - } - - void start() - { - data_size = 0; - num_items = 0; - } - - int finish(void *snapdata) - { - snapnum++; - - // collect some data - /* - int change = 0; - if(data_size > top_size) - { - change++; - top_size = data_size; - } - - if(num_items > top_items) - { - change++; - top_items = num_items; - } - - if(change) - { - dbg_msg("snapshot", "new top, items=%d size=%d", top_items, top_size); - }*/ - - // flattern and make the snapshot - snapshot *snap = (snapshot *)snapdata; - snap->num_items = num_items; - int offset_size = sizeof(int)*num_items; - mem_copy(snap->offsets, offsets, offset_size); - mem_copy(snap->data_start(), data, data_size); - return sizeof(int) + offset_size + data_size; - } - - void *new_item(int type, int id, int size) - { - snapshot::item *obj = (snapshot::item *)(data+data_size); - obj->type_and_id = (type<<16)|id; - offsets[num_items] = data_size; - data_size += sizeof(int) + size; - num_items++; - dbg_assert(data_size < MAX_SNAPSHOT_SIZE, "too much data"); - dbg_assert(num_items < MAX_ITEMS, "too many items"); - - return &obj->data; - } -}; - -static snapshot_builder builder; - -void *snap_new_item(int type, int id, int size) -{ - dbg_assert(type >= 0 && type <=0xffff, "incorrect type"); - dbg_assert(id >= 0 && id <=0xffff, "incorrect id"); - return builder.new_item(type, id, size); -} - - -// -class client -{ -public: - enum - { - STATE_EMPTY = 0, - STATE_CONNECTING = 1, - STATE_INGAME = 2, - }; - - // connection state info - int state; - - // (ticks) if lastactivity > 5 seconds kick him - int64 lastactivity; - connection conn; - - char name[MAX_NAME_LENGTH]; - char clan[MAX_CLANNAME_LENGTH]; - /* - client() - { - state = STATE_EMPTY; - name[0] = 0; - clan[0] = 0; - } - - ~client() - { - dbg_assert(state == STATE_EMPTY, "client destoyed while in use"); - }*/ - - bool is_empty() const { return state == STATE_EMPTY; } - bool is_ingame() const { return state == STATE_INGAME; } - const netaddr4 &address() const { return conn.address(); } -}; - -static client clients[MAX_CLIENTS]; -static int current_tick = 0; -static int send_heartbeats = 1; - -int server_tick() -{ - return current_tick; -} - -int server_tickspeed() -{ - return 50; -} - -int server_init() -{ - for(int i = 0; i < MAX_CLIENTS; i++) - { - clients[i].state = client::STATE_EMPTY; - clients[i].name[0] = 0; - clients[i].clan[0] = 0; - clients[i].lastactivity = 0; - } - - current_tick = 0; - - return 0; -} - -int server_getclientinfo(int client_id, client_info *info) -{ - dbg_assert(client_id >= 0 && client_id < MAX_CLIENTS, "client_id is not valid"); - dbg_assert(info != 0, "info can not be null"); - - if(clients[client_id].is_ingame()) - { - info->name = clients[client_id].name; - info->latency = 0; - return 1; - } - return 0; -} - -// -class server -{ -public: - - socket_udp4 game_socket; - const char *map_name; - const char *server_name; - int64 lasttick; - int64 lastheartbeat; - netaddr4 master_server; - - int biggest_snapshot; - - bool run(const char *servername, const char *mapname) - { - biggest_snapshot = 0; - - net_init(); // For Windows compatibility. - map_name = mapname; - server_name = servername; - - // load map - if(!map_load(mapname)) - { - dbg_msg("server", "failed to load map. mapname='%s'"); - return false; - } - - // start server - if(!game_socket.open(8303)) - { - dbg_msg("network/server", "couldn't open socket"); - return false; - } - - for(int i = 0; i < MAX_CLIENTS; i++) - dbg_msg("network/server", "\t%d: %d", i, clients[i].state); - - if (net_host_lookup(MASTER_SERVER_ADDRESS, MASTER_SERVER_PORT, &master_server) != 0) - master_server = netaddr4(0, 0, 0, 0, 0); - - mods_init(); - - int64 time_per_tick = time_freq()/SERVER_TICK_SPEED; - int64 time_per_heartbeat = time_freq() * 30; - int64 starttime = time_get(); - //int64 lasttick = starttime; - lasttick = starttime; - lastheartbeat = 0; - - int64 reporttime = time_get(); - int64 reportinterval = time_freq()*3; - - int64 simulationtime = 0; - int64 snaptime = 0; - int64 networktime = 0; - - while(1) - { - int64 t = time_get(); - if(t-lasttick > time_per_tick) - { - { - int64 start = time_get(); - tick(); - simulationtime += time_get()-start; - } - - { - int64 start = time_get(); - snap(); - snaptime += time_get()-start; - } - - // Check for client timeouts - for (int i = 0; i < MAX_CLIENTS; i++) - { - if (clients[i].state != client::STATE_EMPTY) - { - // check last activity time - if (((lasttick - clients[i].lastactivity) / time_freq()) > SERVER_CLIENT_TIMEOUT) - client_timeout(i); - } - } - - lasttick += time_per_tick; - } - - if(send_heartbeats) - { - if (t > lastheartbeat+time_per_heartbeat) - { - if (master_server.port != 0) - { - int players = 0; - - for (int i = 0; i < MAX_CLIENTS; i++) - if (!clients[i].is_empty()) - players++; - - netaddr4 me(127, 0, 0, 0, 8303); - - send_heartbeat(0, &me, players, MAX_CLIENTS, server_name, mapname); - } - - lastheartbeat = t+time_per_heartbeat; - } - } - - { - int64 start = time_get(); - pump_network(); - networktime += time_get()-start; - } - - if(reporttime < time_get()) - { - int64 totaltime = simulationtime+snaptime+networktime; - dbg_msg("server/report", "sim=%.02fms snap=%.02fms net=%.02fms total=%.02fms load=%.02f%%", - simulationtime/(float)reportinterval*1000, - snaptime/(float)reportinterval*1000, - networktime/(float)reportinterval*1000, - totaltime/(float)reportinterval*1000, - (simulationtime+snaptime+networktime)/(float)reportinterval*100.0f); - - unsigned sent_total=0, recv_total=0; - for (int i = 0; i < MAX_CLIENTS; i++) - if (!clients[i].is_empty()) - { - unsigned s,r; - clients[i].conn.counter_get(&s,&r); - clients[i].conn.counter_reset(); - sent_total += s; - recv_total += r; - } - - - dbg_msg("server/report", "biggestsnap=%d send=%d recv=%d", - biggest_snapshot, sent_total/3, recv_total/3); - - simulationtime = 0; - snaptime = 0; - networktime = 0; - - reporttime += reportinterval; - } - - thread_sleep(1); - } - - mods_shutdown(); - map_unload(); - } - - void tick() - { - current_tick++; - mods_tick(); - } - - void snap() - { - mods_presnap(); - - for(int i = 0; i < MAX_CLIENTS; i++) - { - if(clients[i].is_ingame()) - { - char data[MAX_SNAPSHOT_SIZE]; - char compdata[MAX_SNAPSHOT_SIZE]; - builder.start(); - mods_snap(i); - - // finish snapshot - int snapshot_size = builder.finish(data); - - // compress it - int compsize = lzw_compress(data, snapshot_size, compdata); - snapshot_size = compsize; - - if(snapshot_size > biggest_snapshot) - biggest_snapshot = snapshot_size; - - const int max_size = MAX_SNAPSHOT_PACKSIZE; - int numpackets = (snapshot_size+max_size-1)/max_size; - for(int n = 0, left = snapshot_size; left; n++) - { - int chunk = left < max_size ? left : max_size; - left -= chunk; - - packet p(NETMSG_SERVER_SNAP); - p.write_int(numpackets); - p.write_int(n); - p.write_int(chunk); - p.write_raw(&compdata[n*max_size], chunk); - clients[i].conn.send(&p); - } - } - } - - mods_postsnap(); - } - - void send_accept(client *client, const char *map) - { - packet p(NETMSG_SERVER_ACCEPT); - p.write_str(map); - client->conn.send(&p); - } - - void drop(int cid, const char *reason) - { - if(clients[cid].state == client::STATE_EMPTY) - return; - - clients[cid].state = client::STATE_EMPTY; - mods_client_drop(cid); - dbg_msg("game", "player dropped. reason='%s' cid=%x name='%s'", reason, cid, clients[cid].name); - } - - int find_client(const netaddr4 *addr) - { - // fetch client - for(int i = 0; i < MAX_CLIENTS; i++) - { - if(!clients[i].is_empty() && clients[i].address() == *addr) - return i; - } - return -1; - } - - void client_process_packet(int cid, packet *p) - { - clients[cid].lastactivity = lasttick; - if(p->msg() == NETMSG_CLIENT_DONE) - { - dbg_msg("game", "player as entered the game. cid=%x", cid); - clients[cid].state = client::STATE_INGAME; - mods_client_enter(cid); - } - else if(p->msg() == NETMSG_CLIENT_INPUT) - { - int input[MAX_INPUT_SIZE]; - int size = p->read_int(); - for(int i = 0; i < size/4; i++) - input[i] = p->read_int(); - if(p->is_good()) - { - //dbg_msg("network/server", "applying input %d %d %d", input[0], input[1], input[2]); - mods_client_input(cid, input); - } - } - else if(p->msg() == NETMSG_CLIENT_ERROR) - { - const char *reason = p->read_str(); - if(p->is_good()) - dbg_msg("network/server", "client error. cid=%x reason='%s'", cid, reason); - else - dbg_msg("network/server", "client error. cid=%x", cid); - drop(cid, "client error"); - } - else - { - dbg_msg("network/server", "invalid message. cid=%x msg=%x", cid, p->msg()); - drop(cid, "invalid message"); - } - } - - void process_packet(packet *p, netaddr4 *from) - { - if(p->msg() == NETMSG_CLIENT_CONNECT) - { - // we got no state for this client yet - const char *version; - const char *name; - const char *clan; - const char *password; - const char *skin; - - version = p->read_str(); - name = p->read_str(); - clan = p->read_str(); - password = p->read_str(); - skin = p->read_str(); - - if(p->is_good()) - { - // check version - if(strncmp(version, TEEWARS_NETVERSION, 32) != 0) - { - // TODO: send error - return; - } - - // look for empty slot, linear search - int id = -1; - for(int i = 0; i < MAX_CLIENTS; i++) - if(clients[i].is_empty()) - { - id = i; - break; - } - - if(id != -1) - { - // slot found - // TODO: perform correct copy here - mem_copy(clients[id].name, name, MAX_NAME_LENGTH); - mem_copy(clients[id].clan, clan, MAX_CLANNAME_LENGTH); - clients[id].state = client::STATE_CONNECTING; - clients[id].conn.init(&game_socket, from); - - clients[id].lastactivity = lasttick; - clients[id].name[MAX_NAME_LENGTH-1] = 0; - clients[id].clan[MAX_CLANNAME_LENGTH-1] = 0; - - dbg_msg("network/server", "client connected. '%s' on slot %d", name, id); - - // TODO: return success - send_accept(&clients[id], map_name); - } - else - { - // no slot found - // TODO: send error - dbg_msg("network/server", "client connected but server is full"); - - for(int i = 0; i < MAX_CLIENTS; i++) - dbg_msg("network/server", "\t%d: %d", i, clients[i].state); - } - } - } - else - { - int cid = find_client(from); - if(cid >= 0) - { - if(clients[cid].conn.feed(p)) - { - // packet is ok - unsigned msg = p->msg(); - - // client found, check state - if(((msg>>16)&0xff)&clients[cid].state) - { - // state is ok - client_process_packet(cid, p); - } - else - { - // invalid state, disconnect the client - drop(cid, "invalid message at this state"); - } - } - else - { - drop(cid, "connection error"); - } - - } - else - dbg_msg("network/server", "packet from strange address."); - } - } - - void client_timeout(int clientId) - { - drop(clientId, "client timedout"); - } - - void pump_network() - { - while(1) - { - packet p; - netaddr4 from; - - int bytes = game_socket.recv(&from, p.data(), p.max_size()); - if(bytes <= 0) - break; - - process_packet(&p, &from); - } - // TODO: check for client timeouts - } - - char *write_int(char *buffer, int integer) - { - *buffer++ = integer >> 24; - *buffer++ = integer >> 16; - *buffer++ = integer >> 8; - *buffer++ = integer; - - return buffer; - } - - char *write_netaddr4(char *buffer, netaddr4 *address) - { - *buffer++ = address->ip[0]; - *buffer++ = address->ip[1]; - *buffer++ = address->ip[2]; - *buffer++ = address->ip[3]; - - return write_int(buffer, address->port); - } - - void send_heartbeat(int version, netaddr4 *address, int players, int max_players, const char *name, const char *map_name) - { - char buffer[216] = {0}; - char *d = buffer; - - d = write_int(d, 'TWHB'); - d = write_int(d, version); - d = write_netaddr4(d, address); - d = write_int(d,players); - d = write_int(d, max_players); - - int len = strlen(name); - if (len > 128) - len = 128; - - memcpy(d, name, len); - d += 128; - - len = strlen(map_name); - if (len > 64) - len = 64; - - memcpy(d, map_name, len); - d += 64; - - game_socket.send(&master_server, buffer, sizeof(buffer)); - } -}; - -int server_main(int argc, char **argv) -{ - dbg_msg("server", "starting..."); - - const char *mapname = "data/demo.map"; - const char *servername = 0; - // parse arguments - for(int i = 1; i < argc; i++) - { - if(argv[i][0] == '-' && argv[i][1] == 'm' && argv[i][2] == 0 && argc - i > 1) - { - // -m map - i++; - mapname = argv[i]; - } - else if(argv[i][0] == '-' && argv[i][1] == 'n' && argv[i][2] == 0 && argc - i > 1) - { - // -n server name - i++; - servername = argv[i]; - } - else if(argv[i][0] == '-' && argv[i][1] == 'p' && argv[i][2] == 0) - { - // -p (private server) - send_heartbeats = 0; - } - } - - if(!mapname) - { - dbg_msg("server", "no map given (-m MAPNAME)"); - return 0; - } - - if(!servername) - { - dbg_msg("server", "no server name given (-n \"server name\")"); - return 0; - } - - server_init(); - server s; - s.run(servername, mapname); - return 0; -} |