From eb21e9d6bb772c6fba533bfe4b421dc7efe181b1 Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Wed, 24 Sep 2008 09:03:49 +0000 Subject: cleaned up the code a bit more. pooling of character and player objects with reusable macros. fixed crashing when changing maps and a couple of other bugs --- src/engine/e_network.c | 34 +++++++++++++++++++------ src/engine/server/es_server.c | 45 ++++++++++++++++----------------- src/game/server/entities/character.cpp | 3 +++ src/game/server/entities/character.hpp | 13 +--------- src/game/server/entity.hpp | 46 +++++++++++++++++++++++++++++++++- src/game/server/gamecontext.cpp | 15 ++--------- src/game/server/gamecontext.hpp | 1 - src/game/server/hooks.cpp | 2 +- src/game/server/player.cpp | 10 +++++++- src/game/server/player.hpp | 3 +++ 10 files changed, 112 insertions(+), 60 deletions(-) diff --git a/src/engine/e_network.c b/src/engine/e_network.c index ed9f3405..85a9117c 100644 --- a/src/engine/e_network.c +++ b/src/engine/e_network.c @@ -47,6 +47,7 @@ enum NET_PACKETFLAG_CONTROL=1, NET_PACKETFLAG_CONNLESS=2, NET_PACKETFLAG_RESEND=4, + NET_PACKETFLAG_COMPRESSION=8, NET_CHUNKFLAG_VITAL=1, NET_CHUNKFLAG_RESEND=2, @@ -234,24 +235,41 @@ static void send_packet_connless(NETSOCKET socket, NETADDR *addr, const void *da static void send_packet(NETSOCKET socket, NETADDR *addr, NETPACKETCONSTRUCT *packet) { unsigned char buffer[NET_MAX_PACKETSIZE]; - buffer[0] = ((packet->flags<<4)&0xf0)|((packet->ack>>8)&0xf); - buffer[1] = packet->ack&0xff; - buffer[2] = packet->num_chunks; + int compressed_size = -1; + int final_size = -1; + + /* log the data */ if(datalog) { io_write(datalog, &packet->data_size, sizeof(packet->data_size)); io_write(datalog, &packet->chunk_data, packet->data_size); } + /* compress if its enabled */ if(COMPRESSION) + compressed_size = huffman_compress(&huffmanstate, packet->chunk_data, packet->data_size, &buffer[3], NET_MAX_PACKETSIZE-4); + + /* check if the compression was enabled, successful and good enough */ + if(compressed_size > 0 && compressed_size < packet->data_size) { - int compressed_size = huffman_compress(&huffmanstate, packet->chunk_data, packet->data_size, &buffer[3], NET_MAX_PACKETSIZE-4); - net_udp_send(socket, addr, buffer, NET_PACKETHEADERSIZE+compressed_size); + final_size = compressed_size; + packet->flags |= NET_PACKETFLAG_COMPRESSION; } else { + /* use uncompressed data */ + final_size = packet->data_size; mem_copy(&buffer[3], packet->chunk_data, packet->data_size); - net_udp_send(socket, addr, buffer, NET_PACKETHEADERSIZE+packet->data_size); + packet->flags &= ~NET_PACKETFLAG_COMPRESSION; + } + + /* set header and send the packet if all things are good */ + if(final_size >= 0) + { + buffer[0] = ((packet->flags<<4)&0xf0)|((packet->ack>>8)&0xf); + buffer[1] = packet->ack&0xff; + buffer[2] = packet->num_chunks; + net_udp_send(socket, addr, buffer, NET_PACKETHEADERSIZE+final_size); } } @@ -261,7 +279,7 @@ static int unpack_packet(unsigned char *buffer, int size, NETPACKETCONSTRUCT *pa /* check the size */ if(size < NET_PACKETHEADERSIZE || size > NET_MAX_PACKETSIZE) { - dbg_msg("", "packet too small"); + dbg_msg("", "packet too small, %d", size); return -1; } @@ -281,7 +299,7 @@ static int unpack_packet(unsigned char *buffer, int size, NETPACKETCONSTRUCT *pa } else { - if(COMPRESSION) + if(packet->flags&NET_PACKETFLAG_COMPRESSION) huffman_decompress(&huffmanstate, &buffer[3], packet->data_size, packet->chunk_data, sizeof(packet->chunk_data)); else mem_copy(packet->chunk_data, &buffer[3], packet->data_size); diff --git a/src/engine/server/es_server.c b/src/engine/server/es_server.c index a3c8327f..6cdf835f 100644 --- a/src/engine/server/es_server.c +++ b/src/engine/server/es_server.c @@ -38,8 +38,6 @@ static int browseinfo_progression = -1; static int64 lastheartbeat; /*static NETADDR4 master_server;*/ - - static char current_map[64]; static int current_map_crc; static unsigned char *current_map_data = 0; @@ -521,40 +519,40 @@ static void server_do_snap() } -static int new_client_callback(int cid, void *user) +static void reset_client(int cid) { - int i; - clients[cid].state = SRVCLIENT_STATE_CONNECTING; - clients[cid].name[0] = 0; - clients[cid].clan[0] = 0; - /* reset input */ + int i; for(i = 0; i < 200; i++) { clients[cid].inputs[i].game_tick = -1; clients[cid].inputs[i].pred_tick = -1; } clients[cid].current_input = 0; - mem_zero(&clients[cid].latestinput, sizeof(clients[cid].latestinput)); - + snapstorage_purge_all(&clients[cid].snapshots); clients[cid].last_acked_snapshot = -1; clients[cid].snap_rate = SRVCLIENT_SNAPRATE_INIT; clients[cid].score = 0; clients[cid].authed = 0; +} + +static int new_client_callback(int cid, void *user) +{ + clients[cid].state = SRVCLIENT_STATE_CONNECTING; + clients[cid].name[0] = 0; + clients[cid].clan[0] = 0; + reset_client(cid); return 0; } static int del_client_callback(int cid, void *user) { /* notify the mod about the drop */ - if(clients[cid].state == SRVCLIENT_STATE_READY || - clients[cid].state == SRVCLIENT_STATE_INGAME) - { + if(clients[cid].state >= SRVCLIENT_STATE_READY) mods_client_drop(cid); - } - + clients[cid].state = SRVCLIENT_STATE_EMPTY; clients[cid].name[0] = 0; clients[cid].clan[0] = 0; @@ -682,7 +680,7 @@ static void server_process_client_packet(NETCHUNK *packet) int tick, size, i; CLIENT_INPUT *input; int64 tagtime; - + clients[cid].last_acked_snapshot = msg_unpack_int(); tick = msg_unpack_int(); size = msg_unpack_int(); @@ -690,7 +688,7 @@ static void server_process_client_packet(NETCHUNK *packet) /* check for errors */ if(msg_unpack_error() || size/4 > MAX_INPUT_SIZE) return; - + if(clients[cid].last_acked_snapshot > 0) clients[cid].snap_rate = SRVCLIENT_SNAPRATE_FULL; @@ -715,7 +713,8 @@ static void server_process_client_packet(NETCHUNK *packet) clients[cid].current_input %= 200; /* call the mod with the fresh input data */ - mods_client_direct_input(cid, clients[cid].latestinput.data); + if(clients[cid].state == SRVCLIENT_STATE_INGAME) + mods_client_direct_input(cid, clients[cid].latestinput.data); } else if(msg == NETMSG_RCON_CMD) { @@ -784,7 +783,8 @@ static void server_process_client_packet(NETCHUNK *packet) else { /* game message */ - mods_message(msg, cid); + if(clients[cid].state >= SRVCLIENT_STATE_READY) + mods_message(msg, cid); } } @@ -992,10 +992,8 @@ static int server_run() continue; server_send_map(c); + reset_client(c); clients[c].state = SRVCLIENT_STATE_CONNECTING; - clients[c].last_acked_snapshot = -1; - clients[c].snap_rate = SRVCLIENT_SNAPRATE_RECOVER; - snapstorage_purge_all(&clients[c].snapshots); } game_start_time = time_get(); @@ -1029,7 +1027,8 @@ static int server_run() { if(clients[c].inputs[i].game_tick == server_tick()) { - mods_client_predicted_input(c, clients[c].inputs[i].data); + if(clients[c].state == SRVCLIENT_STATE_INGAME) + mods_client_predicted_input(c, clients[c].inputs[i].data); break; } } diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index 60acdca8..e79962c2 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -32,6 +32,9 @@ static INPUT_COUNT count_input(int prev, int cur) return c; } + +MACRO_ALLOC_POOL_ID_IMPL(CHARACTER, MAX_CLIENTS) + // player CHARACTER::CHARACTER() : ENTITY(NETOBJTYPE_CHARACTER) diff --git a/src/game/server/entities/character.hpp b/src/game/server/entities/character.hpp index 9bd441ba..c25b4b5f 100644 --- a/src/game/server/entities/character.hpp +++ b/src/game/server/entities/character.hpp @@ -11,19 +11,8 @@ class CHARACTER : public ENTITY { - /*static CHARACTER pool_data[MAX_CLIENTS]; - static int pool_used[MAX_CLIENTS];*/ + MACRO_ALLOC_POOL_ID() public: -/* - void operator delete(void *character) - { - (CHARACTER *)character - int id = (CHARACTER *)character - (CHARACTER *)pool_data; - dbg_assert(pool_used[id], ""); - pool_used[id] = 0; - mem_zero(&pool_data[id], sizeof(CHARACTER)); - }*/ - // player controlling this character class PLAYER *player; diff --git a/src/game/server/entity.hpp b/src/game/server/entity.hpp index d3ae3a1c..8ccb2d9a 100644 --- a/src/game/server/entity.hpp +++ b/src/game/server/entity.hpp @@ -1,14 +1,59 @@ #ifndef GAME_SERVER_ENTITY_H #define GAME_SERVER_ENTITY_H +#include #include +#define MACRO_ALLOC_HEAP() \ + public: \ + void *operator new(size_t size) \ + { \ + void *p = mem_alloc(size, 1); \ + /*dbg_msg("", "++ %p %d", p, size);*/ \ + mem_zero(p, size); \ + return p; \ + } \ + void operator delete(void *p) \ + { \ + /*dbg_msg("", "-- %p", p);*/ \ + mem_free(p); \ + } \ + private: + +#define MACRO_ALLOC_POOL_ID() \ + public: \ + void *operator new(size_t size, int id); \ + void operator delete(void *p); \ + private: + +#define MACRO_ALLOC_POOL_ID_IMPL(POOLTYPE, poolsize) \ + static char pool_data_##POOLTYPE[poolsize][sizeof(POOLTYPE)] = {{0}}; \ + static int pool_used_##POOLTYPE[poolsize] = {0}; \ + void *POOLTYPE::operator new(size_t size, int id) \ + { \ + dbg_assert(sizeof(POOLTYPE) == size, "size error"); \ + dbg_assert(!pool_used_##POOLTYPE[id], "already used"); \ + /*dbg_msg("pool", "++ %s %d", #POOLTYPE, id);*/ \ + pool_used_##POOLTYPE[id] = 1; \ + mem_zero(pool_data_##POOLTYPE[id], size); \ + return pool_data_##POOLTYPE[id]; \ + } \ + void POOLTYPE::operator delete(void *p) \ + { \ + int id = (POOLTYPE*)p - (POOLTYPE*)pool_data_##POOLTYPE; \ + dbg_assert(pool_used_##POOLTYPE[id], "not used"); \ + /*dbg_msg("pool", "-- %s %d", #POOLTYPE, id);*/ \ + pool_used_##POOLTYPE[id] = 0; \ + mem_zero(pool_data_##POOLTYPE[id], sizeof(POOLTYPE)); \ + } + /* Class: Entity Basic entity class. */ class ENTITY { + MACRO_ALLOC_HEAP() private: friend class GAMEWORLD; // thy these? ENTITY *prev_entity; @@ -21,7 +66,6 @@ protected: int id; int objtype; public: - ENTITY(int objtype); virtual ~ENTITY(); diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 7866e0f0..987ce64e 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -7,15 +7,13 @@ GAMECONTEXT game; GAMECONTEXT::GAMECONTEXT() { for(int i = 0; i < MAX_CLIENTS; i++) - { players[i] = 0; - /*players = new PLAYER(); - players[i].init(-1);*/ - } } GAMECONTEXT::~GAMECONTEXT() { + for(int i = 0; i < MAX_CLIENTS; i++) + delete players[i]; } void GAMECONTEXT::clear() @@ -23,15 +21,6 @@ void GAMECONTEXT::clear() this->~GAMECONTEXT(); mem_zero(this, sizeof(*this)); new (this) GAMECONTEXT(); - // reset all players - /* - for(int i = 0; i < MAX_CLIENTS; i++) - players[i].init(-1); - - world.~GAMEWORLD(); - mem_zero(&world, sizeof(world)); - world.GAMEWORLD(); - */ } diff --git a/src/game/server/gamecontext.hpp b/src/game/server/gamecontext.hpp index 4c7079c8..dd10ec4d 100644 --- a/src/game/server/gamecontext.hpp +++ b/src/game/server/gamecontext.hpp @@ -27,7 +27,6 @@ All players (PLAYER::snap) */ - class GAMECONTEXT { public: diff --git a/src/game/server/hooks.cpp b/src/game/server/hooks.cpp index 0cd6d6e1..494f4f62 100644 --- a/src/game/server/hooks.cpp +++ b/src/game/server/hooks.cpp @@ -73,7 +73,7 @@ void mods_client_enter(int client_id) void mods_connected(int client_id) { - game.players[client_id] = new PLAYER(client_id); + game.players[client_id] = new(client_id) PLAYER(client_id); //game.players[client_id].init(client_id); //game.players[client_id].client_id = client_id; diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index a31cf21c..252e23e3 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -5,12 +5,20 @@ #include "player.hpp" #include "gamecontext.hpp" +MACRO_ALLOC_POOL_ID_IMPL(PLAYER, MAX_CLIENTS) + PLAYER::PLAYER(int client_id) { character = 0; this->client_id = client_id; } +PLAYER::~PLAYER() +{ + delete character; + character = 0; +} + /* void PLAYER::init(int client_id) { @@ -168,7 +176,7 @@ void PLAYER::try_respawn() if(num_ents == 0) { spawning = false; - character = new CHARACTER(); + character = new(client_id) CHARACTER(); character->spawn(this, spawnpos, team); } } diff --git a/src/game/server/player.hpp b/src/game/server/player.hpp index 9836bffc..c92265a8 100644 --- a/src/game/server/player.hpp +++ b/src/game/server/player.hpp @@ -7,9 +7,12 @@ // player object class PLAYER { + MACRO_ALLOC_POOL_ID() +private: CHARACTER *character; public: PLAYER(int client_id); + ~PLAYER(); // TODO: clean this up char skin_name[64]; -- cgit 1.4.1