/*
Copyright (C) 1997-2001 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
// server.h

#include "../qcommon/qcommon.h"
#include "../game/g_public.h"

//=============================================================================

#define	MAX_MASTERS	8				// max recipients for heartbeat packets
#define	HEARTBEAT_SECONDS	300

typedef enum {
	ss_dead,			// no map loaded
	ss_loading,			// spawning level edicts
	ss_game				// actively running
} server_state_t;

// some commands are only valid before the server has finished
// initializing (precache commands, static sounds / objects, etc)

typedef struct
{
	server_state_t	state;			// precache commands are only valid during load
	qboolean	loadgame;			// client begins should reuse existing entity
	
	unsigned	time;				// always sv.framenum * svc.frametime msec
	unsigned	framenum;

	char		name[MAX_QPATH];			// map name, or cinematic name

	char		configstrings[MAX_CONFIGSTRINGS][MAX_CONFIGSTRING_CHARS];
	entity_state_t	baselines[MAX_EDICTS];

	//
	// global variables shared between game and server
	//
	struct edict_s	*edicts;
	int			edict_size;
	int			num_edicts;		// current number, <= max_edicts
	int			max_edicts;
} server_t;

struct gclient_s
{
	player_state_t	ps;		// communicated by server to clients
	client_shared_t	r;
};

struct edict_s
{
	entity_state_t	s;
	entity_shared_t	r;
};

#define EDICT_NUM(n) ((edict_t *)((qbyte *)sv.edicts + sv.edict_size*(n)))
#define NUM_FOR_EDICT(e) ( ((qbyte *)(e)-(qbyte *)sv.edicts ) / sv.edict_size)

/*
typedef enum
{
	CS_FREE,		// can be reused for a new connection
	CS_ZOMBIE,		// client has been disconnected, but don't reuse
					// connection for a couple seconds
	CS_AWAITING,	// has send a "new" command, is awaiting for fetching configstrings
	CS_CONNECTED,	// has been assigned to a client_t, but not in game yet
	CS_SPAWNED		// client is fully in game
}sv_client_state_t;
*/
typedef struct
{
	int					areabytes;
	qbyte				areabits[MAX_MAP_AREAS/8];		// portalarea visibility bits
	player_state_t		ps;
	int					num_entities;
	int					first_entity;		// into the circular sv_packet_entities[]
	unsigned int		sentTimeStamp;		// time at what this frame snap was sent to the clients
	match_state_t		matchstate;
} client_frame_t;

#define	LATENCY_COUNTS	16
#define	RATE_MESSAGES	25	// wsw : jal : was 10: I think it must fit sv_pps, I have to calculate it

typedef struct client_s
{
	sv_client_state_t	state;

	char			userinfo[MAX_INFO_STRING];		// name, etc

	char			reliableCommands[MAX_RELIABLE_COMMANDS][MAX_STRING_CHARS];
	int				reliableSequence;		// last added reliable message, not necesarily sent or acknowledged yet
	int				reliableAcknowledge;	// last acknowledged reliable message
	int				reliableSent;			// last sent reliable message, not necesarily acknowledged yet

	int				clientCommandExecuted; // last client-command we received

	unsigned int	lastPacketSentTime;		// time when we sent the last message to this client
	unsigned int	lastPacketReceivedTime;	// time when we received the last message from this client
	unsigned		lastconnect;

	int				lastframe;	// for delta compression (must be signed, -1 means no compression)
	usercmd_t		lastcmd;			// for filling in big drops
	unsigned int	lastSentFrameNum;	// for knowing which was last frame we sent

	int				commandMsec;		// every seconds this is reset, if user
										// commands exhaust it, assume time cheating

	int				frame_latency[LATENCY_COUNTS];
	int				ping;
#ifndef RATEKILLED
	//int				message_size[RATE_MESSAGES];	// used to rate drop packets
	int				rate;
	int				suppressCount;		// number of messages rate suppressed
#endif
	edict_t			*edict;				// EDICT_NUM(clientnum+1)
	char			name[32];			// extracted from userinfo, high bits masked

	// The sounds datagram is written to by multicasted sound commands
	// It can be harmlessly overflowed.
	msg_t			soundsmsg;
	qbyte			soundsmsgData[MAX_MSGLEN];

	client_frame_t	frames[UPDATE_BACKUP];	// updates can be delta'd from here

	qbyte			*download;			// file being downloaded
	int				downloadsize;		// total bytes (can't use EOF because of paks)
	char			downloadname[MAX_QPATH];
	unsigned int	downloadtimeout;	// so we can free the file being downloaded
										// if client omits sending success of failure message

	int				challenge;			// challenge of this user, randomly generated

	netchan_t		netchan;
#ifdef BATTLEYE
	qboolean		battleye;
	battleye_transmit_t	BE;
#endif
} client_t;

