mirror of
https://github.com/nzp-team/fteqw.git
synced 2024-11-27 06:02:16 +00:00
2ee8387644
Console code no longer makes assumptions about con_main Screenshots rework, for screenshot_360, but also some other cleanups. Fixed an issue with beginpolygon (finally). Added per-rtlight style strings. Added cvar to control whether ents will be culled by fog. Added define to disable IPLOG, etc. Added r_editlights cvar and related commands, for whenever csaddon isn't available. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5338 fc73d0e0-1445-4013-8a0c-d673dee63da5
1637 lines
48 KiB
C
1637 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
|
|
int sequence; //the outgoing sequence - without mask, meaning we know if its current or stale
|
|
float ping_time; //how long it took for the client to ack it, may be negative
|
|
float move_msecs; //
|
|
int packetsizein; //amount of data received for this frame
|
|
int packetsizeout; //amount of data that was sent in the frame
|
|
|
|
packet_entities_t qwentities; //package containing entity states that were sent in this frame, for deltaing
|
|
|
|
struct resendinfo_s
|
|
{
|
|
unsigned int entnum;
|
|
unsigned int bits; //delta (fte or dpp5+)
|
|
unsigned int flags; //csqc
|
|
} *resend;
|
|
unsigned int numresend;
|
|
unsigned int maxresend;
|
|
|
|
unsigned short resendstats[32];//the number of each entity that was sent in this frame
|
|
unsigned int numresendstats; //the bits of each entity that were sent in this frame
|
|
|
|
//antilag
|
|
//these are to recalculate the player's origin without old knockbacks nor teleporters, to give more accurate weapon start positions (post-command).
|
|
vec3_t pmorigin;
|
|
vec3_t pmvelocity;
|
|
int pmtype;
|
|
unsigned int pmjumpheld:1;
|
|
unsigned int pmonladder:1;
|
|
float pmwaterjumptime;
|
|
usercmd_t cmd;
|
|
//these are old positions of players, to give more accurate victim positions
|
|
vec3_t playerpositions[MAX_CLIENTS]; //where each player was in this frame, for antilag
|
|
qboolean playerpresent[MAX_CLIENTS]; //whether the player was actually present
|
|
} client_frame_t;
|
|
|
|
#ifdef Q2SERVER
|
|
typedef struct //merge?
|
|
{
|
|
int areabytes;
|
|
qbyte areabits[MAX_Q2MAP_AREAS/8]; // portalarea visibility bits
|
|
q2player_state_t ps[MAX_SPLITS]; //yuck
|
|
int clientnum[MAX_SPLITS];
|
|
int num_entities;
|
|
int first_entity; // into the circular sv_packet_entities[]
|
|
int senttime; // for ping calculations
|
|
float ping_time;
|
|
} q2client_frame_t;
|
|
#endif
|
|
#ifdef Q3SERVER
|
|
#include "clq3defs.h"
|
|
typedef struct //merge?
|
|
{
|
|
int flags;
|
|
int areabytes;
|
|
qbyte areabits[MAX_Q2MAP_AREAS/8]; // portalarea visibility bits
|
|
q3playerState_t ps;
|
|
int num_entities;
|
|
int first_entity; // into the circular sv_packet_entities[]
|
|
int senttime; // for ping calculations
|
|
|
|
|
|
int serverMessageNum;
|
|
int serverCommandNum;
|
|
int serverTime; // server time the message is valid for (in msec)
|
|
int localTime;
|
|
int deltaFrame;
|
|
} q3client_frame_t;
|
|
#endif
|
|
|
|
#define MAX_BACK_BUFFERS 16
|
|
|
|
enum
|
|
{
|
|
PRESPAWN_INVALID=0,
|
|
PRESPAWN_PROTOCOLSWITCH, //nq drops unreliables until reliables are acked. this gives us a chance to drop any clc_move packets with formats from the previous map
|
|
PRESPAWN_SERVERINFO,
|
|
#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;
|
|
|
|
// spawn parms are carried from level to level
|
|
float spawn_parms[NUM_SPAWN_PARMS];
|
|
char *spawn_parmstring; //qc-specified data.
|
|
char *spawninfo; //entity-formatted data (for hexen2's ClientReEnter)
|
|
float spawninfotime;
|
|
float nextservertimeupdate; //next time to send STAT_TIME
|
|
float lastoutgoingphysicstime;//sv.world.physicstime of the last outgoing message.
|
|
|
|
// client known data for deltas
|
|
int old_frags;
|
|
|
|
unsigned int pendingstats[((MAX_CL_STATS*2) + 31)>>5]; //these are the stats that have changed and that need sending/resending
|
|
int statsi[MAX_CL_STATS];
|
|
float statsf[MAX_CL_STATS];
|
|
char *statss[MAX_CL_STATS];
|
|
char *centerprintstring;
|
|
|
|
union{ //save space
|
|
client_frame_t *frames; // updates can be deltad from here
|
|
#ifdef Q2SERVER
|
|
q2client_frame_t *q2frames;
|
|
#endif
|
|
#ifdef Q3SERVER
|
|
q3client_frame_t *q3frames;
|
|
#endif
|
|
} frameunion;
|
|
packet_entities_t sentents;
|
|
unsigned int *pendingdeltabits;
|
|
unsigned int *pendingcsqcbits;
|
|
unsigned int nextdeltaindex; //splurged round-robin to deal with overflows
|
|
unsigned int nextcsqcindex; //splurged round-robin
|
|
#define SENDFLAGS_USABLE 0x3fffffffu //this number of bits are actually safe in a float. not all together, but otherwise safe.
|
|
#define SENDFLAGS_PRESENT 0x80000000u //this entity is present on that client
|
|
#define SENDFLAGS_REMOVED 0x40000000u //to handle remove packetloss
|
|
|
|
char downloadfn[MAX_QPATH];
|
|
vfsfile_t *download; // file being downloaded
|
|
qofs_t downloadsize; // total bytes
|
|
qofs_t downloadcount; // bytes sent
|
|
|
|
qofs_t downloadacked; //DP-specific
|
|
qofs_t downloadstarted; //DP-specific
|
|
|
|
int spec_track; // entnum of player tracking
|
|
|
|
unsigned int spec_print; //bitfield for things this spectator should see that were directed to the player that they're tracking.
|
|
|
|
#ifdef Q3SERVER
|
|
int gamestatesequence; //the sequence number the initial gamestate was sent in.
|
|
int last_server_command_num;
|
|
int last_client_command_num;
|
|
int num_server_commands;
|
|
int num_client_commands;
|
|
char server_commands[64][1024];
|
|
char last_client_command[1024];
|
|
#endif
|
|
|
|
//true/false/persist
|
|
unsigned int penalties;
|
|
qbyte istobeloaded; //loadgame creates place holders for clients to connect to. Effectivly loading a game reconnects all clients, but has precreated ents.
|
|
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;
|
|
|
|
int language; //the server operators language
|
|
laggedpacket_t *free_lagged_packet;
|
|
packet_entities_t entstatebuffer; /*just a temp buffer*/
|
|
|
|
char name[64]; // map name (base filename). static because of restart command after disconnecting.
|
|
levelcache_t *levcache;
|
|
|
|
struct frameendtasks_s
|
|
{
|
|
struct frameendtasks_s *next;
|
|
void(*callback)(struct frameendtasks_s *task);
|
|
void *ctxptr;
|
|
intptr_t ctxint;
|
|
char data[1];
|
|
} *frameendtasks;
|
|
} server_static_t;
|
|
|
|
//=============================================================================
|
|
|
|
/*
|
|
// edict->movetype values
|
|
#define MOVETYPE_NONE 0 // never moves
|
|
#define MOVETYPE_ANGLENOCLIP 1
|
|
#define MOVETYPE_ANGLECLIP 2
|
|
#define MOVETYPE_WALK 3 // gravity
|
|
#define MOVETYPE_STEP 4 // gravity, special edge handling
|
|
#define MOVETYPE_FLY 5
|
|
#define MOVETYPE_TOSS 6 // gravity
|
|
#define MOVETYPE_PUSH 7 // no clip to world, push and crush
|
|
#define MOVETYPE_NOCLIP 8
|
|
#define MOVETYPE_FLYMISSILE 9 // extra size to monsters
|
|
#define MOVETYPE_BOUNCE 10
|
|
#define MOVETYPE_BOUNCEMISSILE 11 // bounce w/o gravity
|
|
#define MOVETYPE_FOLLOW 12 // track movement of aiment
|
|
#define MOVETYPE_H2PUSHPULL 13 // pushable/pullable object
|
|
#define MOVETYPE_H2SWIM 14 // should keep the object in water
|
|
#define MOVETYPE_PHYSICS 32
|
|
#define MOVETYPE_FLY_WORLDONLY 33
|
|
|
|
// edict->solid values
|
|
#define SOLID_NOT 0 // no interaction with other objects
|
|
#define SOLID_TRIGGER 1 // touch on edge, but not blocking
|
|
#define SOLID_BBOX 2 // touch on edge, block
|
|
#define SOLID_SLIDEBOX 3 // touch on edge, but not an onground
|
|
#define SOLID_BSP 4 // bsp clip, touch on edge, block
|
|
#define SOLID_PHASEH2 5
|
|
#define SOLID_CORPSE 5
|
|
#define SOLID_LADDER 20 //dmw. touch on edge, not blocking. Touching players have different physics. Otherwise a SOLID_TRIGGER. deprecated. use solid_bsp and skin=-16
|
|
|
|
#define DAMAGE_NO 0
|
|
#define DAMAGE_YES 1
|
|
#define DAMAGE_AIM 2
|
|
*/
|
|
|
|
#define PVSF_NORMALPVS 0x0
|
|
#define PVSF_NOTRACECHECK 0x1
|
|
#define PVSF_USEPHS 0x2
|
|
#define PVSF_IGNOREPVS 0x3
|
|
#define PVSF_MODE_MASK 0x3
|
|
#define PVSF_NOREMOVE 0x80
|
|
|
|
// entity effects
|
|
|
|
//define EF_BRIGHTFIELD 1
|
|
//define EF_MUZZLEFLASH 2
|
|
//#define EF_BRIGHTLIGHT (1<<2)
|
|
//#define EF_DIMLIGHT (1<<4)
|
|
|
|
//#define EF_FULLBRIGHT 512
|
|
|
|
|
|
#define SPAWNFLAG_NOT_EASY (1<<8)
|
|
#define SPAWNFLAG_NOT_MEDIUM (1<<9)
|
|
#define SPAWNFLAG_NOT_HARD (1<<10)
|
|
#define SPAWNFLAG_NOT_DEATHMATCH (1<<11)
|
|
|
|
#define SPAWNFLAG_NOT_H2PALADIN (1<<8)
|
|
#define SPAWNFLAG_NOT_H2CLERIC (1<<9)
|
|
#define SPAWNFLAG_NOT_H2NECROMANCER (1<<10)
|
|
#define SPAWNFLAG_NOT_H2THEIF (1<<11)
|
|
#define SPAWNFLAG_NOT_H2EASY (1<<12)
|
|
#define SPAWNFLAG_NOT_H2MEDIUM (1<<13)
|
|
#define SPAWNFLAG_NOT_H2HARD (1<<14)
|
|
#define SPAWNFLAG_NOT_H2DEATHMATCH (1<<15)
|
|
#define SPAWNFLAG_NOT_H2COOP (1<<16)
|
|
#define SPAWNFLAG_NOT_H2SINGLE (1<<17)
|
|
|
|
#if 0//ndef Q2SERVER
|
|
typedef enum multicast_e
|
|
{
|
|
MULTICAST_ALL,
|
|
MULTICAST_PHS,
|
|
MULTICAST_PVS,
|
|
MULTICAST_ALL_R,
|
|
MULTICAST_PHS_R,
|
|
MULTICAST_PVS_R
|
|
} multicast_t;
|
|
#endif
|
|
|
|
|
|
//shared with qc
|
|
#define MSG_PRERELONE -100
|
|
#define MSG_BROADCAST 0 // unreliable to all
|
|
#define MSG_ONE 1 // reliable to one (msg_entity)
|
|
#define MSG_ALL 2 // reliable to all
|
|
#define MSG_INIT 3 // write to the init string
|
|
#define MSG_MULTICAST 4 // for multicast()
|
|
#define MSG_CSQC 5 // for writing csqc entities
|
|
|
|
//============================================================================
|
|
|
|
extern cvar_t sv_mintic, sv_maxtic, sv_limittics;
|
|
extern cvar_t sv_maxspeed;
|
|
extern cvar_t sv_antilag;
|
|
extern cvar_t sv_antilag_frac;
|
|
|
|
void SV_Master_ReResolve(void);
|
|
void SV_Master_Shutdown(void);
|
|
void SV_Master_Heartbeat (void);
|
|
|
|
extern cvar_t pr_ssqc_progs;
|
|
extern cvar_t spawn;
|
|
extern cvar_t teamplay;
|
|
extern cvar_t deathmatch;
|
|
extern cvar_t coop;
|
|
extern cvar_t fraglimit;
|
|
extern cvar_t timelimit;
|
|
|
|
extern server_static_t svs; // persistant server info
|
|
extern server_t sv; // local server
|
|
|
|
extern client_t *host_client;
|
|
|
|
extern edict_t *sv_player;
|
|
|
|
//extern char localmodels[MAX_MODELS][5]; // inline model names for precache
|
|
|
|
extern 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);
|
|
|
|
|
|
//
|
|
// svonly.c
|
|
//
|
|
typedef enum {RD_NONE, RD_CLIENT, RD_PACKET, RD_PACKET_LOG, RD_OBLIVION, RD_MASTER} redirect_t; //oblivion is provided so people can read the output before the buffer is wiped.
|
|
void SV_BeginRedirect (redirect_t rd, int lang);
|
|
void SV_EndRedirect (void);
|
|
|
|
|
|
qboolean PR_GameCodePacket(char *s);
|
|
qboolean PR_GameCodePausedTic(float pausedtime);
|
|
qboolean PR_ShouldTogglePause(client_t *initiator, qboolean pausedornot);
|
|
|
|
//
|
|
// sv_ents.c
|
|
//
|
|
void SV_WriteEntitiesToClient (client_t *client, sizebuf_t *msg, qboolean ignorepvs);
|
|
void SVFTE_EmitBaseline(entity_state_t *to, qboolean numberisimportant, sizebuf_t *msg, unsigned int pext2);
|
|
void SVQ3Q1_BuildEntityPacket(client_t *client, packet_entities_t *pack);
|
|
void SV_Snapshot_BuildStateQ1(entity_state_t *state, edict_t *ent, client_t *client, packet_entities_t *pack);
|
|
int SV_HullNumForPlayer(int h2hull, float *mins, float *maxs);
|
|
void SV_GibFilterInit(void);
|
|
void SV_GibFilterPurge(void);
|
|
void SV_CleanupEnts(void);
|
|
void SV_ProcessSendFlags(client_t *c);
|
|
|
|
void SV_AckEntityFrame(client_t *cl, int framenum);
|
|
void SV_ReplaceEntityFrame(client_t *cl, int framenum);
|
|
|
|
//
|
|
// sv_nchan.c
|
|
//
|
|
|
|
void ClientReliableCheckBlock(client_t *cl, int maxsize);
|
|
void ClientReliable_FinishWrite(client_t *cl);
|
|
void ClientReliableWrite_Begin(client_t *cl, int c, int maxsize);
|
|
client_t *ClientReliableWrite_BeginSplit(client_t *cl, int svc, int svclen);
|
|
void ClientReliableWrite_Angle(client_t *cl, float f);
|
|
void ClientReliableWrite_Angle16(client_t *cl, float f);
|
|
void ClientReliableWrite_Byte(client_t *cl, int c);
|
|
void ClientReliableWrite_Char(client_t *cl, int c);
|
|
void ClientReliableWrite_Float(client_t *cl, float f);
|
|
void ClientReliableWrite_Coord(client_t *cl, float f);
|
|
void ClientReliableWrite_Long(client_t *cl, int c);
|
|
void ClientReliableWrite_Short(client_t *cl, int c);
|
|
void ClientReliableWrite_Entity(client_t *cl, int c);
|
|
void ClientReliableWrite_String(client_t *cl, const char *s);
|
|
void ClientReliableWrite_SZ(client_t *cl, const void *data, int len);
|
|
|
|
|
|
#ifdef SVRANKING
|
|
//flags
|
|
#define RANK_MUTED 2
|
|
#define RANK_CUFFED 4
|
|
#define RANK_CRIPPLED 8 //ha ha... get speed cheaters with this!... :o)
|
|
|
|
#define NUM_RANK_SPAWN_PARMS 32
|
|
|
|
typedef struct { //stats info
|
|
int kills;
|
|
int deaths;
|
|
float parm[NUM_RANK_SPAWN_PARMS];
|
|
float timeonserver;
|
|
qbyte flags1;
|
|
qbyte trustlevel;
|
|
char pad2;
|
|
char pad3;
|
|
|
|
#if NUM_RANK_SPAWN_PARMS>32
|
|
quint64_t created;
|
|
quint64_t lastseen;
|
|
#endif
|
|
} rankstats_t;
|
|
|
|
typedef struct { //name, identity and order.
|
|
int prev; //score is held for convineance.
|
|
int next;
|
|
char name[32];
|
|
int pwd;
|
|
float score;
|
|
} rankheader_t;
|
|
|
|
typedef struct {
|
|
rankheader_t h;
|
|
rankstats_t s;
|
|
} rankinfo_t;
|
|
|
|
int Rank_GetPlayerID(char *guid, const char *name, int pwd, qboolean allowcreate, qboolean requirepasswordtobeset);
|
|
void Rank_SetPlayerStats(int id, rankstats_t *stats);
|
|
rankstats_t *Rank_GetPlayerStats(int id, rankstats_t *buffer);
|
|
rankinfo_t *Rank_GetPlayerInfo(int id, rankinfo_t *buffer);
|
|
qboolean Rank_OpenRankings(void);
|
|
void Rank_Flush (void);
|
|
|
|
void Rank_ListTop10_f (void);
|
|
void Rank_RegisterCommands(void);
|
|
int Rank_GetPass (char *name);
|
|
|
|
extern cvar_t rank_needlogin;
|
|
qboolean ReloadRanking(client_t *cl, const char *newname);
|
|
#endif
|
|
|
|
client_t *SV_GetClientForString(const char *name, int *id);
|
|
qboolean SV_MayCheat(void);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void NPP_Flush(void);
|
|
void NPP_NQWriteByte(int dest, qbyte data);
|
|
void NPP_NQWriteChar(int dest, char data);
|
|
void NPP_NQWriteShort(int dest, short data);
|
|
void NPP_NQWriteLong(int dest, long data);
|
|
void NPP_NQWriteAngle(int dest, float data);
|
|
void NPP_NQWriteCoord(int dest, float data);
|
|
void NPP_NQWriteFloat(int dest, float data);
|
|
void NPP_NQWriteString(int dest, const char *data);
|
|
void NPP_NQWriteEntity(int dest, int data);
|
|
|
|
void NPP_QWWriteByte(int dest, qbyte data);
|
|
void NPP_QWWriteChar(int dest, char data);
|
|
void NPP_QWWriteShort(int dest, short data);
|
|
void NPP_QWWriteLong(int dest, long data);
|
|
void NPP_QWWriteAngle(int dest, float data);
|
|
void NPP_QWWriteCoord(int dest, float data);
|
|
void NPP_QWWriteFloat(int dest, float data);
|
|
void NPP_QWWriteString(int dest, const char *data);
|
|
void NPP_QWWriteEntity(int dest, int data);
|
|
|
|
|
|
|
|
void NPP_MVDForceFlush(void);
|
|
|
|
|
|
//replacement rand function (useful cos it's fully portable, with seed grabbing)
|
|
void predictablesrand(unsigned int x);
|
|
int predictablerandgetseed(void);
|
|
int predictablerand(void);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef SVCHAT
|
|
void SV_WipeChat(client_t *client);
|
|
int SV_ChatMove(int impulse);
|
|
void SV_ChatThink(client_t *client);
|
|
#endif
|
|
|
|
|
|
#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
|
|
|