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

This commit is contained in:
Magnus Auvinen 2008-09-24 09:03:49 +00:00
parent d9d37b945e
commit eb21e9d6bb
10 changed files with 112 additions and 60 deletions

View file

@ -47,6 +47,7 @@ enum
NET_PACKETFLAG_CONTROL=1, NET_PACKETFLAG_CONTROL=1,
NET_PACKETFLAG_CONNLESS=2, NET_PACKETFLAG_CONNLESS=2,
NET_PACKETFLAG_RESEND=4, NET_PACKETFLAG_RESEND=4,
NET_PACKETFLAG_COMPRESSION=8,
NET_CHUNKFLAG_VITAL=1, NET_CHUNKFLAG_VITAL=1,
NET_CHUNKFLAG_RESEND=2, 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) static void send_packet(NETSOCKET socket, NETADDR *addr, NETPACKETCONSTRUCT *packet)
{ {
unsigned char buffer[NET_MAX_PACKETSIZE]; unsigned char buffer[NET_MAX_PACKETSIZE];
buffer[0] = ((packet->flags<<4)&0xf0)|((packet->ack>>8)&0xf); int compressed_size = -1;
buffer[1] = packet->ack&0xff; int final_size = -1;
buffer[2] = packet->num_chunks;
/* log the data */
if(datalog) if(datalog)
{ {
io_write(datalog, &packet->data_size, sizeof(packet->data_size)); io_write(datalog, &packet->data_size, sizeof(packet->data_size));
io_write(datalog, &packet->chunk_data, packet->data_size); io_write(datalog, &packet->chunk_data, packet->data_size);
} }
/* compress if its enabled */
if(COMPRESSION) 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); final_size = compressed_size;
net_udp_send(socket, addr, buffer, NET_PACKETHEADERSIZE+compressed_size); packet->flags |= NET_PACKETFLAG_COMPRESSION;
} }
else else
{ {
/* use uncompressed data */
final_size = packet->data_size;
mem_copy(&buffer[3], packet->chunk_data, 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 */ /* check the size */
if(size < NET_PACKETHEADERSIZE || size > NET_MAX_PACKETSIZE) if(size < NET_PACKETHEADERSIZE || size > NET_MAX_PACKETSIZE)
{ {
dbg_msg("", "packet too small"); dbg_msg("", "packet too small, %d", size);
return -1; return -1;
} }
@ -281,7 +299,7 @@ static int unpack_packet(unsigned char *buffer, int size, NETPACKETCONSTRUCT *pa
} }
else else
{ {
if(COMPRESSION) if(packet->flags&NET_PACKETFLAG_COMPRESSION)
huffman_decompress(&huffmanstate, &buffer[3], packet->data_size, packet->chunk_data, sizeof(packet->chunk_data)); huffman_decompress(&huffmanstate, &buffer[3], packet->data_size, packet->chunk_data, sizeof(packet->chunk_data));
else else
mem_copy(packet->chunk_data, &buffer[3], packet->data_size); mem_copy(packet->chunk_data, &buffer[3], packet->data_size);

View file

@ -38,8 +38,6 @@ static int browseinfo_progression = -1;
static int64 lastheartbeat; static int64 lastheartbeat;
/*static NETADDR4 master_server;*/ /*static NETADDR4 master_server;*/
static char current_map[64]; static char current_map[64];
static int current_map_crc; static int current_map_crc;
static unsigned char *current_map_data = 0; 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 */ /* reset input */
int i;
for(i = 0; i < 200; i++) for(i = 0; i < 200; i++)
{ {
clients[cid].inputs[i].game_tick = -1; clients[cid].inputs[i].game_tick = -1;
clients[cid].inputs[i].pred_tick = -1; clients[cid].inputs[i].pred_tick = -1;
} }
clients[cid].current_input = 0; clients[cid].current_input = 0;
mem_zero(&clients[cid].latestinput, sizeof(clients[cid].latestinput)); mem_zero(&clients[cid].latestinput, sizeof(clients[cid].latestinput));
snapstorage_purge_all(&clients[cid].snapshots); snapstorage_purge_all(&clients[cid].snapshots);
clients[cid].last_acked_snapshot = -1; clients[cid].last_acked_snapshot = -1;
clients[cid].snap_rate = SRVCLIENT_SNAPRATE_INIT; clients[cid].snap_rate = SRVCLIENT_SNAPRATE_INIT;
clients[cid].score = 0; clients[cid].score = 0;
clients[cid].authed = 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; return 0;
} }
static int del_client_callback(int cid, void *user) static int del_client_callback(int cid, void *user)
{ {
/* notify the mod about the drop */ /* notify the mod about the drop */
if(clients[cid].state == SRVCLIENT_STATE_READY || if(clients[cid].state >= SRVCLIENT_STATE_READY)
clients[cid].state == SRVCLIENT_STATE_INGAME)
{
mods_client_drop(cid); mods_client_drop(cid);
}
clients[cid].state = SRVCLIENT_STATE_EMPTY; clients[cid].state = SRVCLIENT_STATE_EMPTY;
clients[cid].name[0] = 0; clients[cid].name[0] = 0;
clients[cid].clan[0] = 0; clients[cid].clan[0] = 0;
@ -682,7 +680,7 @@ static void server_process_client_packet(NETCHUNK *packet)
int tick, size, i; int tick, size, i;
CLIENT_INPUT *input; CLIENT_INPUT *input;
int64 tagtime; int64 tagtime;
clients[cid].last_acked_snapshot = msg_unpack_int(); clients[cid].last_acked_snapshot = msg_unpack_int();
tick = msg_unpack_int(); tick = msg_unpack_int();
size = msg_unpack_int(); size = msg_unpack_int();
@ -690,7 +688,7 @@ static void server_process_client_packet(NETCHUNK *packet)
/* check for errors */ /* check for errors */
if(msg_unpack_error() || size/4 > MAX_INPUT_SIZE) if(msg_unpack_error() || size/4 > MAX_INPUT_SIZE)
return; return;
if(clients[cid].last_acked_snapshot > 0) if(clients[cid].last_acked_snapshot > 0)
clients[cid].snap_rate = SRVCLIENT_SNAPRATE_FULL; clients[cid].snap_rate = SRVCLIENT_SNAPRATE_FULL;
@ -715,7 +713,8 @@ static void server_process_client_packet(NETCHUNK *packet)
clients[cid].current_input %= 200; clients[cid].current_input %= 200;
/* call the mod with the fresh input data */ /* 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) else if(msg == NETMSG_RCON_CMD)
{ {
@ -784,7 +783,8 @@ static void server_process_client_packet(NETCHUNK *packet)
else else
{ {
/* game message */ /* 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; continue;
server_send_map(c); server_send_map(c);
reset_client(c);
clients[c].state = SRVCLIENT_STATE_CONNECTING; 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(); game_start_time = time_get();
@ -1029,7 +1027,8 @@ static int server_run()
{ {
if(clients[c].inputs[i].game_tick == server_tick()) 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; break;
} }
} }

View file

@ -32,6 +32,9 @@ static INPUT_COUNT count_input(int prev, int cur)
return c; return c;
} }
MACRO_ALLOC_POOL_ID_IMPL(CHARACTER, MAX_CLIENTS)
// player // player
CHARACTER::CHARACTER() CHARACTER::CHARACTER()
: ENTITY(NETOBJTYPE_CHARACTER) : ENTITY(NETOBJTYPE_CHARACTER)

View file

@ -11,19 +11,8 @@
class CHARACTER : public ENTITY class CHARACTER : public ENTITY
{ {
/*static CHARACTER pool_data[MAX_CLIENTS]; MACRO_ALLOC_POOL_ID()
static int pool_used[MAX_CLIENTS];*/
public: 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 // player controlling this character
class PLAYER *player; class PLAYER *player;

View file

@ -1,14 +1,59 @@
#ifndef GAME_SERVER_ENTITY_H #ifndef GAME_SERVER_ENTITY_H
#define GAME_SERVER_ENTITY_H #define GAME_SERVER_ENTITY_H
#include <new>
#include <base/vmath.hpp> #include <base/vmath.hpp>
#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 Class: Entity
Basic entity class. Basic entity class.
*/ */
class ENTITY class ENTITY
{ {
MACRO_ALLOC_HEAP()
private: private:
friend class GAMEWORLD; // thy these? friend class GAMEWORLD; // thy these?
ENTITY *prev_entity; ENTITY *prev_entity;
@ -21,7 +66,6 @@ protected:
int id; int id;
int objtype; int objtype;
public: public:
ENTITY(int objtype); ENTITY(int objtype);
virtual ~ENTITY(); virtual ~ENTITY();

View file

@ -7,15 +7,13 @@ GAMECONTEXT game;
GAMECONTEXT::GAMECONTEXT() GAMECONTEXT::GAMECONTEXT()
{ {
for(int i = 0; i < MAX_CLIENTS; i++) for(int i = 0; i < MAX_CLIENTS; i++)
{
players[i] = 0; players[i] = 0;
/*players = new PLAYER();
players[i].init(-1);*/
}
} }
GAMECONTEXT::~GAMECONTEXT() GAMECONTEXT::~GAMECONTEXT()
{ {
for(int i = 0; i < MAX_CLIENTS; i++)
delete players[i];
} }
void GAMECONTEXT::clear() void GAMECONTEXT::clear()
@ -23,15 +21,6 @@ void GAMECONTEXT::clear()
this->~GAMECONTEXT(); this->~GAMECONTEXT();
mem_zero(this, sizeof(*this)); mem_zero(this, sizeof(*this));
new (this) GAMECONTEXT(); 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();
*/
} }

View file

@ -27,7 +27,6 @@
All players (PLAYER::snap) All players (PLAYER::snap)
*/ */
class GAMECONTEXT class GAMECONTEXT
{ {
public: public:

View file

@ -73,7 +73,7 @@ void mods_client_enter(int client_id)
void mods_connected(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].init(client_id);
//game.players[client_id].client_id = client_id; //game.players[client_id].client_id = client_id;

View file

@ -5,12 +5,20 @@
#include "player.hpp" #include "player.hpp"
#include "gamecontext.hpp" #include "gamecontext.hpp"
MACRO_ALLOC_POOL_ID_IMPL(PLAYER, MAX_CLIENTS)
PLAYER::PLAYER(int client_id) PLAYER::PLAYER(int client_id)
{ {
character = 0; character = 0;
this->client_id = client_id; this->client_id = client_id;
} }
PLAYER::~PLAYER()
{
delete character;
character = 0;
}
/* /*
void PLAYER::init(int client_id) void PLAYER::init(int client_id)
{ {
@ -168,7 +176,7 @@ void PLAYER::try_respawn()
if(num_ents == 0) if(num_ents == 0)
{ {
spawning = false; spawning = false;
character = new CHARACTER(); character = new(client_id) CHARACTER();
character->spawn(this, spawnpos, team); character->spawn(this, spawnpos, team);
} }
} }

View file

@ -7,9 +7,12 @@
// player object // player object
class PLAYER class PLAYER
{ {
MACRO_ALLOC_POOL_ID()
private:
CHARACTER *character; CHARACTER *character;
public: public:
PLAYER(int client_id); PLAYER(int client_id);
~PLAYER();
// TODO: clean this up // TODO: clean this up
char skin_name[64]; char skin_name[64];