diff --git a/datasrc/client.dts b/datasrc/client.dts index edded5361..937866468 100644 --- a/datasrc/client.dts +++ b/datasrc/client.dts @@ -81,4 +81,3 @@ const array:int image = images.* const array:int sprite = sprites.*.* const array:int anim = animations.* const array:int powerup = powerups.* -const array:int gametype = playerstats.* diff --git a/datasrc/server.dts b/datasrc/server.dts index f141ede00..aa3e12fde 100644 --- a/datasrc/server.dts +++ b/datasrc/server.dts @@ -1,7 +1,6 @@ const array:int sound = sounds.* const array:int weapon = weapons.* const array:int powerup = powerups.* -const array:int gametype = playerstats.* struct weapon { int firedelay = firedelay@1 diff --git a/default.bam b/default.bam index edba03ab4..799459861 100644 --- a/default.bam +++ b/default.bam @@ -5,6 +5,11 @@ if family == "windows" then dc_compiler = "scripts\\compiler.py" end +netobj_compiler = "python scripts/netobj.py" +if family == "windows" then + netobj_compiler = "scripts\\netobj.py" +end + dat2c_compiler = "python scripts/dat2c.py" if family == "windows" then dat2c_compiler = "scripts\\dat2c.py" @@ -56,6 +61,15 @@ function dc_cdata(output, data, script) return os.execute(dc_compiler .. " " .. data .. " " .. script .. " -c " .. output) end +function netobj_source(output, proto) + print("netobj source " .. PathFilename(output) .. " = " .. PathFilename(proto)) + return os.execute(netobj_compiler .. " source " .. proto .. " " .. output) +end + +function netobj_header(output, proto) + print("netobj header " .. PathFilename(output) .. " = " .. PathFilename(proto)) + return os.execute(netobj_compiler .. " header " .. proto .. " " .. output) +end function CHash(output, ...) local inputs = {} @@ -91,6 +105,17 @@ function Dat2c(datafile, sourcefile, arrayname) return sourcefile end +function NetObjCompile(protofile, sourcefile, headerfile) + protofile = Path(protofile) + sourcefile = Path(sourcefile) + headerfile = Path(headerfile) + bam_add_job("netobj_source", sourcefile, protofile) + bam_add_job("netobj_header", headerfile, protofile) + bam_add_dependency(sourcefile, protofile) + bam_add_dependency(headerfile, protofile) + return {source = sourcefile, header=headerfile} +end + function DataCompile(datafile, scriptfile, headerfile, sourcefile, outputdatafile) datafile = Path(datafile) scriptfile = Path(scriptfile) @@ -137,11 +162,16 @@ networkdata = DataCompile( "datasrc/network.dts", "src/game/generated/g_protocol_ids.h", "src/game/generated/g_protocol_ids.cpp") + +netobj = NetObjCompile( + "src/game/g_protocol.def", + "src/game/generated/g_protocol.cpp", + "src/game/generated/g_protocol.h") nethash = CHash( "src/game/generated/nethash.c", "src/engine/e_protocol.h", - "src/game/g_protocol.h", + "src/game/generated/g_protocol.h", "src/game/g_tuning.h", "src/game/g_game.cpp", networkdata.header) @@ -260,7 +290,7 @@ function build(settings) server = Compile(server_settings, Collect("src/engine/server/*.c")) masterserver = Compile(settings, Collect("src/mastersrv/*.cpp")) - game_shared = Compile(settings, Collect("src/game/*.cpp"), nethash) + game_shared = Compile(settings, Collect("src/game/*.cpp"), nethash, netobj.source) game_client = Compile(settings, Collect("src/game/client/*.cpp"), clientdata.source, clientdata.cdata) game_server = Compile(settings, Collect("src/game/server/*.cpp"), serverdata.source, serverdata.cdata) game_editor = Compile(settings, Collect("src/game/editor/*.cpp")) diff --git a/scripts/compiler.py b/scripts/compiler.py index b883398a8..726785e0f 100755 --- a/scripts/compiler.py +++ b/scripts/compiler.py @@ -487,8 +487,8 @@ class translator: for s in self.structs: s.emit_header_code(out) print >>out, "" - print >>out, "data_container *load_data_from_file(const char *filename);" - print >>out, "data_container *load_data_from_memory(unsigned char *filename);" + print >>out, "struct data_container *load_data_from_file(const char *filename);" + print >>out, "struct data_container *load_data_from_memory(unsigned char *filename);" print >>out, "" diff --git a/scripts/netobj.py b/scripts/netobj.py new file mode 100644 index 000000000..107f49c45 --- /dev/null +++ b/scripts/netobj.py @@ -0,0 +1,270 @@ +import sys, os + +line_count = 0 + +class variable: + name = "unknown" + def __init__(self, args, name): + global line_count + self.name = name + self.line = line_count + def emit_declaration(self): + return ["\tint %s;" % self.name] + def linedef(self): + return "#line %d" % self.line + def emit_secure(self): + return [] + +class var_any(variable): + def __init__(self, args, name): + variable.__init__(self, args, name) + +class var_range(variable): + def __init__(self, args, name): + variable.__init__(self, args, name) + self.min = args[0] + self.max = args[1] + def emit_secure(self): + return [self.linedef(), "obj->%s = netobj_clamp_int(obj->%s, %s, %s);" % (self.name, self.name, self.min, self.max)] + +class var_clientid(variable): + def __init__(self, args, name): + variable.__init__(self, args, name) + def emit_secure(self): + return [self.linedef(), "obj->%s = netobj_clamp_int(obj->%s, -1, MAX_CLIENTS);" % (self.name, self.name)] + +class var_string(variable): + def __init__(self, args, name): + variable.__init__(self, args, name) + +class object: + def __init__(self, line): + fields = line.split() + self.name = fields[1] + self.extends = None + if len(fields) == 4 and fields[2] == "extends": + self.extends = fields[3] + self.enum_name = "NETOBJTYPE_%s" % self.name.upper() + self.struct_name = "NETOBJ_%s" % self.name.upper() + self.members = [] + + def parse(self, lines): + global line_count + for index in xrange(0, len(lines)): + line_count += 1 + line = lines[index] + if not len(line): + continue + + if line == "end": + return lines[index+1:] + else: + # check for argument + fields = line.split(")", 1) + if len(fields) == 2: + names = [line.strip() for line in fields[1].split(",")] + l = fields[0].split("(", 1) + type = l[0] + args = [line.strip() for line in l[1].split(",")] + else: + l = fields[0].split(None, 1) + type = l[0] + args = [] + names = [line.strip() for line in l[1].split(",")] + + for name in names: + create_string = 'var_%s(%s, "%s")' % (type, args, name) + new_member = eval(create_string) + self.members += [new_member] + + raise BaseException("Parse error") + + def emit_declaration(self): + lines = [] + if self.extends: + lines += ["struct %s : public NETOBJ_%s\n {" % (self.struct_name, self.extends.upper())] + else: + lines += ["struct %s\n {" % self.struct_name] + for m in self.members: + lines += m.emit_declaration() + lines += ["};"] + return lines + + def emit_secure(self): + lines = [] + for m in self.members: + lines += m.emit_secure() + return lines + +class event(object): + def __init__(self, line): + object.__init__(self, line) + self.enum_name = "NETEVENTTYPE_%s" % self.name.upper() + self.struct_name = "NETEVENT_%s" % self.name.upper() + +class raw_reader: + def __init__(self): + self.raw_lines = [] + def parse(self, lines): + global line_count + for index in xrange(0, len(lines)): + line_count += 1 + line = lines[index] + if not len(line): + continue + + if line == "end": + return lines[index+1:] + else: + self.raw_lines += [line] + + raise BaseException("Parse error") + +class proto: + def __init__(self): + self.objects = [] + self.source_raw = [] + self.header_raw = [] + + +def load(filename): + # read the file + global line_count + line_count = 0 + lines = [line.strip() for line in file(filename).readlines()] + + p = proto() + + while len(lines): + line_count += 1 + line = lines[0] + line = line.split("//", 2)[0] # strip comment + + if not len(line): + del lines[0] + continue + + fields = line.split(None, 1) + + del lines[0] + + if fields[0] == "object" or fields[0] == "msg": + new_obj = object(line) + lines = new_obj.parse(lines) + p.objects += [new_obj] + elif fields[0] == "event": + new_obj = event(line) + lines = new_obj.parse(lines) + p.objects += [new_obj] + elif fields[0] == "raw_source": + raw = raw_reader() + lines = raw.parse(lines) + p.source_raw += raw.raw_lines + elif fields[0] == "raw_header": + raw = raw_reader() + lines = raw.parse(lines) + p.header_raw += raw.raw_lines + else: + print "error, strange line:", line + + return p + +def emit_header_file(f, p): + for l in p.header_raw: + print >>f, l + + if 1: # emit the enum table + print >>f, "enum {" + print >>f, "\tNETOBJTYPE_INVALID=0," + for obj in p.objects: + print >>f, "\t%s," % obj.enum_name + print >>f, "\tNUM_NETOBJTYPES" + print >>f, "};" + print >>f, "" + + print >>f, "int netobj_secure(int type, void *data, int size);" + print >>f, "const char *netobj_get_name(int type);" + print >>f, "" + + for obj in p.objects: + for l in obj.emit_declaration(): + print >>f, l + print >>f, "" + +def emit_source_file(f, p, protofilename): + + + print >>f, "#line 1 \"%s\"" % os.path.abspath(protofilename) + + for l in p.source_raw: + print >>f, l + + print >>f, "static int netobj_clamp_int(int v, int min, int max)" + print >>f, "{" + print >>f, "if(v>f, "if(v>max) return max;" + print >>f, "return v;" + print >>f, "}" + print >>f, "" + + if 1: # names + print >>f, "static const char *object_names[] = {" + print >>f, "\t" + '"invalid",' + for obj in p.objects: + print >>f, '\t"%s",' % obj.name + print >>f, '\t""' + print >>f, "};" + print >>f, "" + + if 1: # secure functions + print >>f, "static int secure_object_invalid(void *data, int size) { return 0; }" + for obj in p.objects: + print >>f, "static int secure_%s(void *data, int size)" % obj.name + print >>f, "{" + print >>f, "\t%s *obj = (%s *)data;" % (obj.struct_name, obj.struct_name) + print >>f, "\t(void)obj;" # to get rid of "unused variable" warning + print >>f, "\tif(size != sizeof(%s)) return -1;" % obj.struct_name + if obj.extends: + print >>f, "\tif(secure_%s(data, sizeof(NETOBJ_%s)) != 0) return -1;" % (obj.extends, obj.extends.upper()) + + for l in obj.emit_secure(): + print >>f, "\t" + l + print >>f, "\treturn 0;"; + print >>f, "}" + print >>f, "" + + if 1: # secure function table + print >>f, "typedef static int(*SECUREFUNC)(void *data, int size);" + print >>f, "static SECUREFUNC secure_funcs[] = {" + print >>f, "\t" + 'secure_object_invalid,' + for obj in p.objects: + print >>f, "\tsecure_%s," % obj.name + print >>f, "\t" + '0x0' + print >>f, "};" + print >>f, "" + + if 1: + print >>f, "int netobj_secure(int type, void *data, int size)" + print >>f, "{" + print >>f, "\tif(type < 0 || type >= NUM_NETOBJTYPES) return -1;" + print >>f, "\treturn secure_funcs[type](data, size);" + print >>f, "};" + print >>f, "" + + if 1: + print >>f, "const char *netobj_get_name(int type)" + print >>f, "{" + print >>f, "\tif(type < 0 || type >= NUM_NETOBJTYPES) return \"(invalid)\";" + print >>f, "\treturn object_names[type];" + print >>f, "};" + print >>f, "" + +if sys.argv[1] == "header": + p = load(sys.argv[2]) + emit_header_file(file(sys.argv[3], "w"), p) +elif sys.argv[1] == "source": + p = load(sys.argv[2]) + emit_source_file(file(sys.argv[3], "w"), p, sys.argv[2]) +else: + print "invalid command" + sys.exit(-1) diff --git a/src/engine/client/ec_client.c b/src/engine/client/ec_client.c index 7185c4710..0ddcf7d95 100644 --- a/src/engine/client/ec_client.c +++ b/src/engine/client/ec_client.c @@ -211,30 +211,48 @@ enum NUM_SNAPSHOT_TYPES=2 }; +/* the game snapshots are modifiable by the game */ 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) +void *snap_get_item(int snapid, int index, SNAP_ITEM *item) { SNAPSHOT_ITEM *i; dbg_assert(snapid >= 0 && snapid < NUM_SNAPSHOT_TYPES, "invalid snapid"); - i = snapshot_get_item(snapshots[snapid]->snap, index); + i = snapshot_get_item(snapshots[snapid]->alt_snap, index); + item->datasize = snapshot_get_item_datasize(snapshots[snapid]->alt_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) +void snap_invalidate_item(int snapid, int index) +{ + SNAPSHOT_ITEM *i; + dbg_assert(snapid >= 0 && snapid < NUM_SNAPSHOT_TYPES, "invalid snapid"); + i = snapshot_get_item(snapshots[snapid]->alt_snap, index); + if(i) + { + if((char *)i < (char *)snapshots[snapid]->alt_snap || (char *)i > (char *)snapshots[snapid]->alt_snap + snapshots[snapid]->snap_size) + dbg_msg("ASDFASDFASdf", "ASDFASDFASDF"); + if((char *)i >= (char *)snapshots[snapid]->snap && (char *)i < (char *)snapshots[snapid]->snap + snapshots[snapid]->snap_size) + dbg_msg("ASDFASDFASdf", "ASDFASDFASDF"); + i->type_and_id = -1; + } +} + +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); + SNAPSHOT_ITEM *itm = snapshot_get_item(snapshots[snapid]->alt_snap, i); if(snapitem_type(itm) == type && snapitem_id(itm) == id) return (void *)snapitem_data(itm); } @@ -762,6 +780,11 @@ static void client_process_packet(NETPACKET *packet) int total_size = msg_unpack_int(); int size = msg_unpack_int(); const unsigned char *data = msg_unpack_raw(size); + + /* check fior errors */ + if(msg_unpack_error() || size <= 0 || total_size <= 0) + return; + io_write(mapdownload_file, data, size); mapdownload_totalsize = total_size; @@ -834,7 +857,7 @@ static void client_process_packet(NETPACKET *packet) crc = msg_unpack_int(); part_size = msg_unpack_int(); } - + data = (const char *)msg_unpack_raw(part_size); if(msg_unpack_error()) @@ -882,6 +905,7 @@ static void client_process_packet(NETPACKET *packet) complete_size = (num_parts-1) * MAX_SNAPSHOT_PACKSIZE + part_size; + /* reset snapshoting */ snapshot_part = 0; /* find snapshot that we should use as delta */ @@ -891,7 +915,7 @@ static void client_process_packet(NETPACKET *packet) /* find delta */ if(delta_tick >= 0) { - int deltashot_size = snapstorage_get(&snapshot_storage, delta_tick, 0, &deltashot); + int deltashot_size = snapstorage_get(&snapshot_storage, delta_tick, 0, &deltashot, 0); if(deltashot_size < 0) { @@ -912,17 +936,28 @@ static void client_process_packet(NETPACKET *packet) deltasize = sizeof(int)*3; if(complete_size) - { + { + int intsize; int compsize = zerobit_decompress(snapshot_incomming_data, complete_size, tmpbuffer); - int intsize = intpack_decompress(tmpbuffer, compsize, tmpbuffer2); + + if(compsize < 0) /* failure during decompression, bail */ + return; + + intsize = intpack_decompress(tmpbuffer, compsize, tmpbuffer2); + + if(intsize < 0) /* failure during decompression, bail */ + return; + deltadata = tmpbuffer2; deltasize = intsize; } - - /*dbg_msg("UNPACK", "%d unpacked with %d", game_tick, delta_tick); */ + /* unpack delta */ purgetick = delta_tick; snapsize = snapshot_unpack_delta(deltashot, (SNAPSHOT*)tmpbuffer3, deltadata, deltasize); + if(snapsize < 0) + return; + if(msg != NETMSG_SNAPEMPTY && snapshot_crc((SNAPSHOT*)tmpbuffer3) != crc) { if(config.debug) @@ -950,10 +985,9 @@ static void client_process_packet(NETPACKET *packet) 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_add(&snapshot_storage, game_tick, time_get(), snapsize, (SNAPSHOT*)tmpbuffer3, 1); /* apply snapshot, cycle pointers */ recived_snapshots++; diff --git a/src/engine/e_compression.c b/src/engine/e_compression.c index fa7d78668..0a16d0b43 100644 --- a/src/engine/e_compression.c +++ b/src/engine/e_compression.c @@ -125,9 +125,8 @@ long zerobit_decompress(const void *src_, int size, void *dst_) unsigned char *src = (unsigned char *)src_; unsigned char *dst = (unsigned char *)dst_; unsigned char *end = src + size; - - while(src != end) + while(src < end) { unsigned char bit = 0x80; unsigned char mask = *src++; @@ -140,6 +139,9 @@ long zerobit_decompress(const void *src_, int size, void *dst_) else *dst++ = 0; } + + if(src > end) + return -1; } return (long)(dst-(unsigned char *)dst_); diff --git a/src/engine/e_engine.c b/src/engine/e_engine.c index c5cb3616b..6fe61efec 100644 --- a/src/engine/e_engine.c +++ b/src/engine/e_engine.c @@ -1,6 +1,7 @@ /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ #include #include +#include #include #include @@ -25,6 +26,15 @@ const char *engine_savepath(const char *filename, char *buffer, int max) } +int engine_stress(float probability) +{ + if(!config.dbg_stress) + return 0; + if(rand()/(float)RAND_MAX < probability) + return 1; + return 0; +} + void engine_init(const char *appname) { dbg_msg("engine", "running on %s-%s-%s", CONF_FAMILY_STRING, CONF_PLATFORM_STRING, CONF_ARCH_STRING); diff --git a/src/engine/e_engine.h b/src/engine/e_engine.h index 6974db1d5..6818d96d5 100644 --- a/src/engine/e_engine.h +++ b/src/engine/e_engine.h @@ -4,6 +4,7 @@ const char *engine_savepath(const char *filename, char *buffer, int max); void engine_init(const char *appname); void engine_parse_arguments(int argc, char **argv); void engine_writeconfig(); +int engine_stress(float probability); enum diff --git a/src/engine/e_if_other.h b/src/engine/e_if_other.h index 931df64da..b3a61e7f4 100644 --- a/src/engine/e_if_other.h +++ b/src/engine/e_if_other.h @@ -34,6 +34,7 @@ typedef struct { int type; int id; + int datasize; } SNAP_ITEM; /* @@ -234,7 +235,7 @@ int snap_num_items(int snapid); Returns: Returns a pointer to the item if it exists, otherwise NULL. */ -const void *snap_get_item(int snapid, int index, SNAP_ITEM *item); +void *snap_get_item(int snapid, int index, SNAP_ITEM *item); /* Function: snap_find_item @@ -250,7 +251,19 @@ const void *snap_get_item(int snapid, int index, SNAP_ITEM *item); Returns: Returns a pointer to the item if it exists, otherwise NULL. */ -const void *snap_find_item(int snapid, int type, int id); +void *snap_find_item(int snapid, int type, int id); + +/* + Function: snap_invalidate_item + Marks an item as invalid byt setting type and id to 0xffffffff. + + Arguments: + snapid - Snapshot ID to the data to fetch. + * SNAP_PREV for previous snapshot. + * SNAP_CUR for current snapshot. + index - Index of the item. +*/ +void snap_invalidate_item(int snapid, int index); /* Function: snap_input diff --git a/src/engine/e_network.c b/src/engine/e_network.c index acf723ba9..9211726fe 100644 --- a/src/engine/e_network.c +++ b/src/engine/e_network.c @@ -54,7 +54,6 @@ typedef struct unsigned char *data; } NETPACKETDATA; - static void send_packet(NETSOCKET socket, NETADDR4 *addr, NETPACKETDATA *packet) { unsigned char buffer[NETWORK_MAX_PACKET_SIZE]; @@ -356,7 +355,18 @@ static int conn_feed(NETCONNECTION *conn, NETPACKETDATA *p, NETADDR4 *addr) conn->remote_closed = 1; if(p->data_size) - conn_set_error(conn, (char *)p->data); + { + /* make sure to sanitize the error string form the other party*/ + char str[128]; + if(p->data_size < 128) + str_copy(str, (char *)p->data, p->data_size); + else + str_copy(str, (char *)p->data, 128); + str_sanitize_strong(str); + + /* set the error string */ + conn_set_error(conn, str); + } else conn_set_error(conn, "no reason given"); if(config.debug) @@ -739,7 +749,7 @@ int netserver_recv(NETSERVER *s, NETPACKET *packet) else { /* errornous packet, drop it */ - dbg_msg("server", "crazy packet"); + /* dbg_msg("server", "crazy packet"); */ } /* read header */ @@ -751,7 +761,11 @@ int netserver_recv(NETSERVER *s, NETPACKET *packet) int netserver_send(NETSERVER *s, NETPACKET *packet) { - dbg_assert(packet->data_size < NETWORK_MAX_PAYLOAD, "packet payload too big"); + if(packet->data_size >= NETWORK_MAX_PAYLOAD) + { + dbg_msg("netserver", "packet payload too big. %d. dropping packet", packet->data_size); + return -1; + } if(packet->flags&PACKETFLAG_CONNLESS) { @@ -898,7 +912,11 @@ int netclient_recv(NETCLIENT *c, NETPACKET *packet) int netclient_send(NETCLIENT *c, NETPACKET *packet) { - dbg_assert(packet->data_size < NETWORK_MAX_PAYLOAD, "packet payload too big"); + if(packet->data_size >= NETWORK_MAX_PAYLOAD) + { + dbg_msg("netclient", "packet payload too big. %d. dropping packet", packet->data_size); + return -1; + } if(packet->flags&PACKETFLAG_CONNLESS) { diff --git a/src/engine/e_packer.c b/src/engine/e_packer.c index 9e77927d6..fa5d54cf3 100644 --- a/src/engine/e_packer.c +++ b/src/engine/e_packer.c @@ -1,12 +1,39 @@ /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ +#include #include "e_system.h" #include "e_packer.h" #include "e_compression.h" +#include "e_engine.h" /* useful for debugging */ -#define packing_error(p) p->error = 1 -/* #define packing_error(p) p->error = 1; dbg_break() */ +#if 0 + #define packing_error(p) p->error = 1; dbg_break() +#else + #define packing_error(p) p->error = 1 +#endif + +int stress_get_int() +{ + static const int nasty[] = {-1, 0, 1, 66000, -66000, (-1<<31), 0x7fffffff}; + if(rand()&1) + return rand(); + return nasty[rand()%6]; +} + +const char *stress_get_string(int *size) +{ + static char noise[1024]; + int i; + int s; + s = (rand()%1024)-1; + for(i = 0; i < s; i++) + noise[i] = (rand()%254)+1; + noise[s] = 0; + if(size) + *size = s; + return noise; +} void packer_reset(PACKER *p) { @@ -19,6 +46,9 @@ void packer_add_int(PACKER *p, int i) { if(p->error) return; + + /*if(engine_stress(0.05f)) + i = stress_get_int();*/ /* make sure that we have space enough */ if(p->end - p->current < 6) @@ -35,6 +65,15 @@ void packer_add_string(PACKER *p, const char *str, int limit) if(p->error) return; + /* STRESS: do this better */ + /* + if(engine_stress(0.1f)) + { + str = stress_get_string(0); + limit = 0; + }*/ + + /* */ if(limit > 0) { while(*str && limit != 0) @@ -105,8 +144,14 @@ void unpacker_reset(UNPACKER *p, const unsigned char *data, int size) int unpacker_get_int(UNPACKER *p) { int i; - if(p->error || p->current >= p->end) + if(p->error) return 0; + if(p->current >= p->end) + { + packing_error(p); + return 0; + } + p->current = vint_unpack(p->current, &i); if(p->current > p->end) { @@ -118,11 +163,11 @@ int unpacker_get_int(UNPACKER *p) const char *unpacker_get_string(UNPACKER *p) { - const char *ptr; + char *ptr; if(p->error || p->current >= p->end) return ""; - ptr = (const char *)p->current; + ptr = (char *)p->current; while(*p->current) /* skip the string */ { p->current++; @@ -133,17 +178,26 @@ const char *unpacker_get_string(UNPACKER *p) } } p->current++; + + /* sanitize all strings */ + str_sanitize(ptr); return ptr; } const unsigned char *unpacker_get_raw(UNPACKER *p, int size) { const unsigned char *ptr = p->current; - p->current += size; - if(p->current > p->end) + if(p->error) + return 0; + + /* check for nasty sizes */ + if(size < 0 || p->current+size > p->end) { packing_error(p); return 0; } + + /* "unpack" the data */ + p->current += size; return ptr; } diff --git a/src/engine/e_snapshot.c b/src/engine/e_snapshot.c index 6c908518d..9dc64ae8b 100644 --- a/src/engine/e_snapshot.c +++ b/src/engine/e_snapshot.c @@ -1,6 +1,7 @@ /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ #include #include "e_snapshot.h" +#include "e_engine.h" #include "e_compression.h" #include "e_common_interface.h" @@ -317,6 +318,8 @@ int snapshot_unpack_delta(SNAPSHOT *from, SNAPSHOT *to, void *srcdata, int data_ SNAPBUILD builder; SNAPSHOT_DELTA *delta = (SNAPSHOT_DELTA *)srcdata; int *data = (int *)delta->data; + int *end = (int *)(((char *)srcdata + data_size)); + SNAPSHOT_ITEM *fromitem; int i, d, keep, itemsize; int *deleted; @@ -329,6 +332,8 @@ int snapshot_unpack_delta(SNAPSHOT *from, SNAPSHOT *to, void *srcdata, int data_ /* unpack deleted stuff */ deleted = data; data += delta->num_deleted_items; + if(data > end) + return -1; /* copy all non deleted stuff */ for(i = 0; i < from->num_items; i++) @@ -358,11 +363,17 @@ int snapshot_unpack_delta(SNAPSHOT *from, SNAPSHOT *to, void *srcdata, int data_ /* unpack updated stuff */ for(i = 0; i < delta->num_update_items; i++) { + if(data+3 > end) + return -1; + itemsize = *data++; type = *data++; id = *data++; snapshot_current = type; + if(data+itemsize/4 > end) + return -1; + key = (type<<16)|id; /* create the item if needed */ @@ -442,10 +453,16 @@ void snapstorage_purge_until(SNAPSTORAGE *ss, int tick) ss->last = 0; } -void snapstorage_add(SNAPSTORAGE *ss, int tick, int64 tagtime, int data_size, void *data) +void snapstorage_add(SNAPSTORAGE *ss, int tick, int64 tagtime, int data_size, void *data, int create_alt) { /* allocate memory for holder + snapshot_data */ - SNAPSTORAGE_HOLDER *h = (SNAPSTORAGE_HOLDER *)mem_alloc(sizeof(SNAPSTORAGE_HOLDER)+data_size, 1); + SNAPSTORAGE_HOLDER *h; + int total_size = sizeof(SNAPSTORAGE_HOLDER)+data_size; + + if(create_alt) + total_size += data_size; + + h = (SNAPSTORAGE_HOLDER *)mem_alloc(total_size, 1); /* set data */ h->tick = tick; @@ -453,6 +470,15 @@ void snapstorage_add(SNAPSTORAGE *ss, int tick, int64 tagtime, int data_size, vo h->snap_size = data_size; h->snap = (SNAPSHOT*)(h+1); mem_copy(h->snap, data, data_size); + + if(create_alt) /* create alternative if wanted */ + { + h->alt_snap = (SNAPSHOT*)(((char *)h->snap) + data_size); + mem_copy(h->alt_snap, data, data_size); + } + else + h->alt_snap = 0; + /* link */ h->next = 0; @@ -464,7 +490,7 @@ void snapstorage_add(SNAPSTORAGE *ss, int tick, int64 tagtime, int data_size, vo ss->last = h; } -int snapstorage_get(SNAPSTORAGE *ss, int tick, int64 *tagtime, SNAPSHOT **data) +int snapstorage_get(SNAPSTORAGE *ss, int tick, int64 *tagtime, SNAPSHOT **data, SNAPSHOT **alt_data) { SNAPSTORAGE_HOLDER *h = ss->first; @@ -476,6 +502,8 @@ int snapstorage_get(SNAPSTORAGE *ss, int tick, int64 *tagtime, SNAPSHOT **data) *tagtime = h->tagtime; if(data) *data = h->snap; + if(alt_data) + *alt_data = h->alt_snap; return h->snap_size; } @@ -524,6 +552,14 @@ int snapbuild_finish(SNAPBUILD *sb, void *snapdata) void *snapbuild_new_item(SNAPBUILD *sb, int type, int id, int size) { SNAPSHOT_ITEM *obj = (SNAPSHOT_ITEM *)(sb->data+sb->data_size); + + if(engine_stress(0.01f)) + { + size += ((rand()%5) - 2)*4; + if(size < 0) + size = 0; + } + mem_zero(obj, sizeof(SNAPSHOT_ITEM) + size); obj->type_and_id = (type<<16)|id; sb->offsets[sb->num_items] = sb->data_size; diff --git a/src/engine/e_snapshot.h b/src/engine/e_snapshot.h index 1396f6ee2..9527cb24c 100644 --- a/src/engine/e_snapshot.h +++ b/src/engine/e_snapshot.h @@ -52,6 +52,7 @@ typedef struct SNAPSTORAGE_HOLDER_t int snap_size; SNAPSHOT *snap; + SNAPSHOT *alt_snap; } SNAPSTORAGE_HOLDER; typedef struct SNAPSTORAGE_t @@ -63,8 +64,8 @@ typedef struct SNAPSTORAGE_t void snapstorage_init(SNAPSTORAGE *ss); void snapstorage_purge_all(SNAPSTORAGE *ss); void snapstorage_purge_until(SNAPSTORAGE *ss, int tick); -void snapstorage_add(SNAPSTORAGE *ss, int tick, int64 tagtime, int data_size, void *data); -int snapstorage_get(SNAPSTORAGE *ss, int tick, int64 *tagtime, SNAPSHOT **data); +void snapstorage_add(SNAPSTORAGE *ss, int tick, int64 tagtime, int data_size, void *data, int create_alt); +int snapstorage_get(SNAPSTORAGE *ss, int tick, int64 *tagtime, SNAPSHOT **data, SNAPSHOT **alt_data); /* SNAPBUILD */ diff --git a/src/engine/e_system.c b/src/engine/e_system.c index d2fb4eeb5..044b48a26 100644 --- a/src/engine/e_system.c +++ b/src/engine/e_system.c @@ -47,6 +47,10 @@ extern "C" { #endif +IOHANDLE io_stdin() { return (IOHANDLE)stdin; } +IOHANDLE io_stdout() { return (IOHANDLE)stdout; } +IOHANDLE io_stderr() { return (IOHANDLE)stderr; } + IOHANDLE logfile = 0; void dbg_assert_imp(const char *filename, int line, int test, const char *msg) @@ -462,19 +466,21 @@ int net_addr4_cmp(const NETADDR4 *a, const NETADDR4 *b) int net_host_lookup(const char *hostname, unsigned short port, NETADDR4 *addr) { - struct hostent* ip = gethostbyname(hostname); + struct addrinfo hints; + struct addrinfo *result; + int e; + + mem_zero(&hints, sizeof(hints)); + hints.ai_family = AF_INET; - if(ip && ip->h_length > 0) - { - addr->ip[0] = ip->h_addr_list[0][0]; - addr->ip[1] = ip->h_addr_list[0][1]; - addr->ip[2] = ip->h_addr_list[0][2]; - addr->ip[3] = ip->h_addr_list[0][3]; - addr->port = port; - return 0; - } + e = getaddrinfo(hostname, NULL, &hints, &result); + if(e != 0 || !result) + return -1; - return -1; + sockaddr_to_netaddr4(result->ai_addr, addr); + freeaddrinfo(result); + addr->port = port; + return 0; } NETSOCKET net_udp4_create(NETADDR4 bindaddr) @@ -842,6 +848,31 @@ void str_format(char *buffer, int buffer_size, const char *format, ...) buffer[buffer_size-1] = 0; /* assure null termination */ } + + +/* makes sure that the string only contains the characters between 32 and 127 */ +void str_sanitize_strong(char *str) +{ + while(*str) + { + *str &= 0x7f; + if(*str < 32) + *str = 32; + str++; + } +} + +/* makes sure that the string only contains the characters between 32 and 255 + \r\n\t */ +void str_sanitize(char *str) +{ + while(*str) + { + if(*str < 32 && !(*str == '\r') && !(*str == '\n') && !(*str == '\t')) + *str = ' '; + str++; + } +} + #if defined(__cplusplus) } #endif diff --git a/src/engine/e_system.h b/src/engine/e_system.h index 1fd929e82..d524382be 100644 --- a/src/engine/e_system.h +++ b/src/engine/e_system.h @@ -526,6 +526,12 @@ void pstr_format(pstr *str, )*/ void str_append(char *dst, const char *src, int dst_size); void str_copy(char *dst, const char *src, int dst_size); void str_format(char *buffer, int buffer_size, const char *format, ...); +void str_sanitize_strong(char *str); +void str_sanitize(char *str); + +IOHANDLE io_stdin(); +IOHANDLE io_stdout(); +IOHANDLE io_stderr(); #ifdef __cplusplus } diff --git a/src/engine/server/es_server.c b/src/engine/server/es_server.c index d8b8d9781..9fe75e39d 100644 --- a/src/engine/server/es_server.c +++ b/src/engine/server/es_server.c @@ -371,14 +371,14 @@ static void server_do_snap() snapstorage_purge_until(&clients[i].snapshots, current_tick-SERVER_TICK_SPEED); /* save it the snapshot */ - snapstorage_add(&clients[i].snapshots, current_tick, time_get(), snapshot_size, data); + snapstorage_add(&clients[i].snapshots, current_tick, time_get(), snapshot_size, data, 0); /* find snapshot that we can preform delta against */ emptysnap.data_size = 0; emptysnap.num_items = 0; { - deltashot_size = snapstorage_get(&clients[i].snapshots, clients[i].last_acked_snapshot, 0, &deltashot); + deltashot_size = snapstorage_get(&clients[i].snapshots, clients[i].last_acked_snapshot, 0, &deltashot, 0); if(deltashot_size >= 0) delta_tick = clients[i].last_acked_snapshot; else @@ -625,15 +625,19 @@ static void server_process_client_packet(NETPACKET *packet) int64 tagtime; clients[cid].last_acked_snapshot = msg_unpack_int(); - if(clients[cid].last_acked_snapshot > 0) - clients[cid].snap_rate = SRVCLIENT_SNAPRATE_FULL; - - if(snapstorage_get(&clients[cid].snapshots, clients[cid].last_acked_snapshot, &tagtime, 0) >= 0) - clients[cid].latency = (int)(((time_get()-tagtime)*1000)/time_freq()); - tick = msg_unpack_int(); size = msg_unpack_int(); + /* 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; + + if(snapstorage_get(&clients[cid].snapshots, clients[cid].last_acked_snapshot, &tagtime, 0, 0) >= 0) + clients[cid].latency = (int)(((time_get()-tagtime)*1000)/time_freq()); + input = &clients[cid].inputs[clients[cid].current_input]; input->timeleft = server_tick_start_time(tick)-time_get(); input->pred_tick = tick; diff --git a/src/game/client/gc_client.cpp b/src/game/client/gc_client.cpp index 20d1df7c9..8446d729c 100644 --- a/src/game/client/gc_client.cpp +++ b/src/game/client/gc_client.cpp @@ -27,7 +27,7 @@ extern "C" { struct data_container *data = 0; int64 debug_firedelay = 0; -player_input input_data = {0}; +NETOBJ_PLAYER_INPUT input_data = {0}; int input_target_lock = 0; int chat_mode = CHATMODE_NONE; @@ -40,11 +40,16 @@ tuning_params tuning; vec2 mouse_pos; vec2 local_character_pos; vec2 local_target_pos; -const obj_player_character *local_character = 0; -const obj_player_character *local_prev_character = 0; -const obj_player_info *local_info = 0; -const obj_flag *flags[2] = {0,0}; -const obj_game *gameobj = 0; + +/* +const NETOBJ_PLAYER_CHARACTER *local_character = 0; +const NETOBJ_PLAYER_CHARACTER *local_prev_character = 0; +const NETOBJ_PLAYER_INFO *local_info = 0; +const NETOBJ_FLAG *flags[2] = {0,0}; +const NETOBJ_GAME *gameobj = 0; +*/ + +snapstate netobjects; int picked_up_weapon = -1; @@ -54,7 +59,7 @@ void client_data::update_render_info() render_info = skin_info; // force team colors - if(gameobj && gameobj->gametype != GAMETYPE_DM) + if(netobjects.gameobj && netobjects.gameobj->gametype != GAMETYPE_DM) { const int team_colors[2] = {65387, 10223467}; if(team >= 0 || team <= 1) @@ -232,7 +237,7 @@ void chat_add_line(int client_id, int team, const char *line) if(client_datas[client_id].team == -1) chat_lines[chat_current_line].name_color = -1; - if(gameobj && gameobj->gametype != GAMETYPE_DM) + if(netobjects.gameobj && netobjects.gameobj->gametype != GAMETYPE_DM) { if(client_datas[client_id].team == 0) chat_lines[chat_current_line].name_color = 0; @@ -261,41 +266,40 @@ void process_events(int snaptype) SNAP_ITEM item; const void *data = snap_get_item(snaptype, index, &item); - if(item.type == EVENT_DAMAGEINDICATION) + if(item.type == NETEVENTTYPE_DAMAGEIND) { - ev_damageind *ev = (ev_damageind *)data; + NETEVENT_DAMAGEIND *ev = (NETEVENT_DAMAGEIND *)data; effect_damage_indicator(vec2(ev->x, ev->y), get_direction(ev->angle)); } - else if(item.type == EVENT_AIR_JUMP) + else if(item.type == NETEVENTTYPE_AIR_JUMP) { - ev_common *ev = (ev_common *)data; + NETEVENT_COMMON *ev = (NETEVENT_COMMON *)data; effect_air_jump(vec2(ev->x, ev->y)); } - else if(item.type == EVENT_EXPLOSION) + else if(item.type == NETEVENTTYPE_EXPLOSION) { - ev_explosion *ev = (ev_explosion *)data; + NETEVENT_EXPLOSION *ev = (NETEVENT_EXPLOSION *)data; effect_explosion(vec2(ev->x, ev->y)); } - else if(item.type == EVENT_SMOKE) + /*else if(item.type == EVENT_SMOKE) { - ev_explosion *ev = (ev_explosion *)data; + EV_EXPLOSION *ev = (EV_EXPLOSION *)data; vec2 p(ev->x, ev->y); - } - else if(item.type == EVENT_PLAYERSPAWN) + }*/ + else if(item.type == NETEVENTTYPE_SPAWN) { - ev_explosion *ev = (ev_explosion *)data; + NETEVENT_SPAWN *ev = (NETEVENT_SPAWN *)data; effect_playerspawn(vec2(ev->x, ev->y)); } - else if(item.type == EVENT_DEATH) + else if(item.type == NETEVENTTYPE_DEATH) { - ev_explosion *ev = (ev_explosion *)data; + NETEVENT_DEATH *ev = (NETEVENT_DEATH *)data; effect_playerdeath(vec2(ev->x, ev->y)); } - else if(item.type == EVENT_SOUND_WORLD) + else if(item.type == NETEVENTTYPE_SOUND_WORLD) { - ev_sound *ev = (ev_sound *)data; - if(ev->sound >= 0 && ev->sound < NUM_SOUNDS) - snd_play_random(CHN_WORLD, ev->sound, 1.0f, vec2(ev->x, ev->y)); + NETEVENT_SOUND_WORLD *ev = (NETEVENT_SOUND_WORLD *)data; + snd_play_random(CHN_WORLD, ev->soundid, 1.0f, vec2(ev->x, ev->y)); } } } @@ -303,12 +307,7 @@ void process_events(int snaptype) void clear_object_pointers() { // clear out the invalid pointers - local_character = 0; - local_prev_character = 0; - local_info = 0; - flags[0] = 0; - flags[1] = 0; - gameobj = 0; + mem_zero(&netobjects, sizeof(netobjects)); } void send_info(bool start) @@ -526,16 +525,16 @@ void render_goals(float x, float y, float w) // render goals //y = ystart+h-54; - if(gameobj && gameobj->time_limit) + if(netobjects.gameobj && netobjects.gameobj->time_limit) { char buf[64]; - str_format(buf, sizeof(buf), "Time Limit: %d min", gameobj->time_limit); + str_format(buf, sizeof(buf), "Time Limit: %d min", netobjects.gameobj->time_limit); gfx_text(0, x+w/2, y, 24.0f, buf, -1); } - if(gameobj && gameobj->score_limit) + if(netobjects.gameobj && netobjects.gameobj->score_limit) { char buf[64]; - str_format(buf, sizeof(buf), "Score Limit: %d", gameobj->score_limit); + str_format(buf, sizeof(buf), "Score Limit: %d", netobjects.gameobj->score_limit); gfx_text(0, x+40, y, 24.0f, buf, -1); } } @@ -560,14 +559,14 @@ void render_spectators(float x, float y, float w) SNAP_ITEM item; const void *data = snap_get_item(SNAP_CURRENT, i, &item); - if(item.type == OBJTYPE_PLAYER_INFO) + if(item.type == NETOBJTYPE_PLAYER_INFO) { - const obj_player_info *info = (const obj_player_info *)data; + const NETOBJ_PLAYER_INFO *info = (const NETOBJ_PLAYER_INFO *)data; if(info->team == -1) { if(count) strcat(buffer, ", "); - strcat(buffer, client_datas[info->clientid].name); + strcat(buffer, client_datas[info->cid].name); count++; } } @@ -595,7 +594,7 @@ void render_scoreboard(float x, float y, float w, int team, const char *title) // render title if(!title) { - if(gameobj->game_over) + if(netobjects.gameobj->game_over) title = "Game Over"; else title = "Score Board"; @@ -611,10 +610,11 @@ void render_scoreboard(float x, float y, float w, int team, const char *title) { gfx_text(0, x+10, y, 48, title, -1); - if(gameobj) + if(netobjects.gameobj) { char buf[128]; - str_format(buf, sizeof(buf), "%d", gameobj->teamscore[team&1]); + int score = team ? netobjects.gameobj->teamscore_blue : netobjects.gameobj->teamscore_red; + str_format(buf, sizeof(buf), "%d", score); tw = gfx_text_width(0, 48, buf, -1); gfx_text(0, x+w-tw-30, y, 48, buf, -1); } @@ -623,16 +623,16 @@ void render_scoreboard(float x, float y, float w, int team, const char *title) y += 54.0f; // find players - const obj_player_info *players[MAX_CLIENTS] = {0}; + const NETOBJ_PLAYER_INFO *players[MAX_CLIENTS] = {0}; int num_players = 0; for(int i = 0; i < snap_num_items(SNAP_CURRENT); i++) { SNAP_ITEM item; const void *data = snap_get_item(SNAP_CURRENT, i, &item); - if(item.type == OBJTYPE_PLAYER_INFO) + if(item.type == NETOBJTYPE_PLAYER_INFO) { - players[num_players] = (const obj_player_info *)data; + players[num_players] = (const NETOBJ_PLAYER_INFO *)data; num_players++; } } @@ -644,7 +644,7 @@ void render_scoreboard(float x, float y, float w, int team, const char *title) { if(players[i]->score < players[i+1]->score) { - const obj_player_info *tmp = players[i]; + const NETOBJ_PLAYER_INFO *tmp = players[i]; players[i] = players[i+1]; players[i+1] = tmp; } @@ -660,7 +660,7 @@ void render_scoreboard(float x, float y, float w, int team, const char *title) // render player scores for(int i = 0; i < num_players; i++) { - const obj_player_info *info = players[i]; + const NETOBJ_PLAYER_INFO *info = players[i]; // make sure that we render the correct team if(team == -1 || info->team != team) @@ -683,18 +683,19 @@ void render_scoreboard(float x, float y, float w, int team, const char *title) if(config.cl_show_player_ids) { - str_format(buf, sizeof(buf), "%d | %s", info->clientid, client_datas[info->clientid].name); + str_format(buf, sizeof(buf), "%d | %s", info->cid, client_datas[info->cid].name); gfx_text(0, x+128, y, font_size, buf, -1); } else - gfx_text(0, x+128, y, font_size, client_datas[info->clientid].name, -1); + gfx_text(0, x+128, y, font_size, client_datas[info->cid].name, -1); str_format(buf, sizeof(buf), "%4d", info->latency); float tw = gfx_text_width(0, font_size, buf, -1); gfx_text(0, x+w-tw-35, y, font_size, buf, -1); // render avatar - if((flags[0] && flags[0]->carried_by == info->clientid) || (flags[1] && flags[1]->carried_by == info->clientid)) + if((netobjects.flags[0] && netobjects.flags[0]->carried_by == info->cid) || + (netobjects.flags[1] && netobjects.flags[1]->carried_by == info->cid)) { gfx_blend_normal(); gfx_texture_set(data->images[IMAGE_GAME].id); @@ -708,7 +709,7 @@ void render_scoreboard(float x, float y, float w, int team, const char *title) gfx_quads_end(); } - render_tee(&idlestate, &client_datas[info->clientid].render_info, EMOTE_NORMAL, vec2(1,0), vec2(x+90, y+28)); + render_tee(&idlestate, &client_datas[info->cid].render_info, EMOTE_NORMAL, vec2(1,0), vec2(x+90, y+28)); y += 50.0f; @@ -739,21 +740,21 @@ void render_game() if(config.cl_predict) { - if(!local_character || (local_character->health < 0) || (gameobj && gameobj->game_over)) + if(!netobjects.local_character || (netobjects.local_character->health < 0) || (netobjects.gameobj && netobjects.gameobj->game_over)) { // don't use predicted } else local_character_pos = mix(predicted_prev_player.pos, predicted_player.pos, client_predintratick()); } - else if(local_character && local_prev_character) + else if(netobjects.local_character && netobjects.local_prev_character) { local_character_pos = mix( - vec2(local_prev_character->x, local_prev_character->y), - vec2(local_character->x, local_character->y), client_intratick()); + vec2(netobjects.local_prev_character->x, netobjects.local_prev_character->y), + vec2(netobjects.local_character->x, netobjects.local_character->y), client_intratick()); } - if(local_info && local_info->team == -1) + if(netobjects.local_info && netobjects.local_info->team == -1) spectate = true; animstate idlestate; @@ -1089,7 +1090,7 @@ void render_game() gfx_quads_end(); }*/ - if(local_character && !spectate && !(gameobj && gameobj->game_over)) + if(netobjects.local_character && !spectate && !(netobjects.gameobj && netobjects.gameobj->game_over)) { gfx_texture_set(data->images[IMAGE_GAME].id); gfx_quads_begin(); @@ -1097,7 +1098,7 @@ void render_game() // render cursor if (!menu_active && !emoticon_selector_active) { - select_sprite(data->weapons[local_character->weapon%data->num_weapons].sprite_cursor); + select_sprite(data->weapons[netobjects.local_character->weapon%data->num_weapons].sprite_cursor); float cursorsize = 64; draw_sprite(local_target_pos.x, local_target_pos.y, cursorsize); } @@ -1113,10 +1114,10 @@ void render_game() // if weaponstage is active, put a "glow" around the stage ammo select_sprite(SPRITE_TEE_BODY); - for (int i = 0; i < local_character->weaponstage; i++) - gfx_quads_drawTL(x+local_character->ammocount * 12 -i*12, y+22, 11, 11); - select_sprite(data->weapons[local_character->weapon%data->num_weapons].sprite_proj); - for (int i = 0; i < min(local_character->ammocount, 10); i++) + for (int i = 0; i < netobjects.local_character->weaponstage; i++) + gfx_quads_drawTL(x+netobjects.local_character->ammocount * 12 -i*12, y+22, 11, 11); + select_sprite(data->weapons[netobjects.local_character->weapon%data->num_weapons].sprite_proj); + for (int i = 0; i < min(netobjects.local_character->ammocount, 10); i++) gfx_quads_drawTL(x+i*12,y+24,10,10); gfx_quads_end(); @@ -1127,7 +1128,7 @@ void render_game() // render health select_sprite(SPRITE_HEALTH_FULL); - for(; h < local_character->health; h++) + for(; h < netobjects.local_character->health; h++) gfx_quads_drawTL(x+h*12,y,10,10); select_sprite(SPRITE_HEALTH_EMPTY); @@ -1137,7 +1138,7 @@ void render_game() // render armor meter h = 0; select_sprite(SPRITE_ARMOR_FULL); - for(; h < local_character->armor; h++) + for(; h < netobjects.local_character->armor; h++) gfx_quads_drawTL(x+h*12,y+12,10,10); select_sprite(SPRITE_ARMOR_EMPTY); @@ -1172,7 +1173,7 @@ void render_game() // render victim tee x -= 24.0f; - if(gameobj && gameobj->gametype == GAMETYPE_CTF) + if(netobjects.gameobj && netobjects.gameobj->gametype == GAMETYPE_CTF) { if(killmsgs[r].mode_special&1) { @@ -1206,7 +1207,7 @@ void render_game() if(killmsgs[r].victim != killmsgs[r].killer) { - if(gameobj && gameobj->gametype == GAMETYPE_CTF) + if(netobjects.gameobj && netobjects.gameobj->gametype == GAMETYPE_CTF) { if(killmsgs[r].mode_special&2) { @@ -1305,34 +1306,34 @@ void render_game() } // render goals - if(gameobj) + if(netobjects.gameobj) { - int gametype = gameobj->gametype; + int gametype = netobjects.gameobj->gametype; float whole = 300*gfx_screenaspect(); float half = whole/2.0f; gfx_mapscreen(0,0,300*gfx_screenaspect(),300); - if(!gameobj->sudden_death) + if(!netobjects.gameobj->sudden_death) { char buf[32]; int time = 0; - if(gameobj->time_limit) + if(netobjects.gameobj->time_limit) { - time = gameobj->time_limit*60 - ((client_tick()-gameobj->round_start_tick)/client_tickspeed()); + time = netobjects.gameobj->time_limit*60 - ((client_tick()-netobjects.gameobj->round_start_tick)/client_tickspeed()); - if(gameobj->game_over) + if(netobjects.gameobj->game_over) time = 0; } else - time = (client_tick()-gameobj->round_start_tick)/client_tickspeed(); + time = (client_tick()-netobjects.gameobj->round_start_tick)/client_tickspeed(); str_format(buf, sizeof(buf), "%d:%02d", time /60, time %60); float w = gfx_text_width(0, 16, buf, -1); gfx_text(0, half-w/2, 2, 16, buf, -1); } - if(gameobj->sudden_death) + if(netobjects.gameobj->sudden_death) { const char *text = "Sudden Death"; float w = gfx_text_width(0, 16, text, -1); @@ -1340,7 +1341,7 @@ void render_game() } // render small score hud - if(!(gameobj && gameobj->game_over) && (gametype == GAMETYPE_TDM || gametype == GAMETYPE_CTF)) + if(!(netobjects.gameobj && netobjects.gameobj->game_over) && (gametype == GAMETYPE_TDM || gametype == GAMETYPE_CTF)) { for(int t = 0; t < 2; t++) { @@ -1355,15 +1356,15 @@ void render_game() gfx_quads_end(); char buf[32]; - str_format(buf, sizeof(buf), "%d", gameobj->teamscore[t]); + str_format(buf, sizeof(buf), "%d", t?netobjects.gameobj->teamscore_blue:netobjects.gameobj->teamscore_red); float w = gfx_text_width(0, 14, buf, -1); if(gametype == GAMETYPE_CTF) { gfx_text(0, whole-20-w/2+5, 300-40-15+t*20+2, 14, buf, -1); - if(flags[t]) + if(netobjects.flags[t]) { - if(flags[t]->carried_by == -2 || (flags[t]->carried_by == -1 && ((client_tick()/10)&1))) + if(netobjects.flags[t]->carried_by == -2 || (netobjects.flags[t]->carried_by == -1 && ((client_tick()/10)&1))) { gfx_blend_normal(); gfx_texture_set(data->images[IMAGE_GAME].id); @@ -1376,9 +1377,9 @@ void render_game() gfx_quads_drawTL(whole-40+5, 300-40-15+t*20+1, size/2, size); gfx_quads_end(); } - else if(flags[t]->carried_by >= 0) + else if(netobjects.flags[t]->carried_by >= 0) { - int id = flags[t]->carried_by%MAX_CLIENTS; + int id = netobjects.flags[t]->carried_by%MAX_CLIENTS; const char *name = client_datas[id].name; float w = gfx_text_width(0, 10, name, -1); gfx_text(0, whole-40-5-w, 300-40-15+t*20+2, 10, name, -1); @@ -1396,15 +1397,15 @@ void render_game() } // render warmup timer - if(gameobj->warmup) + if(netobjects.gameobj->warmup) { char buf[256]; float w = gfx_text_width(0, 24, "Warmup", -1); gfx_text(0, 150*gfx_screenaspect()+-w/2, 50, 24, "Warmup", -1); - int seconds = gameobj->warmup/SERVER_TICK_SPEED; + int seconds = netobjects.gameobj->warmup/SERVER_TICK_SPEED; if(seconds < 5) - str_format(buf, sizeof(buf), "%d.%d", seconds, (gameobj->warmup*10/SERVER_TICK_SPEED)%10); + str_format(buf, sizeof(buf), "%d.%d", seconds, (netobjects.gameobj->warmup*10/SERVER_TICK_SPEED)%10); else str_format(buf, sizeof(buf), "%d", seconds); w = gfx_text_width(0, 24, buf, -1); @@ -1439,12 +1440,12 @@ void render_game() } } - if(config.debug && local_character && local_prev_character) + if(config.debug && netobjects.local_character && netobjects.local_prev_character) { gfx_mapscreen(0, 0, 300*gfx_screenaspect(), 300); - float speed = distance(vec2(local_prev_character->x, local_prev_character->y), - vec2(local_character->x, local_character->y)); + float speed = distance(vec2(netobjects.local_prev_character->x, netobjects.local_prev_character->y), + vec2(netobjects.local_character->x, netobjects.local_character->y)); char buf[512]; str_format(buf, sizeof(buf), "%.2f", speed/2); @@ -1453,15 +1454,15 @@ void render_game() // render score board if(inp_key_pressed(KEY_TAB) || // user requested - (!spectate && (!local_character || local_character->health < 0)) || // not spectating and is dead - (gameobj && gameobj->game_over) // game over + (!spectate && (!netobjects.local_character || netobjects.local_character->health < 0)) || // not spectating and is dead + (netobjects.gameobj && netobjects.gameobj->game_over) // game over ) { gfx_mapscreen(0, 0, width, height); float w = 650.0f; - if (gameobj && gameobj->gametype == GAMETYPE_DM) + if(netobjects.gameobj && netobjects.gameobj->gametype == GAMETYPE_DM) { render_scoreboard(width/2-w/2, 150.0f, w, 0, 0); //render_scoreboard(gameobj, 0, 0, -1, 0); @@ -1469,12 +1470,12 @@ void render_game() else { - if(gameobj && gameobj->game_over) + if(netobjects.gameobj && netobjects.gameobj->game_over) { const char *text = "DRAW!"; - if(gameobj->teamscore[0] > gameobj->teamscore[1]) + if(netobjects.gameobj->teamscore_red > netobjects.gameobj->teamscore_blue) text = "Red Team Wins!"; - else if(gameobj->teamscore[1] > gameobj->teamscore[0]) + else if(netobjects.gameobj->teamscore_blue > netobjects.gameobj->teamscore_red) text = "Blue Team Wins!"; float w = gfx_text_width(0, 92.0f, text, -1); diff --git a/src/game/client/gc_client.h b/src/game/client/gc_client.h index 857a9088a..93a90a867 100644 --- a/src/game/client/gc_client.h +++ b/src/game/client/gc_client.h @@ -20,11 +20,29 @@ extern vec2 local_character_pos; extern vec2 local_target_pos; // snap pointers -extern const obj_player_character *local_character; -extern const obj_player_character *local_prev_character; -extern const obj_player_info *local_info; -extern const obj_flag *flags[2]; -extern const obj_game *gameobj; +struct snapstate +{ + const NETOBJ_PLAYER_CHARACTER *local_character; + const NETOBJ_PLAYER_CHARACTER *local_prev_character; + const NETOBJ_PLAYER_INFO *local_info; + const NETOBJ_FLAG *flags[2]; + const NETOBJ_GAME *gameobj; + + const NETOBJ_PLAYER_INFO *player_infos[MAX_CLIENTS]; + const NETOBJ_PLAYER_INFO *info_by_score[MAX_CLIENTS]; + int num_players; +}; + +extern snapstate netobjects; + +/* +extern const NETOBJ_PLAYER_CHARACTER *local_character; +extern const NETOBJ_PLAYER_CHARACTER *local_prev_character; +extern const NETOBJ_PLAYER_INFO *local_info; +extern const NETOBJ_FLAG *flags[2]; +extern const NETOBJ_GAME *gameobj; +* */ + extern tuning_params tuning; // predicted players @@ -33,7 +51,7 @@ extern player_core predicted_player; // input extern int picked_up_weapon; -extern player_input input_data; +extern NETOBJ_PLAYER_INPUT input_data; extern int input_target_lock; // debug @@ -45,7 +63,7 @@ enum MAX_EXTRA_PROJECTILES=32, }; -extern obj_projectile extraproj_projectiles[MAX_EXTRA_PROJECTILES]; +extern NETOBJ_PROJECTILE extraproj_projectiles[MAX_EXTRA_PROJECTILES]; extern int extraproj_num; void extraproj_reset(); diff --git a/src/game/client/gc_hooks.cpp b/src/game/client/gc_hooks.cpp index a63910073..9292d08c5 100644 --- a/src/game/client/gc_hooks.cpp +++ b/src/game/client/gc_hooks.cpp @@ -120,17 +120,17 @@ extern "C" void modc_predict() const void *data = snap_get_item(SNAP_CURRENT, i, &item); int client_id = item.id; - if(item.type == OBJTYPE_PLAYER_CHARACTER) + if(item.type == NETOBJTYPE_PLAYER_CHARACTER) { - const obj_player_character *character = (const obj_player_character *)data; + const NETOBJ_PLAYER_CHARACTER *character = (const NETOBJ_PLAYER_CHARACTER *)data; client_datas[client_id].predicted.world = &world; world.players[client_id] = &client_datas[client_id].predicted; client_datas[client_id].predicted.read(character); } - else if(item.type == OBJTYPE_PLAYER_INFO) + else if(item.type == NETOBJTYPE_PLAYER_INFO) { - const obj_player_info *info = (const obj_player_info *)data; + const NETOBJ_PLAYER_INFO *info = (const NETOBJ_PLAYER_INFO *)data; if(info->local) local_cid = client_id; } @@ -155,7 +155,7 @@ extern "C" void modc_predict() // apply player input int *input = client_get_input(tick); if(input) - world.players[c]->input = *((player_input*)input); + world.players[c]->input = *((NETOBJ_PLAYER_INPUT*)input); } world.players[c]->tick(); @@ -230,6 +230,23 @@ extern "C" void modc_newsnapshot() static int snapshot_count = 0; snapshot_count++; + // secure snapshot + { + int num = snap_num_items(SNAP_CURRENT); + for(int index = 0; index < num; index++) + { + SNAP_ITEM item; + void *data = snap_get_item(SNAP_CURRENT, index, &item); + if(netobj_secure(item.type, data, item.datasize) != 0) + { + if(config.debug) + dbg_msg("game", "invalidated %d %d (%s) %d", index, item.type, netobj_get_name(item.type), item.id); + snap_invalidate_item(SNAP_CURRENT, index); + } + } + } + + process_events(SNAP_CURRENT); if(config.dbg_stress) @@ -256,32 +273,32 @@ extern "C" void modc_newsnapshot() SNAP_ITEM item; const void *data = snap_get_item(SNAP_CURRENT, i, &item); - if(item.type == OBJTYPE_PLAYER_INFO) + if(item.type == NETOBJTYPE_PLAYER_INFO) { - const obj_player_info *info = (const obj_player_info *)data; + const NETOBJ_PLAYER_INFO *info = (const NETOBJ_PLAYER_INFO *)data; - client_datas[info->clientid].team = info->team; + client_datas[info->cid].team = info->team; if(info->local) { - local_info = info; - const void *data = snap_find_item(SNAP_CURRENT, OBJTYPE_PLAYER_CHARACTER, item.id); + netobjects.local_info = info; + const void *data = snap_find_item(SNAP_CURRENT, NETOBJTYPE_PLAYER_CHARACTER, item.id); if(data) { - local_character = (const obj_player_character *)data; - local_character_pos = vec2(local_character->x, local_character->y); + netobjects.local_character = (const NETOBJ_PLAYER_CHARACTER *)data; + local_character_pos = vec2(netobjects.local_character->x, netobjects.local_character->y); - const void *p = snap_find_item(SNAP_PREV, OBJTYPE_PLAYER_CHARACTER, item.id); + const void *p = snap_find_item(SNAP_PREV, NETOBJTYPE_PLAYER_CHARACTER, item.id); if(p) - local_prev_character = (obj_player_character *)p; + netobjects.local_prev_character = (NETOBJ_PLAYER_CHARACTER *)p; } } } - else if(item.type == OBJTYPE_GAME) - gameobj = (obj_game *)data; - else if(item.type == OBJTYPE_FLAG) + else if(item.type == NETOBJTYPE_GAME) + netobjects.gameobj = (NETOBJ_GAME *)data; + else if(item.type == NETOBJTYPE_FLAG) { - flags[item.id%2] = (const obj_flag *)data; + netobjects.flags[item.id%2] = (const NETOBJ_FLAG *)data; } } } @@ -394,7 +411,7 @@ extern "C" void modc_statechange(int state, int old) } } -obj_projectile extraproj_projectiles[MAX_EXTRA_PROJECTILES]; +NETOBJ_PROJECTILE extraproj_projectiles[MAX_EXTRA_PROJECTILES]; int extraproj_num; void extraproj_reset() @@ -409,6 +426,11 @@ extern "C" void modc_message(int msg) int cid = msg_unpack_int(); int team = msg_unpack_int(); const char *message = msg_unpack_string(); + + /* check for errors and invalid inputs */ + if(msg_unpack_error() || cid < 0 || cid >= MAX_CLIENTS) + return; + dbg_msg("message", "chat cid=%d team=%d msg='%s'", cid, team, message); chat_add_line(cid, team, message); @@ -423,10 +445,13 @@ extern "C" void modc_message(int msg) for(int k = 0; k < num; k++) { - obj_projectile proj; - for(unsigned i = 0; i < sizeof(obj_projectile)/sizeof(int); i++) + NETOBJ_PROJECTILE proj; + for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++) ((int *)&proj)[i] = msg_unpack_int(); + if(msg_unpack_error()) + return; + if(extraproj_num != MAX_EXTRA_PROJECTILES) { extraproj_projectiles[extraproj_num] = proj; @@ -440,6 +465,10 @@ extern "C" void modc_message(int msg) const char *name = msg_unpack_string(); const char *skinname = msg_unpack_string(); + /* check for errors and invalid inputs */ + if(msg_unpack_error() || cid < 0 || cid >= MAX_CLIENTS) + return; + strncpy(client_datas[cid].name, name, 64); strncpy(client_datas[cid].skin_name, skinname, 64); @@ -466,13 +495,24 @@ extern "C" void modc_message(int msg) } else if(msg == MSG_TUNE_PARAMS) { - int *params = (int *)&tuning; + // unpack the new tuning + tuning_params new_tuning; + int *params = (int *)&new_tuning; for(unsigned i = 0; i < sizeof(tuning_params)/sizeof(int); i++) params[i] = msg_unpack_int(); + + // check for unpacking errors + if(msg_unpack_error()) + return; + + // apply new tuning + tuning = new_tuning; } else if(msg == MSG_WEAPON_PICKUP) { int weapon = msg_unpack_int(); + if(msg_unpack_error()) + return; picked_up_weapon = weapon+1; } else if(msg == MSG_READY_TO_ENTER) @@ -481,23 +521,41 @@ extern "C" void modc_message(int msg) } else if(msg == MSG_KILLMSG) { + // unpack messages + killmsg msg; + msg.killer = msg_unpack_int(); + msg.victim = msg_unpack_int(); + msg.weapon = msg_unpack_int(); + msg.mode_special = msg_unpack_int(); + msg.tick = client_tick(); + + // check for unpacking errors + if(msg_unpack_error() || msg.killer >= MAX_CLIENTS || msg.victim >= MAX_CLIENTS || msg.weapon >= NUM_WEAPONS) + return; + + // add the message killmsg_current = (killmsg_current+1)%killmsg_max; - killmsgs[killmsg_current].killer = msg_unpack_int(); - killmsgs[killmsg_current].victim = msg_unpack_int(); - killmsgs[killmsg_current].weapon = msg_unpack_int(); - killmsgs[killmsg_current].mode_special = msg_unpack_int(); - killmsgs[killmsg_current].tick = client_tick(); + killmsgs[killmsg_current] = msg; } else if (msg == MSG_EMOTICON) { + // unpack int cid = msg_unpack_int(); int emoticon = msg_unpack_int(); + + // check for errors + if(msg_unpack_error() || cid < 0 || cid >= MAX_CLIENTS) + return; + + // apply client_datas[cid].emoticon = emoticon; client_datas[cid].emoticon_start = client_tick(); } else if(msg == MSG_SOUND_GLOBAL) { int soundid = msg_unpack_int(); + if(msg_unpack_error() || soundid < 0) + return; snd_play_random(CHN_GLOBAL, soundid, 1.0f, vec2(0,0)); } } diff --git a/src/game/client/gc_menu.cpp b/src/game/client/gc_menu.cpp index 51333288e..ec2cc2fe8 100644 --- a/src/game/client/gc_menu.cpp +++ b/src/game/client/gc_menu.cpp @@ -27,10 +27,6 @@ extern "C" { extern data_container *data; -// abit uglyness -extern const obj_player_info *local_info; -extern const obj_game *gameobj; - extern bool menu_active; extern bool menu_game_active; @@ -1614,9 +1610,9 @@ static void menu2_render_game(RECT main_view) if(ui_do_button(&disconnect_button, "Disconnect", 0, &button, ui_draw_menu_button, 0)) client_disconnect(); - if(local_info && gameobj) + if(netobjects.local_info && netobjects.gameobj) { - if(local_info->team != -1) + if(netobjects.local_info->team != -1) { ui_vsplit_l(&main_view, 10.0f, &button, &main_view); ui_vsplit_l(&main_view, 120.0f, &button, &main_view); @@ -1628,9 +1624,9 @@ static void menu2_render_game(RECT main_view) } } - if(gameobj->gametype == GAMETYPE_DM) + if(netobjects.gameobj->gametype == GAMETYPE_DM) { - if(local_info->team != 0) + if(netobjects.local_info->team != 0) { ui_vsplit_l(&main_view, 10.0f, &button, &main_view); ui_vsplit_l(&main_view, 120.0f, &button, &main_view); @@ -1644,7 +1640,7 @@ static void menu2_render_game(RECT main_view) } else { - if(local_info->team != 0) + if(netobjects.local_info->team != 0) { ui_vsplit_l(&main_view, 10.0f, &button, &main_view); ui_vsplit_l(&main_view, 120.0f, &button, &main_view); @@ -1656,7 +1652,7 @@ static void menu2_render_game(RECT main_view) } } - if(local_info->team != 1) + if(netobjects.local_info->team != 1) { ui_vsplit_l(&main_view, 10.0f, &button, &main_view); ui_vsplit_l(&main_view, 120.0f, &button, &main_view); diff --git a/src/game/client/gc_render.cpp b/src/game/client/gc_render.cpp index 1d276ec3b..6e001bd19 100644 --- a/src/game/client/gc_render.cpp +++ b/src/game/client/gc_render.cpp @@ -349,25 +349,25 @@ static void render_items() SNAP_ITEM item; const void *data = snap_get_item(SNAP_CURRENT, i, &item); - if(item.type == OBJTYPE_PROJECTILE) + if(item.type == NETOBJTYPE_PROJECTILE) { - render_projectile((const obj_projectile *)data, item.id); + render_projectile((const NETOBJ_PROJECTILE *)data, item.id); } - else if(item.type == OBJTYPE_POWERUP) + else if(item.type == NETOBJTYPE_POWERUP) { const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); if(prev) - render_powerup((const obj_powerup *)prev, (const obj_powerup *)data); + render_powerup((const NETOBJ_POWERUP *)prev, (const NETOBJ_POWERUP *)data); } - else if(item.type == OBJTYPE_LASER) + else if(item.type == NETOBJTYPE_LASER) { - render_laser((const obj_laser *)data); + render_laser((const NETOBJ_LASER *)data); } - else if(item.type == OBJTYPE_FLAG) + else if(item.type == NETOBJTYPE_FLAG) { const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); if (prev) - render_flag((const obj_flag *)prev, (const obj_flag *)data); + render_flag((const NETOBJ_FLAG *)prev, (const NETOBJ_FLAG *)data); } } @@ -393,19 +393,19 @@ static void render_players() SNAP_ITEM item; const void *data = snap_get_item(SNAP_CURRENT, i, &item); - if(item.type == OBJTYPE_PLAYER_CHARACTER) + if(item.type == NETOBJTYPE_PLAYER_CHARACTER) { const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); - const void *prev_info = snap_find_item(SNAP_PREV, OBJTYPE_PLAYER_INFO, item.id); - const void *info = snap_find_item(SNAP_CURRENT, OBJTYPE_PLAYER_INFO, item.id); + const void *prev_info = snap_find_item(SNAP_PREV, NETOBJTYPE_PLAYER_INFO, item.id); + const void *info = snap_find_item(SNAP_CURRENT, NETOBJTYPE_PLAYER_INFO, item.id); if(prev && prev_info && info) { render_player( - (const obj_player_character *)prev, - (const obj_player_character *)data, - (const obj_player_info *)prev_info, - (const obj_player_info *)info + (const NETOBJ_PLAYER_CHARACTER *)prev, + (const NETOBJ_PLAYER_CHARACTER *)data, + (const NETOBJ_PLAYER_INFO *)prev_info, + (const NETOBJ_PLAYER_INFO *)info ); } } diff --git a/src/game/client/gc_render.h b/src/game/client/gc_render.h index b62206f72..a6f57b7be 100644 --- a/src/game/client/gc_render.h +++ b/src/game/client/gc_render.h @@ -54,13 +54,13 @@ void render_particles(); // object render methods (gc_render_obj.cpp) void render_tee(class animstate *anim, tee_render_info *info, int emote, vec2 dir, vec2 pos); -void render_flag(const struct obj_flag *prev, const struct obj_flag *current); -void render_powerup(const struct obj_powerup *prev, const struct obj_powerup *current); -void render_projectile(const struct obj_projectile *current, int itemid); -void render_laser(const struct obj_laser *current); +void render_flag(const struct NETOBJ_FLAG *prev, const struct NETOBJ_FLAG *current); +void render_powerup(const struct NETOBJ_POWERUP *prev, const struct NETOBJ_POWERUP *current); +void render_projectile(const struct NETOBJ_PROJECTILE *current, int itemid); +void render_laser(const struct NETOBJ_LASER *current); void render_player( - const struct obj_player_character *prev_char, const struct obj_player_character *player_char, - const struct obj_player_info *prev_info, const struct obj_player_info *player_info); + const struct NETOBJ_PLAYER_CHARACTER *prev_char, const struct NETOBJ_PLAYER_CHARACTER *player_char, + const struct NETOBJ_PLAYER_INFO *prev_info, const struct NETOBJ_PLAYER_INFO *player_info); // map render methods (gc_render_map.cpp) void render_eval_envelope(ENVPOINT *points, int num_points, int channels, float time, float *result); diff --git a/src/game/client/gc_render_obj.cpp b/src/game/client/gc_render_obj.cpp index cedfc1297..995994ed0 100644 --- a/src/game/client/gc_render_obj.cpp +++ b/src/game/client/gc_render_obj.cpp @@ -11,7 +11,7 @@ #include "gc_client.h" -void render_projectile(const obj_projectile *current, int itemid) +void render_projectile(const NETOBJ_PROJECTILE *current, int itemid) { if(debug_firedelay) { @@ -34,7 +34,7 @@ void render_projectile(const obj_projectile *current, int itemid) vec2 pos = calc_pos(startpos, startvel, gravity, ct); vec2 prevpos = calc_pos(startpos, startvel, gravity, ct-0.001f); - select_sprite(data->weapons[current->type%data->num_weapons].sprite_proj); + select_sprite(data->weapons[clamp(current->type, 0, NUM_WEAPONS-1)].sprite_proj); vec2 vel = pos-prevpos; //vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), client_intratick()); @@ -63,7 +63,7 @@ void render_projectile(const obj_projectile *current, int itemid) gfx_quads_end(); } -void render_powerup(const obj_powerup *prev, const obj_powerup *current) +void render_powerup(const NETOBJ_POWERUP *prev, const NETOBJ_POWERUP *current) { gfx_texture_set(data->images[IMAGE_GAME].id); gfx_quads_begin(); @@ -73,8 +73,8 @@ void render_powerup(const obj_powerup *prev, const obj_powerup *current) if (current->type == POWERUP_WEAPON) { angle = 0; //-pi/6;//-0.25f * pi * 2.0f; - select_sprite(data->weapons[current->subtype%data->num_weapons].sprite_body); - size = data->weapons[current->subtype%data->num_weapons].visual_size; + select_sprite(data->weapons[clamp(current->subtype, 0, NUM_WEAPONS-1)].sprite_body); + size = data->weapons[clamp(current->subtype, 0, NUM_WEAPONS-1)].visual_size; } else { @@ -107,7 +107,7 @@ void render_powerup(const obj_powerup *prev, const obj_powerup *current) gfx_quads_end(); } -void render_flag(const obj_flag *prev, const obj_flag *current) +void render_flag(const NETOBJ_FLAG *prev, const NETOBJ_FLAG *current) { float angle = 0.0f; float size = 42.0f; @@ -125,7 +125,7 @@ void render_flag(const obj_flag *prev, const obj_flag *current) vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), client_intratick()); - if(local_info && current->carried_by == local_info->clientid) + if(netobjects.local_info && current->carried_by == netobjects.local_info->cid) pos = local_character_pos; //gfx_setcolor(current->team ? 0 : 1,0,current->team ? 1 : 0,1); @@ -135,7 +135,7 @@ void render_flag(const obj_flag *prev, const obj_flag *current) } -void render_laser(const struct obj_laser *current) +void render_laser(const struct NETOBJ_LASER *current) { vec2 pos = vec2(current->x, current->y); @@ -245,19 +245,19 @@ static void render_hand(tee_render_info *info, vec2 center_pos, vec2 dir, float } void render_player( - const obj_player_character *prev_char, - const obj_player_character *player_char, - const obj_player_info *prev_info, - const obj_player_info *player_info + const NETOBJ_PLAYER_CHARACTER *prev_char, + const NETOBJ_PLAYER_CHARACTER *player_char, + const NETOBJ_PLAYER_INFO *prev_info, + const NETOBJ_PLAYER_INFO *player_info ) { - obj_player_character prev; - obj_player_character player; + NETOBJ_PLAYER_CHARACTER prev; + NETOBJ_PLAYER_CHARACTER player; prev = *prev_char; player = *player_char; - obj_player_info info = *player_info; - tee_render_info render_info = client_datas[info.clientid].render_info; + NETOBJ_PLAYER_INFO info = *player_info; + tee_render_info render_info = client_datas[info.cid].render_info; float intratick = client_intratick(); float ticktime = client_ticktime(); @@ -267,7 +267,7 @@ void render_player( if(info.local && config.cl_predict) { - if(!local_character || (local_character->health < 0) || (gameobj && gameobj->game_over)) + if(!netobjects.local_character || (netobjects.local_character->health < 0) || (netobjects.gameobj && netobjects.gameobj->game_over)) { } else @@ -329,7 +329,7 @@ void render_player( if(player_char->hooked_player != -1) { - if(local_info && player_char->hooked_player == local_info->clientid) + if(netobjects.local_info && player_char->hooked_player == netobjects.local_info->cid) { hook_pos = mix(vec2(predicted_prev_player.pos.x, predicted_prev_player.pos.y), vec2(predicted_player.pos.x, predicted_player.pos.y), client_predintratick()); @@ -351,7 +351,8 @@ void render_player( // render chain select_sprite(SPRITE_HOOK_CHAIN); - for(float f = 24; f < d; f += 24) + int i = 0; + for(float f = 24; f < d && i < 1024; f += 24, i++) { vec2 p = hook_pos + dir*f; gfx_quads_draw(p.x, p.y,24,16); @@ -360,7 +361,7 @@ void render_player( gfx_quads_setrotation(0); gfx_quads_end(); - render_hand(&client_datas[info.clientid].render_info, position, normalize(hook_pos-pos), -pi/2, vec2(20, 0)); + render_hand(&client_datas[info.cid].render_info, position, normalize(hook_pos-pos), -pi/2, vec2(20, 0)); } // draw gun @@ -478,9 +479,9 @@ void render_player( switch (player.weapon) { - case WEAPON_GUN: render_hand(&client_datas[info.clientid].render_info, p, direction, -3*pi/4, vec2(-15, 4)); break; - case WEAPON_SHOTGUN: render_hand(&client_datas[info.clientid].render_info, p, direction, -pi/2, vec2(-5, 4)); break; - case WEAPON_GRENADE: render_hand(&client_datas[info.clientid].render_info, p, direction, -pi/2, vec2(-4, 7)); break; + case WEAPON_GUN: render_hand(&client_datas[info.cid].render_info, p, direction, -3*pi/4, vec2(-15, 4)); break; + case WEAPON_SHOTGUN: render_hand(&client_datas[info.cid].render_info, p, direction, -pi/2, vec2(-5, 4)); break; + case WEAPON_GRENADE: render_hand(&client_datas[info.cid].render_info, p, direction, -pi/2, vec2(-4, 7)); break; } } @@ -507,13 +508,13 @@ void render_player( gfx_quads_end(); } - if (client_datas[info.clientid].emoticon_start != -1 && client_datas[info.clientid].emoticon_start + 2 * client_tickspeed() > client_tick()) + if (client_datas[info.cid].emoticon_start != -1 && client_datas[info.cid].emoticon_start + 2 * client_tickspeed() > client_tick()) { gfx_texture_set(data->images[IMAGE_EMOTICONS].id); gfx_quads_begin(); - int since_start = client_tick() - client_datas[info.clientid].emoticon_start; - int from_end = client_datas[info.clientid].emoticon_start + 2 * client_tickspeed() - client_tick(); + int since_start = client_tick() - client_datas[info.cid].emoticon_start; + int from_end = client_datas[info.cid].emoticon_start + 2 * client_tickspeed() - client_tick(); float a = 1; @@ -534,7 +535,7 @@ void render_player( gfx_setcolor(1.0f,1.0f,1.0f,a); // client_datas::emoticon is an offset from the first emoticon - select_sprite(SPRITE_OOP + client_datas[info.clientid].emoticon); + select_sprite(SPRITE_OOP + client_datas[info.cid].emoticon); gfx_quads_draw(position.x, position.y - 23 - 32*h, 64, 64*h); gfx_quads_end(); } @@ -547,7 +548,7 @@ void render_player( if(config.cl_nameplates_always == 0) a = clamp(1-powf(distance(local_target_pos, position)/200.0f,16.0f), 0.0f, 1.0f); - const char *name = client_datas[info.clientid].name; + const char *name = client_datas[info.cid].name; float tw = gfx_text_width(0, 28.0f, name, -1); gfx_text_color(1,1,1,a); gfx_text(0, position.x-tw/2.0f, position.y-60, 28.0f, name, -1); diff --git a/src/game/g_game.cpp b/src/game/g_game.cpp index 25114cb7e..c217b5a32 100644 --- a/src/game/g_game.cpp +++ b/src/game/g_game.cpp @@ -400,7 +400,7 @@ void player_core::move() move_box(&pos, &vel, vec2(28.0f, 28.0f), 0); } -void player_core::write(obj_player_core *obj_core) +void player_core::write(NETOBJ_PLAYER_CORE *obj_core) { obj_core->x = (int)pos.x; obj_core->y = (int)pos.y; @@ -427,7 +427,7 @@ void player_core::write(obj_player_core *obj_core) obj_core->angle = (int)(a*256.0f); } -void player_core::read(const obj_player_core *obj_core) +void player_core::read(const NETOBJ_PLAYER_CORE *obj_core) { pos.x = obj_core->x; pos.y = obj_core->y; @@ -445,7 +445,7 @@ void player_core::read(const obj_player_core *obj_core) void player_core::quantize() { - obj_player_core c; + NETOBJ_PLAYER_CORE c; write(&c); read(&c); } diff --git a/src/game/g_game.h b/src/game/g_game.h index a9fddde7a..00870319f 100644 --- a/src/game/g_game.h +++ b/src/game/g_game.h @@ -133,15 +133,15 @@ public: int hooked_player; int jumped; - player_input input; + NETOBJ_PLAYER_INPUT input; int triggered_events; void tick(); void move(); - void read(const obj_player_core *obj_core); - void write(obj_player_core *obj_core); + void read(const NETOBJ_PLAYER_CORE *obj_core); + void write(NETOBJ_PLAYER_CORE *obj_core); void quantize(); }; diff --git a/src/game/g_layers.cpp b/src/game/g_layers.cpp index 1595e266a..6614bc909 100644 --- a/src/game/g_layers.cpp +++ b/src/game/g_layers.cpp @@ -33,12 +33,10 @@ void layers_init() if(tilemap->flags&1) { - dbg_msg("layers", "game"); game_layer = tilemap; p = 2; } } - dbg_msg("layers", "%d %d", i, layer->type); } } } diff --git a/src/game/g_protocol.def b/src/game/g_protocol.def new file mode 100644 index 000000000..8df707c3b --- /dev/null +++ b/src/game/g_protocol.def @@ -0,0 +1,211 @@ + +raw_source + #include "g_protocol.h" + #include "g_protocol_ids.h" + #include + #define max_int 100000 +end + +raw_header + enum + { + // emotes + EMOTE_NORMAL=0, + EMOTE_PAIN, + EMOTE_HAPPY, + EMOTE_SURPRISE, + EMOTE_ANGRY, + EMOTE_BLINK, + NUM_EMOTES, + + // playerstates + PLAYERSTATE_UNKNOWN=0, + PLAYERSTATE_PLAYING, + PLAYERSTATE_IN_MENU, + PLAYERSTATE_CHATTING, + NUM_PLAYERSTATES, + + // game types + GAMETYPE_DM=0, + GAMETYPE_TDM, + GAMETYPE_CTF, + NUM_GAMETYPES, + + // other stuff + INPUT_STATE_MASK=0x1f, + }; + + enum + { + MSG_NULL=0, + MSG_SAY, // client -> server + MSG_CHAT, // server -> client + MSG_SETINFO, // server -> client - contains name, skin and color info + MSG_KILLMSG, // server -> client + MSG_SETTEAM, + MSG_JOIN, + MSG_QUIT, + MSG_EMOTICON, + MSG_STARTINFO, // client -> server + MSG_CHANGEINFO, // client -> server + MSG_READY_TO_ENTER, // server -> client + MSG_WEAPON_PICKUP, + MSG_SOUND_GLOBAL, + MSG_TUNE_PARAMS, + MSG_KILL, + MSG_EXTRA_PROJECTILE, // server -> client + + }; + +end + + + +object player_input + any left + any right + + any target_x + any target_y + + any jump + any fire + any hook + any blink + + any player_state + + any wanted_weapon + any next_weapon + any prev_weapon +end + +object projectile + any x, y + any vx, vy + range(0, NUM_WEAPONS) type + range(0, max_int) start_tick +end + +object laser + any x + any y + any from_x + any from_y + range(0, max_int) eval_tick +end + +object powerup + any x, y + range(0, max_int) type + range(0, max_int) subtype +end + +object flag + any x, y + range(0, 1) team + clientid carried_by +end + +object game + range(0, max_int) round_start_tick + + range(0, 1) game_over + range(0, 1) sudden_death + range(0, 1) paused + + range(0, max_int) score_limit + range(0, max_int) time_limit + range(0, NUM_GAMETYPES-1) gametype + + range(0, max_int) warmup + + any teamscore_red + any teamscore_blue +end + +// core object needed for physics +object player_core + any x, y + any vx, vy + + any angle + range(0, 2) jumped + + clientid hooked_player + range(0, 3) hook_state + range(0, max_int) hook_tick + + any hook_x + any hook_y + any hook_dx + any hook_dy +end + +// info about the player that is only needed when it's on screen +object player_character extends player_core + range(0, NUM_PLAYERSTATES-1) player_state + + range(0, 10) health + range(0, 10) armor + range(0, 10) ammocount + range(0, 10) weaponstage + + range(0, NUM_WEAPONS-1) weapon + range(0, NUM_EMOTES-1) emote + + range(0, max_int) attacktick +end + +// information about the player that is always needed +object player_info + range(0, 1) local + clientid cid + range(-1, 1) team + + any score + + any latency + any latency_flux +end + +event common + any x, y +end + +event explosion + any x, y +end + +event spawn + any x, y +end + +event death + any x, y +end + +event air_jump + any x, y +end + +event sound_global + any x, y + range(0, NUM_SOUNDS-1) soundid +end + +event sound_world + any x, y + range(0, NUM_SOUNDS-1) soundid +end + +event damageind + any x, y + any angle +end + +//msg say +// clientid cid +// range(-1, 1) team +// string message +//end diff --git a/src/game/g_protocol.h b/src/game/g_protocol.h index f4878729d..195f5ae21 100644 --- a/src/game/g_protocol.h +++ b/src/game/g_protocol.h @@ -4,7 +4,10 @@ #ifndef GAME_PROTOCOL_H #define GAME_PROTOCOL_H +#include + // Network stuff +/* enum { OBJTYPE_NULL=0, @@ -209,6 +212,6 @@ struct obj_player_info int score; int latency; int latency_flux; -}; +};*/ #endif diff --git a/src/game/server/gs_common.h b/src/game/server/gs_common.h index 194751b2c..ffeadecfe 100644 --- a/src/game/server/gs_common.h +++ b/src/game/server/gs_common.h @@ -204,7 +204,7 @@ public: projectile(int type, int owner, vec2 pos, vec2 vel, int span, entity* powner, int damage, int flags, float force, int sound_impact, int weapon); - void fill_info(obj_projectile *proj); + void fill_info(NETOBJ_PROJECTILE *proj); virtual void reset(); virtual void tick(); @@ -270,12 +270,12 @@ public: int color_feet; // these are non-heldback inputs - player_input latest_previnput; - player_input latest_input; + NETOBJ_PLAYER_INPUT latest_previnput; + NETOBJ_PLAYER_INPUT latest_input; // input - player_input previnput; - player_input input; + NETOBJ_PLAYER_INPUT previnput; + NETOBJ_PLAYER_INPUT input; int num_inputs; int jumped; @@ -332,7 +332,7 @@ public: int handle_weapons(); int handle_ninja(); - void on_direct_input(player_input *input); + void on_direct_input(NETOBJ_PLAYER_INPUT *input); void fire_weapon(); virtual void tick(); diff --git a/src/game/server/gs_game.cpp b/src/game/server/gs_game.cpp index a1b5fd7b3..228ae828f 100644 --- a/src/game/server/gs_game.cpp +++ b/src/game/server/gs_game.cpp @@ -6,7 +6,7 @@ #include "gs_common.h" gameobject::gameobject() -: entity(OBJTYPE_GAME) +: entity(NETOBJTYPE_GAME) { // select gametype if(strcmp(config.sv_gametype, "ctf") == 0) @@ -260,7 +260,7 @@ void gameobject::tick() void gameobject::snap(int snapping_client) { - obj_game *game = (obj_game *)snap_new_item(OBJTYPE_GAME, 0, sizeof(obj_game)); + NETOBJ_GAME *game = (NETOBJ_GAME *)snap_new_item(NETOBJTYPE_GAME, 0, sizeof(NETOBJ_GAME)); game->paused = world->paused; game->game_over = game_over_tick==-1?0:1; game->sudden_death = sudden_death; @@ -272,8 +272,8 @@ void gameobject::snap(int snapping_client) game->warmup = warmup; - game->teamscore[0] = teamscore[0]; - game->teamscore[1] = teamscore[1]; + game->teamscore_red = teamscore[0]; + game->teamscore_blue = teamscore[1]; } int gameobject::getteam(int notthisid) diff --git a/src/game/server/gs_game_ctf.cpp b/src/game/server/gs_game_ctf.cpp index 37e2baba7..a703e6b69 100644 --- a/src/game/server/gs_game_ctf.cpp +++ b/src/game/server/gs_game_ctf.cpp @@ -99,7 +99,7 @@ void gameobject_ctf::tick() else { player *close_players[MAX_CLIENTS]; - int types[] = {OBJTYPE_PLAYER_CHARACTER}; + int types[] = {NETOBJTYPE_PLAYER_CHARACTER}; int num = world->find_entities(f->pos, 32.0f, (entity**)close_players, MAX_CLIENTS, types, 1); for(int i = 0; i < num; i++) { @@ -161,7 +161,7 @@ void gameobject_ctf::tick() // Flag flag::flag(int _team) -: entity(OBJTYPE_FLAG) +: entity(NETOBJTYPE_FLAG) { team = _team; proximity_radius = phys_size; @@ -183,7 +183,7 @@ void flag::reset() void flag::snap(int snapping_client) { - obj_flag *flag = (obj_flag *)snap_new_item(OBJTYPE_FLAG, team, sizeof(obj_flag)); + NETOBJ_FLAG *flag = (NETOBJ_FLAG *)snap_new_item(NETOBJTYPE_FLAG, team, sizeof(NETOBJ_FLAG)); flag->x = (int)pos.x; flag->y = (int)pos.y; flag->team = team; diff --git a/src/game/server/gs_server.cpp b/src/game/server/gs_server.cpp index 656609a61..514850a01 100644 --- a/src/game/server/gs_server.cpp +++ b/src/game/server/gs_server.cpp @@ -107,7 +107,7 @@ void event_handler::snap(int snapping_client) { if(cmask_is_set(client_masks[i], snapping_client)) { - ev_common *ev = (ev_common *)&data[offsets[i]]; + NETEVENT_COMMON *ev = (NETEVENT_COMMON *)&data[offsets[i]]; if(distance(players[snapping_client].pos, vec2(ev->x, ev->y)) < 1500.0f) { void *d = snap_new_item(types[i], i, sizes[i]); @@ -297,6 +297,7 @@ void game_world::tick() if(!paused) { + /* static PERFORMACE_INFO scopes[OBJTYPE_FLAG+1] = { {"null", 0}, @@ -320,31 +321,32 @@ void game_world::tick() }; static PERFORMACE_INFO tick_scope = {"tick", 0}; - perf_start(&tick_scope); + perf_start(&tick_scope);*/ // update all objects for(entity *ent = first_entity; ent; ent = ent->next_entity) { - if(ent->objtype >= 0 && ent->objtype < OBJTYPE_FLAG) - perf_start(&scopes[ent->objtype]); + /*if(ent->objtype >= 0 && ent->objtype < OBJTYPE_FLAG) + perf_start(&scopes[ent->objtype]);*/ ent->tick(); - if(ent->objtype >= 0 && ent->objtype < OBJTYPE_FLAG) - perf_end(); + /*if(ent->objtype >= 0 && ent->objtype < OBJTYPE_FLAG) + perf_end();*/ } + /* perf_end(); static PERFORMACE_INFO deftick_scope = {"tick_defered", 0}; - perf_start(&deftick_scope); + perf_start(&deftick_scope);*/ for(entity *ent = first_entity; ent; ent = ent->next_entity) { - if(ent->objtype >= 0 && ent->objtype < OBJTYPE_FLAG) - perf_start(&scopes_def[ent->objtype]); + /*if(ent->objtype >= 0 && ent->objtype < OBJTYPE_FLAG) + perf_start(&scopes_def[ent->objtype]);*/ ent->tick_defered(); - if(ent->objtype >= 0 && ent->objtype < OBJTYPE_FLAG) - perf_end(); + /*if(ent->objtype >= 0 && ent->objtype < OBJTYPE_FLAG) + perf_end();*/ } - perf_end(); + /*perf_end();*/ } remove_entities(); @@ -380,7 +382,7 @@ static input_count count_input(int prev, int cur) ////////////////////////////////////////////////// projectile::projectile(int type, int owner, vec2 pos, vec2 vel, int span, entity* powner, int damage, int flags, float force, int sound_impact, int weapon) -: entity(OBJTYPE_PROJECTILE) +: entity(NETOBJTYPE_PROJECTILE) { this->type = type; this->pos = pos; @@ -437,7 +439,7 @@ void projectile::tick() } } -void projectile::fill_info(obj_projectile *proj) +void projectile::fill_info(NETOBJ_PROJECTILE *proj) { proj->x = (int)pos.x; proj->y = (int)pos.y; @@ -455,7 +457,7 @@ void projectile::snap(int snapping_client) if(distance(players[snapping_client].pos, curpos) > 1000.0f) return; - obj_projectile *proj = (obj_projectile *)snap_new_item(OBJTYPE_PROJECTILE, id, sizeof(obj_projectile)); + NETOBJ_PROJECTILE *proj = (NETOBJ_PROJECTILE *)snap_new_item(NETOBJTYPE_PROJECTILE, id, sizeof(NETOBJ_PROJECTILE)); fill_info(proj); } @@ -464,7 +466,7 @@ void projectile::snap(int snapping_client) // laser ////////////////////////////////////////////////// laser::laser(vec2 pos, vec2 direction, float start_energy, player *owner) -: entity(OBJTYPE_LASER) +: entity(NETOBJTYPE_LASER) { this->pos = pos; this->owner = owner; @@ -554,7 +556,7 @@ void laser::snap(int snapping_client) if(distance(players[snapping_client].pos, pos) > 1000.0f) return; - obj_laser *obj = (obj_laser *)snap_new_item(OBJTYPE_LASER, id, sizeof(obj_laser)); + NETOBJ_LASER *obj = (NETOBJ_LASER *)snap_new_item(NETOBJTYPE_LASER, id, sizeof(NETOBJ_LASER)); obj->x = (int)pos.x; obj->y = (int)pos.y; obj->from_x = (int)from.x; @@ -568,7 +570,7 @@ void laser::snap(int snapping_client) ////////////////////////////////////////////////// // TODO: move to separate file player::player() -: entity(OBJTYPE_PLAYER_CHARACTER) +: entity(NETOBJTYPE_PLAYER_CHARACTER) { init(); } @@ -788,7 +790,7 @@ void player::try_respawn() // check if the position is occupado entity *ents[2] = {0}; - int types[] = {OBJTYPE_PLAYER_CHARACTER}; + int types[] = {NETOBJTYPE_PLAYER_CHARACTER}; int num_ents = world->find_entities(spawnpos, 64, ents, 2, types, 1); for(int i = 0; i < num_ents; i++) { @@ -901,12 +903,12 @@ int player::handle_ninja() core.vel = vec2(0.0f,0.0f); if ((ninja.currentmovetime % 2) == 0) { - create_smoke(pos); + //create_smoke(pos); } // check if we hit anything along the way { - int type = OBJTYPE_PLAYER_CHARACTER; + int type = NETOBJTYPE_PLAYER_CHARACTER; entity *ents[64]; vec2 dir = pos - oldpos; float radius = phys_size * 2.0f; //length(dir * 0.5f); @@ -990,12 +992,12 @@ void player::fire_weapon() 1, 0, 0, -1, WEAPON_GUN); // pack the projectile and send it to the client directly - obj_projectile p; + NETOBJ_PROJECTILE p; proj->fill_info(&p); msg_pack_start(MSG_EXTRA_PROJECTILE, 0); msg_pack_int(1); - for(unsigned i = 0; i < sizeof(obj_projectile)/sizeof(int); i++) + for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++) msg_pack_int(((int *)&p)[i]); msg_pack_end(); server_send_msg(client_id); @@ -1014,12 +1016,12 @@ void player::fire_weapon() 1, projectile::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_GRENADE); // pack the projectile and send it to the client directly - obj_projectile p; + NETOBJ_PROJECTILE p; proj->fill_info(&p); msg_pack_start(MSG_EXTRA_PROJECTILE, 0); msg_pack_int(1); - for(unsigned i = 0; i < sizeof(obj_projectile)/sizeof(int); i++) + for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++) msg_pack_int(((int *)&p)[i]); msg_pack_end(); server_send_msg(client_id); @@ -1050,10 +1052,10 @@ void player::fire_weapon() 1, 0, 0, -1, WEAPON_SHOTGUN); // pack the projectile and send it to the client directly - obj_projectile p; + NETOBJ_PROJECTILE p; proj->fill_info(&p); - for(unsigned i = 0; i < sizeof(obj_projectile)/sizeof(int); i++) + for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++) msg_pack_int(((int *)&p)[i]); } @@ -1245,7 +1247,7 @@ int player::handle_weapons() // only one that needs update (for now) // do selection for the weapon and bash anything in it // check if we hit anything along the way - int type = OBJTYPE_PLAYER_CHARACTER; + int type = NETOBJTYPE_PLAYER_CHARACTER; entity *ents[64]; vec2 lookdir(direction.x > 0.0f ? 1.0f : -1.0f, 0.0f); vec2 dir = lookdir * data->weapons[active_weapon].meleereach; @@ -1278,7 +1280,7 @@ int player::handle_weapons() vec2 fdir = normalize(ents[i]->pos- pos); // set his velocity to fast upward (for now) - create_smoke(ents[i]->pos); + //create_smoke(ents[i]->pos); create_sound(pos, SOUND_HAMMER_HIT); if(numobjectshit < 10) hitobjects[numobjectshit++] = ents[i]; @@ -1318,7 +1320,7 @@ int player::handle_weapons() return 0; } -void player::on_direct_input(player_input *new_input) +void player::on_direct_input(NETOBJ_PLAYER_INPUT *new_input) { mem_copy(&latest_previnput, &latest_input, sizeof(latest_input)); mem_copy(&latest_input, new_input, sizeof(latest_input)); @@ -1444,7 +1446,7 @@ void player::tick_defered() if(events&COREEVENT_AIR_JUMP) { create_sound(pos, SOUND_PLAYER_AIRJUMP, mask); - ev_common *c = (ev_common *)::events.create(EVENT_AIR_JUMP, sizeof(ev_common), mask); + NETEVENT_COMMON *c = (NETEVENT_COMMON *)::events.create(NETEVENTTYPE_AIR_JUMP, sizeof(NETEVENT_COMMON), mask); if(c) { c->x = (int)pos.x; @@ -1580,12 +1582,12 @@ void player::snap(int snaping_client) { if(1) { - obj_player_info *info = (obj_player_info *)snap_new_item(OBJTYPE_PLAYER_INFO, client_id, sizeof(obj_player_info)); + NETOBJ_PLAYER_INFO *info = (NETOBJ_PLAYER_INFO *)snap_new_item(NETOBJTYPE_PLAYER_INFO, client_id, sizeof(NETOBJ_PLAYER_INFO)); info->latency = latency_min; info->latency_flux = latency_max-latency_min; info->local = 0; - info->clientid = client_id; + info->cid = client_id; info->score = score; info->team = team; @@ -1595,7 +1597,7 @@ void player::snap(int snaping_client) if(health > 0 && team >= 0 && distance(players[snaping_client].pos, pos) < 1000.0f) { - obj_player_character *character = (obj_player_character *)snap_new_item(OBJTYPE_PLAYER_CHARACTER, client_id, sizeof(obj_player_character)); + NETOBJ_PLAYER_CHARACTER *character = (NETOBJ_PLAYER_CHARACTER *)snap_new_item(NETOBJTYPE_PLAYER_CHARACTER, client_id, sizeof(NETOBJ_PLAYER_CHARACTER)); core.write(character); @@ -1651,7 +1653,7 @@ player *players; // powerup ////////////////////////////////////////////////// powerup::powerup(int _type, int _subtype) -: entity(OBJTYPE_POWERUP) +: entity(NETOBJTYPE_POWERUP) { type = _type; subtype = _subtype; @@ -1747,7 +1749,7 @@ void powerup::tick() // loop through all players, setting their emotes entity *ents[64]; - const int types[] = {OBJTYPE_PLAYER_CHARACTER}; + const int types[] = {NETOBJTYPE_PLAYER_CHARACTER}; int num = world->find_entities(vec2(0, 0), 1000000, ents, 64, types, 1); for (int i = 0; i < num; i++) { @@ -1782,7 +1784,7 @@ void powerup::snap(int snapping_client) if(spawntick != -1) return; - obj_powerup *up = (obj_powerup *)snap_new_item(OBJTYPE_POWERUP, id, sizeof(obj_powerup)); + NETOBJ_POWERUP *up = (NETOBJ_POWERUP *)snap_new_item(NETOBJTYPE_POWERUP, id, sizeof(NETOBJ_POWERUP)); up->x = (int)pos.x; up->y = (int)pos.y; up->type = type; // TODO: two diffrent types? what gives? @@ -1805,7 +1807,7 @@ void create_damageind(vec2 p, float angle, int amount) for(int i = 0; i < amount; i++) { float f = mix(s, e, float(i+1)/float(amount+2)); - ev_damageind *ev = (ev_damageind *)events.create(EVENT_DAMAGEINDICATION, sizeof(ev_damageind)); + NETEVENT_DAMAGEIND *ev = (NETEVENT_DAMAGEIND *)events.create(NETEVENTTYPE_DAMAGEIND, sizeof(NETEVENT_DAMAGEIND)); if(ev) { ev->x = (int)p.x; @@ -1818,7 +1820,7 @@ void create_damageind(vec2 p, float angle, int amount) void create_explosion(vec2 p, int owner, int weapon, bool bnodamage) { // create the event - ev_explosion *ev = (ev_explosion *)events.create(EVENT_EXPLOSION, sizeof(ev_explosion)); + NETEVENT_EXPLOSION *ev = (NETEVENT_EXPLOSION *)events.create(NETEVENTTYPE_EXPLOSION, sizeof(NETEVENT_EXPLOSION)); if(ev) { ev->x = (int)p.x; @@ -1848,21 +1850,22 @@ void create_explosion(vec2 p, int owner, int weapon, bool bnodamage) } } +/* void create_smoke(vec2 p) { // create the event - ev_explosion *ev = (ev_explosion *)events.create(EVENT_SMOKE, sizeof(ev_explosion)); + EV_EXPLOSION *ev = (EV_EXPLOSION *)events.create(EVENT_SMOKE, sizeof(EV_EXPLOSION)); if(ev) { ev->x = (int)p.x; ev->y = (int)p.y; } -} +}*/ void create_playerspawn(vec2 p) { // create the event - ev_spawn *ev = (ev_spawn *)events.create(EVENT_PLAYERSPAWN, sizeof(ev_spawn)); + NETEVENT_SPAWN *ev = (NETEVENT_SPAWN *)events.create(NETEVENTTYPE_SPAWN, sizeof(NETEVENT_SPAWN)); if(ev) { ev->x = (int)p.x; @@ -1873,7 +1876,7 @@ void create_playerspawn(vec2 p) void create_death(vec2 p) { // create the event - ev_death *ev = (ev_death *)events.create(EVENT_DEATH, sizeof(ev_death)); + NETEVENT_DEATH *ev = (NETEVENT_DEATH *)events.create(NETEVENTTYPE_DEATH, sizeof(NETEVENT_DEATH)); if(ev) { ev->x = (int)p.x; @@ -1887,12 +1890,12 @@ void create_sound(vec2 pos, int sound, int mask) return; // create a sound - ev_sound *ev = (ev_sound *)events.create(EVENT_SOUND_WORLD, sizeof(ev_sound), mask); + NETEVENT_SOUND_WORLD *ev = (NETEVENT_SOUND_WORLD *)events.create(NETEVENTTYPE_SOUND_WORLD, sizeof(NETEVENT_SOUND_WORLD), mask); if(ev) { ev->x = (int)pos.x; ev->y = (int)pos.y; - ev->sound = sound; + ev->soundid = sound; } } @@ -2043,7 +2046,7 @@ void mods_snap(int client_id) void mods_client_direct_input(int client_id, void *input) { if(!world->paused) - players[client_id].on_direct_input((player_input *)input); + players[client_id].on_direct_input((NETOBJ_PLAYER_INPUT *)input); /* if(i->fire) @@ -2058,11 +2061,11 @@ void mods_client_predicted_input(int client_id, void *input) { if(!world->paused) { - if (memcmp(&players[client_id].input, input, sizeof(player_input)) != 0) + if (memcmp(&players[client_id].input, input, sizeof(NETOBJ_PLAYER_INPUT)) != 0) players[client_id].last_action = server_tick(); //players[client_id].previnput = players[client_id].input; - players[client_id].input = *(player_input*)input; + players[client_id].input = *(NETOBJ_PLAYER_INPUT*)input; players[client_id].num_inputs++; if(players[client_id].input.target_x == 0 && players[client_id].input.target_y == 0) diff --git a/src/tools/packetgen.c b/src/tools/packetgen.c new file mode 100644 index 000000000..dcfe0885d --- /dev/null +++ b/src/tools/packetgen.c @@ -0,0 +1,36 @@ +/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ +#include + +enum { NUM_SOCKETS = 64 }; + +int run(NETADDR4 dest) +{ + NETSOCKET sockets[NUM_SOCKETS]; + int i; + + for(i = 0; i < NUM_SOCKETS; i++) + { + NETADDR4 bindaddr = {{0,0,0,0}, 0}; + sockets[i] = net_udp4_create(bindaddr); + } + + while(1) + { + unsigned char data[1024]; + int size = 0; + int socket_to_use = 0; + io_read(io_stdin(), &size, 2); + io_read(io_stdin(), &socket_to_use, 1); + size %= 256; + socket_to_use %= NUM_SOCKETS; + io_read(io_stdin(), data, size); + net_udp4_send(sockets[socket_to_use], &dest, data, size); + } +} + +int main(int argc, char **argv) +{ + NETADDR4 dest = {{127,0,0,1},8303}; + run(dest); + return 0; +}