/* 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 #define MAX_SIGNON_BUFFERS 16 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; double autosave_time; 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; 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 { const char *vw_model_precache[32]; 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 *lightstyles[MAX_LIGHTSTYLES]; }; const char *ptrs[1]; } strings; qboolean stringsalloced; //if true, we need to free the string pointers safely rather than just memsetting them to 0 vec3_t lightstylecolours[MAX_LIGHTSTYLES]; char h2miditrack[MAX_QPATH]; qbyte h2cdtrack; 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 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]; // 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 num_signon_buffers; int signon_buffer_size[MAX_SIGNON_BUFFERS]; qbyte signon_buffers[MAX_SIGNON_BUFFERS][MAX_DATAGRAM]; qboolean msgfromdemo; qboolean gamedirchanged; qboolean haveitems2; //use items2 field instead of serverflags for the high bits of STAT_ITEMS qboolean mvdrecording; //==================================================== //this lot is for serverside playback of demos #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 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 vec3_t playerpositions[MAX_CLIENTS]; //where each player was in this frame, for antilag qboolean playerpresent[MAX_CLIENTS]; //whether the player was actually present } 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, PRESPAWN_SOUNDLIST, //nq skips these PRESPAWN_VWEPMODELLIST, //qw ugly extension. 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. 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 char userinfo[EXTENDED_INFO_STRING]; // infostring 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. 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 // 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; // 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 char downloadfn[MAX_QPATH]; vfsfile_t *download; // file being downloaded qofs_t downloadsize; // total bytes qofs_t downloadcount; // bytes sent qofs_t downloadacked; //DP-specific qofs_t downloadstarted; //DP-specific 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_server_command_num; int last_client_command_num; int num_server_commands; int num_client_commands; char server_commands[64][1024]; char last_client_command[1024]; #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. 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; 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; #ifdef PROTOCOL_VERSION_FTE qboolean pextknown; unsigned int fteprotocolextensions; unsigned int fteprotocolextensions2; #endif 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_clients; /*max number of player slots supported by the client */ unsigned int maxmodels; /*max models supported by whatever the protocol is*/ enum { SCP_BAD, //don't send (a bot) SCP_QUAKEWORLD, SCP_QUAKE2, SCP_QUAKE3, //all the below are considered netquake clients. SCP_NETQUAKE, SCP_BJP3, //16bit angles,model+sound indexes. nothing else (assume raised ent limits too). SCP_FITZ666, SCP_DARKPLACES6, SCP_DARKPLACES7 //extra prediction stuff //note, nq is nq+ } 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 int msecs; #ifndef NEWSPEEDCHEATPROT int msec_cheating; float last_check; #endif qboolean gibfilter; int trustlevel; qboolean wasrecorded; //this client shouldn't get any net messages sent to them 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; } 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 #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 [] (?) } header_t; typedef struct { sizebuf_t sb; int bufsize; 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; //============================================================================= #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, #ifdef VM_LUA GT_LUA, //for the luls #endif GT_HALFLIFE, GT_QUAKE2, //q2 servers run from a q2 game dll GT_QUAKE3, //q3 servers run off the q3 qvm api GT_MAX } gametype_e; typedef struct levelcache_s { struct levelcache_s *next; char *mapname; gametype_e gametype; } 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; char info[MAX_SERVERINFO_STRING]; // 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; qboolean demoplayback; qboolean demorecording; qboolean msgfromdemo; int language; //the server operators language 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 char localinfo[MAX_LOCALINFO_STRING+1]; 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, 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); #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 #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_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); void SV_GeneratePublicUserInfo(int pext, client_t *cl, char *info, int infolength); char *SV_PlayerPublicAddress(client_t *cl); qboolean SVC_GetChallenge (qboolean respond_dp); int SV_NewChallenge (void); client_t *SVC_DirectConnect(void); int SV_ModelIndex (const char *name); void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg); void SVQW_WriteDelta (entity_state_t *from, entity_state_t *to, sizebuf_t *msg, qboolean force, unsigned int protext); client_t *SV_AddSplit(client_t *controller, char *info, int id); void SV_SpawnParmsToQC(client_t *client); void SV_SpawnParmsToClient(client_t *client); void SV_GetNewSpawnParms(client_t *cl); void SV_SaveSpawnparms (void); void SV_SaveSpawnparmsClient(client_t *client, float *transferparms); //if transferparms, calls SetTransferParms instead, and does not modify the player. void SV_SaveLevelCache(const char *savename, qboolean dontharmgame); void SV_Savegame (const char *savename, qboolean autosave); qboolean SV_LoadLevelCache(const char *savename, const char *level, const char *startspot, qboolean ignoreplayers); void SV_Physics_Client (edict_t *ent, int num); void SV_ExecuteUserCommand (char *s, qboolean fromQC); void SV_InitOperatorCommands (void); void SV_SendServerinfo (client_t *client); void SV_ExtractFromUserinfo (client_t *cl, qboolean verbose); void SV_SaveInfos(vfsfile_t *f); void SV_FixupName(char *in, char *out, unsigned int outlen); #ifdef SUBSERVERS //cluster stuff typedef struct pubsubserver_s { struct { void (*InstructSlave)(struct pubsubserver_s *ps, sizebuf_t *cmd); //send to. first two bytes of the message should be ignored (overwrite them to carry size) int (*SubServerRead)(struct pubsubserver_s *ps); //read from. fills up net_message } funcs; struct pubsubserver_s *next; unsigned int id; char name[64]; int activeplayers; int transferingplayers; netadr_t addrv4; netadr_t addrv6; } pubsubserver_t; extern qboolean isClusterSlave; void SSV_UpdateAddresses(void); void SSV_InitiatePlayerTransfer(client_t *cl, const char *newserver); void SSV_InstructMaster(sizebuf_t *cmd); void SSV_CheckFromMaster(void); void SSV_PrintToMaster(char *s); void SSV_ReadFromControlServer(void); void SSV_SavePlayerStats(client_t *cl, int reason); //initial, periodic (in case of node crashes), part void SSV_RequestShutdown(void); //asks the cluster to not send us new players pubsubserver_t *Sys_ForkServer(void); void Sys_InstructMaster(sizebuf_t *cmd); //first two bytes will always be the length of the data #define SSV_IsSubServer() isClusterSlave void MSV_SubServerCommand_f(void); void MSV_SubServerCommand_f(void); void MSV_MapCluster_f(void); void SSV_Send(const char *dest, const char *src, const char *cmd, const char *msg); qboolean MSV_ClusterLogin(char *guid, char *userinfo, size_t userinfosize); void MSV_PollSlaves(void); void MSV_Status(void); #else #define SSV_UpdateAddresses() ((void)0) #define MSV_ClusterLogin(guid,info,infosize) false #define SSV_IsSubServer() false #endif // // sv_init.c // void SV_SpawnServer (const char *server, const char *startspot, qboolean noents, qboolean usecinematic); void SV_UnspawnServer (void); void SV_FlushSignon (void); void SV_UpdateMaxPlayers(int newmax); void SV_FilterImpulseInit(void); qboolean SV_FilterImpulse(int imp, int level); //svq2_game.c qboolean SVQ2_InitGameProgs(void); void VARGS SVQ2_ShutdownGameProgs (void); //svq2_ents.c void SVQ2_BuildClientFrame (client_t *client); void SVQ2_WriteFrameToClient (client_t *client, sizebuf_t *msg); #ifdef Q2SERVER void MSGQ2_WriteDeltaEntity (q2entity_state_t *from, q2entity_state_t *to, sizebuf_t *msg, qboolean force, qboolean newentity); void SVQ2_BuildBaselines(void); #endif //q3 stuff #ifdef Q3SERVER void SVQ3_ShutdownGame(void); qboolean SVQ3_InitGame(void); qboolean SVQ3_ConsoleCommand(void); qboolean SVQ3_HandleClient(void); void SVQ3_DirectConnect(void); void SVQ3_NewMapConnects(void); void SVQ3_DropClient(client_t *cl); int SVQ3_AddBot(void); void SVQ3_RunFrame(void); void SVQ3_SendMessage(client_t *client); qboolean SVQ3_Command(void); #endif // // sv_send.c // void SV_CalcNetRates(client_t *cl, double *ftime, int *frames, double *minf, double *maxf); //gets received framerate etc info qboolean SV_ChallengePasses(int challenge); void SV_QCStatName(int type, char *name, int statnum); void SV_QCStatFieldIdx(int type, unsigned int fieldindex, int statnum); void SV_QCStatGlobal(int type, char *globalname, int statnum); void SV_QCStatPtr(int type, void *ptr, int statnum); void SV_ClearQCStats(void); void SV_SendClientMessages (void); void VARGS SV_Multicast (vec3_t origin, multicast_t to); #define FULLDIMENSIONMASK 0xffffffff void SV_MulticastProtExt(vec3_t origin, multicast_t to, int dimension_mask, int with, int without); void SV_MulticastCB(vec3_t origin, multicast_t to, int dimension_mask, void (*callback)(client_t *cl, sizebuf_t *msg, void *ctx), void *ctx); void SV_StartSound (int ent, vec3_t origin, float *velocity, int seenmask, int channel, const char *sample, int volume, float attenuation, float pitchadj, float timeofs, unsigned int flags); void QDECL SVQ1_StartSound (float *origin, wedict_t *entity, int channel, const char *sample, int volume, float attenuation, float pitchadj, float timeofs, unsigned int chflags); void SV_PrintToClient(client_t *cl, int level, const char *string); void SV_TPrintToClient(client_t *cl, int level, const char *string); void SV_StuffcmdToClient(client_t *cl, const char *string); void VARGS SV_ClientPrintf (client_t *cl, int level, const char *fmt, ...) LIKEPRINTF(3); void VARGS SV_ClientTPrintf (client_t *cl, int level, translation_t text, ...); void VARGS SV_BroadcastPrintf (int level, const char *fmt, ...) LIKEPRINTF(2); void VARGS SV_BroadcastTPrintf (int level, translation_t fmt, ...); void VARGS SV_BroadcastCommand (const char *fmt, ...) LIKEPRINTF(1); void SV_SendServerInfoChange(const char *key, const char *value); void SV_SendMessagesToAll (void); void SV_FindModelNumbers (void); void SV_BroadcastUserinfoChange(client_t *about, qboolean isbasic, const char *key, const char *newval); // // sv_user.c // #ifdef NQPROT void SVNQ_New_f (void); void SVNQ_ExecuteClientMessage (client_t *cl); #endif qboolean SV_UserInfoIsBasic(const char *infoname); //standard message. void SV_ExecuteClientMessage (client_t *cl); void SVQ2_ExecuteClientMessage (client_t *cl); int SV_PMTypeForClient (client_t *cl, edict_t *ent); void SV_UserInit (void); qboolean SV_TogglePause (client_t *cl); #ifdef PEXT2_VOICECHAT void SV_VoiceInitClient(client_t *client); void SV_VoiceSendPacket(client_t *client, sizebuf_t *buf); #endif void SV_ClientThink (void); void SV_Begin_Core(client_t *split); void VoteFlushAll(void); void SV_SetUpClientEdict (client_t *cl, edict_t *ent); void SV_UpdateToReliableMessages (void); void SV_FlushBroadcasts (void); qboolean SV_CanTrack(client_t *client, int entity); void SV_DarkPlacesDownloadChunk(client_t *cl, sizebuf_t *msg); void SV_New_f (void); void SV_PreRunCmd(void); void SV_RunCmd (usercmd_t *ucmd, qboolean recurse); void SV_PostRunCmd(void); void SV_RunCmdCleanup(void); void SV_SendClientPrespawnInfo(client_t *client); void SV_ClientProtocolExtensionsChanged(client_t *client); //sv_master.c void SVM_Think(int port); // // svonly.c // typedef enum {RD_NONE, RD_CLIENT, RD_PACKET, RD_PACKET_LOG, RD_OBLIVION, RD_MASTER} redirect_t; //oblivion is provided so people can read the output before the buffer is wiped. void SV_BeginRedirect (redirect_t rd, int lang); void SV_EndRedirect (void); qboolean PR_GameCodePacket(char *s); qboolean PR_GameCodePausedTic(float pausedtime); qboolean PR_ShouldTogglePause(client_t *initiator, qboolean pausedornot); // // sv_ents.c // void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignorepvs); void SVFTE_EmitBaseline(entity_state_t *to, qboolean numberisimportant, sizebuf_t *msg, unsigned int pext2); void SVQ3Q1_BuildEntityPacket(client_t *client, packet_entities_t *pack); void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *client, packet_entities_t *pack); int SV_HullNumForPlayer(int h2hull, float *mins, float *maxs); void SV_GibFilterInit(void); void SV_GibFilterPurge(void); void SV_CleanupEnts(void); void SV_ProcessSendFlags(client_t *c); void SV_AckEntityFrame(client_t *cl, int framenum); void SV_ReplaceEntityFrame(client_t *cl, int framenum); // // sv_nchan.c // void ClientReliableCheckBlock(client_t *cl, int maxsize); void ClientReliable_FinishWrite(client_t *cl); void ClientReliableWrite_Begin(client_t *cl, int c, int maxsize); client_t *ClientReliableWrite_BeginSplit(client_t *cl, int svc, int svclen); void ClientReliableWrite_Angle(client_t *cl, float f); void ClientReliableWrite_Angle16(client_t *cl, float f); void ClientReliableWrite_Byte(client_t *cl, int c); void ClientReliableWrite_Char(client_t *cl, int c); void ClientReliableWrite_Float(client_t *cl, float f); void ClientReliableWrite_Coord(client_t *cl, float f); void ClientReliableWrite_Long(client_t *cl, int c); void ClientReliableWrite_Short(client_t *cl, int c); void ClientReliableWrite_Entity(client_t *cl, int c); void ClientReliableWrite_String(client_t *cl, const char *s); void ClientReliableWrite_SZ(client_t *cl, const void *data, int len); #ifdef SVRANKING //flags #define RANK_MUTED 2 #define RANK_CUFFED 4 #define RANK_CRIPPLED 8 //ha ha... get speed cheaters with this!... :o) #define NUM_RANK_SPAWN_PARMS 32 typedef struct { //stats info int kills; int deaths; float parm[NUM_RANK_SPAWN_PARMS]; float timeonserver; qbyte flags1; qbyte trustlevel; char pad2; char pad3; #if NUM_RANK_SPAWN_PARMS>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 /* // // 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; char filename[MAX_QPATH]; //demos/foo.mvd char simplename[MAX_QPATH]; //foo.mvd 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_demofps; extern cvar_t sv_demoPings; extern cvar_t sv_demoUseCache; extern cvar_t sv_demoMaxSize; extern cvar_t sv_demoMaxDirSize; 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[32]; } qtvpendingstate_t; int SV_MVD_GotQTVRequest(vfsfile_t *clientstream, char *headerstart, char *headerend, qtvpendingstate_t *p); // savegame.c void SV_LegacySavegame_f(void); void SV_Savegame_f (void); void SV_Loadgame_f (void); void SV_AutoSave(void); void SV_FlushLevelCache(void); extern cvar_t sv_autosave; 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 void AddLinksToPmove ( edict_t *player, areanode_t *node ); void AddLinksToPmove_Force ( edict_t *player, areanode_t *node ); #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