fteqw/engine/server/server.h
Spoike 8241ed13be tweak intermissions a little so that quakeworld mods actually works properly (especially mvds).
dynamically allocate music_playlist_* cvars. may require the use of set from configs in order to create them in advance.
add a trail to rogue's plasma weapon.
fix r_waterstyle bug
attempt to optimise qcvm slightly.
tweak copyentity to be a bit more useful.
tweak ban code slightly. 'stealth' penalty hides other penalties.
fix some d3d9 rendering issues with q3.
fix some q2 stuff.
add the NOLEGACY thing that a few people have asked for lately.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4978 fc73d0e0-1445-4013-8a0c-d673dee63da5
2015-09-01 04:45:15 +00:00

1462 lines
41 KiB
C

/*
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 time;
double starttime;
int framenum;
int logindatabase;
qboolean paused; // are we 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/<name>.bsp, for model_precache[0]
world_t world;
union {
#ifdef Q2SERVER
struct {
char configstring[Q2MAX_CONFIGSTRINGS][MAX_QPATH];
};
#endif
struct {
const char *vw_model_precache[32];
const char *model_precache[MAX_PRECACHE_MODELS]; // NULL terminated
char particle_precache[MAX_SSPARTICLESPRE][MAX_QPATH]; // NULL terminated
char sound_precache[MAX_PRECACHE_SOUNDS][MAX_QPATH]; // NULL terminated
const char *lightstyles[MAX_LIGHTSTYLES];
vec3_t lightstylecolours[MAX_LIGHTSTYLES];
};
} strings;
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;
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
vec3_t playerpositions[MAX_CLIENTS]; //where each player was in this frame, for antilag
qboolean playerpresent[MAX_CLIENTS]; //whether the player was actually present
packet_entities_t entities; //package containing entity states that were sent in this frame, for deltaing
unsigned int *resendentnum; //the number of each entity that was sent in this frame
unsigned int *resendentbits; //the bits of each entity that were sent in this frame
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
} client_frame_t;
#ifdef Q2SERVER
typedef struct //merge?
{
int areabytes;
qbyte areabits[MAX_Q2MAP_AREAS/8]; // portalarea visibility bits
q2player_state_t ps;
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_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_DONE
};
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
typedef struct client_s
{
client_conn_state_t state;
unsigned int prespawn_stage;
unsigned int prespawn_idx;
qboolean prespawn_allow_modellist;
qboolean prespawn_allow_soundlist;
int spectator; // non-interactive
int redirect;
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
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 *spawninfo;
float spawninfotime;
float nextservertimeupdate;
// 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 *pendingentbits;
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
#ifdef PEXT_CSQC
int csqclastsentsequence;
int *csqcentsequence;//the sequence number a csqc entity was sent in
int *csqcentversions;//the version of the entity when it was sent in that sequenced packet.
#endif
//true/false/persist
unsigned int penalties;
/* qbyte ismuted;
qbyte iscuffed;
qbyte iscrippled;
qbyte isdeaf;
qbyte islagged;
qbyte isvip;
*/
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_PROQUAKE,
SCP_FITZ666,
SCP_DARKPLACES6,
SCP_DARKPLACES7 //extra prediction stuff
//note, nq is nq+
} protocol;
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;
#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)
// 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
#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];
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;
struct mvdpendingdest_s *pendingdest;
} demo_t;
//=============================================================================
#define STATFRAMES 100
typedef struct
{
double active;
double idle;
int count;
int packets;
double latched_active;
double latched_idle;
int latched_packets;
} 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;
#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_ALL (BAN_BAN|BAN_PERMIT|BAN_CUFF|BAN_MUTE|BAN_CRIPPLED|BAN_DEAF|BAN_LAGGED|BAN_VIP|BAN_BLIND|BAN_SPECONLY|BAN_STEALTH)
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;
} 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_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);
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);
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_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(char *savename, qboolean dontharmgame);
void SV_Savegame (char *savename);
qboolean SV_LoadLevelCache(char *savename, char *level, 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 pubsubserver_s *next;
unsigned int id;
char name[64];
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_PollSlaves(void);
void SSV_InstructMaster(sizebuf_t *cmd);
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
void Sys_InstructSlave(pubsubserver_t *s, sizebuf_t *cmd);
int Sys_SubServerRead(pubsubserver_t *s); //1: yes. 0: no. -1: error
pubsubserver_t *Sys_ForkServer(void);
#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() false
#define MSV_ClusterLogin(guid,info,infosize) false
#define SSV_IsSubServer() false
#endif
//
// sv_init.c
//
void SV_SpawnServer (char *server, 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_StartSound (int ent, vec3_t origin, int seenmask, int channel, const char *sample, int volume, float attenuation, int pitchadj, float timeofs, unsigned int flags);
void SVQ1_StartSound (float *origin, wedict_t *entity, int channel, const char *sample, int volume, float attenuation, int pitchadj, float timeofs, unsigned int flags);
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, char *fmt, ...) LIKEPRINTF(3);
void VARGS SV_ClientTPrintf (client_t *cl, int level, translation_t text, ...);
void VARGS SV_BroadcastPrintf (int level, char *fmt, ...) LIKEPRINTF(2);
void VARGS SV_BroadcastTPrintf (int level, translation_t fmt, ...);
void VARGS SV_BroadcastCommand (char *fmt, ...) LIKEPRINTF(1);
void SV_SendServerInfoChange(char *key, const char *value);
void SV_SendMessagesToAll (void);
void SV_FindModelNumbers (void);
//
// sv_user.c
//
#ifdef NQPROT
void SVNQ_New_f (void);
void SVNQ_ExecuteClientMessage (client_t *cl);
#endif
qboolean SV_UserInfoIsBasic(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, client_t *client);
void SVQ3Q1_BuildEntityPacket(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_CSQC_DroppedPacket(client_t *client, int sequence);
void SV_CSQC_DropAll(client_t *client);
//
// 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;
} 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_STREAM} desttype;
int socket;
vfsfile_t *file;
char name[MAX_QPATH];
char path[MAX_QPATH];
char *cache;
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);
void SV_MVDStop (int 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_MVDInit(void);
char *SV_MVDNum(char *buffer, int bufferlen, int num);
void SV_SendMVDMessage(void);
void SV_MVD_WriteReliables(void);
qboolean SV_ReadMVD (void);
void SV_FlushDemoSignon (void);
void DestFlush(qboolean compleate);
// savegame.c
void SV_FlushLevelCache(void);
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