/* Copyright (C) 1996-1997 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // server.h #define QW_SERVER typedef enum { ss_dead, // no map loaded ss_clustermode, ss_loading, // spawning level edicts ss_active, // actively running ss_cinematic } server_state_t; // some qc commands are only valid before the server has finished // initializing (precache commands, static sounds / objects, etc) #ifdef SVCHAT typedef struct chatvar_s { char varname[64]; float value; struct chatvar_s *next; } chatvar_t; typedef struct { qboolean active; char filename[64]; edict_t *edict; char maintext[1024]; struct { float tag; char text[256]; } option[6]; int options; chatvar_t *vars; float time; } svchat_t; #endif typedef struct { int netstyle; char particleeffecttype[64]; char stain[3]; qbyte radius; qbyte dlightrgb[3]; qbyte dlightradius; qbyte dlighttime; qbyte dlightcfade[3]; } svcustomtents_t; typedef struct laggedpacket_s { double time; struct laggedpacket_s *next; int length; unsigned char data[MAX_QWMSGLEN+10]; } laggedpacket_t; typedef struct { vec3_t origin; char angles[3]; qbyte modelindex; qbyte frame; qbyte colormap; qbyte skinnum; qbyte effects; qbyte scale; qbyte trans; char fatness; } mvdentity_state_t; typedef struct { vec3_t position; unsigned short soundnum; qbyte volume; qbyte attenuation; } staticsound_state_t; extern entity_state_t *sv_staticentities; extern int sv_max_staticentities; extern staticsound_state_t *sv_staticsounds; extern int sv_max_staticsounds; typedef struct { qboolean active; // false when server is going down server_state_t state; // precache commands are only valid during load float gamespeed; //time progression multiplier, fixed per-level. qboolean csqcdebug; unsigned int csqcchecksum; qboolean mapchangelocked; #ifdef SAVEDGAMES char loadgame_on_restart[MAX_QPATH]; //saved game to load on map_restart double autosave_time; #endif double time; double starttime; int framenum; int logindatabase; enum { PAUSE_EXPLICIT = 1, //someone hit pause PAUSE_SERVICE = 2, //we're running as a service and someone paused us rather than killing us. PAUSE_AUTO = 4 //console is down in a singleplayer game. } paused, oldpaused; float pausedstart; //check player/eyes models for hacks unsigned model_player_checksum; unsigned eyes_player_checksum; // char name[64]; // file map name (moved to svs, for restart) char mapname[256]; // text description of the map char modelname[MAX_QPATH]; // maps/.bsp, for model_precache[0] world_t world; union { #ifdef Q2SERVER struct { const char *configstring[Q2MAX_CONFIGSTRINGS]; const char *q2_extramodels[MAX_PRECACHE_MODELS]; // NULL terminated const char *q2_extrasounds[MAX_PRECACHE_SOUNDS]; // NULL terminated }; #endif struct { #ifdef HAVE_LEGACY const char *vw_model_precache[32]; #endif const char *model_precache[MAX_PRECACHE_MODELS]; // NULL terminated const char *particle_precache[MAX_SSPARTICLESPRE]; // NULL terminated const char *sound_precache[MAX_PRECACHE_SOUNDS]; // NULL terminated }; const char *ptrs[1]; } strings; qboolean stringsalloced; //if true, we need to free the string pointers safely rather than just memsetting them to 0 struct { const char *str; //double dynamic. urgh, but allows it to be nice and long. vec3_t colours; } *lightstyles; size_t maxlightstyles; //limited to MAX_NET_LIGHTSTYLES #ifdef HEXEN2 char h2miditrack[MAX_QPATH]; qbyte h2cdtrack; #endif vec3_t skyroom_pos; //parsed from world._skyroom qboolean skyroom_pos_known; int allocated_client_slots; //number of slots available. (used mostly to stop single player saved games cacking up) int spawned_client_slots; //number of PLAYER slots which are active (ie: putclientinserver was called) int spawned_observer_slots; model_t *models[MAX_PRECACHE_MODELS]; struct client_s *skipbprintclient; //SV_BroadcastPrint skips this client // added to every client's unreliable buffer each frame, then cleared sizebuf_t datagram; qbyte datagram_buf[MAX_DATAGRAM]; // added to every client's reliable buffer each frame, then cleared sizebuf_t reliable_datagram; qbyte reliable_datagram_buf[MAX_QWMSGLEN]; // the multicast buffer is used to send a message to a set of clients sizebuf_t multicast; qbyte multicast_buf[MAX_QWMSGLEN]; #ifdef NQPROT sizebuf_t nqdatagram; qbyte nqdatagram_buf[MAX_NQDATAGRAM]; sizebuf_t nqreliable_datagram; qbyte nqreliable_datagram_buf[MAX_NQMSGLEN]; sizebuf_t nqmulticast; qbyte nqmulticast_buf[MAX_NQMSGLEN]; #endif #ifdef Q2SERVER sizebuf_t q2datagram; qbyte q2datagram_buf[MAX_Q2DATAGRAM]; sizebuf_t q2reliable_datagram; qbyte q2reliable_datagram_buf[MAX_Q2MSGLEN]; sizebuf_t q2multicast; qbyte q2multicast_buf[MAX_Q2MSGLEN]; #endif // the master buffer is used for building log packets sizebuf_t master; qbyte master_buf[MAX_DATAGRAM]; // the signon buffer will be sent to each client as they connect // traditionally includes the entity baselines, the static entities, etc // large levels will have >MAX_DATAGRAM sized signons, so // multiple signon messages are kept // fte only stores writebyted stuff in here. everything else is regenerated based upon the client's extensions. sizebuf_t signon; int used_signon_space; qbyte signon_buffer[MAX_OVERALLMSGLEN]; //flushed after every 512 bytes (two leading bytes says the size of the buffer). qboolean gamedirchanged; qboolean haveitems2; //use items2 field instead of serverflags for the high bits of STAT_ITEMS #ifdef MVD_RECORDING qboolean mvdrecording; #endif //==================================================== //this lot is for serverside playback of mvds. Use QTV instead. #ifdef SERVER_DEMO_PLAYBACK qboolean mvdplayback; float realtime; vfsfile_t *demofile; //also signifies playing the thing. int lasttype; int lastto; //playback spikes (svc_nails/nails2) int numdemospikes; struct { vec3_t org; qbyte id; qbyte pitch; qbyte yaw; qbyte modelindex; } demospikes[255]; //playback of entities (svc_nails/nails2) mvdentity_state_t *demostate; mvdentity_state_t *demobaselines; int demomaxents; qboolean demostatevalid; //players struct { int stats[MAX_CL_STATS]; int pl; int ping; int frags; int userid; int weaponframe; char userinfo[MAX_INFO_STRING]; vec3_t oldorg; vec3_t oldang; float updatetime; } recordedplayer[MAX_CLIENTS]; //gamestate char demoinfo[MAX_SERVERINFO_STRING]; char demmodel_precache[MAX_MODELS][MAX_QPATH]; // NULL terminated char demsound_precache[MAX_SOUNDS][MAX_QPATH]; // NULL terminated char demgamedir[64]; char demname[64]; // map name qboolean democausesreconnect; //this makes current clients go through the connection process (and when the demo ends too) sizebuf_t demosignon; int num_demosignon_buffers; int demosignon_buffer_size[MAX_SIGNON_BUFFERS]; qbyte demosignon_buffers[MAX_SIGNON_BUFFERS][MAX_DATAGRAM]; char demfullmapname[64]; char *demolightstyles[MAX_LIGHTSTYLES]; #endif //==================================================== // movevars_t demomovevars; //FIXME:! //end this lot... (demo playback) int num_static_entities; int num_static_sounds; svcustomtents_t customtents[255]; int *csqcentversion;//prevents ent versions from going backwards } server_t; void SV_WipeServerState(void); /* #define CS_EMPTY 0 #define CS_ZOMBIE (1u<<0) //just stops the slot from being reused for a bit. #define CS_CLUSTER (1u<<1) //is managed by the cluster host (and will appear on scoreboards). #define CS_SPAWNED (1u<<2) //has an active entity. #define CS_ACTIVE (1u<<3) //has a connection #define cs_free (CS_EMPTY) #define cs_zombie (CS_ZOMBIE) #define cs_loadzombie (CS_SPAWNED) #define cs_connected (CS_ACTIVE) #define cs_spawned (CS_ACTIVE|CS_SPAWNED) */ typedef enum { cs_free, // can be reused for a new connection cs_zombie, // client has been disconnected, but don't reuse connection for a couple seconds. entity was already cleared. cs_loadzombie, // slot reserved for a client. the player's entity may or may not be known (istobeloaded says that state). parms _ARE_ known. cs_connected, // has been assigned to a client_t, but not in game yet cs_spawned // client is fully in game } client_conn_state_t; typedef struct { // received from client // reply double senttime; //time we sent this frame to the client, for ping calcs (realtime) int sequence; //the outgoing sequence - without mask, meaning we know if its current or stale float ping_time; //how long it took for the client to ack it, may be negative float move_msecs; // int packetsizein; //amount of data received for this frame int packetsizeout; //amount of data that was sent in the frame packet_entities_t qwentities; //package containing entity states that were sent in this frame, for deltaing struct resendinfo_s { unsigned int entnum; unsigned int bits; //delta (fte or dpp5+) unsigned int flags; //csqc } *resend; unsigned int numresend; unsigned int maxresend; unsigned short resendstats[32];//the number of each entity that was sent in this frame unsigned int numresendstats; //the bits of each entity that were sent in this frame //antilag //these are to recalculate the player's origin without old knockbacks nor teleporters, to give more accurate weapon start positions (post-command). vec3_t pmorigin; vec3_t pmvelocity; int pmtype; unsigned int pmjumpheld:1; unsigned int pmonladder:1; float pmwaterjumptime; usercmd_t cmd; //these are old positions of players, to give more accurate victim positions laggedentinfo_t laggedplayer[MAX_CLIENTS]; unsigned int numlaggedplayers; float laggedtime; //sv.time of when this frame was sent } client_frame_t; #ifdef Q2SERVER typedef struct //merge? { int areabytes; qbyte areabits[MAX_Q2MAP_AREAS/8]; // portalarea visibility bits q2player_state_t ps[MAX_SPLITS]; //yuck int clientnum[MAX_SPLITS]; int num_entities; int first_entity; // into the circular sv_packet_entities[] int senttime; // for ping calculations float ping_time; } q2client_frame_t; #endif #ifdef Q3SERVER #include "clq3defs.h" typedef struct //merge? { int flags; int areabytes; qbyte areabits[MAX_Q2MAP_AREAS/8]; // portalarea visibility bits q3playerState_t ps; int num_entities; int first_entity; // into the circular sv_packet_entities[] int senttime; // for ping calculations int serverMessageNum; int serverCommandNum; int serverTime; // server time the message is valid for (in msec) int localTime; int deltaFrame; } q3client_frame_t; #endif #define MAX_BACK_BUFFERS 16 enum { PRESPAWN_INVALID=0, PRESPAWN_PROTOCOLSWITCH, //nq drops unreliables until reliables are acked. this gives us a chance to drop any clc_move packets with formats from the previous map PRESPAWN_SERVERINFO, #ifdef MVD_RECORDING PRESPAWN_CSPROGS, //demos contain a copy of the csprogs. #endif PRESPAWN_SOUNDLIST, //nq skips these #ifdef HAVE_LEGACY PRESPAWN_VWEPMODELLIST, //qw ugly extension. #endif PRESPAWN_MODELLIST, PRESPAWN_MAPCHECK, //wait for old prespawn command PRESPAWN_PARTICLES, PRESPAWN_CUSTOMTENTS, PRESPAWN_SIGNON_BUF, PRESPAWN_SPAWNSTATIC, PRESPAWN_AMBIENTSOUND, PRESPAWN_BASELINES, PRESPAWN_SPAWN, PRESPAWN_BRUSHES, PRESPAWN_COMPLETED }; enum { //'soft' limits that result in warnings if the client's protocol is too limited. PLIMIT_ENTITIES = 1u<<0, PLIMIT_MODELS = 1u<<1, PLIMIT_SOUNDS = 1u<<2 }; //client_t->spec_print + sv_specprint #define SPECPRINT_CENTERPRINT 0x1 #define SPECPRINT_SPRINT 0x2 #define SPECPRINT_STUFFCMD 0x4 #define STUFFCMD_IGNOREINDEMO ( 1<<0) // do not put in mvd demo #define STUFFCMD_DEMOONLY ( 1<<1) // put in mvd demo only #define STUFFCMD_BROADCAST ( 1<<2) // everyone sees it. #define STUFFCMD_UNRELIABLE ( 1<<3) // someone might not see it. oh well. enum serverprotocols_e { SCP_BAD, //don't send (a bot) SCP_QUAKEWORLD, SCP_QUAKE2, SCP_QUAKE3, //all the below are considered netquake clients. SCP_NETQUAKE, //bjp1, bjp2 SCP_BJP3, //16bit angles,model+sound indexes. nothing else (assume raised ent limits too). SCP_FITZ666, //dp5 SCP_DARKPLACES6, SCP_DARKPLACES7 //extra prediction stuff //note, nq is nq+ }; typedef struct client_s { client_conn_state_t state; unsigned int prespawn_stage; unsigned int prespawn_idx; unsigned int prespawn_idx2; qboolean prespawn_allow_modellist; qboolean prespawn_allow_soundlist; int spectator; // non-interactive int redirect; //1=redirected because full, 2=cluster transfer qboolean sendinfo; // at end of frame, send info to all // this prevents malicious multiple broadcasts float lastnametime; // time of last name change int lastnamecount; // time of last name change unsigned checksum; // checksum for calcs qboolean drop; // lose this guy next opportunity int lossage; // loss percentage int challenge; int userid; // identifying number infobuf_t userinfo; // all of the user's various settings infosync_t infosync; // information about the infos that the client still doesn't know (server and multiple clients). char *transfer; usercmd_t lastcmd; // for filling in big drops and partial predictions double localtime; // of last message qboolean jump_held; qboolean lockangles; //mod is spamming angle changes, don't do relative changes float maxspeed; // localized maxspeed float entgravity; // localized ent gravity int viewent; //fake the entity positioning. int clientcamera; //cache for dp_sv_clientcamera. edict_t *edict; // EDICT_NUM(clientnum+1) //additional game modes use additional edict pointers. this ensures that references are crashes. #ifdef Q2SERVER q2edict_t *q2edict; // EDICT_NUM(clientnum+1) #endif #ifdef HLSERVER struct hledict_s *hledict; #endif int playercolor; int playerclass; char teambuf[32]; char *team; char *name; char namebuf[32]; // for printing to other people // extracted from userinfo char guid[64]; /*+2 for split+pad*/ int messagelevel; // for filtering printed messages int autoaimdot; //smallest dotproduct allowed for autoaim #ifdef HAVE_LEGACY float *dp_ping; float *dp_pl; #endif // the datagram is written to after every frame, but only cleared // when it is sent out to the client. overflow is tolerated. sizebuf_t datagram; qbyte datagram_buf[MAX_OVERALLMSGLEN/2]; // back buffers for client reliable data sizebuf_t backbuf; int num_backbuf; int backbuf_size[MAX_BACK_BUFFERS]; qbyte backbuf_data[MAX_BACK_BUFFERS][MAX_BACKBUFLEN]; double connection_started; // or time of disconnect for zombies qboolean send_message; // set on frames a datagram arived on laggedentinfo_t laggedents[MAX_CLIENTS]; unsigned int laggedents_count; float laggedents_frac; float laggedents_time; // spawn parms are carried from level to level float spawn_parms[NUM_SPAWN_PARMS]; char *spawn_parmstring; //qc-specified data. char *spawninfo; //entity-formatted data (for hexen2's ClientReEnter) float spawninfotime; float nextservertimeupdate; //next time to send STAT_TIME float lastoutgoingphysicstime;//sv.world.physicstime of the last outgoing message. // client known data for deltas int old_frags; unsigned int pendingstats[((MAX_CL_STATS*2) + 31)>>5]; //these are the stats that have changed and that need sending/resending int statsi[MAX_CL_STATS]; float statsf[MAX_CL_STATS]; char *statss[MAX_CL_STATS]; char *centerprintstring; union{ //save space client_frame_t *frames; // updates can be deltad from here #ifdef Q2SERVER q2client_frame_t *q2frames; #endif #ifdef Q3SERVER q3client_frame_t *q3frames; #endif } frameunion; packet_entities_t sentents; unsigned int *pendingdeltabits; unsigned int *pendingcsqcbits; unsigned int nextdeltaindex; //splurged round-robin to deal with overflows unsigned int nextcsqcindex; //splurged round-robin #define SENDFLAGS_USABLE 0x3fffffffu //this number of bits are actually safe in a float. not all together, but otherwise safe. #define SENDFLAGS_PRESENT 0x80000000u //this entity is present on that client #define SENDFLAGS_REMOVED 0x40000000u //to handle remove packetloss #ifdef HAVE_LEGACY char *dlqueue; //name\name delimited list of files to ask the client to download. #endif char downloadfn[MAX_QPATH]; vfsfile_t *download; // file being downloaded qofs_t downloadsize; // total bytes qofs_t downloadcount; // bytes sent #ifdef NQPROT qofs_t downloadacked; //DP-specific qofs_t downloadstarted; //DP-specific #endif int spec_track; // entnum of player tracking unsigned int spec_print; //bitfield for things this spectator should see that were directed to the player that they're tracking. #ifdef Q3SERVER int gamestatesequence; //the sequence number the initial gamestate was sent in. int last_client_command_num; char last_client_command[1024]; //quake3 does reliables only via this mechanism. basically just like q1's stuffcmds. int server_command_ack; //number known to have been received. int server_command_sequence; //number available. char server_commands[64][1024]; //the commands, to deal with resends #endif //true/false/persist unsigned int penalties; qbyte istobeloaded; //loadgame creates place holders for clients to connect to. Effectivly loading a game reconnects all clients, but has precreated ents. qboolean spawned; //the player's entity was spawned. double floodprotmessage; double lastspoke; double lockedtill; float joinobservelockeduntil; qboolean upgradewarn; // did we warn him? vfsfile_t *upload; char uploadfn[MAX_QPATH]; netadr_t snap_from; qboolean remote_snap; //===== NETWORK ============ int chokecount; qboolean waschoked; int delta_sequence; // -1 = no compression int last_sequence; //last inputframe sequence received netchan_t netchan; qboolean isindependant; int lastsequence_acknowledged; #ifdef VOICECHAT unsigned int voice_read; /*place in ring*/ unsigned char voice_mute[(MAX_CLIENTS+7)/8]; qboolean voice_active; enum { /*note - when recording an mvd, only 'all' will be received by non-spectating viewers. all other chat will only be heard when spectating the receiver(or sender) of said chat*/ /*should we add one to respond to the last speaker? or should that be an automagic +voip_reply instead?*/ VT_TEAM, VT_ALL, VT_NONMUTED, /*cheap, but allows custom private channels with no external pesters*/ VT_SPECSELF, /*sends to self, audiable to people spectating self*/ VT_PLAYERSLOT0 /*player0+...*/ } voice_target; #endif #ifdef SVCHAT svchat_t chat; #endif #ifdef SVRANKING int rankid; int kills; int deaths; double stats_started; #endif qboolean csqcactive; qboolean pextknown; unsigned int fteprotocolextensions; unsigned int fteprotocolextensions2; unsigned int ezprotocolextensions1; unsigned int zquake_extensions; unsigned int max_net_ents; /*highest entity number the client can receive (limited by either protocol or client's buffer size)*/ unsigned int max_net_staticents; /*limit to the number of static ents supported by the client*/ unsigned int max_net_clients; /*max number of player slots supported by the client */ unsigned int maxmodels; /*max models supported by whatever the protocol is*/ enum serverprotocols_e protocol; unsigned int supportedprotocols; qboolean proquake_angles_hack; //expect 16bit client->server angles . unsigned int lastruncmd; //for non-qw physics. timestamp they were last run, so switching between physics modes isn't a (significant) cheat //speed cheat testing #define NEWSPEEDCHEATPROT float msecs; #ifndef NEWSPEEDCHEATPROT int msec_cheating; float last_check; #endif qboolean gibfilter; int trustlevel; vec3_t specorigin; //mvds need to use a different origin from the one QC has. vec3_t specvelocity; int language; //the clients language // struct { // qbyte vweap; // } otherclientsknown[MAX_CLIENTS]; //updated as needed. Flag at a time, or all flags. struct client_s *controller; /*first in splitscreen chain, NULL=nosplitscreen*/ struct client_s *controlled; /*next in splitscreen chain*/ /*these are the current rates*/ float ratetime; float inrate; float outrate; int rate; int drate; netadr_t realip; int realip_status; int realip_num; int realip_ping; char *reversedns; unsigned int plimitwarned; float delay; laggedpacket_t *laggedpacket; laggedpacket_t *laggedpacket_last; #ifdef VM_Q1 int hideentity; qboolean hideplayers; #endif } client_t; #if defined(NQPROT) || defined(Q2SERVER) || defined(Q3SERVER) #define ISQWCLIENT(cl) ((cl)->protocol == SCP_QUAKEWORLD) #define ISQ2CLIENT(cl) ((cl)->protocol == SCP_QUAKE2) #define ISQ3CLIENT(cl) ((cl)->protocol == SCP_QUAKE3) #define ISNQCLIENT(cl) ((cl)->protocol >= SCP_NETQUAKE) #define ISDPCLIENT(cl) ((cl)->protocol >= SCP_DARKPLACES6) #else #define ISQWCLIENT(cl) ((cl)->protocol != SCP_BAD) #define ISQ2CLIENT(cl) false #define ISQ3CLIENT(cl) false #define ISNQCLIENT(cl) false #define ISDPCLIENT(cl) false #endif // a client can leave the server in one of four ways: // dropping properly by quiting or disconnecting // timing out if no valid messages are received for timeout.value seconds // getting kicked off by the server operator // a program error, like an overflowed reliable buffer //============================================================================= //mvd stuff #ifdef MVD_RECORDING #define MSG_BUF_SIZE 8192 typedef struct { vec3_t origin; vec3_t angles; int weaponframe; int skinnum; int model; int effects; } demoinfo_t; typedef struct { demoinfo_t info; float sec; int parsecount; qboolean fixangle; vec3_t angle; float cmdtime; int flags; int frame; } demo_client_t; typedef struct { qbyte type; qbyte full; int to; int size; qbyte data[1]; //gcc doesn't allow [] (?) } mvd_header_t; typedef struct { sizebuf_t sb; int bufsize; mvd_header_t *h; } demobuf_t; typedef struct { demo_client_t clients[MAX_CLIENTS]; double time; demobuf_t buf; } demo_frame_t; typedef struct { qbyte *data; int start, end, last; int maxsize; } dbuffer_t; #define DEMO_FRAMES 64 //why is this not just 2? #define DEMO_FRAMES_MASK (DEMO_FRAMES - 1) typedef struct { // demobuf_t *dbuf; // dbuffer_t dbuffer; sizebuf_t datagram; qbyte datagram_data[MSG_BUF_SIZE]; int lastto; int lasttype; double time, pingtime; int statsi[MAX_CLIENTS][MAX_CL_STATS]; // ouch! float statsf[MAX_CLIENTS][MAX_CL_STATS]; // ouch! char *statss[MAX_CLIENTS][MAX_CL_STATS]; // ouch! client_t recorder; qboolean playerreset[MAX_CLIENTS]; //will ensure that the model etc is written when this player is next written. qboolean fixangle[MAX_CLIENTS]; float fixangletime[MAX_CLIENTS]; vec3_t angles[MAX_CLIENTS]; qboolean resetdeltas; int parsecount; int lastwritten; demo_frame_t frames[DEMO_FRAMES]; demoinfo_t info[MAX_CLIENTS]; qbyte buffer[20*MAX_QWMSGLEN]; int bufsize; int forceFrame; struct mvddest_s *dest; } demo_t; #endif //============================================================================= #define SVSTATS_PERIOD 10 typedef struct { double active; double idle; int count; int packets; double maxresponse; //longest (active) frame time within the current period int maxpackets; //max packet count in a single frame double latched_time; //time that the current period ends double latched_active; //active time in the last period double latched_idle; int latched_count; int latched_packets; int latched_maxpackets; double latched_maxresponse; } svstats_t; // MAX_CHALLENGES is made large to prevent a denial // of service attack that could cycle all of them // out before legitimate users connected #define MAX_CHALLENGES 1024 typedef struct { netadr_t adr; int challenge; int time; } challenge_t; typedef struct bannedips_s { unsigned int banflags; struct bannedips_s *next; netadr_t adr; netadr_t adrmask; time_t expiretime; char reason[1]; } bannedips_t; typedef enum { GT_PROGS, //q1, qw, h2 are similar enough that we consider it only one game mode. (We don't support the h2 protocol) GT_Q1QVM, GT_HALFLIFE, GT_QUAKE2, //q2 servers run from a q2 game dll GT_QUAKE3, //q3 servers run off the q3 qvm api #ifdef VM_LUA GT_LUA, //for the luls #endif GT_MAX } gametype_e; typedef struct levelcache_s { struct levelcache_s *next; char *mapname; gametype_e gametype; unsigned char savedplayers[(MAX_CLIENTS+7)>>3]; //bitmask to say which players are actually stored in the cache. so that restarts can restore. } levelcache_t; #ifdef TCPCONNECT typedef struct svtcpstream_s { int socketnum; int inlen; qboolean waitingforprotocolconfirmation; char inbuffer[1500]; float timeouttime; netadr_t remoteaddr; struct svtcpstream_s *next; } svtcpstream_t; #endif typedef struct { gametype_e gametype; int spawncount; // number of servers spawned since start, // used to check late spawns int framenum; //physics frame number for out-of-sequence thinks (fix for slow rockets) int clusterserverid; // which server we are in the cluster. for gamecode to track with stats. struct ftenet_connections_s *sockets; int allocated_client_slots; //number of entries in the clients array client_t *clients; //[svs.allocated_client_slots] int serverflags; // episode completion information double last_heartbeat; int heartbeat_sequence; svstats_t stats; infobuf_t info; infobuf_t localinfo; // log messages are used so that fraglog processes can get stats int logsequence; // the message currently being filled double logtime; // time of last swap #define FRAGLOG_BUFFERS 8 sizebuf_t log[FRAGLOG_BUFFERS]; qbyte log_buf[FRAGLOG_BUFFERS][MAX_DATAGRAM]; challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting bannedips_t *bannedips; char progsnames[MAX_PROGS][MAX_QPATH]; progsnum_t progsnum[MAX_PROGS]; int numprogs; struct netprim_s netprim; laggedpacket_t *free_lagged_packet; packet_entities_t entstatebuffer; /*just a temp buffer*/ char name[64]; // map name (base filename). static because of restart command after disconnecting. levelcache_t *levcache; struct frameendtasks_s { struct frameendtasks_s *next; void(*callback)(struct frameendtasks_s *task); void *ctxptr; intptr_t ctxint; char data[1]; } *frameendtasks; } server_static_t; //============================================================================= /* // edict->movetype values #define MOVETYPE_NONE 0 // never moves #define MOVETYPE_ANGLENOCLIP 1 #define MOVETYPE_ANGLECLIP 2 #define MOVETYPE_WALK 3 // gravity #define MOVETYPE_STEP 4 // gravity, special edge handling #define MOVETYPE_FLY 5 #define MOVETYPE_TOSS 6 // gravity #define MOVETYPE_PUSH 7 // no clip to world, push and crush #define MOVETYPE_NOCLIP 8 #define MOVETYPE_FLYMISSILE 9 // extra size to monsters #define MOVETYPE_BOUNCE 10 #define MOVETYPE_BOUNCEMISSILE 11 // bounce w/o gravity #define MOVETYPE_FOLLOW 12 // track movement of aiment #define MOVETYPE_H2PUSHPULL 13 // pushable/pullable object #define MOVETYPE_H2SWIM 14 // should keep the object in water #define MOVETYPE_PHYSICS 32 #define MOVETYPE_FLY_WORLDONLY 33 // edict->solid values #define SOLID_NOT 0 // no interaction with other objects #define SOLID_TRIGGER 1 // touch on edge, but not blocking #define SOLID_BBOX 2 // touch on edge, block #define SOLID_SLIDEBOX 3 // touch on edge, but not an onground #define SOLID_BSP 4 // bsp clip, touch on edge, block #define SOLID_PHASEH2 5 #define SOLID_CORPSE 5 #define SOLID_LADDER 20 //dmw. touch on edge, not blocking. Touching players have different physics. Otherwise a SOLID_TRIGGER. deprecated. use solid_bsp and skin=-16 #define DAMAGE_NO 0 #define DAMAGE_YES 1 #define DAMAGE_AIM 2 */ #define PVSF_NORMALPVS 0x0 #define PVSF_NOTRACECHECK 0x1 #define PVSF_USEPHS 0x2 #define PVSF_IGNOREPVS 0x3 #define PVSF_MODE_MASK 0x3 #define PVSF_NOREMOVE 0x80 // entity effects //define EF_BRIGHTFIELD 1 //define EF_MUZZLEFLASH 2 //#define EF_BRIGHTLIGHT (1<<2) //#define EF_DIMLIGHT (1<<4) //#define EF_FULLBRIGHT 512 #define SPAWNFLAG_NOT_EASY (1<<8) #define SPAWNFLAG_NOT_MEDIUM (1<<9) #define SPAWNFLAG_NOT_HARD (1<<10) #define SPAWNFLAG_NOT_DEATHMATCH (1<<11) #define SPAWNFLAG_NOT_H2PALADIN (1<<8) #define SPAWNFLAG_NOT_H2CLERIC (1<<9) #define SPAWNFLAG_NOT_H2NECROMANCER (1<<10) #define SPAWNFLAG_NOT_H2THEIF (1<<11) #define SPAWNFLAG_NOT_H2EASY (1<<12) #define SPAWNFLAG_NOT_H2MEDIUM (1<<13) #define SPAWNFLAG_NOT_H2HARD (1<<14) #define SPAWNFLAG_NOT_H2DEATHMATCH (1<<15) #define SPAWNFLAG_NOT_H2COOP (1<<16) #define SPAWNFLAG_NOT_H2SINGLE (1<<17) #if 0//ndef Q2SERVER typedef enum multicast_e { MULTICAST_ALL, MULTICAST_PHS, MULTICAST_PVS, MULTICAST_ALL_R, MULTICAST_PHS_R, MULTICAST_PVS_R } multicast_t; #endif //shared with qc #define MSG_PRERELONE -100 #define MSG_BROADCAST 0 // unreliable to all #define MSG_ONE 1 // reliable to one (msg_entity) #define MSG_ALL 2 // reliable to all #define MSG_INIT 3 // write to the init string #define MSG_MULTICAST 4 // for multicast() #define MSG_CSQC 5 // for writing csqc entities //============================================================================ extern cvar_t sv_mintic, sv_maxtic, sv_limittics; extern cvar_t sv_maxspeed; extern cvar_t sv_antilag; extern cvar_t sv_antilag_frac; void SV_Master_ReResolve(void); void SV_Master_Shutdown(void); void SV_Master_Heartbeat (void); extern cvar_t pr_ssqc_progs; extern cvar_t spawn; extern cvar_t teamplay; extern cvar_t deathmatch; extern cvar_t coop; extern cvar_t fraglimit; extern cvar_t timelimit; extern server_static_t svs; // persistant server info extern server_t sv; // local server extern client_t *host_client; extern edict_t *sv_player; //extern char localmodels[MAX_MODELS][5]; // inline model names for precache extern vfsfile_t *sv_fraglogfile; //=========================================================== void SV_AddDebugPolygons(void); const char *SV_CheckRejectConnection(netadr_t *adr, const char *uinfo, unsigned int protocol, unsigned int pext1, unsigned int pext2, unsigned int ezpext1, char *guid); // //sv_ccmds.c // char *SV_BannedReason (netadr_t *a); void SV_EvaluatePenalties(client_t *cl); void SV_AutoAddPenalty (client_t *cl, unsigned int banflag, int duration, char *reason); //note: not all penalties are actually penalties, but they can still expire. #define BAN_BAN (1u<<0) //user is banned from the server #define BAN_PERMIT (1u<<1) //+user can evade block bans or filterban #define BAN_CUFF (1u<<2) //can't shoot/use impulses #define BAN_MUTE (1u<<3) //can't use say/say_team/voip #define BAN_CRIPPLED (1u<<4) //can't move #define BAN_DEAF (1u<<5) //can't see say/say_team #define BAN_LAGGED (1u<<6) //given an extra 200ms #define BAN_VIP (1u<<7) //+mods might give the user special rights, via the *VIP infokey. the engine itself currently does not do anything but track it. #define BAN_BLIND (1u<<8) //player's pvs is wiped. #define BAN_SPECONLY (1u<<9) //player is forced to spectate #define BAN_STEALTH (1u<<10)//player is not told of their bans #define BAN_USER1 (1u<<11)//mod-specified #define BAN_USER2 (1u<<12)//mod-specified #define BAN_USER3 (1u<<13)//mod-specified #define BAN_USER4 (1u<<14)//mod-specified #define BAN_USER5 (1u<<15)//mod-specified #define BAN_USER6 (1u<<16)//mod-specified #define BAN_USER7 (1u<<17)//mod-specified #define BAN_USER8 (1u<<18)//mod-specified #define BAN_MAPPER (1u<<19)//+player is allowed to use the brush/entity editing clc. #define BAN_VMUTE (1u<<20)//can't use voip (but can still use other forms of chat) #define BAN_NOLOCALHOST (BAN_BAN|BAN_PERMIT|BAN_SPECONLY) //any attempt to ban localhost is denied, but you can vip, lag, cripple, etc them. // // sv_main.c // NORETURN void VARGS SV_Error (char *error, ...) LIKEPRINTF(1); void SV_Shutdown (void); float SV_Frame (void); void SV_FinalMessage (char *message); void SV_DropClient (client_t *drop); struct quakeparms_s; void SV_Init (struct quakeparms_s *parms); void SV_ExecInitialConfigs(char *defaultexec); void SV_ArgumentOverrides(void); int SV_CalcPing (client_t *cl, qboolean forcecalc); void SV_FullClientUpdate (client_t *client, client_t *to); char *SV_PlayerPublicAddress(client_t *cl); qboolean SVC_GetChallenge (qboolean respond_dp); int SV_NewChallenge (void); void SVC_DirectConnect(int expectedreliablesequence); typedef struct { enum serverprotocols_e protocol; //protocol used to talk to this client. #ifdef NQPROT qboolean proquakeanglehack; //specifies that the client will expect proquake angles if we give a proquake CCREP_ACCEPT response. unsigned int expectedreliablesequence; //required for nq connection cookies (like tcp's syn cookies). unsigned int supportedprotocols; //1<32 quint64_t created; quint64_t lastseen; #endif } rankstats_t; typedef struct { //name, identity and order. int prev; //score is held for convineance. int next; char name[32]; int pwd; float score; } rankheader_t; typedef struct { rankheader_t h; rankstats_t s; } rankinfo_t; int Rank_GetPlayerID(char *guid, const char *name, int pwd, qboolean allowcreate, qboolean requirepasswordtobeset); void Rank_SetPlayerStats(int id, rankstats_t *stats); rankstats_t *Rank_GetPlayerStats(int id, rankstats_t *buffer); rankinfo_t *Rank_GetPlayerInfo(int id, rankinfo_t *buffer); qboolean Rank_OpenRankings(void); void Rank_Flush (void); void Rank_ListTop10_f (void); void Rank_RegisterCommands(void); int Rank_GetPass (char *name); extern cvar_t rank_needlogin; qboolean ReloadRanking(client_t *cl, const char *newname); #endif client_t *SV_GetClientForString(const char *name, int *id); qboolean SV_MayCheat(void); void NPP_Flush(void); void NPP_NQWriteByte(int dest, qbyte data); void NPP_NQWriteChar(int dest, char data); void NPP_NQWriteShort(int dest, short data); void NPP_NQWriteLong(int dest, long data); void NPP_NQWriteAngle(int dest, float data); void NPP_NQWriteCoord(int dest, float data); void NPP_NQWriteFloat(int dest, float data); void NPP_NQWriteString(int dest, const char *data); void NPP_NQWriteEntity(int dest, int data); void NPP_QWWriteByte(int dest, qbyte data); void NPP_QWWriteChar(int dest, char data); void NPP_QWWriteShort(int dest, short data); void NPP_QWWriteLong(int dest, long data); void NPP_QWWriteAngle(int dest, float data); void NPP_QWWriteCoord(int dest, float data); void NPP_QWWriteFloat(int dest, float data); void NPP_QWWriteString(int dest, const char *data); void NPP_QWWriteEntity(int dest, int data); void NPP_MVDForceFlush(void); //replacement rand function (useful cos it's fully portable, with seed grabbing) void predictablesrand(unsigned int x); int predictablerandgetseed(void); int predictablerand(void); #ifdef SVCHAT void SV_WipeChat(client_t *client); int SV_ChatMove(int impulse); void SV_ChatThink(client_t *client); #endif #ifdef MVD_RECORDING /* // // sv_mvd.c // //qtv proxies are meant to send a small header now, bit like http //this header gives supported version numbers and stuff typedef struct mvdpendingdest_s { qboolean error; //disables writers, quit ASAP. #ifdef _WIN32 qintptr_t socket; #else int socket; #endif char inbuffer[2048]; char outbuffer[2048]; char challenge[64]; qboolean hasauthed; qboolean isreverse; int insize; int outsize; struct mvdpendingdest_s *nextdest; } mvdpendingdest_t;*/ typedef struct mvddest_s { qboolean error; //disables writers, quit ASAP. qboolean droponmapchange; enum {DEST_NONE, DEST_FILE, DEST_BUFFEREDFILE, DEST_THREADEDFILE, DEST_STREAM} desttype; vfsfile_t *file; int id; char filename[MAX_QPATH]; //demos/foo.mvd (or a username) char simplename[MAX_QPATH]; //foo.mvd (or a qtv resource) int flushing; //worker has a cache (used as a sync point) char *cache; char *altcache; int cacheused; int maxcachesize; unsigned int totalsize; struct mvddest_s *nextdest; } mvddest_t; void SV_MVDPings (void); void SV_MVD_FullClientUpdate(sizebuf_t *msg, client_t *player); sizebuf_t *MVDWrite_Begin(qbyte type, int to, int size); void MVDSetMsgBuf(demobuf_t *prev,demobuf_t *cur); enum mvdclosereason_e { MVD_CLOSE_STOPPED, MVD_CLOSE_SIZELIMIT, MVD_CLOSE_CANCEL, MVD_CLOSE_DISCONNECTED, //qtv disconnected MVD_CLOSE_FSERROR }; void SV_MVDStop (enum mvdclosereason_e reason, qboolean mvdonly); void SV_MVDStop_f (void); qboolean SV_MVDWritePackets (int num); void MVD_Init (void); void SV_MVD_RunPendingConnections(void); void SV_MVD_SendInitialGamestate(mvddest_t *dest); extern demo_t demo; // server demo struct extern cvar_t sv_demoDir, sv_demoDirAlt; extern cvar_t sv_demoAutoRecord; extern cvar_t sv_demofps; extern cvar_t sv_demoPings; extern cvar_t sv_demoUseCache; extern cvar_t sv_demoMaxSize; extern cvar_t sv_demoMaxDirSize; qboolean MVD_CheckSpace(qboolean broadcastwarnings); void SV_MVD_AutoRecord (void); char *SV_Demo_CurrentOutput(void); void SV_Demo_PrintOutputs(void); void SV_MVDInit(void); char *SV_MVDNum(char *buffer, int bufferlen, int num); const char *SV_MVDLastNum(unsigned int num); void SV_SendMVDMessage(void); void SV_MVD_WriteReliables(qboolean writebroadcasts); qboolean SV_ReadMVD (void); void SV_FlushDemoSignon (void); void DestFlush(qboolean compleate); typedef struct { qboolean hasauthed; qboolean isreverse; char challenge[64]; } qtvpendingstate_t; int SV_MVD_GotQTVRequest(vfsfile_t *clientstream, char *headerstart, char *headerend, qtvpendingstate_t *p); #endif // savegame.c void SV_Savegame_f (void); void SV_Savegame_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx); void SV_Loadgame_f (void); qboolean SV_Loadgame (const char *unsafe_savename); void SV_AutoSave(void); void SV_FlushLevelCache(void); extern cvar_t sv_autosave; extern cvar_t sv_savefmt; int SV_RateForClient(client_t *cl); void SVVC_Frame (qboolean enabled); void SV_CalcPHS (void); void SV_GetConsoleCommands (void); void SV_CheckTimer(void); void SV_LogPlayer(client_t *cl, char *msg); extern vec3_t pmove_mins, pmove_maxs; //abs min/max extents #ifdef USEAREAGRID void AddAllLinksToPmove (world_t *w, wedict_t *player); #else void AddLinksToPmove (world_t *w, wedict_t *player, areanode_t *node); void AddLinksToPmove_Force (world_t *w, wedict_t *player, areanode_t *node); #define AddAllLinksToPmove(w,p) do{AddLinksToPmove(w,p,(w)->areanodes);AddLinksToPmove_Force(w,p,&(w)->portallist);}while(0) #endif #ifdef HLSERVER void SVHL_SaveLevelCache(char *filename); //network frame info void SVHL_Snapshot_Build(client_t *client, packet_entities_t *pack, qbyte *pvs, edict_t *clent, qboolean ignorepvs); qbyte *SVHL_Snapshot_SetupPVS(client_t *client, qbyte *pvs, unsigned int pvsbufsize); void SVHL_BuildStats(client_t *client, int *si, float *sf, char **ss); //gamecode entry points int SVHL_InitGame(void); void SVHL_SetupGame(void); void SVHL_SpawnEntities(char *entstring); void SVHL_RunFrame (void); qboolean SVHL_ClientConnect(client_t *client, netadr_t adr, char rejectmessage[128]); void SVHL_PutClientInServer(client_t *client); void SVHL_RunPlayerCommand(client_t *cl, usercmd_t *oldest, usercmd_t *oldcmd, usercmd_t *newcmd); qboolean HLSV_ClientCommand(client_t *client); void SVHL_DropClient(client_t *drop); void SVHL_ShutdownGame(void); #endif