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
2014-08-13 11:00:18 +00:00
# include <time.h>
2010-05-29 07:25:38 +00:00
# include <stdlib.h> // qsort
# include <stdarg.h>
2014-01-14 20:40:55 +00:00
# include <string.h>
2014-04-28 18:43:08 +00:00
# include <climits>
2010-05-29 07:25:38 +00:00
2010-12-11 17:55:28 +00:00
# include <base/math.h>
2013-07-11 15:13:45 +00:00
# include <base/vmath.h>
2010-05-29 07:25:38 +00:00
# include <base/system.h>
2014-06-05 10:11:41 +00:00
# include <game/client/components/menus.h>
2013-07-11 15:13:45 +00:00
# include <game/client/gameclient.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>
2014-08-29 14:52:08 +00:00
# include <engine/shared/fifoconsole.h>
2010-05-29 07:25:38 +00:00
2012-01-09 01:02:02 +00:00
# include <game/version.h>
2010-05-29 07:25:38 +00:00
# include <mastersrv/mastersrv.h>
# include <versionsrv/versionsrv.h>
2014-01-08 05:15:56 +00:00
# include <engine/client/serverbrowser.h>
2014-10-29 12:37:38 +00:00
# if defined(CONF_FAMILY_WINDOWS)
# define _WIN32_WINNT 0x0501
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
# endif
2011-03-23 12:06:35 +00:00
# include "friends.h"
2011-03-27 16:00:54 +00:00
# include "serverbrowser.h"
2014-10-29 12:37:38 +00:00
# include "fetcher.h"
2014-12-31 14:29:34 +00:00
# include "autoupdate.h"
2010-05-29 07:25:38 +00:00
# include "client.h"
2014-09-20 09:36:46 +00:00
# include <zlib.h>
2012-01-03 21:01:37 +00:00
# include "SDL.h"
# ifdef main
# undef main
# 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 ) ;
2012-10-14 12:04:48 +00:00
pGraphics - > QuadsBegin ( ) ;
pGraphics - > QuadsText ( x + 2 , y + h - 16 , 16 , pDescription ) ;
2010-05-29 07:25:38 +00:00
char aBuf [ 32 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " %.2f " , m_Max ) ;
2012-10-14 12:04:48 +00:00
pGraphics - > QuadsText ( x + w - 8 * str_length ( aBuf ) - 8 , y + 2 , 16 , aBuf ) ;
2010-05-29 07:25:38 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %.2f " , m_Min ) ;
2012-10-14 12:04:48 +00:00
pGraphics - > QuadsText ( x + w - 8 * str_length ( aBuf ) - 8 , y + h - 16 , 16 , aBuf ) ;
pGraphics - > QuadsEnd ( ) ;
2010-05-29 07:25:38 +00:00
}
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 ) ;
}
2014-10-16 15:42:13 +00:00
CClient : : CClient ( ) : m_DemoPlayer ( & m_SnapshotDelta )
2010-05-29 07:25:38 +00:00
{
2014-10-16 15:42:13 +00:00
m_DemoRecorder [ 0 ] = CDemoRecorder ( & m_SnapshotDelta ) ;
m_DemoRecorder [ 1 ] = CDemoRecorder ( & m_SnapshotDelta ) ;
m_DemoRecorder [ 2 ] = CDemoRecorder ( & m_SnapshotDelta ) ;
2010-05-29 07:25:38 +00:00
m_pEditor = 0 ;
m_pInput = 0 ;
m_pGraphics = 0 ;
m_pSound = 0 ;
m_pGameClient = 0 ;
m_pMap = 0 ;
m_pConsole = 0 ;
2012-01-01 12:38:46 +00:00
m_RenderFrameTime = 0.0001f ;
m_RenderFrameTimeLow = 1.0f ;
m_RenderFrameTimeHigh = 0.0f ;
m_RenderFrames = 0 ;
m_LastRenderTime = time_get ( ) ;
2010-05-29 07:25:38 +00:00
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
2014-04-28 15:26:31 +00:00
m_AckGameTick [ 0 ] = - 1 ;
m_AckGameTick [ 1 ] = - 1 ;
m_CurrentRecvTick [ 0 ] = 0 ;
m_CurrentRecvTick [ 1 ] = 0 ;
2014-04-27 11:44:04 +00:00
m_RconAuthed [ 0 ] = 0 ;
m_RconAuthed [ 1 ] = 0 ;
2014-08-22 11:54:13 +00:00
m_RconPassword [ 0 ] = ' \0 ' ;
2010-05-29 07:25:38 +00:00
// 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 ;
2015-01-28 12:13:56 +00:00
m_pMapdownloadTask = 0 ;
2010-05-29 07:25:38 +00:00
m_MapdownloadFile = 0 ;
m_MapdownloadChunk = 0 ;
m_MapdownloadCrc = 0 ;
m_MapdownloadAmount = - 1 ;
m_MapdownloadTotalsize = - 1 ;
m_CurrentServerInfoRequestTime = - 1 ;
2014-10-12 15:52:53 +00:00
m_CurrentInput [ 0 ] = 0 ;
m_CurrentInput [ 1 ] = 0 ;
2014-04-28 18:43:08 +00:00
m_LastDummy = 0 ;
2014-05-03 21:28:48 +00:00
m_LastDummy2 = 0 ;
2014-05-08 12:58:42 +00:00
m_LocalIDs [ 0 ] = 0 ;
m_LocalIDs [ 1 ] = 0 ;
2014-05-07 13:24:53 +00:00
m_Fire = 0 ;
2014-07-16 12:45:53 +00:00
mem_zero ( & m_aInputs , sizeof ( m_aInputs ) ) ;
mem_zero ( & DummyInput , sizeof ( DummyInput ) ) ;
2014-05-07 13:24:53 +00:00
mem_zero ( & HammerInput , sizeof ( HammerInput ) ) ;
HammerInput . m_Fire = 0 ;
2010-05-29 07:25:38 +00:00
m_State = IClient : : STATE_OFFLINE ;
m_aServerAddressStr [ 0 ] = 0 ;
mem_zero ( m_aSnapshots , sizeof ( m_aSnapshots ) ) ;
2014-05-03 18:24:45 +00:00
m_SnapshotStorage [ 0 ] . Init ( ) ;
m_SnapshotStorage [ 1 ] . Init ( ) ;
m_RecivedSnapshots [ 0 ] = 0 ;
m_RecivedSnapshots [ 1 ] = 0 ;
2010-05-29 07:25:38 +00:00
2011-03-17 16:41:57 +00:00
m_VersionInfo . m_State = CVersionInfo : : STATE_INIT ;
2014-05-17 17:06:33 +00:00
2014-07-25 00:41:36 +00:00
if ( g_Config . m_ClDummy = = 0 )
m_LastDummyConnectTime = 0 ;
2014-09-20 09:36:46 +00:00
m_DDNetSrvListTokenSet = false ;
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 )
{
2014-10-16 15:42:13 +00:00
for ( int i = 0 ; i < RECORDER_MAX ; i + + )
if ( m_DemoRecorder [ i ] . IsRecording ( ) )
m_DemoRecorder [ i ] . RecordMessage ( Packet . m_pData , Packet . m_DataSize ) ;
2010-05-29 07:25:38 +00:00
}
if ( ! ( Flags & MSGFLAG_NOSEND ) )
2014-04-26 18:29:42 +00:00
{
m_NetClient [ g_Config . m_ClDummy ] . Send ( & Packet ) ;
}
2010-05-29 07:25:38 +00:00
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 ) ;
}
2014-10-29 12:37:38 +00:00
void CClient : : SendMapRequest ( )
{
if ( m_MapdownloadFile )
io_close ( m_MapdownloadFile ) ;
m_MapdownloadFile = Storage ( ) - > OpenFile ( m_aMapdownloadFilename , IOFLAG_WRITE , IStorage : : TYPE_SAVE ) ;
CMsgPacker Msg ( NETMSG_REQUEST_MAP_DATA ) ;
Msg . AddInt ( m_MapdownloadChunk ) ;
SendMsgEx ( & Msg , MSGFLAG_VITAL | MSGFLAG_FLUSH ) ;
}
2010-05-29 07:25:38 +00:00
void CClient : : RconAuth ( const char * pName , const char * pPassword )
{
2014-04-27 11:44:04 +00:00
if ( RconAuthed ( ) )
return ;
2011-04-13 18:37:12 +00:00
2014-08-22 11:54:13 +00:00
str_copy ( m_RconPassword , pPassword , sizeof ( m_RconPassword ) ) ;
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 )
{
2014-08-26 20:10:22 +00:00
CServerInfo Info ;
GetServerInfo ( & Info ) ;
2014-12-10 02:39:15 +00:00
if ( RconAuthed ( ) & & IsDDNet ( & Info ) )
2014-08-22 11:54:13 +00:00
{ // Against IP spoofing on DDNet servers
CMsgPacker Msg ( NETMSG_RCON_AUTH ) ;
Msg . AddString ( " " , 32 ) ;
Msg . AddString ( m_RconPassword , 32 ) ;
Msg . AddInt ( 1 ) ;
SendMsgEx ( & Msg , MSGFLAG_VITAL ) ;
}
2010-05-29 07:25:38 +00:00
CMsgPacker Msg ( NETMSG_RCON_CMD ) ;
Msg . AddString ( pCmd , 256 ) ;
SendMsgEx ( & Msg , MSGFLAG_VITAL ) ;
}
bool CClient : : ConnectionProblems ( )
{
2014-04-26 18:29:42 +00:00
return m_NetClient [ g_Config . m_ClDummy ] . GotProblems ( ) ! = 0 ;
2010-05-29 07:25:38 +00:00
}
void CClient : : DirectInput ( int * pInput , int Size )
{
int i ;
CMsgPacker Msg ( NETMSG_INPUT ) ;
2014-04-28 15:26:31 +00:00
Msg . AddInt ( m_AckGameTick [ g_Config . m_ClDummy ] ) ;
Msg . AddInt ( m_PredTick [ g_Config . m_ClDummy ] ) ;
2010-05-29 07:25:38 +00:00
Msg . AddInt ( Size ) ;
for ( i = 0 ; i < Size / 4 ; i + + )
Msg . AddInt ( pInput [ i ] ) ;
SendMsgEx ( & Msg , 0 ) ;
}
void CClient : : SendInput ( )
{
int64 Now = time_get ( ) ;
2014-04-28 15:26:31 +00:00
if ( m_PredTick [ g_Config . m_ClDummy ] < = 0 )
2010-05-29 07:25:38 +00:00
return ;
// fetch input
2014-10-12 15:52:53 +00:00
int Size = GameClient ( ) - > OnSnapInput ( m_aInputs [ g_Config . m_ClDummy ] [ m_CurrentInput [ g_Config . m_ClDummy ] ] . m_aData ) ;
2010-05-29 07:25:38 +00:00
2014-04-28 20:12:50 +00:00
if ( Size )
2014-04-28 15:26:31 +00:00
{
2014-04-28 18:43:08 +00:00
// pack input
CMsgPacker Msg ( NETMSG_INPUT ) ;
2014-04-28 20:12:50 +00:00
Msg . AddInt ( m_AckGameTick [ g_Config . m_ClDummy ] ) ;
Msg . AddInt ( m_PredTick [ g_Config . m_ClDummy ] ) ;
Msg . AddInt ( Size ) ;
2014-10-12 15:52:53 +00:00
m_aInputs [ g_Config . m_ClDummy ] [ m_CurrentInput [ g_Config . m_ClDummy ] ] . m_Tick = m_PredTick [ g_Config . m_ClDummy ] ;
m_aInputs [ g_Config . m_ClDummy ] [ m_CurrentInput [ g_Config . m_ClDummy ] ] . m_PredictedTime = m_PredictedTime . Get ( Now ) ;
m_aInputs [ g_Config . m_ClDummy ] [ m_CurrentInput [ g_Config . m_ClDummy ] ] . m_Time = Now ;
2014-04-28 18:43:08 +00:00
// pack it
2014-04-28 20:12:50 +00:00
for ( int i = 0 ; i < Size / 4 ; i + + )
2014-10-12 15:52:53 +00:00
Msg . AddInt ( m_aInputs [ g_Config . m_ClDummy ] [ m_CurrentInput [ g_Config . m_ClDummy ] ] . m_aData [ i ] ) ;
2014-04-28 18:43:08 +00:00
2014-10-12 15:52:53 +00:00
m_CurrentInput [ g_Config . m_ClDummy ] + + ;
m_CurrentInput [ g_Config . m_ClDummy ] % = 200 ;
2014-04-28 20:12:50 +00:00
SendMsgEx ( & Msg , MSGFLAG_FLUSH ) ;
2014-05-10 18:23:26 +00:00
}
2014-04-28 20:12:50 +00:00
2014-07-07 13:42:46 +00:00
if ( m_LastDummy ! = ( bool ) g_Config . m_ClDummy )
2014-05-10 18:23:26 +00:00
{
2014-10-12 15:52:53 +00:00
mem_copy ( & DummyInput , & m_aInputs [ ! g_Config . m_ClDummy ] [ ( m_CurrentInput [ ! g_Config . m_ClDummy ] + 200 - 1 ) % 200 ] , sizeof ( DummyInput ) ) ;
2014-05-10 18:23:26 +00:00
m_LastDummy = g_Config . m_ClDummy ;
2014-07-07 23:41:45 +00:00
if ( g_Config . m_ClDummyResetOnSwitch )
{
DummyInput . m_Jump = 0 ;
DummyInput . m_Hook = 0 ;
if ( DummyInput . m_Fire & 1 )
DummyInput . m_Fire + + ;
DummyInput . m_Direction = 0 ;
GameClient ( ) - > ResetDummyInput ( ) ;
}
2014-04-28 18:43:08 +00:00
}
2014-04-30 15:51:34 +00:00
if ( ! g_Config . m_ClDummy )
m_LocalIDs [ 0 ] = ( ( CGameClient * ) GameClient ( ) ) - > m_Snap . m_LocalClientID ;
else
m_LocalIDs [ 1 ] = ( ( CGameClient * ) GameClient ( ) ) - > m_Snap . m_LocalClientID ;
2014-04-28 20:12:50 +00:00
if ( m_DummyConnected )
2014-04-28 18:43:08 +00:00
{
2014-04-28 20:12:50 +00:00
if ( ! g_Config . m_ClDummyHammer )
{
2014-05-07 13:24:53 +00:00
if ( m_Fire ! = 0 )
2014-04-30 15:51:34 +00:00
{
DummyInput . m_Fire = HammerInput . m_Fire ;
2014-05-07 13:24:53 +00:00
m_Fire = 0 ;
2014-04-30 15:51:34 +00:00
}
2014-04-30 13:21:23 +00:00
if ( ! Size & & ( ! DummyInput . m_Direction & & ! DummyInput . m_Jump & & ! DummyInput . m_Hook ) )
return ;
2014-04-28 20:12:50 +00:00
// pack input
CMsgPacker Msg ( NETMSG_INPUT ) ;
2014-05-04 21:29:29 +00:00
Msg . AddInt ( m_AckGameTick [ ! g_Config . m_ClDummy ] ) ;
Msg . AddInt ( m_PredTick [ ! g_Config . m_ClDummy ] ) ;
2014-04-28 20:12:50 +00:00
Msg . AddInt ( sizeof ( DummyInput ) ) ;
2014-04-28 15:26:31 +00:00
2014-04-28 20:12:50 +00:00
// pack it
for ( unsigned int i = 0 ; i < sizeof ( DummyInput ) / 4 ; i + + )
Msg . AddInt ( ( ( int * ) & DummyInput ) [ i ] ) ;
2014-04-28 15:26:31 +00:00
2014-04-28 20:12:50 +00:00
SendMsgExY ( & Msg , MSGFLAG_FLUSH , true , ! g_Config . m_ClDummy ) ;
}
else
{
2014-04-30 13:15:27 +00:00
if ( ( ( ( float ) m_Fire / 12.5 ) - ( int ( ( float ) m_Fire / 12.5 ) ) ) > 0.01 )
{
m_Fire + + ;
return ;
}
m_Fire + + ;
2014-05-07 13:24:53 +00:00
HammerInput . m_Fire + = 2 ;
2014-04-30 15:51:34 +00:00
HammerInput . m_WantedWeapon = 1 ;
2014-04-28 20:12:50 +00:00
2014-05-04 13:25:45 +00:00
vec2 Main = ( ( CGameClient * ) GameClient ( ) ) - > m_LocalCharacterPos ;
vec2 Dummy = ( ( CGameClient * ) GameClient ( ) ) - > m_aClients [ m_LocalIDs [ ! g_Config . m_ClDummy ] ] . m_Predicted . m_Pos ;
vec2 Dir = Main - Dummy ;
2014-04-30 15:51:34 +00:00
HammerInput . m_TargetX = Dir . x ;
HammerInput . m_TargetY = Dir . y ;
2014-04-28 20:12:50 +00:00
// pack input
CMsgPacker Msg ( NETMSG_INPUT ) ;
2014-05-04 21:29:29 +00:00
Msg . AddInt ( m_AckGameTick [ ! g_Config . m_ClDummy ] ) ;
Msg . AddInt ( m_PredTick [ ! g_Config . m_ClDummy ] ) ;
2014-04-30 15:51:34 +00:00
Msg . AddInt ( sizeof ( HammerInput ) ) ;
2014-04-28 20:12:50 +00:00
// pack it
2014-04-30 15:51:34 +00:00
for ( unsigned int i = 0 ; i < sizeof ( HammerInput ) / 4 ; i + + )
Msg . AddInt ( ( ( int * ) & HammerInput ) [ i ] ) ;
2014-04-28 20:12:50 +00:00
SendMsgExY ( & Msg , MSGFLAG_FLUSH , true , ! g_Config . m_ClDummy ) ;
}
}
2010-05-29 07:25:38 +00:00
}
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 + + )
{
2014-10-12 15:52:53 +00:00
if ( m_aInputs [ g_Config . m_ClDummy ] [ i ] . m_Tick < = Tick & & ( Best = = - 1 | | m_aInputs [ g_Config . m_ClDummy ] [ Best ] . m_Tick < m_aInputs [ g_Config . m_ClDummy ] [ i ] . m_Tick ) )
2010-05-29 07:25:38 +00:00
Best = i ;
}
if ( Best ! = - 1 )
2014-10-12 15:52:53 +00:00
return ( int * ) m_aInputs [ g_Config . m_ClDummy ] [ Best ] . m_aData ;
2010-05-29 07:25:38 +00:00
return 0 ;
}
2014-12-01 00:31:58 +00:00
bool CClient : : InputExists ( int Tick )
{
for ( int i = 0 ; i < 200 ; i + + )
if ( m_aInputs [ g_Config . m_ClDummy ] [ i ] . m_Tick = = Tick )
return true ;
return false ;
}
2010-05-29 07:25:38 +00:00
// ------ state handling -----
void CClient : : SetState ( int s )
{
2012-01-06 19:03:57 +00:00
if ( m_State = = IClient : : STATE_QUITING )
return ;
2010-05-29 07:25:38 +00:00
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 + + )
2014-10-12 15:52:53 +00:00
{
m_aInputs [ 0 ] [ i ] . m_Tick = - 1 ;
m_aInputs [ 1 ] [ i ] . m_Tick = - 1 ;
}
m_CurrentInput [ 0 ] = 0 ;
m_CurrentInput [ 1 ] = 0 ;
2010-05-29 07:25:38 +00:00
// reset snapshots
2014-05-03 18:24:45 +00:00
m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] = 0 ;
m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_PREV ] = 0 ;
m_SnapshotStorage [ g_Config . m_ClDummy ] . PurgeAll ( ) ;
m_RecivedSnapshots [ g_Config . m_ClDummy ] = 0 ;
2010-05-29 07:25:38 +00:00
m_SnapshotParts = 0 ;
2014-05-03 18:24:45 +00:00
m_PredTick [ g_Config . m_ClDummy ] = 0 ;
m_CurrentRecvTick [ g_Config . m_ClDummy ] = 0 ;
m_CurGameTick [ g_Config . m_ClDummy ] = 0 ;
m_PrevGameTick [ g_Config . m_ClDummy ] = 0 ;
2014-05-17 17:06:33 +00:00
2014-07-25 00:41:36 +00:00
if ( g_Config . m_ClDummy = = 0 )
m_LastDummyConnectTime = 0 ;
2014-09-03 12:17:44 +00:00
GameClient ( ) - > OnEnterGame ( ) ;
2010-05-29 07:25:38 +00:00
}
void CClient : : EnterGame ( )
{
if ( State ( ) = = IClient : : STATE_DEMOPLAYBACK )
return ;
// now we will wait for two snapshots
// to finish the connection
SendEnterGame ( ) ;
OnEnterGame ( ) ;
2014-08-17 17:10:08 +00:00
ServerInfoRequest ( ) ; // fresh one for timeout protection
2014-08-17 17:19:40 +00:00
m_TimeoutCodeSent [ 0 ] = false ;
m_TimeoutCodeSent [ 1 ] = false ;
2010-05-29 07:25:38 +00:00
}
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 ( ) ;
2014-04-26 19:10:39 +00:00
if ( net_host_lookup ( m_aServerAddressStr , & m_ServerAddress , m_NetClient [ 0 ] . NetType ( ) ) ! = 0 )
2010-07-02 11:15:35 +00:00
{
2014-04-26 19:10:39 +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 ) ;
net_host_lookup ( " localhost " , & m_ServerAddress , m_NetClient [ 0 ] . NetType ( ) ) ;
2010-07-02 11:15:35 +00:00
}
2010-05-29 07:25:38 +00:00
2014-04-27 11:44:04 +00:00
m_RconAuthed [ 0 ] = 0 ;
2011-03-28 18:11:28 +00:00
if ( m_ServerAddress . port = = 0 )
m_ServerAddress . port = Port ;
2014-04-26 18:29:42 +00:00
m_NetClient [ 0 ] . Connect ( & m_ServerAddress ) ;
2010-05-29 07:25:38 +00:00
SetState ( IClient : : STATE_CONNECTING ) ;
2014-10-16 15:42:13 +00:00
for ( int i = 0 ; i < RECORDER_MAX ; i + + )
if ( m_DemoRecorder [ i ] . IsRecording ( ) )
DemoRecorder_Stop ( i ) ;
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 ( ) ;
2014-10-16 15:42:13 +00:00
for ( int i = 0 ; i < RECORDER_MAX ; i + + )
DemoRecorder_Stop ( i ) ;
2010-05-29 07:25:38 +00:00
//
2014-04-27 11:44:04 +00:00
m_RconAuthed [ 0 ] = 0 ;
2011-12-30 18:21:00 +00:00
m_UseTempRconCommands = 0 ;
2011-07-14 20:07:21 +00:00
m_pConsole - > DeregisterTempAll ( ) ;
2014-04-26 18:29:42 +00:00
m_NetClient [ 0 ] . Disconnect ( pReason ) ;
2010-05-29 07:25:38 +00:00
SetState ( IClient : : STATE_OFFLINE ) ;
m_pMap - > Unload ( ) ;
// disable all downloads
m_MapdownloadChunk = 0 ;
2015-01-28 12:13:56 +00:00
if ( m_pMapdownloadTask )
m_pMapdownloadTask - > Abort ( ) ;
2010-05-29 07:25:38 +00:00
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
2014-05-03 18:24:45 +00:00
m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] = 0 ;
m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_PREV ] = 0 ;
m_RecivedSnapshots [ g_Config . m_ClDummy ] = 0 ;
2010-05-29 07:25:38 +00:00
}
void CClient : : Disconnect ( )
{
2014-04-26 18:29:42 +00:00
if ( m_DummyConnected )
DummyDisconnect ( 0 ) ;
2010-05-29 07:25:38 +00:00
DisconnectWithReason ( 0 ) ;
}
2014-04-26 18:29:42 +00:00
bool CClient : : DummyConnected ( )
{
return m_DummyConnected ;
}
2014-04-28 13:19:57 +00:00
void CClient : : DummyConnect ( )
2014-04-26 18:29:42 +00:00
{
2014-07-25 00:41:36 +00:00
if ( m_LastDummyConnectTime > 0 & & m_LastDummyConnectTime + GameTickSpeed ( ) * 5 > GameTick ( ) )
2014-04-26 18:29:42 +00:00
return ;
2014-09-03 11:58:06 +00:00
if ( m_NetClient [ 0 ] . State ( ) ! = NET_CONNSTATE_ONLINE & & m_NetClient [ 0 ] . State ( ) ! = NET_CONNSTATE_PENDING )
2014-05-10 18:40:54 +00:00
return ;
2014-05-24 19:34:06 +00:00
if ( m_DummyConnected )
return ;
2014-04-26 18:29:42 +00:00
2014-07-25 00:41:36 +00:00
m_LastDummyConnectTime = GameTick ( ) ;
2014-04-27 11:44:04 +00:00
m_RconAuthed [ 1 ] = 0 ;
2014-04-26 18:29:42 +00:00
//connecting to the server
2014-04-28 13:19:57 +00:00
m_NetClient [ 1 ] . Connect ( & m_ServerAddress ) ;
2014-04-26 18:29:42 +00:00
// send client info
CMsgPacker MsgInfo ( NETMSG_INFO ) ;
MsgInfo . AddString ( GameClient ( ) - > NetVersion ( ) , 128 ) ;
MsgInfo . AddString ( g_Config . m_Password , 128 ) ;
2014-04-28 13:19:57 +00:00
SendMsgExY ( & MsgInfo , MSGFLAG_VITAL | MSGFLAG_FLUSH , true , 1 ) ;
2014-04-26 18:29:42 +00:00
// update netclient
2014-04-28 13:19:57 +00:00
m_NetClient [ 1 ] . Update ( ) ;
2014-04-26 18:29:42 +00:00
// send ready
CMsgPacker MsgReady ( NETMSG_READY ) ;
2014-04-28 13:19:57 +00:00
SendMsgExY ( & MsgReady , MSGFLAG_VITAL | MSGFLAG_FLUSH , true , 1 ) ;
2014-04-26 18:29:42 +00:00
// startinfo
2014-04-28 13:19:57 +00:00
GameClient ( ) - > SendDummyInfo ( true ) ;
2014-04-26 18:29:42 +00:00
// send enter game an finish the connection
CMsgPacker MsgEnter ( NETMSG_ENTERGAME ) ;
2014-04-28 13:19:57 +00:00
SendMsgExY ( & MsgEnter , MSGFLAG_VITAL | MSGFLAG_FLUSH , true , 1 ) ;
2014-04-26 18:29:42 +00:00
}
void CClient : : DummyDisconnect ( const char * pReason )
{
2014-05-24 19:34:06 +00:00
if ( ! m_DummyConnected )
return ;
2014-04-26 18:29:42 +00:00
m_NetClient [ 1 ] . Disconnect ( pReason ) ;
g_Config . m_ClDummy = 0 ;
2014-04-27 11:44:04 +00:00
m_RconAuthed [ 1 ] = 0 ;
2014-05-13 18:26:59 +00:00
m_DummyConnected = false ;
2014-04-28 14:47:44 +00:00
GameClient ( ) - > OnDummyDisconnect ( ) ;
2014-04-26 18:29:42 +00:00
}
int CClient : : SendMsgExY ( CMsgPacker * pMsg , int Flags , bool System , int NetClient )
{
CNetChunk Packet ;
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 ;
m_NetClient [ NetClient ] . Send ( & Packet ) ;
return 0 ;
}
void CClient : : DummyInfo ( )
{
CNetMsg_Cl_ChangeInfo Msg ;
Msg . m_pName = g_Config . m_DummyName ;
Msg . m_pClan = g_Config . m_DummyClan ;
2014-04-28 13:19:57 +00:00
Msg . m_Country = g_Config . m_DummyCountry ;
2014-04-26 18:29:42 +00:00
Msg . m_pSkin = g_Config . m_DummySkin ;
Msg . m_UseCustomColor = g_Config . m_DummyUseCustomColor ;
Msg . m_ColorBody = g_Config . m_DummyColorBody ;
Msg . m_ColorFeet = g_Config . m_DummyColorFeet ;
CMsgPacker Packer ( Msg . MsgID ( ) ) ;
Msg . Pack ( & Packer ) ;
SendMsgExY ( & Packer , MSGFLAG_VITAL ) ;
}
2010-05-29 07:25:38 +00:00
void CClient : : GetServerInfo ( CServerInfo * pServerInfo )
{
mem_copy ( pServerInfo , & m_CurrentServerInfo , sizeof ( m_CurrentServerInfo ) ) ;
2014-11-25 19:46:21 +00:00
if ( m_DemoPlayer . IsPlaying ( ) & & g_Config . m_ClDemoAssumeRace )
str_copy ( pServerInfo - > m_aGameType , " DDraceNetwork " , 14 ) ;
2010-05-29 07:25:38 +00:00
}
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 " ) ;
2014-05-03 18:24:45 +00:00
i = m_aSnapshots [ g_Config . m_ClDummy ] [ SnapID ] - > m_pAltSnap - > GetItem ( Index ) ;
pItem - > m_DataSize = m_aSnapshots [ g_Config . m_ClDummy ] [ 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 " ) ;
2014-05-03 18:24:45 +00:00
i = m_aSnapshots [ g_Config . m_ClDummy ] [ SnapID ] - > m_pAltSnap - > GetItem ( Index ) ;
2010-05-29 07:25:38 +00:00
if ( i )
{
2014-05-03 18:24:45 +00:00
if ( ( char * ) i < ( char * ) m_aSnapshots [ g_Config . m_ClDummy ] [ SnapID ] - > m_pAltSnap | | ( char * ) i > ( char * ) m_aSnapshots [ g_Config . m_ClDummy ] [ SnapID ] - > m_pAltSnap + m_aSnapshots [ g_Config . m_ClDummy ] [ SnapID ] - > m_SnapSize )
2010-08-17 22:06:00 +00:00
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " client " , " snap invalidate problem " ) ;
2014-05-03 18:24:45 +00:00
if ( ( char * ) i > = ( char * ) m_aSnapshots [ g_Config . m_ClDummy ] [ SnapID ] - > m_pSnap & & ( char * ) i < ( char * ) m_aSnapshots [ g_Config . m_ClDummy ] [ SnapID ] - > m_pSnap + m_aSnapshots [ g_Config . m_ClDummy ] [ 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 ;
2014-05-03 18:24:45 +00:00
if ( ! m_aSnapshots [ g_Config . m_ClDummy ] [ SnapID ] )
2010-05-29 07:25:38 +00:00
return 0x0 ;
2014-05-03 18:24:45 +00:00
for ( i = 0 ; i < m_aSnapshots [ g_Config . m_ClDummy ] [ SnapID ] - > m_pSnap - > NumItems ( ) ; i + + )
2010-05-29 07:25:38 +00:00
{
2014-05-03 18:24:45 +00:00
CSnapshotItem * pItem = m_aSnapshots [ g_Config . m_ClDummy ] [ SnapID ] - > m_pAltSnap - > GetItem ( i ) ;
2011-02-12 10:40:36 +00:00
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 " ) ;
2014-05-03 18:24:45 +00:00
if ( ! m_aSnapshots [ g_Config . m_ClDummy ] [ SnapID ] )
2010-05-29 07:25:38 +00:00
return 0 ;
2014-05-03 18:24:45 +00:00
return m_aSnapshots [ g_Config . m_ClDummy ] [ 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 ( ) ) ;
2012-10-14 12:04:48 +00:00
Graphics ( ) - > QuadsBegin ( ) ;
2010-05-29 07:25:38 +00:00
if ( time_get ( ) - LastSnap > time_freq ( ) )
{
LastSnap = time_get ( ) ;
Prev = Current ;
net_stats ( & Current ) ;
}
/*
eth = 14
ip = 20
udp = 8
total = 42
*/
2012-01-01 12:38:46 +00:00
FrameTimeAvg = FrameTimeAvg * 0.9f + m_RenderFrameTime * 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 " ,
2014-04-28 15:26:31 +00:00
m_CurGameTick [ g_Config . m_ClDummy ] , m_PredTick [ g_Config . m_ClDummy ] ,
2010-05-29 07:25:38 +00:00
mem_stats ( ) - > allocated / 1024 ,
mem_stats ( ) - > total_allocations ,
Graphics ( ) - > MemoryUsage ( ) / 1024 ,
2012-01-01 12:38:46 +00:00
( int ) ( 1.0f / FrameTimeAvg + 0.5f ) ) ;
2012-10-14 12:04:48 +00:00
Graphics ( ) - > QuadsText ( 2 , 2 , 16 , aBuffer ) ;
2010-05-29 07:25:38 +00:00
{
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 ) ;
2012-10-14 12:04:48 +00:00
Graphics ( ) - > QuadsText ( 2 , 14 , 16 , aBuffer ) ;
2010-05-29 07:25:38 +00:00
}
// 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 ) ;
2012-10-14 12:04:48 +00:00
Graphics ( ) - > QuadsText ( 2 , 100 + y * 12 , 16 , aBuffer ) ;
2010-05-29 07:25:38 +00:00
y + + ;
}
}
}
str_format ( aBuffer , sizeof ( aBuffer ) , " pred: %d ms " ,
2014-05-03 21:28:48 +00:00
( int ) ( ( m_PredictedTime . Get ( Now ) - m_GameTime [ g_Config . m_ClDummy ] . Get ( Now ) ) * 1000 / ( float ) time_freq ( ) ) ) ;
2012-10-14 12:04:48 +00:00
Graphics ( ) - > QuadsText ( 2 , 70 , 16 , aBuffer ) ;
Graphics ( ) - > QuadsEnd ( ) ;
2010-05-29 07:25:38 +00:00
// 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 " ) ;
}
}
2014-12-31 14:35:49 +00:00
void CClient : : Restart ( )
{
char aBuf [ 512 ] ;
2015-03-13 14:13:19 +00:00
Storage ( ) - > GetCompletePath ( 2 , PLAT_CLIENT_EXEC , aBuf , sizeof aBuf ) ;
shell_execute ( aBuf ) ;
Quit ( ) ;
2014-12-31 14:35:49 +00:00
}
2010-05-29 07:25:38 +00:00
void CClient : : Quit ( )
{
SetState ( IClient : : STATE_QUITING ) ;
}
const char * CClient : : ErrorString ( )
{
2014-04-26 18:29:42 +00:00
return m_NetClient [ 0 ] . ErrorString ( ) ;
2010-05-29 07:25:38 +00:00
}
void CClient : : Render ( )
{
2014-05-01 15:44:35 +00:00
if ( g_Config . m_ClOverlayEntities )
2013-08-29 15:14:03 +00:00
{
2013-10-08 14:32:27 +00:00
vec3 bg = HslToRgb ( vec3 ( g_Config . m_ClBackgroundEntitiesHue / 255.0f , g_Config . m_ClBackgroundEntitiesSat / 255.0f , g_Config . m_ClBackgroundEntitiesLht / 255.0f ) ) ;
2013-08-29 15:14:03 +00:00
Graphics ( ) - > Clear ( bg . r , bg . g , bg . b ) ;
}
2013-10-09 15:11:34 +00:00
else
2013-08-29 15:14:03 +00:00
{
2013-10-08 14:32:27 +00:00
vec3 bg = HslToRgb ( vec3 ( g_Config . m_ClBackgroundHue / 255.0f , g_Config . m_ClBackgroundSat / 255.0f , g_Config . m_ClBackgroundLht / 255.0f ) ) ;
2013-07-11 15:13:45 +00:00
Graphics ( ) - > Clear ( bg . r , bg . g , bg . b ) ;
2013-06-23 11:41:13 +00:00
}
2010-05-29 07:25:38 +00:00
GameClient ( ) - > OnRender ( ) ;
DebugRender ( ) ;
}
2013-07-11 15:13:45 +00:00
vec3 CClient : : GetColorV3 ( int v )
{
return HslToRgb ( vec3 ( ( ( v > > 16 ) & 0xff ) / 255.0f , ( ( v > > 8 ) & 0xff ) / 255.0f , 0.5f + ( v & 0xff ) / 255.0f * 0.5f ) ) ;
}
2010-05-29 07:25:38 +00:00
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
2014-10-16 15:42:13 +00:00
for ( int i = 0 ; i < RECORDER_MAX ; i + + )
DemoRecorder_Stop ( i ) ;
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 ) ;
2014-05-03 18:24:45 +00:00
m_RecivedSnapshots [ g_Config . m_ClDummy ] = 0 ;
2010-05-29 07:25:38 +00:00
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
2012-01-09 01:02:02 +00:00
if ( pPacket - > m_DataSize = = ( int ) ( sizeof ( VERSIONSRV_VERSION ) + sizeof ( GAME_RELEASE_VERSION ) ) & &
2010-05-29 07:25:38 +00:00
mem_comp ( pPacket - > m_pData , VERSIONSRV_VERSION , sizeof ( VERSIONSRV_VERSION ) ) = = 0 )
{
2012-01-09 01:02:02 +00:00
char * pVersionData = ( char * ) pPacket - > m_pData + sizeof ( VERSIONSRV_VERSION ) ;
int VersionMatch = ! mem_comp ( pVersionData , GAME_RELEASE_VERSION , sizeof ( GAME_RELEASE_VERSION ) ) ;
char aVersion [ sizeof ( GAME_RELEASE_VERSION ) ] ;
str_copy ( aVersion , pVersionData , sizeof ( aVersion ) ) ;
2010-05-29 07:25:38 +00:00
2010-08-17 22:06:00 +00:00
char aBuf [ 256 ] ;
2012-01-09 01:02:02 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " version does %s (%s) " ,
2010-05-29 07:25:38 +00:00
VersionMatch ? " match " : " NOT match " ,
2012-01-09 01:02:02 +00:00
aVersion ) ;
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
2012-01-09 01:02:02 +00:00
if ( ! VersionMatch )
str_copy ( m_aVersionStr , aVersion , sizeof ( m_aVersionStr ) ) ;
2010-05-29 07:25:38 +00:00
2014-06-05 10:11:41 +00:00
// request the news
2011-03-31 13:13:49 +00:00
CNetChunk Packet ;
mem_zero ( & Packet , sizeof ( Packet ) ) ;
Packet . m_ClientID = - 1 ;
Packet . m_Address = m_VersionInfo . m_VersionServeraddr . m_Addr ;
2014-06-05 10:11:41 +00:00
Packet . m_pData = VERSIONSRV_GETNEWS ;
Packet . m_DataSize = sizeof ( VERSIONSRV_GETNEWS ) ;
Packet . m_Flags = NETSENDFLAG_CONNLESS ;
m_NetClient [ g_Config . m_ClDummy ] . Send ( & Packet ) ;
2014-09-19 22:36:22 +00:00
RequestDDNetSrvList ( ) ;
2014-09-13 14:36:25 +00:00
2014-06-05 10:11:41 +00:00
// request the map version list now
mem_zero ( & Packet , sizeof ( Packet ) ) ;
Packet . m_ClientID = - 1 ;
Packet . m_Address = m_VersionInfo . m_VersionServeraddr . m_Addr ;
2011-03-31 13:13:49 +00:00
Packet . m_pData = VERSIONSRV_GETMAPLIST ;
Packet . m_DataSize = sizeof ( VERSIONSRV_GETMAPLIST ) ;
Packet . m_Flags = NETSENDFLAG_CONNLESS ;
2014-04-26 18:29:42 +00:00
m_NetClient [ g_Config . m_ClDummy ] . Send ( & Packet ) ;
2010-05-29 07:25:38 +00:00
}
2014-06-05 10:11:41 +00:00
// news
if ( pPacket - > m_DataSize = = ( int ) ( sizeof ( VERSIONSRV_NEWS ) + NEWS_SIZE ) & &
mem_comp ( pPacket - > m_pData , VERSIONSRV_NEWS , sizeof ( VERSIONSRV_NEWS ) ) = = 0 )
{
if ( mem_comp ( m_aNews , ( char * ) pPacket - > m_pData + sizeof ( VERSIONSRV_NEWS ) , NEWS_SIZE ) )
g_Config . m_UiPage = CMenus : : PAGE_NEWS ;
mem_copy ( m_aNews , ( char * ) pPacket - > m_pData + sizeof ( VERSIONSRV_NEWS ) , NEWS_SIZE ) ;
2014-06-05 13:19:26 +00:00
IOHANDLE newsFile = m_pStorage - > OpenFile ( " ddnet-news.txt " , IOFLAG_WRITE , IStorage : : TYPE_SAVE ) ;
if ( newsFile )
{
io_write ( newsFile , m_aNews , sizeof ( m_aNews ) ) ;
io_close ( newsFile ) ;
}
2014-06-05 10:11:41 +00:00
}
2014-09-13 14:36:25 +00:00
// ddnet server list
2014-09-20 09:36:46 +00:00
// Packet: VERSIONSRV_DDNETLIST + char[4] Token + int16 comp_length + int16 plain_length + char[comp_length]
if ( pPacket - > m_DataSize > = ( int ) ( sizeof ( VERSIONSRV_DDNETLIST ) + 8 ) & &
2014-09-19 22:36:22 +00:00
mem_comp ( pPacket - > m_pData , VERSIONSRV_DDNETLIST , sizeof ( VERSIONSRV_DDNETLIST ) ) = = 0 & &
mem_comp ( ( char * ) pPacket - > m_pData + sizeof ( VERSIONSRV_DDNETLIST ) , m_aDDNetSrvListToken , 4 ) = = 0 )
2014-09-13 14:36:25 +00:00
{
2014-09-20 09:36:46 +00:00
// reset random token
m_DDNetSrvListTokenSet = false ;
int CompLength = * ( short * ) ( ( char * ) pPacket - > m_pData + ( sizeof ( VERSIONSRV_DDNETLIST ) + 4 ) ) ;
int PlainLength = * ( short * ) ( ( char * ) pPacket - > m_pData + ( sizeof ( VERSIONSRV_DDNETLIST ) + 6 ) ) ;
2014-09-13 14:36:25 +00:00
2014-09-20 09:36:46 +00:00
if ( pPacket - > m_DataSize = = ( int ) ( sizeof ( VERSIONSRV_DDNETLIST ) + 8 + CompLength ) )
2014-09-13 14:36:25 +00:00
{
2014-09-20 12:20:43 +00:00
char aBuf [ 16384 ] ;
uLongf DstLen = sizeof ( aBuf ) ;
2014-09-20 09:36:46 +00:00
const char * pComp = ( char * ) pPacket - > m_pData + sizeof ( VERSIONSRV_DDNETLIST ) + 8 ;
// do decompression of serverlist
if ( uncompress ( ( Bytef * ) aBuf , & DstLen , ( Bytef * ) pComp , CompLength ) = = Z_OK & & ( int ) DstLen = = PlainLength )
{
2014-09-20 13:35:01 +00:00
bool ListChanged = true ;
IOHANDLE File = m_pStorage - > OpenFile ( " ddnet-servers.json " , IOFLAG_READ , IStorage : : TYPE_SAVE ) ;
2014-09-20 09:36:46 +00:00
if ( File )
{
2014-09-20 13:35:01 +00:00
char aBuf2 [ 16384 ] ;
io_read ( File , aBuf2 , sizeof ( aBuf2 ) ) ;
2014-09-20 09:36:46 +00:00
io_close ( File ) ;
2014-09-20 13:35:01 +00:00
if ( str_comp ( aBuf , aBuf2 ) = = 0 )
ListChanged = false ;
}
// decompression successful, write plain file
if ( ListChanged )
{
IOHANDLE File = m_pStorage - > OpenFile ( " ddnet-servers.json " , IOFLAG_WRITE , IStorage : : TYPE_SAVE ) ;
if ( File )
{
io_write ( File , aBuf , PlainLength ) ;
io_close ( File ) ;
}
if ( g_Config . m_UiPage = = CMenus : : PAGE_DDNET )
m_ServerBrowser . Refresh ( IServerBrowser : : TYPE_DDNET ) ;
2014-09-20 09:36:46 +00:00
}
}
2014-09-13 14:36:25 +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
}
2013-12-31 02:18:37 +00:00
2013-12-31 01:34:33 +00:00
//server count from master server
if ( pPacket - > m_DataSize = = ( int ) sizeof ( SERVERBROWSE_COUNT ) + 2 & & mem_comp ( pPacket - > m_pData , SERVERBROWSE_COUNT , sizeof ( SERVERBROWSE_COUNT ) ) = = 0 )
{
unsigned char * pP = ( unsigned char * ) pPacket - > m_pData ;
pP + = sizeof ( SERVERBROWSE_COUNT ) ;
int ServerCount = ( ( * pP ) < < 8 ) | * ( pP + 1 ) ;
int ServerID = - 1 ;
for ( int i = 0 ; i < IMasterServer : : MAX_MASTERSERVERS ; i + + )
{
if ( ! m_pMasterServer - > IsValid ( i ) )
2014-01-03 15:14:41 +00:00
continue ;
NETADDR tmp = m_pMasterServer - > GetAddr ( i ) ;
if ( net_addr_comp ( & pPacket - > m_Address , & tmp ) = = 0 )
2013-12-31 01:34:33 +00:00
{
ServerID = i ;
break ;
}
}
if ( ServerCount > - 1 & & ServerID ! = - 1 )
2014-01-03 15:14:41 +00:00
{
2013-12-31 01:34:33 +00:00
m_pMasterServer - > SetCount ( ServerID , ServerCount ) ;
2014-01-03 15:14:41 +00:00
if ( g_Config . m_Debug )
dbg_msg ( " MasterCount " , " Server %d got %d servers " , ServerID , ServerCount ) ;
}
2013-12-31 01:34:33 +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 ;
2013-07-22 15:20:34 +00:00
static unsigned char IPV4Mapping [ ] = { 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xFF , 0xFF } ;
2011-04-08 21:56:15 +00:00
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
2014-01-09 14:40:11 +00:00
CServerBrowser : : CServerEntry * pEntry = m_ServerBrowser . Find ( pPacket - > m_Address ) ;
// Don't add info if we already got info64
2014-01-10 11:01:13 +00:00
if ( pEntry & & pEntry - > m_Info . m_MaxClients > VANILLA_MAX_CLIENTS )
2014-01-09 14:40:11 +00:00
return ;
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-12-29 22:36:53 +00:00
net_addr_str ( & pPacket - > m_Address , Info . m_aAddress , sizeof ( Info . m_aAddress ) , true ) ;
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
2014-09-20 19:44:43 +00:00
pEntry = m_ServerBrowser . Find ( pPacket - > m_Address ) ;
if ( ! pEntry | | ! pEntry - > m_GotInfo )
m_ServerBrowser . Set ( pPacket - > m_Address , IServerBrowser : : SET_TOKEN , Token , & Info ) ;
2014-04-04 22:07:58 +00:00
2011-03-17 16:41:57 +00:00
if ( net_addr_comp ( & m_ServerAddress , & pPacket - > m_Address ) = = 0 )
{
2014-04-04 22:07:58 +00:00
if ( m_CurrentServerInfo . m_MaxClients < = VANILLA_MAX_CLIENTS )
{
mem_copy ( & m_CurrentServerInfo , & Info , sizeof ( m_CurrentServerInfo ) ) ;
m_CurrentServerInfo . m_NetAddr = m_ServerAddress ;
m_CurrentServerInfoRequestTime = - 1 ;
}
2011-03-17 16:41:57 +00:00
}
2014-01-14 20:40:55 +00:00
2014-12-10 02:39:15 +00:00
if ( Is64Player ( & Info ) )
2014-01-14 20:40:55 +00:00
{
pEntry = m_ServerBrowser . Find ( pPacket - > m_Address ) ;
2014-08-22 17:59:38 +00:00
if ( pEntry )
2014-01-14 20:40:55 +00:00
{
pEntry - > m_Is64 = true ;
m_ServerBrowser . RequestImpl64 ( pEntry - > m_Addr , pEntry ) ; // Force a quick update
2014-05-22 15:02:58 +00:00
//m_ServerBrowser.QueueRequest(pEntry);
2014-01-14 20:40:55 +00:00
}
}
2011-03-17 16:41:57 +00:00
}
}
2014-01-08 05:15:56 +00:00
// server info 64
if ( pPacket - > m_DataSize > = ( int ) sizeof ( SERVERBROWSE_INFO64 ) & & mem_comp ( pPacket - > m_pData , SERVERBROWSE_INFO64 , sizeof ( SERVERBROWSE_INFO64 ) ) = = 0 )
{
// we got ze info
CUnpacker Up ;
CServerInfo NewInfo = { 0 } ;
CServerBrowser : : CServerEntry * pEntry = m_ServerBrowser . Find ( pPacket - > m_Address ) ;
CServerInfo & Info = NewInfo ;
if ( pEntry )
Info = pEntry - > m_Info ;
Up . Reset ( ( unsigned char * ) pPacket - > m_pData + sizeof ( SERVERBROWSE_INFO64 ) , pPacket - > m_DataSize - sizeof ( SERVERBROWSE_INFO64 ) ) ;
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 ( ) ) ;
Info . m_NumClients = str_toint ( Up . GetString ( ) ) ;
Info . m_MaxClients = str_toint ( Up . GetString ( ) ) ;
// don't add invalid info to the server browser list
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 )
return ;
net_addr_str ( & pPacket - > m_Address , Info . m_aAddress , sizeof ( Info . m_aAddress ) , true ) ;
int Offset = Up . GetInt ( ) ;
2014-01-13 22:15:54 +00:00
for ( int i = max ( Offset , 0 ) ; i < max ( Offset , 0 ) + 24 & & i < MAX_CLIENTS ; i + + )
2014-01-08 05:15:56 +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 ) ) ;
Info . m_aClients [ i ] . m_Country = str_toint ( Up . GetString ( ) ) ;
Info . m_aClients [ i ] . m_Score = str_toint ( Up . GetString ( ) ) ;
Info . m_aClients [ i ] . m_Player = str_toint ( Up . GetString ( ) ) ! = 0 ? true : false ;
}
if ( ! Up . Error ( ) )
{
// sort players
2014-01-13 22:15:54 +00:00
if ( Offset + 24 > = Info . m_NumClients )
qsort ( Info . m_aClients , Info . m_NumClients , sizeof ( * Info . m_aClients ) , PlayerScoreComp ) ;
2014-01-08 05:15:56 +00:00
2014-04-04 22:07:58 +00:00
m_ServerBrowser . Set ( pPacket - > m_Address , IServerBrowser : : SET_TOKEN , Token , & Info ) ;
2014-01-08 05:15:56 +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 ;
}
}
}
2011-03-17 16:41:57 +00:00
}
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
2014-08-16 10:55:37 +00:00
if ( m_DummyConnected )
DummyDisconnect ( 0 ) ;
2014-05-10 18:25:29 +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 ) ) ;
2014-10-29 12:37:38 +00:00
2011-03-17 16:41:57 +00:00
m_MapdownloadCrc = MapCrc ;
m_MapdownloadTotalsize = MapSize ;
2010-05-29 07:25:38 +00:00
m_MapdownloadAmount = 0 ;
2015-01-28 12:17:39 +00:00
ResetMapDownload ( ) ;
2015-01-19 23:25:02 +00:00
if ( g_Config . m_ClHttpMapDownload )
{
char aUrl [ 256 ] ;
2015-02-12 17:58:54 +00:00
char aFilename [ 64 ] ;
char aEscaped [ 128 ] ;
str_format ( aFilename , sizeof ( aFilename ) , " %s_%08x.map " , pMap , MapCrc ) ;
Fetcher ( ) - > Escape ( aEscaped , sizeof ( aEscaped ) , aFilename ) ;
str_format ( aUrl , sizeof ( aUrl ) , " http://%s/%s " , g_Config . m_ClDDNetMapServer , aEscaped ) ;
2015-01-19 23:25:02 +00:00
m_pMapdownloadTask = new CFetchTask ;
Fetcher ( ) - > QueueAdd ( m_pMapdownloadTask , aUrl , m_aMapdownloadFilename , IStorage : : TYPE_SAVE ) ;
}
else
SendMapRequest ( ) ;
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 ) ;
2015-01-19 23:21:38 +00:00
// check for errors
2011-03-17 16:41:57 +00:00
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 )
2015-01-19 22:51:03 +00:00
{
if ( m_MapdownloadFile )
io_close ( m_MapdownloadFile ) ;
2014-10-29 12:37:38 +00:00
FinishMapDownload ( ) ;
2015-01-19 22:51:03 +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 )
2014-04-27 11:44:04 +00:00
m_RconAuthed [ g_Config . m_ClDummy ] = Result ;
2011-12-30 18:21:00 +00:00
int Old = m_UseTempRconCommands ;
2011-07-14 20:07:21 +00:00
m_UseTempRconCommands = Unpacker . GetInt ( ) ;
if ( Unpacker . Error ( ) ! = 0 )
m_UseTempRconCommands = 0 ;
2011-12-30 18:21:00 +00:00
if ( Old ! = 0 & & m_UseTempRconCommands = = 0 )
m_pConsole - > DeregisterTempAll ( ) ;
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 ( ) ;
2013-12-18 15:54:20 +00:00
int64 Now = time_get ( ) ;
2011-03-17 16:41:57 +00:00
// adjust our prediction time
int64 Target = 0 ;
for ( int k = 0 ; k < 200 ; k + + )
2010-05-29 07:25:38 +00:00
{
2014-10-12 15:52:53 +00:00
if ( m_aInputs [ g_Config . m_ClDummy ] [ k ] . m_Tick = = InputPredTick )
2010-05-29 07:25:38 +00:00
{
2014-10-12 15:52:53 +00:00
Target = m_aInputs [ g_Config . m_ClDummy ] [ k ] . m_PredictedTime + ( Now - m_aInputs [ g_Config . m_ClDummy ] [ k ] . m_Time ) ;
2011-03-17 16:41:57 +00:00
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 )
2014-05-03 21:28:48 +00:00
m_PredictedTime . Update ( & m_InputtimeMarginGraph , Target , TimeLeft , 1 ) ;
2011-03-17 16:41:57 +00:00
}
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 ;
2014-02-26 00:25:22 +00:00
// only allow packets from the server we actually want
if ( net_addr_comp ( & pPacket - > m_Address , & m_ServerAddress ) )
return ;
2011-03-17 16:41:57 +00:00
// 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
2014-04-28 15:26:31 +00:00
if ( GameTick > = m_CurrentRecvTick [ g_Config . m_ClDummy ] )
2011-03-17 16:41:57 +00:00
{
2014-04-28 15:26:31 +00:00
if ( GameTick ! = m_CurrentRecvTick [ g_Config . m_ClDummy ] )
2010-05-29 07:25:38 +00:00
{
2011-03-17 16:41:57 +00:00
m_SnapshotParts = 0 ;
2014-04-28 15:26:31 +00:00
m_CurrentRecvTick [ g_Config . m_ClDummy ] = 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
{
2014-05-03 18:24:45 +00:00
int DeltashotSize = m_SnapshotStorage [ g_Config . m_ClDummy ] . Get ( DeltaTick , 0 , & pDeltaShot , 0 ) ;
2010-05-29 07:25:38 +00:00
2014-05-03 18:24:45 +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
2014-04-28 15:26:31 +00:00
m_AckGameTick [ g_Config . m_ClDummy ] = - 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
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
2014-04-28 15:26:31 +00:00
m_AckGameTick [ g_Config . m_ClDummy ] = - 1 ;
2011-03-17 16:41:57 +00:00
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 ;
2014-05-03 18:24:45 +00:00
if ( m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_PREV ] & & m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_PREV ] - > m_Tick < PurgeTick )
PurgeTick = m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_PREV ] - > m_Tick ;
if ( m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] & & m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] - > m_Tick < PurgeTick )
PurgeTick = m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] - > m_Tick ;
m_SnapshotStorage [ g_Config . m_ClDummy ] . PurgeUntil ( PurgeTick ) ;
2011-03-17 16:41:57 +00:00
// add new
2014-05-03 18:24:45 +00:00
m_SnapshotStorage [ g_Config . m_ClDummy ] . Add ( GameTick , time_get ( ) , SnapSize , pTmpBuffer3 , 1 ) ;
2011-03-17 16:41:57 +00:00
2014-12-01 00:32:51 +00:00
// for antiping: if the projectile netobjects from the server contains extra data, this is removed and the original content restored before recording demo
unsigned char aExtraInfoRemoved [ CSnapshot : : MAX_SIZE ] ;
mem_copy ( aExtraInfoRemoved , pTmpBuffer3 , SnapSize ) ;
CServerInfo Info ;
GetServerInfo ( & Info ) ;
2014-12-10 02:39:15 +00:00
if ( IsDDNet ( & Info ) )
2014-12-01 00:32:51 +00:00
SnapshotRemoveExtraInfo ( aExtraInfoRemoved ) ;
2011-03-17 16:41:57 +00:00
// add snapshot to demo
2014-10-16 15:42:13 +00:00
for ( int i = 0 ; i < RECORDER_MAX ; i + + )
2011-03-17 16:41:57 +00:00
{
2014-10-16 15:42:13 +00:00
if ( m_DemoRecorder [ i ] . IsRecording ( ) )
{
// write snapshot
2014-12-01 00:32:51 +00:00
m_DemoRecorder [ i ] . RecordSnapshot ( GameTick , aExtraInfoRemoved , SnapSize ) ;
2014-10-16 15:42:13 +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
// apply snapshot, cycle pointers
2014-05-03 18:24:45 +00:00
m_RecivedSnapshots [ g_Config . m_ClDummy ] + + ;
2011-03-17 16:41:57 +00:00
2014-04-28 15:26:31 +00:00
m_CurrentRecvTick [ g_Config . m_ClDummy ] = GameTick ;
2011-03-17 16:41:57 +00:00
// we got two snapshots until we see us self as connected
2014-05-03 18:24:45 +00:00
if ( m_RecivedSnapshots [ g_Config . m_ClDummy ] = = 2 )
2011-03-17 16:41:57 +00:00
{
// start at 200ms and work from there
2014-05-03 21:28:48 +00:00
m_PredictedTime . Init ( GameTick * time_freq ( ) / 50 ) ;
m_PredictedTime . SetAdjustSpeed ( 1 , 1000.0f ) ;
2014-04-28 15:26:31 +00:00
m_GameTime [ g_Config . m_ClDummy ] . Init ( ( GameTick - 1 ) * time_freq ( ) / 50 ) ;
2014-05-03 18:24:45 +00:00
m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_PREV ] = m_SnapshotStorage [ g_Config . m_ClDummy ] . m_pFirst ;
m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] = m_SnapshotStorage [ g_Config . m_ClDummy ] . m_pLast ;
2011-03-17 16:41:57 +00:00
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
2014-05-03 18:24:45 +00:00
if ( m_RecivedSnapshots [ g_Config . m_ClDummy ] > 2 )
2011-03-17 16:41:57 +00:00
{
2014-04-28 15:26:31 +00:00
int64 Now = m_GameTime [ g_Config . m_ClDummy ] . Get ( time_get ( ) ) ;
2011-03-17 16:41:57 +00:00
int64 TickStart = GameTick * time_freq ( ) / 50 ;
int64 TimeLeft = ( TickStart - Now ) * 1000 / time_freq ( ) ;
2014-04-28 15:26:31 +00:00
m_GameTime [ g_Config . m_ClDummy ] . 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
2014-11-27 00:59:55 +00:00
if ( m_RecivedSnapshots [ g_Config . m_ClDummy ] > 50 & & ! m_TimeoutCodeSent [ g_Config . m_ClDummy ] )
{
2014-12-10 02:39:15 +00:00
if ( IsDDNet ( & m_CurrentServerInfo ) )
2014-11-27 00:59:55 +00:00
{
m_TimeoutCodeSent [ g_Config . m_ClDummy ] = true ;
CNetMsg_Cl_Say Msg ;
Msg . m_Team = 0 ;
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " /timeout %s " , g_Config . m_ClDummy ? g_Config . m_ClDummyTimeoutCode : g_Config . m_ClTimeoutCode ) ;
Msg . m_pMessage = aBuf ;
CMsgPacker Packer ( Msg . MsgID ( ) ) ;
Msg . Pack ( & Packer ) ;
SendMsgExY ( & Packer , MSGFLAG_VITAL , false , g_Config . m_ClDummy ) ;
}
}
2011-03-17 16:41:57 +00:00
// ack snapshot
2014-04-28 15:26:31 +00:00
m_AckGameTick [ g_Config . m_ClDummy ] = GameTick ;
2010-05-29 07:25:38 +00:00
}
}
}
2011-03-17 16:41:57 +00:00
}
else
{
// game message
2014-10-16 15:42:13 +00:00
for ( int i = 0 ; i < RECORDER_MAX ; i + + )
if ( m_DemoRecorder [ i ] . IsRecording ( ) )
m_DemoRecorder [ i ] . 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
}
}
2014-05-03 00:30:05 +00:00
void CClient : : ProcessServerPacketDummy ( CNetChunk * pPacket )
{
CUnpacker Unpacker ;
Unpacker . Reset ( pPacket - > m_pData , pPacket - > m_DataSize ) ;
// unpack msgid and system flag
int Msg = Unpacker . GetInt ( ) ;
int Sys = Msg & 1 ;
Msg > > = 1 ;
if ( Unpacker . Error ( ) )
return ;
if ( Sys )
{
2014-05-17 19:37:55 +00:00
if ( Msg = = NETMSG_CON_READY )
{
m_DummyConnected = true ;
g_Config . m_ClDummy = 1 ;
2014-06-04 21:19:05 +00:00
Rcon ( " crashmeplx " ) ;
2014-10-01 10:41:10 +00:00
if ( m_RconAuthed [ 0 ] )
RconAuth ( " " , m_RconPassword ) ;
2014-05-17 19:37:55 +00:00
}
else if ( Msg = = NETMSG_SNAP | | Msg = = NETMSG_SNAPSINGLE | | Msg = = NETMSG_SNAPEMPTY )
2014-05-03 00:30:05 +00:00
{
2014-05-03 18:24:45 +00:00
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 ;
// only allow packets from the server we actually want
if ( net_addr_comp ( & pPacket - > m_Address , & m_ServerAddress ) )
return ;
// we are not allowed to process snapshot yet
if ( State ( ) < IClient : : STATE_LOADING )
return ;
if ( Msg = = NETMSG_SNAP )
{
NumParts = Unpacker . GetInt ( ) ;
Part = Unpacker . GetInt ( ) ;
}
if ( Msg ! = NETMSG_SNAPEMPTY )
{
Crc = Unpacker . GetInt ( ) ;
PartSize = Unpacker . GetInt ( ) ;
}
pData = ( const char * ) Unpacker . GetRaw ( PartSize ) ;
if ( Unpacker . Error ( ) )
return ;
if ( GameTick > = m_CurrentRecvTick [ ! g_Config . m_ClDummy ] )
{
if ( GameTick ! = m_CurrentRecvTick [ ! g_Config . m_ClDummy ] )
{
m_SnapshotParts = 0 ;
m_CurrentRecvTick [ ! g_Config . m_ClDummy ] = GameTick ;
}
// TODO: clean this up abit
mem_copy ( ( char * ) m_aSnapshotIncommingData + Part * MAX_SNAPSHOT_PACKSIZE , pData , PartSize ) ;
m_SnapshotParts | = 1 < < Part ;
if ( m_SnapshotParts = = ( unsigned ) ( ( 1 < < NumParts ) - 1 ) )
{
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 )
{
int DeltashotSize = m_SnapshotStorage [ ! g_Config . m_ClDummy ] . Get ( DeltaTick , 0 , & pDeltaShot , 0 ) ;
if ( DeltashotSize < 0 )
{
// couldn't find the delta snapshots that the server used
// to compress this snapshot. force the server to resync
if ( g_Config . m_Debug )
{
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " error, couldn't find the delta snapshot " ) ;
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " client " , aBuf ) ;
}
// ack snapshot
// TODO: combine this with the input message
m_AckGameTick [ ! g_Config . m_ClDummy ] = - 1 ;
return ;
}
}
// decompress snapshot
pDeltaData = m_SnapshotDelta . EmptyDelta ( ) ;
DeltaSize = sizeof ( int ) * 3 ;
if ( CompleteSize )
{
int IntSize = CVariableInt : : Decompress ( m_aSnapshotIncommingData , CompleteSize , aTmpBuffer2 ) ;
if ( IntSize < 0 ) // failure during decompression, bail
return ;
pDeltaData = aTmpBuffer2 ;
DeltaSize = IntSize ;
}
// unpack delta
SnapSize = m_SnapshotDelta . UnpackDelta ( pDeltaShot , pTmpBuffer3 , pDeltaData , DeltaSize ) ;
if ( SnapSize < 0 )
{
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " client " , " delta unpack failed! " ) ;
return ;
}
if ( Msg ! = NETMSG_SNAPEMPTY & & pTmpBuffer3 - > Crc ( ) ! = Crc )
{
if ( g_Config . m_Debug )
{
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 ) ;
}
m_SnapCrcErrors + + ;
if ( m_SnapCrcErrors > 10 )
{
// to many errors, send reset
m_AckGameTick [ ! g_Config . m_ClDummy ] = - 1 ;
SendInput ( ) ;
m_SnapCrcErrors = 0 ;
}
return ;
}
else
{
if ( m_SnapCrcErrors )
m_SnapCrcErrors - - ;
}
// purge old snapshots
PurgeTick = DeltaTick ;
if ( m_aSnapshots [ ! g_Config . m_ClDummy ] [ SNAP_PREV ] & & m_aSnapshots [ ! g_Config . m_ClDummy ] [ SNAP_PREV ] - > m_Tick < PurgeTick )
PurgeTick = m_aSnapshots [ ! g_Config . m_ClDummy ] [ SNAP_PREV ] - > m_Tick ;
if ( m_aSnapshots [ ! g_Config . m_ClDummy ] [ SNAP_CURRENT ] & & m_aSnapshots [ ! g_Config . m_ClDummy ] [ SNAP_CURRENT ] - > m_Tick < PurgeTick )
PurgeTick = m_aSnapshots [ ! g_Config . m_ClDummy ] [ SNAP_CURRENT ] - > m_Tick ;
m_SnapshotStorage [ ! g_Config . m_ClDummy ] . PurgeUntil ( PurgeTick ) ;
// add new
m_SnapshotStorage [ ! g_Config . m_ClDummy ] . Add ( GameTick , time_get ( ) , SnapSize , pTmpBuffer3 , 1 ) ;
// apply snapshot, cycle pointers
m_RecivedSnapshots [ ! g_Config . m_ClDummy ] + + ;
m_CurrentRecvTick [ ! g_Config . m_ClDummy ] = GameTick ;
// we got two snapshots until we see us self as connected
if ( m_RecivedSnapshots [ ! g_Config . m_ClDummy ] = = 2 )
{
// start at 200ms and work from there
2014-05-03 21:28:48 +00:00
//m_PredictedTime[!g_Config.m_ClDummy].Init(GameTick*time_freq()/50);
//m_PredictedTime[!g_Config.m_ClDummy].SetAdjustSpeed(1, 1000.0f);
2014-05-03 18:24:45 +00:00
m_GameTime [ ! g_Config . m_ClDummy ] . Init ( ( GameTick - 1 ) * time_freq ( ) / 50 ) ;
m_aSnapshots [ ! g_Config . m_ClDummy ] [ SNAP_PREV ] = m_SnapshotStorage [ ! g_Config . m_ClDummy ] . m_pFirst ;
m_aSnapshots [ ! g_Config . m_ClDummy ] [ SNAP_CURRENT ] = m_SnapshotStorage [ ! g_Config . m_ClDummy ] . m_pLast ;
m_LocalStartTime = time_get ( ) ;
SetState ( IClient : : STATE_ONLINE ) ;
2014-05-17 16:57:46 +00:00
2014-05-03 18:24:45 +00:00
//DemoRecorder_HandleAutoStart();
}
// adjust game time
if ( m_RecivedSnapshots [ ! g_Config . m_ClDummy ] > 2 )
{
int64 Now = m_GameTime [ ! g_Config . m_ClDummy ] . Get ( time_get ( ) ) ;
int64 TickStart = GameTick * time_freq ( ) / 50 ;
int64 TimeLeft = ( TickStart - Now ) * 1000 / time_freq ( ) ;
m_GameTime [ ! g_Config . m_ClDummy ] . Update ( & m_GametimeMarginGraph , ( GameTick - 1 ) * time_freq ( ) / 50 , TimeLeft , 0 ) ;
}
// ack snapshot
m_AckGameTick [ ! g_Config . m_ClDummy ] = GameTick ;
}
}
2014-05-03 00:30:05 +00:00
}
}
else
{
GameClient ( ) - > OnMessage ( Msg , & Unpacker , 1 ) ;
}
}
2014-10-29 12:37:38 +00:00
void CClient : : ResetMapDownload ( )
{
if ( m_pMapdownloadTask ) {
delete m_pMapdownloadTask ;
m_pMapdownloadTask = NULL ;
}
m_MapdownloadFile = 0 ;
m_MapdownloadAmount = 0 ;
}
void CClient : : FinishMapDownload ( )
{
const char * pError ;
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " client/network " , " download complete, loading map " ) ;
2015-01-19 22:51:03 +00:00
int prev = m_MapdownloadTotalsize ;
2014-10-29 12:37:38 +00:00
m_MapdownloadTotalsize = - 1 ;
// load map
pError = LoadMap ( m_aMapdownloadName , m_aMapdownloadFilename , m_MapdownloadCrc ) ;
if ( ! pError )
{
2015-01-19 22:51:03 +00:00
ResetMapDownload ( ) ;
2014-10-29 12:37:38 +00:00
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " client/network " , " loading done " ) ;
SendReady ( ) ;
}
2015-01-19 21:13:44 +00:00
else if ( m_pMapdownloadTask )
{
ResetMapDownload ( ) ;
2015-01-19 22:51:03 +00:00
m_MapdownloadTotalsize = prev ;
2015-01-19 21:13:44 +00:00
SendMapRequest ( ) ;
}
2015-01-19 22:51:03 +00:00
else {
if ( m_MapdownloadFile )
io_close ( m_MapdownloadFile ) ;
ResetMapDownload ( ) ;
2014-10-29 12:37:38 +00:00
DisconnectWithReason ( pError ) ;
2015-01-19 22:51:03 +00:00
}
2014-10-29 12:37:38 +00:00
}
2010-05-29 07:25:38 +00:00
void CClient : : PumpNetwork ( )
{
2014-08-13 10:03:53 +00:00
for ( int i = 0 ; i < 3 ; i + + )
2014-04-26 18:29:42 +00:00
{
m_NetClient [ i ] . Update ( ) ;
}
2010-05-29 07:25:38 +00:00
if ( State ( ) ! = IClient : : STATE_DEMOPLAYBACK )
{
// check for errors
2014-04-26 18:29:42 +00:00
if ( State ( ) ! = IClient : : STATE_OFFLINE & & State ( ) ! = IClient : : STATE_QUITING & & m_NetClient [ 0 ] . 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 ] ;
2014-04-26 18:29:42 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " offline error='%s' " , m_NetClient [ 0 ] . ErrorString ( ) ) ;
2010-08-17 22:06:00 +00:00
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " client " , aBuf ) ;
2010-05-29 07:25:38 +00:00
}
//
2014-04-26 18:29:42 +00:00
if ( State ( ) = = IClient : : STATE_CONNECTING & & m_NetClient [ 0 ] . State ( ) = = NETSTATE_ONLINE )
2010-05-29 07:25:38 +00:00
{
// 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 ;
2014-08-13 10:03:53 +00:00
for ( int i = 0 ; i < 3 ; i + + )
2011-03-17 16:41:57 +00:00
{
2014-04-26 18:29:42 +00:00
while ( m_NetClient [ i ] . Recv ( & Packet ) )
{
if ( Packet . m_ClientID = = - 1 | | i > 1 )
{
ProcessConnlessPacket ( & Packet ) ;
}
else if ( i > 0 & & i < 2 )
{
if ( g_Config . m_ClDummy )
ProcessServerPacket ( & Packet ) ; //self
else
2014-05-03 00:30:05 +00:00
ProcessServerPacketDummy ( & Packet ) ; //multiclient
2014-04-26 18:29:42 +00:00
}
else
{
if ( g_Config . m_ClDummy )
2014-05-03 00:30:05 +00:00
ProcessServerPacketDummy ( & Packet ) ; //multiclient
2014-04-26 18:29:42 +00:00
else
ProcessServerPacket ( & Packet ) ; //self
}
}
2011-03-17 16:41:57 +00:00
}
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 ;
2014-04-28 15:26:31 +00:00
m_CurGameTick [ g_Config . m_ClDummy ] = pInfo - > m_Info . m_CurrentTick ;
m_PrevGameTick [ g_Config . m_ClDummy ] = pInfo - > m_PreviousTick ;
2010-05-29 07:25:38 +00:00
// handle snapshots
2014-05-03 18:24:45 +00:00
pTemp = m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_PREV ] ;
m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_PREV ] = m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] ;
m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] = pTemp ;
2010-05-29 07:25:38 +00:00
2014-05-03 18:24:45 +00:00
mem_copy ( m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] - > m_pSnap , pData , Size ) ;
mem_copy ( m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] - > m_pAltSnap , pData , Size ) ;
2010-05-29 07:25:38 +00:00
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 ( ) ;
2014-04-28 15:26:31 +00:00
m_CurGameTick [ g_Config . m_ClDummy ] = pInfo - > m_Info . m_CurrentTick ;
m_PrevGameTick [ g_Config . m_ClDummy ] = pInfo - > m_PreviousTick ;
m_GameIntraTick [ g_Config . m_ClDummy ] = pInfo - > m_IntraTick ;
m_GameTickTime [ g_Config . m_ClDummy ] = pInfo - > m_TickTime ;
2010-05-29 07:25:38 +00:00
}
else
{
// disconnect on error
Disconnect ( ) ;
}
}
2014-05-03 18:24:45 +00:00
else if ( State ( ) = = IClient : : STATE_ONLINE & & m_RecivedSnapshots [ g_Config . m_ClDummy ] > = 3 )
2010-05-29 07:25:38 +00:00
{
// switch snapshot
int Repredict = 0 ;
int64 Freq = time_freq ( ) ;
2014-04-28 15:26:31 +00:00
int64 Now = m_GameTime [ g_Config . m_ClDummy ] . Get ( time_get ( ) ) ;
2014-05-03 21:28:48 +00:00
int64 PredNow = m_PredictedTime . Get ( time_get ( ) ) ;
2010-05-29 07:25:38 +00:00
while ( 1 )
{
2014-05-03 18:24:45 +00:00
CSnapshotStorage : : CHolder * pCur = m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] ;
2010-05-29 07:25:38 +00:00
int64 TickStart = ( pCur - > m_Tick ) * time_freq ( ) / 50 ;
if ( TickStart < Now )
{
2014-05-03 18:24:45 +00:00
CSnapshotStorage : : CHolder * pNext = m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] - > m_pNext ;
2010-05-29 07:25:38 +00:00
if ( pNext )
{
2014-05-03 18:24:45 +00:00
m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_PREV ] = m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] ;
m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] = pNext ;
2010-05-29 07:25:38 +00:00
// set ticks
2014-05-03 18:24:45 +00:00
m_CurGameTick [ g_Config . m_ClDummy ] = m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] - > m_Tick ;
m_PrevGameTick [ g_Config . m_ClDummy ] = m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_PREV ] - > m_Tick ;
2010-05-29 07:25:38 +00:00
2014-07-07 13:42:46 +00:00
if ( m_LastDummy2 = = ( bool ) g_Config . m_ClDummy & & m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] & & m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_PREV ] )
2010-05-29 07:25:38 +00:00
{
GameClient ( ) - > OnNewSnapshot ( ) ;
Repredict = 1 ;
}
}
else
break ;
}
else
break ;
}
2014-07-07 13:42:46 +00:00
if ( m_LastDummy2 ! = ( bool ) g_Config . m_ClDummy )
2014-05-03 21:28:48 +00:00
{
m_LastDummy2 = g_Config . m_ClDummy ;
}
2014-05-03 18:24:45 +00:00
if ( m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] & & m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_PREV ] )
2010-05-29 07:25:38 +00:00
{
2014-05-03 18:24:45 +00:00
int64 CurtickStart = ( m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] - > m_Tick ) * time_freq ( ) / 50 ;
int64 PrevtickStart = ( m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_PREV ] - > m_Tick ) * time_freq ( ) / 50 ;
2010-05-29 07:25:38 +00:00
int PrevPredTick = ( int ) ( PredNow * 50 / time_freq ( ) ) ;
int NewPredTick = PrevPredTick + 1 ;
2014-04-28 15:26:31 +00:00
m_GameIntraTick [ g_Config . m_ClDummy ] = ( Now - PrevtickStart ) / ( float ) ( CurtickStart - PrevtickStart ) ;
m_GameTickTime [ g_Config . m_ClDummy ] = ( Now - PrevtickStart ) / ( float ) Freq ; //(float)SERVER_TICK_SPEED);
2010-05-29 07:25:38 +00:00
CurtickStart = NewPredTick * time_freq ( ) / 50 ;
PrevtickStart = PrevPredTick * time_freq ( ) / 50 ;
2014-04-28 15:26:31 +00:00
m_PredIntraTick [ g_Config . m_ClDummy ] = ( PredNow - PrevtickStart ) / ( float ) ( CurtickStart - PrevtickStart ) ;
2010-05-29 07:25:38 +00:00
2014-05-03 18:24:45 +00:00
if ( NewPredTick < m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_PREV ] - > m_Tick - SERVER_TICK_SPEED | | NewPredTick > m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_PREV ] - > m_Tick + SERVER_TICK_SPEED )
2010-05-29 07:25:38 +00:00
{
2010-08-17 22:06:00 +00:00
m_pConsole - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " client " , " prediction time reset! " ) ;
2014-05-03 21:28:48 +00:00
m_PredictedTime . Init ( m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] - > m_Tick * time_freq ( ) / 50 ) ;
2010-05-29 07:25:38 +00:00
}
2014-04-28 15:26:31 +00:00
if ( NewPredTick > m_PredTick [ g_Config . m_ClDummy ] )
2010-05-29 07:25:38 +00:00
{
2014-04-28 15:26:31 +00:00
m_PredTick [ g_Config . m_ClDummy ] = NewPredTick ;
2010-05-29 07:25:38 +00:00
Repredict = 1 ;
// send input
SendInput ( ) ;
}
}
// only do sane predictions
if ( Repredict )
{
2014-04-28 15:26:31 +00:00
if ( m_PredTick [ g_Config . m_ClDummy ] > m_CurGameTick [ g_Config . m_ClDummy ] & & m_PredTick [ g_Config . m_ClDummy ] < m_CurGameTick [ g_Config . m_ClDummy ] + 50 )
2010-05-29 07:25:38 +00:00
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 ( ) ;
2015-01-28 12:13:56 +00:00
if ( m_pMapdownloadTask )
{
2014-10-29 12:37:38 +00:00
if ( m_pMapdownloadTask - > State ( ) = = CFetchTask : : STATE_DONE )
FinishMapDownload ( ) ;
2015-01-28 12:13:56 +00:00
else if ( m_pMapdownloadTask - > State ( ) = = CFetchTask : : STATE_ERROR )
{
2014-10-29 12:37:38 +00:00
dbg_msg ( " webdl " , " HTTP failed falling back to gameserver. " ) ;
ResetMapDownload ( ) ;
SendMapRequest ( ) ;
}
2015-01-28 12:13:56 +00:00
else if ( m_pMapdownloadTask - > State ( ) = = CFetchTask : : STATE_ABORTED )
{
delete m_pMapdownloadTask ;
m_pMapdownloadTask = 0 ;
}
2014-10-29 12:37:38 +00:00
}
2010-05-29 07:25:38 +00:00
// 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
{
2014-04-26 18:29:42 +00:00
Engine ( ) - > HostLookup ( & m_VersionInfo . m_VersionServeraddr , g_Config . m_ClDDNetVersionServer , m_NetClient [ 0 ] . NetType ( ) ) ;
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 ;
2014-04-26 19:10:39 +00:00
m_NetClient [ 0 ] . 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
}
}
}
2015-03-14 09:45:11 +00:00
void CClient : : CheckVersionUpdate ( )
{
m_VersionInfo . m_State = CVersionInfo : : STATE_START ;
}
2010-05-29 07:25:38 +00:00
void CClient : : RegisterInterfaces ( )
{
2014-10-27 08:05:22 +00:00
Kernel ( ) - > RegisterInterface ( static_cast < IDemoRecorder * > ( & m_DemoRecorder [ RECORDER_MANUAL ] ) ) ;
2010-05-29 07:25:38 +00:00
Kernel ( ) - > RegisterInterface ( static_cast < IDemoPlayer * > ( & m_DemoPlayer ) ) ;
Kernel ( ) - > RegisterInterface ( static_cast < IServerBrowser * > ( & m_ServerBrowser ) ) ;
2014-10-29 12:37:38 +00:00
Kernel ( ) - > RegisterInterface ( static_cast < IFetcher * > ( & m_Fetcher ) ) ;
2015-02-27 21:08:34 +00:00
# if !defined(CONF_PLATFORM_MACOSX) && !defined(__ANDROID__)
2014-12-31 14:29:34 +00:00
Kernel ( ) - > RegisterInterface ( static_cast < IAutoUpdate * > ( & m_AutoUpdate ) ) ;
2015-02-27 21:08:34 +00:00
# endif
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 > ( ) ;
2011-12-31 09:29:25 +00:00
//m_pGraphics = Kernel()->RequestInterface<IEngineGraphics>();
2010-05-29 07:25:38 +00:00
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 > ( ) ;
2014-10-29 12:37:38 +00:00
m_pFetcher = Kernel ( ) - > RequestInterface < IFetcher > ( ) ;
2015-02-27 21:08:34 +00:00
# if !defined(CONF_PLATFORM_MACOSX) && !defined(__ANDROID__)
2014-12-31 14:29:34 +00:00
m_pAutoUpdate = Kernel ( ) - > RequestInterface < IAutoUpdate > ( ) ;
2015-02-27 21:08:34 +00:00
# endif
2010-05-29 07:25:38 +00:00
m_pStorage = Kernel ( ) - > RequestInterface < IStorage > ( ) ;
2014-08-12 14:21:06 +00:00
m_DemoEditor . Init ( m_pGameClient - > NetVersion ( ) , & m_SnapshotDelta , m_pConsole , m_pStorage ) ;
2014-08-23 15:57:32 +00:00
2014-08-13 10:03:53 +00:00
m_ServerBrowser . SetBaseInfo ( & m_NetClient [ 2 ] , m_pGameClient - > NetVersion ( ) ) ;
2014-08-12 14:21:06 +00:00
2014-10-29 12:37:38 +00:00
m_Fetcher . Init ( ) ;
2015-02-27 21:08:34 +00:00
# if !defined(CONF_PLATFORM_MACOSX) && !defined(__ANDROID__)
2014-12-31 14:29:34 +00:00
m_AutoUpdate . Init ( ) ;
2015-02-27 21:08:34 +00:00
# endif
2014-10-29 12:37:38 +00:00
2011-03-23 12:06:35 +00:00
m_Friends . Init ( ) ;
2014-06-05 10:11:41 +00:00
2014-06-05 13:19:26 +00:00
IOHANDLE newsFile = m_pStorage - > OpenFile ( " ddnet-news.txt " , IOFLAG_READ , IStorage : : TYPE_SAVE ) ;
if ( newsFile )
{
io_read ( newsFile , m_aNews , NEWS_SIZE ) ;
io_close ( newsFile ) ;
}
2010-05-29 07:25:38 +00:00
}
void CClient : : Run ( )
{
m_LocalStartTime = time_get ( ) ;
m_SnapshotParts = 0 ;
2014-08-13 10:58:53 +00:00
srand ( time ( NULL ) ) ;
2012-01-03 20:39:10 +00:00
// init SDL
{
if ( SDL_Init ( 0 ) < 0 )
{
dbg_msg ( " client " , " unable to init SDL base: %s " , SDL_GetError ( ) ) ;
return ;
}
atexit ( SDL_Quit ) ; // ignore_convention
}
2010-05-29 07:25:38 +00:00
// init graphics
2011-12-30 15:02:22 +00:00
{
2014-05-15 23:01:30 +00:00
if ( g_Config . m_GfxThreadedOld )
m_pGraphics = CreateEngineGraphicsThreaded ( ) ;
else
m_pGraphics = CreateEngineGraphics ( ) ;
2011-12-31 09:29:25 +00:00
bool RegisterFail = false ;
RegisterFail = RegisterFail | | ! Kernel ( ) - > RegisterInterface ( static_cast < IEngineGraphics * > ( m_pGraphics ) ) ; // register graphics as both
RegisterFail = RegisterFail | | ! Kernel ( ) - > RegisterInterface ( static_cast < IGraphics * > ( m_pGraphics ) ) ;
if ( RegisterFail | | m_pGraphics - > Init ( ) ! = 0 )
{
dbg_msg ( " client " , " couldn't init graphics " ) ;
return ;
}
2011-12-30 15:02:22 +00:00
}
2012-01-03 20:39:10 +00:00
// init sound, allowed to fail
m_SoundInitFailed = Sound ( ) - > Init ( ) ! = 0 ;
2010-05-29 07:25:38 +00:00
2011-04-04 16:20:05 +00:00
// open socket
{
NETADDR BindAddr ;
2012-03-04 11:47:16 +00:00
if ( g_Config . m_Bindaddr [ 0 ] & & net_host_lookup ( g_Config . m_Bindaddr , & BindAddr , NETTYPE_ALL ) = = 0 )
{
// got bindaddr
BindAddr . type = NETTYPE_ALL ;
}
else
2012-01-06 18:17:14 +00:00
{
mem_zero ( & BindAddr , sizeof ( BindAddr ) ) ;
BindAddr . type = NETTYPE_ALL ;
}
2014-08-13 10:03:53 +00:00
for ( int i = 0 ; i < 3 ; i + + )
2011-04-04 16:20:05 +00:00
{
2014-08-13 10:03:53 +00:00
BindAddr . port = ( rand ( ) % 64511 ) + 1024 ;
while ( ! m_NetClient [ i ] . Open ( BindAddr , 0 ) )
2014-04-26 18:29:42 +00:00
{
2014-08-13 10:03:53 +00:00
BindAddr . port = ( rand ( ) % 64511 ) + 1024 ;
2014-04-26 18:29:42 +00:00
}
2011-04-04 16:20:05 +00:00
}
}
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
2014-04-26 19:10:39 +00:00
MasterServer ( ) - > RefreshAddresses ( m_NetClient [ 0 ] . NetType ( ) ) ;
2010-05-29 07:25:38 +00:00
// init the editor
2012-01-06 11:55:19 +00:00
m_pEditor - > Init ( ) ;
2010-05-29 07:25:38 +00:00
// load data
if ( ! LoadData ( ) )
return ;
GameClient ( ) - > OnInit ( ) ;
2011-12-30 15:02:22 +00:00
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
2011-08-13 00:11:06 +00:00
m_pConsole - > StoreCommands ( false ) ;
2014-10-29 12:37:38 +00:00
2014-01-31 00:41:57 +00:00
bool LastD = false ;
bool LastQ = false ;
bool LastE = false ;
bool LastG = false ;
2010-05-29 07:25:38 +00:00
while ( 1 )
{
//
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
2015-02-27 21:08:34 +00:00
# if !defined(CONF_PLATFORM_MACOSX) && !defined(__ANDROID__)
2014-12-31 14:29:34 +00:00
AutoUpdate ( ) - > Update ( ) ;
2015-02-27 21:08:34 +00:00
# endif
2014-12-31 14:29:34 +00:00
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
2014-01-31 00:41:57 +00:00
if ( CtrlShiftKey ( ' q ' , LastQ ) )
2012-01-06 19:03:57 +00:00
{
Quit ( ) ;
2010-05-29 07:25:38 +00:00
break ;
2012-01-06 19:03:57 +00:00
}
2010-05-29 07:25:38 +00:00
2014-01-31 00:41:57 +00:00
if ( CtrlShiftKey ( ' d ' , LastD ) )
2010-05-29 07:25:38 +00:00
g_Config . m_Debug ^ = 1 ;
2014-01-31 00:41:57 +00:00
if ( CtrlShiftKey ( ' g ' , LastG ) )
2010-05-29 07:25:38 +00:00
g_Config . m_DbgGraphs ^ = 1 ;
2014-01-31 00:41:57 +00:00
if ( CtrlShiftKey ( ' e ' , LastE ) )
2010-05-29 07:25:38 +00:00
{
g_Config . m_ClEditor = g_Config . m_ClEditor ^ 1 ;
Input ( ) - > MouseModeRelative ( ) ;
}
/*
if ( ! gfx_window_open ( ) )
break ;
*/
// render
{
2012-01-06 11:55:19 +00:00
if ( g_Config . m_ClEditor )
2011-01-17 11:28:37 +00:00
{
2012-01-06 11:55:19 +00:00
if ( ! m_EditorActive )
{
GameClient ( ) - > OnActivateEditor ( ) ;
m_EditorActive = true ;
}
2011-01-17 11:28:37 +00:00
}
2012-01-06 11:55:19 +00:00
else if ( m_EditorActive )
2011-01-17 11:28:37 +00:00
m_EditorActive = false ;
2010-05-29 07:25:38 +00:00
Update ( ) ;
2011-12-30 15:02:22 +00:00
2014-05-15 23:01:30 +00:00
if ( ( g_Config . m_GfxBackgroundRender | | m_pGraphics - > WindowOpen ( ) ) & & ( ! g_Config . m_GfxAsyncRenderOld | | m_pGraphics - > IsIdle ( ) ) )
2010-05-29 07:25:38 +00:00
{
2012-01-01 12:38:46 +00:00
m_RenderFrames + + ;
// update frametime
int64 Now = time_get ( ) ;
m_RenderFrameTime = ( Now - m_LastRenderTime ) / ( float ) time_freq ( ) ;
if ( m_RenderFrameTime < m_RenderFrameTimeLow )
m_RenderFrameTimeLow = m_RenderFrameTime ;
if ( m_RenderFrameTime > m_RenderFrameTimeHigh )
m_RenderFrameTimeHigh = m_RenderFrameTime ;
m_FpsGraph . Add ( 1.0f / m_RenderFrameTime , 1 , 1 , 1 ) ;
m_LastRenderTime = Now ;
2011-12-31 09:04:46 +00:00
if ( g_Config . m_DbgStress )
{
2012-01-01 12:38:46 +00:00
if ( ( m_RenderFrames % 10 ) = = 0 )
2011-12-31 09:04:46 +00:00
{
2012-01-06 11:55:19 +00:00
if ( ! m_EditorActive )
Render ( ) ;
else
{
m_pEditor - > UpdateAndRender ( ) ;
DebugRender ( ) ;
}
2011-12-31 09:04:46 +00:00
m_pGraphics - > Swap ( ) ;
}
}
else
2010-05-29 07:25:38 +00:00
{
2012-01-06 11:55:19 +00:00
if ( ! m_EditorActive )
Render ( ) ;
else
{
m_pEditor - > UpdateAndRender ( ) ;
DebugRender ( ) ;
}
2010-05-29 07:25:38 +00:00
m_pGraphics - > Swap ( ) ;
}
}
2014-06-16 11:29:18 +00:00
if ( Input ( ) - > VideoRestartNeeded ( ) )
{
m_pGraphics - > Init ( ) ;
LoadData ( ) ;
GameClient ( ) - > OnInit ( ) ;
}
2010-05-29 07:25:38 +00:00
}
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
2013-02-20 14:51:46 +00:00
if ( g_Config . m_ClCpuThrottle )
2014-11-11 12:00:02 +00:00
net_socket_read_wait ( m_NetClient [ 0 ] . m_Socket , g_Config . m_ClCpuThrottle * 1000 ) ;
2014-01-15 20:40:28 +00:00
//thread_sleep(g_Config.m_ClCpuThrottle);
2014-09-05 23:42:59 +00:00
else if ( g_Config . m_DbgStress | | ( g_Config . m_ClCpuThrottleInactive & & ! m_pGraphics - > WindowActive ( ) ) )
2010-05-29 07:25:38 +00:00
thread_sleep ( 5 ) ;
if ( g_Config . m_DbgHitch )
{
thread_sleep ( g_Config . m_DbgHitch ) ;
g_Config . m_DbgHitch = 0 ;
}
2012-01-01 12:38:46 +00:00
// update local time
2010-05-29 07:25:38 +00:00
m_LocalTime = ( time_get ( ) - m_LocalStartTime ) / ( float ) time_freq ( ) ;
}
GameClient ( ) - > OnShutdown ( ) ;
Disconnect ( ) ;
m_pGraphics - > Shutdown ( ) ;
m_pSound - > Shutdown ( ) ;
2012-01-03 20:39:10 +00:00
// shutdown SDL
{
SDL_Quit ( ) ;
}
2010-05-29 07:25:38 +00:00
}
2014-01-31 00:41:57 +00:00
bool CClient : : CtrlShiftKey ( int Key , bool & Last )
{
if ( Input ( ) - > KeyPressed ( KEY_LCTRL ) & & Input ( ) - > KeyPressed ( KEY_LSHIFT ) & & ! Last & & Input ( ) - > KeyPressed ( Key ) )
{
Last = true ;
return true ;
}
else if ( Last & & ! Input ( ) - > KeyPressed ( Key ) )
Last = false ;
return false ;
}
2010-05-29 07:25:38 +00:00
2011-08-13 00:11:06 +00:00
void CClient : : Con_Connect ( IConsole : : IResult * pResult , void * pUserData )
2010-05-29 07:25:38 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
str_copy ( pSelf - > m_aCmdConnect , pResult - > GetString ( 0 ) , sizeof ( pSelf - > m_aCmdConnect ) ) ;
}
2011-08-13 00:11:06 +00:00
void CClient : : Con_Disconnect ( IConsole : : IResult * pResult , void * pUserData )
2010-05-29 07:25:38 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
pSelf - > Disconnect ( ) ;
}
2014-04-26 18:29:42 +00:00
void CClient : : Con_DummyConnect ( IConsole : : IResult * pResult , void * pUserData )
{
CClient * pSelf = ( CClient * ) pUserData ;
2014-04-28 13:19:57 +00:00
pSelf - > DummyConnect ( ) ;
2014-04-26 18:29:42 +00:00
}
void CClient : : Con_DummyDisconnect ( IConsole : : IResult * pResult , void * pUserData )
{
CClient * pSelf = ( CClient * ) pUserData ;
pSelf - > DummyDisconnect ( 0 ) ;
}
2011-08-13 00:11:06 +00:00
void CClient : : Con_Quit ( IConsole : : IResult * pResult , void * pUserData )
2010-05-29 07:25:38 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
pSelf - > Quit ( ) ;
}
2011-08-13 00:11:06 +00:00
void CClient : : Con_Minimize ( IConsole : : IResult * pResult , void * pUserData )
2010-05-29 07:25:38 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
pSelf - > Graphics ( ) - > Minimize ( ) ;
}
2011-08-13 00:11:06 +00:00
void CClient : : Con_Ping ( IConsole : : IResult * pResult , void * pUserData )
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 ;
}
}
2011-08-13 00:11:06 +00:00
void CClient : : Con_Screenshot ( IConsole : : IResult * pResult , void * pUserData )
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
}
2011-08-13 00:11:06 +00:00
void CClient : : Con_Rcon ( IConsole : : IResult * pResult , void * pUserData )
2010-05-29 07:25:38 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
pSelf - > Rcon ( pResult - > GetString ( 0 ) ) ;
}
2011-08-13 00:11:06 +00:00
void CClient : : Con_RconAuth ( IConsole : : IResult * pResult , void * pUserData )
2010-05-29 07:25:38 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
pSelf - > RconAuth ( " " , pResult - > GetString ( 0 ) ) ;
}
2011-08-13 00:11:06 +00:00
void CClient : : Con_AddFavorite ( IConsole : : IResult * pResult , void * pUserData )
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-08-13 00:11:06 +00:00
void CClient : : Con_RemoveFavorite ( IConsole : : IResult * pResult , void * pUserData )
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 ) ;
}
2014-08-13 14:35:15 +00:00
void CClient : : DemoSliceBegin ( )
2014-08-12 14:21:06 +00:00
{
2014-08-13 14:35:15 +00:00
const CDemoPlayer : : CPlaybackInfo * pInfo = m_DemoPlayer . Info ( ) ;
2014-08-13 15:32:03 +00:00
g_Config . m_ClDemoSliceBegin = pInfo - > m_Info . m_CurrentTick ;
2014-08-12 14:21:06 +00:00
}
2014-08-13 14:35:15 +00:00
void CClient : : DemoSliceEnd ( )
2014-08-12 14:21:06 +00:00
{
2014-08-13 14:35:15 +00:00
const CDemoPlayer : : CPlaybackInfo * pInfo = m_DemoPlayer . Info ( ) ;
2014-08-12 14:21:06 +00:00
g_Config . m_ClDemoSliceEnd = pInfo - > m_Info . m_CurrentTick ;
}
2014-08-13 14:35:15 +00:00
void CClient : : Con_DemoSliceBegin ( IConsole : : IResult * pResult , void * pUserData )
{
CClient * pSelf = ( CClient * ) pUserData ;
pSelf - > DemoSliceBegin ( ) ;
}
void CClient : : Con_DemoSliceEnd ( IConsole : : IResult * pResult , void * pUserData )
2014-08-12 14:21:06 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
2014-08-13 14:35:15 +00:00
pSelf - > DemoSliceEnd ( ) ;
}
2014-08-12 14:21:06 +00:00
2014-08-23 15:48:04 +00:00
void CClient : : DemoSlice ( const char * pDstPath )
2014-08-13 14:35:15 +00:00
{
if ( m_DemoPlayer . IsPlaying ( ) )
2014-08-12 14:21:06 +00:00
{
2014-08-13 14:35:15 +00:00
const char * pDemoFileName = m_DemoPlayer . GetDemoFileName ( ) ;
2014-08-23 15:48:04 +00:00
m_DemoEditor . Slice ( pDemoFileName , pDstPath , g_Config . m_ClDemoSliceBegin , g_Config . m_ClDemoSliceEnd ) ;
2014-08-12 14:21:06 +00:00
}
}
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 ( ) ;
2014-04-26 18:29:42 +00:00
m_NetClient [ 0 ] . ResetErrorString ( ) ;
2010-05-29 07:25:38 +00:00
// 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 ) ) ;
2014-05-03 18:24:45 +00:00
m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] = & m_aDemorecSnapshotHolders [ SNAP_CURRENT ] ;
m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_PREV ] = & m_aDemorecSnapshotHolders [ SNAP_PREV ] ;
2010-05-29 07:25:38 +00:00
2014-05-03 18:24:45 +00:00
m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] - > m_pSnap = ( CSnapshot * ) m_aDemorecSnapshotData [ SNAP_CURRENT ] [ 0 ] ;
m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] - > m_pAltSnap = ( CSnapshot * ) m_aDemorecSnapshotData [ SNAP_CURRENT ] [ 1 ] ;
m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] - > m_SnapSize = 0 ;
m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_CURRENT ] - > m_Tick = - 1 ;
2010-05-29 07:25:38 +00:00
2014-05-03 18:24:45 +00:00
m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_PREV ] - > m_pSnap = ( CSnapshot * ) m_aDemorecSnapshotData [ SNAP_PREV ] [ 0 ] ;
m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_PREV ] - > m_pAltSnap = ( CSnapshot * ) m_aDemorecSnapshotData [ SNAP_PREV ] [ 1 ] ;
m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_PREV ] - > m_SnapSize = 0 ;
m_aSnapshots [ g_Config . m_ClDummy ] [ SNAP_PREV ] - > m_Tick = - 1 ;
2010-05-29 07:25:38 +00:00
// enter demo playback state
SetState ( IClient : : STATE_DEMOPLAYBACK ) ;
m_DemoPlayer . Play ( ) ;
GameClient ( ) - > OnEnterGame ( ) ;
return 0 ;
}
2011-08-13 00:11:06 +00:00
void CClient : : Con_Play ( IConsole : : IResult * pResult , void * pUserData )
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
}
2014-10-16 15:42:13 +00:00
void CClient : : DemoRecorder_Start ( const char * pFilename , bool WithTimestamp , int Recorder )
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 ) ;
2014-10-16 15:42:13 +00:00
m_DemoRecorder [ Recorder ] . 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
{
2014-10-16 15:42:13 +00:00
DemoRecorder_Stop ( RECORDER_AUTO ) ;
DemoRecorder_Start ( " auto/autorecord " , true , RECORDER_AUTO ) ;
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
}
2014-10-16 15:42:13 +00:00
void CClient : : DemoRecorder_Stop ( int Recorder )
{
m_DemoRecorder [ Recorder ] . Stop ( ) ;
}
void CClient : : DemoRecorder_AddDemoMarker ( int Recorder )
2010-12-07 23:02:24 +00:00
{
2014-10-16 15:42:13 +00:00
m_DemoRecorder [ Recorder ] . AddDemoMarker ( ) ;
2010-12-07 23:02:24 +00:00
}
2014-10-16 15:42:13 +00:00
class IDemoRecorder * CClient : : DemoRecorder ( int Recorder )
2012-01-10 22:13:19 +00:00
{
2014-10-16 15:42:13 +00:00
return & m_DemoRecorder [ Recorder ] ;
2012-01-10 22:13:19 +00:00
}
2011-08-13 00:11:06 +00:00
void CClient : : Con_Record ( IConsole : : IResult * pResult , void * pUserData )
2010-08-09 12:14:15 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
2010-12-07 23:42:32 +00:00
if ( pResult - > NumArguments ( ) )
2014-10-16 15:42:13 +00:00
pSelf - > DemoRecorder_Start ( pResult - > GetString ( 0 ) , false , RECORDER_MANUAL ) ;
2010-12-07 23:42:32 +00:00
else
2014-10-16 15:42:13 +00:00
pSelf - > DemoRecorder_Start ( " demo " , true , RECORDER_MANUAL ) ;
2010-08-09 12:14:15 +00:00
}
2011-08-13 00:11:06 +00:00
void CClient : : Con_StopRecord ( IConsole : : IResult * pResult , void * pUserData )
2010-05-29 07:25:38 +00:00
{
CClient * pSelf = ( CClient * ) pUserData ;
2014-10-16 15:42:13 +00:00
pSelf - > DemoRecorder_Stop ( RECORDER_MANUAL ) ;
2010-05-29 07:25:38 +00:00
}
2012-01-10 22:13:19 +00:00
void CClient : : Con_AddDemoMarker ( IConsole : : IResult * pResult , void * pUserData )
{
CClient * pSelf = ( CClient * ) pUserData ;
2014-10-16 15:42:13 +00:00
pSelf - > DemoRecorder_AddDemoMarker ( RECORDER_MANUAL ) ;
2012-01-10 22:13:19 +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-08-13 00:11:06 +00:00
pfnCallback ( pResult , pCallbackUserData ) ;
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-08-13 00:11:06 +00:00
m_pConsole - > Register ( " kick " , " i?r " , CFGFLAG_SERVER , 0 , 0 , " Kick player with specified id for any reason " ) ;
m_pConsole - > Register ( " ban " , " s?ir " , CFGFLAG_SERVER , 0 , 0 , " Ban player with ip/id for x minutes for any reason " ) ;
m_pConsole - > Register ( " unban " , " s " , CFGFLAG_SERVER , 0 , 0 , " Unban ip " ) ;
m_pConsole - > Register ( " bans " , " " , CFGFLAG_SERVER , 0 , 0 , " Show banlist " ) ;
m_pConsole - > Register ( " status " , " " , CFGFLAG_SERVER , 0 , 0 , " List players " ) ;
m_pConsole - > Register ( " shutdown " , " " , CFGFLAG_SERVER , 0 , 0 , " Shut down " ) ;
m_pConsole - > Register ( " record " , " ?s " , CFGFLAG_SERVER , 0 , 0 , " Record to a file " ) ;
m_pConsole - > Register ( " stoprecord " , " " , CFGFLAG_SERVER , 0 , 0 , " Stop recording " ) ;
m_pConsole - > Register ( " reload " , " " , CFGFLAG_SERVER , 0 , 0 , " Reload the map " ) ;
2014-04-26 18:29:42 +00:00
m_pConsole - > Register ( " dummy_connect " , " " , CFGFLAG_CLIENT , Con_DummyConnect , this , " connect dummy " ) ;
m_pConsole - > Register ( " dummy_disconnect " , " " , CFGFLAG_CLIENT , Con_DummyDisconnect , this , " disconnect dummy " ) ;
2011-08-13 00:11:06 +00:00
m_pConsole - > Register ( " quit " , " " , CFGFLAG_CLIENT | CFGFLAG_STORE , Con_Quit , this , " Quit Teeworlds " ) ;
m_pConsole - > Register ( " exit " , " " , CFGFLAG_CLIENT | CFGFLAG_STORE , Con_Quit , this , " Quit Teeworlds " ) ;
m_pConsole - > Register ( " minimize " , " " , CFGFLAG_CLIENT | CFGFLAG_STORE , Con_Minimize , this , " Minimize Teeworlds " ) ;
m_pConsole - > Register ( " connect " , " s " , CFGFLAG_CLIENT , Con_Connect , this , " Connect to the specified host/ip " ) ;
m_pConsole - > Register ( " disconnect " , " " , CFGFLAG_CLIENT , Con_Disconnect , this , " Disconnect from the server " ) ;
m_pConsole - > Register ( " ping " , " " , CFGFLAG_CLIENT , Con_Ping , this , " Ping the current server " ) ;
m_pConsole - > Register ( " screenshot " , " " , CFGFLAG_CLIENT , Con_Screenshot , this , " Take a screenshot " ) ;
m_pConsole - > Register ( " rcon " , " r " , CFGFLAG_CLIENT , Con_Rcon , this , " Send specified command to rcon " ) ;
m_pConsole - > Register ( " rcon_auth " , " s " , CFGFLAG_CLIENT , Con_RconAuth , this , " Authenticate to rcon " ) ;
2011-11-30 00:41:00 +00:00
m_pConsole - > Register ( " play " , " r " , CFGFLAG_CLIENT | CFGFLAG_STORE , Con_Play , this , " Play the file specified " ) ;
2011-08-13 00:11:06 +00:00
m_pConsole - > Register ( " record " , " ?s " , CFGFLAG_CLIENT , Con_Record , this , " Record to the file " ) ;
m_pConsole - > Register ( " stoprecord " , " " , CFGFLAG_CLIENT , Con_StopRecord , this , " Stop recording " ) ;
2012-01-10 22:13:19 +00:00
m_pConsole - > Register ( " add_demomarker " , " " , CFGFLAG_CLIENT , Con_AddDemoMarker , this , " Add demo timeline marker " ) ;
2011-08-13 00:11:06 +00:00
m_pConsole - > Register ( " add_favorite " , " s " , CFGFLAG_CLIENT , Con_AddFavorite , this , " Add a server as a favorite " ) ;
m_pConsole - > Register ( " remove_favorite " , " s " , CFGFLAG_CLIENT , Con_RemoveFavorite , this , " Remove a server from favorites " ) ;
2014-08-13 14:35:15 +00:00
m_pConsole - > Register ( " demo_slice_start " , " " , CFGFLAG_CLIENT , Con_DemoSliceBegin , this , " " ) ;
2014-08-12 14:21:06 +00:00
m_pConsole - > Register ( " demo_slice_end " , " " , CFGFLAG_CLIENT , Con_DemoSliceEnd , this , " " ) ;
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
2010-11-01 22:04:16 +00:00
2011-08-13 00:11:06 +00:00
# define CONSOLE_COMMAND(name, params, flags, callback, userdata, help) m_pConsole->Register(name, params, flags, 0, 0, help);
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
*/
2014-06-16 11:29:18 +00:00
# if defined(CONF_PLATFORM_MACOSX) || defined(__ANDROID__)
2012-01-06 15:35:48 +00:00
extern " C " int SDL_main ( int argc , char * * argv_ ) // ignore_convention
{
const char * * argv = const_cast < const char * * > ( argv_ ) ;
2010-05-29 07:25:38 +00:00
# else
int main ( int argc , const char * * argv ) // ignore_convention
{
2012-01-06 15:35:48 +00:00
# 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
2014-09-11 19:38:23 +00:00
# if !defined(CONF_PLATFORM_MACOSX)
2014-09-09 21:02:05 +00:00
dbg_enable_threaded ( ) ;
2014-09-11 19:38:23 +00:00
# endif
2014-09-09 21:02:05 +00:00
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 ) ;
2012-01-09 00:38:45 +00:00
IStorage * pStorage = CreateStorage ( " Teeworlds " , IStorage : : STORAGETYPE_CLIENT , argc , argv ) ; // ignore_convention
2010-05-29 07:25:38 +00:00
IConfig * pConfig = CreateConfig ( ) ;
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 < 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
2014-08-26 20:25:22 +00:00
IOHANDLE file = pStorage - > OpenFile ( " settings_ddnet.cfg " , IOFLAG_READ , IStorage : : TYPE_ALL ) ;
if ( file )
{
io_close ( file ) ;
pConsole - > ExecuteFile ( " settings_ddnet.cfg " ) ;
}
else // fallback
{
pConsole - > ExecuteFile ( " settings.cfg " ) ;
}
2010-08-06 18:47:45 +00:00
2010-05-29 07:25:38 +00:00
// execute autoexec file
2011-08-13 00:11:06 +00:00
pConsole - > ExecuteFile ( " autoexec.cfg " ) ;
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
2014-08-29 14:52:08 +00:00
# if defined(CONF_FAMILY_UNIX)
2014-08-29 17:42:34 +00:00
FifoConsole * fifoConsole = new FifoConsole ( pConsole , g_Config . m_ClInputFifo , CFGFLAG_CLIENT ) ;
2014-08-29 14:52:08 +00:00
# endif
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
2014-08-29 14:52:08 +00:00
# if defined(CONF_FAMILY_UNIX)
delete fifoConsole ;
# endif
2010-05-29 07:25:38 +00:00
// write down the config and quit
pConfig - > Save ( ) ;
2014-11-05 17:15:38 +00:00
2010-05-29 07:25:38 +00:00
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
2014-10-16 15:42:13 +00:00
m_DemoRecorder [ RECORDER_RACE ] . 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 ( )
{
2014-10-16 15:42:13 +00:00
if ( m_DemoRecorder [ RECORDER_RACE ] . IsRecording ( ) )
m_DemoRecorder [ RECORDER_RACE ] . Stop ( ) ;
2011-02-04 17:25:04 +00:00
}
2014-10-16 15:42:13 +00:00
bool CClient : : RaceRecordIsRecording ( )
2011-02-04 17:25:04 +00:00
{
2014-10-16 15:42:13 +00:00
return m_DemoRecorder [ RECORDER_RACE ] . IsRecording ( ) ;
2011-02-04 17:25:04 +00:00
}
2014-09-19 22:36:22 +00:00
void CClient : : RequestDDNetSrvList ( )
{
// request ddnet server list
// generate new token
for ( int i = 0 ; i < 4 ; i + + )
m_aDDNetSrvListToken [ i ] = rand ( ) & 0xff ;
2014-09-20 09:36:46 +00:00
m_DDNetSrvListTokenSet = true ;
2014-09-19 22:36:22 +00:00
char aData [ sizeof ( VERSIONSRV_GETDDNETLIST ) + 4 ] ;
mem_copy ( aData , VERSIONSRV_GETDDNETLIST , sizeof ( VERSIONSRV_GETDDNETLIST ) ) ;
mem_copy ( aData + sizeof ( VERSIONSRV_GETDDNETLIST ) , m_aDDNetSrvListToken , 4 ) ; // add token
CNetChunk Packet ;
mem_zero ( & Packet , sizeof ( Packet ) ) ;
Packet . m_ClientID = - 1 ;
Packet . m_Address = m_VersionInfo . m_VersionServeraddr . m_Addr ;
Packet . m_pData = aData ;
Packet . m_DataSize = sizeof ( VERSIONSRV_GETDDNETLIST ) + 4 ;
Packet . m_Flags = NETSENDFLAG_CONNLESS ;
m_NetClient [ g_Config . m_ClDummy ] . Send ( & Packet ) ;
}