2007-07-13 13:40:04 +00:00
|
|
|
#include <stdarg.h>
|
2007-05-22 15:03:32 +00:00
|
|
|
#include <baselib/stream/file.h>
|
|
|
|
#include <baselib/network.h>
|
|
|
|
|
2007-05-27 00:47:07 +00:00
|
|
|
#include "versions.h"
|
2007-07-13 13:40:04 +00:00
|
|
|
#include "ringbuffer.h"
|
|
|
|
#include "compression.h"
|
|
|
|
#include "snapshot.h"
|
2007-05-27 00:47:07 +00:00
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
NETMSG_NULL=0,
|
|
|
|
|
|
|
|
// sent by server
|
|
|
|
NETMSG_MAP,
|
|
|
|
NETMSG_SNAP,
|
|
|
|
NETMSG_SNAPEMPTY,
|
|
|
|
NETMSG_SNAPSMALL,
|
|
|
|
|
|
|
|
// sent by client
|
|
|
|
NETMSG_INFO,
|
|
|
|
NETMSG_ENTERGAME,
|
|
|
|
NETMSG_INPUT,
|
|
|
|
NETMSG_SNAPACK,
|
|
|
|
|
|
|
|
// sent by both
|
|
|
|
NETMSG_ERROR,
|
|
|
|
};
|
2007-05-27 00:47:07 +00:00
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
|
|
|
|
// this should be revised
|
|
|
|
enum
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
MAX_NAME_LENGTH=32,
|
|
|
|
MAX_CLANNAME_LENGTH=32,
|
|
|
|
MAX_INPUT_SIZE=128,
|
|
|
|
MAX_SNAPSHOT_SIZE=64*1024,
|
|
|
|
MAX_SNAPSHOT_PACKSIZE=768
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class snapshot_storage
|
|
|
|
{
|
|
|
|
struct holder
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-22 09:15:34 +00:00
|
|
|
int64 tagtime;
|
2007-07-13 13:40:04 +00:00
|
|
|
int tick;
|
|
|
|
int data_size;
|
|
|
|
int *data() { return (int *)(this+1); }
|
2007-05-22 15:03:32 +00:00
|
|
|
};
|
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
ring_buffer buffer;
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
public:
|
|
|
|
void purge_until(int tick)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
while(1)
|
|
|
|
{
|
|
|
|
ring_buffer::item *i = buffer.first();
|
|
|
|
if(!i)
|
|
|
|
break;
|
|
|
|
holder *h = (holder *)i->data();
|
|
|
|
if(h->tick < tick)
|
|
|
|
buffer.pop_first();
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
void purge_all()
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
buffer.reset();
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-22 09:15:34 +00:00
|
|
|
void add(int tick, int64 tagtime, int data_size, void *data)
|
2007-05-24 10:57:18 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
holder *h = (holder *)buffer.alloc(sizeof(holder)+data_size);
|
|
|
|
h->tick = tick;
|
|
|
|
h->data_size = data_size;
|
2007-07-22 09:15:34 +00:00
|
|
|
h->tagtime = tagtime;
|
2007-07-13 13:40:04 +00:00
|
|
|
mem_copy(h->data(), data, data_size);
|
2007-05-24 10:57:18 +00:00
|
|
|
}
|
|
|
|
|
2007-07-22 09:15:34 +00:00
|
|
|
int get(int tick, int64 *tagtime, void **data)
|
2007-05-24 10:57:18 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
ring_buffer::item *i = buffer.first();
|
|
|
|
while(i)
|
|
|
|
{
|
|
|
|
holder *h = (holder *)i->data();
|
|
|
|
if(h->tick == tick)
|
|
|
|
{
|
2007-07-22 09:15:34 +00:00
|
|
|
if(data)
|
|
|
|
*data = h->data();
|
|
|
|
if(tagtime)
|
|
|
|
*tagtime = h->tagtime;
|
2007-07-13 13:40:04 +00:00
|
|
|
return h->data_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
i = i->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
2007-07-13 13:40:04 +00:00
|
|
|
};
|
|
|
|
/*
|
|
|
|
class snapshot_delta_builder
|
|
|
|
{
|
2007-05-22 15:03:32 +00:00
|
|
|
public:
|
2007-07-13 13:40:04 +00:00
|
|
|
static const int MAX_ITEMS = 512;
|
2007-05-27 00:47:07 +00:00
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
char data[MAX_SNAPSHOT_SIZE];
|
|
|
|
int data_size;
|
2007-05-27 00:47:07 +00:00
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
int offsets[MAX_ITEMS];
|
|
|
|
int num_items;
|
|
|
|
|
|
|
|
int top_size;
|
|
|
|
int top_items;
|
2007-05-27 00:47:07 +00:00
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
int snapnum;
|
|
|
|
|
|
|
|
snapshot_delta_builder()
|
|
|
|
{
|
|
|
|
top_size = 0;
|
|
|
|
top_items = 0;
|
|
|
|
snapnum = 0;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
2007-07-13 13:40:04 +00:00
|
|
|
|
|
|
|
void start()
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
data_size = 0;
|
|
|
|
num_items = 0;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
2007-07-13 13:40:04 +00:00
|
|
|
|
|
|
|
int finish(void *snapdata)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
snapnum++;
|
|
|
|
|
|
|
|
// flattern and make the snapshot
|
|
|
|
snapshot *snap = (snapshot *)snapdata;
|
|
|
|
snap->data_size = data_size;
|
|
|
|
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;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
2007-07-13 13:40:04 +00:00
|
|
|
};
|
|
|
|
*/
|
|
|
|
|
|
|
|
class snapshot_builder
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
static const int MAX_ITEMS = 512;
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
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()
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
top_size = 0;
|
|
|
|
top_items = 0;
|
|
|
|
snapnum = 0;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
void start()
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
data_size = 0;
|
|
|
|
num_items = 0;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
snapshot::item *get_item(int index)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
return (snapshot::item *)&(data[offsets[index]]);
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
int *get_item_data(int key)
|
2007-05-24 10:57:18 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
for(int i = 0; i < num_items; i++)
|
|
|
|
{
|
|
|
|
if(get_item(i)->key() == key)
|
|
|
|
return (int *)get_item(i)->data();
|
|
|
|
}
|
|
|
|
return 0;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
2007-07-13 13:40:04 +00:00
|
|
|
|
|
|
|
int finish(void *snapdata)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
snapnum++;
|
|
|
|
|
|
|
|
// flattern and make the snapshot
|
|
|
|
snapshot *snap = (snapshot *)snapdata;
|
|
|
|
snap->data_size = data_size;
|
|
|
|
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(snapshot) + offset_size + data_size;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
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(snapshot::item) + 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();
|
|
|
|
}
|
2007-05-22 15:03:32 +00:00
|
|
|
};
|
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
class data_packer
|
2007-05-27 00:47:07 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
enum
|
2007-05-27 00:47:07 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
BUFFER_SIZE=1024*2
|
2007-05-27 00:47:07 +00:00
|
|
|
};
|
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
unsigned char buffer[BUFFER_SIZE];
|
|
|
|
unsigned char *current;
|
|
|
|
unsigned char *end;
|
|
|
|
int error;
|
2007-05-27 00:47:07 +00:00
|
|
|
public:
|
|
|
|
void reset()
|
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
error = 0;
|
|
|
|
current = buffer;
|
|
|
|
end = current + BUFFER_SIZE;
|
2007-05-27 00:47:07 +00:00
|
|
|
}
|
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
void add_int(int i)
|
2007-05-27 00:47:07 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
// TODO: add space check
|
|
|
|
// TODO: variable length encoding perhaps
|
|
|
|
// TODO: add debug marker
|
|
|
|
current = vint_pack(current, i);
|
|
|
|
//*current++ = (i>>24)&0xff;
|
|
|
|
//*current++ = (i>>16)&0xff;
|
|
|
|
//*current++ = (i>>8)&0xff;
|
|
|
|
//*current++ = i&0xff;
|
2007-05-27 00:47:07 +00:00
|
|
|
}
|
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
void add_string(const char *p, int limit)
|
2007-05-27 00:47:07 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
// TODO: add space check
|
|
|
|
// TODO: add debug marker
|
|
|
|
if(limit > 0)
|
2007-05-27 00:47:07 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
while(*p && limit != 0)
|
|
|
|
{
|
|
|
|
*current++ = *p++;
|
|
|
|
limit--;
|
|
|
|
}
|
|
|
|
*current++ = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while(*p)
|
|
|
|
*current++ = *p++;
|
|
|
|
*current++ = 0;
|
2007-05-27 00:47:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
void add_raw(const unsigned char *data, int size)
|
2007-05-27 00:47:07 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
// TODO: add space check
|
|
|
|
// TODO: add debug marker
|
|
|
|
//add_int(size);
|
|
|
|
while(size)
|
2007-05-27 00:47:07 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
*current++ = *data++;
|
|
|
|
size--;
|
|
|
|
}
|
2007-05-27 00:47:07 +00:00
|
|
|
}
|
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
int size() const
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
return (const unsigned char *)current-(const unsigned char *)buffer;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
const unsigned char *data()
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
return (const unsigned char *)buffer;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
2007-07-13 13:40:04 +00:00
|
|
|
};
|
2007-05-22 15:03:32 +00:00
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
class data_unpacker
|
|
|
|
{
|
|
|
|
const unsigned char *current;
|
|
|
|
const unsigned char *start;
|
|
|
|
const unsigned char *end;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
public:
|
|
|
|
void reset(const unsigned char *data, int size)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
error = 0;
|
|
|
|
start = data;
|
|
|
|
end = start + size;
|
|
|
|
current = start;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
int get_int()
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
int i;
|
|
|
|
current = vint_unpack(current, &i);
|
|
|
|
// TODO: might be changed into variable width
|
|
|
|
// TODO: add range check
|
|
|
|
// TODO: add debug marker
|
|
|
|
//i = (current[0]<<24) | (current[1]<<16) | (current[2]<<8) | (current[3]);
|
|
|
|
//current += 4;
|
|
|
|
return i;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
const char *get_string()
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
// TODO: add range check
|
|
|
|
// TODO: add debug marker
|
|
|
|
const char *ptr = (const char *)current;
|
|
|
|
while(*current) // skip the string
|
|
|
|
current++;
|
|
|
|
current++;
|
|
|
|
return ptr;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-13 13:40:04 +00:00
|
|
|
const unsigned char *get_raw(int size)
|
2007-05-22 15:03:32 +00:00
|
|
|
{
|
2007-07-13 13:40:04 +00:00
|
|
|
// TODO: add range check
|
|
|
|
// TODO: add debug marker
|
|
|
|
//int s = get_int();
|
|
|
|
//if(size)
|
|
|
|
//*size = s;
|
|
|
|
const unsigned char *ptr = current;
|
|
|
|
current += size;
|
|
|
|
return ptr;
|
2007-05-22 15:03:32 +00:00
|
|
|
}
|
|
|
|
};
|