mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-26 22:01:50 +00:00
cd97d1fff3
fix q3 looping sounds fix q3sv bug that was kicking clients on map changes attempt to resize q3ui if the window changes size added some more disconnect reasons (for menuqc/q3ui to report). reworked particle count/step arguments for better compat with DP. particles that used count for trails were already broken... drawtextfield builtin will report line numbers shown, so qc can finally tell how much text there actually was added some more items to 'fps_preset dp', stuff needed for the 'quake15' mod. added dpcompat_noretouchground cvar for people wanting to mimic dp's bugs. added 'r_netgraph 2' setting, which will show packet sizes per svc, in part to highlight wasteful mods. added cvar to disable the q1mdl floodfill, which caused problems for yet another person. internal editor now attempts to support debugging asm, if no source is available. fix 64bit icon bug in x11. FINALLY fix high's te_teleport effect. load with no arguments will scan for the most recent a#/s#/quick savedgame instead of using just quick. load command will chose between fte and vanilla savedgame formats based on modification time, if both exist in the same package/dir. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5394 fc73d0e0-1445-4013-8a0c-d673dee63da5
1644 lines
48 KiB
C
1644 lines
48 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;
|
|
|
|
#ifdef SAVEDGAMES
|
|
char loadgame_on_restart[MAX_QPATH]; //saved game to load on map_restart
|
|
double autosave_time;
|
|
#endif
|
|
double time;
|
|
double starttime;
|
|
int framenum;
|
|
int logindatabase;
|
|
|
|
enum
|
|
{
|
|
PAUSE_EXPLICIT = 1, //someone hit pause
|
|
PAUSE_SERVICE = 2, //we're running as a service and someone paused us rather than killing us.
|
|
PAUSE_AUTO = 4 //console is down in a singleplayer game.
|
|
} paused, oldpaused;
|
|
float pausedstart;
|
|
|
|
//check player/eyes models for hacks
|
|
unsigned model_player_checksum;
|
|
unsigned eyes_player_checksum;
|
|
|
|
// char name[64]; // file map name (moved to svs, for restart)
|
|
char mapname[256]; // text description of the map
|
|
char modelname[MAX_QPATH]; // maps/<name>.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 {
|
|
#ifndef NOLEGACY
|
|
const char *vw_model_precache[32];
|
|
#endif
|
|
const char *model_precache[MAX_PRECACHE_MODELS]; // NULL terminated
|
|
const char *particle_precache[MAX_SSPARTICLESPRE]; // NULL terminated
|
|
const char *sound_precache[MAX_PRECACHE_SOUNDS]; // NULL terminated
|
|
const char *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];
|
|
|
|
#ifdef HEXEN2
|
|
char h2miditrack[MAX_QPATH];
|
|
qbyte h2cdtrack;
|
|
#endif
|
|
|
|
int allocated_client_slots; //number of slots available. (used mostly to stop single player saved games cacking up)
|
|
int spawned_client_slots; //number of PLAYER slots which are active (ie: putclientinserver was called)
|
|
int spawned_observer_slots;
|
|
|
|
model_t *models[MAX_PRECACHE_MODELS];
|
|
|
|
struct client_s *skipbprintclient; //SV_BroadcastPrint skips this client
|
|
|
|
// added to every client's unreliable buffer each frame, then cleared
|
|
sizebuf_t datagram;
|
|
qbyte datagram_buf[MAX_DATAGRAM];
|
|
|
|
// added to every client's reliable buffer each frame, then cleared
|
|
sizebuf_t reliable_datagram;
|
|
qbyte reliable_datagram_buf[MAX_QWMSGLEN];
|
|
|
|
// the multicast buffer is used to send a message to a set of clients
|
|
sizebuf_t multicast;
|
|
qbyte multicast_buf[MAX_QWMSGLEN];
|
|
|
|
#ifdef NQPROT
|
|
sizebuf_t nqdatagram;
|
|
qbyte nqdatagram_buf[MAX_NQDATAGRAM];
|
|
|
|
sizebuf_t nqreliable_datagram;
|
|
qbyte nqreliable_datagram_buf[MAX_NQMSGLEN];
|
|
|
|
sizebuf_t nqmulticast;
|
|
qbyte nqmulticast_buf[MAX_NQMSGLEN];
|
|
#endif
|
|
|
|
#ifdef Q2SERVER
|
|
sizebuf_t q2datagram;
|
|
qbyte q2datagram_buf[MAX_Q2DATAGRAM];
|
|
|
|
sizebuf_t q2reliable_datagram;
|
|
qbyte q2reliable_datagram_buf[MAX_Q2MSGLEN];
|
|
|
|
sizebuf_t q2multicast;
|
|
qbyte q2multicast_buf[MAX_Q2MSGLEN];
|
|
#endif
|
|
|
|
// the master buffer is used for building log packets
|
|
sizebuf_t master;
|
|
qbyte master_buf[MAX_DATAGRAM];
|
|
|
|
// the signon buffer will be sent to each client as they connect
|
|
// traditionally includes the entity baselines, the static entities, etc
|
|
// large levels will have >MAX_DATAGRAM sized signons, so
|
|
// multiple signon messages are kept
|
|
// fte only stores writebyted stuff in here. everything else is regenerated based upon the client's extensions.
|
|
sizebuf_t signon;
|
|
int num_signon_buffers;
|
|
int signon_buffer_size[MAX_SIGNON_BUFFERS];
|
|
qbyte signon_buffers[MAX_SIGNON_BUFFERS][MAX_DATAGRAM];
|
|
|
|
qboolean gamedirchanged;
|
|
|
|
qboolean haveitems2; //use items2 field instead of serverflags for the high bits of STAT_ITEMS
|
|
|
|
|
|
|
|
|
|
#ifdef MVD_RECORDING
|
|
qboolean mvdrecording;
|
|
#endif
|
|
|
|
//====================================================
|
|
//this lot is for serverside playback of mvds. Use QTV instead.
|
|
#ifdef SERVER_DEMO_PLAYBACK
|
|
qboolean mvdplayback;
|
|
float realtime;
|
|
vfsfile_t *demofile; //also signifies playing the thing.
|
|
|
|
int lasttype;
|
|
int lastto;
|
|
|
|
//playback spikes (svc_nails/nails2)
|
|
int numdemospikes;
|
|
struct {
|
|
vec3_t org;
|
|
qbyte id;
|
|
qbyte pitch;
|
|
qbyte yaw;
|
|
qbyte modelindex;
|
|
} demospikes[255];
|
|
|
|
//playback of entities (svc_nails/nails2)
|
|
mvdentity_state_t *demostate;
|
|
mvdentity_state_t *demobaselines;
|
|
int demomaxents;
|
|
qboolean demostatevalid;
|
|
|
|
//players
|
|
struct {
|
|
int stats[MAX_CL_STATS];
|
|
int pl;
|
|
int ping;
|
|
int frags;
|
|
int userid;
|
|
int weaponframe;
|
|
char userinfo[MAX_INFO_STRING];
|
|
vec3_t oldorg;
|
|
vec3_t oldang;
|
|
float updatetime;
|
|
} recordedplayer[MAX_CLIENTS];
|
|
|
|
//gamestate
|
|
char demoinfo[MAX_SERVERINFO_STRING];
|
|
char demmodel_precache[MAX_MODELS][MAX_QPATH]; // NULL terminated
|
|
char demsound_precache[MAX_SOUNDS][MAX_QPATH]; // NULL terminated
|
|
char demgamedir[64];
|
|
char demname[64]; // map name
|
|
|
|
qboolean democausesreconnect; //this makes current clients go through the connection process (and when the demo ends too)
|
|
sizebuf_t demosignon;
|
|
int num_demosignon_buffers;
|
|
int demosignon_buffer_size[MAX_SIGNON_BUFFERS];
|
|
qbyte demosignon_buffers[MAX_SIGNON_BUFFERS][MAX_DATAGRAM];
|
|
char demfullmapname[64];
|
|
|
|
char *demolightstyles[MAX_LIGHTSTYLES];
|
|
#endif
|
|
//====================================================
|
|
// movevars_t demomovevars; //FIXME:!
|
|
//end this lot... (demo playback)
|
|
|
|
int num_static_entities;
|
|
int num_static_sounds;
|
|
|
|
svcustomtents_t customtents[255];
|
|
|
|
int *csqcentversion;//prevents ent versions from going backwards
|
|
} server_t;
|
|
void SV_WipeServerState(void);
|
|
|
|
/*
|
|
#define CS_EMPTY 0
|
|
#define CS_ZOMBIE (1u<<0) //just stops the slot from being reused for a bit.
|
|
#define CS_CLUSTER (1u<<1) //is managed by the cluster host (and will appear on scoreboards).
|
|
#define CS_SPAWNED (1u<<2) //has an active entity.
|
|
#define CS_ACTIVE (1u<<3) //has a connection
|
|
|
|
#define cs_free (CS_EMPTY)
|
|
#define cs_zombie (CS_ZOMBIE)
|
|
#define cs_loadzombie (CS_SPAWNED)
|
|
#define cs_connected (CS_ACTIVE)
|
|
#define cs_spawned (CS_ACTIVE|CS_SPAWNED)
|
|
*/
|
|
|
|
typedef enum
|
|
{
|
|
cs_free, // can be reused for a new connection
|
|
cs_zombie, // client has been disconnected, but don't reuse connection for a couple seconds. entity was already cleared.
|
|
cs_loadzombie, // slot reserved for a client. the player's entity may or may not be known (istobeloaded says that state). parms _ARE_ known.
|
|
cs_connected, // has been assigned to a client_t, but not in game yet
|
|
cs_spawned // client is fully in game
|
|
} client_conn_state_t;
|
|
|
|
typedef struct
|
|
{
|
|
// received from client
|
|
|
|
// reply
|
|
double senttime; //time we sent this frame to the client, for ping calcs (realtime)
|
|
int sequence; //the outgoing sequence - without mask, meaning we know if its current or stale
|
|
float ping_time; //how long it took for the client to ack it, may be negative
|
|
float move_msecs; //
|
|
int packetsizein; //amount of data received for this frame
|
|
int packetsizeout; //amount of data that was sent in the frame
|
|
|
|
packet_entities_t qwentities; //package containing entity states that were sent in this frame, for deltaing
|
|
|
|
struct resendinfo_s
|
|
{
|
|
unsigned int entnum;
|
|
unsigned int bits; //delta (fte or dpp5+)
|
|
unsigned int flags; //csqc
|
|
} *resend;
|
|
unsigned int numresend;
|
|
unsigned int maxresend;
|
|
|
|
unsigned short resendstats[32];//the number of each entity that was sent in this frame
|
|
unsigned int numresendstats; //the bits of each entity that were sent in this frame
|
|
|
|
//antilag
|
|
//these are to recalculate the player's origin without old knockbacks nor teleporters, to give more accurate weapon start positions (post-command).
|
|
vec3_t pmorigin;
|
|
vec3_t pmvelocity;
|
|
int pmtype;
|
|
unsigned int pmjumpheld:1;
|
|
unsigned int pmonladder:1;
|
|
float pmwaterjumptime;
|
|
usercmd_t cmd;
|
|
//these are old positions of players, to give more accurate victim positions
|
|
laggedentinfo_t laggedplayer[MAX_CLIENTS];
|
|
unsigned int numlaggedplayers;
|
|
float laggedtime; //sv.time of when this frame was sent
|
|
} client_frame_t;
|
|
|
|
#ifdef Q2SERVER
|
|
typedef struct //merge?
|
|
{
|
|
int areabytes;
|
|
qbyte areabits[MAX_Q2MAP_AREAS/8]; // portalarea visibility bits
|
|
q2player_state_t ps[MAX_SPLITS]; //yuck
|
|
int clientnum[MAX_SPLITS];
|
|
int num_entities;
|
|
int first_entity; // into the circular sv_packet_entities[]
|
|
int senttime; // for ping calculations
|
|
float ping_time;
|
|
} q2client_frame_t;
|
|
#endif
|
|
#ifdef Q3SERVER
|
|
#include "clq3defs.h"
|
|
typedef struct //merge?
|
|
{
|
|
int flags;
|
|
int areabytes;
|
|
qbyte areabits[MAX_Q2MAP_AREAS/8]; // portalarea visibility bits
|
|
q3playerState_t ps;
|
|
int num_entities;
|
|
int first_entity; // into the circular sv_packet_entities[]
|
|
int senttime; // for ping calculations
|
|
|
|
|
|
int serverMessageNum;
|
|
int serverCommandNum;
|
|
int serverTime; // server time the message is valid for (in msec)
|
|
int localTime;
|
|
int deltaFrame;
|
|
} q3client_frame_t;
|
|
#endif
|
|
|
|
#define MAX_BACK_BUFFERS 16
|
|
|
|
enum
|
|
{
|
|
PRESPAWN_INVALID=0,
|
|
PRESPAWN_PROTOCOLSWITCH, //nq drops unreliables until reliables are acked. this gives us a chance to drop any clc_move packets with formats from the previous map
|
|
PRESPAWN_SERVERINFO,
|
|
#ifdef MVD_RECORDING
|
|
PRESPAWN_CSPROGS, //demos contain a copy of the csprogs.
|
|
#endif
|
|
PRESPAWN_SOUNDLIST, //nq skips these
|
|
#ifndef NOLEGACY
|
|
PRESPAWN_VWEPMODELLIST, //qw ugly extension.
|
|
#endif
|
|
PRESPAWN_MODELLIST,
|
|
PRESPAWN_MAPCHECK, //wait for old prespawn command
|
|
PRESPAWN_PARTICLES,
|
|
PRESPAWN_CUSTOMTENTS,
|
|
PRESPAWN_SIGNON_BUF,
|
|
PRESPAWN_SPAWNSTATIC,
|
|
PRESPAWN_AMBIENTSOUND,
|
|
PRESPAWN_BASELINES,
|
|
PRESPAWN_SPAWN,
|
|
PRESPAWN_BRUSHES,
|
|
PRESPAWN_COMPLETED
|
|
};
|
|
|
|
enum
|
|
{ //'soft' limits that result in warnings if the client's protocol is too limited.
|
|
PLIMIT_ENTITIES = 1u<<0,
|
|
PLIMIT_MODELS = 1u<<1,
|
|
PLIMIT_SOUNDS = 1u<<2
|
|
};
|
|
|
|
//client_t->spec_print + sv_specprint
|
|
#define SPECPRINT_CENTERPRINT 0x1
|
|
#define SPECPRINT_SPRINT 0x2
|
|
#define SPECPRINT_STUFFCMD 0x4
|
|
|
|
#define STUFFCMD_IGNOREINDEMO ( 1<<0) // do not put in mvd demo
|
|
#define STUFFCMD_DEMOONLY ( 1<<1) // put in mvd demo only
|
|
#define STUFFCMD_BROADCAST ( 1<<2) // everyone sees it.
|
|
#define STUFFCMD_UNRELIABLE ( 1<<3) // someone might not see it. oh well.
|
|
|
|
typedef struct client_s
|
|
{
|
|
client_conn_state_t state;
|
|
|
|
unsigned int prespawn_stage;
|
|
unsigned int prespawn_idx;
|
|
unsigned int prespawn_idx2;
|
|
qboolean prespawn_allow_modellist;
|
|
qboolean prespawn_allow_soundlist;
|
|
|
|
int spectator; // non-interactive
|
|
int redirect; //1=redirected because full, 2=cluster transfer
|
|
|
|
qboolean sendinfo; // at end of frame, send info to all
|
|
// this prevents malicious multiple broadcasts
|
|
float lastnametime; // time of last name change
|
|
int lastnamecount; // time of last name change
|
|
unsigned checksum; // checksum for calcs
|
|
qboolean drop; // lose this guy next opportunity
|
|
int lossage; // loss percentage
|
|
|
|
int challenge;
|
|
int userid; // identifying number
|
|
infobuf_t userinfo; // all of the user's various settings
|
|
infosync_t infosync; // information about the infos that the client still doesn't know (server and multiple clients).
|
|
char *transfer;
|
|
|
|
usercmd_t lastcmd; // for filling in big drops and partial predictions
|
|
double localtime; // of last message
|
|
qboolean jump_held;
|
|
qboolean lockangles; //mod is spamming angle changes, don't do relative changes
|
|
|
|
float maxspeed; // localized maxspeed
|
|
float entgravity; // localized ent gravity
|
|
|
|
int viewent; //fake the entity positioning.
|
|
|
|
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
|
|
#ifndef NOLEGACY
|
|
float *dp_ping;
|
|
float *dp_pl;
|
|
#endif
|
|
|
|
// the datagram is written to after every frame, but only cleared
|
|
// when it is sent out to the client. overflow is tolerated.
|
|
sizebuf_t datagram;
|
|
qbyte datagram_buf[MAX_OVERALLMSGLEN/2];
|
|
|
|
// back buffers for client reliable data
|
|
sizebuf_t backbuf;
|
|
int num_backbuf;
|
|
int backbuf_size[MAX_BACK_BUFFERS];
|
|
qbyte backbuf_data[MAX_BACK_BUFFERS][MAX_BACKBUFLEN];
|
|
|
|
double connection_started; // or time of disconnect for zombies
|
|
qboolean send_message; // set on frames a datagram arived on
|
|
|
|
laggedentinfo_t laggedents[MAX_CLIENTS];
|
|
unsigned int laggedents_count;
|
|
float laggedents_frac;
|
|
float laggedents_time;
|
|
|
|
// spawn parms are carried from level to level
|
|
float spawn_parms[NUM_SPAWN_PARMS];
|
|
char *spawn_parmstring; //qc-specified data.
|
|
char *spawninfo; //entity-formatted data (for hexen2's ClientReEnter)
|
|
float spawninfotime;
|
|
float nextservertimeupdate; //next time to send STAT_TIME
|
|
float lastoutgoingphysicstime;//sv.world.physicstime of the last outgoing message.
|
|
|
|
// client known data for deltas
|
|
int old_frags;
|
|
|
|
unsigned int pendingstats[((MAX_CL_STATS*2) + 31)>>5]; //these are the stats that have changed and that need sending/resending
|
|
int statsi[MAX_CL_STATS];
|
|
float statsf[MAX_CL_STATS];
|
|
char *statss[MAX_CL_STATS];
|
|
char *centerprintstring;
|
|
|
|
union{ //save space
|
|
client_frame_t *frames; // updates can be deltad from here
|
|
#ifdef Q2SERVER
|
|
q2client_frame_t *q2frames;
|
|
#endif
|
|
#ifdef Q3SERVER
|
|
q3client_frame_t *q3frames;
|
|
#endif
|
|
} frameunion;
|
|
packet_entities_t sentents;
|
|
unsigned int *pendingdeltabits;
|
|
unsigned int *pendingcsqcbits;
|
|
unsigned int nextdeltaindex; //splurged round-robin to deal with overflows
|
|
unsigned int nextcsqcindex; //splurged round-robin
|
|
#define SENDFLAGS_USABLE 0x3fffffffu //this number of bits are actually safe in a float. not all together, but otherwise safe.
|
|
#define SENDFLAGS_PRESENT 0x80000000u //this entity is present on that client
|
|
#define SENDFLAGS_REMOVED 0x40000000u //to handle remove packetloss
|
|
|
|
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_client_command_num;
|
|
char last_client_command[1024];
|
|
|
|
//quake3 does reliables only via this mechanism. basically just like q1's stuffcmds.
|
|
int server_command_ack; //number known to have been received.
|
|
int server_command_sequence; //number available.
|
|
char server_commands[64][1024]; //the commands, to deal with resends
|
|
#endif
|
|
|
|
//true/false/persist
|
|
unsigned int penalties;
|
|
qbyte istobeloaded; //loadgame creates place holders for clients to connect to. Effectivly loading a game reconnects all clients, but has precreated ents.
|
|
qboolean spawned; //the player's entity was spawned.
|
|
|
|
double floodprotmessage;
|
|
double lastspoke;
|
|
double lockedtill;
|
|
float joinobservelockeduntil;
|
|
|
|
qboolean upgradewarn; // did we warn him?
|
|
|
|
vfsfile_t *upload;
|
|
char uploadfn[MAX_QPATH];
|
|
netadr_t snap_from;
|
|
qboolean remote_snap;
|
|
|
|
//===== NETWORK ============
|
|
int chokecount;
|
|
qboolean waschoked;
|
|
int delta_sequence; // -1 = no compression
|
|
int last_sequence; //last inputframe sequence received
|
|
netchan_t netchan;
|
|
qboolean isindependant;
|
|
|
|
int lastsequence_acknowledged;
|
|
|
|
#ifdef VOICECHAT
|
|
unsigned int voice_read; /*place in ring*/
|
|
unsigned char voice_mute[(MAX_CLIENTS+7)/8];
|
|
qboolean voice_active;
|
|
enum
|
|
{
|
|
/*note - when recording an mvd, only 'all' will be received by non-spectating viewers. all other chat will only be heard when spectating the receiver(or sender) of said chat*/
|
|
|
|
/*should we add one to respond to the last speaker? or should that be an automagic +voip_reply instead?*/
|
|
VT_TEAM,
|
|
VT_ALL,
|
|
VT_NONMUTED, /*cheap, but allows custom private channels with no external pesters*/
|
|
VT_SPECSELF, /*sends to self, audiable to people spectating self*/
|
|
VT_PLAYERSLOT0
|
|
/*player0+...*/
|
|
} voice_target;
|
|
#endif
|
|
|
|
#ifdef SVCHAT
|
|
svchat_t chat;
|
|
#endif
|
|
#ifdef SVRANKING
|
|
int rankid;
|
|
|
|
int kills;
|
|
int deaths;
|
|
|
|
double stats_started;
|
|
#endif
|
|
|
|
qboolean csqcactive;
|
|
#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_staticents; /*limit to the number of static ents supported by the client*/
|
|
unsigned int max_net_clients; /*max number of player slots supported by the client */
|
|
unsigned int maxmodels; /*max models supported by whatever the protocol is*/
|
|
|
|
enum {
|
|
SCP_BAD, //don't send (a bot)
|
|
SCP_QUAKEWORLD,
|
|
SCP_QUAKE2,
|
|
SCP_QUAKE3,
|
|
//all the below are considered netquake clients.
|
|
SCP_NETQUAKE,
|
|
//bjp1, bjp2
|
|
SCP_BJP3, //16bit angles,model+sound indexes. nothing else (assume raised ent limits too).
|
|
SCP_FITZ666,
|
|
//dp5
|
|
SCP_DARKPLACES6,
|
|
SCP_DARKPLACES7 //extra prediction stuff
|
|
//note, nq is nq+
|
|
} protocol;
|
|
unsigned int supportedprotocols;
|
|
qboolean proquake_angles_hack; //expect 16bit client->server angles .
|
|
|
|
unsigned int lastruncmd; //for non-qw physics. timestamp they were last run, so switching between physics modes isn't a (significant) cheat
|
|
//speed cheat testing
|
|
#define NEWSPEEDCHEATPROT
|
|
float msecs;
|
|
#ifndef NEWSPEEDCHEATPROT
|
|
int msec_cheating;
|
|
float last_check;
|
|
#endif
|
|
|
|
qboolean gibfilter;
|
|
|
|
int trustlevel;
|
|
|
|
vec3_t specorigin; //mvds need to use a different origin from the one QC has.
|
|
vec3_t specvelocity;
|
|
|
|
int language; //the clients language
|
|
|
|
// struct {
|
|
// qbyte vweap;
|
|
// } otherclientsknown[MAX_CLIENTS]; //updated as needed. Flag at a time, or all flags.
|
|
|
|
struct client_s *controller; /*first in splitscreen chain, NULL=nosplitscreen*/
|
|
struct client_s *controlled; /*next in splitscreen chain*/
|
|
|
|
/*these are the current rates*/
|
|
float ratetime;
|
|
float inrate;
|
|
float outrate;
|
|
|
|
int rate;
|
|
int drate;
|
|
|
|
netadr_t realip;
|
|
int realip_status;
|
|
int realip_num;
|
|
int realip_ping;
|
|
char *reversedns;
|
|
|
|
unsigned int plimitwarned;
|
|
|
|
float delay;
|
|
laggedpacket_t *laggedpacket;
|
|
laggedpacket_t *laggedpacket_last;
|
|
} client_t;
|
|
|
|
#if defined(NQPROT) || defined(Q2SERVER) || defined(Q3SERVER)
|
|
#define ISQWCLIENT(cl) ((cl)->protocol == SCP_QUAKEWORLD)
|
|
#define ISQ2CLIENT(cl) ((cl)->protocol == SCP_QUAKE2)
|
|
#define ISQ3CLIENT(cl) ((cl)->protocol == SCP_QUAKE3)
|
|
#define ISNQCLIENT(cl) ((cl)->protocol >= SCP_NETQUAKE)
|
|
#define ISDPCLIENT(cl) ((cl)->protocol >= SCP_DARKPLACES6)
|
|
#else
|
|
#define ISQWCLIENT(cl) ((cl)->protocol != SCP_BAD)
|
|
#define ISQ2CLIENT(cl) false
|
|
#define ISQ3CLIENT(cl) false
|
|
#define ISNQCLIENT(cl) false
|
|
#define ISDPCLIENT(cl) false
|
|
#endif
|
|
|
|
// a client can leave the server in one of four ways:
|
|
// dropping properly by quiting or disconnecting
|
|
// timing out if no valid messages are received for timeout.value seconds
|
|
// getting kicked off by the server operator
|
|
// a program error, like an overflowed reliable buffer
|
|
|
|
|
|
|
|
|
|
//=============================================================================
|
|
|
|
//mvd stuff
|
|
#ifdef MVD_RECORDING
|
|
#define MSG_BUF_SIZE 8192
|
|
|
|
typedef struct
|
|
{
|
|
vec3_t origin;
|
|
vec3_t angles;
|
|
int weaponframe;
|
|
int skinnum;
|
|
int model;
|
|
int effects;
|
|
} demoinfo_t;
|
|
|
|
typedef struct
|
|
{
|
|
demoinfo_t info;
|
|
float sec;
|
|
int parsecount;
|
|
qboolean fixangle;
|
|
vec3_t angle;
|
|
float cmdtime;
|
|
int flags;
|
|
int frame;
|
|
} demo_client_t;
|
|
|
|
typedef struct {
|
|
qbyte type;
|
|
qbyte full;
|
|
int to;
|
|
int size;
|
|
qbyte data[1]; //gcc doesn't allow [] (?)
|
|
} mvd_header_t;
|
|
|
|
typedef struct
|
|
{
|
|
sizebuf_t sb;
|
|
int bufsize;
|
|
mvd_header_t *h;
|
|
} demobuf_t;
|
|
|
|
typedef struct
|
|
{
|
|
demo_client_t clients[MAX_CLIENTS];
|
|
double time;
|
|
demobuf_t buf;
|
|
} demo_frame_t;
|
|
|
|
typedef struct {
|
|
qbyte *data;
|
|
int start, end, last;
|
|
int maxsize;
|
|
} dbuffer_t;
|
|
|
|
#define DEMO_FRAMES 64 //why is this not just 2?
|
|
#define DEMO_FRAMES_MASK (DEMO_FRAMES - 1)
|
|
|
|
typedef struct
|
|
{
|
|
// demobuf_t *dbuf;
|
|
// dbuffer_t dbuffer;
|
|
sizebuf_t datagram;
|
|
qbyte datagram_data[MSG_BUF_SIZE];
|
|
int lastto;
|
|
int lasttype;
|
|
double time, pingtime;
|
|
int statsi[MAX_CLIENTS][MAX_CL_STATS]; // ouch!
|
|
float statsf[MAX_CLIENTS][MAX_CL_STATS]; // ouch!
|
|
char *statss[MAX_CLIENTS][MAX_CL_STATS]; // ouch!
|
|
client_t recorder;
|
|
qboolean playerreset[MAX_CLIENTS]; //will ensure that the model etc is written when this player is next written.
|
|
qboolean fixangle[MAX_CLIENTS];
|
|
float fixangletime[MAX_CLIENTS];
|
|
vec3_t angles[MAX_CLIENTS];
|
|
qboolean resetdeltas;
|
|
int parsecount;
|
|
int lastwritten;
|
|
demo_frame_t frames[DEMO_FRAMES];
|
|
demoinfo_t info[MAX_CLIENTS];
|
|
qbyte buffer[20*MAX_QWMSGLEN];
|
|
int bufsize;
|
|
int forceFrame;
|
|
|
|
struct mvddest_s *dest;
|
|
} demo_t;
|
|
#endif
|
|
|
|
//=============================================================================
|
|
|
|
#define SVSTATS_PERIOD 10
|
|
typedef struct
|
|
{
|
|
double active;
|
|
double idle;
|
|
int count;
|
|
int packets;
|
|
double maxresponse; //longest (active) frame time within the current period
|
|
int maxpackets; //max packet count in a single frame
|
|
|
|
double latched_time; //time that the current period ends
|
|
double latched_active; //active time in the last period
|
|
double latched_idle;
|
|
int latched_count;
|
|
int latched_packets;
|
|
int latched_maxpackets;
|
|
double latched_maxresponse;
|
|
} svstats_t;
|
|
|
|
// MAX_CHALLENGES is made large to prevent a denial
|
|
// of service attack that could cycle all of them
|
|
// out before legitimate users connected
|
|
#define MAX_CHALLENGES 1024
|
|
|
|
typedef struct
|
|
{
|
|
netadr_t adr;
|
|
int challenge;
|
|
int time;
|
|
} challenge_t;
|
|
|
|
typedef struct bannedips_s {
|
|
unsigned int banflags;
|
|
struct bannedips_s *next;
|
|
netadr_t adr;
|
|
netadr_t adrmask;
|
|
time_t expiretime;
|
|
char reason[1];
|
|
} bannedips_t;
|
|
|
|
typedef enum {
|
|
GT_PROGS, //q1, qw, h2 are similar enough that we consider it only one game mode. (We don't support the h2 protocol)
|
|
GT_Q1QVM,
|
|
GT_HALFLIFE,
|
|
GT_QUAKE2, //q2 servers run from a q2 game dll
|
|
GT_QUAKE3, //q3 servers run off the q3 qvm api
|
|
#ifdef VM_LUA
|
|
GT_LUA, //for the luls
|
|
#endif
|
|
GT_MAX
|
|
} gametype_e;
|
|
|
|
typedef struct levelcache_s {
|
|
struct levelcache_s *next;
|
|
char *mapname;
|
|
gametype_e gametype;
|
|
unsigned char savedplayers[(MAX_CLIENTS+7)>>3]; //bitmask to say which players are actually stored in the cache. so that restarts can restore.
|
|
} levelcache_t;
|
|
|
|
#ifdef TCPCONNECT
|
|
typedef struct svtcpstream_s {
|
|
int socketnum;
|
|
int inlen;
|
|
qboolean waitingforprotocolconfirmation;
|
|
char inbuffer[1500];
|
|
float timeouttime;
|
|
netadr_t remoteaddr;
|
|
struct svtcpstream_s *next;
|
|
} svtcpstream_t;
|
|
#endif
|
|
|
|
typedef struct
|
|
{
|
|
gametype_e gametype;
|
|
int spawncount; // number of servers spawned since start,
|
|
// used to check late spawns
|
|
int framenum; //physics frame number for out-of-sequence thinks (fix for slow rockets)
|
|
int clusterserverid; // which server we are in the cluster. for gamecode to track with stats.
|
|
|
|
struct ftenet_connections_s *sockets;
|
|
|
|
int allocated_client_slots; //number of entries in the clients array
|
|
client_t *clients; //[svs.allocated_client_slots]
|
|
int serverflags; // episode completion information
|
|
|
|
double last_heartbeat;
|
|
int heartbeat_sequence;
|
|
svstats_t stats;
|
|
|
|
infobuf_t info;
|
|
infobuf_t localinfo;
|
|
|
|
// log messages are used so that fraglog processes can get stats
|
|
int logsequence; // the message currently being filled
|
|
double logtime; // time of last swap
|
|
|
|
#define FRAGLOG_BUFFERS 8
|
|
sizebuf_t log[FRAGLOG_BUFFERS];
|
|
qbyte log_buf[FRAGLOG_BUFFERS][MAX_DATAGRAM];
|
|
|
|
challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting
|
|
|
|
bannedips_t *bannedips;
|
|
|
|
char progsnames[MAX_PROGS][MAX_QPATH];
|
|
progsnum_t progsnum[MAX_PROGS];
|
|
int numprogs;
|
|
|
|
struct netprim_s netprim;
|
|
|
|
laggedpacket_t *free_lagged_packet;
|
|
packet_entities_t entstatebuffer; /*just a temp buffer*/
|
|
|
|
char name[64]; // map name (base filename). static because of restart command after disconnecting.
|
|
levelcache_t *levcache;
|
|
|
|
struct frameendtasks_s
|
|
{
|
|
struct frameendtasks_s *next;
|
|
void(*callback)(struct frameendtasks_s *task);
|
|
void *ctxptr;
|
|
intptr_t ctxint;
|
|
char data[1];
|
|
} *frameendtasks;
|
|
} server_static_t;
|
|
|
|
//=============================================================================
|
|
|
|
/*
|
|
// edict->movetype values
|
|
#define MOVETYPE_NONE 0 // never moves
|
|
#define MOVETYPE_ANGLENOCLIP 1
|
|
#define MOVETYPE_ANGLECLIP 2
|
|
#define MOVETYPE_WALK 3 // gravity
|
|
#define MOVETYPE_STEP 4 // gravity, special edge handling
|
|
#define MOVETYPE_FLY 5
|
|
#define MOVETYPE_TOSS 6 // gravity
|
|
#define MOVETYPE_PUSH 7 // no clip to world, push and crush
|
|
#define MOVETYPE_NOCLIP 8
|
|
#define MOVETYPE_FLYMISSILE 9 // extra size to monsters
|
|
#define MOVETYPE_BOUNCE 10
|
|
#define MOVETYPE_BOUNCEMISSILE 11 // bounce w/o gravity
|
|
#define MOVETYPE_FOLLOW 12 // track movement of aiment
|
|
#define MOVETYPE_H2PUSHPULL 13 // pushable/pullable object
|
|
#define MOVETYPE_H2SWIM 14 // should keep the object in water
|
|
#define MOVETYPE_PHYSICS 32
|
|
#define MOVETYPE_FLY_WORLDONLY 33
|
|
|
|
// edict->solid values
|
|
#define SOLID_NOT 0 // no interaction with other objects
|
|
#define SOLID_TRIGGER 1 // touch on edge, but not blocking
|
|
#define SOLID_BBOX 2 // touch on edge, block
|
|
#define SOLID_SLIDEBOX 3 // touch on edge, but not an onground
|
|
#define SOLID_BSP 4 // bsp clip, touch on edge, block
|
|
#define SOLID_PHASEH2 5
|
|
#define SOLID_CORPSE 5
|
|
#define SOLID_LADDER 20 //dmw. touch on edge, not blocking. Touching players have different physics. Otherwise a SOLID_TRIGGER. deprecated. use solid_bsp and skin=-16
|
|
|
|
#define DAMAGE_NO 0
|
|
#define DAMAGE_YES 1
|
|
#define DAMAGE_AIM 2
|
|
*/
|
|
|
|
#define PVSF_NORMALPVS 0x0
|
|
#define PVSF_NOTRACECHECK 0x1
|
|
#define PVSF_USEPHS 0x2
|
|
#define PVSF_IGNOREPVS 0x3
|
|
#define PVSF_MODE_MASK 0x3
|
|
#define PVSF_NOREMOVE 0x80
|
|
|
|
// entity effects
|
|
|
|
//define EF_BRIGHTFIELD 1
|
|
//define EF_MUZZLEFLASH 2
|
|
//#define EF_BRIGHTLIGHT (1<<2)
|
|
//#define EF_DIMLIGHT (1<<4)
|
|
|
|
//#define EF_FULLBRIGHT 512
|
|
|
|
|
|
#define SPAWNFLAG_NOT_EASY (1<<8)
|
|
#define SPAWNFLAG_NOT_MEDIUM (1<<9)
|
|
#define SPAWNFLAG_NOT_HARD (1<<10)
|
|
#define SPAWNFLAG_NOT_DEATHMATCH (1<<11)
|
|
|
|
#define SPAWNFLAG_NOT_H2PALADIN (1<<8)
|
|
#define SPAWNFLAG_NOT_H2CLERIC (1<<9)
|
|
#define SPAWNFLAG_NOT_H2NECROMANCER (1<<10)
|
|
#define SPAWNFLAG_NOT_H2THEIF (1<<11)
|
|
#define SPAWNFLAG_NOT_H2EASY (1<<12)
|
|
#define SPAWNFLAG_NOT_H2MEDIUM (1<<13)
|
|
#define SPAWNFLAG_NOT_H2HARD (1<<14)
|
|
#define SPAWNFLAG_NOT_H2DEATHMATCH (1<<15)
|
|
#define SPAWNFLAG_NOT_H2COOP (1<<16)
|
|
#define SPAWNFLAG_NOT_H2SINGLE (1<<17)
|
|
|
|
#if 0//ndef Q2SERVER
|
|
typedef enum multicast_e
|
|
{
|
|
MULTICAST_ALL,
|
|
MULTICAST_PHS,
|
|
MULTICAST_PVS,
|
|
MULTICAST_ALL_R,
|
|
MULTICAST_PHS_R,
|
|
MULTICAST_PVS_R
|
|
} multicast_t;
|
|
#endif
|
|
|
|
|
|
//shared with qc
|
|
#define MSG_PRERELONE -100
|
|
#define MSG_BROADCAST 0 // unreliable to all
|
|
#define MSG_ONE 1 // reliable to one (msg_entity)
|
|
#define MSG_ALL 2 // reliable to all
|
|
#define MSG_INIT 3 // write to the init string
|
|
#define MSG_MULTICAST 4 // for multicast()
|
|
#define MSG_CSQC 5 // for writing csqc entities
|
|
|
|
//============================================================================
|
|
|
|
extern cvar_t sv_mintic, sv_maxtic, sv_limittics;
|
|
extern cvar_t sv_maxspeed;
|
|
extern cvar_t sv_antilag;
|
|
extern cvar_t sv_antilag_frac;
|
|
|
|
void SV_Master_ReResolve(void);
|
|
void SV_Master_Shutdown(void);
|
|
void SV_Master_Heartbeat (void);
|
|
|
|
extern cvar_t pr_ssqc_progs;
|
|
extern cvar_t spawn;
|
|
extern cvar_t teamplay;
|
|
extern cvar_t deathmatch;
|
|
extern cvar_t coop;
|
|
extern cvar_t fraglimit;
|
|
extern cvar_t timelimit;
|
|
|
|
extern server_static_t svs; // persistant server info
|
|
extern server_t sv; // local server
|
|
|
|
extern client_t *host_client;
|
|
|
|
extern edict_t *sv_player;
|
|
|
|
//extern char localmodels[MAX_MODELS][5]; // inline model names for precache
|
|
|
|
extern vfsfile_t *sv_fraglogfile;
|
|
|
|
//===========================================================
|
|
|
|
void SV_AddDebugPolygons(void);
|
|
const char *SV_CheckRejectConnection(netadr_t *adr, const char *uinfo, unsigned int protocol, unsigned int pext1, unsigned int pext2, 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);
|
|
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 (const 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(const 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;
|
|
char printtext[4096]; //to split it into lines.
|
|
} 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, const 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 SV_StuffcmdToClient_Unreliable(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_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);
|
|
|
|
#ifdef NQPROT
|
|
void SV_DarkPlacesDownloadChunk(client_t *cl, sizebuf_t *msg);
|
|
#endif
|
|
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);
|
|
vfsfile_t *SVM_GenerateIndex(const char *fname);
|
|
|
|
|
|
//
|
|
// 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);
|
|
extern char sv_redirected_buf[8000];
|
|
extern redirect_t sv_redirected;
|
|
extern int sv_redirectedlang;
|
|
|
|
|
|
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
|
|
|
|
|
|
#ifdef MVD_RECORDING
|
|
/*
|
|
//
|
|
// sv_mvd.c
|
|
//
|
|
//qtv proxies are meant to send a small header now, bit like http
|
|
//this header gives supported version numbers and stuff
|
|
typedef struct mvdpendingdest_s {
|
|
qboolean error; //disables writers, quit ASAP.
|
|
#ifdef _WIN32
|
|
qintptr_t socket;
|
|
#else
|
|
int socket;
|
|
#endif
|
|
|
|
char inbuffer[2048];
|
|
char outbuffer[2048];
|
|
|
|
char challenge[64];
|
|
qboolean hasauthed;
|
|
qboolean isreverse;
|
|
|
|
int insize;
|
|
int outsize;
|
|
|
|
struct mvdpendingdest_s *nextdest;
|
|
} mvdpendingdest_t;*/
|
|
|
|
typedef struct mvddest_s {
|
|
qboolean error; //disables writers, quit ASAP.
|
|
qboolean droponmapchange;
|
|
|
|
enum {DEST_NONE, DEST_FILE, DEST_BUFFEREDFILE, DEST_THREADEDFILE, DEST_STREAM} desttype;
|
|
|
|
vfsfile_t *file;
|
|
|
|
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_demoDir;
|
|
extern cvar_t sv_demoAutoRecord;
|
|
extern cvar_t sv_demofps;
|
|
extern cvar_t sv_demoPings;
|
|
extern cvar_t sv_demoUseCache;
|
|
extern cvar_t sv_demoMaxSize;
|
|
extern cvar_t sv_demoMaxDirSize;
|
|
|
|
qboolean MVD_CheckSpace(qboolean broadcastwarnings);
|
|
void SV_MVD_AutoRecord (void);
|
|
char *SV_Demo_CurrentOutput(void);
|
|
void SV_Demo_PrintOutputs(void);
|
|
void SV_MVDInit(void);
|
|
char *SV_MVDNum(char *buffer, int bufferlen, int num);
|
|
const char *SV_MVDLastNum(unsigned int num);
|
|
void SV_SendMVDMessage(void);
|
|
void SV_MVD_WriteReliables(qboolean writebroadcasts);
|
|
qboolean SV_ReadMVD (void);
|
|
void SV_FlushDemoSignon (void);
|
|
void DestFlush(qboolean compleate);
|
|
|
|
typedef struct
|
|
{
|
|
qboolean hasauthed;
|
|
qboolean isreverse;
|
|
char challenge[32];
|
|
} qtvpendingstate_t;
|
|
int SV_MVD_GotQTVRequest(vfsfile_t *clientstream, char *headerstart, char *headerend, qtvpendingstate_t *p);
|
|
#endif
|
|
|
|
// savegame.c
|
|
void SV_Savegame_f (void);
|
|
void SV_Savegame_c(int argn, const char *partial, struct xcommandargcompletioncb_s *ctx);
|
|
void SV_Loadgame_f (void);
|
|
qboolean SV_Loadgame (const char *unsafe_savename);
|
|
void SV_AutoSave(void);
|
|
void SV_FlushLevelCache(void);
|
|
extern cvar_t sv_autosave;
|
|
extern cvar_t sv_savefmt;
|
|
|
|
|
|
int SV_RateForClient(client_t *cl);
|
|
|
|
void SVVC_Frame (qboolean enabled);
|
|
void SV_CalcPHS (void);
|
|
|
|
void SV_GetConsoleCommands (void);
|
|
void SV_CheckTimer(void);
|
|
|
|
void SV_LogPlayer(client_t *cl, char *msg);
|
|
|
|
extern vec3_t pmove_mins, pmove_maxs; //abs min/max extents
|
|
#ifdef USEAREAGRID
|
|
void AddAllLinksToPmove (world_t *w, wedict_t *player);
|
|
#else
|
|
void AddLinksToPmove (world_t *w, wedict_t *player, areanode_t *node);
|
|
void AddLinksToPmove_Force (world_t *w, wedict_t *player, areanode_t *node);
|
|
#define AddAllLinksToPmove(w,p) do{AddLinksToPmove(w,p,(w)->areanodes);AddLinksToPmove_Force(w,p,&(w)->portallist);}while(0)
|
|
#endif
|
|
|
|
|
|
#ifdef HLSERVER
|
|
void SVHL_SaveLevelCache(char *filename);
|
|
|
|
//network frame info
|
|
void SVHL_Snapshot_Build(client_t *client, packet_entities_t *pack, qbyte *pvs, edict_t *clent, qboolean ignorepvs);
|
|
qbyte *SVHL_Snapshot_SetupPVS(client_t *client, qbyte *pvs, unsigned int pvsbufsize);
|
|
void SVHL_BuildStats(client_t *client, int *si, float *sf, char **ss);
|
|
|
|
//gamecode entry points
|
|
int SVHL_InitGame(void);
|
|
void SVHL_SetupGame(void);
|
|
void SVHL_SpawnEntities(char *entstring);
|
|
void SVHL_RunFrame (void);
|
|
qboolean SVHL_ClientConnect(client_t *client, netadr_t adr, char rejectmessage[128]);
|
|
void SVHL_PutClientInServer(client_t *client);
|
|
void SVHL_RunPlayerCommand(client_t *cl, usercmd_t *oldest, usercmd_t *oldcmd, usercmd_t *newcmd);
|
|
qboolean HLSV_ClientCommand(client_t *client);
|
|
void SVHL_DropClient(client_t *drop);
|
|
void SVHL_ShutdownGame(void);
|
|
#endif
|
|
|