From 9d632dd826c8a312095de0f56df66b2580d336cb Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Sun, 6 Jul 2008 11:21:21 +0000 Subject: [PATCH] major update. server clean up and much added documentation --- src/engine/client/ec_client.c | 63 +- src/engine/client/ec_srvbrowse.c | 10 +- src/engine/e_engine.c | 9 +- src/engine/e_engine.h | 2 +- src/engine/e_if_client.h | 5 +- src/engine/e_if_gfx.h | 4 + src/engine/e_if_other.h | 14 + src/engine/e_if_server.h | 2 +- src/engine/e_network.c | 48 +- src/engine/e_network.h | 16 +- src/engine/e_snapshot.c | 34 +- src/engine/e_system.c | 80 +- src/engine/e_system.h | 591 +++++++---- src/engine/server/es_register.c | 14 +- src/engine/server/es_server.c | 25 +- src/game/client/gc_client.cpp | 7 +- src/game/client/gc_client.hpp | 12 +- src/game/client/gc_hooks.cpp | 71 +- src/game/client/gc_menu.cpp | 2 +- src/game/client/gc_render.cpp | 8 +- src/game/client/gc_render.hpp | 2 +- src/game/client/gc_render_obj.cpp | 21 +- src/game/g_game.cpp | 20 +- src/game/g_game.hpp | 12 +- src/game/g_protocol.hpp | 217 ---- src/game/server/gs_common.hpp | 417 ++++++-- src/game/server/gs_ent_pickup.cpp | 140 +++ src/game/server/gs_ent_player.cpp | 1128 ++++++++++++++++++++ src/game/server/gs_game.cpp | 83 +- src/game/server/gs_game_ctf.cpp | 77 +- src/game/server/gs_game_ctf.hpp | 6 +- src/game/server/gs_game_tdm.cpp | 6 +- src/game/server/gs_game_tdm.hpp | 2 +- src/game/server/gs_server.cpp | 1645 ++++------------------------- src/mastersrv/mastersrv.cpp | 34 +- src/tools/crapnet.cpp | 18 +- src/tools/fake_server.c | 8 +- src/tools/packetgen.c | 10 +- 38 files changed, 2608 insertions(+), 2255 deletions(-) delete mode 100644 src/game/g_protocol.hpp create mode 100644 src/game/server/gs_ent_pickup.cpp create mode 100644 src/game/server/gs_ent_player.cpp diff --git a/src/engine/client/ec_client.c b/src/engine/client/ec_client.c index 8872d5f4c..b84391944 100644 --- a/src/engine/client/ec_client.c +++ b/src/engine/client/ec_client.c @@ -43,7 +43,7 @@ const int prediction_margin = 7; /* magic network prediction value */ NETCLIENT *net; /* TODO: ugly, fix me */ -extern void client_serverbrowse_set(NETADDR4 *addr, int request, SERVER_INFO *info); +extern void client_serverbrowse_set(NETADDR *addr, int request, SERVER_INFO *info); static int snapshot_part; static int64 local_start_time; @@ -53,7 +53,7 @@ static float frametime = 0.0001f; static float frametime_low = 1.0f; static float frametime_high = 0.0f; static int frames = 0; -static NETADDR4 server_address; +static NETADDR server_address; static int window_must_refocus = 0; static int snaploss = 0; static int snapcrcerrors = 0; @@ -489,11 +489,13 @@ void client_connect(const char *server_address_str) if(port_str) port = atoi(port_str); - - if(net_host_lookup(buf, port, &server_address) != 0) + + /* TODO: IPv6 support */ + if(net_host_lookup(buf, &server_address, NETTYPE_IPV4) != 0) dbg_msg("client", "could not find the address of %s, connecting to localhost", buf); rcon_authed = 0; + server_address.port = port; netclient_connect(net, &server_address); client_set_state(CLIENTSTATE_CONNECTING); @@ -534,6 +536,8 @@ static int client_load_data() extern int snapshot_data_rate[0xffff]; extern int snapshot_data_updates[0xffff]; +const char *modc_getitemname(int type); + static void client_debug_render() { static NETSTATS prev, current; @@ -555,29 +559,50 @@ static void client_debug_render() net_stats(¤t); } + /* + eth = 14 + ip = 20 + udp = 8 + total = 42 + */ + frametime_avg = frametime_avg*0.9f + frametime*0.1f; - str_format(buffer, sizeof(buffer), "ticks: %8d %8d send: %5d/%3d recv: %5d/%3d snaploss: %d mem %dk gfxmem: %dk fps: %3d", + str_format(buffer, sizeof(buffer), "ticks: %8d %8d snaploss: %d mem %dk gfxmem: %dk fps: %3d", current_tick, current_predtick, - (current.sent_bytes-prev.sent_bytes), - (current.sent_packets-prev.sent_packets), - (current.recv_bytes-prev.recv_bytes), - (current.recv_packets-prev.recv_packets), snaploss, mem_allocated()/1024, gfx_memory_usage()/1024, (int)(1.0f/frametime_avg)); gfx_quads_text(2, 2, 16, buffer); + + { + int send_packets = (current.sent_packets-prev.sent_packets); + int send_bytes = (current.sent_bytes-prev.sent_bytes); + int send_total = send_bytes + send_packets*42; + int recv_packets = (current.recv_packets-prev.recv_packets); + int recv_bytes = (current.recv_bytes-prev.recv_bytes); + int recv_total = recv_bytes + recv_packets*42; + + if(!send_packets) send_packets++; + if(!recv_packets) recv_packets++; + str_format(buffer, sizeof(buffer), "send: %3d %5d+%4d=%5d (%3d kbps) avg: %5d\nrecv: %3d %5d+%4d=%5d (%3d kbps) avg: %5d", + send_packets, send_bytes, send_packets*42, send_total, (send_total*8)/1024, send_bytes/send_packets, + recv_packets, recv_bytes, recv_packets*42, recv_total, (recv_total*8)/1024, recv_bytes/recv_packets); + gfx_quads_text(2, 14, 16, buffer); + } /* render rates */ { + int y = 0; int i; for(i = 0; i < 256; i++) { if(snapshot_data_rate[i]) { - str_format(buffer, sizeof(buffer), "%4d : %8d %8d %8d", i, snapshot_data_rate[i]/8, snapshot_data_updates[i], + str_format(buffer, sizeof(buffer), "%4d %20s: %8d %8d %8d", i, modc_getitemname(i), snapshot_data_rate[i]/8, snapshot_data_updates[i], (snapshot_data_rate[i]/snapshot_data_updates[i])/8); - gfx_quads_text(2, 100+i*8, 16, buffer); + gfx_quads_text(2, 100+y*12, 16, buffer); + y++; } } } @@ -684,13 +709,13 @@ static void client_process_packet(NETCHUNK *packet) memcmp(packet->data, SERVERBROWSE_LIST, sizeof(SERVERBROWSE_LIST)) == 0) { int size = packet->data_size-sizeof(SERVERBROWSE_LIST); - int num = size/sizeof(NETADDR4); - NETADDR4 *addrs = (NETADDR4 *)((char*)packet->data+sizeof(SERVERBROWSE_LIST)); + int num = size/sizeof(NETADDR); + NETADDR *addrs = (NETADDR *)((char*)packet->data+sizeof(SERVERBROWSE_LIST)); int i; for(i = 0; i < num; i++) { - NETADDR4 addr = addrs[i]; + NETADDR addr = addrs[i]; SERVER_INFO info = {0}; #if defined(CONF_ARCH_ENDIAN_BIG) @@ -1016,12 +1041,16 @@ static void client_process_packet(NETCHUNK *packet) purgetick = delta_tick; snapsize = snapshot_unpack_delta(deltashot, (SNAPSHOT*)tmpbuffer3, deltadata, deltasize); if(snapsize < 0) + { + dbg_msg("client", "delta unpack failed!"); return; - + } + if(msg != NETMSG_SNAPEMPTY && snapshot_crc((SNAPSHOT*)tmpbuffer3) != crc) { if(config.debug) - dbg_msg("client", "snapshot crc error %d", snapcrcerrors); + dbg_msg("client", "snapshot crc error #%d - tick=%d wantedcrc=%d gotcrc=%d compressed_size=%d", snapcrcerrors, game_tick, crc, snapshot_crc((SNAPSHOT*)tmpbuffer3), complete_size); + snapcrcerrors++; if(snapcrcerrors > 10) { @@ -1248,7 +1277,7 @@ extern void editor_init(); static void client_run() { - NETADDR4 bindaddr; + NETADDR bindaddr; int64 reporttime = time_get(); int64 reportinterval = time_freq()*1; diff --git a/src/engine/client/ec_srvbrowse.c b/src/engine/client/ec_srvbrowse.c index d6f045f15..41c6a7a08 100644 --- a/src/engine/client/ec_srvbrowse.c +++ b/src/engine/client/ec_srvbrowse.c @@ -20,7 +20,7 @@ extern NETCLIENT *net; typedef struct SERVERENTRY_t SERVERENTRY; struct SERVERENTRY_t { - NETADDR4 addr; + NETADDR addr; int64 request_time; int got_info; SERVER_INFO info; @@ -264,7 +264,7 @@ static void client_serverbrowse_remove_request(SERVERENTRY *entry) } } -void client_serverbrowse_set(NETADDR4 *addr, int request, SERVER_INFO *info) +void client_serverbrowse_set(NETADDR *addr, int request, SERVER_INFO *info) { int hash = addr->ip[0]; SERVERENTRY *entry = 0; @@ -272,7 +272,7 @@ void client_serverbrowse_set(NETADDR4 *addr, int request, SERVER_INFO *info) entry = serverlist_ip[hash]; while(entry) { - if(net_addr4_cmp(&entry->addr, addr) == 0) + if(net_addr_comp(&entry->addr, addr) == 0) { /* update the server that we already have */ if(!serverlist_lan) @@ -377,7 +377,7 @@ void client_serverbrowse_refresh(int lan) } else { - NETADDR4 addr; + NETADDR addr; NETCHUNK p; int i; @@ -396,7 +396,7 @@ void client_serverbrowse_refresh(int lan) continue; p.address = addr; - netclient_send(net, &p); + netclient_send(net, &p); } if(config.debug) diff --git a/src/engine/e_engine.c b/src/engine/e_engine.c index 6e1efa95d..f71b7b6e4 100644 --- a/src/engine/e_engine.c +++ b/src/engine/e_engine.c @@ -235,11 +235,11 @@ enum typedef struct { char hostname[128]; - NETADDR4 addr; + NETADDR addr; /* these are used for lookups */ struct { - NETADDR4 addr; + NETADDR addr; int result; void *thread; volatile int state; @@ -264,7 +264,7 @@ void lookup_thread(void *user) for(i = 0; i < info->num; i++) { int index = info->start+i; - master_servers[index].lookup.result = net_host_lookup(master_servers[index].hostname, 8300, &master_servers[index].lookup.addr); + master_servers[index].lookup.result = net_host_lookup(master_servers[index].hostname, &master_servers[index].lookup.addr, NETTYPE_IPV4); master_servers[index].lookup.state = STATE_RESULT; } } @@ -304,6 +304,7 @@ void mastersrv_update() if(master_servers[i].lookup.result == 0) { master_servers[i].addr = master_servers[i].lookup.addr; + master_servers[i].addr.port = 8300; } master_servers[i].lookup.state = STATE_PROCESSED; } @@ -332,7 +333,7 @@ int mastersrv_refreshing() return needs_update; } -NETADDR4 mastersrv_get(int index) +NETADDR mastersrv_get(int index) { return master_servers[index].addr; } diff --git a/src/engine/e_engine.h b/src/engine/e_engine.h index 7b5baec9c..1c2475882 100644 --- a/src/engine/e_engine.h +++ b/src/engine/e_engine.h @@ -24,5 +24,5 @@ int mastersrv_refresh_addresses(); void mastersrv_update(); int mastersrv_refreshing(); void mastersrv_dump_servers(); -NETADDR4 mastersrv_get(int index); +NETADDR mastersrv_get(int index); const char *mastersrv_name(int index); diff --git a/src/engine/e_if_client.h b/src/engine/e_if_client.h index e06d3e6b4..280edf1a6 100644 --- a/src/engine/e_if_client.h +++ b/src/engine/e_if_client.h @@ -2,6 +2,10 @@ #ifndef ENGINE_IF_CLIENT_H #define ENGINE_IF_CLIENT_H +/* + Title: Client Interface +*/ + /* Section: Constants */ @@ -21,7 +25,6 @@ enum CLIENTSTATE_ONLINE, CLIENTSTATE_QUITING, - /* Constants: Image Formats IMG_AUTO - Lets the engine choose the format. IMG_RGB - 8-Bit uncompressed RGB diff --git a/src/engine/e_if_gfx.h b/src/engine/e_if_gfx.h index 57af6072d..b758ed30c 100644 --- a/src/engine/e_if_gfx.h +++ b/src/engine/e_if_gfx.h @@ -2,6 +2,10 @@ #ifndef ENGINE_IF_GFX_H #define ENGINE_IF_GFX_H +/* + Title: Graphics +*/ + /* Section: Structures */ diff --git a/src/engine/e_if_other.h b/src/engine/e_if_other.h index e02a7fd12..3d43533d6 100644 --- a/src/engine/e_if_other.h +++ b/src/engine/e_if_other.h @@ -281,6 +281,20 @@ void snap_invalidate_item(int snapid, int index); */ void snap_input(void *data, int size); +/* + Function: snap_set_staticsize + Tells the engine how big a specific item always will be. This + helps the engine to compress snapshots better. + + Arguments: + type - Item type + size - Size of the data. + + Remarks: + Size must be in a multiple of 4. +*/ +void snap_set_staticsize(int type, int size); + /* message packing */ enum { diff --git a/src/engine/e_if_server.h b/src/engine/e_if_server.h index c9775d904..dd5e14032 100644 --- a/src/engine/e_if_server.h +++ b/src/engine/e_if_server.h @@ -3,7 +3,7 @@ #define ENGINE_IF_SERVER_H /* - Section: Server Hooks + Section: Server Interface */ /* server */ diff --git a/src/engine/e_network.c b/src/engine/e_network.c index 51fcbd759..2eef9006a 100644 --- a/src/engine/e_network.c +++ b/src/engine/e_network.c @@ -170,7 +170,7 @@ typedef struct NETPACKETCONSTRUCT construct; - NETADDR4 peeraddr; + NETADDR peeraddr; NETSOCKET socket; NETSTATS stats; } NETCONNECTION; @@ -182,7 +182,7 @@ typedef struct typedef struct { - NETADDR4 addr; + NETADDR addr; NETCONNECTION *conn; int current_chunk; int client_id; @@ -205,7 +205,7 @@ struct NETSERVER_t struct NETCLIENT_t { - NETADDR4 server_addr; + NETADDR server_addr; NETSOCKET socket; NETRECVINFO recv; @@ -215,7 +215,7 @@ struct NETCLIENT_t static IOHANDLE datalog = 0; static HUFFSTATE huffmanstate; -#define COMPRESSION 0 +#define COMPRESSION 1 typedef struct pcap_hdr_s { unsigned magic_number; /* magic number */ @@ -235,7 +235,7 @@ typedef struct pcaprec_hdr_s { } pcaprec_hdr_t; /* packs the data tight and sends it */ -static void send_packet(NETSOCKET socket, NETADDR4 *addr, NETPACKETCONSTRUCT *packet) +static void send_packet(NETSOCKET socket, NETADDR *addr, NETPACKETCONSTRUCT *packet) { unsigned char buffer[NET_MAX_PACKETSIZE]; buffer[0] = ((packet->flags<<4)&0xf0)|((packet->ack>>8)&0xf); @@ -249,13 +249,13 @@ static void send_packet(NETSOCKET socket, NETADDR4 *addr, NETPACKETCONSTRUCT *pa if(COMPRESSION) { - int compressed_size = (huffman_compress(&huffmanstate, packet->chunk_data, packet->data_size, &buffer[4], NET_MAX_PACKETSIZE-4)+7)/8; - net_udp4_send(socket, addr, buffer, NET_PACKETHEADERSIZE+compressed_size); + int compressed_size = (huffman_compress(&huffmanstate, packet->chunk_data, packet->data_size, &buffer[3], NET_MAX_PACKETSIZE-4)+7)/8; + net_udp_send(socket, addr, buffer, NET_PACKETHEADERSIZE+compressed_size); } else { mem_copy(&buffer[3], packet->chunk_data, packet->data_size); - net_udp4_send(socket, addr, buffer, NET_PACKETHEADERSIZE+packet->data_size); + net_udp_send(socket, addr, buffer, NET_PACKETHEADERSIZE+packet->data_size); } } @@ -473,7 +473,7 @@ static void conn_resend(NETCONNECTION *conn) dbg_msg("conn", "resent %d packets", resend_count); } -static int conn_connect(NETCONNECTION *conn, NETADDR4 *addr) +static int conn_connect(NETCONNECTION *conn, NETADDR *addr) { if(conn->state != NET_CONNSTATE_OFFLINE) return -1; @@ -504,7 +504,7 @@ static void conn_disconnect(NETCONNECTION *conn, const char *reason) conn_reset(conn); } -static int conn_feed(NETCONNECTION *conn, NETPACKETCONSTRUCT *packet, NETADDR4 *addr) +static int conn_feed(NETCONNECTION *conn, NETPACKETCONSTRUCT *packet, NETADDR *addr) { int64 now = time_get(); conn->last_recv_time = now; @@ -685,11 +685,11 @@ static int conn_update(NETCONNECTION *conn) return 0; } -NETSERVER *netserver_open(NETADDR4 bindaddr, int max_clients, int flags) +NETSERVER *netserver_open(NETADDR bindaddr, int max_clients, int flags) { int i; NETSERVER *server; - NETSOCKET socket = net_udp4_create(bindaddr); + NETSOCKET socket = net_udp_create(bindaddr); if(socket == NETSOCKET_INVALID) return 0; @@ -756,7 +756,7 @@ static void recvinfo_clear(NETRECVINFO *info) info->valid = 0; } -static void recvinfo_start(NETRECVINFO *info, NETADDR4 *addr, NETCONNECTION *conn, int cid) +static void recvinfo_start(NETRECVINFO *info, NETADDR *addr, NETCONNECTION *conn, int cid) { info->addr = *addr; info->conn = conn; @@ -823,7 +823,7 @@ int netserver_recv(NETSERVER *s, NETCHUNK *chunk) { while(1) { - NETADDR4 addr; + NETADDR addr; int i, bytes, found; /* check for a chunk */ @@ -831,7 +831,7 @@ int netserver_recv(NETSERVER *s, NETCHUNK *chunk) return 1; /* TODO: empty the recvinfo */ - bytes = net_udp4_recv(s->socket, &addr, s->recv.buffer, NET_MAX_PACKETSIZE); + bytes = net_udp_recv(s->socket, &addr, s->recv.buffer, NET_MAX_PACKETSIZE); /* no more packets for now */ if(bytes <= 0) @@ -849,7 +849,7 @@ int netserver_recv(NETSERVER *s, NETCHUNK *chunk) for(i = 0; i < s->max_clients; i++) { if(s->slots[i].conn.state != NET_CONNSTATE_OFFLINE && - net_addr4_cmp(&s->slots[i].conn.peeraddr, &addr) == 0) + net_addr_comp(&s->slots[i].conn.peeraddr, &addr) == 0) { found = 1; /* silent ignore.. we got this client already */ break; @@ -884,7 +884,7 @@ int netserver_recv(NETSERVER *s, NETCHUNK *chunk) /* normal packet, find matching slot */ for(i = 0; i < s->max_clients; i++) { - if(net_addr4_cmp(&s->slots[i].conn.peeraddr, &addr) == 0) + if(net_addr_comp(&s->slots[i].conn.peeraddr, &addr) == 0) { if(conn_feed(&s->slots[i].conn, &s->recv.data, &addr)) { @@ -952,17 +952,17 @@ NETSOCKET netserver_socket(NETSERVER *s) return s->socket; } -int netserver_client_addr(NETSERVER *s, int client_id, NETADDR4 *addr) +int netserver_client_addr(NETSERVER *s, int client_id, NETADDR *addr) { *addr = s->slots[client_id].conn.peeraddr; return 1; } -NETCLIENT *netclient_open(NETADDR4 bindaddr, int flags) +NETCLIENT *netclient_open(NETADDR bindaddr, int flags) { NETCLIENT *client = (NETCLIENT *)mem_alloc(sizeof(NETCLIENT), 1); mem_zero(client, sizeof(NETCLIENT)); - client->socket = net_udp4_create(bindaddr); + client->socket = net_udp_create(bindaddr); conn_init(&client->conn, client->socket); return client; } @@ -988,7 +988,7 @@ int netclient_disconnect(NETCLIENT *c, const char *reason) return 0; } -int netclient_connect(NETCLIENT *c, NETADDR4 *addr) +int netclient_connect(NETCLIENT *c, NETADDR *addr) { conn_connect(&c->conn, addr); return 0; @@ -998,7 +998,7 @@ int netclient_recv(NETCLIENT *c, NETCHUNK *chunk) { while(1) { - NETADDR4 addr; + NETADDR addr; int bytes; /* check for a chunk */ @@ -1006,7 +1006,7 @@ int netclient_recv(NETCLIENT *c, NETCHUNK *chunk) return 1; /* TODO: empty the recvinfo */ - bytes = net_udp4_recv(c->socket, &addr, c->recv.buffer, NET_MAX_PACKETSIZE); + bytes = net_udp_recv(c->socket, &addr, c->recv.buffer, NET_MAX_PACKETSIZE); /* no more packets for now */ if(bytes <= 0) @@ -1089,7 +1089,7 @@ void netcommon_openlog(const char *filename) static const int freq_table[256+1] = { -31230,4545,2657,431,1950,919,444,482,2244,617,838,542,715,1814,304,240,754,212,647,186, +1<<30,4545,2657,431,1950,919,444,482,2244,617,838,542,715,1814,304,240,754,212,647,186, 283,131,146,166,543,164,167,136,179,859,363,113,157,154,204,108,137,180,202,176, 872,404,168,134,151,111,113,109,120,126,129,100,41,20,16,22,18,18,17,19, 16,37,13,21,362,166,99,78,95,88,81,70,83,284,91,187,77,68,52,68, diff --git a/src/engine/e_network.h b/src/engine/e_network.h index 746230a7c..eaa9df39d 100644 --- a/src/engine/e_network.h +++ b/src/engine/e_network.h @@ -5,7 +5,7 @@ typedef struct /* -1 means that it's a stateless packet */ /* 0 on the client means the server */ int client_id; - NETADDR4 address; /* only used when client_id == -1 */ + NETADDR address; /* only used when client_id == -1 */ int flags; int data_size; const void *data; @@ -45,7 +45,7 @@ void netcommon_openlog(const char *filename); void netcommon_init(); /* server side */ -NETSERVER *netserver_open(NETADDR4 bindaddr, int max_clients, int flags); +NETSERVER *netserver_open(NETADDR bindaddr, int max_clients, int flags); int netserver_set_callbacks(NETSERVER *s, NETFUNC_NEWCLIENT new_client, NETFUNC_DELCLIENT del_client, void *user); int netserver_recv(NETSERVER *s, NETCHUNK *chunk); int netserver_send(NETSERVER *s, NETCHUNK *chunk); @@ -53,14 +53,14 @@ int netserver_close(NETSERVER *s); int netserver_update(NETSERVER *s); NETSOCKET netserver_socket(NETSERVER *s); int netserver_drop(NETSERVER *s, int client_id, const char *reason); -int netserver_client_addr(NETSERVER *s, int client_id, NETADDR4 *addr); +int netserver_client_addr(NETSERVER *s, int client_id, NETADDR *addr); int netserver_max_clients(NETSERVER *s); /*void netserver_stats(NETSERVER *s, NETSTATS *stats);*/ /* client side */ -NETCLIENT *netclient_open(NETADDR4 bindaddr, int flags); +NETCLIENT *netclient_open(NETADDR bindaddr, int flags); int netclient_disconnect(NETCLIENT *c, const char *reason); -int netclient_connect(NETCLIENT *c, NETADDR4 *addr); +int netclient_connect(NETCLIENT *c, NETADDR *addr); int netclient_recv(NETCLIENT *c, NETCHUNK *chunk); int netclient_send(NETCLIENT *c, NETCHUNK *chunk); int netclient_close(NETCLIENT *c); @@ -79,7 +79,7 @@ public: net_server() : ptr(0) {} ~net_server() { close(); } - int open(NETADDR4 bindaddr, int max, int flags) { ptr = netserver_open(bindaddr, max, flags); return ptr != 0; } + int open(NETADDR bindaddr, int max, int flags) { ptr = netserver_open(bindaddr, max, flags); return ptr != 0; } int close() { int r = netserver_close(ptr); ptr = 0; return r; } int set_callbacks(NETFUNC_NEWCLIENT new_client, NETFUNC_DELCLIENT del_client, void *user) @@ -103,10 +103,10 @@ public: net_client() : ptr(0) {} ~net_client() { close(); } - int open(NETADDR4 bindaddr, int flags) { ptr = netclient_open(bindaddr, flags); return ptr != 0; } + int open(NETADDR bindaddr, int flags) { ptr = netclient_open(bindaddr, flags); return ptr != 0; } int close() { int r = netclient_close(ptr); ptr = 0; return r; } - int connect(NETADDR4 *addr) { return netclient_connect(ptr, addr); } + int connect(NETADDR *addr) { return netclient_connect(ptr, addr); } int disconnect(const char *reason) { return netclient_disconnect(ptr, reason); } int recv(NETCHUNK *chunk) { return netclient_recv(ptr, chunk); } diff --git a/src/engine/e_snapshot.c b/src/engine/e_snapshot.c index 9d06f59d8..88949b651 100644 --- a/src/engine/e_snapshot.c +++ b/src/engine/e_snapshot.c @@ -6,6 +6,15 @@ #include "e_common_interface.h" +/* TODO: strange arbitrary number */ +static short item_sizes[64] = {0}; + +void snap_set_staticsize(int itemtype, int size) +{ + dbg_msg("","%d = %d", itemtype, size); + item_sizes[itemtype] = size; +} + int *snapitem_data(SNAPSHOT_ITEM *item) { return (int *)(item+1); } int snapitem_type(SNAPSHOT_ITEM *item) { return item->type_and_id>>16; } int snapitem_id(SNAPSHOT_ITEM *item) { return item->type_and_id&0xffff; } @@ -253,14 +262,21 @@ int snapshot_create_delta(SNAPSHOT *from, SNAPSHOT *to, void *dstdata) if(pastindex != -1) { static PERFORMACE_INFO scope = {"diff", 0}; + int *item_data_dst = data+3; perf_start(&scope); pastitem = snapshot_get_item(from, pastindex); - if(diff_item((int*)snapitem_data(pastitem), (int*)snapitem_data(curitem), data+3, itemsize/4)) + + if(item_sizes[snapitem_type(curitem)]) + item_data_dst = data+2; + + if(diff_item((int*)snapitem_data(pastitem), (int*)snapitem_data(curitem), item_data_dst, itemsize/4)) { - *data++ = itemsize; + *data++ = snapitem_type(curitem); *data++ = snapitem_id(curitem); + if(!item_sizes[snapitem_type(curitem)]) + *data++ = itemsize/4; data += itemsize/4; delta->num_update_items++; } @@ -271,9 +287,10 @@ int snapshot_create_delta(SNAPSHOT *from, SNAPSHOT *to, void *dstdata) static PERFORMACE_INFO scope = {"copy", 0}; perf_start(&scope); - *data++ = itemsize; *data++ = snapitem_type(curitem); *data++ = snapitem_id(curitem); + if(!item_sizes[snapitem_type(curitem)]) + *data++ = itemsize/4; mem_copy(data, snapitem_data(curitem), itemsize); size_count += itemsize; @@ -370,12 +387,19 @@ 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) + if(data+2 > end) return -1; - itemsize = *data++; type = *data++; id = *data++; + if(item_sizes[type]) + itemsize = item_sizes[type]; + else + { + if(data+1 > end) + return -1; + itemsize = (*data++) * 4; + } snapshot_current = type; if(range_check(end, data, itemsize) || itemsize < 0) return -1; diff --git a/src/engine/e_system.c b/src/engine/e_system.c index c0d3595cc..f8fca8640 100644 --- a/src/engine/e_system.c +++ b/src/engine/e_system.c @@ -465,8 +465,9 @@ int64 time_freq() } /* ----- network ----- */ -static void netaddr4_to_sockaddr(const NETADDR4 *src, struct sockaddr *dest) +static void netaddr_to_sockaddr(const NETADDR *src, struct sockaddr *dest) { + /* TODO: IPv6 support */ struct sockaddr_in *p = (struct sockaddr_in *)dest; mem_zero(p, sizeof(struct sockaddr_in)); p->sin_family = AF_INET; @@ -474,9 +475,11 @@ static void netaddr4_to_sockaddr(const NETADDR4 *src, struct sockaddr *dest) p->sin_addr.s_addr = htonl(src->ip[0]<<24|src->ip[1]<<16|src->ip[2]<<8|src->ip[3]); } -static void sockaddr_to_netaddr4(const struct sockaddr *src, NETADDR4 *dst) +static void sockaddr_to_netaddr(const struct sockaddr *src, NETADDR *dst) { + /* TODO: IPv6 support */ unsigned int ip = htonl(((struct sockaddr_in*)src)->sin_addr.s_addr); + dst->type = NETTYPE_IPV4; dst->port = htons(((struct sockaddr_in*)src)->sin_port); dst->ip[0] = (unsigned char)((ip>>24)&0xFF); dst->ip[1] = (unsigned char)((ip>>16)&0xFF); @@ -484,21 +487,15 @@ static void sockaddr_to_netaddr4(const struct sockaddr *src, NETADDR4 *dst) dst->ip[3] = (unsigned char)(ip&0xFF); } -int net_addr4_cmp(const NETADDR4 *a, const NETADDR4 *b) +int net_addr_comp(const NETADDR *a, const NETADDR *b) { - if( a->ip[0] != b->ip[0] || - a->ip[1] != b->ip[1] || - a->ip[2] != b->ip[2] || - a->ip[3] != b->ip[3] || - a->port != b->port - ) - return 1; - return 0; + return mem_comp(a, b, sizeof(NETADDR)); } -int net_host_lookup(const char *hostname, unsigned short port, NETADDR4 *addr) +int net_host_lookup(const char *hostname, NETADDR *addr, int types) { + /* TODO: IPv6 support */ struct addrinfo hints; struct addrinfo *result; int e; @@ -510,14 +507,15 @@ int net_host_lookup(const char *hostname, unsigned short port, NETADDR4 *addr) if(e != 0 || !result) return -1; - sockaddr_to_netaddr4(result->ai_addr, addr); + sockaddr_to_netaddr(result->ai_addr, addr); freeaddrinfo(result); - addr->port = port; + addr->port = 0; return 0; } -NETSOCKET net_udp4_create(NETADDR4 bindaddr) +NETSOCKET net_udp_create(NETADDR bindaddr) { + /* TODO: IPv6 support */ struct sockaddr addr; unsigned int mode = 1; int broadcast = 1; @@ -528,10 +526,10 @@ NETSOCKET net_udp4_create(NETADDR4 bindaddr) return NETSOCKET_INVALID; /* bind, we should check for error */ - netaddr4_to_sockaddr(&bindaddr, &addr); + netaddr_to_sockaddr(&bindaddr, &addr); if(bind(sock, &addr, sizeof(addr)) != 0) { - net_udp4_close(sock); + net_udp_close(sock); return NETSOCKET_INVALID; } @@ -549,12 +547,12 @@ NETSOCKET net_udp4_create(NETADDR4 bindaddr) return sock; } -int net_udp4_send(NETSOCKET sock, const NETADDR4 *addr, const void *data, int size) +int net_udp_send(NETSOCKET sock, const NETADDR *addr, const void *data, int size) { struct sockaddr sa; int d; mem_zero(&sa, sizeof(sa)); - netaddr4_to_sockaddr(addr, &sa); + netaddr_to_sockaddr(addr, &sa); d = sendto((int)sock, (const char*)data, size, 0, &sa, sizeof(sa)); if(d < 0) dbg_msg("net", "sendto error %d %x", d, d); @@ -563,7 +561,7 @@ int net_udp4_send(NETSOCKET sock, const NETADDR4 *addr, const void *data, int si return d; } -int net_udp4_recv(NETSOCKET sock, NETADDR4 *addr, void *data, int maxsize) +int net_udp_recv(NETSOCKET sock, NETADDR *addr, void *data, int maxsize) { struct sockaddr from; int bytes; @@ -571,7 +569,7 @@ int net_udp4_recv(NETSOCKET sock, NETADDR4 *addr, void *data, int maxsize) bytes = recvfrom(sock, (char*)data, maxsize, 0, &from, &fromlen); if(bytes > 0) { - sockaddr_to_netaddr4(&from, addr); + sockaddr_to_netaddr(&from, addr); network_stats.recv_bytes += bytes; network_stats.recv_packets++; return bytes; @@ -581,7 +579,7 @@ int net_udp4_recv(NETSOCKET sock, NETADDR4 *addr, void *data, int maxsize) return -1; /* error */ } -int net_udp4_close(NETSOCKET sock) +int net_udp_close(NETSOCKET sock) { #if defined(CONF_FAMILY_WINDOWS) closesocket(sock); @@ -591,8 +589,9 @@ int net_udp4_close(NETSOCKET sock) return 0; } -NETSOCKET net_tcp4_create(const NETADDR4 *a) +NETSOCKET net_tcp_create(const NETADDR *a) { + /* TODO: IPv6 support */ struct sockaddr addr; /* create socket */ @@ -601,14 +600,14 @@ NETSOCKET net_tcp4_create(const NETADDR4 *a) return NETSOCKET_INVALID; /* bind, we should check for error */ - netaddr4_to_sockaddr(a, &addr); + netaddr_to_sockaddr(a, &addr); bind(sock, &addr, sizeof(addr)); /* return */ return sock; } -int net_tcp4_set_non_blocking(NETSOCKET sock) +int net_tcp_set_non_blocking(NETSOCKET sock) { unsigned int mode = 1; #if defined(CONF_FAMILY_WINDOWS) @@ -618,7 +617,7 @@ int net_tcp4_set_non_blocking(NETSOCKET sock) #endif } -int net_tcp4_set_blocking(NETSOCKET sock) +int net_tcp_set_blocking(NETSOCKET sock) { unsigned int mode = 0; #if defined(CONF_FAMILY_WINDOWS) @@ -628,12 +627,12 @@ int net_tcp4_set_blocking(NETSOCKET sock) #endif } -int net_tcp4_listen(NETSOCKET sock, int backlog) +int net_tcp_listen(NETSOCKET sock, int backlog) { return listen(sock, backlog); } -int net_tcp4_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR4 *a) +int net_tcp_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR *a) { int s; socklen_t sockaddr_len; @@ -645,48 +644,48 @@ int net_tcp4_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR4 *a) if (s != -1) { - sockaddr_to_netaddr4(&addr, a); + sockaddr_to_netaddr(&addr, a); *new_sock = s; } return s; } -int net_tcp4_connect(NETSOCKET sock, const NETADDR4 *a) +int net_tcp_connect(NETSOCKET sock, const NETADDR *a) { struct sockaddr addr; - netaddr4_to_sockaddr(a, &addr); + netaddr_to_sockaddr(a, &addr); return connect(sock, &addr, sizeof(addr)); } -int net_tcp4_connect_non_blocking(NETSOCKET sock, const NETADDR4 *a) +int net_tcp_connect_non_blocking(NETSOCKET sock, const NETADDR *a) { struct sockaddr addr; int res; - netaddr4_to_sockaddr(a, &addr); - net_tcp4_set_non_blocking(sock); + netaddr_to_sockaddr(a, &addr); + net_tcp_set_non_blocking(sock); res = connect(sock, &addr, sizeof(addr)); - net_tcp4_set_blocking(sock); + net_tcp_set_blocking(sock); return res; } -int net_tcp4_send(NETSOCKET sock, const void *data, int size) +int net_tcp_send(NETSOCKET sock, const void *data, int size) { int d; d = send((int)sock, (const char*)data, size, 0); return d; } -int net_tcp4_recv(NETSOCKET sock, void *data, int maxsize) +int net_tcp_recv(NETSOCKET sock, void *data, int maxsize) { int bytes; bytes = recv((int)sock, (char*)data, maxsize, 0); return bytes; } -int net_tcp4_close(NETSOCKET sock) +int net_tcp_close(NETSOCKET sock) { #if defined(CONF_FAMILY_WINDOWS) closesocket(sock); @@ -958,6 +957,11 @@ void str_hex(char *dst, int dst_size, const void *data, int data_size) } } +int mem_comp(const void *a, const void *b, int size) +{ + return memcmp(a,b,size); +} + void net_stats(NETSTATS *stats_inout) { *stats_inout = network_stats; diff --git a/src/engine/e_system.h b/src/engine/e_system.h index 38c2b0765..0b1cbaab3 100644 --- a/src/engine/e_system.h +++ b/src/engine/e_system.h @@ -1,4 +1,9 @@ /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ + +/* + Title: OS Abstraction +*/ + #ifndef BASE_SYSTEM_H #define BASE_SYSTEM_H @@ -9,10 +14,9 @@ extern "C" { #endif /* Group: Debug */ -/********** +/* Function: dbg_assert - - Breaks into the debugger based on a test. + Breaks into the debugger based on a test. Parameters: test - Result of the test. @@ -23,25 +27,24 @@ extern "C" { See Also: -**********/ +*/ void dbg_assert(int test, const char *msg); #define dbg_assert(test,msg) dbg_assert_imp(__FILE__, __LINE__, test, msg) void dbg_assert_imp(const char *filename, int line, int test, const char *msg); -/********** +/* Function: dbg_break - - Breaks into the debugger. + Breaks into the debugger. Remarks: Does nothing in release version of the library. See Also: -**********/ +*/ void dbg_break(); -/********** +/* Function: dbg_msg Prints a debug message. @@ -55,15 +58,14 @@ void dbg_break(); See Also: -**********/ +*/ void dbg_msg(const char *sys, const char *fmt, ...); /* Group: Memory */ -/********** +/* Function: mem_alloc - - Allocates memory. + Allocates memory. Parameters: size - Size of the needed block. @@ -79,14 +81,13 @@ void dbg_msg(const char *sys, const char *fmt, ...); See Also: -**********/ +*/ void *mem_alloc_debug(const char *filename, int line, unsigned size, unsigned alignment); #define mem_alloc(s,a) mem_alloc_debug(__FILE__, __LINE__, (s), (a)) -/********** +/* Function: mem_free - - Frees a block allocated through . + Frees a block allocated through . Remarks: - In the debug version of the library the function will assert if @@ -95,10 +96,10 @@ void *mem_alloc_debug(const char *filename, int line, unsigned size, unsigned al See Also: -**********/ +*/ void mem_free(void *block); -/********** +/* Function: mem_copy Copies a a memory block. @@ -113,37 +114,54 @@ void mem_free(void *block); See Also: -**********/ +*/ void mem_copy(void *dest, const void *source, unsigned size); -/********** +/* Function: mem_move - Copies a a memory block. + Copies a a memory block Parameters: - dest - Destination. - source - Source to copy. - size - Size of the block to copy. + dest - Destination + source - Source to copy + size - Size of the block to copy Remarks: - - This functions handles cases where source and destination is overlapping. + - This functions handles cases where source and destination + is overlapping See Also: -**********/ +*/ void mem_move(void *dest, const void *source, unsigned size); -/********** +/* Function: mem_zero - Sets a complete memory block to 0. + Sets a complete memory block to 0 Parameters: - block - Pointer to the block to zero out. - size - Size of the block. -**********/ + block - Pointer to the block to zero out + size - Size of the block +*/ void mem_zero(void *block, unsigned size); -/* ------- io ------- */ +/* + Function: mem_comp + Compares two blocks of memory + + Parameters: + a - First block of data + b - Second block of data + size - Size of the data to compare + + Returns: + <0 - Block a is lesser then block b + 0 - Block a is equal to block b + >0 - Block a is greater then block b +*/ +int mem_comp(const void *a, const void *b, int size); + +/* Group: File IO */ enum { IOFLAG_READ = 1, IOFLAG_WRITE = 2, @@ -156,9 +174,7 @@ enum { typedef struct IOINTERNAL *IOHANDLE; -/**** Group: File IO ****/ - -/**** +/* Function: io_open Opens a file. @@ -169,10 +185,10 @@ typedef struct IOINTERNAL *IOHANDLE; Returns: Returns a handle to the file on success and 0 on failure. -****/ +*/ IOHANDLE io_open(const char *filename, int flags); -/**** +/* Function: io_read Reads data into a buffer from a file. @@ -184,10 +200,10 @@ IOHANDLE io_open(const char *filename, int flags); Returns: Number of bytes read. -****/ +*/ unsigned io_read(IOHANDLE io, void *buffer, unsigned size); -/***** +/* Function: io_skip Skips data in a file. @@ -197,13 +213,12 @@ unsigned io_read(IOHANDLE io, void *buffer, unsigned size); Returns: Number of bytes skipped. -****/ +*/ unsigned io_skip(IOHANDLE io, unsigned size); -/***** +/* Function: io_write - - Writes data from a buffer to file. + Writes data from a buffer to file. Parameters: io - Handle to the file. @@ -212,10 +227,10 @@ unsigned io_skip(IOHANDLE io, unsigned size); Returns: Number of bytes written. -*****/ +*/ unsigned io_write(IOHANDLE io, const void *buffer, unsigned size); -/***** +/* Function: io_seek Seeks to a specified offset in the file. @@ -226,10 +241,10 @@ unsigned io_write(IOHANDLE io, const void *buffer, unsigned size); Returns: Returns 0 on success. -*****/ +*/ int io_seek(IOHANDLE io, int offset, int origin); -/***** +/* Function: io_tell Gets the current position in the file. @@ -238,10 +253,10 @@ int io_seek(IOHANDLE io, int offset, int origin); Returns: Returns the current position. -1L if an error occured. -*****/ +*/ long int io_tell(IOHANDLE io); -/***** +/* Function: io_length Gets the total length of the file. Resetting cursor to the beginning @@ -250,10 +265,10 @@ long int io_tell(IOHANDLE io); Returns: Returns the total size. -1L if an error occured. -*****/ +*/ long int io_length(IOHANDLE io); -/***** +/* Function: io_close Closes a file. @@ -262,10 +277,10 @@ long int io_length(IOHANDLE io); Returns: Returns 0 on success. -*****/ +*/ int io_close(IOHANDLE io); -/***** +/* Function: io_flush Empties all buffers and writes all pending data. @@ -274,22 +289,77 @@ int io_close(IOHANDLE io); Returns: Returns 0 on success. -*****/ +*/ int io_flush(IOHANDLE io); -/**** Group: Threads ****/ -/***** +/* + Function: io_stdin + Returns an to the standard input. +*/ +IOHANDLE io_stdin(); + +/* + Function: io_stdout + Returns an to the standard output. +*/ +IOHANDLE io_stdout(); + +/* + Function: io_stderr + Returns an to the standard error. +*/ +IOHANDLE io_stderr(); + + +/* Group: Threads */ + +/* Function: thread_sleep - - Suspends the current thread for a given period. + Suspends the current thread for a given period. Parameters: milliseconds - Number of milliseconds to sleep. -*****/ +*/ void thread_sleep(int milliseconds); -/**** Group: Locks ****/ +/* + Function: thread_create + Creates a new thread. + + Parameters: + threadfunc - Entry point for the new thread. + user - Pointer to pass to the thread. + +*/ +void *thread_create(void (*threadfunc)(void *), void *user); + +/* + Function: thread_wait + Waits for a thread to be done or destroyed. + + Parameters: + thread - Thread to wait for. +*/ +void thread_wait(void *thread); + +/* + Function: thread_destoy + Destroys a thread. + + Parameters: + thread - Thread to destroy. +*/ +void thread_destroy(void *thread); + +/* + Function: thread_yeild + Yeild the current threads execution slice. +*/ +void thread_yield(); + + +/* Group: Locks */ typedef void* LOCK; LOCK lock_create(); @@ -299,7 +369,7 @@ int lock_try(LOCK lock); void lock_wait(LOCK lock); void lock_release(LOCK lock); -/**** Group: Timer ****/ +/* Group: Timer */ #ifdef __GNUC__ /* if compiled with -pedantic-errors it will complain about long not being a C90 thing. @@ -308,71 +378,88 @@ __extension__ typedef long long int64; #else typedef long long int64; #endif -/***** +/* Function: time_get - - Fetches a sample from a high resolution timer. + Fetches a sample from a high resolution timer. Returns: Current value of the timer. Remarks: To know how fast the timer is ticking, see . -*****/ +*/ int64 time_get(); -/***** +/* Function: time_freq - - Returns the frequency of the high resolution timer. + Returns the frequency of the high resolution timer. Returns: Returns the frequency of the high resolution timer. -*****/ +*/ int64 time_freq(); -/**** Group: Network General ipv4 ****/ +/* + Function: time_timestamp + Retrives the current time as a UNIX timestamp + + Returns: + The time as a UNIX timestamp +*/ +unsigned time_timestamp(); + +/* Group: Network General ipv4 */ typedef int NETSOCKET; enum { - NETSOCKET_INVALID = -1 + NETSOCKET_INVALID = -1, + + NETTYPE_INVALID = 0, + NETTYPE_IPV4 = 1, + NETTYPE_IPV6 = 2, + NETTYPE_ALL = ~0 }; -typedef struct +/* +typedef struct { unsigned char ip[4]; unsigned short port; -} NETADDR4; +} NETADDR4;*/ -/***** +typedef struct +{ + unsigned int type; + unsigned char ip[16]; + unsigned short port; +} NETADDR; + +/* Function: net_host_lookup - - Does a hostname lookup by name and fills out the passed NETADDE4 struct with the recieved details. + Does a hostname lookup by name and fills out the passed NETADDR struct with the recieved details. Returns: 0 on success. -*****/ -int net_host_lookup(const char *hostname, unsigned short port, NETADDR4 *addr); +*/ +int net_host_lookup(const char *hostname, NETADDR *addr, int types); -/**** Group: Network UDP4 ****/ +/* Group: Network UDP */ -/***** - Function: net_udp4_create - - Creates a UDP4 socket and binds it to a port. +/* + Function: net_udp_create + Creates a UDP socket and binds it to a port. Parameters: port - Port to bind the socket to. Returns: On success it returns an handle to the socket. On failure it returns NETSOCKET_INVALID. -*****/ -NETSOCKET net_udp4_create(NETADDR4 bindaddr); +*/ +NETSOCKET net_udp_create(NETADDR bindaddr); -/***** - Function: net_udp4_send - - Sends a packet over an UDP4 socket. +/* + Function: net_udp_send + Sends a packet over an UDP socket. Parameters: sock - Socket to use. @@ -382,177 +469,322 @@ NETSOCKET net_udp4_create(NETADDR4 bindaddr); Returns: On success it returns the number of bytes sent. Returns -1 on error. -*****/ -int net_udp4_send(NETSOCKET sock, const NETADDR4 *addr, const void *data, int size); +*/ +int net_udp_send(NETSOCKET sock, const NETADDR *addr, const void *data, int size); -/***** - Function: net_udp4_recv - - Recives a packet over an UDP4 socket. +/* + Function: net_udp_recv + Recives a packet over an UDP socket. Parameters: sock - Socket to use. - addr - Pointer to an NETADDR4 that will recive the address. + addr - Pointer to an NETADDR that will recive the address. data - Pointer to a buffer that will recive the data. maxsize - Maximum size to recive. Returns: On success it returns the number of bytes recived. Returns -1 on error. -*****/ -int net_udp4_recv(NETSOCKET sock, NETADDR4 *addr, void *data, int maxsize); +*/ +int net_udp_recv(NETSOCKET sock, NETADDR *addr, void *data, int maxsize); -/***** - Function: net_udp4_close - - Closes an UDP4 socket. +/* + Function: net_udp_close + Closes an UDP socket. Parameters: sock - Socket to close. Returns: Returns 0 on success. -1 on error. -*****/ -int net_udp4_close(NETSOCKET sock); +*/ +int net_udp_close(NETSOCKET sock); -/**** Group: Network TCP4 ****/ +/* Group: Network TCP */ -/***** - Function: net_tcp4_create +/* + Function: net_tcp_create DOCTODO: serp -*****/ -NETSOCKET net_tcp4_create(const NETADDR4 *a); +*/ +NETSOCKET net_tcp_create(const NETADDR *a); -/***** - Function: net_tcp4_set_non_blocking +/* + Function: net_tcp_set_non_blocking DOCTODO: serp -*****/ -int net_tcp4_set_non_blocking(NETSOCKET sock); +*/ +int net_tcp_set_non_blocking(NETSOCKET sock); -/***** - Function: net_tcp4_set_non_blocking +/* + Function: net_tcp_set_non_blocking DOCTODO: serp -*****/ -int net_tcp4_set_blocking(NETSOCKET sock); +*/ +int net_tcp_set_blocking(NETSOCKET sock); -/***** - Function: net_tcp4_listen +/* + Function: net_tcp_listen DOCTODO: serp -*****/ -int net_tcp4_listen(NETSOCKET sock, int backlog); +*/ +int net_tcp_listen(NETSOCKET sock, int backlog); -/***** - Function: net_tcp4_accept +/* + Function: net_tcp_accept DOCTODO: serp -*****/ -int net_tcp4_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR4 *a); +*/ +int net_tcp_accept(NETSOCKET sock, NETSOCKET *new_sock, NETADDR *a); -/***** - Function: net_tcp4_connect +/* + Function: net_tcp_connect DOCTODO: serp -*****/ -int net_tcp4_connect(NETSOCKET sock, const NETADDR4 *a); +*/ +int net_tcp_connect(NETSOCKET sock, const NETADDR *a); -/***** - Function: net_tcp4_connect_non_blocking +/* + Function: net_tcp_connect_non_blocking DOCTODO: serp -*****/ -int net_tcp4_connect_non_blocking(NETSOCKET sock, const NETADDR4 *a); +*/ +int net_tcp_connect_non_blocking(NETSOCKET sock, const NETADDR *a); -/***** - Function: net_tcp4_send +/* + Function: net_tcp_send DOCTODO: serp -*****/ -int net_tcp4_send(NETSOCKET sock, const void *data, int size); +*/ +int net_tcp_send(NETSOCKET sock, const void *data, int size); -/***** - Function: net_tcp4_recv +/* + Function: net_tcp_recv DOCTODO: serp -*****/ -int net_tcp4_recv(NETSOCKET sock, void *data, int maxsize); +*/ +int net_tcp_recv(NETSOCKET sock, void *data, int maxsize); -/***** - Function: net_tcp4_close +/* + Function: net_tcp_close DOCTODO: serp -*****/ -int net_tcp4_close(NETSOCKET sock); +*/ +int net_tcp_close(NETSOCKET sock); -/***** +/* Function: net_errno DOCTODO: serp -*****/ +*/ int net_errno(); -/***** +/* Function: net_would_block DOCTODO: serp -*****/ +*/ int net_would_block(); -/***** +/* Function: net_init DOCTODO: serp -*****/ +*/ int net_init(); +/* Group: Strings */ + +/* + Function: str_append + Appends a string to another. + + Parameters: + dst - Pointer to a buffer that contains a string. + src - String to append. + dst_size - Size of the buffer of the dst string. + + Remarks: + - The strings are treated as zero-termineted strings. + - Garantees that dst string will contain zero-termination. +*/ +void str_append(char *dst, const char *src, int dst_size); + +/* + Function: str_copy + Copies a string to another. + + Parameters: + dst - Pointer to a buffer that shall recive the string. + src - String to be copied. + dst_size - Size of the buffer dst. + + Remarks: + - The strings are treated as zero-termineted strings. + - Garantees that dst string will contain zero-termination. +*/ +void str_copy(char *dst, const char *src, int dst_size); + +/* + Function: str_format + Performs printf formating into a buffer. + + Parameters: + buffer - Pointer to the buffer to recive the formated string. + buffer_size - Size of the buffer. + format - printf formating string. + ... - Parameters for the formating. + + Remarks: + - See the C manual for syntax for the printf formating string. + - The strings are treated as zero-termineted strings. + - Garantees that dst string will contain zero-termination. +*/ +void str_format(char *buffer, int buffer_size, const char *format, ...); + +/* + Function: str_sanitize_strong + Replaces all characters below 32 and above 127 with whitespace. + + Parameters: + str - String to sanitize. + + Remarks: + - The strings are treated as zero-termineted strings. +*/ +void str_sanitize_strong(char *str); + +/* + Function: str_sanitize + Replaces all characters below 32 and above 127 with whitespace with + exception to \r, \n and \r. + + Parameters: + str - String to sanitize. + + Remarks: + - The strings are treated as zero-termineted strings. +*/ +void str_sanitize(char *str); + +/* + Function: str_comp_nocase + Compares to strings case insensitive. + + Parameters: + a - String to compare. + b - String to compare. + + Returns: + <0 - String g a is lesser then string b + 0 - String a is equal to string b + >0 - String a is greater then string b + + Remarks: + - Only garanted to work with a-z/A-Z. + - The strings are treated as zero-termineted strings. +*/ +int str_comp_nocase(const char *a, const char *b); + +/* + Function: str_find_nocase + Finds a string inside another string case insensitive. + + Parameters: + haystack - String to search in + needle - String to search for + + Returns: + A pointer into haystack where the needle was found. + Returns NULL of needle could not be found. + + Remarks: + - Only garanted to work with a-z/A-Z. + - The strings are treated as zero-termineted strings. +*/ +const char *str_find_nocase(const char *haystack, const char *needle); -/* NOT DOCUMENTED */ +/* + Function: str_hex + Takes a datablock and generates a hexstring of it. + + Parameters: + dst - Buffer to fill with hex data + dst_size - size of the buffer + data - Data to turn into hex + data - Size of the data + + Remarks: + - The desination buffer will be zero-terminated +*/ +void str_hex(char *dst, int dst_size, const void *data, int data_size); + + +/* + Function: fs_listdir + Lists the files in a directory + + Parameters: + dir - Directory to list + cb - Callback function to call for each entry + user - Pointer to give to the callback + + Returns: + DOCTODO +*/ typedef void (*fs_listdir_callback)(const char *name, int is_dir, void *user); int fs_listdir(const char *dir, fs_listdir_callback cb, void *user); -int fs_storage_path(const char *appname, char *path, int max); + +/* + Function: fs_makedir + Creates a directory + + Parameters: + path - Directory to create + + Returns: + DOCTODO + + Remarks: + Does not create several directories if needed. "a/b/c" will result + in a failure if b or a does not exist. +*/ int fs_makedir(const char *path); -int net_addr4_cmp(const NETADDR4 *a, const NETADDR4 *b); + +/* + Function: fs_storage_path + Fetches per user configuration directory. + + Returns: + DOCTODO + + Remarks: + - Returns ~/.appname on UNIX based systems + - Returns %APPDATA%/Appname on Windows based systems +*/ +int fs_storage_path(const char *appname, char *path, int max); + + +/* + Group: Undocumented +*/ + +int net_addr_comp(const NETADDR *a, const NETADDR *b); +int net_addr_str(const NETADDR *addr, char *string, int max_length); int net_socket_read_wait(NETSOCKET sock, int time); void mem_debug_dump(); int mem_allocated(); -void *thread_create(void (*threadfunc)(void *), void *user); -void thread_wait(void *thread); -void thread_destroy(void *thread); -void thread_yield(); -unsigned time_timestamp(); - void swap_endian(void *data, unsigned elem_size, unsigned num); -/* #define cache_prefetch(addr) __builtin_prefetch(addr) */ - -/*typedef unsigned char [256] pstr; -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); -int str_comp_nocase(const char *a, const char *b); -const char *str_find_nocase(const char *haystack, const char *needle); -void str_hex(char *dst, int dst_size, const void *data, int data_size); - typedef void (*DBG_LOGGER)(const char *line); void dbg_logger(DBG_LOGGER logger); void dbg_logger_stdout(); void dbg_logger_debugger(); void dbg_logger_file(const char *filename); -IOHANDLE io_stdin(); -IOHANDLE io_stdout(); -IOHANDLE io_stderr(); - typedef struct { int sent_packets; @@ -561,6 +793,7 @@ typedef struct int recv_bytes; } NETSTATS; + void net_stats(NETSTATS *stats); #ifdef __cplusplus diff --git a/src/engine/server/es_register.c b/src/engine/server/es_register.c index cec0fa194..a85900aaa 100644 --- a/src/engine/server/es_register.c +++ b/src/engine/server/es_register.c @@ -29,7 +29,7 @@ static void register_new_state(int state) register_state_start = time_get(); } -static void register_send_fwcheckresponse(NETADDR4 *addr) +static void register_send_fwcheckresponse(NETADDR *addr) { NETCHUNK packet; packet.client_id = -1; @@ -40,7 +40,7 @@ static void register_send_fwcheckresponse(NETADDR4 *addr) netserver_send(net, &packet); } -static void register_send_heartbeat(NETADDR4 addr) +static void register_send_heartbeat(NETADDR addr) { static unsigned char data[sizeof(SERVERBROWSE_HEARTBEAT) + 2]; unsigned short port = config.sv_port; @@ -62,7 +62,7 @@ static void register_send_heartbeat(NETADDR4 addr) netserver_send(net, &packet); } -static void register_send_count_request(NETADDR4 addr) +static void register_send_count_request(NETADDR addr) { NETCHUNK packet; packet.client_id = -1; @@ -75,13 +75,13 @@ static void register_send_count_request(NETADDR4 addr) typedef struct { - NETADDR4 addr; + NETADDR addr; int count; int valid; int64 last_send; } MASTERSERVER_INFO; -static MASTERSERVER_INFO masterserver_info[MAX_MASTERSERVERS] = {{{{0}}}}; +static MASTERSERVER_INFO masterserver_info[MAX_MASTERSERVERS] = {{{0}}}; static int register_registered_server = -1; void register_update() @@ -111,7 +111,7 @@ void register_update() int i; for(i = 0; i < MAX_MASTERSERVERS; i++) { - NETADDR4 addr = mastersrv_get(i); + NETADDR addr = mastersrv_get(i); masterserver_info[i].addr = addr; masterserver_info[i].count = 0; @@ -229,7 +229,7 @@ static void register_got_count(NETCHUNK *p) for(i = 0; i < MAX_MASTERSERVERS; i++) { - if(net_addr4_cmp(&masterserver_info[i].addr, &p->address) == 0) + if(net_addr_comp(&masterserver_info[i].addr, &p->address) == 0) { masterserver_info[i].count = count; break; diff --git a/src/engine/server/es_server.c b/src/engine/server/es_server.c index ac1a79a15..72da4f5dc 100644 --- a/src/engine/server/es_server.c +++ b/src/engine/server/es_server.c @@ -147,8 +147,8 @@ int snap_new_id() { int id; int64 now = time_get(); - dbg_assert(snap_id_inited == 1, "requesting id too soon"); - + if(!snap_id_inited) + snap_init_id(); /* process timed ids */ while(snap_first_timed_id != -1 && snap_ids[snap_first_timed_id].timeout < now) @@ -433,7 +433,7 @@ static void server_do_snap() break; } } - + /* create delta */ { static PERFORMACE_INFO scope = {"delta", 0}; @@ -453,16 +453,18 @@ static void server_do_snap() { static PERFORMACE_INFO scope = {"compress", 0}; + /*char buffer[512];*/ perf_start(&scope); snapshot_size = intpack_compress(deltadata, deltasize, compdata); + + /*str_hex(buffer, sizeof(buffer), compdata, snapshot_size); + dbg_msg("", "deltasize=%d -> %d : %s", deltasize, snapshot_size, buffer);*/ + perf_end(); } - numpackets = (snapshot_size+max_size-1)/max_size; - - for(n = 0, left = snapshot_size; left; n++) { int chunk = left < max_size ? left : max_size; @@ -776,7 +778,7 @@ static void server_process_client_packet(NETCHUNK *packet) } } -static void server_send_serverinfo(NETADDR4 *addr, int lan) +static void server_send_serverinfo(NETADDR *addr, int lan) { NETCHUNK packet; PACKER p; @@ -904,10 +906,9 @@ static int server_load_map(const char *mapname) static int server_run() { - NETADDR4 bindaddr; + NETADDR bindaddr; net_init(); - snap_init_id(); /* */ console_register_print_callback(server_send_rcon_line_authed); @@ -920,9 +921,11 @@ static int server_run() } /* start server */ - if(config.sv_bindaddr[0] && net_host_lookup(config.sv_bindaddr, config.sv_port, &bindaddr) == 0) + /* TODO: IPv6 support */ + if(config.sv_bindaddr[0] && net_host_lookup(config.sv_bindaddr, &bindaddr, NETTYPE_IPV4) == 0) { /* sweet! */ + bindaddr.port = config.sv_port; } else { @@ -1108,7 +1111,7 @@ static void con_kick(void *result, void *user_data) static void con_status(void *result, void *user_data) { int i; - NETADDR4 addr; + NETADDR addr; for(i = 0; i < MAX_CLIENTS; i++) { if(clients[i].state == SRVCLIENT_STATE_INGAME) diff --git a/src/game/client/gc_client.cpp b/src/game/client/gc_client.cpp index c42c354ec..f0195a471 100644 --- a/src/game/client/gc_client.cpp +++ b/src/game/client/gc_client.cpp @@ -880,7 +880,7 @@ void render_game() // don't use predicted } else - local_character_pos = mix(predicted_prev_player.pos, predicted_player.pos, client_predintratick()); + local_character_pos = mix(predicted_prev_char.pos, predicted_char.pos, client_predintratick()); } else if(netobjects.local_character && netobjects.local_prev_character) { @@ -1663,3 +1663,8 @@ void render_game() } + +extern "C" const char *modc_getitemname(int type) +{ + return netobj_get_name(type); +} diff --git a/src/game/client/gc_client.hpp b/src/game/client/gc_client.hpp index 750154b36..f19766bf7 100644 --- a/src/game/client/gc_client.hpp +++ b/src/game/client/gc_client.hpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include @@ -22,8 +22,8 @@ extern vec2 local_target_pos; // snap pointers struct SNAPSTATE { - const NETOBJ_PLAYER_CHARACTER *local_character; - const NETOBJ_PLAYER_CHARACTER *local_prev_character; + const NETOBJ_CHARACTER *local_character; + const NETOBJ_CHARACTER *local_prev_character; const NETOBJ_PLAYER_INFO *local_info; const NETOBJ_FLAG *flags[2]; const NETOBJ_GAME *gameobj; @@ -46,8 +46,8 @@ extern const NETOBJ_GAME *gameobj; extern TUNING_PARAMS tuning; // predicted players -extern PLAYER_CORE predicted_prev_player; -extern PLAYER_CORE predicted_player; +extern CHARACTER_CORE predicted_prev_char; +extern CHARACTER_CORE predicted_char; // input extern NETOBJ_PLAYER_INPUT input_data; @@ -148,7 +148,7 @@ struct CLIENT_DATA int team; int emoticon; int emoticon_start; - PLAYER_CORE predicted; + CHARACTER_CORE predicted; TEE_RENDER_INFO skin_info; // this is what the server reports TEE_RENDER_INFO render_info; // this is what we use diff --git a/src/game/client/gc_hooks.cpp b/src/game/client/gc_hooks.cpp index 2aaca900f..5d9570fb3 100644 --- a/src/game/client/gc_hooks.cpp +++ b/src/game/client/gc_hooks.cpp @@ -56,6 +56,9 @@ static void load_sounds_thread(void *do_render) extern "C" void modc_init() { + for(int i = 0; i < NUM_NETOBJTYPES; i++) + snap_set_staticsize(i, netobj_get_size(i)); + static FONT_SET default_font; int64 start = time_get(); @@ -128,17 +131,17 @@ extern "C" void modc_shutdown() } -PLAYER_CORE predicted_prev_player; -PLAYER_CORE predicted_player; +CHARACTER_CORE predicted_prev_char; +CHARACTER_CORE predicted_char; static int predicted_tick = 0; static int last_new_predicted_tick = -1; extern "C" void modc_predict() { - PLAYER_CORE before_prev_player = predicted_prev_player; - PLAYER_CORE before_player = predicted_player; + CHARACTER_CORE before_prev_char = predicted_prev_char; + CHARACTER_CORE before_char = predicted_char; - // repredict player + // repredict character WORLD_CORE world; world.tuning = tuning; int local_cid = -1; @@ -150,11 +153,11 @@ extern "C" void modc_predict() const void *data = snap_get_item(SNAP_CURRENT, i, &item); int client_id = item.id; - if(item.type == NETOBJTYPE_PLAYER_CHARACTER) + if(item.type == NETOBJTYPE_CHARACTER) { - const NETOBJ_PLAYER_CHARACTER *character = (const NETOBJ_PLAYER_CHARACTER *)data; + const NETOBJ_CHARACTER *character = (const NETOBJ_CHARACTER *)data; client_datas[client_id].predicted.world = &world; - world.players[client_id] = &client_datas[client_id].predicted; + world.characters[client_id] = &client_datas[client_id].predicted; client_datas[client_id].predicted.read(character); } @@ -174,45 +177,45 @@ extern "C" void modc_predict() for(int tick = client_tick()+1; tick <= client_predtick(); tick++) { // fetch the local - if(tick == client_predtick() && world.players[local_cid]) - predicted_prev_player = *world.players[local_cid]; + if(tick == client_predtick() && world.characters[local_cid]) + predicted_prev_char = *world.characters[local_cid]; // first calculate where everyone should move for(int c = 0; c < MAX_CLIENTS; c++) { - if(!world.players[c]) + if(!world.characters[c]) continue; - mem_zero(&world.players[c]->input, sizeof(world.players[c]->input)); + mem_zero(&world.characters[c]->input, sizeof(world.characters[c]->input)); if(local_cid == c) { // apply player input int *input = client_get_input(tick); if(input) - world.players[c]->input = *((NETOBJ_PLAYER_INPUT*)input); + world.characters[c]->input = *((NETOBJ_PLAYER_INPUT*)input); } - world.players[c]->tick(); + world.characters[c]->tick(); } // move all players and quantize their data for(int c = 0; c < MAX_CLIENTS; c++) { - if(!world.players[c]) + if(!world.characters[c]) continue; - world.players[c]->move(); - world.players[c]->quantize(); + world.characters[c]->move(); + world.characters[c]->quantize(); } if(tick > last_new_predicted_tick) { last_new_predicted_tick = tick; - if(local_cid != -1 && world.players[local_cid]) + if(local_cid != -1 && world.characters[local_cid]) { - vec2 pos = world.players[local_cid]->pos; - int events = world.players[local_cid]->triggered_events; + vec2 pos = world.characters[local_cid]->pos; + int events = world.characters[local_cid]->triggered_events; if(events&COREEVENT_GROUND_JUMP) snd_play_random(CHN_WORLD, SOUND_PLAYER_JUMP, 1.0f, pos); if(events&COREEVENT_AIR_JUMP) { @@ -232,26 +235,26 @@ extern "C" void modc_predict() (int)world.players[c]->vel.x, (int)world.players[c]->vel.y);*/ } - if(tick == client_predtick() && world.players[local_cid]) - predicted_player = *world.players[local_cid]; + if(tick == client_predtick() && world.characters[local_cid]) + predicted_char = *world.characters[local_cid]; } if(config.debug && predicted_tick == client_predtick()) { - if(predicted_player.pos.x != before_player.pos.x || - predicted_player.pos.y != before_player.pos.y) + if(predicted_char.pos.x != before_char.pos.x || + predicted_char.pos.y != before_char.pos.y) { dbg_msg("client", "prediction error, (%d %d) (%d %d)", - (int)before_player.pos.x, (int)before_player.pos.y, - (int)predicted_player.pos.x, (int)predicted_player.pos.y); + (int)before_char.pos.x, (int)before_char.pos.y, + (int)predicted_char.pos.x, (int)predicted_char.pos.y); } - if(predicted_prev_player.pos.x != before_prev_player.pos.x || - predicted_prev_player.pos.y != before_prev_player.pos.y) + if(predicted_prev_char.pos.x != before_prev_char.pos.x || + predicted_prev_char.pos.y != before_prev_char.pos.y) { dbg_msg("client", "prediction error, prev (%d %d) (%d %d)", - (int)before_prev_player.pos.x, (int)before_prev_player.pos.y, - (int)predicted_prev_player.pos.x, (int)predicted_prev_player.pos.y); + (int)before_prev_char.pos.x, (int)before_prev_char.pos.y, + (int)predicted_prev_char.pos.x, (int)predicted_prev_char.pos.y); } } @@ -316,15 +319,15 @@ extern "C" void modc_newsnapshot() if(info->local) { netobjects.local_info = info; - const void *data = snap_find_item(SNAP_CURRENT, NETOBJTYPE_PLAYER_CHARACTER, item.id); + const void *data = snap_find_item(SNAP_CURRENT, NETOBJTYPE_CHARACTER, item.id); if(data) { - netobjects.local_character = (const NETOBJ_PLAYER_CHARACTER *)data; + netobjects.local_character = (const NETOBJ_CHARACTER *)data; local_character_pos = vec2(netobjects.local_character->x, netobjects.local_character->y); - const void *p = snap_find_item(SNAP_PREV, NETOBJTYPE_PLAYER_CHARACTER, item.id); + const void *p = snap_find_item(SNAP_PREV, NETOBJTYPE_CHARACTER, item.id); if(p) - netobjects.local_prev_character = (NETOBJ_PLAYER_CHARACTER *)p; + netobjects.local_prev_character = (NETOBJ_CHARACTER *)p; } } } diff --git a/src/game/client/gc_menu.cpp b/src/game/client/gc_menu.cpp index cb8324a7f..3a1e9cee3 100644 --- a/src/game/client/gc_menu.cpp +++ b/src/game/client/gc_menu.cpp @@ -15,7 +15,7 @@ extern "C" { } #include "../g_version.hpp" -#include "../g_protocol.hpp" +#include #include "../generated/gc_data.hpp" #include "gc_render.hpp" diff --git a/src/game/client/gc_render.cpp b/src/game/client/gc_render.cpp index 2e5a3d506..afb827fb6 100644 --- a/src/game/client/gc_render.cpp +++ b/src/game/client/gc_render.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include "gc_render.hpp" @@ -473,7 +473,7 @@ static void render_players() SNAP_ITEM item; const void *data = snap_get_item(SNAP_CURRENT, i, &item); - if(item.type == NETOBJTYPE_PLAYER_CHARACTER) + if(item.type == NETOBJTYPE_CHARACTER) { const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); const void *prev_info = snap_find_item(SNAP_PREV, NETOBJTYPE_PLAYER_INFO, item.id); @@ -482,8 +482,8 @@ static void render_players() if(prev && prev_info && info) { render_player( - (const NETOBJ_PLAYER_CHARACTER *)prev, - (const NETOBJ_PLAYER_CHARACTER *)data, + (const NETOBJ_CHARACTER *)prev, + (const NETOBJ_CHARACTER *)data, (const NETOBJ_PLAYER_INFO *)prev_info, (const NETOBJ_PLAYER_INFO *)info ); diff --git a/src/game/client/gc_render.hpp b/src/game/client/gc_render.hpp index 02bc224df..d819c194d 100644 --- a/src/game/client/gc_render.hpp +++ b/src/game/client/gc_render.hpp @@ -66,7 +66,7 @@ void render_pickup(const struct NETOBJ_PICKUP *prev, const struct NETOBJ_PICKUP void render_projectile(const struct NETOBJ_PROJECTILE *current, int itemid); void render_laser(const struct NETOBJ_LASER *current); void render_player( - const struct NETOBJ_PLAYER_CHARACTER *prev_char, const struct NETOBJ_PLAYER_CHARACTER *player_char, + const struct NETOBJ_CHARACTER *prev_char, const struct NETOBJ_CHARACTER *player_char, const struct NETOBJ_PLAYER_INFO *prev_info, const struct NETOBJ_PLAYER_INFO *player_info); // map render methods (gc_render_map.cpp) diff --git a/src/game/client/gc_render_obj.cpp b/src/game/client/gc_render_obj.cpp index 119db4d66..daba5ceb0 100644 --- a/src/game/client/gc_render_obj.cpp +++ b/src/game/client/gc_render_obj.cpp @@ -3,8 +3,8 @@ #include #include #include -#include "../generated/gc_data.hpp" -#include "../g_protocol.hpp" +#include +#include #include "../g_math.hpp" #include "gc_render.hpp" #include "gc_anim.hpp" @@ -265,14 +265,14 @@ static void render_hand(TEE_RENDER_INFO *info, vec2 center_pos, vec2 dir, float } void render_player( - const NETOBJ_PLAYER_CHARACTER *prev_char, - const NETOBJ_PLAYER_CHARACTER *player_char, + const NETOBJ_CHARACTER *prev_char, + const NETOBJ_CHARACTER *player_char, const NETOBJ_PLAYER_INFO *prev_info, const NETOBJ_PLAYER_INFO *player_info ) { - NETOBJ_PLAYER_CHARACTER prev; - NETOBJ_PLAYER_CHARACTER player; + NETOBJ_CHARACTER prev; + NETOBJ_CHARACTER player; prev = *prev_char; player = *player_char; @@ -330,8 +330,8 @@ void render_player( else { // apply predicted results - predicted_player.write(&player); - predicted_prev_player.write(&prev); + predicted_char.write(&player); + predicted_prev_char.write(&prev); intratick = client_predintratick(); } } @@ -403,8 +403,8 @@ void render_player( { 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()); + hook_pos = mix(vec2(predicted_prev_char.pos.x, predicted_prev_char.pos.y), + vec2(predicted_char.pos.x, predicted_char.pos.y), client_predintratick()); } else hook_pos = mix(vec2(prev_char->hook_x, prev_char->hook_y), vec2(player_char->hook_x, player_char->hook_y), client_intratick()); @@ -541,7 +541,6 @@ void render_player( vec2 diry(-dir.y,dir.x); vec2 muzzlepos = p + dir * data->weapons.id[iw].muzzleoffsetx + diry * offsety; - dbg_msg("", "%d", data->weapons.id[iw].num_sprite_muzzles); draw_sprite(muzzlepos.x, muzzlepos.y, data->weapons.id[iw].visual_size); } } diff --git a/src/game/g_game.cpp b/src/game/g_game.cpp index 6545a75d5..2f14b25f8 100644 --- a/src/game/g_game.cpp +++ b/src/game/g_game.cpp @@ -166,7 +166,7 @@ float velocity_ramp(float value, float start, float range, float curvature) return 1.0f/pow(curvature, (value-start)/range); } -void PLAYER_CORE::reset() +void CHARACTER_CORE::reset() { pos = vec2(0,0); vel = vec2(0,0); @@ -179,7 +179,7 @@ void PLAYER_CORE::reset() triggered_events = 0; } -void PLAYER_CORE::tick() +void CHARACTER_CORE::tick() { float phys_size = 28.0f; triggered_events = 0; @@ -273,7 +273,7 @@ void PLAYER_CORE::tick() // Check against other players first for(int i = 0; i < MAX_CLIENTS; i++) { - PLAYER_CORE *p = world->players[i]; + CHARACTER_CORE *p = world->characters[i]; if(!p || p == this) continue; @@ -312,7 +312,7 @@ void PLAYER_CORE::tick() { if(hooked_player != -1) { - PLAYER_CORE *p = world->players[hooked_player]; + CHARACTER_CORE *p = world->characters[hooked_player]; if(p) hook_pos = p->pos; else @@ -366,7 +366,7 @@ void PLAYER_CORE::tick() { for(int i = 0; i < MAX_CLIENTS; i++) { - PLAYER_CORE *p = world->players[i]; + CHARACTER_CORE *p = world->characters[i]; if(!p) continue; @@ -414,7 +414,7 @@ void PLAYER_CORE::tick() vel = normalize(vel) * 6000; } -void PLAYER_CORE::move() +void CHARACTER_CORE::move() { float rampvalue = velocity_ramp(length(vel)*50, world->tuning.velramp_start, world->tuning.velramp_range, world->tuning.velramp_curvature); @@ -423,7 +423,7 @@ void PLAYER_CORE::move() vel.x = vel.x*(1.0f/rampvalue); } -void PLAYER_CORE::write(NETOBJ_PLAYER_CORE *obj_core) +void CHARACTER_CORE::write(NETOBJ_CHARACTER_CORE *obj_core) { obj_core->x = (int)pos.x; obj_core->y = (int)pos.y; @@ -450,7 +450,7 @@ void PLAYER_CORE::write(NETOBJ_PLAYER_CORE *obj_core) obj_core->angle = (int)(a*256.0f); } -void PLAYER_CORE::read(const NETOBJ_PLAYER_CORE *obj_core) +void CHARACTER_CORE::read(const NETOBJ_CHARACTER_CORE *obj_core) { pos.x = obj_core->x; pos.y = obj_core->y; @@ -466,9 +466,9 @@ void PLAYER_CORE::read(const NETOBJ_PLAYER_CORE *obj_core) jumped = obj_core->jumped; } -void PLAYER_CORE::quantize() +void CHARACTER_CORE::quantize() { - NETOBJ_PLAYER_CORE c; + NETOBJ_CHARACTER_CORE c; write(&c); read(&c); } diff --git a/src/game/g_game.hpp b/src/game/g_game.hpp index 7ab8df40a..61342d76f 100644 --- a/src/game/g_game.hpp +++ b/src/game/g_game.hpp @@ -7,7 +7,7 @@ #include #include "g_math.hpp" #include "g_collision.hpp" -#include "g_protocol.hpp" +#include struct TUNING_PARAMS { @@ -114,14 +114,14 @@ class WORLD_CORE public: WORLD_CORE() { - mem_zero(players, sizeof(players)); + mem_zero(characters, sizeof(characters)); } TUNING_PARAMS tuning; - class PLAYER_CORE *players[MAX_CLIENTS]; + class CHARACTER_CORE *characters[MAX_CLIENTS]; }; -class PLAYER_CORE +class CHARACTER_CORE { public: WORLD_CORE *world; @@ -144,8 +144,8 @@ public: void tick(); void move(); - void read(const NETOBJ_PLAYER_CORE *obj_core); - void write(NETOBJ_PLAYER_CORE *obj_core); + void read(const NETOBJ_CHARACTER_CORE *obj_core); + void write(NETOBJ_CHARACTER_CORE *obj_core); void quantize(); }; diff --git a/src/game/g_protocol.hpp b/src/game/g_protocol.hpp deleted file mode 100644 index 8650b8be4..000000000 --- a/src/game/g_protocol.hpp +++ /dev/null @@ -1,217 +0,0 @@ -/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ -// NOTE: Be very careful when editing this file as it will change the network version - -#ifndef GAME_PROTOCOL_H -#define GAME_PROTOCOL_H - -#include - -// Network stuff -/* -enum -{ - OBJTYPE_NULL=0, - OBJTYPE_GAME, - OBJTYPE_PLAYER_INFO, - OBJTYPE_PLAYER_CHARACTER, // use this if you are searching for the player entity - OBJTYPE_PROJECTILE, - OBJTYPE_LASER, - OBJTYPE_POWERUP, - OBJTYPE_FLAG, - EVENT_EXPLOSION, - EVENT_DAMAGEINDICATION, - EVENT_SOUND_WORLD, - EVENT_SMOKE, - EVENT_PLAYERSPAWN, - EVENT_DEATH, - EVENT_AIR_JUMP, - - EVENT_DUMMY -}; - -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 - -}; - -enum -{ - EMOTE_NORMAL=0, - EMOTE_PAIN, - EMOTE_HAPPY, - EMOTE_SURPRISE, - EMOTE_ANGRY, - EMOTE_BLINK, -}; - -enum -{ - INPUT_STATE_MASK=0x1f, -}; - -enum -{ - PLAYERSTATE_UNKNOWN=0, - PLAYERSTATE_PLAYING, - PLAYERSTATE_IN_MENU, - PLAYERSTATE_CHATTING, - - GAMETYPE_DM=0, - GAMETYPE_TDM, - GAMETYPE_CTF, -}; - -struct player_input -{ - int left; - int right; - - int target_x; - int target_y; - - int jump; - int fire; - int hook; - int blink; - - int player_state; - - int wanted_weapon; - int next_weapon; - int prev_weapon; -}; - -struct ev_common -{ - int x, y; -}; - -struct ev_explosion : public ev_common -{ -}; - -struct ev_spawn : public ev_common -{ -}; - -struct ev_death : public ev_common -{ -}; - -struct ev_sound : public ev_common -{ - int sound; -}; - -struct ev_damageind : public ev_common -{ - int angle; -}; - -struct obj_game -{ - int round_start_tick; - int game_over; - int sudden_death; - int paused; - - int score_limit; - int time_limit; - int gametype; - - int warmup; - - int teamscore[2]; -}; - -struct obj_projectile -{ - int x, y; - int vx, vy; // should be an angle instead - int type; - int start_tick; -}; - -struct obj_laser -{ - int x, y; - int from_x, from_y; - int eval_tick; -}; - -struct obj_powerup -{ - int x, y; - int type; // why do we need two types? - int subtype; -}; - -struct obj_flag -{ - int x, y; - int team; - int carried_by; // is set if the local player has the flag -}; - -// core object needed for physics -struct obj_player_core -{ - int x, y; - int vx, vy; - int angle; - int jumped; - - int hooked_player; - int hook_state; - int hook_tick; - int hook_x, hook_y; - int hook_dx, hook_dy; -}; - -// info about the player that is only needed when it's on screen -struct obj_player_character : public obj_player_core -{ - int player_state; - - int health; - int armor; - int ammocount; - int weaponstage; - - int weapon; // current active weapon - - int emote; - - int attacktick; // num attack ticks left of current attack -}; - -// information about the player that is always needed -struct obj_player_info -{ - int local; - int clientid; - - int team; - int score; - int latency; - int latency_flux; -};*/ - -#endif diff --git a/src/game/server/gs_common.hpp b/src/game/server/gs_common.hpp index b6c809fa3..ff9391164 100644 --- a/src/game/server/gs_common.hpp +++ b/src/game/server/gs_common.hpp @@ -2,16 +2,15 @@ #include "../g_game.hpp" #include "../generated/gs_data.hpp" - extern TUNING_PARAMS tuning; -void create_sound_global(int sound, int target=-1); - inline int cmask_all() { return -1; } inline int cmask_one(int cid) { return 1< +#include "gs_common.hpp" + +////////////////////////////////////////////////// +// powerup +////////////////////////////////////////////////// +PICKUP::PICKUP(int _type, int _subtype) +: ENTITY(NETOBJTYPE_PICKUP) +{ + type = _type; + subtype = _subtype; + proximity_radius = phys_size; + + reset(); + + // TODO: should this be done here? + game.world.insert_entity(this); +} + +void PICKUP::reset() +{ + if (data->pickups[type].spawndelay > 0) + spawntick = server_tick() + server_tickspeed() * data->pickups[type].spawndelay; + else + spawntick = -1; +} + +void PICKUP::tick() +{ + // wait for respawn + if(spawntick > 0) + { + if(server_tick() > spawntick) + { + // respawn + spawntick = -1; + + if(type == POWERUP_WEAPON) + game.create_sound(pos, SOUND_WEAPON_SPAWN); + } + else + return; + } + // Check if a player intersected us + CHARACTER *chr = game.world.closest_character(pos, 20.0f, 0); + if(chr) + { + // player picked us up, is someone was hooking us, let them go + int respawntime = -1; + switch (type) + { + case POWERUP_HEALTH: + if(chr->increase_health(1)) + { + game.create_sound(pos, SOUND_PICKUP_HEALTH); + respawntime = data->pickups[type].respawntime; + } + break; + case POWERUP_ARMOR: + if(chr->increase_armor(1)) + { + game.create_sound(pos, SOUND_PICKUP_ARMOR); + respawntime = data->pickups[type].respawntime; + } + break; + + case POWERUP_WEAPON: + if(subtype >= 0 && subtype < NUM_WEAPONS) + { + if(chr->weapons[subtype].ammo < data->weapons.id[subtype].maxammo || !chr->weapons[subtype].got) + { + chr->weapons[subtype].got = true; + chr->weapons[subtype].ammo = min(data->weapons.id[subtype].maxammo, chr->weapons[subtype].ammo + 10); + respawntime = data->pickups[type].respawntime; + + // TODO: data compiler should take care of stuff like this + if(subtype == WEAPON_GRENADE) + game.create_sound(pos, SOUND_PICKUP_GRENADE); + else if(subtype == WEAPON_SHOTGUN) + game.create_sound(pos, SOUND_PICKUP_SHOTGUN); + else if(subtype == WEAPON_RIFLE) + game.create_sound(pos, SOUND_PICKUP_SHOTGUN); + + if(chr->player) + game.send_weapon_pickup(chr->player->client_id, subtype); + } + } + break; + case POWERUP_NINJA: + { + // activate ninja on target player + chr->ninja.activationtick = server_tick(); + chr->weapons[WEAPON_NINJA].got = true; + chr->last_weapon = chr->active_weapon; + chr->active_weapon = WEAPON_NINJA; + respawntime = data->pickups[type].respawntime; + game.create_sound(pos, SOUND_PICKUP_NINJA); + + // loop through all players, setting their emotes + ENTITY *ents[64]; + int num = game.world.find_entities(vec2(0, 0), 1000000, ents, 64, NETOBJTYPE_CHARACTER); + for (int i = 0; i < num; i++) + { + CHARACTER *c = (CHARACTER *)ents[i]; + if (c != chr) + { + c->emote_type = EMOTE_SURPRISE; + c->emote_stop = server_tick() + server_tickspeed(); + } + } + + chr->emote_type = EMOTE_ANGRY; + chr->emote_stop = server_tick() + 1200 * server_tickspeed() / 1000; + + break; + } + default: + break; + }; + + if(respawntime >= 0) + { + dbg_msg("game", "pickup player='%d:%s' item=%d/%d", + chr->player->client_id, server_clientname(chr->player->client_id), type, subtype); + spawntick = server_tick() + server_tickspeed() * respawntime; + } + } +} + +void PICKUP::snap(int snapping_client) +{ + if(spawntick != -1) + return; + + NETOBJ_PICKUP *up = (NETOBJ_PICKUP *)snap_new_item(NETOBJTYPE_PICKUP, id, sizeof(NETOBJ_PICKUP)); + up->x = (int)pos.x; + up->y = (int)pos.y; + up->type = type; // TODO: two diffrent types? what gives? + up->subtype = subtype; +} diff --git a/src/game/server/gs_ent_player.cpp b/src/game/server/gs_ent_player.cpp new file mode 100644 index 000000000..b476a9725 --- /dev/null +++ b/src/game/server/gs_ent_player.cpp @@ -0,0 +1,1128 @@ +#include +#include +#include +#include "gs_common.hpp" + + +struct INPUT_COUNT +{ + int presses; + int releases; +}; + +static INPUT_COUNT count_input(int prev, int cur) +{ + INPUT_COUNT c = {0,0}; + prev &= INPUT_STATE_MASK; + cur &= INPUT_STATE_MASK; + int i = prev; + while(i != cur) + { + i = (i+1)&INPUT_STATE_MASK; + if(i&1) + c.presses++; + else + c.releases++; + } + + return c; +} + +// player +CHARACTER::CHARACTER() +: ENTITY(NETOBJTYPE_CHARACTER) +{} + +void CHARACTER::reset() +{ + +} + +bool CHARACTER::spawn(PLAYER *player, vec2 pos, int team) +{ + player_state = PLAYERSTATE_UNKNOWN; + emote_stop = -1; + last_action = -1; + active_weapon = WEAPON_GUN; + last_weapon = WEAPON_HAMMER; + queued_weapon = -1; + + //clear(); + this->player = player; + this->pos = pos; + this->team = team; + + core.reset(); + core.world = &game.world.core; + core.pos = pos; + game.world.core.characters[player->client_id] = &core; + + game.world.insert_entity(this); + alive = true; + return true; +} + +void CHARACTER::destroy() +{ + game.world.core.characters[player->client_id] = 0; + alive = false; +} + +void CHARACTER::set_weapon(int w) +{ + if(w == active_weapon) + return; + + last_weapon = active_weapon; + queued_weapon = -1; + active_weapon = w; + if(active_weapon < 0 || active_weapon >= NUM_WEAPONS) + active_weapon = 0; + + game.create_sound(pos, SOUND_WEAPON_SWITCH); +} + +bool CHARACTER::is_grounded() +{ + if(col_check_point((int)(pos.x+phys_size/2), (int)(pos.y+phys_size/2+5))) + return true; + if(col_check_point((int)(pos.x-phys_size/2), (int)(pos.y+phys_size/2+5))) + return true; + return false; +} + + +int CHARACTER::handle_ninja() +{ + vec2 direction = normalize(vec2(latest_input.target_x, latest_input.target_y)); + + if ((server_tick() - ninja.activationtick) > (data->weapons.ninja.duration * server_tickspeed() / 1000)) + { + // time's up, return + weapons[WEAPON_NINJA].got = false; + active_weapon = last_weapon; + if(active_weapon == WEAPON_NINJA) + active_weapon = WEAPON_GUN; + set_weapon(active_weapon); + return 0; + } + + // force ninja weapon + set_weapon(WEAPON_NINJA); + + // Check if it should activate + if (count_input(latest_previnput.fire, latest_input.fire).presses && (server_tick() > ninja.currentcooldown)) + { + // ok then, activate ninja + attack_tick = server_tick(); + ninja.activationdir = direction; + ninja.currentmovetime = data->weapons.ninja.movetime * server_tickspeed() / 1000; + ninja.currentcooldown = data->weapons.ninja.base->firedelay * server_tickspeed() / 1000 + server_tick(); + + // reset hit objects + numobjectshit = 0; + + game.create_sound(pos, SOUND_NINJA_FIRE); + + // release all hooks when ninja is activated + //release_hooked(); + //release_hooks(); + } + + ninja.currentmovetime--; + + if (ninja.currentmovetime == 0) + { + // reset player velocity + core.vel *= 0.2f; + //return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON; + } + + if (ninja.currentmovetime > 0) + { + // Set player velocity + core.vel = ninja.activationdir * data->weapons.ninja.velocity; + vec2 oldpos = pos; + move_box(&core.pos, &core.vel, vec2(phys_size, phys_size), 0.0f); + // reset velocity so the client doesn't predict stuff + core.vel = vec2(0.0f,0.0f); + if ((ninja.currentmovetime % 2) == 0) + { + //create_smoke(pos); + } + + // check if we hit anything along the way + { + CHARACTER *ents[64]; + vec2 dir = pos - oldpos; + float radius = phys_size * 2.0f; //length(dir * 0.5f); + vec2 center = oldpos + dir * 0.5f; + int num = game.world.find_entities(center, radius, (ENTITY**)ents, 64, NETOBJTYPE_CHARACTER); + + for (int i = 0; i < num; i++) + { + // Check if entity is a player + if (ents[i] == this) + continue; + // make sure we haven't hit this object before + bool balreadyhit = false; + for (int j = 0; j < numobjectshit; j++) + { + if (hitobjects[j] == ents[i]) + balreadyhit = true; + } + if (balreadyhit) + continue; + + // check so we are sufficiently close + if (distance(ents[i]->pos, pos) > (phys_size * 2.0f)) + continue; + + // hit a player, give him damage and stuffs... + game.create_sound(ents[i]->pos, SOUND_NINJA_HIT); + // set his velocity to fast upward (for now) + if(numobjectshit < 10) + hitobjects[numobjectshit++] = ents[i]; + + ents[i]->take_damage(vec2(0,10.0f), data->weapons.ninja.base->damage, player->client_id,WEAPON_NINJA); + } + } + return 0; + } + + return 0; +} + + +void CHARACTER::do_weaponswitch() +{ + if(reload_timer != 0) // make sure we have reloaded + return; + + if(queued_weapon == -1) // check for a queued weapon + return; + + if(weapons[WEAPON_NINJA].got) // if we have ninja, no weapon selection is possible + return; + + // switch weapon + set_weapon(queued_weapon); +} + +void CHARACTER::handle_weaponswitch() +{ + int wanted_weapon = active_weapon; + if(queued_weapon != -1) + wanted_weapon = queued_weapon; + + // select weapon + int next = count_input(latest_previnput.next_weapon, latest_input.next_weapon).presses; + int prev = count_input(latest_previnput.prev_weapon, latest_input.prev_weapon).presses; + + if(next < 128) // make sure we only try sane stuff + { + while(next) // next weapon selection + { + wanted_weapon = (wanted_weapon+1)%NUM_WEAPONS; + if(weapons[wanted_weapon].got) + next--; + } + } + + if(prev < 128) // make sure we only try sane stuff + { + while(prev) // prev weapon selection + { + wanted_weapon = (wanted_weapon-1)<0?NUM_WEAPONS-1:wanted_weapon-1; + if(weapons[wanted_weapon].got) + prev--; + } + } + + // direct weapon selection + if(latest_input.wanted_weapon) + wanted_weapon = input.wanted_weapon-1; + + // check for insane values + if(wanted_weapon >= 0 && wanted_weapon < NUM_WEAPONS && wanted_weapon != active_weapon && weapons[wanted_weapon].got) + queued_weapon = wanted_weapon; + + do_weaponswitch(); +} + +void CHARACTER::fire_weapon() +{ + if(reload_timer != 0 || active_weapon == WEAPON_NINJA) + return; + + do_weaponswitch(); + + vec2 direction = normalize(vec2(latest_input.target_x, latest_input.target_y)); + + bool fullauto = false; + if(active_weapon == WEAPON_GRENADE || active_weapon == WEAPON_SHOTGUN || active_weapon == WEAPON_RIFLE) + fullauto = true; + + + // check if we gonna fire + bool will_fire = false; + if(count_input(latest_previnput.fire, latest_input.fire).presses) will_fire = true; + if(fullauto && (latest_input.fire&1) && weapons[active_weapon].ammo) will_fire = true; + if(!will_fire) + return; + + // check for ammo + if(!weapons[active_weapon].ammo) + { + game.create_sound(pos, SOUND_WEAPON_NOAMMO); + return; + } + + vec2 projectile_startpos = pos+direction*phys_size*0.75f; + + switch(active_weapon) + { + case WEAPON_HAMMER: + { + // reset objects hit + numobjectshit = 0; + game.create_sound(pos, SOUND_HAMMER_FIRE); + + CHARACTER *ents[64]; + int num = game.world.find_entities(pos+direction*phys_size*0.75f, phys_size*0.5f, (ENTITY**)ents, 64, NETOBJTYPE_CHARACTER); + + for (int i = 0; i < num; i++) + { + CHARACTER *target = ents[i]; + if (target == this) + continue; + + // hit a player, give him damage and stuffs... + vec2 fdir = normalize(ents[i]->pos - pos); + + // set his velocity to fast upward (for now) + game.create_sound(pos, SOUND_HAMMER_HIT); + ents[i]->take_damage(vec2(0,-1.0f), data->weapons.hammer.base->damage, player->client_id, active_weapon); + vec2 dir; + if (length(target->pos - pos) > 0.0f) + dir = normalize(target->pos - pos); + else + dir = vec2(0,-1); + + target->core.vel += normalize(dir + vec2(0,-1.1f)) * 10.0f; + } + + } break; + + case WEAPON_GUN: + { + PROJECTILE *proj = new PROJECTILE(WEAPON_GUN, + player->client_id, + projectile_startpos, + direction, + (int)(server_tickspeed()*tuning.gun_lifetime), + this, + 1, 0, 0, -1, WEAPON_GUN); + + // pack the projectile and send it to the client directly + NETOBJ_PROJECTILE p; + proj->fill_info(&p); + + msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0); + msg_pack_int(1); + for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++) + msg_pack_int(((int *)&p)[i]); + msg_pack_end(); + server_send_msg(player->client_id); + + game.create_sound(pos, SOUND_GUN_FIRE); + } break; + + case WEAPON_SHOTGUN: + { + int shotspread = 2; + + msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0); + msg_pack_int(shotspread*2+1); + + for(int i = -shotspread; i <= shotspread; i++) + { + float spreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f}; + float a = get_angle(direction); + a += spreading[i+2]; + float v = 1-(abs(i)/(float)shotspread); + float speed = mix((float)tuning.shotgun_speeddiff, 1.0f, v); + PROJECTILE *proj = new PROJECTILE(WEAPON_SHOTGUN, + player->client_id, + projectile_startpos, + vec2(cosf(a), sinf(a))*speed, + (int)(server_tickspeed()*tuning.shotgun_lifetime), + this, + 1, 0, 0, -1, WEAPON_SHOTGUN); + + // pack the projectile and send it to the client directly + NETOBJ_PROJECTILE p; + proj->fill_info(&p); + + for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++) + msg_pack_int(((int *)&p)[i]); + } + + msg_pack_end(); + server_send_msg(player->client_id); + + game.create_sound(pos, SOUND_SHOTGUN_FIRE); + } break; + + case WEAPON_GRENADE: + { + PROJECTILE *proj = new PROJECTILE(WEAPON_GRENADE, + player->client_id, + projectile_startpos, + direction, + (int)(server_tickspeed()*tuning.grenade_lifetime), + this, + 1, PROJECTILE::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_GRENADE); + + // pack the projectile and send it to the client directly + NETOBJ_PROJECTILE p; + proj->fill_info(&p); + + msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0); + msg_pack_int(1); + for(unsigned i = 0; i < sizeof(NETOBJ_PROJECTILE)/sizeof(int); i++) + msg_pack_int(((int *)&p)[i]); + msg_pack_end(); + server_send_msg(player->client_id); + + game.create_sound(pos, SOUND_GRENADE_FIRE); + } break; + + case WEAPON_RIFLE: + { + new LASER(pos, direction, tuning.laser_reach, this); + game.create_sound(pos, SOUND_RIFLE_FIRE); + } break; + + } + + if(weapons[active_weapon].ammo > 0) // -1 == unlimited + weapons[active_weapon].ammo--; + attack_tick = server_tick(); + reload_timer = data->weapons.id[active_weapon].firedelay * server_tickspeed() / 1000; +} + +int CHARACTER::handle_weapons() +{ + vec2 direction = normalize(vec2(latest_input.target_x, latest_input.target_y)); + + /* + if(config.dbg_stress) + { + for(int i = 0; i < NUM_WEAPONS; i++) + { + weapons[i].got = true; + weapons[i].ammo = 10; + } + + if(reload_timer) // twice as fast reload + reload_timer--; + } */ + + // check reload timer + if(reload_timer) + { + reload_timer--; + return 0; + } + + if (active_weapon == WEAPON_NINJA) + { + // don't update other weapons while ninja is active + return handle_ninja(); + } + + // fire weapon, if wanted + fire_weapon(); + + // ammo regen + int ammoregentime = data->weapons.id[active_weapon].ammoregentime; + if(ammoregentime) + { + // If equipped and not active, regen ammo? + if (reload_timer <= 0) + { + if (weapons[active_weapon].ammoregenstart < 0) + weapons[active_weapon].ammoregenstart = server_tick(); + + if ((server_tick() - weapons[active_weapon].ammoregenstart) >= ammoregentime * server_tickspeed() / 1000) + { + // Add some ammo + weapons[active_weapon].ammo = min(weapons[active_weapon].ammo + 1, 10); + weapons[active_weapon].ammoregenstart = -1; + } + } + else + { + weapons[active_weapon].ammoregenstart = -1; + } + } + + return 0; +} + +void CHARACTER::on_predicted_input(NETOBJ_PLAYER_INPUT *new_input) +{ + // check for changes + if(mem_comp(&input, new_input, sizeof(NETOBJ_PLAYER_INPUT)) != 0) + last_action = server_tick(); + + // copy new input + mem_copy(&input, new_input, sizeof(input)); + num_inputs++; + + // or are not allowed to aim in the center + if(input.target_x == 0 && input.target_y == 0) + input.target_y = -1; +} + +void CHARACTER::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)); + + if(num_inputs > 2 && team != -1) + { + handle_weaponswitch(); + fire_weapon(); + } +} + +void CHARACTER::tick() +{ + //input = latest_input; + + // grab latest input + /* + { + int size = 0; + int *input = server_latestinput(client_id, &size); + if(input) + { + mem_copy(&latest_previnput, &latest_input, sizeof(latest_input)); + mem_copy(&latest_input, input, sizeof(latest_input)); + } + }*/ + + // check if we have enough input + // this is to prevent initial weird clicks + /* + if(num_inputs < 2) + { + latest_previnput = latest_input; + previnput = input; + }*/ + + //game.world.core.players[player->client_id] = &core; + + // enable / disable physics + /* + if(team == -1 || dead) + { + game.world.core.players[client_id] = 0; + //game.world.remove_entity(this); + } + else + { + game.world.core.players[client_id] = &core; + //game.world._entity(this); + } + + // spectator + if(team == -1) + return; + + if(spawning) + try_respawn(); + + // TODO: rework the input to be more robust + if(dead) + { + if(server_tick()-die_tick >= server_tickspeed()/2 && count_input(latest_previnput.fire, latest_input.fire).presses) + die_tick = -1; + if(server_tick()-die_tick >= server_tickspeed()*5) // auto respawn after 3 sec + respawn(); + //if((input.fire&1) && server_tick()-die_tick >= server_tickspeed()/2) // auto respawn after 0.5 sec + //respawn(); + return; + } + * */ + + //player_core core; + //core.pos = pos; + //core.jumped = jumped; + core.input = input; + core.tick(); + + // handle weapons + handle_weapons(); + + player_state = input.player_state; + + // Previnput + previnput = input; + return; +} + +void CHARACTER::tick_defered() +{ + /*if(!dead) + {*/ + vec2 start_pos = core.pos; + vec2 start_vel = core.vel; + bool stuck_before = test_box(core.pos, vec2(28.0f, 28.0f)); + + core.move(); + bool stuck_after_move = test_box(core.pos, vec2(28.0f, 28.0f)); + core.quantize(); + bool stuck_after_quant = test_box(core.pos, vec2(28.0f, 28.0f)); + pos = core.pos; + + if(!stuck_before && (stuck_after_move || stuck_after_quant)) + { + dbg_msg("player", "STUCK!!! %d %d %d %f %f %f %f %x %x %x %x", + stuck_before, + stuck_after_move, + stuck_after_quant, + start_pos.x, start_pos.y, + start_vel.x, start_vel.y, + *((unsigned *)&start_pos.x), *((unsigned *)&start_pos.y), + *((unsigned *)&start_vel.x), *((unsigned *)&start_vel.y)); + } + + int events = core.triggered_events; + int mask = cmask_all_except_one(player->client_id); + + if(events&COREEVENT_GROUND_JUMP) game.create_sound(pos, SOUND_PLAYER_JUMP, mask); + if(events&COREEVENT_AIR_JUMP) + { + game.create_sound(pos, SOUND_PLAYER_AIRJUMP, mask); + NETEVENT_COMMON *c = (NETEVENT_COMMON *)game.events.create(NETEVENTTYPE_AIRJUMP, sizeof(NETEVENT_COMMON), mask); + if(c) + { + c->x = (int)pos.x; + c->y = (int)pos.y; + } + } + + //if(events&COREEVENT_HOOK_LAUNCH) snd_play_random(CHN_WORLD, SOUND_HOOK_LOOP, 1.0f, pos); + if(events&COREEVENT_HOOK_ATTACH_PLAYER) game.create_sound(pos, SOUND_HOOK_ATTACH_PLAYER, cmask_all()); + if(events&COREEVENT_HOOK_ATTACH_GROUND) game.create_sound(pos, SOUND_HOOK_ATTACH_GROUND, mask); + //if(events&COREEVENT_HOOK_RETRACT) snd_play_random(CHN_WORLD, SOUND_PLAYER_JUMP, 1.0f, pos); + //} + + if(team == -1) + { + pos.x = input.target_x; + pos.y = input.target_y; + } +} + +bool CHARACTER::increase_health(int amount) +{ + if(health >= 10) + return false; + health = clamp(health+amount, 0, 10); + return true; +} + +bool CHARACTER::increase_armor(int amount) +{ + if(armor >= 10) + return false; + armor = clamp(armor+amount, 0, 10); + return true; +} + +void CHARACTER::die(int killer, int weapon) +{ + /*if (dead || team == -1) + return;*/ + int mode_special = game.controller->on_character_death(this, &game.players[killer], weapon); + + dbg_msg("game", "kill killer='%d:%s' victim='%d:%s' weapon=%d special=%d", + killer, server_clientname(killer), + player->client_id, server_clientname(player->client_id), weapon, mode_special); + + // send the kill message + NETMSG_SV_KILLMSG msg; + msg.killer = killer; + msg.victim = player->client_id; + msg.weapon = weapon; + msg.mode_special = mode_special; + msg.pack(MSGFLAG_VITAL); + server_send_msg(-1); + + // a nice sound + game.create_sound(pos, SOUND_PLAYER_DIE); + + // set dead state + // TODO: do stuff here + /* + die_pos = pos; + dead = true; + die_tick = server_tick(); + */ + alive = false; + game.world.remove_entity(this); + game.create_death(pos, player->client_id); +} + +bool CHARACTER::take_damage(vec2 force, int dmg, int from, int weapon) +{ + core.vel += force; + + if(game.controller->is_friendly_fire(player->client_id, from) && !config.sv_teamdamage) + return false; + + // player only inflicts half damage on self + if(from == player->client_id) + dmg = max(1, dmg/2); + + // CTF and TDM (TODO: check for FF) + //if (gameobj->gametype != GAMETYPE_DM && from >= 0 && players[from].team == team) + //return false; + + damage_taken++; + + // create healthmod indicator + if(server_tick() < damage_taken_tick+25) + { + // make sure that the damage indicators doesn't group together + game.create_damageind(pos, damage_taken*0.25f, dmg); + } + else + { + damage_taken = 0; + game.create_damageind(pos, 0, dmg); + } + + if(dmg) + { + if(armor) + { + if(dmg > 1) + { + health--; + dmg--; + } + + if(dmg > armor) + { + dmg -= armor; + armor = 0; + } + else + { + armor -= dmg; + dmg = 0; + } + } + + health -= dmg; + } + + damage_taken_tick = server_tick(); + + // do damage hit sound + if(from >= 0 && from != player->client_id) + game.create_sound(game.players[from].view_pos, SOUND_HIT, cmask_one(from)); + + // check for death + if(health <= 0) + { + die(from, weapon); + + // set attacker's face to happy (taunt!) + if (from >= 0 && from != player->client_id) + { + CHARACTER *chr = &game.players[from].character; + chr->emote_type = EMOTE_HAPPY; + chr->emote_stop = server_tick() + server_tickspeed(); + } + + return false; + } + + if (dmg > 2) + game.create_sound(pos, SOUND_PLAYER_PAIN_LONG); + else + game.create_sound(pos, SOUND_PLAYER_PAIN_SHORT); + + emote_type = EMOTE_PAIN; + emote_stop = server_tick() + 500 * server_tickspeed() / 1000; + + // spawn blood? + return true; +} + +void CHARACTER::snap(int snaping_client) +{ + if(distance(game.players[snaping_client].view_pos, pos) > 1000.0f) + return; + + NETOBJ_CHARACTER *character = (NETOBJ_CHARACTER *)snap_new_item(NETOBJTYPE_CHARACTER, player->client_id, sizeof(NETOBJ_CHARACTER)); + + core.write(character); + + // this is to make sure that players that are just standing still + // isn't sent. this is because the physics keep bouncing between + // 0-128 when just standing. + // TODO: fix the physics so this isn't needed + if(snaping_client != player->client_id && abs(character->vy) < 256.0f) + character->vy = 0; + + if (emote_stop < server_tick()) + { + emote_type = EMOTE_NORMAL; + emote_stop = -1; + } + + character->emote = emote_type; + + character->ammocount = 0; + character->health = 0; + character->armor = 0; + + character->weapon = active_weapon; + character->attacktick = attack_tick; + + character->wanted_direction = input.direction; + /* + if(input.left && !input.right) + character->wanted_direction = -1; + else if(!input.left && input.right) + character->wanted_direction = 1;*/ + + + if(player->client_id == snaping_client) + { + character->health = health; + character->armor = armor; + if(weapons[active_weapon].ammo > 0) + character->ammocount = weapons[active_weapon].ammo; + } + + if (character->emote == EMOTE_NORMAL) + { + if(250 - ((server_tick() - last_action)%(250)) < 5) + character->emote = EMOTE_BLINK; + } + + character->player_state = player_state; +} + +PLAYER::PLAYER() +{ +} + +void PLAYER::init(int client_id) +{ + // clear everything + mem_zero(this, sizeof(*this)); + new(this) PLAYER(); + this->client_id = client_id; +} + +void PLAYER::tick() +{ + server_setclientscore(client_id, score); + + // do latency stuff + { + CLIENT_INFO info; + if(server_getclientinfo(client_id, &info)) + { + latency.accum += info.latency; + latency.accum_max = max(latency.accum_max, info.latency); + latency.accum_min = min(latency.accum_min, info.latency); + } + + if(server_tick()%server_tickspeed() == 0) + { + latency.avg = latency.accum/server_tickspeed(); + latency.max = latency.accum_max; + latency.min = latency.accum_min; + latency.accum = 0; + latency.accum_min = 1000; + latency.accum_max = 0; + } + } + + if(spawning && !get_character()) + try_respawn(); + + if(get_character()) + view_pos = get_character()->pos; +} + +void PLAYER::snap(int snaping_client) +{ + 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->cid = client_id; + info->score = score; + info->team = team; + + if(client_id == snaping_client) + info->local = 1; +} + +void PLAYER::on_disconnect() +{ + kill_character(); + + //game.controller->on_player_death(&game.players[client_id], 0, -1); + + char buf[512]; + str_format(buf, sizeof(buf), "%s has left the game", server_clientname(client_id)); + game.send_chat(-1, CHAT_ALL, buf); + + dbg_msg("game", "leave player='%d:%s'", client_id, server_clientname(client_id)); + + // clear this whole structure + init(-1); + + /*game.world.remove_entity(&game.players[client_id]); + game.world.core.players[client_id] = 0x0; + game.players[client_id].client_id = -1; */ +} + +void PLAYER::on_predicted_input(NETOBJ_PLAYER_INPUT *new_input) +{ + CHARACTER *chr = get_character(); + if(chr) + chr->on_predicted_input(new_input); +} + +void PLAYER::on_direct_input(NETOBJ_PLAYER_INPUT *new_input) +{ + CHARACTER *chr = get_character(); + if(chr) + chr->on_direct_input(new_input); + + if(!chr && team >= 0 && (new_input->fire&1)) + { + spawning = true; + dbg_msg("", "I wanna spawn"); + } +} + +CHARACTER *PLAYER::get_character() +{ + if(character.alive) + return &character; + return 0; +} + +void PLAYER::kill_character() +{ + CHARACTER *chr = get_character(); + if(chr) + chr->die(-1, -1); +} + +void PLAYER::respawn() +{ + spawning = true; +} + +void PLAYER::set_team(int new_team) +{ + // clamp the team + new_team = game.controller->clampteam(new_team); + if(team == new_team) + return; + + char buf[512]; + str_format(buf, sizeof(buf), "%s joined the %s", server_clientname(client_id), game.controller->get_team_name(new_team)); + game.send_chat(-1, CHAT_ALL, buf); + + kill_character(); + team = new_team; + score = 0; + dbg_msg("game", "team_join player='%d:%s' team=%d", client_id, server_clientname(client_id), team); + + game.controller->on_player_info_change(&game.players[client_id]); + + // send all info to this client + for(int i = 0; i < MAX_CLIENTS; i++) + { + if(game.players[i].client_id != -1) + game.send_info(i, -1); + } +} + +vec2 spawn_points[3][64]; +int num_spawn_points[3] = {0}; + +struct SPAWNEVAL +{ + SPAWNEVAL() + { + got = false; + friendly_team = -1; +// die_pos = vec2(0,0); + pos = vec2(100,100); + } + + vec2 pos; + bool got; + int friendly_team; + float score; +// vec2 die_pos; +}; + +static float evaluate_spawn(SPAWNEVAL *eval, vec2 pos) +{ + float score = 0.0f; + CHARACTER *c = (CHARACTER *)game.world.find_first(NETOBJTYPE_CHARACTER); + for(; c; c = (CHARACTER *)c->typenext()) + { + // team mates are not as dangerous as enemies + float scoremod = 1.0f; + if(eval->friendly_team != -1 && c->team == eval->friendly_team) + scoremod = 0.5f; + + float d = distance(pos, c->pos); + if(d == 0) + score += 1000000000.0f; + else + score += 1.0f/d; + } + + // weight in the die posititon + /* + float d = distance(pos, eval->die_pos); + if(d == 0) + score += 1000000000.0f; + else + score += 1.0f/d;*/ + + return score; +} + +static void evaluate_spawn_type(SPAWNEVAL *eval, int t) +{ + // get spawn point + /* + int start, num; + map_get_type(t, &start, &num); + if(!num) + return; + */ + for(int i = 0; i < num_spawn_points[t]; i++) + { + //num_spawn_points[t] + //mapres_spawnpoint *sp = (mapres_spawnpoint*)map_get_item(start + i, NULL, NULL); + vec2 p = spawn_points[t][i];// vec2((float)sp->x, (float)sp->y); + float s = evaluate_spawn(eval, p); + if(!eval->got || eval->score > s) + { + eval->got = true; + eval->score = s; + eval->pos = p; + } + } +} + +void PLAYER::try_respawn() +{ + vec2 spawnpos = vec2(100.0f, -60.0f); + + // get spawn point + SPAWNEVAL eval; + //eval.die_pos = die_pos; + + eval.pos = vec2(100, 100); + + if(game.controller->gametype == GAMETYPE_CTF) + { + eval.friendly_team = team; + + // try first try own team spawn, then normal spawn and then enemy + evaluate_spawn_type(&eval, 1+(team&1)); + if(!eval.got) + { + evaluate_spawn_type(&eval, 0); + if(!eval.got) + evaluate_spawn_type(&eval, 1+((team+1)&1)); + } + } + else + { + if(game.controller->gametype == GAMETYPE_TDM) + eval.friendly_team = team; + + evaluate_spawn_type(&eval, 0); + evaluate_spawn_type(&eval, 1); + evaluate_spawn_type(&eval, 2); + } + + spawnpos = eval.pos; + + // check if the position is occupado + ENTITY *ents[2] = {0}; + int num_ents = game.world.find_entities(spawnpos, 64, ents, 2, NETOBJTYPE_CHARACTER); + + if(num_ents == 0) + { + spawning = false; + character.spawn(this, spawnpos, team); + } + + /* + pos = spawnpos; + + core.pos = pos; + core.vel = vec2(0,0); + core.hooked_player = -1; + + health = 10; + armor = 0; + jumped = 0; + + mem_zero(&ninja, sizeof(ninja)); + + dead = false; + player_state = PLAYERSTATE_PLAYING; + + game.world.insert_entity(this); + + core.hook_state = HOOK_IDLE; + + mem_zero(&input, sizeof(input)); + + // init weapons + mem_zero(&weapons, sizeof(weapons)); + weapons[WEAPON_HAMMER].got = true; + weapons[WEAPON_HAMMER].ammo = -1; + weapons[WEAPON_GUN].got = true; + weapons[WEAPON_GUN].ammo = 10; + + active_weapon = WEAPON_GUN; + last_weapon = WEAPON_HAMMER; + queued_weapon = 0; + + reload_timer = 0; + + // Create sound and spawn effects + game.create_sound(pos, SOUND_PLAYER_SPAWN); + game.create_playerspawn(pos); + + game.controller->on_player_spawn(player); + */ +} diff --git a/src/game/server/gs_game.cpp b/src/game/server/gs_game.cpp index 55ffc2881..685d61ad3 100644 --- a/src/game/server/gs_game.cpp +++ b/src/game/server/gs_game.cpp @@ -6,7 +6,6 @@ #include "gs_common.hpp" GAMECONTROLLER::GAMECONTROLLER() -: ENTITY(NETOBJTYPE_GAME) { // select gametype if(strcmp(config.sv_gametype, "ctf") == 0) @@ -91,14 +90,32 @@ void GAMECONTROLLER::endround() if(warmup) // game can't end when we are running warmup return; - world->paused = true; + game.world.paused = true; game_over_tick = server_tick(); sudden_death = 0; } void GAMECONTROLLER::resetgame() { - world->reset_requested = true; + game.world.reset_requested = true; +} + +const char *GAMECONTROLLER::get_team_name(int team) +{ + if(is_teamplay) + { + if(team == 0) + return "red team"; + else if(team == 1) + return "blue team"; + } + else + { + if(team == 0) + return "game"; + } + + return "spectators"; } static bool is_separator(char c) { return c == ';' || c == ' ' || c == ',' || c == '\t'; } @@ -110,7 +127,7 @@ void GAMECONTROLLER::startround() round_start_tick = server_tick(); sudden_death = 0; game_over_tick = -1; - world->paused = false; + game.world.paused = false; teamscore[0] = 0; teamscore[1] = 0; round_count++; @@ -178,8 +195,8 @@ void GAMECONTROLLER::post_reset() { for(int i = 0; i < MAX_CLIENTS; i++) { - if(players[i].client_id != -1) - players[i].respawn(); + if(game.players[i].client_id != -1) + game.players[i].respawn(); } } @@ -198,13 +215,13 @@ void GAMECONTROLLER::on_player_info_change(class PLAYER *p) } -int GAMECONTROLLER::on_player_death(class PLAYER *victim, class PLAYER *killer, int weapon) +int GAMECONTROLLER::on_character_death(class CHARACTER *victim, class PLAYER *killer, int weapon) { // do scoreing if(!killer) return 0; - if(killer == victim) - victim->score--; // suicide + if(killer == victim->player) + victim->player->score--; // suicide else { if(is_teamplay && victim->team == killer->team) @@ -227,7 +244,7 @@ bool GAMECONTROLLER::is_friendly_fire(int cid1, int cid2) if(is_teamplay) { - if(players[cid1].team == players[cid2].team) + if(game.players[cid1].team == game.players[cid2].team) return true; } @@ -271,8 +288,8 @@ void GAMECONTROLLER::tick() { for(int i = 0; i < MAX_CLIENTS; i++) { - if(players[i].client_id != -1) - prog = max(prog, (players[i].score*100)/config.sv_scorelimit); + if(game.players[i].client_id != -1) + prog = max(prog, (game.players[i].score*100)/config.sv_scorelimit); } } } @@ -285,20 +302,20 @@ void GAMECONTROLLER::tick() void GAMECONTROLLER::snap(int snapping_client) { - 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; + NETOBJ_GAME *gameobj = (NETOBJ_GAME *)snap_new_item(NETOBJTYPE_GAME, 0, sizeof(NETOBJ_GAME)); + gameobj->paused = game.world.paused; + gameobj->game_over = game_over_tick==-1?0:1; + gameobj->sudden_death = sudden_death; - game->score_limit = config.sv_scorelimit; - game->time_limit = config.sv_timelimit; - game->round_start_tick = round_start_tick; - game->gametype = gametype; + gameobj->score_limit = config.sv_scorelimit; + gameobj->time_limit = config.sv_timelimit; + gameobj->round_start_tick = round_start_tick; + gameobj->gametype = gametype; - game->warmup = warmup; + gameobj->warmup = warmup; - game->teamscore_red = teamscore[0]; - game->teamscore_blue = teamscore[1]; + gameobj->teamscore_red = teamscore[0]; + gameobj->teamscore_blue = teamscore[1]; } int GAMECONTROLLER::get_auto_team(int notthisid) @@ -306,10 +323,10 @@ int GAMECONTROLLER::get_auto_team(int notthisid) int numplayers[2] = {0,0}; for(int i = 0; i < MAX_CLIENTS; i++) { - if(players[i].client_id != -1 && players[i].client_id != notthisid) + if(game.players[i].client_id != -1 && game.players[i].client_id != notthisid) { - if(players[i].team == 0 || players[i].team == 1) - numplayers[players[i].team]++; + if(game.players[i].team == 0 || game.players[i].team == 1) + numplayers[game.players[i].team]++; } } @@ -328,10 +345,10 @@ bool GAMECONTROLLER::can_join_team(int team, int notthisid) int numplayers[2] = {0,0}; for(int i = 0; i < MAX_CLIENTS; i++) { - if(players[i].client_id != -1 && players[i].client_id != notthisid) + if(game.players[i].client_id != -1 && game.players[i].client_id != notthisid) { - if(players[i].team >= 0 || players[i].team == 1) - numplayers[players[i].team]++; + if(game.players[i].team >= 0 || game.players[i].team == 1) + numplayers[game.players[i].team]++; } } @@ -347,14 +364,14 @@ void GAMECONTROLLER::do_player_score_wincheck() int topscore_count = 0; for(int i = 0; i < MAX_CLIENTS; i++) { - if(players[i].client_id != -1) + if(game.players[i].client_id != -1) { - if(players[i].score > topscore) + if(game.players[i].score > topscore) { - topscore = players[i].score; + topscore = game.players[i].score; topscore_count = 1; } - else if(players[i].score == topscore) + else if(game.players[i].score == topscore) topscore_count++; } } diff --git a/src/game/server/gs_game_ctf.cpp b/src/game/server/gs_game_ctf.cpp index 031be42a1..27da121aa 100644 --- a/src/game/server/gs_game_ctf.cpp +++ b/src/game/server/gs_game_ctf.cpp @@ -29,26 +29,22 @@ bool GAMECONTROLLER_CTF::on_entity(int index, vec2 pos) return true; } -void GAMECONTROLLER_CTF::on_player_spawn(class PLAYER *p) +int GAMECONTROLLER_CTF::on_character_death(class CHARACTER *victim, class PLAYER *killer, int weaponid) { -} - -int GAMECONTROLLER_CTF::on_player_death(class PLAYER *victim, class PLAYER *killer, int weaponid) -{ - GAMECONTROLLER::on_player_death(victim, killer, weaponid); + GAMECONTROLLER::on_character_death(victim, killer, weaponid); int had_flag = 0; // drop flags for(int fi = 0; fi < 2; fi++) { FLAG *f = flags[fi]; - if(f && f->carrying_player == killer) + if(f && f->carrying_character == &killer->character) had_flag |= 2; - if(f && f->carrying_player == victim) + if(f && f->carrying_character == victim) { - create_sound_global(SOUND_CTF_DROP); + game.create_sound_global(SOUND_CTF_DROP); f->drop_tick = server_tick(); - f->carrying_player = 0; + f->carrying_character = 0; f->vel = vec2(0,0); if(killer && killer->team != victim->team) @@ -75,10 +71,10 @@ void GAMECONTROLLER_CTF::tick() continue; // - if(f->carrying_player) + if(f->carrying_character) { // update flag position - f->pos = f->carrying_player->pos; + f->pos = f->carrying_character->pos; if(flags[fi^1] && flags[fi^1]->at_stand) { @@ -86,35 +82,38 @@ void GAMECONTROLLER_CTF::tick() { // CAPTURE! \o/ teamscore[fi^1] += 100; - f->carrying_player->score += 5; + f->carrying_character->player->score += 5; - dbg_msg("game", "flag_capture player='%d:%s'", f->carrying_player->client_id, server_clientname(f->carrying_player->client_id)); + dbg_msg("game", "flag_capture player='%d:%s'", + f->carrying_character->player->client_id, + server_clientname(f->carrying_character->player->client_id)); for(int i = 0; i < 2; i++) flags[i]->reset(); - create_sound_global(SOUND_CTF_CAPTURE); + game.create_sound_global(SOUND_CTF_CAPTURE); } } } else { - PLAYER *close_players[MAX_CLIENTS]; - int types[] = {NETOBJTYPE_PLAYER_CHARACTER}; - int num = world->find_entities(f->pos, 32.0f, (ENTITY**)close_players, MAX_CLIENTS, types, 1); + CHARACTER *close_characters[MAX_CLIENTS]; + int num = game.world.find_entities(f->pos, 32.0f, (ENTITY**)close_characters, MAX_CLIENTS, NETOBJTYPE_CHARACTER); for(int i = 0; i < num; i++) { - if(close_players[i]->team == f->team) + if(close_characters[i]->team == f->team) { // return the flag if(!f->at_stand) { - PLAYER *p = close_players[i]; - p->score += 1; + CHARACTER *chr = close_characters[i]; + chr->player->score += 1; - dbg_msg("game", "flag_return player='%d:%s'", p->client_id, server_clientname(p->client_id)); + dbg_msg("game", "flag_return player='%d:%s'", + chr->player->client_id, + server_clientname(chr->player->client_id)); - create_sound_global(SOUND_CTF_RETURN); + game.create_sound_global(SOUND_CTF_RETURN); f->reset(); } } @@ -124,35 +123,37 @@ void GAMECONTROLLER_CTF::tick() if(f->at_stand) teamscore[fi^1]++; f->at_stand = 0; - f->carrying_player = close_players[i]; - f->carrying_player->score += 1; + f->carrying_character = close_characters[i]; + f->carrying_character->player->score += 1; - dbg_msg("game", "flag_grab player='%d:%s'", f->carrying_player->client_id, server_clientname(f->carrying_player->client_id)); + dbg_msg("game", "flag_grab player='%d:%s'", + f->carrying_character->player->client_id, + server_clientname(f->carrying_character->player->client_id)); for(int c = 0; c < MAX_CLIENTS; c++) { - if(players[c].client_id == -1) + if(game.players[c].client_id == -1) continue; - if(players[c].team == fi) - create_sound_global(SOUND_CTF_GRAB_EN, players[c].client_id); + if(game.players[c].team == fi) + game.create_sound_global(SOUND_CTF_GRAB_EN, game.players[c].client_id); else - create_sound_global(SOUND_CTF_GRAB_PL, players[c].client_id); + game.create_sound_global(SOUND_CTF_GRAB_PL, game.players[c].client_id); } break; } } - if(!f->carrying_player && !f->at_stand) + if(!f->carrying_character && !f->at_stand) { if(server_tick() > f->drop_tick + server_tickspeed()*30) { - create_sound_global(SOUND_CTF_RETURN); + game.create_sound_global(SOUND_CTF_RETURN); f->reset(); } else { - f->vel.y += world->core.tuning.gravity; + f->vel.y += game.world.core.tuning.gravity; move_box(&f->pos, &f->vel, vec2(f->phys_size, f->phys_size), 0.5f); } } @@ -166,17 +167,17 @@ FLAG::FLAG(int _team) { team = _team; proximity_radius = phys_size; - carrying_player = 0x0; + carrying_character = 0x0; reset(); // TODO: should this be done here? - world->insert_entity(this); + game.world.insert_entity(this); } void FLAG::reset() { - carrying_player = 0; + carrying_character = 0; at_stand = 1; pos = stand_pos; vel = vec2(0,0); @@ -192,6 +193,6 @@ void FLAG::snap(int snapping_client) if(at_stand) flag->carried_by = -2; - else if(carrying_player) - flag->carried_by = carrying_player->client_id; + else if(carrying_character) + flag->carried_by = carrying_character->player->client_id; } diff --git a/src/game/server/gs_game_ctf.hpp b/src/game/server/gs_game_ctf.hpp index 6d5128156..bf6282e7b 100644 --- a/src/game/server/gs_game_ctf.hpp +++ b/src/game/server/gs_game_ctf.hpp @@ -10,9 +10,7 @@ public: virtual void tick(); virtual bool on_entity(int index, vec2 pos); - - virtual void on_player_spawn(class PLAYER *p); - virtual int on_player_death(class PLAYER *victim, class PLAYER *killer, int weapon); + virtual int on_character_death(class CHARACTER *victim, class PLAYER *killer, int weapon); }; // TODO: move to seperate file @@ -20,7 +18,7 @@ class FLAG : public ENTITY { public: static const int phys_size = 14; - PLAYER *carrying_player; + CHARACTER *carrying_character; vec2 vel; vec2 stand_pos; diff --git a/src/game/server/gs_game_tdm.cpp b/src/game/server/gs_game_tdm.cpp index c591b447a..d865a65ab 100644 --- a/src/game/server/gs_game_tdm.cpp +++ b/src/game/server/gs_game_tdm.cpp @@ -8,14 +8,14 @@ GAMECONTROLLER_TDM::GAMECONTROLLER_TDM() is_teamplay = true; } -int GAMECONTROLLER_TDM::on_player_death(class PLAYER *victim, class PLAYER *killer, int weapon) +int GAMECONTROLLER_TDM::on_character_death(class CHARACTER *victim, class PLAYER *killer, int weapon) { - GAMECONTROLLER::on_player_death(victim, killer, weapon); + GAMECONTROLLER::on_character_death(victim, killer, weapon); if(weapon >= 0) { // do team scoring - if(killer == victim) + if(killer == victim->player) teamscore[killer->team&1]--; // klant arschel else teamscore[killer->team&1]++; // good shit diff --git a/src/game/server/gs_game_tdm.hpp b/src/game/server/gs_game_tdm.hpp index 516b581cf..bb35260ca 100644 --- a/src/game/server/gs_game_tdm.hpp +++ b/src/game/server/gs_game_tdm.hpp @@ -5,6 +5,6 @@ class GAMECONTROLLER_TDM : public GAMECONTROLLER public: GAMECONTROLLER_TDM(); - int on_player_death(class PLAYER *victim, class PLAYER *killer, int weapon); + int on_character_death(class CHARACTER *victim, class PLAYER *killer, int weapon); virtual void tick(); }; diff --git a/src/game/server/gs_server.cpp b/src/game/server/gs_server.cpp index 4e7b4179c..5f5662d05 100644 --- a/src/game/server/gs_server.cpp +++ b/src/game/server/gs_server.cpp @@ -14,32 +14,12 @@ #include "gs_game_dm.hpp" TUNING_PARAMS tuning; +GAMECONTEXT game; -void create_damageind(vec2 p, float angle_mod, int amount); -void create_explosion(vec2 p, int owner, int weapon, bool bnodamage); -void create_smoke(vec2 p); -void create_playerspawn(vec2 p); -void create_death(vec2 p, int who); -void create_sound(vec2 pos, int sound, int mask=-1); - -PLAYER *get_player(int index); -class PLAYER *intersect_player(vec2 pos0, vec2 pos1, float radius, vec2 &new_pos, class ENTITY *notthis = 0); -class PLAYER *closest_player(vec2 pos, float radius, ENTITY *notthis); - -GAMEWORLD *world; - -enum +void GAMECONTEXT::send_chat(int chatter_cid, int team, const char *text) { - CHAT_ALL=-2, - CHAT_SPEC=-1, - CHAT_RED=0, - CHAT_BLUE=1 -}; - -static void send_chat(int cid, int team, const char *text) -{ - if(cid >= 0 && cid < MAX_CLIENTS) - dbg_msg("chat", "%d:%d:%s: %s", cid, team, server_clientname(cid), text); + if(chatter_cid >= 0 && chatter_cid < MAX_CLIENTS) + dbg_msg("chat", "%d:%d:%s: %s", chatter_cid, team, server_clientname(chatter_cid), text); else dbg_msg("chat", "*** %s", text); @@ -47,7 +27,7 @@ static void send_chat(int cid, int team, const char *text) { NETMSG_SV_CHAT msg; msg.team = 0; - msg.cid = cid; + msg.cid = chatter_cid; msg.message = text; msg.pack(MSGFLAG_VITAL); server_send_msg(-1); @@ -56,20 +36,20 @@ static void send_chat(int cid, int team, const char *text) { NETMSG_SV_CHAT msg; msg.team = 1; - msg.cid = cid; + msg.cid = chatter_cid; msg.message = text; msg.pack(MSGFLAG_VITAL); for(int i = 0; i < MAX_CLIENTS; i++) { - if(players[i].client_id != -1 && players[i].team == team) + if(game.players[i].client_id != -1 && game.players[i].team == team) server_send_msg(i); } } } -void send_info(int who, int to_who) +void GAMECONTEXT::send_info(int who, int to_who) { NETMSG_SV_SETINFO msg; msg.cid = who; @@ -77,13 +57,13 @@ void send_info(int who, int to_who) msg.skin = players[who].skin_name; msg.use_custom_color = players[who].use_custom_color; msg.color_body = players[who].color_body; - msg.color_feet =players[who].color_feet; + msg.color_feet = players[who].color_feet; msg.pack(MSGFLAG_VITAL); server_send_msg(to_who); } -void send_emoticon(int cid, int emoticon) +void GAMECONTEXT::send_emoticon(int cid, int emoticon) { NETMSG_SV_EMOTICON msg; msg.cid = cid; @@ -92,7 +72,7 @@ void send_emoticon(int cid, int emoticon) server_send_msg(-1); } -void send_weapon_pickup(int cid, int weapon) +void GAMECONTEXT::send_weapon_pickup(int cid, int weapon) { NETMSG_SV_WEAPONPICKUP msg; msg.weapon = weapon; @@ -101,7 +81,7 @@ void send_weapon_pickup(int cid, int weapon) } -void send_broadcast(const char *text, int cid) +void GAMECONTEXT::send_broadcast(const char *text, int cid) { NETMSG_SV_BROADCAST msg; msg.message = text; @@ -159,7 +139,7 @@ void EVENT_HANDLER::snap(int snapping_client) if(cmask_is_set(client_masks[i], snapping_client)) { NETEVENT_COMMON *ev = (NETEVENT_COMMON *)&data[offsets[i]]; - if(distance(players[snapping_client].pos, vec2(ev->x, ev->y)) < 1500.0f) + if(distance(game.players[snapping_client].view_pos, vec2(ev->x, ev->y)) < 1500.0f) { void *d = snap_new_item(types[i], i, sizes[i]); mem_copy(d, &data[offsets[i]], sizes[i]); @@ -168,8 +148,6 @@ void EVENT_HANDLER::snap(int snapping_client) } } -EVENT_HANDLER events; - ////////////////////////////////////////////////// // Entity ////////////////////////////////////////////////// @@ -177,9 +155,9 @@ ENTITY::ENTITY(int objtype) { this->objtype = objtype; pos = vec2(0,0); - flags = FLAG_PHYSICS; proximity_radius = 0; + marked_for_destroy = false; id = snap_new_id(); next_entity = 0; @@ -190,7 +168,7 @@ ENTITY::ENTITY(int objtype) ENTITY::~ENTITY() { - world->remove_entity(this); + game.world.remove_entity(this); snap_free_id(id); } @@ -213,14 +191,18 @@ GAMEWORLD::~GAMEWORLD() delete first_entity; } -int GAMEWORLD::find_entities(vec2 pos, float radius, ENTITY **ents, int max) +ENTITY *GAMEWORLD::find_first(int type) +{ + return first_entity_types[type]; +} + + +int GAMEWORLD::find_entities(vec2 pos, float radius, ENTITY **ents, int max, int type) { int num = 0; - for(ENTITY *ent = first_entity; ent; ent = ent->next_entity) + for(ENTITY *ent = (type<0) ? first_entity : first_entity_types[type]; + ent; ent = (type<0) ? ent->next_entity : ent->next_type_entity) { - if(!(ent->flags&ENTITY::FLAG_PHYSICS)) - continue; - if(distance(ent->pos, pos) < radius+ent->proximity_radius) { ents[num] = ent; @@ -233,29 +215,6 @@ int GAMEWORLD::find_entities(vec2 pos, float radius, ENTITY **ents, int max) return num; } -int GAMEWORLD::find_entities(vec2 pos, float radius, ENTITY **ents, int max, const int* types, int maxtypes) -{ - int num = 0; - for(int t = 0; t < maxtypes; t++) - { - for(ENTITY *ent = first_entity_types[types[t]]; ent; ent = ent->next_type_entity) - { - if(!(ent->flags&ENTITY::FLAG_PHYSICS)) - continue; - - if(distance(ent->pos, pos) < radius+ent->proximity_radius) - { - ents[num] = ent; - num++; - if(num == max) - break; - } - } - } - - return num; -} - void GAMEWORLD::insert_entity(ENTITY *ent) { ENTITY *cur = first_entity; @@ -282,7 +241,7 @@ void GAMEWORLD::insert_entity(ENTITY *ent) void GAMEWORLD::destroy_entity(ENTITY *ent) { - ent->set_flag(ENTITY::FLAG_DESTROY); + ent->marked_for_destroy = true; } void GAMEWORLD::remove_entity(ENTITY *ent) @@ -326,8 +285,7 @@ void GAMEWORLD::reset() ent->reset(); remove_entities(); - for(ENTITY *ent = first_entity; ent; ent = ent->next_entity) - ent->post_reset(); + game.controller->post_reset(); remove_entities(); reset_requested = false; @@ -340,7 +298,7 @@ void GAMEWORLD::remove_entities() while(ent) { ENTITY *next = ent->next_entity; - if(ent->flags&ENTITY::FLAG_DESTROY) + if(ent->marked_for_destroy) { remove_entity(ent); ent->destroy(); @@ -356,86 +314,17 @@ void GAMEWORLD::tick() if(!paused) { - /* - static PERFORMACE_INFO scopes[OBJTYPE_FLAG+1] = - { - {"null", 0}, - {"game", 0}, - {"player_info", 0}, - {"player_character", 0}, - {"projectile", 0}, - {"powerup", 0}, - {"flag", 0} - }; - - static PERFORMACE_INFO scopes_def[OBJTYPE_FLAG+1] = - { - {"null", 0}, - {"game", 0}, - {"player_info", 0}, - {"player_character", 0}, - {"projectile", 0}, - {"powerup", 0}, - {"flag", 0} - }; - - static PERFORMACE_INFO tick_scope = {"tick", 0}; - 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]);*/ ent->tick(); - /*if(ent->objtype >= 0 && ent->objtype < OBJTYPE_FLAG) - perf_end();*/ - } - /* - perf_end(); - - static PERFORMACE_INFO deftick_scope = {"tick_defered", 0}; - 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]);*/ ent->tick_defered(); - /*if(ent->objtype >= 0 && ent->objtype < OBJTYPE_FLAG) - perf_end();*/ - } - /*perf_end();*/ } remove_entities(); } -struct INPUT_COUNT -{ - int presses; - int releases; -}; - -static INPUT_COUNT count_input(int prev, int cur) -{ - INPUT_COUNT c = {0,0}; - prev &= INPUT_STATE_MASK; - cur &= INPUT_STATE_MASK; - int i = prev; - while(i != cur) - { - i = (i+1)&INPUT_STATE_MASK; - if(i&1) - c.presses++; - else - c.releases++; - } - - return c; -} - - ////////////////////////////////////////////////// // projectile ////////////////////////////////////////////////// @@ -456,12 +345,12 @@ PROJECTILE::PROJECTILE(int type, int owner, vec2 pos, vec2 dir, int span, ENTITY this->weapon = weapon; this->bounce = 0; this->start_tick = server_tick(); - world->insert_entity(this); + game.world.insert_entity(this); } void PROJECTILE::reset() { - world->destroy_entity(this); + game.world.destroy_entity(this); } vec2 PROJECTILE::get_pos(float time) @@ -501,20 +390,20 @@ void PROJECTILE::tick() int collide = col_intersect_line(prevpos, curpos, &curpos); //int collide = col_check_point((int)curpos.x, (int)curpos.y); - ENTITY *targetplayer = (ENTITY*)intersect_player(prevpos, curpos, 6.0f, curpos, powner); - if(targetplayer || collide || lifespan < 0) + CHARACTER *targetchr = game.world.intersect_character(prevpos, curpos, 6.0f, curpos, powner); + if(targetchr || collide || lifespan < 0) { - if (lifespan >= 0 || weapon == WEAPON_GRENADE) - create_sound(curpos, sound_impact); + if(lifespan >= 0 || weapon == WEAPON_GRENADE) + game.create_sound(curpos, sound_impact); - if (flags & PROJECTILE_FLAGS_EXPLODE) - create_explosion(curpos, owner, weapon, false); - else if (targetplayer) + if(flags & PROJECTILE_FLAGS_EXPLODE) + game.create_explosion(curpos, owner, weapon, false); + else if(targetchr) { - targetplayer->take_damage(direction * max(0.001f, force), damage, owner, weapon); + targetchr->take_damage(direction * max(0.001f, force), damage, owner, weapon); } - world->destroy_entity(this); + game.world.destroy_entity(this); } } @@ -532,7 +421,7 @@ void PROJECTILE::snap(int snapping_client) { float ct = (server_tick()-start_tick)/(float)server_tickspeed(); - if(distance(players[snapping_client].pos, get_pos(ct)) > 1000.0f) + if(distance(game.players[snapping_client].view_pos, get_pos(ct)) > 1000.0f) return; NETOBJ_PROJECTILE *proj = (NETOBJ_PROJECTILE *)snap_new_item(NETOBJTYPE_PROJECTILE, id, sizeof(NETOBJ_PROJECTILE)); @@ -543,7 +432,7 @@ void PROJECTILE::snap(int snapping_client) ////////////////////////////////////////////////// // laser ////////////////////////////////////////////////// -LASER::LASER(vec2 pos, vec2 direction, float start_energy, PLAYER *owner) +LASER::LASER(vec2 pos, vec2 direction, float start_energy, CHARACTER *owner) : ENTITY(NETOBJTYPE_LASER) { this->pos = pos; @@ -553,21 +442,21 @@ LASER::LASER(vec2 pos, vec2 direction, float start_energy, PLAYER *owner) bounces = 0; do_bounce(); - world->insert_entity(this); + game.world.insert_entity(this); } -bool LASER::hit_player(vec2 from, vec2 to) +bool LASER::hit_character(vec2 from, vec2 to) { vec2 at; - PLAYER *hit = intersect_player(pos, to, 0.0f, at, owner); + CHARACTER *hit = game.world.intersect_character(pos, to, 0.0f, at, owner); if(!hit) return false; this->from = from; pos = at; energy = -1; - hit->take_damage(vec2(0,0), tuning.laser_damage, owner->client_id, WEAPON_RIFLE); + hit->take_damage(vec2(0,0), tuning.laser_damage, owner->player->client_id, WEAPON_RIFLE); return true; } @@ -578,7 +467,7 @@ void LASER::do_bounce() if(energy < 0) { //dbg_msg("laser", "%d removed", server_tick()); - world->destroy_entity(this); + game.world.destroy_entity(this); return; } @@ -586,7 +475,7 @@ void LASER::do_bounce() if(col_intersect_line(pos, to, &to)) { - if(!hit_player(pos, to)) + if(!hit_character(pos, to)) { // intersected from = pos; @@ -604,12 +493,12 @@ void LASER::do_bounce() if(bounces > tuning.laser_bounce_num) energy = -1; - create_sound(pos, SOUND_RIFLE_BOUNCE); + game.create_sound(pos, SOUND_RIFLE_BOUNCE); } } else { - if(!hit_player(pos, to)) + if(!hit_character(pos, to)) { from = pos; pos = to; @@ -622,7 +511,7 @@ void LASER::do_bounce() void LASER::reset() { - world->destroy_entity(this); + game.world.destroy_entity(this); } void LASER::tick() @@ -636,7 +525,7 @@ void LASER::tick() void LASER::snap(int snapping_client) { - if(distance(players[snapping_client].pos, pos) > 1000.0f) + if(distance(game.players[snapping_client].view_pos, pos) > 1000.0f) return; NETOBJ_LASER *obj = (NETOBJ_LASER *)snap_new_item(NETOBJTYPE_LASER, id, sizeof(NETOBJ_LASER)); @@ -647,1193 +536,20 @@ void LASER::snap(int snapping_client) obj->start_tick = eval_tick; } - -////////////////////////////////////////////////// -// player -////////////////////////////////////////////////// -// TODO: move to separate file -PLAYER::PLAYER() -: ENTITY(NETOBJTYPE_PLAYER_CHARACTER) +GAMECONTEXT::GAMECONTEXT() { - init(); + clear(); } -void PLAYER::init() +void GAMECONTEXT::clear() { - proximity_radius = phys_size; - client_id = -1; - team = -1; // -1 == spectator - - latency_accum = 0; - latency_accum_min = 0; - latency_accum_max = 0; - latency_avg = 0; - latency_min = 0; - latency_max = 0; - - reset(); -} - -void PLAYER::reset() -{ - pos = vec2(0.0f, 0.0f); - core.reset(); - - emote_type = 0; - emote_stop = -1; - - //direction = vec2(0.0f, 1.0f); - score = 0; - dead = true; - clear_flag(ENTITY::FLAG_PHYSICS); - spawning = false; - die_tick = 0; - die_pos = vec2(0,0); - damage_taken = 0; - last_chat = 0; - player_state = PLAYERSTATE_UNKNOWN; - - mem_zero(&input, sizeof(input)); - mem_zero(&previnput, sizeof(previnput)); - num_inputs = 0; - - last_action = -1; - - emote_stop = 0; - damage_taken_tick = 0; - attack_tick = 0; - - mem_zero(&ninja, sizeof(ninja)); - - active_weapon = WEAPON_GUN; - last_weapon = WEAPON_HAMMER; - queued_weapon = -1; -} - -void PLAYER::destroy() { } - -void PLAYER::set_weapon(int w) -{ - if(w == active_weapon) - return; - - last_weapon = active_weapon; - queued_weapon = -1; - active_weapon = w; - if(active_weapon < 0 || active_weapon >= NUM_WEAPONS) - active_weapon = 0; - - create_sound(pos, SOUND_WEAPON_SWITCH); -} - -void PLAYER::respawn() -{ - spawning = true; -} - -const char *get_team_name(int team) -{ - if(gamecontroller->gametype == GAMETYPE_DM) - { - if(team == 0) - return "game"; - } - else - { - if(team == 0) - return "red team"; - else if(team == 1) - return "blue team"; - } - - return "spectators"; -} - -void PLAYER::set_team(int new_team) -{ - // clamp the team - new_team = gamecontroller->clampteam(new_team); - if(team == new_team) - return; - - char buf[512]; - str_format(buf, sizeof(buf), "%s joined the %s", server_clientname(client_id), get_team_name(new_team)); - send_chat(-1, CHAT_ALL, buf); - - die(client_id, -1); - team = new_team; - score = 0; - dbg_msg("game", "team_join player='%d:%s' team=%d", client_id, server_clientname(client_id), team); - - gamecontroller->on_player_info_change(&players[client_id]); - - // send all info to this client + // reset all players for(int i = 0; i < MAX_CLIENTS; i++) - { - if(players[i].client_id != -1) - send_info(i, -1); - } -} - -vec2 spawn_points[3][64]; -int num_spawn_points[3] = {0}; - -struct SPAWNEVAL -{ - SPAWNEVAL() - { - got = false; - friendly_team = -1; - die_pos = vec2(0,0); - pos = vec2(100,100); - } - - vec2 pos; - bool got; - int friendly_team; - float score; - vec2 die_pos; -}; - -static float evaluate_spawn(SPAWNEVAL *eval, vec2 pos) -{ - float score = 0.0f; - - for(int c = 0; c < MAX_CLIENTS; c++) - { - if(players[c].client_id == -1) - continue; - - // don't count dead people - if(!(players[c].flags&ENTITY::FLAG_PHYSICS)) - continue; - - // team mates are not as dangerous as enemies - float scoremod = 1.0f; - if(eval->friendly_team != -1 && players[c].team == eval->friendly_team) - scoremod = 0.5f; - - float d = distance(pos, players[c].pos); - if(d == 0) - score += 1000000000.0f; - else - score += 1.0f/d; - } - - // weight in the die posititon - float d = distance(pos, eval->die_pos); - if(d == 0) - score += 1000000000.0f; - else - score += 1.0f/d; - - return score; -} - -static void evaluate_spawn_type(SPAWNEVAL *eval, int t) -{ - // get spawn point - /* - int start, num; - map_get_type(t, &start, &num); - if(!num) - return; - */ - for(int i = 0; i < num_spawn_points[t]; i++) - { - //num_spawn_points[t] - //mapres_spawnpoint *sp = (mapres_spawnpoint*)map_get_item(start + i, NULL, NULL); - vec2 p = spawn_points[t][i];// vec2((float)sp->x, (float)sp->y); - float s = evaluate_spawn(eval, p); - if(!eval->got || eval->score > s) - { - eval->got = true; - eval->score = s; - eval->pos = p; - } - } -} - -void PLAYER::try_respawn() -{ - vec2 spawnpos = vec2(100.0f, -60.0f); - - // get spawn point - SPAWNEVAL eval; - eval.die_pos = die_pos; - - eval.pos = vec2(100, 100); - - if(gamecontroller->gametype == GAMETYPE_CTF) - { - eval.friendly_team = team; - - // try first try own team spawn, then normal spawn and then enemy - evaluate_spawn_type(&eval, 1+(team&1)); - if(!eval.got) - { - evaluate_spawn_type(&eval, 0); - if(!eval.got) - evaluate_spawn_type(&eval, 1+((team+1)&1)); - } - } - else - { - if(gamecontroller->gametype == GAMETYPE_TDM) - eval.friendly_team = team; - - evaluate_spawn_type(&eval, 0); - evaluate_spawn_type(&eval, 1); - evaluate_spawn_type(&eval, 2); - } - - spawnpos = eval.pos; - - // check if the position is occupado - ENTITY *ents[2] = {0}; - 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++) - { - if(ents[i] != this) - return; - } - - spawning = false; - pos = spawnpos; - - core.pos = pos; - core.vel = vec2(0,0); - core.hooked_player = -1; - - health = 10; - armor = 0; - jumped = 0; - - mem_zero(&ninja, sizeof(ninja)); - - dead = false; - set_flag(ENTITY::FLAG_PHYSICS); - player_state = PLAYERSTATE_PLAYING; - - core.hook_state = HOOK_IDLE; - - mem_zero(&input, sizeof(input)); - - // init weapons - mem_zero(&weapons, sizeof(weapons)); - weapons[WEAPON_HAMMER].got = true; - weapons[WEAPON_HAMMER].ammo = -1; - weapons[WEAPON_GUN].got = true; - weapons[WEAPON_GUN].ammo = 10; - - /*weapons[WEAPON_RIFLE].got = true; - weapons[WEAPON_RIFLE].ammo = -1;*/ - - active_weapon = WEAPON_GUN; - last_weapon = WEAPON_HAMMER; - queued_weapon = 0; - - reload_timer = 0; - - // Create sound and spawn effects - create_sound(pos, SOUND_PLAYER_SPAWN); - create_playerspawn(pos); - - gamecontroller->on_player_spawn(this); -} - -bool PLAYER::is_grounded() -{ - if(col_check_point((int)(pos.x+phys_size/2), (int)(pos.y+phys_size/2+5))) - return true; - if(col_check_point((int)(pos.x-phys_size/2), (int)(pos.y+phys_size/2+5))) - return true; - return false; + players[i].init(-1); } -int PLAYER::handle_ninja() -{ - vec2 direction = normalize(vec2(latest_input.target_x, latest_input.target_y)); - - if ((server_tick() - ninja.activationtick) > (data->weapons.ninja.duration * server_tickspeed() / 1000)) - { - // time's up, return - weapons[WEAPON_NINJA].got = false; - active_weapon = last_weapon; - if(active_weapon == WEAPON_NINJA) - active_weapon = WEAPON_GUN; - set_weapon(active_weapon); - return 0; - } - - // force ninja weapon - set_weapon(WEAPON_NINJA); - - // Check if it should activate - if (count_input(latest_previnput.fire, latest_input.fire).presses && (server_tick() > ninja.currentcooldown)) - { - // ok then, activate ninja - attack_tick = server_tick(); - ninja.activationdir = direction; - ninja.currentmovetime = data->weapons.ninja.movetime * server_tickspeed() / 1000; - ninja.currentcooldown = data->weapons.ninja.base->firedelay * server_tickspeed() / 1000 + server_tick(); - - // reset hit objects - numobjectshit = 0; - - create_sound(pos, SOUND_NINJA_FIRE); - - // release all hooks when ninja is activated - //release_hooked(); - //release_hooks(); - } - - ninja.currentmovetime--; - - if (ninja.currentmovetime == 0) - { - // reset player velocity - core.vel *= 0.2f; - //return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON; - } - - if (ninja.currentmovetime > 0) - { - // Set player velocity - core.vel = ninja.activationdir * data->weapons.ninja.velocity; - vec2 oldpos = pos; - move_box(&core.pos, &core.vel, vec2(phys_size, phys_size), 0.0f); - // reset velocity so the client doesn't predict stuff - core.vel = vec2(0.0f,0.0f); - if ((ninja.currentmovetime % 2) == 0) - { - //create_smoke(pos); - } - - // check if we hit anything along the way - { - int type = NETOBJTYPE_PLAYER_CHARACTER; - ENTITY *ents[64]; - vec2 dir = pos - oldpos; - float radius = phys_size * 2.0f; //length(dir * 0.5f); - vec2 center = oldpos + dir * 0.5f; - int num = world->find_entities(center, radius, ents, 64, &type, 1); - - for (int i = 0; i < num; i++) - { - // Check if entity is a player - if (ents[i] == this) - continue; - // make sure we haven't hit this object before - bool balreadyhit = false; - for (int j = 0; j < numobjectshit; j++) - { - if (hitobjects[j] == ents[i]) - balreadyhit = true; - } - if (balreadyhit) - continue; - - // check so we are sufficiently close - if (distance(ents[i]->pos, pos) > (phys_size * 2.0f)) - continue; - - // hit a player, give him damage and stuffs... - create_sound(ents[i]->pos, SOUND_NINJA_HIT); - // set his velocity to fast upward (for now) - if(numobjectshit < 10) - hitobjects[numobjectshit++] = ents[i]; - ents[i]->take_damage(vec2(0,10.0f), data->weapons.ninja.base->damage, client_id,WEAPON_NINJA); - } - } - return 0; - } - - return 0; -} - - -void PLAYER::do_weaponswitch() -{ - if(reload_timer != 0) // make sure we have reloaded - return; - - if(queued_weapon == -1) // check for a queued weapon - return; - - if(weapons[WEAPON_NINJA].got) // if we have ninja, no weapon selection is possible - return; - - // switch weapon - set_weapon(queued_weapon); -} - -void PLAYER::handle_weaponswitch() -{ - int wanted_weapon = active_weapon; - if(queued_weapon != -1) - wanted_weapon = queued_weapon; - - // select weapon - int next = count_input(latest_previnput.next_weapon, latest_input.next_weapon).presses; - int prev = count_input(latest_previnput.prev_weapon, latest_input.prev_weapon).presses; - - if(next < 128) // make sure we only try sane stuff - { - while(next) // next weapon selection - { - wanted_weapon = (wanted_weapon+1)%NUM_WEAPONS; - if(weapons[wanted_weapon].got) - next--; - } - } - - if(prev < 128) // make sure we only try sane stuff - { - while(prev) // prev weapon selection - { - wanted_weapon = (wanted_weapon-1)<0?NUM_WEAPONS-1:wanted_weapon-1; - if(weapons[wanted_weapon].got) - prev--; - } - } - - // direct weapon selection - if(latest_input.wanted_weapon) - wanted_weapon = input.wanted_weapon-1; - - // check for insane values - if(wanted_weapon >= 0 && wanted_weapon < NUM_WEAPONS && wanted_weapon != active_weapon && weapons[wanted_weapon].got) - queued_weapon = wanted_weapon; - - do_weaponswitch(); -} - -void PLAYER::fire_weapon() -{ - if(reload_timer != 0 || active_weapon == WEAPON_NINJA) - return; - - do_weaponswitch(); - - vec2 direction = normalize(vec2(latest_input.target_x, latest_input.target_y)); - - bool fullauto = false; - if(active_weapon == WEAPON_GRENADE || active_weapon == WEAPON_SHOTGUN || active_weapon == WEAPON_RIFLE) - fullauto = true; - - - // check if we gonna fire - bool will_fire = false; - if(count_input(latest_previnput.fire, latest_input.fire).presses) will_fire = true; - if(fullauto && (latest_input.fire&1) && weapons[active_weapon].ammo) will_fire = true; - if(!will_fire) - return; - - // check for ammo - if(!weapons[active_weapon].ammo) - { - create_sound(pos, SOUND_WEAPON_NOAMMO); - return; - } - - vec2 projectile_startpos = pos+direction*phys_size*0.75f; - - switch(active_weapon) - { - case WEAPON_HAMMER: - { - // reset objects hit - numobjectshit = 0; - create_sound(pos, SOUND_HAMMER_FIRE); - - int type = NETOBJTYPE_PLAYER_CHARACTER; - ENTITY *ents[64]; - int num = world->find_entities(pos+direction*phys_size*0.75f, phys_size*0.5f, ents, 64, &type, 1); - - for (int i = 0; i < num; i++) - { - PLAYER *target = (PLAYER*)ents[i]; - if (target == this) - continue; - - // hit a player, give him damage and stuffs... - vec2 fdir = normalize(ents[i]->pos - pos); - - // set his velocity to fast upward (for now) - create_sound(pos, SOUND_HAMMER_HIT); - ents[i]->take_damage(vec2(0,-1.0f), data->weapons.hammer.base->damage, client_id, active_weapon); - vec2 dir; - if (length(target->pos - pos) > 0.0f) - dir = normalize(target->pos - pos); - else - dir = vec2(0,-1); - - target->core.vel += normalize(dir + vec2(0,-1.1f)) * 10.0f; - } - - } break; - - case WEAPON_GUN: - { - PROJECTILE *proj = new PROJECTILE(WEAPON_GUN, - client_id, - projectile_startpos, - direction, - (int)(server_tickspeed()*tuning.gun_lifetime), - this, - 1, 0, 0, -1, WEAPON_GUN); - - // pack the projectile and send it to the client directly - NETOBJ_PROJECTILE p; - proj->fill_info(&p); - - msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0); - msg_pack_int(1); - 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); - - create_sound(pos, SOUND_GUN_FIRE); - } break; - - case WEAPON_SHOTGUN: - { - int shotspread = 2; - - msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0); - msg_pack_int(shotspread*2+1); - - for(int i = -shotspread; i <= shotspread; i++) - { - float spreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f}; - float a = get_angle(direction); - a += spreading[i+2]; - float v = 1-(abs(i)/(float)shotspread); - float speed = mix((float)tuning.shotgun_speeddiff, 1.0f, v); - PROJECTILE *proj = new PROJECTILE(WEAPON_SHOTGUN, - client_id, - projectile_startpos, - vec2(cosf(a), sinf(a))*speed, - (int)(server_tickspeed()*tuning.shotgun_lifetime), - this, - 1, 0, 0, -1, WEAPON_SHOTGUN); - - // pack the projectile and send it to the client directly - NETOBJ_PROJECTILE p; - proj->fill_info(&p); - - 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); - - create_sound(pos, SOUND_SHOTGUN_FIRE); - } break; - - case WEAPON_GRENADE: - { - PROJECTILE *proj = new PROJECTILE(WEAPON_GRENADE, - client_id, - projectile_startpos, - direction, - (int)(server_tickspeed()*tuning.grenade_lifetime), - this, - 1, PROJECTILE::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_GRENADE); - - // pack the projectile and send it to the client directly - NETOBJ_PROJECTILE p; - proj->fill_info(&p); - - msg_pack_start(NETMSGTYPE_SV_EXTRAPROJECTILE, 0); - msg_pack_int(1); - 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); - - create_sound(pos, SOUND_GRENADE_FIRE); - } break; - - case WEAPON_RIFLE: - { - new LASER(pos, direction, tuning.laser_reach, this); - create_sound(pos, SOUND_RIFLE_FIRE); - } break; - - } - - if(weapons[active_weapon].ammo > 0) // -1 == unlimited - weapons[active_weapon].ammo--; - attack_tick = server_tick(); - reload_timer = data->weapons.id[active_weapon].firedelay * server_tickspeed() / 1000; -} - -int PLAYER::handle_weapons() -{ - vec2 direction = normalize(vec2(latest_input.target_x, latest_input.target_y)); - - if(config.dbg_stress) - { - for(int i = 0; i < NUM_WEAPONS; i++) - { - weapons[i].got = true; - weapons[i].ammo = 10; - } - - if(reload_timer) // twice as fast reload - reload_timer--; - } - - // check reload timer - if(reload_timer) - { - reload_timer--; - return 0; - } - - if (active_weapon == WEAPON_NINJA) - { - // don't update other weapons while ninja is active - return handle_ninja(); - } - - // fire weapon, if wanted - fire_weapon(); - - // ammo regen - int ammoregentime = data->weapons.id[active_weapon].ammoregentime; - if(ammoregentime) - { - // If equipped and not active, regen ammo? - if (reload_timer <= 0) - { - if (weapons[active_weapon].ammoregenstart < 0) - weapons[active_weapon].ammoregenstart = server_tick(); - - if ((server_tick() - weapons[active_weapon].ammoregenstart) >= ammoregentime * server_tickspeed() / 1000) - { - // Add some ammo - weapons[active_weapon].ammo = min(weapons[active_weapon].ammo + 1, 10); - weapons[active_weapon].ammoregenstart = -1; - } - } - else - { - weapons[active_weapon].ammoregenstart = -1; - } - } - - return 0; -} - -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)); - if(num_inputs > 2 && team != -1 && !dead) - { - handle_weaponswitch(); - fire_weapon(); - } -} - -void PLAYER::tick() -{ - server_setclientscore(client_id, score); - - // grab latest input - /* - { - int size = 0; - int *input = server_latestinput(client_id, &size); - if(input) - { - mem_copy(&latest_previnput, &latest_input, sizeof(latest_input)); - mem_copy(&latest_input, input, sizeof(latest_input)); - } - }*/ - - // check if we have enough input - // this is to prevent initial weird clicks - if(num_inputs < 2) - { - latest_previnput = latest_input; - previnput = input; - } - - // do latency stuff - { - CLIENT_INFO info; - if(server_getclientinfo(client_id, &info)) - { - latency_accum += info.latency; - latency_accum_max = max(latency_accum_max, info.latency); - latency_accum_min = min(latency_accum_min, info.latency); - } - - if(server_tick()%server_tickspeed() == 0) - { - latency_avg = latency_accum/server_tickspeed(); - latency_max = latency_accum_max; - latency_min = latency_accum_min; - latency_accum = 0; - latency_accum_min = 1000; - latency_accum_max = 0; - } - } - - // enable / disable physics - if(team == -1 || dead) - { - world->core.players[client_id] = 0; - clear_flag(FLAG_PHYSICS); - } - else - { - world->core.players[client_id] = &core; - set_flag(FLAG_PHYSICS); - } - - // spectator - if(team == -1) - return; - - if(spawning) - try_respawn(); - - // TODO: rework the input to be more robust - if(dead) - { - if(server_tick()-die_tick >= server_tickspeed()/2 && count_input(latest_previnput.fire, latest_input.fire).presses) - die_tick = -1; - if(server_tick()-die_tick >= server_tickspeed()*5) // auto respawn after 3 sec - respawn(); - //if((input.fire&1) && server_tick()-die_tick >= server_tickspeed()/2) // auto respawn after 0.5 sec - //respawn(); - return; - } - - //player_core core; - //core.pos = pos; - //core.jumped = jumped; - core.input = input; - core.tick(); - - // handle weapons - handle_weapons(); - - player_state = input.player_state; - - // Previnput - previnput = input; - return; -} - -void PLAYER::tick_defered() -{ - if(!dead) - { - vec2 start_pos = core.pos; - vec2 start_vel = core.vel; - bool stuck_before = test_box(core.pos, vec2(28.0f, 28.0f)); - - core.move(); - bool stuck_after_move = test_box(core.pos, vec2(28.0f, 28.0f)); - core.quantize(); - bool stuck_after_quant = test_box(core.pos, vec2(28.0f, 28.0f)); - pos = core.pos; - - if(!stuck_before && (stuck_after_move || stuck_after_quant)) - { - dbg_msg("player", "STUCK!!! %d %d %d %f %f %f %f %x %x %x %x", - stuck_before, - stuck_after_move, - stuck_after_quant, - start_pos.x, start_pos.y, - start_vel.x, start_vel.y, - *((unsigned *)&start_pos.x), *((unsigned *)&start_pos.y), - *((unsigned *)&start_vel.x), *((unsigned *)&start_vel.y)); - } - - int events = core.triggered_events; - int mask = cmask_all_except_one(client_id); - - if(events&COREEVENT_GROUND_JUMP) create_sound(pos, SOUND_PLAYER_JUMP, mask); - if(events&COREEVENT_AIR_JUMP) - { - create_sound(pos, SOUND_PLAYER_AIRJUMP, mask); - NETEVENT_COMMON *c = (NETEVENT_COMMON *)::events.create(NETEVENTTYPE_AIRJUMP, sizeof(NETEVENT_COMMON), mask); - if(c) - { - c->x = (int)pos.x; - c->y = (int)pos.y; - } - } - - //if(events&COREEVENT_HOOK_LAUNCH) snd_play_random(CHN_WORLD, SOUND_HOOK_LOOP, 1.0f, pos); - if(events&COREEVENT_HOOK_ATTACH_PLAYER) create_sound(pos, SOUND_HOOK_ATTACH_PLAYER, cmask_all()); - if(events&COREEVENT_HOOK_ATTACH_GROUND) create_sound(pos, SOUND_HOOK_ATTACH_GROUND, mask); - //if(events&COREEVENT_HOOK_RETRACT) snd_play_random(CHN_WORLD, SOUND_PLAYER_JUMP, 1.0f, pos); - - } - - if(team == -1) - { - pos.x = input.target_x; - pos.y = input.target_y; - } -} - -void PLAYER::die(int killer, int weapon) -{ - if (dead || team == -1) - return; - - int mode_special = gamecontroller->on_player_death(this, get_player(killer), weapon); - - dbg_msg("game", "kill killer='%d:%s' victim='%d:%s' weapon=%d special=%d", - killer, server_clientname(killer), - client_id, server_clientname(client_id), weapon, mode_special); - - // send the kill message - NETMSG_SV_KILLMSG msg; - msg.killer = killer; - msg.victim = client_id; - msg.weapon = weapon; - msg.mode_special = mode_special; - msg.pack(MSGFLAG_VITAL); - server_send_msg(-1); - - // a nice sound - create_sound(pos, SOUND_PLAYER_DIE); - - // set dead state - die_pos = pos; - dead = true; - die_tick = server_tick(); - clear_flag(FLAG_PHYSICS); - create_death(pos, client_id); -} - -bool PLAYER::take_damage(vec2 force, int dmg, int from, int weapon) -{ - core.vel += force; - - if(gamecontroller->is_friendly_fire(client_id, from) && !config.sv_teamdamage) - return false; - - // player only inflicts half damage on self - if(from == client_id) - dmg = max(1, dmg/2); - - // CTF and TDM (TODO: check for FF) - //if (gameobj->gametype != GAMETYPE_DM && from >= 0 && players[from].team == team) - //return false; - - damage_taken++; - - // create healthmod indicator - if(server_tick() < damage_taken_tick+25) - { - // make sure that the damage indicators doesn't group together - create_damageind(pos, damage_taken*0.25f, dmg); - } - else - { - damage_taken = 0; - create_damageind(pos, 0, dmg); - } - - if(dmg) - { - if(armor) - { - if(dmg > 1) - { - health--; - dmg--; - } - - if(dmg > armor) - { - dmg -= armor; - armor = 0; - } - else - { - armor -= dmg; - dmg = 0; - } - } - - health -= dmg; - } - - damage_taken_tick = server_tick(); - - // do damage hit sound - if(from >= 0 && from != client_id) - create_sound(get_player(from)->pos, SOUND_HIT, cmask_one(from)); - - // check for death - if(health <= 0) - { - die(from, weapon); - - // set attacker's face to happy (taunt!) - if (from >= 0 && from != client_id) - { - PLAYER *p = get_player(from); - - p->emote_type = EMOTE_HAPPY; - p->emote_stop = server_tick() + server_tickspeed(); - } - - return false; - } - - if (dmg > 2) - create_sound(pos, SOUND_PLAYER_PAIN_LONG); - else - create_sound(pos, SOUND_PLAYER_PAIN_SHORT); - - emote_type = EMOTE_PAIN; - emote_stop = server_tick() + 500 * server_tickspeed() / 1000; - - // spawn blood? - return true; -} - -void PLAYER::snap(int snaping_client) -{ - if(1) - { - 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->cid = client_id; - info->score = score; - info->team = team; - - if(client_id == snaping_client) - info->local = 1; - } - - if(!dead && health > 0 && team >= 0 && distance(players[snaping_client].pos, pos) < 1000.0f) - { - NETOBJ_PLAYER_CHARACTER *character = (NETOBJ_PLAYER_CHARACTER *)snap_new_item(NETOBJTYPE_PLAYER_CHARACTER, client_id, sizeof(NETOBJ_PLAYER_CHARACTER)); - - core.write(character); - - // this is to make sure that players that are just standing still - // isn't sent. this is because the physics keep bouncing between - // 0-128 when just standing. - // TODO: fix the physics so this isn't needed - if(snaping_client != client_id && abs(character->vy) < 256.0f) - character->vy = 0; - - if (emote_stop < server_tick()) - { - emote_type = EMOTE_NORMAL; - emote_stop = -1; - } - - character->emote = emote_type; - - character->ammocount = 0; - character->health = 0; - character->armor = 0; - - character->weapon = active_weapon; - character->attacktick = attack_tick; - - character->wanted_direction = input.direction; - /* - if(input.left && !input.right) - character->wanted_direction = -1; - else if(!input.left && input.right) - character->wanted_direction = 1;*/ - - - if(client_id == snaping_client) - { - character->health = health; - character->armor = armor; - if(weapons[active_weapon].ammo > 0) - character->ammocount = weapons[active_weapon].ammo; - } - - if (character->emote == EMOTE_NORMAL) - { - if(250 - ((server_tick() - last_action)%(250)) < 5) - character->emote = EMOTE_BLINK; - } - - character->player_state = player_state; - } -} - -PLAYER *players; - -////////////////////////////////////////////////// -// powerup -////////////////////////////////////////////////// -PICKUP::PICKUP(int _type, int _subtype) -: ENTITY(NETOBJTYPE_PICKUP) -{ - type = _type; - subtype = _subtype; - proximity_radius = phys_size; - - reset(); - - // TODO: should this be done here? - world->insert_entity(this); -} - -void PICKUP::reset() -{ - if (data->pickups[type].spawndelay > 0) - spawntick = server_tick() + server_tickspeed() * data->pickups[type].spawndelay; - else - spawntick = -1; -} - - -void send_weapon_pickup(int cid, int weapon); - -void PICKUP::tick() -{ - // wait for respawn - if(spawntick > 0) - { - if(server_tick() > spawntick) - { - // respawn - spawntick = -1; - - if(type == POWERUP_WEAPON) - create_sound(pos, SOUND_WEAPON_SPAWN); - } - else - return; - } - // Check if a player intersected us - PLAYER* pplayer = closest_player(pos, 20.0f, 0); - if (pplayer) - { - // player picked us up, is someone was hooking us, let them go - int respawntime = -1; - switch (type) - { - case POWERUP_HEALTH: - if(pplayer->health < 10) - { - create_sound(pos, SOUND_PICKUP_HEALTH); - pplayer->health = min(10, pplayer->health + 1); - respawntime = data->pickups[type].respawntime; - } - break; - case POWERUP_ARMOR: - if(pplayer->armor < 10) - { - create_sound(pos, SOUND_PICKUP_ARMOR); - pplayer->armor = min(10, pplayer->armor + 1); - respawntime = data->pickups[type].respawntime; - } - break; - - case POWERUP_WEAPON: - if(subtype >= 0 && subtype < NUM_WEAPONS) - { - if(pplayer->weapons[subtype].ammo < data->weapons.id[subtype].maxammo || !pplayer->weapons[subtype].got) - { - pplayer->weapons[subtype].got = true; - pplayer->weapons[subtype].ammo = min(data->weapons.id[subtype].maxammo, pplayer->weapons[subtype].ammo + 10); - respawntime = data->pickups[type].respawntime; - - // TODO: data compiler should take care of stuff like this - if(subtype == WEAPON_GRENADE) - create_sound(pos, SOUND_PICKUP_GRENADE); - else if(subtype == WEAPON_SHOTGUN) - create_sound(pos, SOUND_PICKUP_SHOTGUN); - else if(subtype == WEAPON_RIFLE) - create_sound(pos, SOUND_PICKUP_SHOTGUN); - - send_weapon_pickup(pplayer->client_id, subtype); - } - } - break; - case POWERUP_NINJA: - { - // activate ninja on target player - pplayer->ninja.activationtick = server_tick(); - pplayer->weapons[WEAPON_NINJA].got = true; - pplayer->last_weapon = pplayer->active_weapon; - pplayer->active_weapon = WEAPON_NINJA; - respawntime = data->pickups[type].respawntime; - create_sound(pos, SOUND_PICKUP_NINJA); - - // loop through all players, setting their emotes - ENTITY *ents[64]; - 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++) - { - PLAYER *p = (PLAYER *)ents[i]; - if (p != pplayer) - { - p->emote_type = EMOTE_SURPRISE; - p->emote_stop = server_tick() + server_tickspeed(); - } - } - - pplayer->emote_type = EMOTE_ANGRY; - pplayer->emote_stop = server_tick() + 1200 * server_tickspeed() / 1000; - - break; - } - default: - break; - }; - - if(respawntime >= 0) - { - dbg_msg("game", "pickup player='%d:%s' item=%d/%d", - pplayer->client_id, server_clientname(pplayer->client_id), type, subtype); - spawntick = server_tick() + server_tickspeed() * respawntime; - } - } -} - -void PICKUP::snap(int snapping_client) -{ - if(spawntick != -1) - return; - - NETOBJ_PICKUP *up = (NETOBJ_PICKUP *)snap_new_item(NETOBJTYPE_PICKUP, id, sizeof(NETOBJ_PICKUP)); - up->x = (int)pos.x; - up->y = (int)pos.y; - up->type = type; // TODO: two diffrent types? what gives? - up->subtype = subtype; -} - -// POWERUP END /////////////////////// - -PLAYER *get_player(int index) -{ - return &players[index]; -} - -void create_damageind(vec2 p, float angle, int amount) +void GAMECONTEXT::create_damageind(vec2 p, float angle, int amount) { float a = 3 * 3.14159f / 2 + angle; //float a = get_angle(dir); @@ -1852,7 +568,7 @@ void create_damageind(vec2 p, float angle, int amount) } } -void create_explosion(vec2 p, int owner, int weapon, bool bnodamage) +void GAMECONTEXT::create_explosion(vec2 p, int owner, int weapon, bool bnodamage) { // create the event NETEVENT_EXPLOSION *ev = (NETEVENT_EXPLOSION *)events.create(NETEVENTTYPE_EXPLOSION, sizeof(NETEVENT_EXPLOSION)); @@ -1865,11 +581,10 @@ void create_explosion(vec2 p, int owner, int weapon, bool bnodamage) if (!bnodamage) { // deal damage - ENTITY *ents[64]; + CHARACTER *ents[64]; float radius = 128.0f; float innerradius = 42.0f; - - int num = world->find_entities(p, radius, ents, 64); + int num = game.world.find_entities(p, radius, (ENTITY**)ents, 64, NETOBJTYPE_CHARACTER); for(int i = 0; i < num; i++) { vec2 diff = ents[i]->pos - p; @@ -1897,7 +612,7 @@ void create_smoke(vec2 p) } }*/ -void create_playerspawn(vec2 p) +void GAMECONTEXT::create_playerspawn(vec2 p) { // create the event NETEVENT_SPAWN *ev = (NETEVENT_SPAWN *)events.create(NETEVENTTYPE_SPAWN, sizeof(NETEVENT_SPAWN)); @@ -1908,7 +623,7 @@ void create_playerspawn(vec2 p) } } -void create_death(vec2 p, int cid) +void GAMECONTEXT::create_death(vec2 p, int cid) { // create the event NETEVENT_DEATH *ev = (NETEVENT_DEATH *)events.create(NETEVENTTYPE_DEATH, sizeof(NETEVENT_DEATH)); @@ -1920,7 +635,7 @@ void create_death(vec2 p, int cid) } } -void create_sound(vec2 pos, int sound, int mask) +void GAMECONTEXT::create_sound(vec2 pos, int sound, int mask) { if (sound < 0) return; @@ -1935,7 +650,7 @@ void create_sound(vec2 pos, int sound, int mask) } } -void create_sound_global(int sound, int target) +void GAMECONTEXT::create_sound_global(int sound, int target) { if (sound < 0) return; @@ -1947,30 +662,28 @@ void create_sound_global(int sound, int target) } // TODO: should be more general -PLAYER *intersect_player(vec2 pos0, vec2 pos1, float radius, vec2& new_pos, ENTITY *notthis) +CHARACTER *GAMEWORLD::intersect_character(vec2 pos0, vec2 pos1, float radius, vec2& new_pos, ENTITY *notthis) { // Find other players float closest_len = distance(pos0, pos1) * 100.0f; vec2 line_dir = normalize(pos1-pos0); - PLAYER *closest = 0; - - for(int i = 0; i < MAX_CLIENTS; i++) - { - if(players[i].client_id < 0 || (ENTITY *)&players[i] == notthis) + CHARACTER *closest = 0; + + CHARACTER *p = (CHARACTER *)game.world.find_first(NETOBJTYPE_CHARACTER); + for(; p; p = (CHARACTER *)p->typenext()) + { + if(p == notthis) continue; - if(!(players[i].flags&ENTITY::FLAG_PHYSICS)) - continue; - - vec2 intersect_pos = closest_point_on_line(pos0, pos1, players[i].pos); - float len = distance(players[i].pos, intersect_pos); - if(len < PLAYER::phys_size+radius) + vec2 intersect_pos = closest_point_on_line(pos0, pos1, p->pos); + float len = distance(p->pos, intersect_pos); + if(len < CHARACTER::phys_size+radius) { if(len < closest_len) { new_pos = intersect_pos; closest_len = len; - closest = &players[i]; + closest = p; } } } @@ -1979,27 +692,25 @@ PLAYER *intersect_player(vec2 pos0, vec2 pos1, float radius, vec2& new_pos, ENTI } -PLAYER *closest_player(vec2 pos, float radius, ENTITY *notthis) +CHARACTER *GAMEWORLD::closest_character(vec2 pos, float radius, ENTITY *notthis) { // Find other players float closest_range = radius*2; - PLAYER *closest = 0; + CHARACTER *closest = 0; - for(int i = 0; i < MAX_CLIENTS; i++) - { - if(players[i].client_id < 0 || (ENTITY *)&players[i] == notthis) + CHARACTER *p = (CHARACTER *)game.world.find_first(NETOBJTYPE_CHARACTER); + for(; p; p = (CHARACTER *)p->typenext()) + { + if(p == notthis) continue; - if(!(players[i].flags&ENTITY::FLAG_PHYSICS)) - continue; - - float len = distance(pos, players[i].pos); - if(len < PLAYER::phys_size+radius) + float len = distance(pos, p->pos); + if(len < CHARACTER::phys_size+radius) { if(len < closest_range) { closest_range = len; - closest = &players[i]; + closest = p; } } } @@ -2007,26 +718,40 @@ PLAYER *closest_player(vec2 pos, float radius, ENTITY *notthis) return closest; } -// Server hooks -void mods_tick() -{ - world->core.tuning = tuning; - world->tick(); - if(world->paused) // make sure that the game object always updates - gamecontroller->tick(); +void GAMECONTEXT::tick() +{ + world.core.tuning = tuning; + world.tick(); + + if(world.paused) // make sure that the game object always updates + controller->tick(); + + for(int i = 0; i < MAX_CLIENTS; i++) + { + if(players[i].client_id != -1) + players[i].tick(); + } } -void mods_snap(int client_id) +void GAMECONTEXT::snap(int client_id) { - world->snap(client_id); + world.snap(client_id); events.snap(client_id); + controller->snap(client_id); + + for(int i = 0; i < MAX_CLIENTS; i++) + { + if(players[i].client_id != -1) + players[i].snap(client_id); + } } +// Server hooks void mods_client_direct_input(int client_id, void *input) { - if(!world->paused) - players[client_id].on_direct_input((NETOBJ_PLAYER_INPUT *)input); + if(!game.world.paused) + game.players[client_id].on_direct_input((NETOBJ_PLAYER_INPUT *)input); /* if(i->fire) @@ -2039,45 +764,60 @@ void mods_client_direct_input(int client_id, void *input) void mods_client_predicted_input(int client_id, void *input) { - if(!world->paused) + if(!game.world.paused) + game.players[client_id].on_predicted_input((NETOBJ_PLAYER_INPUT *)input); + + /* { - 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 = *(NETOBJ_PLAYER_INPUT*)input; - players[client_id].num_inputs++; - if(players[client_id].input.target_x == 0 && players[client_id].input.target_y == 0) - players[client_id].input.target_y = -1; - } + on_predicted_input() + if (memcmp(&game.players[client_id].input, input, sizeof(NETOBJ_PLAYER_INPUT)) != 0) + game.players[client_id].last_action = server_tick(); + + //game.players[client_id].previnput = game.players[client_id].input; + game.players[client_id].input = *(NETOBJ_PLAYER_INPUT*)input; + game.players[client_id].num_inputs++; + + if(game.players[client_id].input.target_x == 0 && game.players[client_id].input.target_y == 0) + game.players[client_id].input.target_y = -1; + }*/ } +// Server hooks +void mods_tick() +{ + game.tick(); +} + +void mods_snap(int client_id) +{ + game.snap(client_id); +} void mods_client_enter(int client_id) { - world->insert_entity(&players[client_id]); - players[client_id].respawn(); + //game.world.insert_entity(&game.players[client_id]); + game.players[client_id].respawn(); dbg_msg("game", "join player='%d:%s'", client_id, server_clientname(client_id)); char buf[512]; - str_format(buf, sizeof(buf), "%s entered and joined the %s", server_clientname(client_id), get_team_name(players[client_id].team)); - send_chat(-1, CHAT_ALL, buf); + str_format(buf, sizeof(buf), "%s entered and joined the %s", server_clientname(client_id), game.controller->get_team_name(game.players[client_id].team)); + game.send_chat(-1, CHAT_ALL, buf); - dbg_msg("game", "team_join player='%d:%s' team=%d", client_id, server_clientname(client_id), players[client_id].team); + dbg_msg("game", "team_join player='%d:%s' team=%d", client_id, server_clientname(client_id), game.players[client_id].team); } void mods_connected(int client_id) { - players[client_id].init(); - players[client_id].client_id = client_id; + game.players[client_id].init(client_id); + //game.players[client_id].client_id = client_id; // Check which team the player should be on if(config.sv_tournament_mode) - players[client_id].team = -1; + game.players[client_id].team = -1; else - players[client_id].team = gamecontroller->get_auto_team(client_id); + game.players[client_id].team = game.controller->get_auto_team(client_id); // send motd NETMSG_SV_MOTD msg; @@ -2088,16 +828,8 @@ void mods_connected(int client_id) void mods_client_drop(int client_id) { - char buf[512]; - str_format(buf, sizeof(buf), "%s has left the game", server_clientname(client_id)); - send_chat(-1, CHAT_ALL, buf); + game.players[client_id].on_disconnect(); - dbg_msg("game", "leave player='%d:%s'", client_id, server_clientname(client_id)); - - gamecontroller->on_player_death(&players[client_id], 0, -1); - world->remove_entity(&players[client_id]); - world->core.players[client_id] = 0x0; - players[client_id].client_id = -1; } void mods_message(int msgtype, int client_id) @@ -2114,18 +846,18 @@ void mods_message(int msgtype, int client_id) NETMSG_CL_SAY *msg = (NETMSG_CL_SAY *)rawmsg; int team = msg->team; if(team) - team = players[client_id].team; + team = game.players[client_id].team; else team = CHAT_ALL; - if(config.sv_spamprotection && players[client_id].last_chat+time_freq() > time_get()) + if(config.sv_spamprotection && game.players[client_id].last_chat+time_freq() > time_get()) { // consider this as spam } else { - players[client_id].last_chat = time_get(); - send_chat(client_id, team, msg->message); + game.players[client_id].last_chat = time_get(); + game.send_chat(client_id, team, msg->message); } } else if (msgtype == NETMSGTYPE_CL_SETTEAM) @@ -2133,21 +865,21 @@ void mods_message(int msgtype, int client_id) NETMSG_CL_SETTEAM *msg = (NETMSG_CL_SETTEAM *)rawmsg; // Switch team on given client and kill/respawn him - if(gamecontroller->can_join_team(msg->team, client_id)) - players[client_id].set_team(msg->team); + if(game.controller->can_join_team(msg->team, client_id)) + game.players[client_id].set_team(msg->team); else { char buf[128]; str_format(buf, sizeof(buf), "Only %d active players are allowed", config.sv_max_clients-config.sv_spectator_slots); - send_broadcast(buf, client_id); + game.send_broadcast(buf, client_id); } } else if (msgtype == NETMSGTYPE_CL_CHANGEINFO || msgtype == NETMSGTYPE_CL_STARTINFO) { NETMSG_CL_CHANGEINFO *msg = (NETMSG_CL_CHANGEINFO *)rawmsg; - players[client_id].use_custom_color = msg->use_custom_color; - players[client_id].color_body = msg->color_body; - players[client_id].color_feet = msg->color_feet; + game.players[client_id].use_custom_color = msg->use_custom_color; + game.players[client_id].color_body = msg->color_body; + game.players[client_id].color_feet = msg->color_feet; // check for invalid chars /* @@ -2168,13 +900,13 @@ void mods_message(int msgtype, int client_id) { char chattext[256]; str_format(chattext, sizeof(chattext), "%s changed name to %s", oldname, server_clientname(client_id)); - send_chat(-1, CHAT_ALL, chattext); + game.send_chat(-1, CHAT_ALL, chattext); } // set skin - str_copy(players[client_id].skin_name, msg->skin, sizeof(players[client_id].skin_name)); + str_copy(game.players[client_id].skin_name, msg->skin, sizeof(game.players[client_id].skin_name)); - gamecontroller->on_player_info_change(&players[client_id]); + game.controller->on_player_info_change(&game.players[client_id]); if(msgtype == NETMSGTYPE_CL_STARTINFO) { @@ -2183,8 +915,8 @@ void mods_message(int msgtype, int client_id) // send all info to this client for(int i = 0; i < MAX_CLIENTS; i++) { - if(players[i].client_id != -1) - send_info(i, client_id); + if(game.players[i].client_id != -1) + game.send_info(i, client_id); } // send tuning parameters to client @@ -2196,23 +928,20 @@ void mods_message(int msgtype, int client_id) server_send_msg(client_id); } - send_info(client_id, -1); + game.send_info(client_id, -1); } else if (msgtype == NETMSGTYPE_CL_EMOTICON) { NETMSG_CL_EMOTICON *msg = (NETMSG_CL_EMOTICON *)rawmsg; - send_emoticon(client_id, msg->emoticon); + game.send_emoticon(client_id, msg->emoticon); } else if (msgtype == NETMSGTYPE_CL_KILL) { - PLAYER *pplayer = get_player(client_id); - pplayer->die(client_id, -1); + //PLAYER *pplayer = get_player(client_id); + game.players[client_id].kill_character(); //(client_id, -1); } } -extern unsigned char internal_data[]; - - static void con_tune_param(void *result, void *user_data) { const char *param_name = console_arg_string(result, 0); @@ -2249,19 +978,19 @@ static void con_tune_dump(void *result, void *user_data) static void con_restart(void *result, void *user_data) { if(console_arg_num(result)) - gamecontroller->do_warmup(console_arg_int(result, 0)); + game.controller->do_warmup(console_arg_int(result, 0)); else - gamecontroller->startround(); + game.controller->startround(); } static void con_broadcast(void *result, void *user_data) { - send_broadcast(console_arg_string(result, 0), -1); + game.send_broadcast(console_arg_string(result, 0), -1); } static void con_say(void *result, void *user_data) { - send_chat(-1, CHAT_ALL, console_arg_string(result, 0)); + game.send_chat(-1, CHAT_ALL, console_arg_string(result, 0)); } static void con_set_team(void *result, void *user_data) @@ -2271,10 +1000,10 @@ static void con_set_team(void *result, void *user_data) dbg_msg("", "%d %d", client_id, team); - if(players[client_id].client_id != client_id) + if(game.players[client_id].client_id != client_id) return; - players[client_id].set_team(team); + game.players[client_id].set_team(team); } void mods_console_init() @@ -2293,32 +1022,38 @@ void mods_init() { //if(!data) /* only load once */ //data = load_data_from_memory(internal_data); + + for(int i = 0; i < NUM_NETOBJTYPES; i++) + snap_set_staticsize(i, netobj_get_size(i)); layers_init(); col_init(); - world = new GAMEWORLD; - players = new PLAYER[MAX_CLIENTS]; + // reset everything here + //world = new GAMEWORLD; + //players = new PLAYER[MAX_CLIENTS]; // select gametype if(strcmp(config.sv_gametype, "ctf") == 0) - gamecontroller = new GAMECONTROLLER_CTF; + game.controller = new GAMECONTROLLER_CTF; else if(strcmp(config.sv_gametype, "tdm") == 0) - gamecontroller = new GAMECONTROLLER_TDM; + game.controller = new GAMECONTROLLER_TDM; else - gamecontroller = new GAMECONTROLLER_DM; + game.controller = new GAMECONTROLLER_DM; // setup core world - for(int i = 0; i < MAX_CLIENTS; i++) - players[i].core.world = &world->core; + //for(int i = 0; i < MAX_CLIENTS; i++) + // game.players[i].core.world = &game.world.core; // create all entities from the game layer MAPITEM_LAYER_TILEMAP *tmap = layers_game_layer(); TILE *tiles = (TILE *)map_get_data(tmap->data); + /* num_spawn_points[0] = 0; num_spawn_points[1] = 0; num_spawn_points[2] = 0; + */ for(int y = 0; y < tmap->height; y++) { @@ -2326,11 +1061,11 @@ void mods_init() { int index = tiles[y*tmap->width+x].index - ENTITY_OFFSET; vec2 pos(x*32.0f+16.0f, y*32.0f+16.0f); - gamecontroller->on_entity(index, pos); + game.controller->on_entity(index, pos); } } - world->insert_entity(gamecontroller); + //game.world.insert_entity(game.controller); if(config.dbg_dummies) { @@ -2338,26 +1073,22 @@ void mods_init() { mods_connected(MAX_CLIENTS-i-1); mods_client_enter(MAX_CLIENTS-i-1); - if(gamecontroller->gametype != GAMETYPE_DM) - players[MAX_CLIENTS-i-1].team = i&1; + if(game.controller->gametype != GAMETYPE_DM) + game.players[MAX_CLIENTS-i-1].team = i&1; } } } void mods_shutdown() { - delete [] players; - delete gamecontroller; - delete world; - gamecontroller = 0; - players = 0; - world = 0; + delete game.controller; + game.controller = 0; } void mods_presnap() {} void mods_postsnap() { - events.clear(); + game.events.clear(); } extern "C" const char *mods_net_version() { return GAME_NETVERSION; } diff --git a/src/mastersrv/mastersrv.cpp b/src/mastersrv/mastersrv.cpp index c9022328a..c27bb03cc 100644 --- a/src/mastersrv/mastersrv.cpp +++ b/src/mastersrv/mastersrv.cpp @@ -13,22 +13,22 @@ enum { EXPIRE_TIME = 90 }; -static struct check_server +static struct CHECK_SERVER { - NETADDR4 address; - NETADDR4 alt_address; + NETADDR address; + NETADDR alt_address; int try_count; int64 try_time; } check_servers[MAX_SERVERS]; static int num_checkservers = 0; -static struct packet_data +static struct PACKET_DATA { unsigned char header[sizeof(SERVERBROWSE_LIST)]; - NETADDR4 servers[MAX_SERVERS]; + NETADDR servers[MAX_SERVERS]; } data; -static struct count_packet_data +static struct COUNT_PACKET_DATA { unsigned char header[sizeof(SERVERBROWSE_COUNT)]; unsigned char high; @@ -41,7 +41,7 @@ static int num_servers = 0; static net_client net_checker; // NAT/FW checker static net_client net_op; // main -void send_ok(NETADDR4 *addr) +void send_ok(NETADDR *addr) { NETCHUNK p; p.client_id = -1; @@ -55,7 +55,7 @@ void send_ok(NETADDR4 *addr) net_op.send(&p); } -void send_error(NETADDR4 *addr) +void send_error(NETADDR *addr) { NETCHUNK p; p.client_id = -1; @@ -66,7 +66,7 @@ void send_error(NETADDR4 *addr) net_op.send(&p); } -void send_check(NETADDR4 *addr) +void send_check(NETADDR *addr) { NETCHUNK p; p.client_id = -1; @@ -77,7 +77,7 @@ void send_check(NETADDR4 *addr) net_checker.send(&p); } -void add_checkserver(NETADDR4 *info, NETADDR4 *alt) +void add_checkserver(NETADDR *info, NETADDR *alt) { // add server if(num_checkservers == MAX_SERVERS) @@ -96,13 +96,13 @@ void add_checkserver(NETADDR4 *info, NETADDR4 *alt) num_checkservers++; } -void add_server(NETADDR4 *info) +void add_server(NETADDR *info) { // see if server already exists in list int i; for(i = 0; i < num_servers; i++) { - if(net_addr4_cmp(&data.servers[i], info) == 0) + if(net_addr_comp(&data.servers[i], info) == 0) { dbg_msg("mastersrv", "updated: %d.%d.%d.%d:%d", info->ip[0], info->ip[1], info->ip[2], info->ip[3], info->port); @@ -183,7 +183,7 @@ void purge_servers() int main(int argc, char **argv) { - NETADDR4 bindaddr; + NETADDR bindaddr; mem_zero(&bindaddr, sizeof(bindaddr)); bindaddr.port = MASTERSERVER_PORT; @@ -210,7 +210,7 @@ int main(int argc, char **argv) if(packet.data_size == sizeof(SERVERBROWSE_HEARTBEAT)+2 && memcmp(packet.data, SERVERBROWSE_HEARTBEAT, sizeof(SERVERBROWSE_HEARTBEAT)) == 0) { - NETADDR4 alt; + NETADDR alt; unsigned char *d = (unsigned char *)packet.data; alt = packet.address; alt.port = @@ -244,7 +244,7 @@ int main(int argc, char **argv) p.client_id = -1; p.address = packet.address; p.flags = NETSENDFLAG_CONNLESS; - p.data_size = num_servers*sizeof(NETADDR4)+sizeof(SERVERBROWSE_LIST); + p.data_size = num_servers*sizeof(NETADDR)+sizeof(SERVERBROWSE_LIST); p.data = &data; net_op.send(&p); } @@ -259,8 +259,8 @@ int main(int argc, char **argv) // remove it from checking for(int i = 0; i < num_checkservers; i++) { - if(net_addr4_cmp(&check_servers[i].address, &packet.address) == 0 || - net_addr4_cmp(&check_servers[i].alt_address, &packet.address) == 0) + if(net_addr_comp(&check_servers[i].address, &packet.address) == 0 || + net_addr_comp(&check_servers[i].alt_address, &packet.address) == 0) { num_checkservers--; check_servers[i] = check_servers[num_checkservers]; diff --git a/src/tools/crapnet.cpp b/src/tools/crapnet.cpp index ba8a30d81..f807bb61a 100644 --- a/src/tools/crapnet.cpp +++ b/src/tools/crapnet.cpp @@ -8,7 +8,7 @@ struct packet packet *prev; packet *next; - NETADDR4 send_to; + NETADDR send_to; int64 timestamp; int id; int data_size; @@ -20,10 +20,10 @@ static packet *last = (packet *)0; static int current_latency = 0; static int debug = 0; -int run(int port, NETADDR4 dest) +int run(int port, NETADDR dest) { - NETADDR4 src = {{0,0,0,0},port}; - NETSOCKET socket = net_udp4_create(src); + NETADDR src = {NETTYPE_IPV4, {0,0,0,0},port}; + NETSOCKET socket = net_udp_create(src); char buffer[1024*2]; int id = 0; @@ -35,8 +35,8 @@ int run(int port, NETADDR4 dest) { // fetch data int data_trash = 0; - NETADDR4 from; - int bytes = net_udp4_recv(socket, &from, buffer, 1024*2); + NETADDR from; + int bytes = net_udp_recv(socket, &from, buffer, 1024*2); if(bytes <= 0) break; @@ -46,7 +46,7 @@ int run(int port, NETADDR4 dest) // create new packet packet *p = (packet *)mem_alloc(sizeof(packet)+bytes, 1); - if(net_addr4_cmp(&from, &dest) == 0) + if(net_addr_comp(&from, &dest) == 0) { p->send_to = src; // from the server } @@ -112,7 +112,7 @@ int run(int port, NETADDR4 dest) // send and remove packet //if((rand()%20) != 0) // heavy packetloss - net_udp4_send(socket, &p->send_to, p->data, p->data_size); + net_udp_send(socket, &p->send_to, p->data, p->data_size); // update lag double flux = rand()/(double)RAND_MAX; @@ -136,7 +136,7 @@ int run(int port, NETADDR4 dest) int main(int argc, char **argv) { - NETADDR4 a = {{127,0,0,1},8303}; + NETADDR a = {NETTYPE_IPV4, {127,0,0,1},8303}; run(8302, a); return 0; } diff --git a/src/tools/fake_server.c b/src/tools/fake_server.c index 9f588e374..763caa730 100644 --- a/src/tools/fake_server.c +++ b/src/tools/fake_server.c @@ -37,7 +37,7 @@ int flags = 0; const char *version = "0.3.0 2d82e361de24cb25"; const char *map = "somemap"; const char *server_name = "unnamed server"; -NETADDR4 master_servers[16] = {{{0},0}}; +NETADDR master_servers[16] = {{0,{0},0}}; int num_masters = 0; const char *player_names[16] = {0}; @@ -109,7 +109,7 @@ static void build_infomessage() } } -static void send_serverinfo(NETADDR4 *addr) +static void send_serverinfo(NETADDR *addr) { NETCHUNK p; p.client_id = -1; @@ -120,7 +120,7 @@ static void send_serverinfo(NETADDR4 *addr) netserver_send(net, &p); } -static void send_fwcheckresponse(NETADDR4 *addr) +static void send_fwcheckresponse(NETADDR *addr) { NETCHUNK p; p.client_id = -1; @@ -134,7 +134,7 @@ static void send_fwcheckresponse(NETADDR4 *addr) static int run() { int64 next_heartbeat = 0; - NETADDR4 bindaddr = {{0},0}; + NETADDR bindaddr = {NETTYPE_IPV4, {0},0}; net = netserver_open(bindaddr, 0, 0); if(!net) return -1; diff --git a/src/tools/packetgen.c b/src/tools/packetgen.c index dcfe0885d..9e46c44de 100644 --- a/src/tools/packetgen.c +++ b/src/tools/packetgen.c @@ -3,15 +3,15 @@ enum { NUM_SOCKETS = 64 }; -int run(NETADDR4 dest) +int run(NETADDR 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); + NETADDR bindaddr = {NETTYPE_IPV4, {0}, 0}; + sockets[i] = net_udp_create(bindaddr); } while(1) @@ -24,13 +24,13 @@ int run(NETADDR4 dest) size %= 256; socket_to_use %= NUM_SOCKETS; io_read(io_stdin(), data, size); - net_udp4_send(sockets[socket_to_use], &dest, data, size); + net_udp_send(sockets[socket_to_use], &dest, data, size); } } int main(int argc, char **argv) { - NETADDR4 dest = {{127,0,0,1},8303}; + NETADDR dest = {NETTYPE_IPV4, {127,0,0,1},8303}; run(dest); return 0; }