2010-11-20 10:37:14 +00:00
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
2011-07-31 16:39:48 +00:00
# include <new>
2010-05-29 07:25:38 +00:00
# include <stdlib.h> // qsort
# include <stdarg.h>
2010-12-11 17:55:28 +00:00
# include <base/math.h>
2010-05-29 07:25:38 +00:00
# include <base/system.h>
2011-02-27 14:03:57 +00:00
# include <engine/client.h>
# include <engine/config.h>
# include <engine/console.h>
# include <engine/editor.h>
# include <engine/engine.h>
# include <engine/graphics.h>
# include <engine/input.h>
# include <engine/keys.h>
# include <engine/map.h>
# include <engine/masterserver.h>
# include <engine/serverbrowser.h>
# include <engine/sound.h>
# include <engine/storage.h>
# include <engine/textrender.h>
# include <engine/shared/config.h>
2010-05-29 07:25:38 +00:00
# include <engine/shared/compression.h>
2011-02-27 14:03:57 +00:00
# include <engine/shared/datafile.h>
# include <engine/shared/demo.h>
2011-07-30 16:29:40 +00:00
# include <engine/shared/filecollection.h>
2011-03-31 13:13:49 +00:00
# include <engine/shared/mapchecker.h>
2010-05-29 07:25:38 +00:00
# include <engine/shared/network.h>
# include <engine/shared/packer.h>
# include <engine/shared/protocol.h>
2011-02-27 14:03:57 +00:00
# include <engine/shared/ringbuffer.h>
# include <engine/shared/snapshot.h>
2010-05-29 07:25:38 +00:00
# include <mastersrv/mastersrv.h>
# include <versionsrv/versionsrv.h>
2011-03-23 12:06:35 +00:00
# include "friends.h"
2011-03-27 16:00:54 +00:00
# include "serverbrowser.h"
2010-05-29 07:25:38 +00:00
# include "client.h"
2010-09-06 19:55:09 +00:00
# if defined(CONF_FAMILY_WINDOWS)
2011-02-27 14:03:57 +00:00
# define _WIN32_WINNT 0x0501
# define WIN32_LEAN_AND_MEAN
2010-09-06 19:55:09 +00:00
# include <windows.h>
# endif
2010-05-29 07:25:38 +00:00
void CGraph : : Init ( float Min , float Max )
{
m_Min = Min ;
m_Max = Max ;
m_Index = 0 ;
}
void CGraph : : ScaleMax ( )
{
int i = 0 ;
m_Max = 0 ;
for ( i = 0 ; i < MAX_VALUES ; i + + )
{
if ( m_aValues [ i ] > m_Max )
m_Max = m_aValues [ i ] ;
}
}
void CGraph : : ScaleMin ( )
{
int i = 0 ;
m_Min = m_Max ;
for ( i = 0 ; i < MAX_VALUES ; i + + )
{
if ( m_aValues [ i ] < m_Min )
m_Min = m_aValues [ i ] ;
}
}
void CGraph : : Add ( float v , float r , float g , float b )
{
m_Index = ( m_Index + 1 ) & ( MAX_VALUES - 1 ) ;
m_aValues [ m_Index ] = v ;
m_aColors [ m_Index ] [ 0 ] = r ;
m_aColors [ m_Index ] [ 1 ] = g ;
m_aColors [ m_Index ] [ 2 ] = b ;
}
void CGraph : : Render ( IGraphics * pGraphics , int Font , float x , float y , float w , float h , const char * pDescription )
{
//m_pGraphics->BlendNormal();
pGraphics - > TextureSet ( - 1 ) ;
pGraphics - > QuadsBegin ( ) ;
pGraphics - > SetColor ( 0 , 0 , 0 , 0.75f ) ;
IGraphics : : CQuadItem QuadItem ( x , y , w , h ) ;
pGraphics - > QuadsDrawTL ( & QuadItem , 1 ) ;
pGraphics - > QuadsEnd ( ) ;
pGraphics - > LinesBegin ( ) ;
pGraphics - > SetColor ( 0.95f , 0.95f , 0.95f , 1.00f ) ;
IGraphics : : CLineItem LineItem ( x , y + h / 2 , x + w , y + h / 2 ) ;
pGraphics - > LinesDraw ( & LineItem , 1 ) ;
pGraphics - > SetColor ( 0.5f , 0.5f , 0.5f , 0.75f ) ;
IGraphics : : CLineItem Array [ 2 ] = {
IGraphics : : CLineItem ( x , y + ( h * 3 ) / 4 , x + w , y + ( h * 3 ) / 4 ) ,
IGraphics : : CLineItem ( x , y + h / 4 , x + w , y + h / 4 ) } ;
pGraphics - > LinesDraw ( Array , 2 ) ;
for ( int i = 1 ; i < MAX_VALUES ; i + + )
{
float a0 = ( i - 1 ) / ( float ) MAX_VALUES ;
float a1 = i / ( float ) MAX_VALUES ;
int i0 = ( m_Index + i - 1 ) & ( MAX_VALUES - 1 ) ;
int i1 = ( m_Index + i ) & ( MAX_VALUES - 1 ) ;
float v0 = ( m_aValues [ i0 ] - m_Min ) / ( m_Max - m_Min ) ;
float v1 = ( m_aValues [ i1 ] - m_Min ) / ( m_Max - m_Min ) ;
IGraphics : : CColorVertex Array [ 2 ] = {
IGraphics : : CColorVertex ( 0 , m_aColors [ i0 ] [ 0 ] , m_aColors [ i0 ] [ 1 ] , m_aColors [ i0 ] [ 2 ] , 0.75f ) ,
IGraphics : : CColorVertex ( 1 , m_aColors [ i1 ] [ 0 ] , m_aColors [ i1 ] [ 1 ] , m_aColors [ i1 ] [ 2 ] , 0.75f ) } ;
pGraphics - > SetColorVertex ( Array , 2 ) ;
IGraphics : : CLineItem LineItem ( x + a0 * w , y + h - v0 * h , x + a1 * w , y + h - v1 * h ) ;
pGraphics - > LinesDraw ( & LineItem , 1 ) ;
}
pGraphics - > LinesEnd ( ) ;
pGraphics - > TextureSet ( Font ) ;
pGraphics - > QuadsText ( x + 2 , y + h - 16 , 16 , 1 , 1 , 1 , 1 , pDescription ) ;
char aBuf [ 32 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " %.2f " , m_Max ) ;
pGraphics - > QuadsText ( x + w - 8 * str_length ( aBuf ) - 8 , y + 2 , 16 , 1 , 1 , 1 , 1 , aBuf ) ;
str_format ( aBuf , sizeof ( aBuf ) , " %.2f " , m_Min ) ;
pGraphics - > QuadsText ( x + w - 8 * str_length ( aBuf ) - 8 , y + h - 16 , 16 , 1 , 1 , 1 , 1 , aBuf ) ;
}
void CSmoothTime : : Init ( int64 Target )
{
m_Snap = time_get ( ) ;
m_Current = Target ;
m_Target = Target ;
m_aAdjustSpeed [ 0 ] = 0.3f ;
m_aAdjustSpeed [ 1 ] = 0.3f ;
m_Graph . Init ( 0.0f , 0.5f ) ;
}
void CSmoothTime : : SetAdjustSpeed ( int Direction , float Value )
{
m_aAdjustSpeed [ Direction ] = Value ;
}
int64 CSmoothTime : : Get ( int64 Now )
{
int64 c = m_Current + ( Now - m_Snap ) ;
int64 t = m_Target + ( Now - m_Snap ) ;
// it's faster to adjust upward instead of downward
// we might need to adjust these abit
float AdjustSpeed = m_aAdjustSpeed [ 0 ] ;
if ( t > c )
AdjustSpeed = m_aAdjustSpeed [ 1 ] ;
float a = ( ( Now - m_Snap ) / ( float ) time_freq ( ) ) * AdjustSpeed ;
if ( a > 1.0f )
a = 1.0f ;
int64 r = c + ( int64 ) ( ( t - c ) * a ) ;
m_Graph . Add ( a + 0.5f , 1 , 1 , 1 ) ;
return r ;
}
void CSmoothTime : : UpdateInt ( int64 Target )
{
int64 Now = time_get ( ) ;
m_Current = Get ( Now ) ;
m_Snap = Now ;
m_Target = Target ;
}
void CSmoothTime : : Update ( CGraph * pGraph , int64 Target , int TimeLeft , int AdjustDirection )
{
int UpdateTimer = 1 ;
if ( TimeLeft < 0 )
{
int IsSpike = 0 ;
if ( TimeLeft < - 50 )
{
IsSpike = 1 ;
m_SpikeCounter + = 5 ;
if ( m_SpikeCounter > 50 )
m_SpikeCounter = 50 ;
}
if ( IsSpike & & m_SpikeCounter < 15 )
{
// ignore this ping spike
UpdateTimer = 0 ;
pGraph - > Add ( TimeLeft , 1 , 1 , 0 ) ;
}
else
{
pGraph - > Add ( TimeLeft , 1 , 0 , 0 ) ;
if ( m_aAdjustSpeed [ AdjustDirection ] < 30.0f )
m_aAdjustSpeed [ AdjustDirection ] * = 2.0f ;
}
}
else
{
if ( m_SpikeCounter )
m_SpikeCounter - - ;
pGraph - > Add ( TimeLeft , 0 , 1 , 0 ) ;
m_aAdjustSpeed [ AdjustDirection ] * = 0.95f ;
if ( m_aAdjustSpeed [ AdjustDirection ] < 2.0f )
m_aAdjustSpeed [ AdjustDirection ] = 2.0f ;
}
if ( UpdateTimer )
UpdateInt ( Target ) ;
}
CClient : : CClient ( ) : m_DemoPlayer ( & m_SnapshotDelta ) , m_DemoRecorder ( & m_SnapshotDelta )
{
m_pEditor = 0 ;
m_pInput = 0 ;
m_pGraphics = 0 ;
m_pSound = 0 ;
m_pGameClient = 0 ;
m_pMap = 0 ;
m_pConsole = 0 ;
m_FrameTime = 0.0001f ;
m_FrameTimeLow = 1.0f ;
m_FrameTimeHigh = 0.0f ;
m_Frames = 0 ;
m_GameTickSpeed = SERVER_TICK_SPEED ;
m_WindowMustRefocus = 0 ;
m_SnapCrcErrors = 0 ;
2010-12-12 15:48:13 +00:00
m_AutoScreenshotRecycle = false ;
2011-01-17 11:28:37 +00:00
m_EditorActive = false ;
2010-05-29 07:25:38 +00:00
m_AckGameTick = - 1 ;
m_CurrentRecvTick = 0 ;
m_RconAuthed = 0 ;
// version-checking
m_aVersionStr [ 0 ] = ' 0 ' ;
m_aVersionStr [ 1 ] = 0 ;
// pinging
m_PingStartTime = 0 ;
//
m_aCurrentMap [ 0 ] = 0 ;
m_CurrentMapCrc = 0 ;
//
m_aCmdConnect [ 0 ] = 0 ;
// map download
m_aMapdownloadFilename [ 0 ] = 0 ;
m_aMapdownloadName [ 0 ] = 0 ;
m_MapdownloadFile = 0 ;
m_MapdownloadChunk = 0 ;
m_MapdownloadCrc = 0 ;
m_MapdownloadAmount = - 1 ;
m_MapdownloadTotalsize = - 1 ;
m_CurrentServerInfoRequestTime = - 1 ;
m_CurrentInput = 0 ;
m_State = IClient : : STATE_OFFLINE ;
m_aServerAddressStr [ 0 ] = 0 ;
mem_zero ( m_aSnapshots , sizeof ( m_aSnapshots ) ) ;
2011-07-31 15:07:10 +00:00
m_SnapshotStorage . Init ( ) ;
2010-05-29 07:25:38 +00:00
m_RecivedSnapshots = 0 ;
2011-03-17 16:41:57 +00:00
m_VersionInfo . m_State = CVersionInfo : : STATE_INIT ;
2010-05-29 07:25:38 +00:00
}
// ----- send functions -----
int CClient : : SendMsg ( CMsgPacker * pMsg , int Flags )
{
return SendMsgEx ( pMsg , Flags , false ) ;
}
int CClient : : SendMsgEx ( CMsgPacker * pMsg , int Flags , bool System )
{
CNetChunk Packet ;
if ( State ( ) = = IClient : : STATE_OFFLINE )
return 0 ;
mem_zero ( & Packet , sizeof ( CNetChunk ) ) ;
Packet . m_ClientID = 0 ;
Packet . m_pData = pMsg - > Data ( ) ;
Packet . m_DataSize = pMsg - > Size ( ) ;
// HACK: modify the message id in the packet and store the system flag
if ( * ( ( unsigned char * ) Packet . m_pData ) = = 1 & & System & & Packet . m_DataSize = = 1 )
dbg_break ( ) ;
* ( ( unsigned char * ) Packet . m_pData ) < < = 1 ;
if ( System )
* ( ( unsigned char * ) Packet . m_pData ) | = 1 ;
if ( Flags & MSGFLAG_VITAL )
Packet . m_Flags | = NETSENDFLAG_VITAL ;
if ( Flags & MSGFLAG_FLUSH )
Packet . m_Flags | = NETSENDFLAG_FLUSH ;
if ( Flags & MSGFLAG_RECORD )
{
if ( m_DemoRecorder . IsRecording ( ) )
m_DemoRecorder . RecordMessage ( Packet . m_pData , Packet . m_DataSize ) ;
}
if ( ! ( Flags & MSGFLAG_NOSEND ) )
m_NetClient . Send ( & Packet ) ;
return 0 ;
}
void CClient : : SendInfo ( )
{
CMsgPacker Msg ( NETMSG_INFO ) ;
Msg . AddString ( GameClient ( ) - > NetVersion ( ) , 128 ) ;
Msg . AddString ( g_Config . m_Password , 128 ) ;
SendMsgEx ( & Msg , MSGFLAG_VITAL | MSGFLAG_FLUSH ) ;
}
void CClient : : SendEnterGame ( )
{
CMsgPacker Msg ( NETMSG_ENTERGAME ) ;
SendMsgEx ( & Msg , MSGFLAG_VITAL | MSGFLAG_FLUSH ) ;
}
void CClient : : SendReady ( )
{
CMsgPacker Msg ( NETMSG_READY ) ;
SendMsgEx ( & Msg , MSGFLAG_VITAL | MSGFLAG_FLUSH ) ;
}
void CClient : : RconAuth ( const char * pName , const char * pPassword )
{
if ( RconAuthed ( ) )
return ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
CMsgPacker Msg ( NETMSG_RCON_AUTH ) ;
Msg . AddString ( pName , 32 ) ;
Msg . AddString ( pPassword , 32 ) ;
2011-07-14 20:07:21 +00:00
Msg . AddInt ( 1 ) ;
2010-05-29 07:25:38 +00:00
SendMsgEx ( & Msg , MSGFLAG_VITAL ) ;
}
void CClient : : Rcon ( const char * pCmd )
{
CMsgPacker Msg ( NETMSG_RCON_CMD ) ;
Msg . AddString ( pCmd , 256 ) ;
SendMsgEx ( & Msg , MSGFLAG_VITAL ) ;
}
bool CClient : : ConnectionProblems ( )
{
return m_NetClient . GotProblems ( ) ! = 0 ;
}
void CClient : : DirectInput ( int * pInput , int Size )
{
int i ;
CMsgPacker Msg ( NETMSG_INPUT ) ;
Msg . AddInt ( m_AckGameTick ) ;
Msg . AddInt ( m_PredTick ) ;
Msg . AddInt ( Size ) ;
for ( i = 0 ; i < Size / 4 ; i + + )
Msg . AddInt ( pInput [ i ] ) ;
SendMsgEx ( & Msg , 0 ) ;
}
void CClient : : SendInput ( )
{
int64 Now = time_get ( ) ;
if ( m_PredTick < = 0 )
return ;
// fetch input
int Size = GameClient ( ) - > OnSnapInput ( m_aInputs [ m_CurrentInput ] . m_aData ) ;
if ( ! Size )
return ;
// pack input
CMsgPacker Msg ( NETMSG_INPUT ) ;
Msg . AddInt ( m_AckGameTick ) ;
Msg . AddInt ( m_PredTick ) ;
Msg . AddInt ( Size ) ;
m_aInputs [ m_CurrentInput ] . m_Tick = m_PredTick ;
m_aInputs [ m_CurrentInput ] . m_PredictedTime = m_PredictedTime . Get ( Now ) ;
m_aInputs [ m_CurrentInput ] . m_Time = Now ;
// pack it
for ( int i = 0 ; i < Size / 4 ; i + + )
Msg . AddInt ( m_aInputs [ m_CurrentInput ] . m_aData [ i ] ) ;
m_CurrentInput + + ;
m_CurrentInput % = 200 ;
SendMsgEx ( & Msg , MSGFLAG_FLUSH ) ;
}
const char * CClient : : LatestVersion ( )
{
return m_aVersionStr ;
}
// TODO: OPT: do this alot smarter!
int * CClient : : GetInput ( int Tick )
{
int Best = - 1 ;
for ( int i = 0 ; i < 200 ; i + + )
{
if ( m_aInputs [ i ] . m_Tick < = Tick & & ( Best = = - 1 | | m_aInputs [ Best ] . m_Tick < m_aInputs [ i ] . m_Tick ) )
Best = i ;
}
if ( Best ! = - 1 )
return ( int * ) m_aInputs [ Best ] . m_aData ;
return 0 ;
}
// ------ state handling -----
void CClient : : SetState ( int s )
{
int Old = m_State ;
if ( g_Config . m_Debug )
2010-08-17 22:06:00 +00:00
{
char aBuf [ 128 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " state change. last=%d current=%d " , m_State , s ) ;
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " client " , aBuf ) ;
}
2010-05-29 07:25:38 +00:00
m_State = s ;
if ( Old ! = s )
GameClient ( ) - > OnStateChange ( m_State , Old ) ;
}
// called when the map is loaded and we should init for a new round
void CClient : : OnEnterGame ( )
{
// reset input
int i ;
for ( i = 0 ; i < 200 ; i + + )
m_aInputs [ i ] . m_Tick = - 1 ;
m_CurrentInput = 0 ;
// reset snapshots
m_aSnapshots [ SNAP_CURRENT ] = 0 ;
m_aSnapshots [ SNAP_PREV ] = 0 ;
m_SnapshotStorage . PurgeAll ( ) ;
m_RecivedSnapshots = 0 ;
m_SnapshotParts = 0 ;
m_PredTick = 0 ;
m_CurrentRecvTick = 0 ;
m_CurGameTick = 0 ;
m_PrevGameTick = 0 ;
}
void CClient : : EnterGame ( )
{
if ( State ( ) = = IClient : : STATE_DEMOPLAYBACK )
return ;
// now we will wait for two snapshots
// to finish the connection
SendEnterGame ( ) ;
OnEnterGame ( ) ;
}
void CClient : : Connect ( const char * pAddress )
{
char aBuf [ 512 ] ;
int Port = 8303 ;
Disconnect ( ) ;
str_copy ( m_aServerAddressStr , pAddress , sizeof ( m_aServerAddressStr ) ) ;
2010-08-17 22:06:00 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " connecting to '%s' " , m_aServerAddressStr ) ;
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " client " , aBuf ) ;
2010-05-29 07:25:38 +00:00
ServerInfoRequest ( ) ;
2011-07-06 23:48:00 +00:00
if ( net_host_lookup ( m_aServerAddressStr , & m_ServerAddress , m_NetClient . NetType ( ) ) ! = 0 )
2010-07-02 11:15:35 +00:00
{
2010-08-17 22:06:00 +00:00
char aBufMsg [ 256 ] ;
str_format ( aBufMsg , sizeof ( aBufMsg ) , " could not find the address of %s, connecting to localhost " , aBuf ) ;
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " client " , aBufMsg ) ;
2011-07-06 23:48:00 +00:00
net_host_lookup ( " localhost " , & m_ServerAddress , m_NetClient . NetType ( ) ) ;
2010-07-02 11:15:35 +00:00
}
2010-05-29 07:25:38 +00:00
m_RconAuthed = 0 ;
2011-03-28 18:11:28 +00:00
if ( m_ServerAddress . port = = 0 )
m_ServerAddress . port = Port ;
2010-05-29 07:25:38 +00:00
m_NetClient . Connect ( & m_ServerAddress ) ;
SetState ( IClient : : STATE_CONNECTING ) ;
if ( m_DemoRecorder . IsRecording ( ) )
2010-12-07 23:02:24 +00:00
DemoRecorder_Stop ( ) ;
2010-05-29 07:25:38 +00:00
m_InputtimeMarginGraph . Init ( - 150.0f , 150.0f ) ;
m_GametimeMarginGraph . Init ( - 150.0f , 150.0f ) ;
}
void CClient : : DisconnectWithReason ( const char * pReason )
{
2010-08-17 22:06:00 +00:00
char aBuf [ 512 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " disconnecting. reason='%s' " , pReason ? pReason : " unknown " ) ;
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " client " , aBuf ) ;
2010-05-29 07:25:38 +00:00
// stop demo playback and recorder
m_DemoPlayer . Stop ( ) ;
2010-12-07 23:02:24 +00:00
DemoRecorder_Stop ( ) ;
2010-05-29 07:25:38 +00:00
//
m_RconAuthed = 0 ;
2011-07-14 20:07:21 +00:00
m_pConsole - > DeregisterTempAll ( ) ;
2010-05-29 07:25:38 +00:00
m_NetClient . Disconnect ( pReason ) ;
SetState ( IClient : : STATE_OFFLINE ) ;
m_pMap - > Unload ( ) ;
// disable all downloads
m_MapdownloadChunk = 0 ;
if ( m_MapdownloadFile )
io_close ( m_MapdownloadFile ) ;
m_MapdownloadFile = 0 ;
m_MapdownloadCrc = 0 ;
m_MapdownloadTotalsize = - 1 ;
m_MapdownloadAmount = 0 ;
// clear the current server info
mem_zero ( & m_CurrentServerInfo , sizeof ( m_CurrentServerInfo ) ) ;
mem_zero ( & m_ServerAddress , sizeof ( m_ServerAddress ) ) ;
// clear snapshots
m_aSnapshots [ SNAP_CURRENT ] = 0 ;
m_aSnapshots [ SNAP_PREV ] = 0 ;
m_RecivedSnapshots = 0 ;
}
void CClient : : Disconnect ( )
{
DisconnectWithReason ( 0 ) ;
}
void CClient : : GetServerInfo ( CServerInfo * pServerInfo )
{
mem_copy ( pServerInfo , & m_CurrentServerInfo , sizeof ( m_CurrentServerInfo ) ) ;
}
void CClient : : ServerInfoRequest ( )
{
mem_zero ( & m_CurrentServerInfo , sizeof ( m_CurrentServerInfo ) ) ;
m_CurrentServerInfoRequestTime = 0 ;
}
int CClient : : LoadData ( )
{
2010-10-06 21:07:35 +00:00
m_DebugFont = Graphics ( ) - > LoadTexture ( " debug_font.png " , IStorage : : TYPE_ALL , CImageInfo : : FORMAT_AUTO , IGraphics : : TEXLOAD_NORESAMPLE ) ;
2010-05-29 07:25:38 +00:00
return 1 ;
}
// ---
2011-02-12 10:40:36 +00:00
void * CClient : : SnapGetItem ( int SnapID , int Index , CSnapItem * pItem )
2010-05-29 07:25:38 +00:00
{
CSnapshotItem * i ;
2011-02-12 10:40:36 +00:00
dbg_assert ( SnapID > = 0 & & SnapID < NUM_SNAPSHOT_TYPES , " invalid SnapID " ) ;
i = m_aSnapshots [ SnapID ] - > m_pAltSnap - > GetItem ( Index ) ;
pItem - > m_DataSize = m_aSnapshots [ SnapID ] - > m_pAltSnap - > GetItemSize ( Index ) ;
2010-05-29 07:25:38 +00:00
pItem - > m_Type = i - > Type ( ) ;
2011-02-12 10:40:36 +00:00
pItem - > m_ID = i - > ID ( ) ;
2010-05-29 07:25:38 +00:00
return ( void * ) i - > Data ( ) ;
}
2011-02-12 10:40:36 +00:00
void CClient : : SnapInvalidateItem ( int SnapID , int Index )
2010-05-29 07:25:38 +00:00
{
CSnapshotItem * i ;
2011-02-12 10:40:36 +00:00
dbg_assert ( SnapID > = 0 & & SnapID < NUM_SNAPSHOT_TYPES , " invalid SnapID " ) ;
i = m_aSnapshots [ SnapID ] - > m_pAltSnap - > GetItem ( Index ) ;
2010-05-29 07:25:38 +00:00
if ( i )
{
2011-02-12 10:40:36 +00:00
if ( ( char * ) i < ( char * ) m_aSnapshots [ SnapID ] - > m_pAltSnap | | ( char * ) i > ( char * ) m_aSnapshots [ SnapID ] - > m_pAltSnap + m_aSnapshots [ SnapID ] - > m_SnapSize )
2010-08-17 22:06:00 +00:00
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " client " , " snap invalidate problem " ) ;
2011-02-12 10:40:36 +00:00
if ( ( char * ) i > = ( char * ) m_aSnapshots [ SnapID ] - > m_pSnap & & ( char * ) i < ( char * ) m_aSnapshots [ SnapID ] - > m_pSnap + m_aSnapshots [ SnapID ] - > m_SnapSize )
2010-08-17 22:06:00 +00:00
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " client " , " snap invalidate problem " ) ;
2010-05-29 07:25:38 +00:00
i - > m_TypeAndID = - 1 ;
}
}
2011-02-12 10:40:36 +00:00
void * CClient : : SnapFindItem ( int SnapID , int Type , int ID )
2010-05-29 07:25:38 +00:00
{
// TODO: linear search. should be fixed.
int i ;
2011-02-12 10:40:36 +00:00
if ( ! m_aSnapshots [ SnapID ] )
2010-05-29 07:25:38 +00:00
return 0x0 ;
2011-02-12 10:40:36 +00:00
for ( i = 0 ; i < m_aSnapshots [ SnapID ] - > m_pSnap - > NumItems ( ) ; i + + )
2010-05-29 07:25:38 +00:00
{
2011-02-12 10:40:36 +00:00
CSnapshotItem * pItem = m_aSnapshots [ SnapID ] - > m_pAltSnap - > GetItem ( i ) ;
if ( pItem - > Type ( ) = = Type & & pItem - > ID ( ) = = ID )
2010-05-29 07:25:38 +00:00
return ( void * ) pItem - > Data ( ) ;
}
return 0x0 ;
}
2011-02-12 10:40:36 +00:00
int CClient : : SnapNumItems ( int SnapID )
2010-05-29 07:25:38 +00:00
{
2011-02-12 10:40:36 +00:00
dbg_assert ( SnapID > = 0 & & SnapID < NUM_SNAPSHOT_TYPES , " invalid SnapID " ) ;
if ( ! m_aSnapshots [ SnapID ] )
2010-05-29 07:25:38 +00:00
return 0 ;
2011-02-12 10:40:36 +00:00
return m_aSnapshots [ SnapID ] - > m_pSnap - > NumItems ( ) ;
2010-05-29 07:25:38 +00:00
}
void CClient : : SnapSetStaticsize ( int ItemType , int Size )
{
m_SnapshotDelta . SetStaticsize ( ItemType , Size ) ;
}
void CClient : : DebugRender ( )
{
static NETSTATS Prev , Current ;
static int64 LastSnap = 0 ;
static float FrameTimeAvg = 0 ;
int64 Now = time_get ( ) ;
char aBuffer [ 512 ] ;
if ( ! g_Config . m_Debug )
return ;
//m_pGraphics->BlendNormal();
Graphics ( ) - > TextureSet ( m_DebugFont ) ;
Graphics ( ) - > MapScreen ( 0 , 0 , Graphics ( ) - > ScreenWidth ( ) , Graphics ( ) - > ScreenHeight ( ) ) ;
if ( time_get ( ) - LastSnap > time_freq ( ) )
{
LastSnap = time_get ( ) ;
Prev = Current ;
net_stats ( & Current ) ;
}
/*
eth = 14
ip = 20
udp = 8
total = 42
*/
FrameTimeAvg = FrameTimeAvg * 0.9f + m_FrameTime * 0.1f ;
2011-04-13 18:37:12 +00:00
str_format ( aBuffer , sizeof ( aBuffer ) , " ticks: %8d %8d mem %dk %d gfxmem: %dk fps: %3d " ,
2010-05-29 07:25:38 +00:00
m_CurGameTick , m_PredTick ,
mem_stats ( ) - > allocated / 1024 ,
mem_stats ( ) - > total_allocations ,
Graphics ( ) - > MemoryUsage ( ) / 1024 ,
( int ) ( 1.0f / FrameTimeAvg ) ) ;
Graphics ( ) - > QuadsText ( 2 , 2 , 16 , 1 , 1 , 1 , 1 , aBuffer ) ;
{
int SendPackets = ( Current . sent_packets - Prev . sent_packets ) ;
int SendBytes = ( Current . sent_bytes - Prev . sent_bytes ) ;
int SendTotal = SendBytes + SendPackets * 42 ;
int RecvPackets = ( Current . recv_packets - Prev . recv_packets ) ;
int RecvBytes = ( Current . recv_bytes - Prev . recv_bytes ) ;
int RecvTotal = RecvBytes + RecvPackets * 42 ;
if ( ! SendPackets ) SendPackets + + ;
if ( ! RecvPackets ) RecvPackets + + ;
str_format ( aBuffer , sizeof ( aBuffer ) , " send: %3d %5d+%4d=%5d (%3d kbps) avg: %5d \n recv: %3d %5d+%4d=%5d (%3d kbps) avg: %5d " ,
SendPackets , SendBytes , SendPackets * 42 , SendTotal , ( SendTotal * 8 ) / 1024 , SendBytes / SendPackets ,
RecvPackets , RecvBytes , RecvPackets * 42 , RecvTotal , ( RecvTotal * 8 ) / 1024 , RecvBytes / RecvPackets ) ;
Graphics ( ) - > QuadsText ( 2 , 14 , 16 , 1 , 1 , 1 , 1 , aBuffer ) ;
}
// render rates
{
int y = 0 ;
int i ;
for ( i = 0 ; i < 256 ; i + + )
{
if ( m_SnapshotDelta . GetDataRate ( i ) )
{
str_format ( aBuffer , sizeof ( aBuffer ) , " %4d %20s: %8d %8d %8d " , i , GameClient ( ) - > GetItemName ( i ) , m_SnapshotDelta . GetDataRate ( i ) / 8 , m_SnapshotDelta . GetDataUpdates ( i ) ,
( m_SnapshotDelta . GetDataRate ( i ) / m_SnapshotDelta . GetDataUpdates ( i ) ) / 8 ) ;
Graphics ( ) - > QuadsText ( 2 , 100 + y * 12 , 16 , 1 , 1 , 1 , 1 , aBuffer ) ;
y + + ;
}
}
}
str_format ( aBuffer , sizeof ( aBuffer ) , " pred: %d ms " ,
( int ) ( ( m_PredictedTime . Get ( Now ) - m_GameTime . Get ( Now ) ) * 1000 / ( float ) time_freq ( ) ) ) ;
Graphics ( ) - > QuadsText ( 2 , 70 , 16 , 1 , 1 , 1 , 1 , aBuffer ) ;
// render graphs
if ( g_Config . m_DbgGraphs )
{
//Graphics()->MapScreen(0,0,400.0f,300.0f);
float w = Graphics ( ) - > ScreenWidth ( ) / 4.0f ;
float h = Graphics ( ) - > ScreenHeight ( ) / 6.0f ;
float sp = Graphics ( ) - > ScreenWidth ( ) / 100.0f ;
float x = Graphics ( ) - > ScreenWidth ( ) - w - sp ;
m_FpsGraph . ScaleMax ( ) ;
m_FpsGraph . ScaleMin ( ) ;
m_FpsGraph . Render ( Graphics ( ) , m_DebugFont , x , sp * 5 , w , h , " FPS " ) ;
m_InputtimeMarginGraph . Render ( Graphics ( ) , m_DebugFont , x , sp * 5 + h + sp , w , h , " Prediction Margin " ) ;
m_GametimeMarginGraph . Render ( Graphics ( ) , m_DebugFont , x , sp * 5 + h + sp + h + sp , w , h , " Gametime Margin " ) ;
}
}
void CClient : : Quit ( )
{
SetState ( IClient : : STATE_QUITING ) ;
}
const char * CClient : : ErrorString ( )
{
return m_NetClient . ErrorString ( ) ;
}
void CClient : : Render ( )
{
2011-04-09 06:41:31 +00:00
2011-04-17 17:14:49 +00:00
if ( g_Config . m_ClShowEntities & & g_Config . m_ClDDRaceCheats )
2011-03-16 12:48:16 +00:00
Graphics ( ) - > Clear ( 0.3f , 0.3f , 0.6f ) ;
else if ( g_Config . m_GfxClear )
2010-09-27 19:41:41 +00:00
Graphics ( ) - > Clear ( 1 , 1 , 0 ) ;
2010-05-29 07:25:38 +00:00
GameClient ( ) - > OnRender ( ) ;
DebugRender ( ) ;
}
const char * CClient : : LoadMap ( const char * pName , const char * pFilename , unsigned WantedCrc )
{
static char aErrorMsg [ 128 ] ;
SetState ( IClient : : STATE_LOADING ) ;
if ( ! m_pMap - > Load ( pFilename ) )
{
str_format ( aErrorMsg , sizeof ( aErrorMsg ) , " map '%s' not found " , pFilename ) ;
return aErrorMsg ;
}
// get the crc of the map
if ( m_pMap - > Crc ( ) ! = WantedCrc )
{
str_format ( aErrorMsg , sizeof ( aErrorMsg ) , " map differs from the server. %08x != %08x " , m_pMap - > Crc ( ) , WantedCrc ) ;
2011-04-07 16:07:22 +00:00
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " client " , aErrorMsg ) ;
m_pMap - > Unload ( ) ;
2010-05-29 07:25:38 +00:00
return aErrorMsg ;
}
// stop demo recording if we loaded a new map
2010-12-07 23:02:24 +00:00
DemoRecorder_Stop ( ) ;
2010-05-29 07:25:38 +00:00
2010-08-17 22:06:00 +00:00
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " loaded map '%s' " , pFilename ) ;
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " client " , aBuf ) ;
2010-05-29 07:25:38 +00:00
m_RecivedSnapshots = 0 ;
str_copy ( m_aCurrentMap , pName , sizeof ( m_aCurrentMap ) ) ;
m_CurrentMapCrc = m_pMap - > Crc ( ) ;
return 0x0 ;
}
const char * CClient : : LoadMapSearch ( const char * pMapName , int WantedCrc )
{
const char * pError = 0 ;
char aBuf [ 512 ] ;
2010-08-17 22:06:00 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " loading map, map=%s wanted crc=%08x " , pMapName , WantedCrc ) ;
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " client " , aBuf ) ;
2010-05-29 07:25:38 +00:00
SetState ( IClient : : STATE_LOADING ) ;
// try the normal maps folder
str_format ( aBuf , sizeof ( aBuf ) , " maps/%s.map " , pMapName ) ;
pError = LoadMap ( pMapName , aBuf , WantedCrc ) ;
if ( ! pError )
return pError ;
// try the downloaded maps
str_format ( aBuf , sizeof ( aBuf ) , " downloadedmaps/%s_%08x.map " , pMapName , WantedCrc ) ;
pError = LoadMap ( pMapName , aBuf , WantedCrc ) ;
2011-02-21 10:23:30 +00:00
if ( ! pError )
return pError ;
// search for the map within subfolders
char aFilename [ 128 ] ;
str_format ( aFilename , sizeof ( aFilename ) , " %s.map " , pMapName ) ;
2011-04-04 14:53:02 +00:00
if ( Storage ( ) - > FindFile ( aFilename , " maps " , IStorage : : TYPE_ALL , aBuf , sizeof ( aBuf ) ) )
2011-02-21 10:23:30 +00:00
pError = LoadMap ( pMapName , aBuf , WantedCrc ) ;
2010-05-29 07:25:38 +00:00
return pError ;
}
int CClient : : PlayerScoreComp ( const void * a , const void * b )
{
2011-03-20 14:33:49 +00:00
CServerInfo : : CClient * p0 = ( CServerInfo : : CClient * ) a ;
CServerInfo : : CClient * p1 = ( CServerInfo : : CClient * ) b ;
if ( p0 - > m_Player & & ! p1 - > m_Player )
return - 1 ;
if ( ! p0 - > m_Player & & p1 - > m_Player )
return 1 ;
2010-05-29 07:25:38 +00:00
if ( p0 - > m_Score = = p1 - > m_Score )
return 0 ;
if ( p0 - > m_Score < p1 - > m_Score )
return 1 ;
return - 1 ;
}
2011-03-17 16:41:57 +00:00
void CClient : : ProcessConnlessPacket ( CNetChunk * pPacket )
2010-05-29 07:25:38 +00:00
{
2011-03-31 13:13:49 +00:00
// version server
if ( m_VersionInfo . m_State = = CVersionInfo : : STATE_READY & & net_addr_comp ( & pPacket - > m_Address , & m_VersionInfo . m_VersionServeraddr . m_Addr ) = = 0 )
2010-05-29 07:25:38 +00:00
{
2011-03-31 13:13:49 +00:00
// version info
2010-05-29 07:25:38 +00:00
if ( pPacket - > m_DataSize = = ( int ) ( sizeof ( VERSIONSRV_VERSION ) + sizeof ( VERSION_DATA ) ) & &
mem_comp ( pPacket - > m_pData , VERSIONSRV_VERSION , sizeof ( VERSIONSRV_VERSION ) ) = = 0 )
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
{
unsigned char * pVersionData = ( unsigned char * ) pPacket - > m_pData + sizeof ( VERSIONSRV_VERSION ) ;
int VersionMatch = ! mem_comp ( pVersionData , VERSION_DATA , sizeof ( VERSION_DATA ) ) ;
2010-08-17 22:06:00 +00:00
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " version does %s (%d.%d.%d) " ,
2010-05-29 07:25:38 +00:00
VersionMatch ? " match " : " NOT match " ,
pVersionData [ 1 ] , pVersionData [ 2 ] , pVersionData [ 3 ] ) ;
2010-08-17 22:06:00 +00:00
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " client/version " , aBuf ) ;
2010-05-29 07:25:38 +00:00
// assume version is out of date when version-data doesn't match
if ( ! VersionMatch )
{
str_format ( m_aVersionStr , sizeof ( m_aVersionStr ) , " %d.%d.%d " , pVersionData [ 1 ] , pVersionData [ 2 ] , pVersionData [ 3 ] ) ;
}
2011-03-31 13:13:49 +00:00
// request the map version list now
CNetChunk Packet ;
mem_zero ( & Packet , sizeof ( Packet ) ) ;
Packet . m_ClientID = - 1 ;
Packet . m_Address = m_VersionInfo . m_VersionServeraddr . m_Addr ;
Packet . m_pData = VERSIONSRV_GETMAPLIST ;
Packet . m_DataSize = sizeof ( VERSIONSRV_GETMAPLIST ) ;
Packet . m_Flags = NETSENDFLAG_CONNLESS ;
m_NetClient . Send ( & Packet ) ;
2010-05-29 07:25:38 +00:00
}
2011-03-31 13:13:49 +00:00
// map version list
if ( pPacket - > m_DataSize > = ( int ) sizeof ( VERSIONSRV_MAPLIST ) & &
2011-04-13 18:37:12 +00:00
mem_comp ( pPacket - > m_pData , VERSIONSRV_MAPLIST , sizeof ( VERSIONSRV_MAPLIST ) ) = = 0 )
2010-05-29 07:25:38 +00:00
{
2011-03-31 13:13:49 +00:00
int Size = pPacket - > m_DataSize - sizeof ( VERSIONSRV_MAPLIST ) ;
int Num = Size / sizeof ( CMapVersion ) ;
m_MapChecker . AddMaplist ( ( CMapVersion * ) ( ( char * ) pPacket - > m_pData + sizeof ( VERSIONSRV_MAPLIST ) ) , Num ) ;
2010-05-29 07:25:38 +00:00
}
2011-03-17 16:41:57 +00:00
}
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
// server list from master server
if ( pPacket - > m_DataSize > = ( int ) sizeof ( SERVERBROWSE_LIST ) & &
mem_comp ( pPacket - > m_pData , SERVERBROWSE_LIST , sizeof ( SERVERBROWSE_LIST ) ) = = 0 )
{
// check for valid master server address
bool Valid = false ;
for ( int i = 0 ; i < IMasterServer : : MAX_MASTERSERVERS ; + + i )
2010-05-29 07:25:38 +00:00
{
2011-03-30 10:08:33 +00:00
if ( m_pMasterServer - > IsValid ( i ) )
2010-05-29 07:25:38 +00:00
{
2011-03-30 10:08:33 +00:00
NETADDR Addr = m_pMasterServer - > GetAddr ( i ) ;
if ( net_addr_comp ( & pPacket - > m_Address , & Addr ) = = 0 )
2011-03-20 23:08:03 +00:00
{
2011-03-30 10:08:33 +00:00
Valid = true ;
break ;
2010-05-29 07:25:38 +00:00
}
}
}
2011-03-17 16:41:57 +00:00
if ( ! Valid )
return ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
int Size = pPacket - > m_DataSize - sizeof ( SERVERBROWSE_LIST ) ;
2011-03-30 10:08:33 +00:00
int Num = Size / sizeof ( CMastersrvAddr ) ;
CMastersrvAddr * pAddrs = ( CMastersrvAddr * ) ( ( char * ) pPacket - > m_pData + sizeof ( SERVERBROWSE_LIST ) ) ;
for ( int i = 0 ; i < Num ; i + + )
2011-03-17 16:41:57 +00:00
{
NETADDR Addr ;
2011-04-08 21:56:15 +00:00
static char IPV4Mapping [ ] = { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xFF , 0xFF } ;
2011-03-30 10:08:33 +00:00
// copy address
2011-04-08 21:56:15 +00:00
if ( ! mem_comp ( IPV4Mapping , pAddrs [ i ] . m_aIp , sizeof ( IPV4Mapping ) ) )
{
mem_zero ( & Addr , sizeof ( Addr ) ) ;
Addr . type = NETTYPE_IPV4 ;
Addr . ip [ 0 ] = pAddrs [ i ] . m_aIp [ 12 ] ;
Addr . ip [ 1 ] = pAddrs [ i ] . m_aIp [ 13 ] ;
Addr . ip [ 2 ] = pAddrs [ i ] . m_aIp [ 14 ] ;
Addr . ip [ 3 ] = pAddrs [ i ] . m_aIp [ 15 ] ;
}
else
{
Addr . type = NETTYPE_IPV6 ;
mem_copy ( Addr . ip , pAddrs [ i ] . m_aIp , sizeof ( Addr . ip ) ) ;
}
2011-03-31 13:13:49 +00:00
Addr . port = ( pAddrs [ i ] . m_aPort [ 0 ] < < 8 ) | pAddrs [ i ] . m_aPort [ 1 ] ;
2011-04-13 18:37:12 +00:00
2011-03-17 16:41:57 +00:00
m_ServerBrowser . Set ( Addr , IServerBrowser : : SET_MASTER_ADD , - 1 , 0x0 ) ;
2010-05-29 07:25:38 +00:00
}
}
2011-03-17 16:41:57 +00:00
// server info
if ( pPacket - > m_DataSize > = ( int ) sizeof ( SERVERBROWSE_INFO ) & & mem_comp ( pPacket - > m_pData , SERVERBROWSE_INFO , sizeof ( SERVERBROWSE_INFO ) ) = = 0 )
2010-05-29 07:25:38 +00:00
{
2011-03-17 16:41:57 +00:00
// we got ze info
CUnpacker Up ;
CServerInfo Info = { 0 } ;
2011-04-13 18:37:12 +00:00
2011-03-17 16:41:57 +00:00
Up . Reset ( ( unsigned char * ) pPacket - > m_pData + sizeof ( SERVERBROWSE_INFO ) , pPacket - > m_DataSize - sizeof ( SERVERBROWSE_INFO ) ) ;
int Token = str_toint ( Up . GetString ( ) ) ;
str_copy ( Info . m_aVersion , Up . GetString ( CUnpacker : : SANITIZE_CC | CUnpacker : : SKIP_START_WHITESPACES ) , sizeof ( Info . m_aVersion ) ) ;
str_copy ( Info . m_aName , Up . GetString ( CUnpacker : : SANITIZE_CC | CUnpacker : : SKIP_START_WHITESPACES ) , sizeof ( Info . m_aName ) ) ;
str_copy ( Info . m_aMap , Up . GetString ( CUnpacker : : SANITIZE_CC | CUnpacker : : SKIP_START_WHITESPACES ) , sizeof ( Info . m_aMap ) ) ;
str_copy ( Info . m_aGameType , Up . GetString ( CUnpacker : : SANITIZE_CC | CUnpacker : : SKIP_START_WHITESPACES ) , sizeof ( Info . m_aGameType ) ) ;
Info . m_Flags = str_toint ( Up . GetString ( ) ) ;
Info . m_NumPlayers = str_toint ( Up . GetString ( ) ) ;
Info . m_MaxPlayers = str_toint ( Up . GetString ( ) ) ;
2011-03-20 14:33:49 +00:00
Info . m_NumClients = str_toint ( Up . GetString ( ) ) ;
Info . m_MaxClients = str_toint ( Up . GetString ( ) ) ;
2011-03-17 16:41:57 +00:00
// don't add invalid info to the server browser list
2011-03-20 14:33:49 +00:00
if ( Info . m_NumClients < 0 | | Info . m_NumClients > MAX_CLIENTS | | Info . m_MaxClients < 0 | | Info . m_MaxClients > MAX_CLIENTS | |
Info . m_NumPlayers < 0 | | Info . m_NumPlayers > Info . m_NumClients | | Info . m_MaxPlayers < 0 | | Info . m_MaxPlayers > Info . m_MaxClients )
2010-05-29 07:25:38 +00:00
return ;
2011-03-28 18:11:28 +00:00
net_addr_str ( & pPacket - > m_Address , Info . m_aAddress , sizeof ( Info . m_aAddress ) ) ;
2010-05-29 07:25:38 +00:00
2011-03-20 14:33:49 +00:00
for ( int i = 0 ; i < Info . m_NumClients ; i + + )
2011-03-17 16:41:57 +00:00
{
2011-03-20 14:33:49 +00:00
str_copy ( Info . m_aClients [ i ] . m_aName , Up . GetString ( CUnpacker : : SANITIZE_CC | CUnpacker : : SKIP_START_WHITESPACES ) , sizeof ( Info . m_aClients [ i ] . m_aName ) ) ;
str_copy ( Info . m_aClients [ i ] . m_aClan , Up . GetString ( CUnpacker : : SANITIZE_CC | CUnpacker : : SKIP_START_WHITESPACES ) , sizeof ( Info . m_aClients [ i ] . m_aClan ) ) ;
2011-06-29 20:27:32 +00:00
Info . m_aClients [ i ] . m_Country = str_toint ( Up . GetString ( ) ) ;
2011-03-20 14:33:49 +00:00
Info . m_aClients [ i ] . m_Score = str_toint ( Up . GetString ( ) ) ;
Info . m_aClients [ i ] . m_Player = str_toint ( Up . GetString ( ) ) ! = 0 ? true : false ;
2011-03-17 16:41:57 +00:00
}
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
if ( ! Up . Error ( ) )
2010-05-29 07:25:38 +00:00
{
2011-03-17 16:41:57 +00:00
// sort players
2011-03-20 14:33:49 +00:00
qsort ( Info . m_aClients , Info . m_NumClients , sizeof ( * Info . m_aClients ) , PlayerScoreComp ) ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
if ( net_addr_comp ( & m_ServerAddress , & pPacket - > m_Address ) = = 0 )
{
mem_copy ( & m_CurrentServerInfo , & Info , sizeof ( m_CurrentServerInfo ) ) ;
m_CurrentServerInfo . m_NetAddr = m_ServerAddress ;
m_CurrentServerInfoRequestTime = - 1 ;
}
else
m_ServerBrowser . Set ( pPacket - > m_Address , IServerBrowser : : SET_TOKEN , Token , & Info ) ;
}
}
}
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
void CClient : : ProcessServerPacket ( CNetChunk * pPacket )
{
CUnpacker Unpacker ;
Unpacker . Reset ( pPacket - > m_pData , pPacket - > m_DataSize ) ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
// unpack msgid and system flag
int Msg = Unpacker . GetInt ( ) ;
int Sys = Msg & 1 ;
Msg > > = 1 ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
if ( Unpacker . Error ( ) )
return ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
if ( Sys )
{
// system message
if ( Msg = = NETMSG_MAP_CHANGE )
{
const char * pMap = Unpacker . GetString ( CUnpacker : : SANITIZE_CC | CUnpacker : : SKIP_START_WHITESPACES ) ;
int MapCrc = Unpacker . GetInt ( ) ;
int MapSize = Unpacker . GetInt ( ) ;
const char * pError = 0 ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
if ( Unpacker . Error ( ) )
return ;
2010-05-29 07:25:38 +00:00
2011-03-31 13:13:49 +00:00
// check for valid standard map
if ( ! m_MapChecker . IsMapValid ( pMap , MapCrc , MapSize ) )
pError = " invalid standard map " ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
for ( int i = 0 ; pMap [ i ] ; i + + ) // protect the player from nasty map names
2010-05-29 07:25:38 +00:00
{
2011-03-17 16:41:57 +00:00
if ( pMap [ i ] = = ' / ' | | pMap [ i ] = = ' \\ ' )
pError = " strange character in map name " ;
}
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
if ( MapSize < 0 )
pError = " invalid map size " ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
if ( pError )
DisconnectWithReason ( pError ) ;
else
{
pError = LoadMapSearch ( pMap , MapCrc ) ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
if ( ! pError )
2010-05-29 07:25:38 +00:00
{
2011-03-17 16:41:57 +00:00
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " client/network " , " loading done " ) ;
SendReady ( ) ;
}
else
2010-05-29 07:25:38 +00:00
{
2011-03-17 16:41:57 +00:00
str_format ( m_aMapdownloadFilename , sizeof ( m_aMapdownloadFilename ) , " downloadedmaps/%s_%08x.map " , pMap , MapCrc ) ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " starting to download map to '%s' " , m_aMapdownloadFilename ) ;
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " client/network " , aBuf ) ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
m_MapdownloadChunk = 0 ;
str_copy ( m_aMapdownloadName , pMap , sizeof ( m_aMapdownloadName ) ) ;
2010-11-21 00:10:25 +00:00
if ( m_MapdownloadFile )
io_close ( m_MapdownloadFile ) ;
2011-03-17 16:41:57 +00:00
m_MapdownloadFile = Storage ( ) - > OpenFile ( m_aMapdownloadFilename , IOFLAG_WRITE , IStorage : : TYPE_SAVE ) ;
m_MapdownloadCrc = MapCrc ;
m_MapdownloadTotalsize = MapSize ;
2010-05-29 07:25:38 +00:00
m_MapdownloadAmount = 0 ;
CMsgPacker Msg ( NETMSG_REQUEST_MAP_DATA ) ;
Msg . AddInt ( m_MapdownloadChunk ) ;
SendMsgEx ( & Msg , MSGFLAG_VITAL | MSGFLAG_FLUSH ) ;
if ( g_Config . m_Debug )
2010-08-17 22:06:00 +00:00
{
str_format ( aBuf , sizeof ( aBuf ) , " requested chunk %d " , m_MapdownloadChunk ) ;
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " client/network " , aBuf ) ;
}
2010-05-29 07:25:38 +00:00
}
}
2011-03-17 16:41:57 +00:00
}
else if ( Msg = = NETMSG_MAP_DATA )
{
int Last = Unpacker . GetInt ( ) ;
int MapCRC = Unpacker . GetInt ( ) ;
int Chunk = Unpacker . GetInt ( ) ;
int Size = Unpacker . GetInt ( ) ;
const unsigned char * pData = Unpacker . GetRaw ( Size ) ;
// check fior errors
if ( Unpacker . Error ( ) | | Size < = 0 | | MapCRC ! = m_MapdownloadCrc | | Chunk ! = m_MapdownloadChunk | | ! m_MapdownloadFile )
return ;
io_write ( m_MapdownloadFile , pData , Size ) ;
m_MapdownloadAmount + = Size ;
if ( Last )
2010-08-17 22:06:00 +00:00
{
2011-03-17 16:41:57 +00:00
const char * pError ;
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " client/network " , " download complete, loading map " ) ;
if ( m_MapdownloadFile )
io_close ( m_MapdownloadFile ) ;
m_MapdownloadFile = 0 ;
m_MapdownloadAmount = 0 ;
m_MapdownloadTotalsize = - 1 ;
// load map
pError = LoadMap ( m_aMapdownloadName , m_aMapdownloadFilename , m_MapdownloadCrc ) ;
if ( ! pError )
{
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " client/network " , " loading done " ) ;
2011-04-13 18:37:12 +00:00
SendReady ( ) ;
2011-03-17 16:41:57 +00:00
}
else
DisconnectWithReason ( pError ) ;
2010-08-17 22:06:00 +00:00
}
2011-03-17 16:41:57 +00:00
else
2010-05-29 07:25:38 +00:00
{
2011-03-17 16:41:57 +00:00
// request new chunk
m_MapdownloadChunk + + ;
CMsgPacker Msg ( NETMSG_REQUEST_MAP_DATA ) ;
Msg . AddInt ( m_MapdownloadChunk ) ;
SendMsgEx ( & Msg , MSGFLAG_VITAL | MSGFLAG_FLUSH ) ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
if ( g_Config . m_Debug )
2010-05-29 07:25:38 +00:00
{
2011-03-17 16:41:57 +00:00
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " requested chunk %d " , m_MapdownloadChunk ) ;
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " client/network " , aBuf ) ;
2010-05-29 07:25:38 +00:00
}
}
2011-03-17 16:41:57 +00:00
}
else if ( Msg = = NETMSG_CON_READY )
{
GameClient ( ) - > OnConnected ( ) ;
}
else if ( Msg = = NETMSG_PING )
{
CMsgPacker Msg ( NETMSG_PING_REPLY ) ;
SendMsgEx ( & Msg , 0 ) ;
}
2011-07-14 20:07:21 +00:00
else if ( Msg = = NETMSG_RCON_CMD_ADD )
{
const char * pName = Unpacker . GetString ( CUnpacker : : SANITIZE_CC ) ;
const char * pHelp = Unpacker . GetString ( CUnpacker : : SANITIZE_CC ) ;
const char * pParams = Unpacker . GetString ( CUnpacker : : SANITIZE_CC ) ;
if ( Unpacker . Error ( ) = = 0 )
m_pConsole - > RegisterTemp ( pName , pParams , CFGFLAG_SERVER , pHelp ) ;
}
else if ( Msg = = NETMSG_RCON_CMD_REM )
{
const char * pName = Unpacker . GetString ( CUnpacker : : SANITIZE_CC ) ;
if ( Unpacker . Error ( ) = = 0 )
m_pConsole - > DeregisterTemp ( pName ) ;
}
2011-03-17 16:41:57 +00:00
else if ( Msg = = NETMSG_RCON_AUTH_STATUS )
{
int Result = Unpacker . GetInt ( ) ;
if ( Unpacker . Error ( ) = = 0 )
m_RconAuthed = Result ;
2011-07-14 20:07:21 +00:00
m_UseTempRconCommands = Unpacker . GetInt ( ) ;
if ( Unpacker . Error ( ) ! = 0 )
m_UseTempRconCommands = 0 ;
2011-03-17 16:41:57 +00:00
}
else if ( Msg = = NETMSG_RCON_LINE )
{
const char * pLine = Unpacker . GetString ( ) ;
if ( Unpacker . Error ( ) = = 0 )
GameClient ( ) - > OnRconLine ( pLine ) ;
}
else if ( Msg = = NETMSG_PING_REPLY )
{
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " latency %.2f " , ( time_get ( ) - m_PingStartTime ) * 1000 / ( float ) time_freq ( ) ) ;
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " client/network " , aBuf ) ;
}
else if ( Msg = = NETMSG_INPUTTIMING )
{
int InputPredTick = Unpacker . GetInt ( ) ;
int TimeLeft = Unpacker . GetInt ( ) ;
// adjust our prediction time
int64 Target = 0 ;
for ( int k = 0 ; k < 200 ; k + + )
2010-05-29 07:25:38 +00:00
{
2011-03-17 16:41:57 +00:00
if ( m_aInputs [ k ] . m_Tick = = InputPredTick )
2010-05-29 07:25:38 +00:00
{
2011-03-17 16:41:57 +00:00
Target = m_aInputs [ k ] . m_PredictedTime + ( time_get ( ) - m_aInputs [ k ] . m_Time ) ;
Target = Target - ( int64 ) ( ( ( TimeLeft - PREDICTION_MARGIN ) / 1000.0f ) * time_freq ( ) ) ;
break ;
2010-05-29 07:25:38 +00:00
}
}
2011-03-17 16:41:57 +00:00
if ( Target )
m_PredictedTime . Update ( & m_InputtimeMarginGraph , Target , TimeLeft , 1 ) ;
}
else if ( Msg = = NETMSG_SNAP | | Msg = = NETMSG_SNAPSINGLE | | Msg = = NETMSG_SNAPEMPTY )
{
int NumParts = 1 ;
int Part = 0 ;
int GameTick = Unpacker . GetInt ( ) ;
int DeltaTick = GameTick - Unpacker . GetInt ( ) ;
int PartSize = 0 ;
int Crc = 0 ;
int CompleteSize = 0 ;
const char * pData = 0 ;
// we are not allowed to process snapshot yet
if ( State ( ) < IClient : : STATE_LOADING )
return ;
if ( Msg = = NETMSG_SNAP )
2010-05-29 07:25:38 +00:00
{
2011-03-17 16:41:57 +00:00
NumParts = Unpacker . GetInt ( ) ;
Part = Unpacker . GetInt ( ) ;
2010-05-29 07:25:38 +00:00
}
2011-03-17 16:41:57 +00:00
if ( Msg ! = NETMSG_SNAPEMPTY )
2010-08-17 22:06:00 +00:00
{
2011-03-17 16:41:57 +00:00
Crc = Unpacker . GetInt ( ) ;
PartSize = Unpacker . GetInt ( ) ;
2010-08-17 22:06:00 +00:00
}
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
pData = ( const char * ) Unpacker . GetRaw ( PartSize ) ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
if ( Unpacker . Error ( ) )
return ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
if ( GameTick > = m_CurrentRecvTick )
{
if ( GameTick ! = m_CurrentRecvTick )
2010-05-29 07:25:38 +00:00
{
2011-03-17 16:41:57 +00:00
m_SnapshotParts = 0 ;
m_CurrentRecvTick = GameTick ;
2010-05-29 07:25:38 +00:00
}
2011-03-17 16:41:57 +00:00
// TODO: clean this up abit
mem_copy ( ( char * ) m_aSnapshotIncommingData + Part * MAX_SNAPSHOT_PACKSIZE , pData , PartSize ) ;
m_SnapshotParts | = 1 < < Part ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
if ( m_SnapshotParts = = ( unsigned ) ( ( 1 < < NumParts ) - 1 ) )
2010-05-29 07:25:38 +00:00
{
2011-03-17 16:41:57 +00:00
static CSnapshot Emptysnap ;
CSnapshot * pDeltaShot = & Emptysnap ;
int PurgeTick ;
void * pDeltaData ;
int DeltaSize ;
unsigned char aTmpBuffer2 [ CSnapshot : : MAX_SIZE ] ;
unsigned char aTmpBuffer3 [ CSnapshot : : MAX_SIZE ] ;
CSnapshot * pTmpBuffer3 = ( CSnapshot * ) aTmpBuffer3 ; // Fix compiler warning for strict-aliasing
int SnapSize ;
CompleteSize = ( NumParts - 1 ) * MAX_SNAPSHOT_PACKSIZE + PartSize ;
// reset snapshoting
m_SnapshotParts = 0 ;
// find snapshot that we should use as delta
Emptysnap . Clear ( ) ;
// find delta
if ( DeltaTick > = 0 )
2010-05-29 07:25:38 +00:00
{
2011-03-17 16:41:57 +00:00
int DeltashotSize = m_SnapshotStorage . Get ( DeltaTick , 0 , & pDeltaShot , 0 ) ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
if ( DeltashotSize < 0 )
2010-05-29 07:25:38 +00:00
{
2011-03-17 16:41:57 +00:00
// couldn't find the delta snapshots that the server used
// to compress this snapshot. force the server to resync
2010-05-29 07:25:38 +00:00
if ( g_Config . m_Debug )
{
2010-08-17 22:06:00 +00:00
char aBuf [ 256 ] ;
2011-03-17 16:41:57 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " error, couldn't find the delta snapshot " ) ;
2010-08-17 22:06:00 +00:00
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " client " , aBuf ) ;
2010-05-29 07:25:38 +00:00
}
2011-03-17 16:41:57 +00:00
// ack snapshot
// TODO: combine this with the input message
m_AckGameTick = - 1 ;
2010-05-29 07:25:38 +00:00
return ;
}
2011-03-17 16:41:57 +00:00
}
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
// decompress snapshot
pDeltaData = m_SnapshotDelta . EmptyDelta ( ) ;
DeltaSize = sizeof ( int ) * 3 ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
if ( CompleteSize )
{
int IntSize = CVariableInt : : Decompress ( m_aSnapshotIncommingData , CompleteSize , aTmpBuffer2 ) ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
if ( IntSize < 0 ) // failure during decompression, bail
return ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
pDeltaData = aTmpBuffer2 ;
DeltaSize = IntSize ;
}
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
// unpack delta
PurgeTick = DeltaTick ;
SnapSize = m_SnapshotDelta . UnpackDelta ( pDeltaShot , pTmpBuffer3 , pDeltaData , DeltaSize ) ;
if ( SnapSize < 0 )
{
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " client " , " delta unpack failed! " ) ;
return ;
}
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
if ( Msg ! = NETMSG_SNAPEMPTY & & pTmpBuffer3 - > Crc ( ) ! = Crc )
{
if ( g_Config . m_Debug )
2010-05-29 07:25:38 +00:00
{
2011-03-17 16:41:57 +00:00
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " snapshot crc error #%d - tick=%d wantedcrc=%d gotcrc=%d compressed_size=%d delta_tick=%d " ,
m_SnapCrcErrors , GameTick , Crc , pTmpBuffer3 - > Crc ( ) , CompleteSize , DeltaTick ) ;
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " client " , aBuf ) ;
2010-05-29 07:25:38 +00:00
}
2011-03-17 16:41:57 +00:00
m_SnapCrcErrors + + ;
if ( m_SnapCrcErrors > 10 )
2010-05-29 07:25:38 +00:00
{
2011-03-17 16:41:57 +00:00
// to many errors, send reset
m_AckGameTick = - 1 ;
SendInput ( ) ;
m_SnapCrcErrors = 0 ;
2010-05-29 07:25:38 +00:00
}
2011-03-17 16:41:57 +00:00
return ;
}
else
{
if ( m_SnapCrcErrors )
m_SnapCrcErrors - - ;
}
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
// purge old snapshots
PurgeTick = DeltaTick ;
if ( m_aSnapshots [ SNAP_PREV ] & & m_aSnapshots [ SNAP_PREV ] - > m_Tick < PurgeTick )
PurgeTick = m_aSnapshots [ SNAP_PREV ] - > m_Tick ;
if ( m_aSnapshots [ SNAP_CURRENT ] & & m_aSnapshots [ SNAP_CURRENT ] - > m_Tick < PurgeTick )
PurgeTick = m_aSnapshots [ SNAP_PREV ] - > m_Tick ;
m_SnapshotStorage . PurgeUntil ( PurgeTick ) ;
// add new
m_SnapshotStorage . Add ( GameTick , time_get ( ) , SnapSize , pTmpBuffer3 , 1 ) ;
// add snapshot to demo
if ( m_DemoRecorder . IsRecording ( ) )
{
// write snapshot
m_DemoRecorder . RecordSnapshot ( GameTick , pTmpBuffer3 , SnapSize ) ;
}
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
// apply snapshot, cycle pointers
m_RecivedSnapshots + + ;
m_CurrentRecvTick = GameTick ;
// we got two snapshots until we see us self as connected
if ( m_RecivedSnapshots = = 2 )
{
// start at 200ms and work from there
m_PredictedTime . Init ( GameTick * time_freq ( ) / 50 ) ;
m_PredictedTime . SetAdjustSpeed ( 1 , 1000.0f ) ;
m_GameTime . Init ( ( GameTick - 1 ) * time_freq ( ) / 50 ) ;
m_aSnapshots [ SNAP_PREV ] = m_SnapshotStorage . m_pFirst ;
m_aSnapshots [ SNAP_CURRENT ] = m_SnapshotStorage . m_pLast ;
m_LocalStartTime = time_get ( ) ;
SetState ( IClient : : STATE_ONLINE ) ;
DemoRecorder_HandleAutoStart ( ) ;
2010-05-29 07:25:38 +00:00
}
2011-03-17 16:41:57 +00:00
// adjust game time
if ( m_RecivedSnapshots > 2 )
{
int64 Now = m_GameTime . Get ( time_get ( ) ) ;
int64 TickStart = GameTick * time_freq ( ) / 50 ;
int64 TimeLeft = ( TickStart - Now ) * 1000 / time_freq ( ) ;
m_GameTime . Update ( & m_GametimeMarginGraph , ( GameTick - 1 ) * time_freq ( ) / 50 , TimeLeft , 0 ) ;
2010-05-29 07:25:38 +00:00
}
2011-03-17 16:41:57 +00:00
// ack snapshot
m_AckGameTick = GameTick ;
2010-05-29 07:25:38 +00:00
}
}
}
2011-03-17 16:41:57 +00:00
}
else
{
// game message
if ( m_DemoRecorder . IsRecording ( ) )
m_DemoRecorder . RecordMessage ( pPacket - > m_pData , pPacket - > m_DataSize ) ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
GameClient ( ) - > OnMessage ( Msg , & Unpacker ) ;
2010-05-29 07:25:38 +00:00
}
}
void CClient : : PumpNetwork ( )
{
m_NetClient . Update ( ) ;
if ( State ( ) ! = IClient : : STATE_DEMOPLAYBACK )
{
// check for errors
2010-08-15 13:41:04 +00:00
if ( State ( ) ! = IClient : : STATE_OFFLINE & & State ( ) ! = IClient : : STATE_QUITING & & m_NetClient . State ( ) = = NETSTATE_OFFLINE )
2010-05-29 07:25:38 +00:00
{
SetState ( IClient : : STATE_OFFLINE ) ;
Disconnect ( ) ;
2010-08-17 22:06:00 +00:00
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " offline error='%s' " , m_NetClient . ErrorString ( ) ) ;
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " client " , aBuf ) ;
2010-05-29 07:25:38 +00:00
}
//
if ( State ( ) = = IClient : : STATE_CONNECTING & & m_NetClient . State ( ) = = NETSTATE_ONLINE )
{
// we switched to online
2010-08-17 22:06:00 +00:00
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " client " , " connected, sending info " ) ;
2010-05-29 07:25:38 +00:00
SetState ( IClient : : STATE_LOADING ) ;
SendInfo ( ) ;
}
}
// process packets
CNetChunk Packet ;
while ( m_NetClient . Recv ( & Packet ) )
2011-03-17 16:41:57 +00:00
{
if ( Packet . m_ClientID = = - 1 )
ProcessConnlessPacket ( & Packet ) ;
else
ProcessServerPacket ( & Packet ) ;
}
2010-05-29 07:25:38 +00:00
}
void CClient : : OnDemoPlayerSnapshot ( void * pData , int Size )
{
// update ticks, they could have changed
const CDemoPlayer : : CPlaybackInfo * pInfo = m_DemoPlayer . Info ( ) ;
CSnapshotStorage : : CHolder * pTemp ;
m_CurGameTick = pInfo - > m_Info . m_CurrentTick ;
m_PrevGameTick = pInfo - > m_PreviousTick ;
// handle snapshots
pTemp = m_aSnapshots [ SNAP_PREV ] ;
m_aSnapshots [ SNAP_PREV ] = m_aSnapshots [ SNAP_CURRENT ] ;
m_aSnapshots [ SNAP_CURRENT ] = pTemp ;
mem_copy ( m_aSnapshots [ SNAP_CURRENT ] - > m_pSnap , pData , Size ) ;
mem_copy ( m_aSnapshots [ SNAP_CURRENT ] - > m_pAltSnap , pData , Size ) ;
GameClient ( ) - > OnNewSnapshot ( ) ;
}
void CClient : : OnDemoPlayerMessage ( void * pData , int Size )
{
CUnpacker Unpacker ;
Unpacker . Reset ( pData , Size ) ;
// unpack msgid and system flag
int Msg = Unpacker . GetInt ( ) ;
int Sys = Msg & 1 ;
Msg > > = 1 ;
if ( Unpacker . Error ( ) )
return ;
if ( ! Sys )
GameClient ( ) - > OnMessage ( Msg , & Unpacker ) ;
}
/*
const IDemoPlayer : : CInfo * client_demoplayer_getinfo ( )
{
static DEMOPLAYBACK_INFO ret ;
const DEMOREC_PLAYBACKINFO * info = m_DemoPlayer . Info ( ) ;
ret . first_tick = info - > first_tick ;
ret . last_tick = info - > last_tick ;
ret . current_tick = info - > current_tick ;
ret . paused = info - > paused ;
ret . speed = info - > speed ;
return & ret ;
} */
/*
void DemoPlayer ( ) - > SetPos ( float percent )
{
demorec_playback_set ( percent ) ;
}
void DemoPlayer ( ) - > SetSpeed ( float speed )
{
demorec_playback_setspeed ( speed ) ;
}
void DemoPlayer ( ) - > SetPause ( int paused )
{
if ( paused )
demorec_playback_pause ( ) ;
else
demorec_playback_unpause ( ) ;
} */
void CClient : : Update ( )
{
if ( State ( ) = = IClient : : STATE_DEMOPLAYBACK )
{
m_DemoPlayer . Update ( ) ;
if ( m_DemoPlayer . IsPlaying ( ) )
{
// update timers
const CDemoPlayer : : CPlaybackInfo * pInfo = m_DemoPlayer . Info ( ) ;
m_CurGameTick = pInfo - > m_Info . m_CurrentTick ;
m_PrevGameTick = pInfo - > m_PreviousTick ;
m_GameIntraTick = pInfo - > m_IntraTick ;
m_GameTickTime = pInfo - > m_TickTime ;
}
else
{
// disconnect on error
Disconnect ( ) ;
}
}
2011-04-07 16:23:03 +00:00
else if ( State ( ) = = IClient : : STATE_ONLINE & & m_RecivedSnapshots > = 3 )
2010-05-29 07:25:38 +00:00
{
// switch snapshot
int Repredict = 0 ;
int64 Freq = time_freq ( ) ;
int64 Now = m_GameTime . Get ( time_get ( ) ) ;
int64 PredNow = m_PredictedTime . Get ( time_get ( ) ) ;
while ( 1 )
{
CSnapshotStorage : : CHolder * pCur = m_aSnapshots [ SNAP_CURRENT ] ;
int64 TickStart = ( pCur - > m_Tick ) * time_freq ( ) / 50 ;
if ( TickStart < Now )
{
CSnapshotStorage : : CHolder * pNext = m_aSnapshots [ SNAP_CURRENT ] - > m_pNext ;
if ( pNext )
{
m_aSnapshots [ SNAP_PREV ] = m_aSnapshots [ SNAP_CURRENT ] ;
m_aSnapshots [ SNAP_CURRENT ] = pNext ;
// set ticks
m_CurGameTick = m_aSnapshots [ SNAP_CURRENT ] - > m_Tick ;
m_PrevGameTick = m_aSnapshots [ SNAP_PREV ] - > m_Tick ;
if ( m_aSnapshots [ SNAP_CURRENT ] & & m_aSnapshots [ SNAP_PREV ] )
{
GameClient ( ) - > OnNewSnapshot ( ) ;
Repredict = 1 ;
}
}
else
break ;
}
else
break ;
}
if ( m_aSnapshots [ SNAP_CURRENT ] & & m_aSnapshots [ SNAP_PREV ] )
{
int64 CurtickStart = ( m_aSnapshots [ SNAP_CURRENT ] - > m_Tick ) * time_freq ( ) / 50 ;
int64 PrevtickStart = ( m_aSnapshots [ SNAP_PREV ] - > m_Tick ) * time_freq ( ) / 50 ;
int PrevPredTick = ( int ) ( PredNow * 50 / time_freq ( ) ) ;
int NewPredTick = PrevPredTick + 1 ;
m_GameIntraTick = ( Now - PrevtickStart ) / ( float ) ( CurtickStart - PrevtickStart ) ;
m_GameTickTime = ( Now - PrevtickStart ) / ( float ) Freq ; //(float)SERVER_TICK_SPEED);
CurtickStart = NewPredTick * time_freq ( ) / 50 ;
PrevtickStart = PrevPredTick * time_freq ( ) / 50 ;
m_PredIntraTick = ( PredNow - PrevtickStart ) / ( float ) ( CurtickStart - PrevtickStart ) ;
if ( NewPredTick < m_aSnapshots [ SNAP_PREV ] - > m_Tick - SERVER_TICK_SPEED | | NewPredTick > m_aSnapshots [ SNAP_PREV ] - > m_Tick + SERVER_TICK_SPEED )
{
2010-08-17 22:06:00 +00:00
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " client " , " prediction time reset! " ) ;
2010-05-29 07:25:38 +00:00
m_PredictedTime . Init ( m_aSnapshots [ SNAP_CURRENT ] - > m_Tick * time_freq ( ) / 50 ) ;
}
if ( NewPredTick > m_PredTick )
{
m_PredTick = NewPredTick ;
Repredict = 1 ;
// send input
SendInput ( ) ;
}
}
// only do sane predictions
if ( Repredict )
{
if ( m_PredTick > m_CurGameTick & & m_PredTick < m_CurGameTick + 50 )
GameClient ( ) - > OnPredict ( ) ;
}
// fetch server info if we don't have it
if ( State ( ) > = IClient : : STATE_LOADING & &
m_CurrentServerInfoRequestTime > = 0 & &
time_get ( ) > m_CurrentServerInfoRequestTime )
{
m_ServerBrowser . Request ( m_ServerAddress ) ;
m_CurrentServerInfoRequestTime = time_get ( ) + time_freq ( ) * 2 ;
}
}
// STRESS TEST: join the server again
if ( g_Config . m_DbgStress )
{
static int64 ActionTaken = 0 ;
int64 Now = time_get ( ) ;
if ( State ( ) = = IClient : : STATE_OFFLINE )
{
if ( Now > ActionTaken + time_freq ( ) * 2 )
{
2010-08-17 22:06:00 +00:00
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " stress " , " reconnecting! " ) ;
2010-05-29 07:25:38 +00:00
Connect ( g_Config . m_DbgStressServer ) ;
ActionTaken = Now ;
}
}
2011-02-13 16:59:51 +00:00
else
{
if ( Now > ActionTaken + time_freq ( ) * ( 10 + g_Config . m_DbgStress ) )
{
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " stress " , " disconnecting! " ) ;
Disconnect ( ) ;
ActionTaken = Now ;
}
}
2010-05-29 07:25:38 +00:00
}
// pump the network
PumpNetwork ( ) ;
// update the maser server registry
MasterServer ( ) - > Update ( ) ;
// update the server browser
2011-03-18 18:03:13 +00:00
m_ServerBrowser . Update ( m_ResortServerBrowser ) ;
m_ResortServerBrowser = false ;
2010-05-29 07:25:38 +00:00
}
void CClient : : VersionUpdate ( )
{
2011-03-17 16:41:57 +00:00
if ( m_VersionInfo . m_State = = CVersionInfo : : STATE_INIT )
2010-05-29 07:25:38 +00:00
{
2011-07-06 23:48:00 +00:00
Engine ( ) - > HostLookup ( & m_VersionInfo . m_VersionServeraddr , g_Config . m_ClVersionServer , m_NetClient . NetType ( ) ) ;
2011-03-17 16:41:57 +00:00
m_VersionInfo . m_State = CVersionInfo : : STATE_START ;
2010-05-29 07:25:38 +00:00
}
2011-03-17 16:41:57 +00:00
else if ( m_VersionInfo . m_State = = CVersionInfo : : STATE_START )
2010-05-29 07:25:38 +00:00
{
if ( m_VersionInfo . m_VersionServeraddr . m_Job . Status ( ) = = CJob : : STATE_DONE )
{
CNetChunk Packet ;
mem_zero ( & Packet , sizeof ( Packet ) ) ;
m_VersionInfo . m_VersionServeraddr . m_Addr . port = VERSIONSRV_PORT ;
Packet . m_ClientID = - 1 ;
Packet . m_Address = m_VersionInfo . m_VersionServeraddr . m_Addr ;
Packet . m_pData = VERSIONSRV_GETVERSION ;
Packet . m_DataSize = sizeof ( VERSIONSRV_GETVERSION ) ;
Packet . m_Flags = NETSENDFLAG_CONNLESS ;
m_NetClient . Send ( & Packet ) ;
2011-03-17 16:41:57 +00:00
m_VersionInfo . m_State = CVersionInfo : : STATE_READY ;
2010-05-29 07:25:38 +00:00
}
}
}
void CClient : : RegisterInterfaces ( )
{
2010-08-09 12:14:15 +00:00
Kernel ( ) - > RegisterInterface ( static_cast < IDemoRecorder * > ( & m_DemoRecorder ) ) ;
2010-05-29 07:25:38 +00:00
Kernel ( ) - > RegisterInterface ( static_cast < IDemoPlayer * > ( & m_DemoPlayer ) ) ;
Kernel ( ) - > RegisterInterface ( static_cast < IServerBrowser * > ( & m_ServerBrowser ) ) ;
2011-03-23 12:06:35 +00:00
Kernel ( ) - > RegisterInterface ( static_cast < IFriends * > ( & m_Friends ) ) ;
2010-05-29 07:25:38 +00:00
}
void CClient : : InitInterfaces ( )
{
// fetch interfaces
2011-02-27 14:03:57 +00:00
m_pEngine = Kernel ( ) - > RequestInterface < IEngine > ( ) ;
2010-05-29 07:25:38 +00:00
m_pEditor = Kernel ( ) - > RequestInterface < IEditor > ( ) ;
m_pGraphics = Kernel ( ) - > RequestInterface < IEngineGraphics > ( ) ;
m_pSound = Kernel ( ) - > RequestInterface < IEngineSound > ( ) ;
m_pGameClient = Kernel ( ) - > RequestInterface < IGameClient > ( ) ;
m_pInput = Kernel ( ) - > RequestInterface < IEngineInput > ( ) ;
m_pMap = Kernel ( ) - > RequestInterface < IEngineMap > ( ) ;
m_pMasterServer = Kernel ( ) - > RequestInterface < IEngineMasterServer > ( ) ;
m_pStorage = Kernel ( ) - > RequestInterface < IStorage > ( ) ;
//
m_ServerBrowser . SetBaseInfo ( & m_NetClient , m_pGameClient - > NetVersion ( ) ) ;
2011-03-23 12:06:35 +00:00
m_Friends . Init ( ) ;
2010-05-29 07:25:38 +00:00
}
void CClient : : Run ( )
{
int64 ReportTime = time_get ( ) ;
int64 ReportInterval = time_freq ( ) * 1 ;
m_LocalStartTime = time_get ( ) ;
m_SnapshotParts = 0 ;
// init graphics
if ( m_pGraphics - > Init ( ) ! = 0 )
return ;
2011-04-04 16:20:05 +00:00
// open socket
{
NETADDR BindAddr ;
mem_zero ( & BindAddr , sizeof ( BindAddr ) ) ;
BindAddr . type = NETTYPE_ALL ;
if ( ! m_NetClient . Open ( BindAddr , 0 ) )
{
dbg_msg ( " client " , " couldn't start network " ) ;
return ;
}
}
2010-05-29 07:25:38 +00:00
// init font rendering
Kernel ( ) - > RequestInterface < IEngineTextRender > ( ) - > Init ( ) ;
// init the input
Input ( ) - > Init ( ) ;
// start refreshing addresses while we load
2011-07-06 23:48:00 +00:00
MasterServer ( ) - > RefreshAddresses ( m_NetClient . NetType ( ) ) ;
2010-05-29 07:25:38 +00:00
// init the editor
m_pEditor - > Init ( ) ;
// init sound, allowed to fail
2011-01-17 12:28:15 +00:00
m_SoundInitFailed = Sound ( ) - > Init ( ) ! = 0 ;
2010-05-29 07:25:38 +00:00
// load data
if ( ! LoadData ( ) )
return ;
GameClient ( ) - > OnInit ( ) ;
2010-08-17 22:06:00 +00:00
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " version %s " , GameClient ( ) - > NetVersion ( ) ) ;
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " client " , aBuf ) ;
2010-05-29 07:25:38 +00:00
// connect to the server if wanted
/*
if ( config . cl_connect [ 0 ] ! = 0 )
Connect ( config . cl_connect ) ;
config . cl_connect [ 0 ] = 0 ;
*/
//
m_FpsGraph . Init ( 0.0f , 200.0f ) ;
// never start with the editor
g_Config . m_ClEditor = 0 ;
Input ( ) - > MouseModeRelative ( ) ;
2010-08-07 18:22:25 +00:00
// process pending commands
2010-08-25 20:30:21 +00:00
m_pConsole - > StoreCommands ( false , - 1 ) ;
2010-08-07 18:22:25 +00:00
2010-05-29 07:25:38 +00:00
while ( 1 )
{
int64 FrameStartTime = time_get ( ) ;
m_Frames + + ;
//
VersionUpdate ( ) ;
// handle pending connects
if ( m_aCmdConnect [ 0 ] )
{
str_copy ( g_Config . m_UiServerAddress , m_aCmdConnect , sizeof ( g_Config . m_UiServerAddress ) ) ;
Connect ( m_aCmdConnect ) ;
m_aCmdConnect [ 0 ] = 0 ;
}
// update input
2010-12-11 21:04:50 +00:00
if ( Input ( ) - > Update ( ) )
break ; // SDL_QUIT
2010-05-29 07:25:38 +00:00
// update sound
Sound ( ) - > Update ( ) ;
// release focus
if ( ! m_pGraphics - > WindowActive ( ) )
{
if ( m_WindowMustRefocus = = 0 )
Input ( ) - > MouseModeAbsolute ( ) ;
m_WindowMustRefocus = 1 ;
}
else if ( g_Config . m_DbgFocus & & Input ( ) - > KeyPressed ( KEY_ESCAPE ) )
{
Input ( ) - > MouseModeAbsolute ( ) ;
m_WindowMustRefocus = 1 ;
}
// refocus
if ( m_WindowMustRefocus & & m_pGraphics - > WindowActive ( ) )
{
if ( m_WindowMustRefocus < 3 )
{
Input ( ) - > MouseModeAbsolute ( ) ;
m_WindowMustRefocus + + ;
}
2010-05-30 01:00:17 +00:00
if ( m_WindowMustRefocus > = 3 | | Input ( ) - > KeyPressed ( KEY_MOUSE_1 ) )
2010-05-29 07:25:38 +00:00
{
Input ( ) - > MouseModeRelative ( ) ;
m_WindowMustRefocus = 0 ;
}
}
// panic quit button
if ( Input ( ) - > KeyPressed ( KEY_LCTRL ) & & Input ( ) - > KeyPressed ( KEY_LSHIFT ) & & Input ( ) - > KeyPressed ( ' q ' ) )
break ;
if ( Input ( ) - > KeyPressed ( KEY_LCTRL ) & & Input ( ) - > KeyPressed ( KEY_LSHIFT ) & & Input ( ) - > KeyDown ( ' d ' ) )
g_Config . m_Debug ^ = 1 ;
if ( Input ( ) - > KeyPressed ( KEY_LCTRL ) & & Input ( ) - > KeyPressed ( KEY_LSHIFT ) & & Input ( ) - > KeyDown ( ' g ' ) )
g_Config . m_DbgGraphs ^ = 1 ;
if ( Input ( ) - > KeyPressed ( KEY_LCTRL ) & & Input ( ) - > KeyPressed ( KEY_LSHIFT ) & & Input ( ) - > KeyDown ( ' e ' ) )
{
g_Config . m_ClEditor = g_Config . m_ClEditor ^ 1 ;
Input ( ) - > MouseModeRelative ( ) ;
}
/*
if ( ! gfx_window_open ( ) )
break ;
*/
// render
if ( g_Config . m_ClEditor )
{
2011-01-17 11:28:37 +00:00
if ( ! m_EditorActive )
{
GameClient ( ) - > OnActivateEditor ( ) ;
m_EditorActive = true ;
}
2010-05-29 07:25:38 +00:00
Update ( ) ;
m_pEditor - > UpdateAndRender ( ) ;
2011-02-18 10:25:55 +00:00
DebugRender ( ) ;
2010-05-29 07:25:38 +00:00
m_pGraphics - > Swap ( ) ;
}
else
{
2011-01-17 11:28:37 +00:00
if ( m_EditorActive )
m_EditorActive = false ;
2010-05-29 07:25:38 +00:00
Update ( ) ;
if ( g_Config . m_DbgStress )
{
if ( ( m_Frames % 10 ) = = 0 )
{
Render ( ) ;
m_pGraphics - > Swap ( ) ;
}
}
else
{
Render ( ) ;
m_pGraphics - > Swap ( ) ;
}
}
2010-12-12 15:48:13 +00:00
AutoScreenshot_Cleanup ( ) ;
2010-05-29 07:25:38 +00:00
// check conditions
if ( State ( ) = = IClient : : STATE_QUITING )
break ;
// beNice
if ( g_Config . m_DbgStress )
thread_sleep ( 5 ) ;
else if ( g_Config . m_ClCpuThrottle | | ! m_pGraphics - > WindowActive ( ) )
thread_sleep ( 1 ) ;
if ( g_Config . m_DbgHitch )
{
thread_sleep ( g_Config . m_DbgHitch ) ;
g_Config . m_DbgHitch = 0 ;
}
if ( ReportTime < time_get ( ) )
{
if ( 0 & & g_Config . m_Debug )
{
dbg_msg ( " client/report " , " fps=%.02f (%.02f %.02f) netstate=%d " ,
m_Frames / ( float ) ( ReportInterval / time_freq ( ) ) ,
1.0f / m_FrameTimeHigh ,
1.0f / m_FrameTimeLow ,
m_NetClient . State ( ) ) ;
}
m_FrameTimeLow = 1 ;
m_FrameTimeHigh = 0 ;
m_Frames = 0 ;
ReportTime + = ReportInterval ;
}
// update frametime
m_FrameTime = ( time_get ( ) - FrameStartTime ) / ( float ) time_freq ( ) ;
if ( m_FrameTime < m_FrameTimeLow )
m_FrameTimeLow = m_FrameTime ;
if ( m_FrameTime > m_FrameTimeHigh )
m_FrameTimeHigh = m_FrameTime ;
m_LocalTime = ( time_get ( ) - m_LocalStartTime ) / ( float ) time_freq ( ) ;
m_FpsGraph . Add ( 1.0f / m_FrameTime , 1 , 1 , 1 ) ;
}
GameClient ( ) - > OnShutdown ( ) ;
Disconnect ( ) ;
m_pGraphics - > Shutdown ( ) ;
m_pSound - > Shutdown ( ) ;
}
2010-08-25 20:30:21 +00:00
void CClient : : Con_Connect ( IConsole : : IResult * pResult , void * pUserData , int ClientID )
2010-05-29 07:25:38 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
str_copy ( pSelf - > m_aCmdConnect , pResult - > GetString ( 0 ) , sizeof ( pSelf - > m_aCmdConnect ) ) ;
}
2010-08-25 20:30:21 +00:00
void CClient : : Con_Disconnect ( IConsole : : IResult * pResult , void * pUserData , int ClientID )
2010-05-29 07:25:38 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
pSelf - > Disconnect ( ) ;
}
2010-08-25 20:30:21 +00:00
void CClient : : Con_Quit ( IConsole : : IResult * pResult , void * pUserData , int ClientID )
2010-05-29 07:25:38 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
pSelf - > Quit ( ) ;
}
2010-08-25 20:30:21 +00:00
void CClient : : Con_Minimize ( IConsole : : IResult * pResult , void * pUserData , int ClientID )
2010-05-29 07:25:38 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
pSelf - > Graphics ( ) - > Minimize ( ) ;
}
2010-08-25 20:30:21 +00:00
void CClient : : Con_Ping ( IConsole : : IResult * pResult , void * pUserData , int ClientID )
2010-05-29 07:25:38 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
CMsgPacker Msg ( NETMSG_PING ) ;
pSelf - > SendMsgEx ( & Msg , 0 ) ;
pSelf - > m_PingStartTime = time_get ( ) ;
}
2010-12-12 15:48:13 +00:00
void CClient : : AutoScreenshot_Start ( )
{
if ( g_Config . m_ClAutoScreenshot )
{
Graphics ( ) - > TakeScreenshot ( " auto/autoscreen " ) ;
m_AutoScreenshotRecycle = true ;
}
}
void CClient : : AutoScreenshot_Cleanup ( )
{
if ( m_AutoScreenshotRecycle )
{
if ( g_Config . m_ClAutoScreenshotMax )
{
// clean up auto taken screens
CFileCollection AutoScreens ;
AutoScreens . Init ( Storage ( ) , " screenshots/auto " , " autoscreen " , " .png " , g_Config . m_ClAutoScreenshotMax ) ;
}
m_AutoScreenshotRecycle = false ;
}
}
2010-08-25 20:30:21 +00:00
void CClient : : Con_Screenshot ( IConsole : : IResult * pResult , void * pUserData , int ClientID )
2010-05-29 07:25:38 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
2010-12-12 15:48:13 +00:00
pSelf - > Graphics ( ) - > TakeScreenshot ( 0 ) ;
2010-05-29 07:25:38 +00:00
}
2010-08-25 20:30:21 +00:00
void CClient : : Con_Rcon ( IConsole : : IResult * pResult , void * pUserData , int ClientID )
2010-05-29 07:25:38 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
pSelf - > Rcon ( pResult - > GetString ( 0 ) ) ;
}
2010-08-25 20:30:21 +00:00
void CClient : : Con_RconAuth ( IConsole : : IResult * pResult , void * pUserData , int ClientID )
2010-05-29 07:25:38 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
pSelf - > RconAuth ( " " , pResult - > GetString ( 0 ) ) ;
}
2010-08-25 20:30:21 +00:00
void CClient : : Con_AddFavorite ( IConsole : : IResult * pResult , void * pUserData , int ClientID )
2010-05-29 07:25:38 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
NETADDR Addr ;
if ( net_addr_from_str ( & Addr , pResult - > GetString ( 0 ) ) = = 0 )
pSelf - > m_ServerBrowser . AddFavorite ( Addr ) ;
}
2011-04-09 06:41:31 +00:00
void CClient : : Con_RemoveFavorite ( IConsole : : IResult * pResult , void * pUserData , int ClientID )
2011-03-27 16:05:11 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
NETADDR Addr ;
if ( net_addr_from_str ( & Addr , pResult - > GetString ( 0 ) ) = = 0 )
pSelf - > m_ServerBrowser . RemoveFavorite ( Addr ) ;
}
2010-10-06 21:07:35 +00:00
const char * CClient : : DemoPlayer_Play ( const char * pFilename , int StorageType )
2010-05-29 07:25:38 +00:00
{
int Crc ;
const char * pError ;
Disconnect ( ) ;
m_NetClient . ResetErrorString ( ) ;
// try to start playback
m_DemoPlayer . SetListner ( this ) ;
2010-10-06 21:07:35 +00:00
if ( m_DemoPlayer . Load ( Storage ( ) , m_pConsole , pFilename , StorageType ) )
2010-05-29 07:25:38 +00:00
return " error loading demo " ;
// load map
2011-03-13 09:41:10 +00:00
Crc = ( m_DemoPlayer . Info ( ) - > m_Header . m_aMapCrc [ 0 ] < < 24 ) |
( m_DemoPlayer . Info ( ) - > m_Header . m_aMapCrc [ 1 ] < < 16 ) |
( m_DemoPlayer . Info ( ) - > m_Header . m_aMapCrc [ 2 ] < < 8 ) |
( m_DemoPlayer . Info ( ) - > m_Header . m_aMapCrc [ 3 ] ) ;
pError = LoadMapSearch ( m_DemoPlayer . Info ( ) - > m_Header . m_aMapName , Crc ) ;
2010-05-29 07:25:38 +00:00
if ( pError )
{
DisconnectWithReason ( pError ) ;
return pError ;
}
GameClient ( ) - > OnConnected ( ) ;
// setup buffers
mem_zero ( m_aDemorecSnapshotData , sizeof ( m_aDemorecSnapshotData ) ) ;
m_aSnapshots [ SNAP_CURRENT ] = & m_aDemorecSnapshotHolders [ SNAP_CURRENT ] ;
m_aSnapshots [ SNAP_PREV ] = & m_aDemorecSnapshotHolders [ SNAP_PREV ] ;
m_aSnapshots [ SNAP_CURRENT ] - > m_pSnap = ( CSnapshot * ) m_aDemorecSnapshotData [ SNAP_CURRENT ] [ 0 ] ;
m_aSnapshots [ SNAP_CURRENT ] - > m_pAltSnap = ( CSnapshot * ) m_aDemorecSnapshotData [ SNAP_CURRENT ] [ 1 ] ;
m_aSnapshots [ SNAP_CURRENT ] - > m_SnapSize = 0 ;
m_aSnapshots [ SNAP_CURRENT ] - > m_Tick = - 1 ;
m_aSnapshots [ SNAP_PREV ] - > m_pSnap = ( CSnapshot * ) m_aDemorecSnapshotData [ SNAP_PREV ] [ 0 ] ;
m_aSnapshots [ SNAP_PREV ] - > m_pAltSnap = ( CSnapshot * ) m_aDemorecSnapshotData [ SNAP_PREV ] [ 1 ] ;
m_aSnapshots [ SNAP_PREV ] - > m_SnapSize = 0 ;
m_aSnapshots [ SNAP_PREV ] - > m_Tick = - 1 ;
// enter demo playback state
SetState ( IClient : : STATE_DEMOPLAYBACK ) ;
m_DemoPlayer . Play ( ) ;
GameClient ( ) - > OnEnterGame ( ) ;
return 0 ;
}
2010-08-25 20:30:21 +00:00
void CClient : : Con_Play ( IConsole : : IResult * pResult , void * pUserData , int ClientID )
2010-05-29 07:25:38 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
2010-10-06 21:07:35 +00:00
pSelf - > DemoPlayer_Play ( pResult - > GetString ( 0 ) , IStorage : : TYPE_ALL ) ;
2010-05-29 07:25:38 +00:00
}
2010-12-07 23:42:32 +00:00
void CClient : : DemoRecorder_Start ( const char * pFilename , bool WithTimestamp )
2010-05-29 07:25:38 +00:00
{
2010-08-09 12:14:15 +00:00
if ( State ( ) ! = IClient : : STATE_ONLINE )
2010-08-17 22:06:00 +00:00
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " demorec/record " , " client is not online " ) ;
2010-05-29 07:25:38 +00:00
else
{
2010-12-07 23:42:32 +00:00
char aFilename [ 128 ] ;
if ( WithTimestamp )
{
char aDate [ 20 ] ;
str_timestamp ( aDate , sizeof ( aDate ) ) ;
str_format ( aFilename , sizeof ( aFilename ) , " demos/%s_%s.demo " , pFilename , aDate ) ;
}
else
str_format ( aFilename , sizeof ( aFilename ) , " demos/%s.demo " , pFilename ) ;
2010-08-17 22:06:00 +00:00
m_DemoRecorder . Start ( Storage ( ) , m_pConsole , aFilename , GameClient ( ) - > NetVersion ( ) , m_aCurrentMap , m_CurrentMapCrc , " client " ) ;
2010-05-29 07:25:38 +00:00
}
}
2010-12-08 00:42:32 +00:00
void CClient : : DemoRecorder_HandleAutoStart ( )
{
if ( g_Config . m_ClAutoDemoRecord )
2010-12-11 17:55:28 +00:00
{
2011-01-06 22:21:51 +00:00
DemoRecorder_Stop ( ) ;
2010-12-08 00:55:13 +00:00
DemoRecorder_Start ( " auto/autorecord " , true ) ;
2010-12-11 17:55:28 +00:00
if ( g_Config . m_ClAutoDemoMax )
{
// clean up auto recorded demos
CFileCollection AutoDemos ;
AutoDemos . Init ( Storage ( ) , " demos/auto " , " autorecord " , " .demo " , g_Config . m_ClAutoDemoMax ) ;
}
}
2010-12-08 00:42:32 +00:00
}
2010-12-07 23:02:24 +00:00
void CClient : : DemoRecorder_Stop ( )
{
m_DemoRecorder . Stop ( ) ;
}
2010-08-25 20:30:21 +00:00
void CClient : : Con_Record ( IConsole : : IResult * pResult , void * pUserData , int ClientID )
2010-08-09 12:14:15 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
2010-12-07 23:42:32 +00:00
if ( pResult - > NumArguments ( ) )
pSelf - > DemoRecorder_Start ( pResult - > GetString ( 0 ) , false ) ;
else
pSelf - > DemoRecorder_Start ( " demo " , true ) ;
2010-08-09 12:14:15 +00:00
}
2010-08-25 20:30:21 +00:00
void CClient : : Con_StopRecord ( IConsole : : IResult * pResult , void * pUserData , int ClientID )
2010-05-29 07:25:38 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
2010-12-07 23:02:24 +00:00
pSelf - > DemoRecorder_Stop ( ) ;
2010-05-29 07:25:38 +00:00
}
2011-03-18 18:03:13 +00:00
void CClient : : ServerBrowserUpdate ( )
{
m_ResortServerBrowser = true ;
}
void CClient : : ConchainServerBrowserUpdate ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
2011-04-09 06:41:31 +00:00
pfnCallback ( pResult , pCallbackUserData , - 1 ) ;
2011-03-18 18:03:13 +00:00
if ( pResult - > NumArguments ( ) )
( ( CClient * ) pUserData ) - > ServerBrowserUpdate ( ) ;
}
2010-05-29 07:25:38 +00:00
void CClient : : RegisterCommands ( )
{
m_pConsole = Kernel ( ) - > RequestInterface < IConsole > ( ) ;
// register server dummy commands for tab completion
2011-03-16 14:27:30 +00:00
m_pConsole - > Register ( " kick " , " i?r " , CFGFLAG_SERVER , 0 , 0 , " Kick player with specified id for any reason " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " ban " , " s?ir " , CFGFLAG_SERVER , 0 , 0 , " Ban player with ip/id for x minutes for any reason " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " unban " , " s " , CFGFLAG_SERVER , 0 , 0 , " Unban ip " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " bans " , " " , CFGFLAG_SERVER , 0 , 0 , " Show banlist " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " status " , " " , CFGFLAG_SERVER , 0 , 0 , " List players " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " shutdown " , " " , CFGFLAG_SERVER , 0 , 0 , " Shut down " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " record " , " ?s " , CFGFLAG_SERVER , 0 , 0 , " Record to a file " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " stoprecord " , " " , CFGFLAG_SERVER , 0 , 0 , " Stop recording " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " reload " , " " , CFGFLAG_SERVER , 0 , 0 , " Reload the map " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " quit " , " " , CFGFLAG_CLIENT | CFGFLAG_STORE , Con_Quit , this , " Quit Teeworlds " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " exit " , " " , CFGFLAG_CLIENT | CFGFLAG_STORE , Con_Quit , this , " Quit Teeworlds " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " minimize " , " " , CFGFLAG_CLIENT | CFGFLAG_STORE , Con_Minimize , this , " Minimize Teeworlds " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " connect " , " s " , CFGFLAG_CLIENT , Con_Connect , this , " Connect to the specified host/ip " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " disconnect " , " " , CFGFLAG_CLIENT , Con_Disconnect , this , " Disconnect from the server " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " ping " , " " , CFGFLAG_CLIENT , Con_Ping , this , " Ping the current server " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " screenshot " , " " , CFGFLAG_CLIENT , Con_Screenshot , this , " Take a screenshot " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " rcon " , " r " , CFGFLAG_CLIENT , Con_Rcon , this , " Send specified command to rcon " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " rcon_auth " , " s " , CFGFLAG_CLIENT , Con_RconAuth , this , " Authenticate to rcon " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " play " , " r " , CFGFLAG_CLIENT , Con_Play , this , " Play the file specified " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " record " , " ?s " , CFGFLAG_CLIENT , Con_Record , this , " Record to the file " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " stoprecord " , " " , CFGFLAG_CLIENT , Con_StopRecord , this , " Stop recording " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " add_favorite " , " s " , CFGFLAG_CLIENT , Con_AddFavorite , this , " Add a server as a favorite " , IConsole : : CONSOLELEVEL_USER ) ;
2011-04-09 06:41:31 +00:00
m_pConsole - > Register ( " remove_favorite " , " s " , CFGFLAG_CLIENT , Con_RemoveFavorite , this , " Remove a server from favorites " , IConsole : : CONSOLELEVEL_USER ) ;
2011-03-18 18:03:13 +00:00
// used for server browser update
m_pConsole - > Chain ( " br_filter_string " , ConchainServerBrowserUpdate , this ) ;
m_pConsole - > Chain ( " br_filter_gametype " , ConchainServerBrowserUpdate , this ) ;
m_pConsole - > Chain ( " br_filter_serveraddress " , ConchainServerBrowserUpdate , this ) ;
2011-02-13 05:35:13 +00:00
// DDRace
2011-04-09 06:41:31 +00:00
2011-03-16 14:27:30 +00:00
m_pConsole - > Register ( " login " , " ?s " , CFGFLAG_SERVER , 0 , 0 , " Allows you access to rcon if no password is given, or changes your level if a password is given " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " auth " , " ?s " , CFGFLAG_SERVER , 0 , 0 , " Allows you access to rcon if no password is given, or changes your level if a password is given " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " vote " , " r " , CFGFLAG_SERVER , 0 , 0 , " Forces the current vote to result in r (Yes/No) " , IConsole : : CONSOLELEVEL_USER ) ;
m_pConsole - > Register ( " cmdlist " , " " , CFGFLAG_SERVER , 0 , 0 , " Shows the list of all commands " , IConsole : : CONSOLELEVEL_USER ) ;
2010-11-01 22:04:16 +00:00
2010-11-02 16:07:45 +00:00
# define CONSOLE_COMMAND(name, params, flags, callback, userdata, help, level) m_pConsole->Register(name, params, flags, 0, 0, help, level);
2010-11-04 23:59:37 +00:00
# include <game/ddracecommands.h>
2010-05-29 07:25:38 +00:00
}
2011-07-31 16:39:48 +00:00
static CClient * CreateClient ( )
{
CClient * pClient = static_cast < CClient * > ( mem_alloc ( sizeof ( CClient ) , 1 ) ) ;
mem_zero ( pClient , sizeof ( CClient ) ) ;
return new ( pClient ) CClient ;
}
2010-05-29 07:25:38 +00:00
/*
Server Time
Client Mirror Time
Client Predicted Time
Snapshot Latency
Downstream latency
Prediction Latency
Upstream latency
*/
# if defined(CONF_PLATFORM_MACOSX)
2010-06-01 19:59:04 +00:00
extern " C " int SDL_main ( int argc , const char * * argv ) // ignore_convention
2010-05-29 07:25:38 +00:00
# else
int main ( int argc , const char * * argv ) // ignore_convention
# endif
{
2010-09-06 19:55:09 +00:00
# if defined(CONF_FAMILY_WINDOWS)
for ( int i = 1 ; i < argc ; i + + ) // ignore_convention
{
if ( str_comp ( " -s " , argv [ i ] ) = = 0 | | str_comp ( " --silent " , argv [ i ] ) = = 0 ) // ignore_convention
{
2010-10-13 10:54:27 +00:00
FreeConsole ( ) ;
2010-09-06 19:55:09 +00:00
break ;
}
}
# endif
2011-07-30 11:50:22 +00:00
CClient * pClient = CreateClient ( ) ;
2010-05-29 07:25:38 +00:00
IKernel * pKernel = IKernel : : Create ( ) ;
2011-07-30 11:50:22 +00:00
pKernel - > RegisterInterface ( pClient ) ;
pClient - > RegisterInterfaces ( ) ;
2010-05-29 07:25:38 +00:00
// create the components
2011-02-27 14:03:57 +00:00
IEngine * pEngine = CreateEngine ( " Teeworlds " ) ;
2010-06-18 18:32:52 +00:00
IConsole * pConsole = CreateConsole ( CFGFLAG_CLIENT ) ;
2010-08-05 18:26:03 +00:00
IStorage * pStorage = CreateStorage ( " Teeworlds " , argc , argv ) ; // ignore_convention
2010-05-29 07:25:38 +00:00
IConfig * pConfig = CreateConfig ( ) ;
IEngineGraphics * pEngineGraphics = CreateEngineGraphics ( ) ;
IEngineSound * pEngineSound = CreateEngineSound ( ) ;
IEngineInput * pEngineInput = CreateEngineInput ( ) ;
IEngineTextRender * pEngineTextRender = CreateEngineTextRender ( ) ;
IEngineMap * pEngineMap = CreateEngineMap ( ) ;
IEngineMasterServer * pEngineMasterServer = CreateEngineMasterServer ( ) ;
{
bool RegisterFail = false ;
2011-02-27 14:03:57 +00:00
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( pEngine ) ;
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( pConsole ) ;
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( pConfig ) ;
2010-05-29 07:25:38 +00:00
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < IEngineGraphics * > ( pEngineGraphics ) ) ; // register graphics as both
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < IGraphics * > ( pEngineGraphics ) ) ;
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < IEngineSound * > ( pEngineSound ) ) ; // register as both
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < ISound * > ( pEngineSound ) ) ;
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < IEngineInput * > ( pEngineInput ) ) ; // register as both
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < IInput * > ( pEngineInput ) ) ;
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < IEngineTextRender * > ( pEngineTextRender ) ) ; // register as both
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < ITextRender * > ( pEngineTextRender ) ) ;
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < IEngineMap * > ( pEngineMap ) ) ; // register as both
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < IMap * > ( pEngineMap ) ) ;
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < IEngineMasterServer * > ( pEngineMasterServer ) ) ; // register as both
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < IMasterServer * > ( pEngineMasterServer ) ) ;
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( CreateEditor ( ) ) ;
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( CreateGameClient ( ) ) ;
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( pStorage ) ;
if ( RegisterFail )
return - 1 ;
}
2011-03-05 10:46:24 +00:00
pEngine - > Init ( ) ;
2010-05-29 07:25:38 +00:00
pConfig - > Init ( ) ;
2011-02-27 14:03:57 +00:00
pEngineMasterServer - > Init ( ) ;
2010-05-29 07:25:38 +00:00
pEngineMasterServer - > Load ( ) ;
// register all console commands
2011-07-30 11:50:22 +00:00
pClient - > RegisterCommands ( ) ;
2010-05-29 07:25:38 +00:00
pKernel - > RequestInterface < IGameClient > ( ) - > OnConsoleInit ( ) ;
// init client's interfaces
2011-07-30 11:50:22 +00:00
pClient - > InitInterfaces ( ) ;
2010-05-29 07:25:38 +00:00
2010-08-06 18:47:45 +00:00
// execute config file
2011-04-12 20:18:15 +00:00
pConsole - > ExecuteFile ( " settings.cfg " , - 1 , IConsole : : CONSOLELEVEL_CONFIG , 0 , 0 ) ;
2010-08-06 18:47:45 +00:00
2010-05-29 07:25:38 +00:00
// execute autoexec file
2011-04-12 20:18:15 +00:00
pConsole - > ExecuteFile ( " autoexec.cfg " , - 1 , IConsole : : CONSOLELEVEL_CONFIG , 0 , 0 ) ;
2010-05-29 07:25:38 +00:00
// parse the command line arguments
if ( argc > 1 ) // ignore_convention
pConsole - > ParseArguments ( argc - 1 , & argv [ 1 ] ) ; // ignore_convention
2010-08-10 22:31:42 +00:00
// restore empty config strings to their defaults
pConfig - > RestoreStrings ( ) ;
2011-07-30 11:50:22 +00:00
pClient - > Engine ( ) - > InitLogfile ( ) ;
2010-08-06 18:38:13 +00:00
2010-05-29 07:25:38 +00:00
// run the client
2011-02-27 14:03:57 +00:00
dbg_msg ( " client " , " starting... " ) ;
2011-07-30 11:50:22 +00:00
pClient - > Run ( ) ;
2010-05-29 07:25:38 +00:00
// write down the config and quit
pConfig - > Save ( ) ;
return 0 ;
}
2011-02-04 17:25:04 +00:00
2011-04-09 06:41:31 +00:00
// DDRace
2011-02-04 17:25:04 +00:00
const char * CClient : : GetCurrentMap ( )
{
return m_aCurrentMap ;
}
int CClient : : GetCurrentMapCrc ( )
{
return m_CurrentMapCrc ;
}
const char * CClient : : RaceRecordStart ( const char * pFilename )
{
char aFilename [ 128 ] ;
str_format ( aFilename , sizeof ( aFilename ) , " demos/%s_%s.demo " , m_aCurrentMap , pFilename ) ;
2011-04-09 06:41:31 +00:00
2011-02-04 17:25:04 +00:00
if ( State ( ) ! = STATE_ONLINE )
dbg_msg ( " demorec/record " , " client is not online " ) ;
else
m_DemoRecorder . Start ( Storage ( ) , m_pConsole , aFilename , GameClient ( ) - > NetVersion ( ) , m_aCurrentMap , m_CurrentMapCrc , " client " ) ;
2011-04-09 06:41:31 +00:00
2011-02-04 17:25:04 +00:00
return m_aCurrentMap ;
}
void CClient : : RaceRecordStop ( )
{
if ( m_DemoRecorder . IsRecording ( ) )
m_DemoRecorder . Stop ( ) ;
}
bool CClient : : DemoIsRecording ( )
{
return m_DemoRecorder . IsRecording ( ) ;
}