/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.
Copyright (C) 2000-2013 Darklegion Development
Copyright (C) 2015-2019 GrangerHub
This file is part of Tremulous.
Tremulous 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 3 of the License,
or (at your option) any later version.
Tremulous 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 Tremulous; if not, see
===========================================================================
*/
// client.h -- primary header for client
#ifndef _CLIENT_H_
#define _CLIENT_H_
#ifdef USE_VOIP
#include
#endif
#include "cgame/cg_public.h"
#include "qcommon/alternatePlayerstate.h"
#include "qcommon/cmd.h"
#include "qcommon/crypto.h"
#include "qcommon/cvar.h"
#include "qcommon/files.h"
#include "qcommon/huffman.h"
#include "qcommon/msg.h"
#include "qcommon/net.h"
#include "qcommon/q_shared.h"
#include "qcommon/qcommon.h"
#include "qcommon/vm.h"
#include "renderercommon/tr_public.h"
#include "sys/sys_shared.h"
#include "ui/ui_public.h"
#include "cl_curl.h"
#include "keys.h"
#include "snd_public.h"
struct alternateEntityState_t {
int number; // entity index
int eType; // entityType_t
int eFlags;
trajectory_t pos; // for calculating position
trajectory_t apos; // for calculating angles
int time;
int time2;
vec3_t origin;
vec3_t origin2;
vec3_t angles;
vec3_t angles2;
int otherEntityNum; // shotgun sources, etc
int otherEntityNum2;
int groundEntityNum; // ENTITYNUM_NONE = in air
int constantLight; // r + (g<<8) + (b<<16) + (intensity<<24)
int loopSound; // constantly loop this sound
int modelindex;
int modelindex2;
int clientNum; // 0 to (MAX_CLIENTS - 1), for players and corpses
int frame;
int solid; // for client side prediction, trap_linkentity sets this properly
int event; // impulse events -- muzzle flashes, footsteps, etc
int eventParm;
// for players
int misc; // bit flags
int weapon; // determines weapon and flash model, etc
int legsAnim; // mask off ANIM_TOGGLEBIT
int torsoAnim; // mask off ANIM_TOGGLEBIT
int generic1;
};
struct alternateSnapshot_t {
int snapFlags; // SNAPFLAG_RATE_DELAYED, etc
int ping;
int serverTime; // server time the message is valid for (in msec)
byte areamask[MAX_MAP_AREA_BYTES]; // portalarea visibility bits
alternatePlayerState_t ps; // complete information about the current player at this time
int numEntities; // all of the entities that need to be presented
alternateEntityState_t entities[MAX_ENTITIES_IN_SNAPSHOT]; // at the time of this snapshot
int numServerCommands; // text based server commands to execute when this
int serverCommandSequence; // snapshot becomes current
};
// file full of random crap that gets used to create cl_guid
#define QKEY_FILE "qkey"
#define QKEY_SIZE 2048
#define RETRANSMIT_TIMEOUT 3000 // time between connection packet retransmits
// snapshots are a view of the server at a given time
struct clSnapshot_t {
bool valid; // cleared if delta parsing was invalid
int snapFlags; // rate delayed and dropped commands
int serverTime; // server time the message is valid for (in msec)
int messageNum; // copied from netchan->incoming_sequence
int deltaNum; // messageNum the delta is from
int ping; // time from when cmdNum-1 was sent to time packet was reeceived
byte areamask[MAX_MAP_AREA_BYTES]; // portalarea visibility bits
int cmdNum; // the next cmdNum the server is expecting
playerState_t ps; // complete information about the current player at this time
alternatePlayerState_t alternatePs; // complete information about the current player at this time
int numEntities; // all of the entities that need to be presented
int parseEntitiesNum; // at the time of this snapshot
int serverCommandNum; // execute all commands up to this before
// making the snapshot current
};
/*
=============================================================================
the clientActive_t structure is wiped completely at every
new gamestate_t, potentially several times during an established connection
=============================================================================
*/
struct outPacket_t {
int p_cmdNumber; // cl.cmdNumber when packet was sent
int p_serverTime; // usercmd->serverTime when packet was sent
int p_realtime; // cls.realtime when packet was sent
};
// the parseEntities array must be large enough to hold PACKET_BACKUP frames of
// entities, so that when a delta compressed message arives from the server
// it can be un-deltad from the original
#define MAX_PARSE_ENTITIES (PACKET_BACKUP * MAX_SNAPSHOT_ENTITIES)
extern int g_console_field_width;
struct clientActive_t {
int timeoutcount; // it requres several frames in a timeout condition
// to disconnect, preventing debugging breaks from
// causing immediate disconnects on continue
clSnapshot_t snap; // latest received from server
int serverTime; // may be paused during play
int oldServerTime; // to prevent time from flowing bakcwards
int oldFrameServerTime; // to check tournament restarts
int serverTimeDelta; // cl.serverTime = cls.realtime + cl.serverTimeDelta
// this value changes as net lag varies
bool extrapolatedSnapshot; // set if any cgame frame has been forced to extrapolate
// cleared when CL_AdjustTimeDelta looks at it
bool newSnapshots; // set on parse of any valid packet
gameState_t gameState; // configstrings
char mapname[MAX_QPATH]; // extracted from CS_SERVERINFO
int parseEntitiesNum; // index (not anded off) into cl_parse_entities[]
int mouseDx[2], mouseDy[2]; // added to by mouse events
int mouseIndex;
int joystickAxis[MAX_JOYSTICK_AXIS]; // set by joystick events
// cgame communicates a few values to the client system
int cgameUserCmdValue; // current weapon to add to usercmd_t
float cgameSensitivity;
// cmds[cmdNumber] is the predicted command, [cmdNumber-1] is the last
// properly generated command
usercmd_t cmds[CMD_BACKUP]; // each mesage will send several old cmds
int cmdNumber; // incremented each frame, because multiple
// frames may need to be packed into a single packet
outPacket_t outPackets[PACKET_BACKUP]; // information about each packet we have sent out
// the client maintains its own idea of view angles, which are
// sent to the server each frame. It is cleared to 0 upon entering each level.
// the server sends a delta each frame which is added to the locally
// tracked view angles to account for standing on rotating objects,
// and teleport direction changes
vec3_t viewangles;
int serverId; // included in each client message so the server
// can tell if it is for a prior map_restart
// big stuff at end of structure so most offsets are 15 bits or less
clSnapshot_t snapshots[PACKET_BACKUP];
entityState_t entityBaselines[MAX_GENTITIES]; // for delta compression when not in previous frame
entityState_t parseEntities[MAX_PARSE_ENTITIES];
};
extern clientActive_t cl;
/*
=============================================================================
the clientConnection_t structure is wiped when disconnecting from a server,
either to go to a full screen console, play a demo, or connect to a different server
A connection can be to either a server through the network layer or a
demo through a file.
=============================================================================
*/
#define MAX_TIMEDEMO_DURATIONS 4096
struct clientConnection_t {
connstate_t state; // connection status
int clientNum;
int lastPacketSentTime; // for retransmits during connection
int lastPacketTime; // for timeouts
char servername[MAX_OSPATH]; // name of server from original connect (used by reconnect)
netadr_t serverAddress;
int connectTime; // for connection retransmits
int connectPacketCount; // for display on connection dialog
char serverMessage[MAX_STRING_TOKENS]; // for display on connection dialog
int challenge; // from the server to use for connecting
char challenge2[33];
bool sendSignature;
int checksumFeed; // from the server for checksum calculations
// these are our reliable messages that go to the server
int reliableSequence;
int reliableAcknowledge; // the last one the server has executed
char reliableCommands[MAX_RELIABLE_COMMANDS][MAX_STRING_CHARS];
// server message (unreliable) and command (reliable) sequence
// numbers are NOT cleared at level changes, but continue to
// increase as long as the connection is valid
// message sequence is used by both the network layer and the
// delta compression layer
int serverMessageSequence;
// reliable messages received from server
int serverCommandSequence;
int lastExecutedServerCommand; // last server command grabbed or executed with CL_GetServerCommand
char serverCommands[MAX_RELIABLE_COMMANDS][MAX_STRING_CHARS];
// file transfer from server
fileHandle_t download;
char downloadTempName[MAX_OSPATH];
char downloadName[MAX_OSPATH];
// XXX Refactor this -vjr
bool cURLEnabled;
bool cURLUsed;
bool cURLDisconnected;
char downloadURL[MAX_OSPATH];
CURL *downloadCURL;
CURLM *downloadCURLM;
bool activeCURLNotGameRelated;
int sv_allowDownload;
char sv_dlURL[MAX_CVAR_VALUE_STRING];
int downloadNumber;
int downloadBlock; // block we are waiting for
int downloadCount; // how many bytes we got
int downloadSize; // how many bytes we got
char downloadList[MAX_INFO_STRING]; // list of paks we need to download
bool downloadRestart; // if true, we need to do another FS_Restart because we downloaded a pak
char newsString[MAX_NEWS_STRING];
// demo information
char demoName[MAX_QPATH];
bool spDemoRecording;
bool demorecording;
bool demoplaying;
bool demowaiting; // don't record until a non-delta message is received
bool firstDemoFrameSkipped;
fileHandle_t demofile;
int timeDemoFrames; // counter of rendered frames
int timeDemoStart; // cls.realtime before first frame
int timeDemoBaseTime; // each frame will be at this time + frameNum * 50
int timeDemoLastFrame; // time the last frame was rendered
int timeDemoMinDuration; // minimum frame duration
int timeDemoMaxDuration; // maximum frame duration
unsigned char timeDemoDurations[MAX_TIMEDEMO_DURATIONS]; // log of frame durations
float aviVideoFrameRemainder;
float aviSoundFrameRemainder;
#ifdef USE_VOIP
bool voipEnabled;
bool voipCodecInitialized;
// incoming data...
// !!! FIXME: convert from parallel arrays to array of a struct.
OpusDecoder *opusDecoder[MAX_CLIENTS];
byte voipIncomingGeneration[MAX_CLIENTS];
int voipIncomingSequence[MAX_CLIENTS];
float voipGain[MAX_CLIENTS];
bool voipIgnore[MAX_CLIENTS];
bool voipMuteAll;
// outgoing data...
// if voipTargets[i / 8] & (1 << (i % 8)),
// then we are sending to clientnum i.
uint8_t voipTargets[(MAX_CLIENTS + 7) / 8];
uint8_t voipFlags;
OpusEncoder *opusEncoder;
int voipOutgoingDataSize;
int voipOutgoingDataFrames;
int voipOutgoingSequence;
byte voipOutgoingGeneration;
byte voipOutgoingData[1024];
float voipPower;
#endif
// big stuff at end of structure so most offsets are 15 bits or less
netchan_t netchan;
};
extern clientConnection_t clc;
/*
==================================================================
the clientStatic_t structure is never wiped, and is used even when
no client connection is active at all
(except when CL_Shutdown is called)
==================================================================
*/
struct ping_t {
netadr_t adr;
int start;
int time;
char info[MAX_INFO_STRING];
};
#define MAX_FEATLABEL_CHARS 32
struct serverInfo_t {
netadr_t adr;
char hostName[MAX_HOSTNAME_LENGTH];
char mapName[MAX_NAME_LENGTH];
char game[MAX_NAME_LENGTH];
char label[MAX_FEATLABEL_CHARS]; // for featured servers, NULL otherwise
int netType;
int gameType;
int clients;
int maxClients;
int minPing;
int maxPing;
int ping;
bool visible;
};
struct clientStatic_t {
// when the server clears the hunk, all of these must be restarted
bool rendererStarted;
bool soundStarted;
bool soundRegistered;
bool uiStarted;
bool cgameStarted;
int framecount;
int frametime; // msec since last frame
int realtime; // ignores pause
int realFrametime; // ignoring pause, so console always works
// master server sequence information
int numAlternateMasterPackets[3];
unsigned int receivedAlternateMasterPackets[3]; // bitfield
int numlocalservers;
serverInfo_t localServers[MAX_OTHER_SERVERS];
int numglobalservers;
serverInfo_t globalServers[MAX_GLOBAL_SERVERS];
// additional global servers
int numGlobalServerAddresses;
netadr_t globalServerAddresses[MAX_GLOBAL_SERVERS];
int numfavoriteservers;
serverInfo_t favoriteServers[MAX_OTHER_SERVERS];
int pingUpdateSource; // source currently pinging or updating
// update server info
netadr_t updateServer;
char updateChallenge[MAX_TOKEN_CHARS];
char updateInfoString[MAX_INFO_STRING];
netadr_t authorizeServer;
// rendering info
glconfig_t glconfig;
qhandle_t charSetShader;
qhandle_t whiteShader;
qhandle_t consoleShader;
vm_t *cgame;
int cgInterface; // 0 == gpp, 2 == 1.1.0
vm_t *ui;
int uiInterface;
struct {
struct rsa_public_key public_key;
struct rsa_private_key private_key;
} rsa;
};
extern clientStatic_t cls;
extern char cl_oldGame[MAX_QPATH];
extern bool cl_oldGameSet;
//=============================================================================
extern refexport_t re; // interface to refresh .dll
//
// cvars
//
extern cvar_t *cl_nodelta;
extern cvar_t *cl_debugMove;
extern cvar_t *cl_noprint;
extern cvar_t *cl_timegraph;
extern cvar_t *cl_maxpackets;
extern cvar_t *cl_packetdup;
extern cvar_t *cl_shownet;
extern cvar_t *cl_showSend;
extern cvar_t *cl_timeNudge;
extern cvar_t *cl_showTimeDelta;
extern cvar_t *cl_freezeDemo;
extern cvar_t *cl_yawspeed;
extern cvar_t *cl_pitchspeed;
extern cvar_t *cl_run;
extern cvar_t *cl_anglespeedkey;
extern cvar_t *cl_sensitivity;
extern cvar_t *cl_freelook;
extern cvar_t *cl_mouseAccel;
extern cvar_t *cl_mouseAccelOffset;
extern cvar_t *cl_mouseAccelStyle;
extern cvar_t *cl_showMouseRate;
extern cvar_t *m_pitch;
extern cvar_t *m_yaw;
extern cvar_t *m_forward;
extern cvar_t *m_side;
extern cvar_t *m_filter;
extern cvar_t *j_pitch;
extern cvar_t *j_yaw;
extern cvar_t *j_forward;
extern cvar_t *j_side;
extern cvar_t *j_up;
extern cvar_t *j_pitch_axis;
extern cvar_t *j_yaw_axis;
extern cvar_t *j_forward_axis;
extern cvar_t *j_side_axis;
extern cvar_t *j_up_axis;
extern cvar_t *cl_timedemo;
extern cvar_t *cl_aviFrameRate;
extern cvar_t *cl_aviMotionJpeg;
extern cvar_t *cl_activeAction;
extern cvar_t *cl_allowDownload;
extern cvar_t *cl_downloadMethod;
extern cvar_t *cl_conXOffset;
extern cvar_t *cl_inGameVideo;
extern cvar_t *cl_lanForcePackets;
extern cvar_t *cl_autoRecordDemo;
extern cvar_t *cl_clantag;
extern cvar_t *cl_consoleKeys;
#ifdef USE_MUMBLE
extern cvar_t *cl_useMumble;
extern cvar_t *cl_mumbleScale;
#endif
#ifdef USE_VOIP
// cl_voipSendTarget is a string: "all" to broadcast to everyone, "none" to
// send to no one, or a comma-separated list of client numbers:
// "0,7,2,23" ... an empty string is treated like "all".
extern cvar_t *cl_voipUseVAD;
extern cvar_t *cl_voipVADThreshold;
extern cvar_t *cl_voipSend;
extern cvar_t *cl_voipSendTarget;
extern cvar_t *cl_voipGainDuringCapture;
extern cvar_t *cl_voipCaptureMult;
extern cvar_t *cl_voipShowMeter;
extern cvar_t *cl_voip;
// 20ms at 48k
#define VOIP_MAX_FRAME_SAMPLES (20 * 48)
// 3 frame is 60ms of audio, the max opus will encode at once
#define VOIP_MAX_PACKET_FRAMES 3
#define VOIP_MAX_PACKET_SAMPLES (VOIP_MAX_FRAME_SAMPLES * VOIP_MAX_PACKET_FRAMES)
#endif
extern cvar_t *cl_rsaAuth;
//=================================================
//
// cl_main
//
void CL_Init(void);
void CL_AddReliableCommand(const char *cmd, bool isDisconnectCmd);
void CL_StartHunkUsers(bool rendererOnly);
void CL_Disconnect_f(void);
void CL_NextDemo(void);
void CL_ReadDemoMessage(void);
demoState_t CL_DemoState(void);
int CL_DemoPos(void);
void CL_DemoName(char *buffer, int size);
void CL_StopRecord_f(void);
void CL_InitDownloads(void);
void CL_NextDownload(void);
void CL_GetPing(int n, char *buf, int buflen, int *pingtime);
void CL_GetPingInfo(int n, char *buf, int buflen);
void CL_ClearPing(int n);
int CL_GetPingQueueCount(void);
bool CL_ServerStatus(char *serverAddress, char *serverStatusString, int maxLen);
bool CL_CheckPaused(void);
//
// cl_input
//
typedef struct {
int down[2]; // key nums holding it down
unsigned downtime; // msec timestamp
unsigned msec; // msec down this frame if both a down and up happened
bool active; // current state
bool wasPressed; // set when down, not cleared when up
} kbutton_t;
void CL_InitInput(void);
void CL_ShutdownInput(void);
void CL_SendCmd(void);
void CL_ClearState(void);
void CL_ReadPackets(void);
void CL_WritePacket(void);
//void IN_CenterView(void);
int Key_StringToKeynum(const char *str);
const char *Key_KeynumToString(int keynum);
//
// cl_parse.c
//
extern bool cl_connectedToPureServer;
extern bool cl_connectedToCheatServer;
#ifdef USE_VOIP
void CL_Voip_f(void);
#endif
void CL_SystemInfoChanged(void);
void CL_ParseServerMessage(msg_t *msg);
//====================================================================
bool CL_UpdateVisiblePings_f(int source);
//
// console
//
void Con_DrawCharacter(int cx, int line, int num);
void Con_CheckResize(void);
void Con_MessageModesInit(void);
void CL_ProtocolSpecificCommandsInit(void);
void Con_Init(void);
void Con_Shutdown(void);
void Con_Clear_f(void);
void Con_ToggleConsole_f(void);
void Con_ClearNotify(void);
void Con_RunConsole(void);
void Con_DrawConsole(void);
void Con_PageUp(void);
void Con_PageDown(void);
void Con_Top(void);
void Con_Bottom(void);
void Con_Close(void);
void CL_LoadConsoleHistory(void);
void CL_SaveConsoleHistory(void);
//
// cl_scrn.c
//
void SCR_Init(void);
void SCR_UpdateScreen(void);
void SCR_DebugGraph(float value);
int SCR_GetBigStringWidth(const char *str); // returns in virtual 640x480 coordinates
void SCR_AdjustFrom640(float *x, float *y, float *w, float *h);
void SCR_FillRect(float x, float y, float width, float height, const float *color);
void SCR_DrawPic(float x, float y, float width, float height, qhandle_t hShader);
void SCR_DrawNamedPic(float x, float y, float width, float height, const char *picname);
void SCR_DrawBigString(int x, int y, const char *s, float alpha,
bool noColorEscape); // draws a string with embedded color control characters with fade
void SCR_DrawBigStringColor(
int x, int y, const char *s, vec4_t color, bool noColorEscape); // ignores embedded color control characters
void SCR_DrawSmallStringExt(int x, int y, const char *string, float *setColor, bool forceColor, bool noColorEscape);
void SCR_DrawSmallChar(int x, int y, int ch);
//
// cl_cin.c
//
void CL_PlayCinematic_f(void);
void SCR_DrawCinematic(void);
void SCR_RunCinematic(void);
void SCR_StopCinematic(void);
int CIN_PlayCinematic(const char *arg0, int xpos, int ypos, int width, int height, int bits);
e_status CIN_StopCinematic(int handle);
e_status CIN_RunCinematic(int handle);
void CIN_DrawCinematic(int handle);
void CIN_SetExtents(int handle, int x, int y, int w, int h);
void CIN_UploadCinematic(int handle);
void CIN_CloseAllVideos(void);
//
// cl_cgame.c
//
void CL_InitCGame(void);
void CL_ShutdownCGame(void);
bool CL_GameCommand(void);
void CL_GameConsoleText(void);
void CL_CGameRendering(stereoFrame_t stereo);
void CL_SetCGameTime(void);
void CL_FirstSnapshot(void);
void CL_ShaderStateChanged(void);
//
// cl_ui.c
//
void CL_InitUI(void);
void CL_ShutdownUI(void);
int Key_GetCatcher(void);
void Key_SetCatcher(int catcher);
void LAN_LoadCachedServers(void);
void LAN_SaveServersToCache(void);
//
// cl_net_chan.c
//
void CL_Netchan_Transmit(netchan_t *chan, msg_t *msg); // int length, const byte *data );
bool CL_Netchan_Process(netchan_t *chan, msg_t *msg);
//
// cl_avi.c
//
bool CL_OpenAVIForWriting(const char *filename);
void CL_TakeVideoFrame(void);
void CL_WriteAVIVideoFrame(const byte *imageBuffer, int size);
void CL_WriteAVIAudioFrame(const byte *pcmBuffer, int size);
bool CL_CloseAVI(void);
bool CL_VideoRecording(void);
//
// cl_main.c
//
void CL_WriteDemoMessage(msg_t *msg, int headerBytes);
int CL_ScaledMilliseconds(void);
#endif