// a client can leave the server in one of four ways:
// dropping properly by quiting or disconnecting
// timing out if no valid messages are received for timeout.value seconds
// getting kicked off by the server operator
// a program error, like an overflowed reliable buffer

//=============================================================================

// MAX_CHALLENGES is made large to prevent a denial
// of service attack that could cycle all of them
// out before legitimate users connected
#define	MAX_CHALLENGES	1024

typedef struct
{
	netadr_t	adr;
	int			challenge;
	int			time;
} challenge_t;


typedef struct
{
	qboolean	initialized;				// sv_init has completed
	unsigned	realtime;					// always increasing, no clamping, etc

	char		mapcmd[MAX_TOKEN_CHARS];	// ie: *intro.cin+base 

	int			spawncount;					// incremented each server start
											// used to check late spawns

	client_t	*clients;					// [maxclients->integer];
	int			num_client_entities;		// maxclients->integer*UPDATE_BACKUP*MAX_PACKET_ENTITIES
	int			next_client_entities;		// next client_entity to use
	entity_state_t	*client_entities;		// [num_client_entities]

	challenge_t	challenges[MAX_CHALLENGES];	// to prevent invalid IPs from connecting

#ifdef SERVERSIDE_DEMOS
	// serverrecord values
	FILE		*demofile;
	msg_t	demo_multicast;
	qbyte		demo_multicast_buf[MAX_MSGLEN];
#endif

} server_static_t;

typedef struct
{
	int			last_heartbeat;
	unsigned	frametime;					// msecs between server packets
} server_constant_t;

//=============================================================================

// shared message buffer to be used for occasional messages
extern msg_t		tmpMessage;
extern qbyte		tmpMessageData[MAX_MSGLEN];

extern	netadr_t	net_from;
extern	netadr_t	master_adr[MAX_MASTERS];	// address of the master server

extern	mempool_t	*sv_mempool;

extern	server_constant_t svc;				// constant server info (trully persistant since sv_init)
extern	server_static_t	svs;				// persistant server info
extern	server_t		sv;					// local server

extern	cvar_t		*sv_maxclients;
extern	cvar_t		*sv_noreload;			// don't reload level state when reentering

extern	cvar_t		*sv_enforcetime;

extern	client_t	*sv_client;
extern	edict_t		*sv_player;

//wsw : jal
extern	cvar_t		*sv_maxrate;
extern	cvar_t		*sv_public;			// should heartbeats be sent

// wsw : debug netcode
extern	cvar_t		*sv_debug_serverCmd;

extern	cvar_t		*sv_uploads;
extern	cvar_t		*sv_uploads_from_server;
extern	cvar_t		*sv_uploads_baseurl;

#ifdef BATTLEYE
extern	cvar_t		*sv_battleye;
#endif

//===========================================================

//
// sv_main.c
//
void SV_FinalMessage( char *message, qboolean reconnect );
void SV_DropClient( client_t *drop, int type, char *fmt, ... );

int SV_ModelIndex( char *name );
int SV_SoundIndex( char *name );
int SV_ImageIndex( char *name );
int SV_SkinIndex( char *name );

void SV_WriteClientdataToMessage( client_t *client, msg_t *msg );

void SV_ExecuteUserCommand( char *s);
void SV_InitOperatorCommands( void );

void SV_SendServerinfo( client_t *client );
void SV_UserinfoChanged( client_t *cl );

void SV_MasterHeartbeat( void );

void SVC_MasterInfoResponse( void );
void SVC_FakeConnect( char *fakeUserinfo, char *fakeIP );

#ifdef COLLISION4D
void SV_BackUpCollisionFrame( void );
#endif

#ifdef BATTLEYE
void SV_BattlEyeFrame( int msec );
#endif

//
// sv_init.c
//
void SV_InitGame( void );
void SV_Map( char *levelstring, qboolean loadgame, qboolean devmap );

void SV_FreeCachedChecksums (void);
unsigned SV_GetCachedPakChecksum (const char *pakname);

