/* Copyright (C) 1997-2001 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 #include "../qcommon/qcommon.h" #include "../game/g_public.h" //============================================================================= #define MAX_MASTERS 8 // max recipients for heartbeat packets #define HEARTBEAT_SECONDS 300 typedef enum { ss_dead, // no map loaded ss_loading, // spawning level edicts ss_game // actively running } server_state_t; // some commands are only valid before the server has finished // initializing (precache commands, static sounds / objects, etc) typedef struct { server_state_t state; // precache commands are only valid during load qboolean loadgame; // client begins should reuse existing entity unsigned time; // always sv.framenum * svc.frametime msec unsigned framenum; char name[MAX_QPATH]; // map name, or cinematic name char configstrings[MAX_CONFIGSTRINGS][MAX_CONFIGSTRING_CHARS]; entity_state_t baselines[MAX_EDICTS]; // // global variables shared between game and server // struct edict_s *edicts; int edict_size; int num_edicts; // current number, <= max_edicts int max_edicts; } server_t; struct gclient_s { player_state_t ps; // communicated by server to clients client_shared_t r; }; struct edict_s { entity_state_t s; entity_shared_t r; }; #define EDICT_NUM(n) ((edict_t *)((qbyte *)sv.edicts + sv.edict_size*(n))) #define NUM_FOR_EDICT(e) ( ((qbyte *)(e)-(qbyte *)sv.edicts ) / sv.edict_size) /* 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_AWAITING, // has send a "new" command, is awaiting for fetching configstrings CS_CONNECTED, // has been assigned to a client_t, but not in game yet CS_SPAWNED // client is fully in game }sv_client_state_t; */ typedef struct { int areabytes; qbyte areabits[MAX_MAP_AREAS/8]; // portalarea visibility bits player_state_t ps; int num_entities; int first_entity; // into the circular sv_packet_entities[] unsigned int sentTimeStamp; // time at what this frame snap was sent to the clients match_state_t matchstate; } client_frame_t; #define LATENCY_COUNTS 16 #define RATE_MESSAGES 25 // wsw : jal : was 10: I think it must fit sv_pps, I have to calculate it typedef struct client_s { sv_client_state_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 clientCommandExecuted; // last client-command we received unsigned int lastPacketSentTime; // time when we sent the last message to this client unsigned int lastPacketReceivedTime; // time when we received the last message from this client unsigned lastconnect; int lastframe; // for delta compression (must be signed, -1 means no compression) usercmd_t lastcmd; // for filling in big drops unsigned int lastSentFrameNum; // for knowing which was last frame we sent int commandMsec; // every seconds this is reset, if user // commands exhaust it, assume time cheating int frame_latency[LATENCY_COUNTS]; int ping; #ifndef RATEKILLED //int message_size[RATE_MESSAGES]; // used to rate drop packets int rate; int suppressCount; // number of messages rate suppressed #endif edict_t *edict; // EDICT_NUM(clientnum+1) char name[32]; // extracted from userinfo, high bits masked // The sounds datagram is written to by multicasted sound commands // It can be harmlessly overflowed. msg_t soundsmsg; qbyte soundsmsgData[MAX_MSGLEN]; client_frame_t frames[UPDATE_BACKUP]; // updates can be delta'd from here qbyte *download; // file being downloaded int downloadsize; // total bytes (can't use EOF because of paks) char downloadname[MAX_QPATH]; unsigned int downloadtimeout; // so we can free the file being downloaded // if client omits sending success of failure message int challenge; // challenge of this user, randomly generated netchan_t netchan; #ifdef BATTLEYE qboolean battleye; battleye_transmit_t BE; #endif } client_t; // 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 //============================================================================= // 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 { qboolean initialized; // sv_init has completed unsigned realtime; // always increasing, no clamping, etc char mapcmd[MAX_TOKEN_CHARS]; // ie: *intro.cin+base int spawncount; // incremented each server start // used to check late spawns client_t *clients; // [maxclients->integer]; int num_client_entities; // maxclients->integer*UPDATE_BACKUP*MAX_PACKET_ENTITIES int next_client_entities; // next client_entity to use entity_state_t *client_entities; // [num_client_entities] challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting #ifdef SERVERSIDE_DEMOS // serverrecord values FILE *demofile; msg_t demo_multicast; qbyte demo_multicast_buf[MAX_MSGLEN]; #endif } server_static_t; typedef struct { int last_heartbeat; unsigned frametime; // msecs between server packets } server_constant_t; //============================================================================= // shared message buffer to be used for occasional messages extern msg_t tmpMessage; extern qbyte tmpMessageData[MAX_MSGLEN]; extern netadr_t net_from; extern netadr_t master_adr[MAX_MASTERS]; // address of the master server extern mempool_t *sv_mempool; extern server_constant_t svc; // constant server info (trully persistant since sv_init) extern server_static_t svs; // persistant server info extern server_t sv; // local server extern cvar_t *sv_maxclients; extern cvar_t *sv_noreload; // don't reload level state when reentering extern cvar_t *sv_enforcetime; extern client_t *sv_client; extern edict_t *sv_player; //wsw : jal extern cvar_t *sv_maxrate; extern cvar_t *sv_public; // should heartbeats be sent // wsw : debug netcode extern cvar_t *sv_debug_serverCmd; extern cvar_t *sv_uploads; extern cvar_t *sv_uploads_from_server; extern cvar_t *sv_uploads_baseurl; #ifdef BATTLEYE extern cvar_t *sv_battleye; #endif //=========================================================== // // sv_main.c // void SV_FinalMessage( char *message, qboolean reconnect ); void SV_DropClient( client_t *drop, int type, char *fmt, ... ); int SV_ModelIndex( char *name ); int SV_SoundIndex( char *name ); int SV_ImageIndex( char *name ); int SV_SkinIndex( char *name ); void SV_WriteClientdataToMessage( client_t *client, msg_t *msg ); void SV_ExecuteUserCommand( char *s); void SV_InitOperatorCommands( void ); void SV_SendServerinfo( client_t *client ); void SV_UserinfoChanged( client_t *cl ); void SV_MasterHeartbeat( void ); void SVC_MasterInfoResponse( void ); void SVC_FakeConnect( char *fakeUserinfo, char *fakeIP ); #ifdef COLLISION4D void SV_BackUpCollisionFrame( void ); #endif #ifdef BATTLEYE void SV_BattlEyeFrame( int msec ); #endif // // sv_init.c // void SV_InitGame( void ); void SV_Map( char *levelstring, qboolean loadgame, qboolean devmap ); void SV_FreeCachedChecksums (void); unsigned SV_GetCachedPakChecksum (const char *pakname); // // sv_phys.c // void SV_PrepWorldFrame (void); // // sv_send.c // void SV_SendServerCommand( client_t *cl, const char *fmt, ... ); void SV_AddReliableCommandsToMessage( client_t *client, msg_t *msg ); qboolean SV_SendClientsFragments( void ); void SV_SendMessageToClient( client_t *client, msg_t *msg ); void SV_ResetClientFrameCounters( void ); typedef enum {RD_NONE, RD_CLIENT, RD_PACKET} redirect_t; // destination class for SV_multicast typedef enum { MULTICAST_ALL, MULTICAST_PHS, MULTICAST_PVS } multicast_t; #define SV_OUTPUTBUF_LENGTH (MAX_MSGLEN - 16) extern char sv_outputbuf[SV_OUTPUTBUF_LENGTH]; void SV_FlushRedirect( int sv_redirected, char *outputbuf ); void SV_SendClientMessages( void ); void SV_Multicast( vec3_t origin, multicast_t to ); void SV_StartSound( vec3_t origin, edict_t *entity, int channel, int soundindex, float volume, float attenuation ); void SV_ClientPrintf( client_t *cl, char *fmt, ... ); void SV_ClientChatf( client_t *cl, char *fmt, ... ); void SV_BroadcastCommand( char *fmt, ... ); // // sv_user.c // void SV_Nextserver( void ); void SV_ExecuteClientMessage( client_t *client, msg_t *msg ); // // sv_ccmds.c // void SV_ReadLevelFile( void ); void SV_Status_f( void ); // // sv_ents.c // void SV_WriteFrameSnapToClient( client_t *client, msg_t *msg ); void SV_BuildClientFrameSnap( client_t *client ); void SV_Error( char *error, ... ); // // sv_game.c // extern game_export_t *ge; void SV_InitGameProgs (void); void SV_ShutdownGameProgs (void); void SV_InitEdict (edict_t *e); void SV_SetAreaPortalState ( edict_t *ent, qboolean open ); //============================================================ // // 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_UnlinkEdict (edict_t *ent); // call before removing an entity, and before trying to move one, // so it doesn't clip against itself void SV_LinkEdict (edict_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 #ifdef COLLISION4D int SV_AreaEdicts( vec3_t mins, vec3_t maxs, int *list, int maxcount, int areatype ); #else int SV_AreaEdicts (vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype); #endif // fills in a table of edict pointers with edicts 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 // ??? does this always return the world? //=================================================================== // // functions that interact with everything apropriate // int SV_PointContents (vec3_t p); // returns the CONTENTS_* value from the world at the given point. // Quake 2 extends this to also check entities, to allow moving liquids void SV_Trace (trace_t *tr, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask); // 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 // passedict is explicitly excluded from clipping checks (normally NULL) #ifdef BATTLEYE // // sv_battleye.c // #define BATTLEYE_MASTERSERVER "wsw.battleye.com:44400" extern qboolean SV_BE_ConnectToMaster(void); extern int SV_BE_CheckConnectAttempt(void); extern void SV_BE_SendToMaster(void* buf, int len); extern int SV_BE_ReceiveFromMaster(void* buf, int len); extern void SV_BE_DisconnectFromMaster(void); #endif #ifdef SERVERSIDE_DEMOS // // sv_demos.c // #define MAX_DEMO_MSGLEN 32768 void SV_ServerRecord_f(void); void SV_ServerStop_f(void); void SV_RecordDemoMessage(void); #endif