This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/engine/client/cl_main.c

1277 lines
32 KiB
C
Raw Normal View History

2007-06-21 22:00:00 +02:00
/*
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.
*/
// cl_main.c -- client main loop
2008-06-09 22:00:00 +02:00
#include "common.h"
2007-06-21 22:00:00 +02:00
#include "client.h"
2008-07-23 22:00:00 +02:00
#include "byteorder.h"
2007-06-21 22:00:00 +02:00
cvar_t *rcon_client_password;
cvar_t *rcon_address;
cvar_t *cl_timeout;
cvar_t *cl_predict;
2008-01-20 22:00:00 +01:00
cvar_t *cl_showfps;
2008-07-11 22:00:00 +02:00
cvar_t *cl_maxfps;
2007-06-21 22:00:00 +02:00
2008-11-16 22:00:00 +01:00
cvar_t *cl_particles;
cvar_t *cl_particlelod;
2008-07-11 22:00:00 +02:00
2007-06-21 22:00:00 +02:00
cvar_t *cl_shownet;
cvar_t *cl_showmiss;
2008-07-06 22:00:00 +02:00
cvar_t *cl_mouselook;
2007-06-21 22:00:00 +02:00
//
// userinfo
//
cvar_t *info_password;
cvar_t *info_spectator;
cvar_t *name;
2009-10-16 22:00:00 +02:00
cvar_t *model;
cvar_t *topcolor;
cvar_t *bottomcolor;
2007-06-21 22:00:00 +02:00
cvar_t *rate;
client_static_t cls;
2007-11-04 22:00:00 +01:00
client_t cl;
2008-12-26 22:00:00 +01:00
clgame_static_t clgame;
2007-06-21 22:00:00 +02:00
extern cvar_t *allow_download;
//======================================================================
//======================================================================
2009-11-02 22:00:00 +01:00
bool CL_Active( void )
2009-10-02 22:00:00 +02:00
{
2009-11-10 22:00:00 +01:00
if( host.type == HOST_DEDICATED ) return true; // always active for dedicated servers
2009-11-16 22:00:00 +01:00
if( CL_GetMaxClients() > 1 ) return true; // always active for multiplayer
2009-11-10 22:00:00 +01:00
return (cls.key_dest == key_game || cls.key_dest == key_hudmenu); // active if not menu or console
2009-10-02 22:00:00 +02:00
}
2007-06-21 22:00:00 +02:00
2009-11-03 22:00:00 +01:00
void CL_ForceVid( void )
{
cl.video_prepped = false;
2009-11-16 22:00:00 +01:00
host.state = HOST_RESTART;
2009-11-03 22:00:00 +01:00
}
void CL_ForceSnd( void )
{
cl.audio_prepped = false;
}
2008-07-15 22:00:00 +02:00
/*
=======================================================================
CLIENT RELIABLE COMMAND COMMUNICATION
=======================================================================
*/
2007-06-21 22:00:00 +02:00
/*
===================
Cmd_ForwardToServer
adds the current command line as a clc_stringcmd to the client message.
things like godmode, noclip, etc, are commands directed to the server,
so when they are typed in at the console, they will need to be forwarded.
===================
*/
/*
==================
CL_ForwardToServer_f
==================
*/
2008-12-20 22:00:00 +01:00
void CL_ForwardToServer_f( void )
2007-06-21 22:00:00 +02:00
{
2008-12-20 22:00:00 +01:00
char *cmd;
2009-11-10 22:00:00 +01:00
if( cls.demoplayback )
{
if( !com.stricmp( Cmd_Argv( 0 ), "pause" ))
cl.refdef.paused ^= 1;
return;
}
if( cls.state != ca_connected && cls.state != ca_active )
2008-12-20 22:00:00 +01:00
return; // not connected
cmd = Cmd_Argv( 0 );
if( *cmd == '-' || *cmd == '+' )
2007-06-21 22:00:00 +02:00
{
2008-12-20 22:00:00 +01:00
Msg( "Unknown command \"%s\"\n", cmd );
2007-06-21 22:00:00 +02:00
return;
2008-12-20 22:00:00 +01:00
}
2007-06-21 22:00:00 +02:00
// don't forward the first argument
2008-07-12 22:00:00 +02:00
if( Cmd_Argc() > 1 )
2007-06-21 22:00:00 +02:00
{
2008-07-15 22:00:00 +02:00
MSG_WriteByte( &cls.netchan.message, clc_stringcmd );
MSG_Print( &cls.netchan.message, Cmd_Args());
2007-06-21 22:00:00 +02:00
}
}
/*
==================
CL_Quit_f
==================
*/
void CL_Quit_f (void)
{
2008-06-06 22:00:00 +02:00
CL_Disconnect();
Sys_Quit();
2007-06-21 22:00:00 +02:00
}
/*
================
CL_Drop
2007-09-10 22:00:00 +02:00
Called after an Host_Error was thrown
2007-06-21 22:00:00 +02:00
================
*/
2009-09-25 22:00:00 +02:00
void CL_Drop( void )
2007-06-21 22:00:00 +02:00
{
2009-09-25 22:00:00 +02:00
if( cls.state == ca_uninitialized )
return;
2007-11-13 22:00:00 +01:00
CL_Disconnect();
2007-06-21 22:00:00 +02:00
}
/*
=======================
CL_SendConnectPacket
We have gotten a challenge from the server, so try and
connect.
======================
*/
2008-07-11 22:00:00 +02:00
void CL_SendConnectPacket (void)
2007-06-21 22:00:00 +02:00
{
netadr_t adr;
int port;
2009-09-17 22:00:00 +02:00
if( !NET_StringToAdr( cls.servername, &adr ))
2007-06-21 22:00:00 +02:00
{
2008-05-20 22:00:00 +02:00
MsgDev( D_INFO, "CL_SendConnectPacket: bad server address\n");
2007-06-21 22:00:00 +02:00
cls.connect_time = 0;
return;
}
2008-07-12 22:00:00 +02:00
if( adr.port == 0 ) adr.port = BigShort( PORT_SERVER );
port = Cvar_VariableValue( "net_qport" );
2007-06-21 22:00:00 +02:00
2007-11-25 22:00:00 +01:00
userinfo_modified = false;
2008-07-12 22:00:00 +02:00
Netchan_OutOfBandPrint(NS_CLIENT, adr, "connect %i %i %i \"%s\"\n", PROTOCOL_VERSION, port, cls.challenge, Cvar_Userinfo());
2007-06-21 22:00:00 +02:00
}
/*
=================
CL_CheckForResend
Resend a connect message if the last one has timed out
=================
*/
2009-09-25 22:00:00 +02:00
void CL_CheckForResend( void )
2007-06-21 22:00:00 +02:00
{
netadr_t adr;
2009-09-25 22:00:00 +02:00
// if the local server is running and we aren't then connect
if( cls.state == ca_disconnected && SV_Active())
2007-06-21 22:00:00 +02:00
{
cls.state = ca_connecting;
2009-09-25 22:00:00 +02:00
com.strncpy( cls.servername, "localhost", sizeof( cls.servername ));
2007-06-21 22:00:00 +02:00
// we don't need a challenge on the localhost
2009-09-25 22:00:00 +02:00
CL_SendConnectPacket();
2007-06-21 22:00:00 +02:00
return;
}
// resend if we haven't gotten a reply yet
2009-02-03 22:00:00 +01:00
if( cls.demoplayback || cls.state != ca_connecting )
2008-05-20 22:00:00 +02:00
return;
2009-09-17 22:00:00 +02:00
if(( cls.realtime - cls.connect_time ) < 3000 ) return;
2007-06-21 22:00:00 +02:00
2009-02-03 22:00:00 +01:00
if( !NET_StringToAdr( cls.servername, &adr ))
2007-06-21 22:00:00 +02:00
{
2008-05-20 22:00:00 +02:00
MsgDev(D_INFO, "CL_CheckForResend: bad server address\n");
2007-06-21 22:00:00 +02:00
cls.state = ca_disconnected;
return;
}
2009-02-03 22:00:00 +01:00
if( adr.port == 0 ) adr.port = BigShort( PORT_SERVER );
2009-09-14 22:00:00 +02:00
cls.connect_time = cls.realtime; // for retransmit requests
2009-02-03 22:00:00 +01:00
Msg( "Connecting to %s...\n", cls.servername );
Netchan_OutOfBandPrint( NS_CLIENT, adr, "getchallenge\n" );
2007-06-21 22:00:00 +02:00
}
/*
================
CL_Connect_f
================
*/
void CL_Connect_f (void)
{
char *server;
if (Cmd_Argc() != 2)
{
2007-07-28 22:00:00 +02:00
Msg ("usage: connect <server>\n");
2007-06-21 22:00:00 +02:00
return;
}
2007-11-21 22:00:00 +01:00
if(Host_ServerState())
{
// if running a local server, kill it and reissue
2007-11-30 22:00:00 +01:00
com.strncpy( host.finalmsg, "Server quit\n", MAX_STRING );
2007-11-21 22:00:00 +01:00
SV_Shutdown( false );
2007-06-21 22:00:00 +02:00
}
2007-11-21 22:00:00 +01:00
else CL_Disconnect();
2007-06-21 22:00:00 +02:00
server = Cmd_Argv (1);
2007-11-21 22:00:00 +01:00
CL_Disconnect();
2007-06-21 22:00:00 +02:00
cls.state = ca_connecting;
2008-07-31 22:00:00 +02:00
com.strncpy (cls.servername, server, sizeof(cls.servername)-1);
2008-06-30 22:00:00 +02:00
cls.connect_time = MAX_HEARTBEAT; // CL_CheckForResend() will fire immediately
2007-06-21 22:00:00 +02:00
}
/*
=====================
CL_Rcon_f
Send the rest of the command line over as
an unconnected command.
=====================
*/
void CL_Rcon_f (void)
{
char message[1024];
int i;
netadr_t to;
if (!rcon_client_password->string)
{
2007-07-28 22:00:00 +02:00
Msg ("You must set 'rcon_password' before\n"
2007-06-21 22:00:00 +02:00
"issuing an rcon command.\n");
return;
}
message[0] = (char)255;
message[1] = (char)255;
message[2] = (char)255;
message[3] = (char)255;
message[4] = 0;
2008-07-31 22:00:00 +02:00
com.strcat (message, "rcon ");
2007-06-21 22:00:00 +02:00
2008-07-31 22:00:00 +02:00
com.strcat (message, rcon_client_password->string);
com.strcat (message, " ");
2007-06-21 22:00:00 +02:00
for (i=1 ; i<Cmd_Argc() ; i++)
{
2008-07-31 22:00:00 +02:00
com.strcat (message, Cmd_Argv(i));
com.strcat (message, " ");
2007-06-21 22:00:00 +02:00
}
if (cls.state >= ca_connected)
to = cls.netchan.remote_address;
else
{
2008-07-31 22:00:00 +02:00
if (!com.strlen(rcon_address->string))
2007-06-21 22:00:00 +02:00
{
2007-07-28 22:00:00 +02:00
Msg ("You must either be connected,\n"
2007-06-21 22:00:00 +02:00
"or set the 'rcon_address' cvar\n"
"to issue rcon commands\n");
return;
}
NET_StringToAdr (rcon_address->string, &to);
if (to.port == 0)
to.port = BigShort (PORT_SERVER);
}
2008-07-31 22:00:00 +02:00
NET_SendPacket (NS_CLIENT, com.strlen(message)+1, message, to);
2007-06-21 22:00:00 +02:00
}
/*
=====================
CL_ClearState
=====================
*/
2009-01-25 22:00:00 +01:00
void CL_ClearState( void )
2007-06-21 22:00:00 +02:00
{
S_StopAllSounds ();
CL_ClearEffects ();
2008-07-01 22:00:00 +02:00
CL_FreeEdicts();
2007-06-21 22:00:00 +02:00
2009-06-24 22:00:00 +02:00
if( clgame.hInstance ) clgame.dllFuncs.pfnReset();
2008-12-26 22:00:00 +01:00
2008-06-22 22:00:00 +02:00
// wipe the entire cl structure
2008-11-15 22:00:00 +01:00
Mem_Set( &cl, 0, sizeof( cl ));
2008-07-12 22:00:00 +02:00
MSG_Clear( &cls.netchan.message );
2008-08-03 22:00:00 +02:00
Cvar_SetValue( "scr_download", 0.0f );
Cvar_SetValue( "scr_loading", 0.0f );
2009-01-25 22:00:00 +01:00
2009-09-10 22:00:00 +02:00
UI_SetActiveMenu( UI_CLOSEMENU );
2007-06-21 22:00:00 +02:00
}
/*
=====================
CL_Disconnect
Goes from a connected state to full screen console state
Sends a disconnect message to the server
2007-09-10 22:00:00 +02:00
This is also called on Host_Error, so it shouldn't cause any errors
2007-06-21 22:00:00 +02:00
=====================
*/
2008-06-28 22:00:00 +02:00
void CL_Disconnect( void )
2007-06-21 22:00:00 +02:00
{
byte final[32];
2008-08-29 22:00:00 +02:00
if( cls.state == ca_disconnected )
2007-06-21 22:00:00 +02:00
return;
cls.connect_time = 0;
2008-05-20 22:00:00 +02:00
CL_Stop_f();
2007-06-21 22:00:00 +02:00
// send a disconnect message to the server
final[0] = clc_stringcmd;
2009-09-25 22:00:00 +02:00
com.strcpy((char *)final+1, "disconnect" );
Netchan_Transmit( &cls.netchan, com.strlen( final ), final );
Netchan_Transmit( &cls.netchan, com.strlen( final ), final );
Netchan_Transmit( &cls.netchan, com.strlen( final ), final );
2007-06-21 22:00:00 +02:00
CL_ClearState ();
// stop download
2009-09-25 22:00:00 +02:00
if( cls.download )
2007-06-21 22:00:00 +02:00
{
2009-09-25 22:00:00 +02:00
FS_Close( cls.download );
2007-06-21 22:00:00 +02:00
cls.download = NULL;
}
cls.state = ca_disconnected;
}
2009-06-22 22:00:00 +02:00
void CL_Disconnect_f( void )
2007-06-21 22:00:00 +02:00
{
2009-06-22 22:00:00 +02:00
Host_Error( "Disconnected from server\n" );
2007-06-21 22:00:00 +02:00
}
/*
====================
CL_Packet_f
packet <destination> <contents>
Contents allows \n escape character
====================
*/
void CL_Packet_f (void)
{
char send[2048];
int i, l;
char *in, *out;
netadr_t adr;
if (Cmd_Argc() != 3)
{
2007-07-28 22:00:00 +02:00
Msg ("packet <destination> <contents>\n");
2007-06-21 22:00:00 +02:00
return;
}
if (!NET_StringToAdr (Cmd_Argv(1), &adr))
{
2007-07-28 22:00:00 +02:00
Msg ("Bad address\n");
2007-06-21 22:00:00 +02:00
return;
}
if (!adr.port)
adr.port = BigShort (PORT_SERVER);
in = Cmd_Argv(2);
out = send+4;
send[0] = send[1] = send[2] = send[3] = (char)0xff;
2008-07-31 22:00:00 +02:00
l = com.strlen (in);
2007-06-21 22:00:00 +02:00
for (i=0 ; i<l ; i++)
{
if (in[i] == '\\' && in[i+1] == 'n')
{
*out++ = '\n';
i++;
}
else
*out++ = in[i];
}
*out = 0;
2008-07-11 22:00:00 +02:00
NET_SendPacket (NS_CLIENT, out-send, send, adr);
2007-06-21 22:00:00 +02:00
}
/*
=================
CL_Changing_f
Just sent as a hint to the client that they should
drop to full console
=================
*/
2008-07-24 22:00:00 +02:00
void CL_Changing_f( void )
2007-06-21 22:00:00 +02:00
{
2009-09-25 22:00:00 +02:00
// if we are downloading, we don't change! This so we don't suddenly stop downloading a map
2008-07-24 22:00:00 +02:00
if( cls.download ) return;
2007-06-21 22:00:00 +02:00
2007-11-14 22:00:00 +01:00
S_StopAllSounds();
2009-09-28 22:00:00 +02:00
cl.audio_prepped = false; // don't play ambients
2007-06-21 22:00:00 +02:00
cls.state = ca_connected; // not active anymore, but not disconnected
2009-09-28 22:00:00 +02:00
Msg( "\nchanging map...\n" );
2007-06-21 22:00:00 +02:00
}
/*
=================
CL_Reconnect_f
The server is changing levels
=================
*/
2009-09-25 22:00:00 +02:00
void CL_Reconnect_f( void )
2007-06-21 22:00:00 +02:00
{
2009-09-16 22:00:00 +02:00
// if we are downloading, we don't change! This so we don't suddenly stop downloading a map
2008-07-24 22:00:00 +02:00
if( cls.download ) return;
2007-06-21 22:00:00 +02:00
S_StopAllSounds ();
2009-10-18 22:00:00 +02:00
// disable plaque draw on change map
cls.drawplaque = false;
Cmd_ExecuteString( "plaque\n" );
2009-09-28 22:00:00 +02:00
2009-10-13 22:00:00 +02:00
if( cls.demoplayback ) return;
2008-07-24 22:00:00 +02:00
if( cls.state == ca_connected )
2007-09-07 22:00:00 +02:00
{
2009-10-13 22:00:00 +02:00
cls.demonum = -1; // not in the demo loop now
2007-06-21 22:00:00 +02:00
cls.state = ca_connected;
2008-07-15 22:00:00 +02:00
MSG_WriteByte( &cls.netchan.message, clc_stringcmd );
MSG_Print( &cls.netchan.message, "new" );
2007-06-21 22:00:00 +02:00
return;
}
2009-02-03 22:00:00 +01:00
if( *cls.servername )
2007-09-07 22:00:00 +02:00
{
2009-02-03 22:00:00 +01:00
if( cls.state >= ca_connected )
2007-09-07 22:00:00 +02:00
{
2007-06-21 22:00:00 +02:00
CL_Disconnect();
2009-09-17 22:00:00 +02:00
cls.connect_time = cls.realtime - 1500;
2007-09-07 22:00:00 +02:00
}
2008-06-30 22:00:00 +02:00
else cls.connect_time = MAX_HEARTBEAT; // fire immediately
2007-06-21 22:00:00 +02:00
2009-10-13 22:00:00 +02:00
cls.demonum = -1; // not in the demo loop now
2007-06-21 22:00:00 +02:00
cls.state = ca_connecting;
2009-09-14 22:00:00 +02:00
Msg( "reconnecting...\n" );
2007-06-21 22:00:00 +02:00
}
}
/*
2008-06-22 22:00:00 +02:00
===================
CL_StatusLocal_f
===================
2007-06-21 22:00:00 +02:00
*/
2008-06-22 22:00:00 +02:00
void CL_GetServerList_f( void )
2007-06-21 22:00:00 +02:00
{
netadr_t adr;
// send a broadcast packet
2008-06-22 22:00:00 +02:00
MsgDev( D_INFO, "status pinging broadcast...\n" );
2009-09-14 22:00:00 +02:00
cls.pingtime = cls.realtime;
2008-06-22 22:00:00 +02:00
adr.type = NA_BROADCAST;
adr.port = BigShort( PORT_SERVER );
Netchan_OutOfBandPrint( NS_CLIENT, adr, "status" );
}
/*
=============
CL_FreeServerInfo
=============
*/
static void CL_FreeServerInfo( serverinfo_t *server )
{
if( server->mapname ) Mem_Free( server->mapname );
if( server->hostname ) Mem_Free( server->hostname );
if( server->shortname ) Mem_Free( server->shortname );
if( server->gamename ) Mem_Free( server->gamename );
if( server->netaddress ) Mem_Free( server->netaddress );
if( server->playerstr ) Mem_Free( server->playerstr );
2009-09-10 22:00:00 +02:00
if( server->pingstring ) Mem_Free( server->pingstring );
2008-06-22 22:00:00 +02:00
memset( server, 0, sizeof(serverinfo_t));
}
2007-06-21 22:00:00 +02:00
2008-06-22 22:00:00 +02:00
/*
=============
CL_FreeServerList
=============
*/
static void CL_FreeServerList_f( void )
{
int i;
for( i = 0; i < cls.numservers; i++ )
CL_FreeServerInfo( &cls.serverlist[i] );
cls.numservers = 0;
}
/*
=============
CL_DupeCheckServerList
Checks for duplicates and returns true if there is one...
Since status has higher priority than info, if there is already an instance and
it's not status, and the current one is status, the old one is removed.
=============
*/
static bool CL_DupeCheckServerList( char *adr, bool status )
{
int i;
for( i = 0; i < cls.numservers; i++ )
2007-06-21 22:00:00 +02:00
{
2008-06-22 22:00:00 +02:00
if(!cls.serverlist[i].netaddress && !cls.serverlist[i].hostname )
{
CL_FreeServerInfo( &cls.serverlist[i] );
continue;
}
if( cls.serverlist[i].netaddress && !com.strcmp( cls.serverlist[i].netaddress, adr ))
{
if( cls.serverlist[i].statusPacket && status )
{
return true;
}
else if( status )
{
CL_FreeServerInfo( &cls.serverlist[i] );
return false;
}
}
2007-06-21 22:00:00 +02:00
}
2008-06-22 22:00:00 +02:00
return false;
}
/*
=============
CL_ParseServerStatus
2007-06-21 22:00:00 +02:00
2008-06-22 22:00:00 +02:00
Parses a status packet from a server
FIXME: check against a list of sent status requests so it's not attempting to parse things it shouldn't
=============
*/
bool CL_ParseServerStatus( char *adr, char *info )
{
serverinfo_t *server;
char *token;
char shortName[32];
if( !info || !info[0] )return false;
if( !adr || !adr[0] ) return false;
if( !com.strchr( info, '\\')) return false;
if( cls.numservers >= MAX_SERVERS )
return true;
if( CL_DupeCheckServerList( adr, true ))
return true;
server = &cls.serverlist[cls.numservers];
CL_FreeServerInfo( server );
cls.numservers++;
// add net address
server->netaddress = copystring( adr );
server->mapname = copystring(Info_ValueForKey( info, "mapname"));
server->maxplayers = com.atoi(Info_ValueForKey( info, "maxclients"));
server->gamename = copystring(Info_ValueForKey( info, "gamename"));
server->hostname = copystring(Info_ValueForKey( info, "hostname"));
if( server->hostname )
2007-06-21 22:00:00 +02:00
{
2008-06-22 22:00:00 +02:00
com.strncpy( shortName, server->hostname, sizeof(shortName));
server->shortname = copystring( shortName );
2007-06-21 22:00:00 +02:00
}
2008-06-22 22:00:00 +02:00
// Check the player count
server->numplayers = com.atoi(Info_ValueForKey( info, "curplayers"));
if( server->numplayers <= 0 )
2007-06-21 22:00:00 +02:00
{
2008-06-22 22:00:00 +02:00
server->numplayers = 0;
2007-06-21 22:00:00 +02:00
2008-06-22 22:00:00 +02:00
token = strtok( info, "\n" );
if( token )
2007-06-21 22:00:00 +02:00
{
2008-06-22 22:00:00 +02:00
token = strtok( NULL, "\n" );
while( token )
{
server->numplayers++;
token = strtok( NULL, "\n" );
}
2007-06-21 22:00:00 +02:00
}
}
2008-06-22 22:00:00 +02:00
// check if it's valid
if( !server->mapname[0] && !server->maxplayers && !server->gamename[0] && !server->hostname[0] )
{
CL_FreeServerInfo( server );
return false;
}
server->playerstr = copystring( va("%i/%i", server->numplayers, server->maxplayers ));
// add the ping
2009-09-14 22:00:00 +02:00
server->ping = cls.realtime - cls.pingtime;
2009-02-03 22:00:00 +01:00
server->pingstring = copystring( va( "%ims", server->ping ));
2008-06-22 22:00:00 +02:00
server->statusPacket = true;
// print information
MsgDev( D_NOTE, "%s %s ", server->hostname, server->mapname );
MsgDev( D_NOTE, "%i/%i %ims\n", server->numplayers, server->maxplayers, server->ping );
return true;
2007-06-21 22:00:00 +02:00
}
2008-06-28 22:00:00 +02:00
/*
=================
CL_ParseStatusMessage
Handle a reply from a ping
=================
*/
2008-07-12 22:00:00 +02:00
void CL_ParseStatusMessage( netadr_t from, sizebuf_t *msg )
2008-06-28 22:00:00 +02:00
{
char *s;
2008-07-12 22:00:00 +02:00
s = MSG_ReadString( msg );
2008-06-28 22:00:00 +02:00
2009-09-16 22:00:00 +02:00
Msg ("%s\n", s);
CL_ParseServerStatus( NET_AdrToString(from), s );
2008-06-28 22:00:00 +02:00
}
2008-08-04 22:00:00 +02:00
//===================================================================
/*
======================
CL_PrepSound
Call before entering a new level, or after changing dlls
======================
*/
void CL_PrepSound( void )
{
int i, sndcount;
2009-10-02 22:00:00 +02:00
MsgDev( D_LOAD, "CL_PrepSound: %s\n", cl.configstrings[CS_NAME] );
2009-01-14 22:00:00 +01:00
for( i = 0, sndcount = 0; i < MAX_SOUNDS && cl.configstrings[CS_SOUNDS+i+1][0]; i++ )
2008-08-04 22:00:00 +02:00
sndcount++; // total num sounds
S_BeginRegistration();
2009-01-14 22:00:00 +01:00
for( i = 0; i < MAX_SOUNDS && cl.configstrings[CS_SOUNDS+1+i][0]; i++ )
2008-08-04 22:00:00 +02:00
{
2009-01-14 22:00:00 +01:00
cl.sound_precache[i+1] = S_RegisterSound( cl.configstrings[CS_SOUNDS+1+i] );
Cvar_SetValue( "scr_loading", scr_loading->value + 5.0f / sndcount );
2008-08-04 22:00:00 +02:00
SCR_UpdateScreen();
}
2008-12-03 22:00:00 +01:00
2008-08-04 22:00:00 +02:00
S_EndRegistration();
2008-12-03 22:00:00 +01:00
CL_RunBackgroundTrack();
2008-08-04 22:00:00 +02:00
cl.audio_prepped = true;
}
/*
=================
CL_PrepVideo
Call before entering a new level, or after changing dlls
=================
*/
void CL_PrepVideo( void )
{
2009-11-03 22:00:00 +01:00
string name, mapname;
int i, mdlcount;
int map_checksum; // dummy
2008-08-04 22:00:00 +02:00
2008-11-09 22:00:00 +01:00
if( !cl.configstrings[CS_MODELS+1][0] )
2008-08-04 22:00:00 +02:00
return; // no map loaded
2009-01-25 22:00:00 +01:00
Cvar_SetValue( "scr_loading", 0.0f ); // reset progress bar
2009-10-02 22:00:00 +02:00
MsgDev( D_LOAD, "CL_PrepVideo: %s\n", cl.configstrings[CS_NAME] );
2008-08-04 22:00:00 +02:00
// let the render dll load the map
2009-11-03 22:00:00 +01:00
com.strncpy( mapname, cl.configstrings[CS_MODELS+1], MAX_STRING );
CM_BeginRegistration( mapname, true, &map_checksum );
re->BeginRegistration( mapname, CM_VisData()); // load map
2008-11-18 22:00:00 +01:00
SCR_RegisterShaders(); // update with new sequence
2008-08-04 22:00:00 +02:00
SCR_UpdateScreen();
2009-01-14 22:00:00 +01:00
for( i = 0, mdlcount = 0; i < MAX_MODELS && cl.configstrings[CS_MODELS+1+i][0]; i++ )
2008-08-04 22:00:00 +02:00
mdlcount++; // total num models
2009-01-14 22:00:00 +01:00
for( i = 0; i < MAX_MODELS && cl.configstrings[CS_MODELS+1+i][0]; i++ )
2008-08-04 22:00:00 +02:00
{
com.strncpy( name, cl.configstrings[CS_MODELS+1+i], MAX_STRING );
re->RegisterModel( name, i+1 );
2009-10-29 22:00:00 +01:00
CM_RegisterModel( name, i+1 );
Cvar_SetValue( "scr_loading", scr_loading->value + 45.0f / mdlcount );
2008-08-04 22:00:00 +02:00
SCR_UpdateScreen();
}
2009-01-16 22:00:00 +01:00
for( i = 0; i < MAX_DECALS && cl.configstrings[CS_DECALS+1+i][0]; i++ )
2008-12-15 22:00:00 +01:00
{
2009-01-16 22:00:00 +01:00
com.strncpy( name, cl.configstrings[CS_DECALS+1+i], MAX_STRING );
cl.decal_shaders[i+1] = re->RegisterShader( name, SHADER_GENERIC );
2008-12-15 22:00:00 +01:00
}
2008-11-18 22:00:00 +01:00
// setup sky and free unneeded stuff
re->EndRegistration( cl.configstrings[CS_SKYNAME] );
2009-11-03 22:00:00 +01:00
CM_EndRegistration (); // free unused models
2009-01-16 22:00:00 +01:00
Cvar_SetValue( "scr_loading", 100.0f ); // all done
2008-11-18 22:00:00 +01:00
2009-09-28 22:00:00 +02:00
if( host.developer <= 2 ) Con_ClearNotify(); // clear any lines of console text
2008-08-04 22:00:00 +02:00
SCR_UpdateScreen();
cl.video_prepped = true;
2009-09-28 22:00:00 +02:00
cl.force_refdef = true;
2008-08-04 22:00:00 +02:00
}
2007-06-21 22:00:00 +02:00
/*
=================
CL_ConnectionlessPacket
Responses to broadcasts, etc
=================
*/
2008-07-12 22:00:00 +02:00
void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
2007-06-21 22:00:00 +02:00
{
2008-06-22 22:00:00 +02:00
char *s, *c;
2007-06-21 22:00:00 +02:00
2008-07-12 22:00:00 +02:00
MSG_BeginReading( msg );
MSG_ReadLong( msg ); // skip the -1
2007-06-21 22:00:00 +02:00
2008-07-12 22:00:00 +02:00
s = MSG_ReadStringLine( msg );
2007-06-21 22:00:00 +02:00
2008-07-12 22:00:00 +02:00
Cmd_TokenizeString( s );
2007-06-21 22:00:00 +02:00
c = Cmd_Argv(0);
2009-06-22 22:00:00 +02:00
MsgDev( D_INFO, "CL_ConnectionlessPacket: %s : %s\n", NET_AdrToString( from ), c );
2007-06-21 22:00:00 +02:00
// server connection
2009-06-22 22:00:00 +02:00
if( !com.strcmp( c, "client_connect" ))
2007-06-21 22:00:00 +02:00
{
2009-06-22 22:00:00 +02:00
if( cls.state == ca_connected )
2007-06-21 22:00:00 +02:00
{
2009-09-11 22:00:00 +02:00
MsgDev( D_INFO, "dup connect received. ignored\n");
2007-06-21 22:00:00 +02:00
return;
}
2008-07-12 22:00:00 +02:00
Netchan_Setup( NS_CLIENT, &cls.netchan, from, Cvar_VariableValue( "net_qport" ));
2008-07-15 22:00:00 +02:00
MSG_WriteByte( &cls.netchan.message, clc_stringcmd );
MSG_Print( &cls.netchan.message, "new" );
2007-06-21 22:00:00 +02:00
cls.state = ca_connected;
2009-09-10 22:00:00 +02:00
UI_SetActiveMenu( UI_CLOSEMENU );
2007-06-21 22:00:00 +02:00
return;
}
// server responding to a status broadcast
2009-06-24 22:00:00 +02:00
if( !com.strcmp( c, "info" ))
2007-06-21 22:00:00 +02:00
{
2008-07-12 22:00:00 +02:00
CL_ParseStatusMessage( from, msg );
2007-06-21 22:00:00 +02:00
return;
}
// remote command from gui front end
2009-06-24 22:00:00 +02:00
if( !com.strcmp( c, "cmd" ))
2007-06-21 22:00:00 +02:00
{
2009-06-24 22:00:00 +02:00
if(!NET_IsLocalAddress( from ))
2007-06-21 22:00:00 +02:00
{
2009-06-24 22:00:00 +02:00
Msg( "Command packet from remote host. Ignored.\n" );
2007-06-21 22:00:00 +02:00
return;
}
2009-06-24 22:00:00 +02:00
ShowWindow( host.hWnd, SW_RESTORE );
2007-11-17 22:00:00 +01:00
SetForegroundWindow ( host.hWnd );
2008-07-12 22:00:00 +02:00
s = MSG_ReadString( msg );
2007-11-17 22:00:00 +01:00
Cbuf_AddText(s);
Cbuf_AddText("\n");
2007-06-21 22:00:00 +02:00
return;
}
// print command from somewhere
2009-06-24 22:00:00 +02:00
if( !com.strcmp( c, "print" ))
2007-06-21 22:00:00 +02:00
{
2008-06-22 22:00:00 +02:00
// print command from somewhere
2008-07-12 22:00:00 +02:00
s = MSG_ReadString( msg );
if(!CL_ParseServerStatus( NET_AdrToString( from ), s ))
2008-06-22 22:00:00 +02:00
Msg( s );
2007-06-21 22:00:00 +02:00
return;
}
// ping from somewhere
2009-06-24 22:00:00 +02:00
if( !com.strcmp(c, "ping" ))
2007-06-21 22:00:00 +02:00
{
2008-07-12 22:00:00 +02:00
Netchan_OutOfBandPrint( NS_CLIENT, from, "ack" );
2007-06-21 22:00:00 +02:00
return;
}
// challenge from the server we are connecting to
2009-06-24 22:00:00 +02:00
if( !com.strcmp( c, "challenge" ))
2007-06-21 22:00:00 +02:00
{
2008-07-12 22:00:00 +02:00
cls.challenge = com.atoi(Cmd_Argv(1));
CL_SendConnectPacket();
2007-06-21 22:00:00 +02:00
return;
}
// echo request from server
2009-06-24 22:00:00 +02:00
if( !com.strcmp( c, "echo" ))
2007-06-21 22:00:00 +02:00
{
2008-07-12 22:00:00 +02:00
Netchan_OutOfBandPrint( NS_CLIENT, from, "%s", Cmd_Argv(1) );
return;
}
// a disconnect message from the server, which will happen if the server
// dropped the connection but it is still getting packets from us
2009-06-24 22:00:00 +02:00
if( !com.strcmp( c, "disconnect" ))
2008-07-12 22:00:00 +02:00
{
CL_Disconnect();
2007-06-21 22:00:00 +02:00
return;
}
2009-06-24 22:00:00 +02:00
Msg( "Unknown command.\n" );
2008-07-11 22:00:00 +02:00
}
/*
=================
2009-06-24 22:00:00 +02:00
CL_ReadNetMessage
2008-07-11 22:00:00 +02:00
=================
*/
2009-06-24 22:00:00 +02:00
void CL_ReadNetMessage( void )
2008-07-11 22:00:00 +02:00
{
2009-06-24 22:00:00 +02:00
while( NET_GetPacket( NS_CLIENT, &net_from, &net_message ))
2008-07-11 22:00:00 +02:00
{
2009-06-24 22:00:00 +02:00
if( host.type == HOST_DEDICATED || cls.demoplayback )
return;
2008-07-11 22:00:00 +02:00
2009-06-24 22:00:00 +02:00
if( net_message.cursize >= 4 && *(int *)net_message.data == -1 )
{
CL_ConnectionlessPacket( net_from, &net_message );
return;
}
2008-07-12 22:00:00 +02:00
2009-06-24 22:00:00 +02:00
// can't be a valid sequenced packet
if( cls.state < ca_connected ) return;
2008-07-11 22:00:00 +02:00
2009-06-24 22:00:00 +02:00
if( net_message.cursize < 8 )
{
MsgDev( D_WARN, "%s: runt packet\n", NET_AdrToString( net_from ));
return;
}
// packet from server
if( !NET_CompareAdr( net_from, cls.netchan.remote_address ))
{
MsgDev( D_WARN, "CL_ReadPackets: %s:sequenced packet without connection\n", NET_AdrToString( net_from ));
return;
}
2008-07-11 22:00:00 +02:00
2009-06-24 22:00:00 +02:00
if( Netchan_Process( &cls.netchan, &net_message ))
{
// the header is different lengths for reliable and unreliable messages
int headerBytes = net_message.readcount;
2008-07-11 22:00:00 +02:00
2009-06-24 22:00:00 +02:00
CL_ParseServerMessage( &net_message );
2008-07-11 22:00:00 +02:00
2009-06-24 22:00:00 +02:00
// we don't know if it is ok to save a demo message until
// after we have parsed the frame
if( cls.demorecording && !cls.demowaiting )
CL_WriteDemoMessage( &net_message, headerBytes );
}
2009-06-22 22:00:00 +02:00
}
}
2008-07-12 22:00:00 +02:00
void CL_ReadPackets( void )
2008-07-11 22:00:00 +02:00
{
2009-06-22 22:00:00 +02:00
if( cls.demoplayback )
CL_ReadDemoMessage();
else CL_ReadNetMessage();
2008-07-11 22:00:00 +02:00
2009-06-24 22:00:00 +02:00
// singleplayer never has connection timeout
if( NET_IsLocalAddress( cls.netchan.remote_address ))
2008-07-09 22:00:00 +02:00
return;
2008-07-11 22:00:00 +02:00
// check timeout
if( cls.state >= ca_connected && !cls.demoplayback )
{
2009-09-17 22:00:00 +02:00
if( cls.realtime - cls.netchan.last_received > (cl_timeout->value * 1000))
2008-07-11 22:00:00 +02:00
{
2009-06-24 22:00:00 +02:00
if( ++cl.timeoutcount > 5 ) // timeoutcount saves debugger
2008-07-11 22:00:00 +02:00
{
2009-09-17 22:00:00 +02:00
Msg( "\nServer connection timed out.\n" );
2008-07-11 22:00:00 +02:00
CL_Disconnect();
return;
}
}
2007-06-21 22:00:00 +02:00
}
2008-07-11 22:00:00 +02:00
else cl.timeoutcount = 0;
2007-06-21 22:00:00 +02:00
}
2008-07-11 22:00:00 +02:00
2007-06-21 22:00:00 +02:00
//=============================================================================
/*
==============
CL_Userinfo_f
==============
*/
void CL_Userinfo_f (void)
{
2009-07-04 22:00:00 +02:00
Msg( "User info settings:\n" );
2008-08-02 22:00:00 +02:00
Info_Print( Cvar_Userinfo());
2007-06-21 22:00:00 +02:00
}
int precache_check; // for autodownload of precache items
int precache_spawncount;
int precache_tex;
2008-08-02 22:00:00 +02:00
// ENV_CNT is map load, ENV_CNT+1 is first cubemap
#define ENV_CNT MAX_CONFIGSTRINGS
#define TEXTURE_CNT (ENV_CNT+13)
2007-06-21 22:00:00 +02:00
static const char *env_suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
2008-08-02 22:00:00 +02:00
void CL_RequestNextDownload( void )
2007-06-21 22:00:00 +02:00
{
2008-07-23 22:00:00 +02:00
string fn;
2008-08-02 22:00:00 +02:00
uint map_checksum; // for detecting cheater maps
2007-06-21 22:00:00 +02:00
2008-08-02 22:00:00 +02:00
if( cls.state != ca_connected )
2007-06-21 22:00:00 +02:00
return;
2008-08-02 22:00:00 +02:00
if( !allow_download->value && precache_check < ENV_CNT )
2007-06-21 22:00:00 +02:00
precache_check = ENV_CNT;
2008-08-02 22:00:00 +02:00
if( precache_check == CS_MODELS )
2007-09-14 22:00:00 +02:00
{
// confirm map
2007-06-21 22:00:00 +02:00
precache_check = CS_MODELS+2; // 0 isn't used
2008-08-02 22:00:00 +02:00
if(!CL_CheckOrDownloadFile( cl.configstrings[CS_MODELS+1] ))
return; // started a download map
2007-06-21 22:00:00 +02:00
}
2008-08-02 22:00:00 +02:00
if( precache_check >= CS_MODELS && precache_check < CS_MODELS+MAX_MODELS )
2007-09-14 22:00:00 +02:00
{
2008-08-02 22:00:00 +02:00
while( precache_check < CS_MODELS+MAX_MODELS && cl.configstrings[precache_check][0])
2007-09-14 22:00:00 +02:00
{
2008-08-02 22:00:00 +02:00
com.sprintf( fn, "%s", cl.configstrings[precache_check++]);
if(!CL_CheckOrDownloadFile( fn )) return; // started a download
2007-06-21 22:00:00 +02:00
}
precache_check = CS_SOUNDS;
}
2008-08-02 22:00:00 +02:00
if( precache_check >= CS_SOUNDS && precache_check < CS_SOUNDS+MAX_SOUNDS )
2007-08-11 22:00:00 +02:00
{
2008-08-02 22:00:00 +02:00
if( precache_check == CS_SOUNDS ) precache_check++; // zero is blank
while( precache_check < CS_SOUNDS+MAX_SOUNDS && cl.configstrings[precache_check][0])
2007-08-11 22:00:00 +02:00
{
2008-08-02 22:00:00 +02:00
// sound pathes from model events
if( cl.configstrings[precache_check][0] == '*' )
2007-08-11 22:00:00 +02:00
{
2008-07-30 22:00:00 +02:00
precache_check++;
continue;
2007-06-21 22:00:00 +02:00
}
2008-08-02 22:00:00 +02:00
com.sprintf( fn, "sound/%s", cl.configstrings[precache_check++]);
if(!CL_CheckOrDownloadFile( fn )) return; // started a download
2007-06-21 22:00:00 +02:00
}
precache_check = ENV_CNT;
}
2008-08-02 22:00:00 +02:00
if( precache_check == ENV_CNT )
2007-08-11 22:00:00 +02:00
{
2007-06-21 22:00:00 +02:00
precache_check = ENV_CNT + 1;
2009-11-03 22:00:00 +01:00
CM_BeginRegistration( cl.configstrings[CS_MODELS+1], true, &map_checksum );
2009-10-28 22:00:00 +01:00
if( map_checksum != com.atoi( cl.configstrings[CS_MAPCHECKSUM] ))
2007-08-11 22:00:00 +02:00
{
2009-10-28 22:00:00 +01:00
Host_Error( "Local map version differs from server: %i != '%s'\n", map_checksum, cl.configstrings[CS_MAPCHECKSUM] );
2007-06-21 22:00:00 +02:00
return;
}
}
2008-08-02 22:00:00 +02:00
if( precache_check > ENV_CNT && precache_check < TEXTURE_CNT )
2007-08-11 22:00:00 +02:00
{
2008-07-30 22:00:00 +02:00
if( allow_download->value )
2007-08-11 22:00:00 +02:00
{
2008-08-02 22:00:00 +02:00
while( precache_check < TEXTURE_CNT )
2007-08-11 22:00:00 +02:00
{
2007-06-21 22:00:00 +02:00
int n = precache_check++ - ENV_CNT - 1;
2009-08-11 22:00:00 +02:00
if( n & 1 ) com.sprintf( fn, "env/%s.dds", cl.configstrings[CS_SKYNAME] ); // cubemap pack
else com.sprintf( fn, "env/%s%s.tga", cl.configstrings[CS_SKYNAME], env_suf[n/2] );
2008-08-02 22:00:00 +02:00
if(!CL_CheckOrDownloadFile( fn )) return; // started a download
2007-06-21 22:00:00 +02:00
}
}
precache_check = TEXTURE_CNT;
}
2008-08-02 22:00:00 +02:00
if( precache_check == TEXTURE_CNT )
2007-08-11 22:00:00 +02:00
{
2007-06-21 22:00:00 +02:00
precache_check = TEXTURE_CNT+1;
precache_tex = 0;
}
// confirm existance of textures, download any that don't exist
2008-08-02 22:00:00 +02:00
if( precache_check == TEXTURE_CNT + 1 )
2007-08-11 22:00:00 +02:00
{
2008-07-30 22:00:00 +02:00
if( allow_download->value )
2007-08-11 22:00:00 +02:00
{
2009-11-03 22:00:00 +01:00
while( precache_tex < CM_NumShaders( ))
2007-08-11 22:00:00 +02:00
{
2009-11-03 22:00:00 +01:00
com.sprintf( fn, "%s", CM_GetShaderName( precache_tex++ ));
2008-12-26 22:00:00 +01:00
if( !CL_CheckOrDownloadFile( fn )) return; // started a download
2007-06-21 22:00:00 +02:00
}
}
2008-08-02 22:00:00 +02:00
precache_check = TEXTURE_CNT + 999;
2007-06-21 22:00:00 +02:00
}
2008-08-03 22:00:00 +02:00
CL_PrepSound();
CL_PrepVideo();
2008-12-26 22:00:00 +01:00
CL_SortUserMessages();
2008-06-12 22:00:00 +02:00
if( cls.demoplayback ) return; // not really connected
2008-07-10 22:00:00 +02:00
MSG_WriteByte( &cls.netchan.message, clc_stringcmd );
2009-10-13 22:00:00 +02:00
MSG_Print( &cls.netchan.message, va( "begin %i\n", precache_spawncount ));
2007-06-21 22:00:00 +02:00
}
/*
=================
CL_Precache_f
The server will send this command right
before allowing the client into the server
=================
*/
2008-08-02 22:00:00 +02:00
void CL_Precache_f( void )
2007-06-21 22:00:00 +02:00
{
precache_check = CS_MODELS;
2009-10-13 22:00:00 +02:00
precache_spawncount = com.atoi( Cmd_Argv( 1 ));
2007-06-21 22:00:00 +02:00
CL_RequestNextDownload();
}
/*
=================
CL_InitLocal
=================
*/
2009-09-10 22:00:00 +02:00
void CL_InitLocal( void )
2007-06-21 22:00:00 +02:00
{
cls.state = ca_disconnected;
2009-01-14 22:00:00 +01:00
2007-11-17 22:00:00 +01:00
CL_InitInput();
2007-06-21 22:00:00 +02:00
2007-11-05 22:00:00 +01:00
// register our variables
2009-09-13 22:00:00 +02:00
cl_predict = Cvar_Get( "cl_predict", "1", CVAR_ARCHIVE, "disables client movement prediction" );
2009-09-16 22:00:00 +02:00
cl_maxfps = Cvar_Get( "cl_maxfps", "1000", 0, "maximum client fps" );
2008-11-16 22:00:00 +01:00
cl_particles = Cvar_Get( "cl_particles", "1", CVAR_ARCHIVE, "disables particle effects" );
cl_particlelod = Cvar_Get( "cl_lod_particle", "0", CVAR_ARCHIVE, "enables particle LOD (1, 2, 3)" );
2007-06-21 22:00:00 +02:00
2009-09-13 22:00:00 +02:00
cl_upspeed = Cvar_Get( "cl_upspeed", "200", 0, "client upspeed limit" );
cl_forwardspeed = Cvar_Get( "cl_forwardspeed", "200", 0, "client forward speed limit" );
cl_backspeed = Cvar_Get( "cl_backspeed", "200", 0, "client bask speed limit" );
cl_sidespeed = Cvar_Get( "cl_sidespeed", "200", 0, "client side-speed limit" );
cl_yawspeed = Cvar_Get( "cl_yawspeed", "140", 0, "client yaw speed" );
cl_pitchspeed = Cvar_Get( "cl_pitchspeed", "150", 0, "client pitch speed" );
cl_anglespeedkey = Cvar_Get( "cl_anglespeedkey", "1.5", 0, "client anglespeed" );
cl_run = Cvar_Get( "cl_run", "0", CVAR_ARCHIVE, "keep client for always run mode" );
2007-06-21 22:00:00 +02:00
2009-09-13 22:00:00 +02:00
cl_shownet = Cvar_Get( "cl_shownet", "0", 0, "client show network packets" );
cl_showmiss = Cvar_Get( "cl_showmiss", "0", 0, "client show network errors" );
cl_timeout = Cvar_Get( "cl_timeout", "120", 0, "connect timeout (in-seconds)" );
2007-06-21 22:00:00 +02:00
2009-09-13 22:00:00 +02:00
rcon_client_password = Cvar_Get( "rcon_password", "", 0, "remote control client password" );
rcon_address = Cvar_Get( "rcon_address", "", 0, "remote control address" );
2007-06-21 22:00:00 +02:00
// userinfo
2009-09-13 22:00:00 +02:00
info_password = Cvar_Get( "password", "", CVAR_USERINFO, "player password" );
info_spectator = Cvar_Get( "spectator", "0", CVAR_USERINFO, "spectator mode" );
name = Cvar_Get( "name", "unnamed", CVAR_USERINFO | CVAR_ARCHIVE, "player name" );
2009-10-16 22:00:00 +02:00
model = Cvar_Get( "model", "player", CVAR_USERINFO | CVAR_ARCHIVE, "player model ('player' it's a single player model)" );
topcolor = Cvar_Get( "topcolor", "0", CVAR_USERINFO | CVAR_ARCHIVE, "player top color" );
bottomcolor = Cvar_Get( "bottomcolor", "0", CVAR_USERINFO | CVAR_ARCHIVE, "player bottom color" );
2009-09-13 22:00:00 +02:00
rate = Cvar_Get( "rate", "25000", CVAR_USERINFO | CVAR_ARCHIVE, "player network rate" ); // FIXME
cl_showfps = Cvar_Get( "cl_showfps", "1", CVAR_ARCHIVE, "show client fps" );
2007-06-21 22:00:00 +02:00
// register our commands
2007-11-17 22:00:00 +01:00
Cmd_AddCommand ("cmd", CL_ForwardToServer_f, "send a console commandline to the server" );
2009-11-10 22:00:00 +01:00
Cmd_AddCommand ("pause", NULL, "pause the game (if the server allows pausing)" );
2008-06-22 22:00:00 +02:00
Cmd_AddCommand ("getserverlist", CL_GetServerList_f, "get info about local servers" );
Cmd_AddCommand ("freeserverlist", CL_FreeServerList_f, "clear info about local servers" );
2007-06-21 22:00:00 +02:00
2007-11-17 22:00:00 +01:00
Cmd_AddCommand ("userinfo", CL_Userinfo_f, "print current client userinfo" );
Cmd_AddCommand ("changing", CL_Changing_f, "sent by server to tell client to wait for level change" );
Cmd_AddCommand ("disconnect", CL_Disconnect_f, "disconnect from server" );
Cmd_AddCommand ("record", CL_Record_f, "record a demo" );
2008-05-20 22:00:00 +02:00
Cmd_AddCommand ("playdemo", CL_PlayDemo_f, "playing a demo" );
2009-10-13 22:00:00 +02:00
Cmd_AddCommand ("startdemos", CL_StartDemos_f, "start playing back the selected demos sequentially" );
Cmd_AddCommand ("demos", CL_Demos_f, "restart looping demos defined by the last startdemos command" );
2008-08-02 22:00:00 +02:00
Cmd_AddCommand ("movie", CL_PlayVideo_f, "playing a movie" );
2008-05-20 22:00:00 +02:00
Cmd_AddCommand ("stop", CL_Stop_f, "stop playing or recording a demo" );
2007-11-06 22:00:00 +01:00
2007-11-17 22:00:00 +01:00
Cmd_AddCommand ("quit", CL_Quit_f, "quit from game" );
Cmd_AddCommand ("exit", CL_Quit_f, "quit from game" );
2007-06-21 22:00:00 +02:00
2007-11-17 22:00:00 +01:00
Cmd_AddCommand ("screenshot", CL_ScreenShot_f, "takes a screenshot of the next rendered frame" );
2008-11-09 22:00:00 +01:00
Cmd_AddCommand ("envshot", CL_EnvShot_f, "takes a six-sides cubemap shot with specified name" );
Cmd_AddCommand ("skyshot", CL_SkyShot_f, "takes a six-sides envmap (skybox) shot with specified name" );
2007-11-17 22:00:00 +01:00
Cmd_AddCommand ("levelshot", CL_LevelShot_f, "same as \"screenshot\", used for create plaque images" );
2009-09-10 22:00:00 +02:00
Cmd_AddCommand ("saveshot", CL_SaveShot_f, "used for create save previews with LoadGame menu" );
2007-06-21 22:00:00 +02:00
2007-11-17 22:00:00 +01:00
Cmd_AddCommand ("connect", CL_Connect_f, "connect to a server by hostname" );
Cmd_AddCommand ("reconnect", CL_Reconnect_f, "reconnect to current level" );
2007-06-21 22:00:00 +02:00
2007-11-17 22:00:00 +01:00
Cmd_AddCommand ("rcon", CL_Rcon_f, "sends a command to the server console (rcon_password and rcon_address required)" );
2007-06-21 22:00:00 +02:00
2007-11-17 22:00:00 +01:00
// this is dangerous to leave in
// Cmd_AddCommand ("packet", CL_Packet_f, "send a packet with custom contents" );
2007-06-21 22:00:00 +02:00
2007-11-17 22:00:00 +01:00
Cmd_AddCommand ("precache", CL_Precache_f, "precache specified resource (by index)" );
Cmd_AddCommand ("download", CL_Download_f, "download specified resource (by name)" );
2007-06-21 22:00:00 +02:00
}
2008-07-11 22:00:00 +02:00
//============================================================================
2008-07-10 22:00:00 +02:00
/*
==================
CL_SendCommand
==================
*/
2009-02-03 22:00:00 +01:00
void CL_SendCommand( void )
2008-07-10 22:00:00 +02:00
{
// send intentions now
2008-07-11 22:00:00 +02:00
CL_SendCmd ();
2008-07-10 22:00:00 +02:00
// resend a connection request if necessary
2008-07-11 22:00:00 +02:00
CL_CheckForResend ();
2009-09-14 22:00:00 +02:00
}
2007-06-21 22:00:00 +02:00
/*
==================
CL_Frame
==================
*/
2009-09-20 22:00:00 +02:00
void CL_Frame( int time )
2007-06-21 22:00:00 +02:00
{
2008-07-06 22:00:00 +02:00
if( host.type == HOST_DEDICATED )
return;
2007-06-21 22:00:00 +02:00
// decide the simulation time
2009-09-16 22:00:00 +02:00
cl.time += time; // can be merged by cl.frame.servertime
2009-07-04 22:00:00 +02:00
cls.realtime += time;
2009-09-17 22:00:00 +02:00
cls.frametime = time * 0.001f;
2009-06-24 22:00:00 +02:00
2009-09-16 22:00:00 +02:00
cl.time = bound( cl.frame.servertime - cl.serverframetime, cl.time, cl.frame.servertime );
if( cls.frametime > 0.2f ) cls.frametime = 0.2f;
2008-07-11 22:00:00 +02:00
// if in the debugger last frame, don't timeout
2009-09-17 22:00:00 +02:00
if( time > 5000 ) cls.netchan.last_received = Sys_Milliseconds();
2008-07-11 22:00:00 +02:00
2007-06-21 22:00:00 +02:00
// fetch results from server
2007-11-17 22:00:00 +01:00
CL_ReadPackets();
2007-06-21 22:00:00 +02:00
2008-07-11 22:00:00 +02:00
// send a new command message to the server
2008-07-10 22:00:00 +02:00
CL_SendCommand();
2007-06-21 22:00:00 +02:00
// predict all unacknowledged movements
2009-10-02 22:00:00 +02:00
CL_PredictMovement();
Host_CheckChanges();
2007-06-21 22:00:00 +02:00
// allow rendering DLL change
2008-08-03 22:00:00 +02:00
if( cls.state == ca_active )
{
if( !cl.video_prepped ) CL_PrepVideo();
if( !cl.audio_prepped ) CL_PrepSound();
}
2007-06-21 22:00:00 +02:00
// update the screen
2007-11-25 22:00:00 +01:00
SCR_UpdateScreen();
2007-06-21 22:00:00 +02:00
2009-09-23 22:00:00 +02:00
SCR_MakeScreenShot();
2007-06-21 22:00:00 +02:00
// update audio
2009-10-06 22:00:00 +02:00
S_Update( &cl.refdef );
2007-06-21 22:00:00 +02:00
// advance local effects for next frame
CL_RunDLights ();
CL_RunLightStyles ();
2007-11-05 22:00:00 +01:00
2007-11-06 22:00:00 +01:00
SCR_RunCinematic();
Con_RunConsole();
2007-06-21 22:00:00 +02:00
cls.framecount++;
}
//============================================================================
/*
====================
CL_Init
====================
*/
2008-06-12 22:00:00 +02:00
void CL_Init( void )
2007-06-21 22:00:00 +02:00
{
2008-07-06 22:00:00 +02:00
if( host.type == HOST_DEDICATED )
return; // nothing running on the client
2007-06-21 22:00:00 +02:00
2007-11-17 22:00:00 +01:00
Con_Init();
2009-06-22 22:00:00 +02:00
2008-12-25 22:00:00 +01:00
if( !CL_LoadProgs( "client" ))
Host_Error( "CL_InitGame: can't initialize client.dll\n" );
2009-06-22 22:00:00 +02:00
MSG_Init( &net_message, net_message_buffer, sizeof( net_message_buffer ));
2009-10-02 22:00:00 +02:00
Host_CheckChanges ();
2007-11-18 22:00:00 +01:00
CL_InitLocal();
2008-08-04 22:00:00 +02:00
cls.initialized = true;
2007-06-21 22:00:00 +02:00
}
/*
===============
CL_Shutdown
2007-09-10 22:00:00 +02:00
FIXME: this is a callback from Sys_Quit and Host_Error. It would be better
2007-06-21 22:00:00 +02:00
to run quit through here before the final handoff to the sys code.
===============
*/
2008-07-17 22:00:00 +02:00
void CL_Shutdown( void )
2007-06-21 22:00:00 +02:00
{
2007-10-29 22:00:00 +01:00
// already freed
2008-08-04 22:00:00 +02:00
if( host.state == HOST_ERROR ) return;
if( host.type == HOST_DEDICATED ) return;
if( !cls.initialized ) return;
2007-06-21 22:00:00 +02:00
2009-09-10 22:00:00 +02:00
Host_WriteConfig();
2008-12-25 22:00:00 +01:00
CL_UnloadProgs();
2008-07-01 22:00:00 +02:00
UI_Shutdown();
2007-06-21 22:00:00 +02:00
S_Shutdown();
2008-08-04 22:00:00 +02:00
SCR_Shutdown();
2007-11-17 22:00:00 +01:00
CL_ShutdownInput();
2008-08-04 22:00:00 +02:00
cls.initialized = false;
}