/* =========================================================================== Wolfenstein: Enemy Territory GPL Source Code Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company. This file is part of the Wolfenstein: Enemy Territory GPL Source Code (“Wolf ET Source Code”). Wolf ET Source Code 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 3 of the License, or (at your option) any later version. Wolf ET Source Code 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 Wolf ET Source Code. If not, see . In addition, the Wolf: ET Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Wolf ET Source Code. If not, please request a copy in writing from id Software at the address below. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. =========================================================================== */ // server.h #include "../game/q_shared.h" #include "../qcommon/qcommon.h" #include "../game/g_public.h" #include "../game/bg_public.h" //bani #ifdef __GNUC__ #define _attribute( x ) __attribute__( x ) #else #define _attribute( x ) #endif //============================================================================= #define PERS_SCORE 0 // !!! MUST NOT CHANGE, SERVER AND // GAME BOTH REFERENCE !!! #define MAX_ENT_CLUSTERS 16 #define MAX_BPS_WINDOW 20 // NERVE - SMF - net debugging typedef struct svEntity_s { struct worldSector_s *worldSector; struct svEntity_s *nextEntityInWorldSector; entityState_t baseline; // for delta compression of initial sighting int numClusters; // if -1, use headnode instead int clusternums[MAX_ENT_CLUSTERS]; int lastCluster; // if all the clusters don't fit in clusternums int areanum, areanum2; int snapshotCounter; // used to prevent double adding from portal views int originCluster; // Gordon: calced upon linking, for origin only bmodel vis checks } svEntity_t; typedef enum { SS_DEAD, // no map loaded SS_LOADING, // spawning level entities SS_GAME // actively running } serverState_t; typedef struct { serverState_t state; qboolean restarting; // if true, send configstring changes during SS_LOADING int serverId; // changes each server start int restartedServerId; // serverId before a map_restart int checksumFeed; // the feed key that we use to compute the pure checksum strings // show_bug.cgi?id=475 // the serverId associated with the current checksumFeed (always <= serverId) int checksumFeedServerId; int snapshotCounter; // incremented for each snapshot built int timeResidual; // <= 1000 / sv_frame->value int nextFrameTime; // when time > nextFrameTime, process world struct cmodel_s *models[MAX_MODELS]; char* configstrings[MAX_CONFIGSTRINGS]; qboolean configstringsmodified[MAX_CONFIGSTRINGS]; svEntity_t svEntities[MAX_GENTITIES]; char *entityParsePoint; // used during game VM init // the game virtual machine will update these on init and changes sharedEntity_t *gentities; int gentitySize; int num_entities; // current number, <= MAX_GENTITIES playerState_t *gameClients; int gameClientSize; // will be > sizeof(playerState_t) due to game private data int restartTime; // NERVE - SMF - net debugging int bpsWindow[MAX_BPS_WINDOW]; int bpsWindowSteps; int bpsTotalBytes; int bpsMaxBytes; int ubpsWindow[MAX_BPS_WINDOW]; int ubpsTotalBytes; int ubpsMaxBytes; float ucompAve; int ucompNum; // -NERVE - SMF md3Tag_t tags[MAX_SERVER_TAGS]; tagHeaderExt_t tagHeadersExt[MAX_TAG_FILES]; int num_tagheaders; int num_tags; } server_t; typedef struct { int areabytes; byte areabits[MAX_MAP_AREA_BYTES]; // portalarea visibility bits playerState_t ps; int num_entities; int first_entity; // into the circular sv_packet_entities[] // the entities MUST be in increasing state number // order, otherwise the delta compression will fail int messageSent; // time the message was transmitted int messageAcked; // time the message was acked int messageSize; // used to rate drop packets } clientSnapshot_t; 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 CS_CONNECTED, // has been assigned to a client_t, but no gamestate yet CS_PRIMED, // gamestate has been sent, but client hasn't sent a usercmd CS_ACTIVE // client is fully in game } clientState_t; typedef struct netchan_buffer_s { msg_t msg; byte msgBuffer[MAX_MSGLEN]; char lastClientCommandString[MAX_STRING_CHARS]; struct netchan_buffer_s *next; } netchan_buffer_t; typedef struct client_s { clientState_t state; char userinfo[MAX_INFO_STRING]; // name, etc char reliableCommands[MAX_RELIABLE_COMMANDS][MAX_STRING_CHARS]; int reliableSequence; // last added reliable message, not necesarily sent or acknowledged yet int reliableAcknowledge; // last acknowledged reliable message int reliableSent; // last sent reliable message, not necesarily acknowledged yet int messageAcknowledge; int binaryMessageLength; char binaryMessage[MAX_BINARY_MESSAGE]; qboolean binaryMessageOverflowed; int gamestateMessageNum; // netchan->outgoingSequence of gamestate int challenge; usercmd_t lastUsercmd; int lastMessageNum; // for delta compression int lastClientCommand; // reliable client message sequence char lastClientCommandString[MAX_STRING_CHARS]; sharedEntity_t *gentity; // SV_GentityNum(clientnum) char name[MAX_NAME_LENGTH]; // extracted from userinfo, high bits masked // downloading char downloadName[MAX_QPATH]; // if not empty string, we are downloading fileHandle_t download; // file being downloaded int downloadSize; // total bytes (can't use EOF because of paks) int downloadCount; // bytes sent int downloadClientBlock; // last block we sent to the client, awaiting ack int downloadCurrentBlock; // current block number int downloadXmitBlock; // last block we xmited unsigned char *downloadBlocks[MAX_DOWNLOAD_WINDOW]; // the buffers for the download blocks int downloadBlockSize[MAX_DOWNLOAD_WINDOW]; qboolean downloadEOF; // We have sent the EOF block int downloadSendTime; // time we last got an ack from the client // www downloading qboolean bDlOK; // passed from cl_wwwDownload CVAR_USERINFO, wether this client supports www dl char downloadURL[MAX_OSPATH]; // the URL we redirected the client to qboolean bWWWDl; // we have a www download going qboolean bWWWing; // the client is doing an ftp/http download qboolean bFallback; // last www download attempt failed, fallback to regular download // note: this is one-shot, multiple downloads would cause a www download to be attempted again int deltaMessage; // frame last client usercmd message int nextReliableTime; // svs.time when another reliable command will be allowed int lastPacketTime; // svs.time when packet was last received int lastConnectTime; // svs.time when connection started int nextSnapshotTime; // send another snapshot when svs.time >= nextSnapshotTime qboolean rateDelayed; // true if nextSnapshotTime was set based on rate instead of snapshotMsec int timeoutCount; // must timeout a few frames in a row so debugging doesn't break clientSnapshot_t frames[PACKET_BACKUP]; // updates can be delta'd from here int ping; int rate; // bytes / second int snapshotMsec; // requests a snapshot every snapshotMsec unless rate choked int pureAuthentic; qboolean gotCP; // TTimo - additional flag to distinguish between a bad pure checksum, and no cp command at all netchan_t netchan; // TTimo // queuing outgoing fragmented messages to send them properly, without udp packet bursts // in case large fragmented messages are stacking up // buffer them into this queue, and hand them out to netchan as needed netchan_buffer_t *netchan_start_queue; //% netchan_buffer_t **netchan_end_queue; netchan_buffer_t *netchan_end_queue; //bani int downloadnotify; } client_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 #define AUTHORIZE_TIMEOUT 5000 typedef struct { netadr_t adr; int challenge; int time; // time the last packet was sent to the autherize server int pingTime; // time the challenge response was sent to client int firstTime; // time the adr was first used, for authorize timeout checks int firstPing; // Used for min and max ping checks qboolean connected; } challenge_t; typedef struct tempBan_s { netadr_t adr; int endtime; } tempBan_t; #define MAX_MASTERS 8 // max recipients for heartbeat packets #define MAX_TEMPBAN_ADDRESSES MAX_CLIENTS #define SERVER_PERFORMANCECOUNTER_FRAMES 600 #define SERVER_PERFORMANCECOUNTER_SAMPLES 6 // this structure will be cleared only when the game dll changes typedef struct { qboolean initialized; // sv_init has completed int time; // will be strictly increasing across level changes int snapFlagServerBit; // ^= SNAPFLAG_SERVERCOUNT every SV_SpawnServer() client_t *clients; // [sv_maxclients->integer]; int numSnapshotEntities; // sv_maxclients->integer*PACKET_BACKUP*MAX_PACKET_ENTITIES int nextSnapshotEntities; // next snapshotEntities to use entityState_t *snapshotEntities; // [numSnapshotEntities] int nextHeartbeatTime; challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting netadr_t redirectAddress; // for rcon return messages tempBan_t tempBanAddresses[MAX_TEMPBAN_ADDRESSES]; #ifdef AUTHORIZE_SUPPORT netadr_t authorizeAddress; #endif // AUTHORIZE_SUPPORT int sampleTimes[SERVER_PERFORMANCECOUNTER_SAMPLES]; int currentSampleIndex; int totalFrameTime; int currentFrameIndex; int serverLoad; } serverStatic_t; //============================================================================= extern serverStatic_t svs; // persistant server info across maps extern server_t sv; // cleared each map extern vm_t *gvm; // game virtual machine #define MAX_MASTER_SERVERS 5 extern cvar_t *sv_fps; extern cvar_t *sv_timeout; extern cvar_t *sv_zombietime; extern cvar_t *sv_rconPassword; extern cvar_t *sv_privatePassword; extern cvar_t *sv_allowDownload; extern cvar_t *sv_friendlyFire; // NERVE - SMF extern cvar_t *sv_maxlives; // NERVE - SMF extern cvar_t *sv_maxclients; extern cvar_t *sv_needpass; extern cvar_t *sv_privateClients; extern cvar_t *sv_hostname; extern cvar_t *sv_master[MAX_MASTER_SERVERS]; extern cvar_t *sv_reconnectlimit; extern cvar_t *sv_tempbanmessage; extern cvar_t *sv_showloss; extern cvar_t *sv_padPackets; extern cvar_t *sv_killserver; extern cvar_t *sv_mapname; extern cvar_t *sv_mapChecksum; extern cvar_t *sv_serverid; extern cvar_t *sv_maxRate; extern cvar_t *sv_minPing; extern cvar_t *sv_maxPing; //extern cvar_t *sv_gametype; extern cvar_t *sv_pure; extern cvar_t *sv_floodProtect; extern cvar_t *sv_allowAnonymous; extern cvar_t *sv_lanForceRate; extern cvar_t *sv_onlyVisibleClients; extern cvar_t *sv_showAverageBPS; // NERVE - SMF - net debugging extern cvar_t* g_gameType; // Rafael gameskill //extern cvar_t *sv_gameskill; // done extern cvar_t *sv_reloading; // TTimo - autodl extern cvar_t *sv_dl_maxRate; // TTimo extern cvar_t *sv_wwwDownload; // general flag to enable/disable www download redirects extern cvar_t *sv_wwwBaseURL; // the base URL of all the files // tell clients to perform their downloads while disconnected from the server // this gets you a better throughput, but you loose the ability to control the download usage extern cvar_t *sv_wwwDlDisconnected; extern cvar_t *sv_wwwFallbackURL; //bani extern cvar_t *sv_cheats; extern cvar_t *sv_packetloss; extern cvar_t *sv_packetdelay; //fretn extern cvar_t *sv_fullmsg; //=========================================================== // // sv_main.c // void SV_FinalCommand( char *cmd, qboolean disconnect ); // ydnar: added disconnect flag so map changes can use this function as well void QDECL SV_SendServerCommand( client_t *cl, const char *fmt, ... ); void SV_AddOperatorCommands( void ); void SV_RemoveOperatorCommands( void ); void SV_MasterHeartbeat( const char *hbname ); void SV_MasterShutdown( void ); void SV_MasterGameCompleteStatus(); // NERVE - SMF //bani - bugtraq 12534 qboolean SV_VerifyChallenge( char *challenge ); // // sv_init.c // void SV_SetConfigstringNoUpdate( int index, const char *val ); void SV_SetConfigstring( int index, const char *val ); void SV_UpdateConfigStrings( void ); void SV_GetConfigstring( int index, char *buffer, int bufferSize ); void SV_SetUserinfo( int index, const char *val ); void SV_GetUserinfo( int index, char *buffer, int bufferSize ); void SV_CreateBaseline( void ); void SV_ChangeMaxClients( void ); void SV_SpawnServer( char *server, qboolean killBots ); // // sv_client.c // void SV_GetChallenge( netadr_t from ); void SV_DirectConnect( netadr_t from ); void SV_AuthorizeIpPacket( netadr_t from ); void SV_ExecuteClientMessage( client_t *cl, msg_t *msg ); void SV_UserinfoChanged( client_t *cl ); void SV_ClientEnterWorld( client_t *client, usercmd_t *cmd ); void SV_FreeClientNetChan( client_t* client ); void SV_DropClient( client_t *drop, const char *reason ); void SV_ExecuteClientCommand( client_t *cl, const char *s, qboolean clientOK, qboolean premaprestart ); void SV_ClientThink( client_t *cl, usercmd_t *cmd ); void SV_WriteDownloadToClient( client_t *cl, msg_t *msg ); // // sv_ccmds.c // void SV_Heartbeat_f( void ); qboolean SV_TempBanIsBanned( netadr_t address ); void SV_TempBanNetAddress( netadr_t address, int length ); // // sv_snapshot.c // void SV_AddServerCommand( client_t *client, const char *cmd ); void SV_UpdateServerCommandsToClient( client_t *client, msg_t *msg ); void SV_WriteFrameToClient( client_t *client, msg_t *msg ); void SV_SendMessageToClient( msg_t *msg, client_t *client ); void SV_SendClientMessages( void ); void SV_SendClientSnapshot( client_t *client ); //bani void SV_SendClientIdle( client_t *client ); // // sv_game.c // int SV_NumForGentity( sharedEntity_t *ent ); //#define SV_GentityNum( num ) ((sharedEntity_t *)((byte *)sv.gentities + sv.gentitySize*(num))) //#define SV_GameClientNum( num ) ((playerState_t *)((byte *)sv.gameClients + sv.gameClientSize*(num))) sharedEntity_t *SV_GentityNum( int num ); playerState_t *SV_GameClientNum( int num ); svEntity_t *SV_SvEntityForGentity( sharedEntity_t *gEnt ); sharedEntity_t *SV_GEntityForSvEntity( svEntity_t *svEnt ); void SV_InitGameProgs( void ); void SV_ShutdownGameProgs( void ); void SV_RestartGameProgs( void ); qboolean SV_inPVS( const vec3_t p1, const vec3_t p2 ); qboolean SV_GetTag( int clientNum, int tagFileNumber, char *tagname, orientation_t * or ); int SV_LoadTag( const char* mod_name ); qboolean SV_GameIsSinglePlayer( void ); qboolean SV_GameIsCoop( void ); void SV_GameBinaryMessageReceived( int cno, const char *buf, int buflen, int commandTime ); // // sv_bot.c // void SV_BotFrame( int time ); int SV_BotAllocateClient( int clientNum ); void SV_BotFreeClient( int clientNum ); void SV_BotInitCvars( void ); int SV_BotLibSetup( void ); int SV_BotLibShutdown( void ); int SV_BotGetSnapshotEntity( int client, int ent ); int SV_BotGetConsoleMessage( int client, char *buf, int size ); int BotImport_DebugPolygonCreate( int color, int numPoints, vec3_t *points ); void BotImport_DebugPolygonDelete( int id ); //============================================================ // // high level object sorting to reduce interaction tests // void SV_ClearWorld( void ); // called after the world model has been loaded, before linking any entities void SV_UnlinkEntity( sharedEntity_t *ent ); // call before removing an entity, and before trying to move one, // so it doesn't clip against itself void SV_LinkEntity( sharedEntity_t *ent ); // Needs to be called any time an entity changes origin, mins, maxs, // or solid. Automatically unlinks if needed. // sets ent->v.absmin and ent->v.absmax // sets ent->leafnums[] for pvs determination even if the entity // is not solid clipHandle_t SV_ClipHandleForEntity( const sharedEntity_t *ent ); void SV_SectorList_f( void ); int SV_AreaEntities( const vec3_t mins, const vec3_t maxs, int *entityList, int maxcount ); // fills in a table of entity numbers with entities that have bounding boxes // that intersect the given area. It is possible for a non-axial bmodel // to be returned that doesn't actually intersect the area on an exact // test. // returns the number of pointers filled in // The world entity is never returned in this list. int SV_PointContents( const vec3_t p, int passEntityNum ); // returns the CONTENTS_* value from the world and all entities at the given point. void SV_Trace( trace_t *results, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask, int capsule ); // mins and maxs are relative // if the entire move stays in a solid volume, trace.allsolid will be set, // trace.startsolid will be set, and trace.fraction will be 0 // if the starting point is in a solid, it will be allowed to move out // to an open area // passEntityNum is explicitly excluded from clipping checks (normally ENTITYNUM_NONE) void SV_ClipToEntity( trace_t *trace, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int entityNum, int contentmask, int capsule ); // clip to a specific entity // // sv_net_chan.c // void SV_Netchan_Transmit( client_t *client, msg_t *msg ); void SV_Netchan_TransmitNextFragment( client_t *client ); qboolean SV_Netchan_Process( client_t *client, msg_t *msg ); //bani - cl->downloadnotify #define DLNOTIFY_REDIRECT 0x00000001 // "Redirecting client ..." #define DLNOTIFY_BEGIN 0x00000002 // "clientDownload: 4 : beginning ..." #define DLNOTIFY_ALL ( DLNOTIFY_REDIRECT | DLNOTIFY_BEGIN )