//
// sv_phys.c
//
void SV_PrepWorldFrame (void);

//
// sv_send.c
//
void SV_SendServerCommand( client_t *cl, const char *fmt, ... );
void SV_AddReliableCommandsToMessage( client_t *client, msg_t *msg );
qboolean SV_SendClientsFragments( void );
void SV_SendMessageToClient( client_t *client, msg_t *msg );
void SV_ResetClientFrameCounters( void );

typedef enum {RD_NONE, RD_CLIENT, RD_PACKET} redirect_t;

// destination class for SV_multicast
typedef enum {
	MULTICAST_ALL,
	MULTICAST_PHS,
	MULTICAST_PVS
} multicast_t;

#define	SV_OUTPUTBUF_LENGTH	(MAX_MSGLEN - 16)

extern	char	sv_outputbuf[SV_OUTPUTBUF_LENGTH];

void SV_FlushRedirect( int sv_redirected, char *outputbuf );
void SV_SendClientMessages( void );

void SV_Multicast( vec3_t origin, multicast_t to );
void SV_StartSound( vec3_t origin, edict_t *entity, int channel,
					int soundindex, float volume,
					float attenuation );
void SV_ClientPrintf( client_t *cl, char *fmt, ... );
void SV_ClientChatf( client_t *cl, char *fmt, ... );
void SV_BroadcastCommand( char *fmt, ... );

//
// sv_user.c
//
void SV_Nextserver( void );
void SV_ExecuteClientMessage( client_t *client, msg_t *msg );

//
// sv_ccmds.c
//
void SV_ReadLevelFile( void );
void SV_Status_f( void );

//
// sv_ents.c
//
void SV_WriteFrameSnapToClient( client_t *client, msg_t *msg );
void SV_BuildClientFrameSnap( client_t *client );


void SV_Error( char *error, ... );

//
// sv_game.c
//
extern	game_export_t	*ge;

void SV_InitGameProgs (void);
void SV_ShutdownGameProgs (void);
void SV_InitEdict (edict_t *e);

void SV_SetAreaPortalState ( edict_t *ent, qboolean open );


//============================================================

//
// high level object sorting to reduce interaction tests
//

void SV_ClearWorld (void);
// called after the world model has been loaded, before linking any entities

void SV_UnlinkEdict (edict_t *ent);
// call before removing an entity, and before trying to move one,
// so it doesn't clip against itself

void SV_LinkEdict (edict_t *ent);
// Needs to be called any time an entity changes origin, mins, maxs,
// or solid.  Automatically unlinks if needed.
// sets ent->v.absmin and ent->v.absmax
// sets ent->leafnums[] for pvs determination even if the entity
// is not solid
#ifdef COLLISION4D
int SV_AreaEdicts( vec3_t mins, vec3_t maxs, int *list, int maxcount, int areatype );
#else
int SV_AreaEdicts (vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype);
#endif
// fills in a table of edict pointers with edicts that have bounding boxes
// that intersect the given area.  It is possible for a non-axial bmodel
// to be returned that doesn't actually intersect the area on an exact
// test.
// returns the number of pointers filled in
// ??? does this always return the world?

//===================================================================

//
// functions that interact with everything apropriate
//
int SV_PointContents (vec3_t p);
// returns the CONTENTS_* value from the world at the given point.
// Quake 2 extends this to also check entities, to allow moving liquids


void SV_Trace (trace_t *tr, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask);
// mins and maxs are relative

// if the entire move stays in a solid volume, trace.allsolid will be set,
// trace.startsolid will be set, and trace.fraction will be 0

// if the starting point is in a solid, it will be allowed to move out
// to an open area

// passedict is explicitly excluded from clipping checks (normally NULL)

#ifdef BATTLEYE
//
// sv_battleye.c
//
#define BATTLEYE_MASTERSERVER	"wsw.battleye.com:44400"

extern qboolean SV_BE_ConnectToMaster(void);
extern int SV_BE_CheckConnectAttempt(void);
extern void SV_BE_SendToMaster(void* buf, int len);
extern int SV_BE_ReceiveFromMaster(void* buf, int len);
extern void SV_BE_DisconnectFromMaster(void);
#endif

#ifdef SERVERSIDE_DEMOS
//
// sv_demos.c
//
#define MAX_DEMO_MSGLEN 32768
void SV_ServerRecord_f(void);
void SV_ServerStop_f(void);
void SV_RecordDemoMessage(void);
#endif
