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. */
2018-11-21 20:26:05 +00:00
# include <limits>
2011-03-21 23:31:42 +00:00
# include <engine/editor.h>
2011-02-27 16:56:03 +00:00
# include <engine/engine.h>
2011-03-23 12:06:35 +00:00
# include <engine/friends.h>
2010-05-29 07:25:38 +00:00
# include <engine/graphics.h>
# include <engine/textrender.h>
# include <engine/demo.h>
# include <engine/map.h>
# include <engine/storage.h>
2011-02-27 16:56:03 +00:00
# include <engine/sound.h>
2010-05-29 07:25:38 +00:00
# include <engine/serverbrowser.h>
2015-04-18 19:17:27 +00:00
# include <engine/updater.h>
2010-09-12 10:16:51 +00:00
# include <engine/shared/demo.h>
2010-05-29 07:25:38 +00:00
# include <engine/shared/config.h>
# include <game/generated/protocol.h>
# include <game/generated/client_data.h>
2013-08-23 23:50:35 +00:00
# include <base/math.h>
# include <base/vmath.h>
2017-06-06 05:31:56 +00:00
# include <game/extrainfo.h>
2010-05-29 07:25:38 +00:00
# include <game/localization.h>
# include <game/version.h>
2017-10-06 20:10:29 +00:00
# include "race.h"
2010-05-29 07:25:38 +00:00
# include "render.h"
# include "gameclient.h"
2015-08-25 00:11:04 +00:00
# include "components/background.h"
2010-05-29 07:25:38 +00:00
# include "components/binds.h"
# include "components/broadcast.h"
# include "components/camera.h"
# include "components/chat.h"
# include "components/console.h"
# include "components/controls.h"
2011-03-16 11:09:22 +00:00
# include "components/countryflags.h"
2010-05-29 07:25:38 +00:00
# include "components/damageind.h"
# include "components/debughud.h"
# include "components/effects.h"
# include "components/emoticon.h"
# include "components/flow.h"
# include "components/hud.h"
# include "components/items.h"
# include "components/killmessages.h"
# include "components/mapimages.h"
# include "components/maplayers.h"
2014-10-10 17:10:57 +00:00
# include "components/mapsounds.h"
2010-05-29 07:25:38 +00:00
# include "components/menus.h"
# include "components/motd.h"
# include "components/particles.h"
# include "components/players.h"
2013-10-09 14:23:18 +00:00
# include "components/nameplates.h"
2010-05-29 07:25:38 +00:00
# include "components/scoreboard.h"
# include "components/skins.h"
# include "components/sounds.h"
2011-03-10 09:08:14 +00:00
# include "components/spectator.h"
2015-05-21 09:41:59 +00:00
# include "components/statboard.h"
2010-05-29 07:25:38 +00:00
# include "components/voting.h"
2011-08-31 11:56:04 +00:00
# include <base/system.h>
2011-02-04 17:25:04 +00:00
# include "components/race_demo.h"
# include "components/ghost.h"
2011-08-31 11:56:04 +00:00
2010-05-29 07:25:38 +00:00
CGameClient g_GameClient ;
2008-08-27 15:48:50 +00:00
2018-07-10 09:29:02 +00:00
// instantiate all systems
2010-05-29 07:25:38 +00:00
static CKillMessages gs_KillMessages ;
static CCamera gs_Camera ;
static CChat gs_Chat ;
static CMotd gs_Motd ;
static CBroadcast gs_Broadcast ;
static CGameConsole gs_GameConsole ;
static CBinds gs_Binds ;
static CParticles gs_Particles ;
static CMenus gs_Menus ;
static CSkins gs_Skins ;
2011-03-16 11:09:22 +00:00
static CCountryFlags gs_CountryFlags ;
2010-05-29 07:25:38 +00:00
static CFlow gs_Flow ;
static CHud gs_Hud ;
static CDebugHud gs_DebugHud ;
static CControls gs_Controls ;
static CEffects gs_Effects ;
static CScoreboard gs_Scoreboard ;
2015-05-21 09:41:59 +00:00
static CStatboard gs_Statboard ;
2010-05-29 07:25:38 +00:00
static CSounds gs_Sounds ;
static CEmoticon gs_Emoticon ;
static CDamageInd gsDamageInd ;
static CVoting gs_Voting ;
2011-03-10 09:08:14 +00:00
static CSpectator gs_Spectator ;
2010-05-29 07:25:38 +00:00
static CPlayers gs_Players ;
2013-10-09 14:23:18 +00:00
static CNamePlates gs_NamePlates ;
2010-05-29 07:25:38 +00:00
static CItems gs_Items ;
static CMapImages gs_MapImages ;
static CMapLayers gs_MapLayersBackGround ( CMapLayers : : TYPE_BACKGROUND ) ;
static CMapLayers gs_MapLayersForeGround ( CMapLayers : : TYPE_FOREGROUND ) ;
2015-08-25 00:11:04 +00:00
static CBackground gs_BackGround ;
2010-05-29 07:25:38 +00:00
2014-10-10 17:10:57 +00:00
static CMapSounds gs_MapSounds ;
2011-04-09 06:41:31 +00:00
static CRaceDemo gs_RaceDemo ;
static CGhost gs_Ghost ;
2010-05-29 07:25:38 +00:00
CGameClient : : CStack : : CStack ( ) { m_Num = 0 ; }
void CGameClient : : CStack : : Add ( class CComponent * pComponent ) { m_paComponents [ m_Num + + ] = pComponent ; }
const char * CGameClient : : Version ( ) { return GAME_VERSION ; }
const char * CGameClient : : NetVersion ( ) { return GAME_NETVERSION ; }
const char * CGameClient : : GetItemName ( int Type ) { return m_NetObjHandler . GetObjName ( Type ) ; }
2009-06-15 06:45:44 +00:00
2010-05-29 07:25:38 +00:00
void CGameClient : : OnConsoleInit ( )
{
2011-02-27 16:56:03 +00:00
m_pEngine = Kernel ( ) - > RequestInterface < IEngine > ( ) ;
2010-05-29 07:25:38 +00:00
m_pClient = Kernel ( ) - > RequestInterface < IClient > ( ) ;
m_pTextRender = Kernel ( ) - > RequestInterface < ITextRender > ( ) ;
m_pSound = Kernel ( ) - > RequestInterface < ISound > ( ) ;
m_pInput = Kernel ( ) - > RequestInterface < IInput > ( ) ;
m_pConsole = Kernel ( ) - > RequestInterface < IConsole > ( ) ;
m_pStorage = Kernel ( ) - > RequestInterface < IStorage > ( ) ;
m_pDemoPlayer = Kernel ( ) - > RequestInterface < IDemoPlayer > ( ) ;
m_pServerBrowser = Kernel ( ) - > RequestInterface < IServerBrowser > ( ) ;
2011-03-21 23:31:42 +00:00
m_pEditor = Kernel ( ) - > RequestInterface < IEditor > ( ) ;
2011-03-23 12:06:35 +00:00
m_pFriends = Kernel ( ) - > RequestInterface < IFriends > ( ) ;
2015-07-22 20:16:49 +00:00
m_pFoes = Client ( ) - > Foes ( ) ;
2019-04-10 17:40:50 +00:00
# if defined(CONF_FAMILY_WINDOWS) || defined(CONF_PLATFORM_LINUX)
2015-04-18 19:17:27 +00:00
m_pUpdater = Kernel ( ) - > RequestInterface < IUpdater > ( ) ;
2015-03-13 14:13:19 +00:00
# endif
2011-04-13 18:37:12 +00:00
2008-08-27 15:48:50 +00:00
// setup pointers
2010-05-29 07:25:38 +00:00
m_pBinds = & : : gs_Binds ;
m_pGameConsole = & : : gs_GameConsole ;
m_pParticles = & : : gs_Particles ;
m_pMenus = & : : gs_Menus ;
m_pSkins = & : : gs_Skins ;
2011-03-16 11:09:22 +00:00
m_pCountryFlags = & : : gs_CountryFlags ;
2010-05-29 07:25:38 +00:00
m_pChat = & : : gs_Chat ;
m_pFlow = & : : gs_Flow ;
m_pCamera = & : : gs_Camera ;
m_pControls = & : : gs_Controls ;
m_pEffects = & : : gs_Effects ;
m_pSounds = & : : gs_Sounds ;
m_pMotd = & : : gs_Motd ;
m_pDamageind = & : : gsDamageInd ;
m_pMapimages = & : : gs_MapImages ;
m_pVoting = & : : gs_Voting ;
2010-08-18 01:57:35 +00:00
m_pScoreboard = & : : gs_Scoreboard ;
2015-05-21 09:41:59 +00:00
m_pStatboard = & : : gs_Statboard ;
2011-04-03 08:11:23 +00:00
m_pItems = & : : gs_Items ;
2011-12-04 13:04:12 +00:00
m_pMapLayersBackGround = & : : gs_MapLayersBackGround ;
m_pMapLayersForeGround = & : : gs_MapLayersForeGround ;
2015-08-25 00:11:04 +00:00
m_pBackGround = & : : gs_BackGround ;
2011-04-13 18:37:12 +00:00
2014-10-10 17:10:57 +00:00
m_pMapSounds = & : : gs_MapSounds ;
2017-09-09 22:57:32 +00:00
m_pPlayers = & : : gs_Players ;
2014-10-10 17:10:57 +00:00
2011-02-04 17:25:04 +00:00
m_pRaceDemo = & : : gs_RaceDemo ;
m_pGhost = & : : gs_Ghost ;
2011-04-09 06:41:31 +00:00
2018-03-13 20:55:47 +00:00
gs_NamePlates . SetPlayers ( m_pPlayers ) ;
2015-05-19 22:51:02 +00:00
// make a list of all the systems, make sure to add them in the correct render order
2010-05-29 07:25:38 +00:00
m_All . Add ( m_pSkins ) ;
2011-03-16 11:09:22 +00:00
m_All . Add ( m_pCountryFlags ) ;
2010-05-29 07:25:38 +00:00
m_All . Add ( m_pMapimages ) ;
m_All . Add ( m_pEffects ) ; // doesn't render anything, just updates effects
m_All . Add ( m_pParticles ) ;
m_All . Add ( m_pBinds ) ;
m_All . Add ( m_pControls ) ;
m_All . Add ( m_pCamera ) ;
m_All . Add ( m_pSounds ) ;
m_All . Add ( m_pVoting ) ;
m_All . Add ( m_pParticles ) ; // doesn't render anything, just updates all the particles
2011-02-04 17:25:04 +00:00
m_All . Add ( m_pRaceDemo ) ;
2014-10-10 17:10:57 +00:00
m_All . Add ( m_pMapSounds ) ;
2011-04-13 18:37:12 +00:00
2015-08-25 00:11:04 +00:00
m_All . Add ( & gs_BackGround ) ; //render instead of gs_MapLayersBackGround when g_Config.m_ClOverlayEntities == 100
2010-05-29 07:25:38 +00:00
m_All . Add ( & gs_MapLayersBackGround ) ; // first to render
m_All . Add ( & m_pParticles - > m_RenderTrail ) ;
2011-04-03 08:11:23 +00:00
m_All . Add ( m_pItems ) ;
2017-09-09 22:57:32 +00:00
m_All . Add ( m_pPlayers ) ;
2011-02-04 17:25:04 +00:00
m_All . Add ( m_pGhost ) ;
2010-05-29 07:25:38 +00:00
m_All . Add ( & gs_MapLayersForeGround ) ;
2010-10-11 10:32:34 +00:00
m_All . Add ( & m_pParticles - > m_RenderExplosions ) ;
2013-10-09 14:23:18 +00:00
m_All . Add ( & gs_NamePlates ) ;
2010-05-29 07:25:38 +00:00
m_All . Add ( & m_pParticles - > m_RenderGeneral ) ;
m_All . Add ( m_pDamageind ) ;
m_All . Add ( & gs_Hud ) ;
2011-03-10 09:08:14 +00:00
m_All . Add ( & gs_Spectator ) ;
2010-05-29 07:25:38 +00:00
m_All . Add ( & gs_Emoticon ) ;
m_All . Add ( & gs_KillMessages ) ;
m_All . Add ( m_pChat ) ;
m_All . Add ( & gs_Broadcast ) ;
m_All . Add ( & gs_DebugHud ) ;
m_All . Add ( & gs_Scoreboard ) ;
2015-05-21 09:41:59 +00:00
m_All . Add ( & gs_Statboard ) ;
2010-05-29 07:25:38 +00:00
m_All . Add ( m_pMotd ) ;
m_All . Add ( m_pMenus ) ;
m_All . Add ( m_pGameConsole ) ;
2011-04-13 18:37:12 +00:00
2008-08-27 15:48:50 +00:00
// build the input stack
2010-05-29 07:25:38 +00:00
m_Input . Add ( & m_pMenus - > m_Binder ) ; // this will take over all input when we want to bind a key
m_Input . Add ( & m_pBinds - > m_SpecialBinds ) ;
m_Input . Add ( m_pGameConsole ) ;
m_Input . Add ( m_pChat ) ; // chat has higher prio due to tha you can quit it by pressing esc
m_Input . Add ( m_pMotd ) ; // for pressing esc to remove it
m_Input . Add ( m_pMenus ) ;
2011-03-10 09:08:14 +00:00
m_Input . Add ( & gs_Spectator ) ;
2010-05-29 07:25:38 +00:00
m_Input . Add ( & gs_Emoticon ) ;
m_Input . Add ( m_pControls ) ;
m_Input . Add ( m_pBinds ) ;
2011-04-13 18:37:12 +00:00
2008-09-04 21:36:44 +00:00
// add the some console commands
2015-12-28 15:14:52 +00:00
Console ( ) - > Register ( " team " , " i[team-id] " , CFGFLAG_CLIENT , ConTeam , this , " Switch team " ) ;
2011-08-13 00:11:06 +00:00
Console ( ) - > Register ( " kill " , " " , CFGFLAG_CLIENT , ConKill , this , " Kill yourself " ) ;
2019-04-10 06:58:08 +00:00
Console ( ) - > Register ( " color_from_rgb " , " s[color] " , CFGFLAG_CLIENT , ConColorFromRgb , this , " Convert HEX RGB color (3 or 6 digits) to TW formats " ) ;
2019-04-10 20:43:57 +00:00
Console ( ) - > Register ( " color_to_rgb " , " i[color] ?i[color] ?i[color] " , CFGFLAG_CLIENT , ConColorToRgb , this , " Convert TW colors to HEX RGB color format " ) ;
2011-04-13 18:37:12 +00:00
2009-01-24 12:16:02 +00:00
// register server dummy commands for tab completion
2015-12-28 15:14:52 +00:00
Console ( ) - > Register ( " tune " , " s[tuning] i[value] " , CFGFLAG_SERVER , 0 , 0 , " Tune variable to value " ) ;
2010-08-06 22:01:43 +00:00
Console ( ) - > Register ( " tune_reset " , " " , CFGFLAG_SERVER , 0 , 0 , " Reset tuning " ) ;
Console ( ) - > Register ( " tune_dump " , " " , CFGFLAG_SERVER , 0 , 0 , " Dump tuning " ) ;
2015-12-28 15:14:52 +00:00
Console ( ) - > Register ( " change_map " , " ?r[map] " , CFGFLAG_SERVER , 0 , 0 , " Change map " ) ;
Console ( ) - > Register ( " restart " , " ?i[seconds] " , CFGFLAG_SERVER , 0 , 0 , " Restart in x seconds " ) ;
Console ( ) - > Register ( " broadcast " , " r[message] " , CFGFLAG_SERVER , 0 , 0 , " Broadcast message " ) ;
Console ( ) - > Register ( " say " , " r[message] " , CFGFLAG_SERVER , 0 , 0 , " Say in chat " ) ;
Console ( ) - > Register ( " set_team " , " i[id] i[team-id] ?i[delay in minutes] " , CFGFLAG_SERVER , 0 , 0 , " Set team of player to team " ) ;
Console ( ) - > Register ( " set_team_all " , " i[team-id] " , CFGFLAG_SERVER , 0 , 0 , " Set team of all players to team " ) ;
Console ( ) - > Register ( " add_vote " , " s[name] r[command] " , CFGFLAG_SERVER , 0 , 0 , " Add a voting option " ) ;
Console ( ) - > Register ( " remove_vote " , " s[name] " , CFGFLAG_SERVER , 0 , 0 , " remove a voting option " ) ;
Console ( ) - > Register ( " force_vote " , " s[name] s[command] ?r[reason] " , CFGFLAG_SERVER , 0 , 0 , " Force a voting option " ) ;
2011-01-21 19:46:00 +00:00
Console ( ) - > Register ( " clear_votes " , " " , CFGFLAG_SERVER , 0 , 0 , " Clears the voting options " ) ;
2015-12-28 15:14:52 +00:00
Console ( ) - > Register ( " vote " , " r['yes'|'no'] " , CFGFLAG_SERVER , 0 , 0 , " Force a vote to yes/no " ) ;
2011-09-04 09:13:30 +00:00
Console ( ) - > Register ( " swap_teams " , " " , CFGFLAG_SERVER , 0 , 0 , " Swap the current teams " ) ;
Console ( ) - > Register ( " shuffle_teams " , " " , CFGFLAG_SERVER , 0 , 0 , " Shuffle the current teams " ) ;
2010-05-29 07:25:38 +00:00
2010-08-25 14:15:59 +00:00
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < m_All . m_Num ; i + + )
m_All . m_paComponents [ i ] - > m_pClient = this ;
2011-04-13 18:37:12 +00:00
2008-09-23 07:43:41 +00:00
// let all the other components register their console commands
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < m_All . m_Num ; i + + )
m_All . m_paComponents [ i ] - > OnConsoleInit ( ) ;
2011-04-13 18:37:12 +00:00
2009-06-15 14:01:36 +00:00
//
2010-05-29 07:25:38 +00:00
Console ( ) - > Chain ( " player_name " , ConchainSpecialInfoupdate , this ) ;
2011-03-20 10:17:51 +00:00
Console ( ) - > Chain ( " player_clan " , ConchainSpecialInfoupdate , this ) ;
Console ( ) - > Chain ( " player_country " , ConchainSpecialInfoupdate , this ) ;
2010-05-29 07:25:38 +00:00
Console ( ) - > Chain ( " player_use_custom_color " , ConchainSpecialInfoupdate , this ) ;
Console ( ) - > Chain ( " player_color_body " , ConchainSpecialInfoupdate , this ) ;
Console ( ) - > Chain ( " player_color_feet " , ConchainSpecialInfoupdate , this ) ;
Console ( ) - > Chain ( " player_skin " , ConchainSpecialInfoupdate , this ) ;
2011-04-13 18:37:12 +00:00
2014-04-28 13:19:57 +00:00
Console ( ) - > Chain ( " dummy_name " , ConchainSpecialDummyInfoupdate , this ) ;
Console ( ) - > Chain ( " dummy_clan " , ConchainSpecialDummyInfoupdate , this ) ;
Console ( ) - > Chain ( " dummy_country " , ConchainSpecialDummyInfoupdate , this ) ;
Console ( ) - > Chain ( " dummy_use_custom_color " , ConchainSpecialDummyInfoupdate , this ) ;
Console ( ) - > Chain ( " dummy_color_body " , ConchainSpecialDummyInfoupdate , this ) ;
Console ( ) - > Chain ( " dummy_color_feet " , ConchainSpecialDummyInfoupdate , this ) ;
Console ( ) - > Chain ( " dummy_skin " , ConchainSpecialDummyInfoupdate , this ) ;
2014-04-28 13:34:56 +00:00
Console ( ) - > Chain ( " cl_dummy " , ConchainSpecialDummy , this ) ;
2008-12-19 11:41:17 +00:00
//
2010-05-29 07:25:38 +00:00
m_SuppressEvents = false ;
2008-09-04 21:36:44 +00:00
}
2010-05-29 07:25:38 +00:00
void CGameClient : : OnInit ( )
2008-09-04 21:36:44 +00:00
{
2011-12-31 09:29:25 +00:00
m_pGraphics = Kernel ( ) - > RequestInterface < IGraphics > ( ) ;
2018-03-21 14:54:51 +00:00
m_pGraphics - > AddWindowResizeListener ( OnWindowResizeCB , this ) ;
2011-12-31 09:29:25 +00:00
// propagate pointers
m_UI . SetGraphics ( Graphics ( ) , TextRender ( ) ) ;
m_RenderTools . m_pGraphics = Graphics ( ) ;
m_RenderTools . m_pUI = UI ( ) ;
2014-12-01 00:31:58 +00:00
2011-02-13 12:58:59 +00:00
int64 Start = time_get ( ) ;
2010-05-29 07:25:38 +00:00
// set the language
2010-10-06 21:07:35 +00:00
g_Localization . Load ( g_Config . m_ClLanguagefile , Storage ( ) , Console ( ) ) ;
2011-02-27 16:56:03 +00:00
// TODO: this should be different
2008-08-30 22:38:56 +00:00
// setup item sizes
for ( int i = 0 ; i < NUM_NETOBJTYPES ; i + + )
2010-05-29 07:25:38 +00:00
Client ( ) - > SnapSetStaticsize ( i , m_NetObjHandler . GetObjSize ( i ) ) ;
2011-02-27 16:56:03 +00:00
2019-03-28 20:51:42 +00:00
Client ( ) - > LoadFont ( ) ;
2011-04-13 18:37:12 +00:00
2011-02-27 16:56:03 +00:00
// init all components
for ( int i = m_All . m_Num - 1 ; i > = 0 ; - - i )
m_All . m_paComponents [ i ] - > OnInit ( ) ;
2014-04-27 22:41:19 +00:00
char aBuf [ 256 ] ;
2011-02-27 16:56:03 +00:00
// setup load amount// load textures
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < g_pData - > m_NumImages ; i + + )
2008-08-30 22:38:56 +00:00
{
2010-10-06 21:07:35 +00:00
g_pData - > m_aImages [ i ] . m_Id = Graphics ( ) - > LoadTexture ( g_pData - > m_aImages [ i ] . m_pFilename , IStorage : : TYPE_ALL , CImageInfo : : FORMAT_AUTO , 0 ) ;
2011-02-27 16:56:03 +00:00
g_GameClient . m_pMenus - > RenderLoading ( ) ;
2010-05-29 07:25:38 +00:00
}
2008-10-08 18:19:45 +00:00
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < m_All . m_Num ; i + + )
m_All . m_paComponents [ i ] - > OnReset ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
m_ServerMode = SERVERMODE_PURE ;
2011-01-06 03:46:10 +00:00
2014-04-27 11:44:04 +00:00
m_DDRaceMsgSent [ 0 ] = false ;
m_DDRaceMsgSent [ 1 ] = false ;
m_ShowOthers [ 0 ] = - 1 ;
m_ShowOthers [ 1 ] = - 1 ;
2011-04-17 17:14:49 +00:00
// Set free binds to DDRace binds if it's active
if ( ! g_Config . m_ClDDRaceBindsSet & & g_Config . m_ClDDRaceBinds )
gs_Binds . SetDDRaceBinds ( true ) ;
2014-08-09 17:17:21 +00:00
2014-08-10 10:54:01 +00:00
if ( g_Config . m_ClTimeoutCode [ 0 ] = = ' \0 ' | | str_comp ( g_Config . m_ClTimeoutCode , " hGuEYnfxicsXGwFq " ) = = 0 )
2014-08-09 17:17:21 +00:00
{
for ( unsigned int i = 0 ; i < 16 ; i + + )
{
2018-03-13 20:55:47 +00:00
if ( rand ( ) % 2 )
2018-10-02 18:52:21 +00:00
g_Config . m_ClTimeoutCode [ i ] = ( char ) ( ( rand ( ) % 26 ) + 97 ) ;
2014-08-09 17:17:21 +00:00
else
2018-10-02 18:52:21 +00:00
g_Config . m_ClTimeoutCode [ i ] = ( char ) ( ( rand ( ) % 26 ) + 65 ) ;
2014-08-09 17:17:21 +00:00
}
}
2014-08-17 17:10:08 +00:00
if ( g_Config . m_ClDummyTimeoutCode [ 0 ] = = ' \0 ' | | str_comp ( g_Config . m_ClDummyTimeoutCode , " hGuEYnfxicsXGwFq " ) = = 0 )
{
for ( unsigned int i = 0 ; i < 16 ; i + + )
{
2018-03-13 20:55:47 +00:00
if ( rand ( ) % 2 )
2018-10-02 18:52:21 +00:00
g_Config . m_ClDummyTimeoutCode [ i ] = ( char ) ( ( rand ( ) % 26 ) + 97 ) ;
2014-08-17 17:10:08 +00:00
else
2018-10-02 18:52:21 +00:00
g_Config . m_ClDummyTimeoutCode [ i ] = ( char ) ( ( rand ( ) % 26 ) + 65 ) ;
2014-08-17 17:10:08 +00:00
}
}
2018-12-23 21:53:27 +00:00
int64 End = time_get ( ) ;
str_format ( aBuf , sizeof ( aBuf ) , " initialisation finished after %.2fms " , ( ( End - Start ) * 1000 ) / ( float ) time_freq ( ) ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " gameclient " , aBuf ) ;
2019-04-11 22:46:54 +00:00
m_GameWorld . m_GameTickSpeed = SERVER_TICK_SPEED ;
m_GameWorld . m_pCollision = Collision ( ) ;
2019-04-21 22:38:24 +00:00
m_GameWorld . m_pTeams = & m_TeamsPredicted ;
2008-08-27 15:48:50 +00:00
}
2016-04-29 21:05:20 +00:00
void CGameClient : : OnUpdate ( )
2008-08-27 15:48:50 +00:00
{
// handle mouse movement
2010-10-13 10:47:42 +00:00
float x = 0.0f , y = 0.0f ;
2010-05-29 07:25:38 +00:00
Input ( ) - > MouseRelative ( & x , & y ) ;
2010-10-13 10:47:42 +00:00
if ( x ! = 0.0f | | y ! = 0.0f )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
for ( int h = 0 ; h < m_Input . m_Num ; h + + )
2008-09-12 07:20:26 +00:00
{
2010-05-29 07:25:38 +00:00
if ( m_Input . m_paComponents [ h ] - > OnMouseMove ( x , y ) )
2008-09-12 07:20:26 +00:00
break ;
}
2008-08-27 15:48:50 +00:00
}
2011-04-13 18:37:12 +00:00
2008-08-27 15:48:50 +00:00
// handle key presses
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < Input ( ) - > NumEvents ( ) ; i + + )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
IInput : : CEvent e = Input ( ) - > GetEvent ( i ) ;
2016-04-30 18:11:26 +00:00
if ( ! Input ( ) - > IsEventValid ( & e ) )
continue ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
for ( int h = 0 ; h < m_Input . m_Num ; h + + )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
if ( m_Input . m_paComponents [ h ] - > OnInput ( e ) )
2008-08-27 15:48:50 +00:00
break ;
}
}
}
2017-02-28 09:08:14 +00:00
void CGameClient : : OnDummySwap ( )
{
2018-03-13 20:55:47 +00:00
if ( g_Config . m_ClDummyResetOnSwitch )
2017-02-28 09:08:14 +00:00
{
m_pControls - > ResetInput ( ! g_Config . m_ClDummy ) ;
2017-03-06 18:45:39 +00:00
m_pControls - > m_InputData [ ! g_Config . m_ClDummy ] . m_Hook = 0 ;
2017-02-28 09:08:14 +00:00
}
2018-06-04 09:06:54 +00:00
int tmp = m_DummyInput . m_Fire ;
2017-02-28 09:08:14 +00:00
m_DummyInput = m_pControls - > m_InputData [ ! g_Config . m_ClDummy ] ;
2018-06-04 09:06:54 +00:00
m_pControls - > m_InputData [ g_Config . m_ClDummy ] . m_Fire = tmp ;
2017-02-28 09:08:14 +00:00
}
2008-08-27 15:48:50 +00:00
2017-02-28 09:08:14 +00:00
int CGameClient : : OnSnapInput ( int * pData , bool Dummy , bool Force )
2008-08-27 15:48:50 +00:00
{
2017-02-28 09:08:14 +00:00
m_LocalIDs [ g_Config . m_ClDummy ] = m_Snap . m_LocalClientID ;
2018-03-13 20:55:47 +00:00
if ( ! Dummy )
2017-02-28 09:08:14 +00:00
{
return m_pControls - > SnapInput ( pData ) ;
}
if ( ! g_Config . m_ClDummyHammer )
{
if ( m_DummyFire ! = 0 )
{
m_DummyInput . m_Fire = m_HammerInput . m_Fire ;
m_DummyFire = 0 ;
}
if ( ! Force & & ( ! m_DummyInput . m_Direction & & ! m_DummyInput . m_Jump & & ! m_DummyInput . m_Hook ) )
{
return 0 ;
}
mem_copy ( pData , & m_DummyInput , sizeof ( m_DummyInput ) ) ;
return sizeof ( m_DummyInput ) ;
}
else
{
if ( ( m_DummyFire / 12.5 ) - ( int ) ( m_DummyFire / 12.5 ) > 0.01 )
{
m_DummyFire + + ;
return 0 ;
}
m_DummyFire + + ;
m_HammerInput . m_Fire + = 2 ;
m_HammerInput . m_WantedWeapon = 1 ;
vec2 Main = m_LocalCharacterPos ;
vec2 Dummy = m_aClients [ m_LocalIDs [ ! g_Config . m_ClDummy ] ] . m_Predicted . m_Pos ;
vec2 Dir = Main - Dummy ;
2018-10-02 18:52:21 +00:00
m_HammerInput . m_TargetX = ( int ) ( Dir . x ) ;
m_HammerInput . m_TargetY = ( int ) ( Dir . y ) ;
2017-02-28 09:08:14 +00:00
mem_copy ( pData , & m_HammerInput , sizeof ( m_HammerInput ) ) ;
return sizeof ( m_HammerInput ) ;
}
2008-08-27 15:48:50 +00:00
}
2010-05-29 07:25:38 +00:00
void CGameClient : : OnConnected ( )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
m_Layers . Init ( Kernel ( ) ) ;
m_Collision . Init ( Layers ( ) ) ;
2011-04-13 18:37:12 +00:00
2013-12-20 11:27:10 +00:00
RenderTools ( ) - > RenderTilemapGenerateSkip ( Layers ( ) ) ;
2008-10-06 18:05:01 +00:00
2017-09-09 18:54:49 +00:00
CRaceHelper : : ms_aFlagIndex [ 0 ] = - 1 ;
CRaceHelper : : ms_aFlagIndex [ 1 ] = - 1 ;
CTile * pGameTiles = static_cast < CTile * > ( Layers ( ) - > Map ( ) - > GetData ( Layers ( ) - > GameLayer ( ) - > m_Data ) ) ;
// get flag positions
for ( int i = 0 ; i < m_Collision . GetWidth ( ) * m_Collision . GetHeight ( ) ; i + + )
{
if ( pGameTiles [ i ] . m_Index - ENTITY_OFFSET = = ENTITY_FLAGSTAND_RED )
CRaceHelper : : ms_aFlagIndex [ TEAM_RED ] = i ;
else if ( pGameTiles [ i ] . m_Index - ENTITY_OFFSET = = ENTITY_FLAGSTAND_BLUE )
CRaceHelper : : ms_aFlagIndex [ TEAM_BLUE ] = i ;
i + = pGameTiles [ i ] . m_Skip ;
}
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < m_All . m_Num ; i + + )
2008-10-08 18:19:45 +00:00
{
2010-05-29 07:25:38 +00:00
m_All . m_paComponents [ i ] - > OnMapLoad ( ) ;
m_All . m_paComponents [ i ] - > OnReset ( ) ;
2008-10-08 18:19:45 +00:00
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
CServerInfo CurrentServerInfo ;
Client ( ) - > GetServerInfo ( & CurrentServerInfo ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
m_ServerMode = SERVERMODE_PURE ;
2011-04-13 18:37:12 +00:00
2018-02-04 15:00:47 +00:00
// send the initial info
2010-05-29 07:25:38 +00:00
SendInfo ( true ) ;
2014-02-13 18:53:30 +00:00
// we should keep this in for now, because otherwise you can't spectate
// people at start as the other info 64 packet is only sent after the first
// snap
2014-06-22 13:30:15 +00:00
Client ( ) - > Rcon ( " crashmeplx " ) ;
2019-04-11 22:46:54 +00:00
m_GameWorld . Clear ( ) ;
m_GameWorld . m_WorldConfig . m_InfiniteAmmo = true ;
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
m_aLastWorldCharacters [ i ] . m_Alive = false ;
2008-08-27 15:48:50 +00:00
}
2010-05-29 07:25:38 +00:00
void CGameClient : : OnReset ( )
2008-08-27 15:48:50 +00:00
{
// clear out the invalid pointers
2014-05-23 21:59:26 +00:00
m_LastNewPredictedTick [ 0 ] = - 1 ;
m_LastNewPredictedTick [ 1 ] = - 1 ;
2010-05-29 07:25:38 +00:00
mem_zero ( & g_GameClient . m_Snap , sizeof ( g_GameClient . m_Snap ) ) ;
2008-08-27 15:48:50 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2011-03-22 21:41:27 +00:00
m_aClients [ i ] . Reset ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < m_All . m_Num ; i + + )
m_All . m_paComponents [ i ] - > OnReset ( ) ;
2011-01-06 03:46:10 +00:00
2015-07-26 16:21:51 +00:00
m_DemoSpecID = SPEC_FOLLOW ;
2011-07-05 21:15:24 +00:00
m_FlagDropTick [ TEAM_RED ] = 0 ;
m_FlagDropTick [ TEAM_BLUE ] = 0 ;
2015-05-20 20:23:58 +00:00
m_LastRoundStartTick = - 1 ;
m_LastFlagCarrierRed = - 4 ;
m_LastFlagCarrierBlue = - 4 ;
2014-04-30 14:02:28 +00:00
m_Tuning [ g_Config . m_ClDummy ] = CTuningParams ( ) ;
2011-08-13 00:11:06 +00:00
m_Teams . Reset ( ) ;
2014-04-27 11:44:04 +00:00
m_DDRaceMsgSent [ 0 ] = false ;
m_DDRaceMsgSent [ 1 ] = false ;
m_ShowOthers [ 0 ] = - 1 ;
m_ShowOthers [ 1 ] = - 1 ;
2008-08-27 15:48:50 +00:00
}
2011-03-10 09:08:14 +00:00
void CGameClient : : UpdatePositions ( )
2008-08-27 15:48:50 +00:00
{
2011-03-10 09:08:14 +00:00
// local character position
2010-05-29 07:25:38 +00:00
if ( g_Config . m_ClPredict & & Client ( ) - > State ( ) ! = IClient : : STATE_DEMOPLAYBACK )
2008-08-27 15:48:50 +00:00
{
2015-09-10 11:09:38 +00:00
if ( ! AntiPingPlayers ( ) )
2008-08-27 15:48:50 +00:00
{
2013-10-09 14:02:23 +00:00
if ( ! m_Snap . m_pLocalCharacter | | ( m_Snap . m_pGameInfoObj & & m_Snap . m_pGameInfoObj - > m_GameStateFlags & GAMESTATEFLAG_GAMEOVER ) )
{
// don't use predicted
}
else
m_LocalCharacterPos = mix ( m_PredictedPrevChar . m_Pos , m_PredictedChar . m_Pos , Client ( ) - > PredIntraGameTick ( ) ) ;
2008-08-27 15:48:50 +00:00
}
else
2013-10-09 14:02:23 +00:00
{
if ( ! ( m_Snap . m_pGameInfoObj & & m_Snap . m_pGameInfoObj - > m_GameStateFlags & GAMESTATEFLAG_GAMEOVER ) )
{
2018-03-13 20:55:47 +00:00
if ( m_Snap . m_pLocalCharacter )
2013-10-09 14:02:23 +00:00
m_LocalCharacterPos = mix ( m_PredictedPrevChar . m_Pos , m_PredictedChar . m_Pos , Client ( ) - > PredIntraGameTick ( ) ) ;
}
// else
// m_LocalCharacterPos = mix(m_PredictedPrevChar.m_Pos, m_PredictedChar.m_Pos, Client()->PredIntraGameTick());
}
2008-08-27 15:48:50 +00:00
}
2010-05-29 07:25:38 +00:00
else if ( m_Snap . m_pLocalCharacter & & m_Snap . m_pLocalPrevCharacter )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
m_LocalCharacterPos = mix (
vec2 ( m_Snap . m_pLocalPrevCharacter - > m_X , m_Snap . m_pLocalPrevCharacter - > m_Y ) ,
vec2 ( m_Snap . m_pLocalCharacter - > m_X , m_Snap . m_pLocalCharacter - > m_Y ) , Client ( ) - > IntraGameTick ( ) ) ;
2008-08-27 15:48:50 +00:00
}
2014-12-01 00:31:58 +00:00
2011-03-10 09:08:14 +00:00
// spectator position
2011-03-12 17:07:57 +00:00
if ( m_Snap . m_SpecInfo . m_Active )
2011-03-10 09:08:14 +00:00
{
2015-07-26 16:21:51 +00:00
if ( Client ( ) - > State ( ) = = IClient : : STATE_DEMOPLAYBACK & & m_DemoSpecID ! = SPEC_FOLLOW & & m_Snap . m_SpecInfo . m_SpectatorID ! = SPEC_FREEVIEW )
2011-03-12 17:07:57 +00:00
{
m_Snap . m_SpecInfo . m_Position = mix (
vec2 ( m_Snap . m_aCharacters [ m_Snap . m_SpecInfo . m_SpectatorID ] . m_Prev . m_X , m_Snap . m_aCharacters [ m_Snap . m_SpecInfo . m_SpectatorID ] . m_Prev . m_Y ) ,
vec2 ( m_Snap . m_aCharacters [ m_Snap . m_SpecInfo . m_SpectatorID ] . m_Cur . m_X , m_Snap . m_aCharacters [ m_Snap . m_SpecInfo . m_SpectatorID ] . m_Cur . m_Y ) ,
Client ( ) - > IntraGameTick ( ) ) ;
m_Snap . m_SpecInfo . m_UsePosition = true ;
}
2015-07-26 16:21:51 +00:00
else if ( m_Snap . m_pSpectatorInfo & & ( ( Client ( ) - > State ( ) = = IClient : : STATE_DEMOPLAYBACK & & m_DemoSpecID = = SPEC_FOLLOW ) | | ( Client ( ) - > State ( ) ! = IClient : : STATE_DEMOPLAYBACK & & m_Snap . m_SpecInfo . m_SpectatorID ! = SPEC_FREEVIEW ) ) )
2011-03-12 17:07:57 +00:00
{
if ( m_Snap . m_pPrevSpectatorInfo )
m_Snap . m_SpecInfo . m_Position = mix ( vec2 ( m_Snap . m_pPrevSpectatorInfo - > m_X , m_Snap . m_pPrevSpectatorInfo - > m_Y ) ,
vec2 ( m_Snap . m_pSpectatorInfo - > m_X , m_Snap . m_pSpectatorInfo - > m_Y ) , Client ( ) - > IntraGameTick ( ) ) ;
else
m_Snap . m_SpecInfo . m_Position = vec2 ( m_Snap . m_pSpectatorInfo - > m_X , m_Snap . m_pSpectatorInfo - > m_Y ) ;
m_Snap . m_SpecInfo . m_UsePosition = true ;
}
2011-03-10 09:08:14 +00:00
}
2019-04-11 22:46:54 +00:00
UpdateRenderedCharacters ( ) ;
2008-08-27 15:48:50 +00:00
}
2008-10-06 18:05:01 +00:00
2010-05-29 07:25:38 +00:00
static void Evolve ( CNetObj_Character * pCharacter , int Tick )
2008-10-06 18:05:01 +00:00
{
2010-05-29 07:25:38 +00:00
CWorldCore TempWorld ;
CCharacterCore TempCore ;
2010-09-30 20:31:11 +00:00
CTeamsCore TempTeams ;
2010-05-29 07:25:38 +00:00
mem_zero ( & TempCore , sizeof ( TempCore ) ) ;
2011-01-06 03:46:10 +00:00
mem_zero ( & TempTeams , sizeof ( TempTeams ) ) ;
2010-09-30 20:31:11 +00:00
TempCore . Init ( & TempWorld , g_GameClient . Collision ( ) , & TempTeams ) ;
2010-05-29 07:25:38 +00:00
TempCore . Read ( pCharacter ) ;
2014-04-14 08:56:14 +00:00
TempCore . m_ActiveWeapon = pCharacter - > m_Weapon ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
while ( pCharacter - > m_Tick < Tick )
2008-10-06 18:05:01 +00:00
{
2010-05-29 07:25:38 +00:00
pCharacter - > m_Tick + + ;
2019-04-11 22:46:54 +00:00
TempCore . Tick ( false ) ;
2018-08-22 06:33:21 +00:00
TempCore . Move ( ) ;
2010-05-29 07:25:38 +00:00
TempCore . Quantize ( ) ;
2008-10-06 18:05:01 +00:00
}
2008-11-16 15:10:57 +00:00
2010-05-29 07:25:38 +00:00
TempCore . Write ( pCharacter ) ;
2008-10-06 18:05:01 +00:00
}
2010-05-29 07:25:38 +00:00
void CGameClient : : OnRender ( )
2008-08-27 15:48:50 +00:00
{
2011-03-10 09:08:14 +00:00
// update the local character and spectate position
UpdatePositions ( ) ;
2011-04-13 18:37:12 +00:00
2008-08-27 15:48:50 +00:00
// render all systems
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < m_All . m_Num ; i + + )
m_All . m_paComponents [ i ] - > OnRender ( ) ;
2011-04-13 18:37:12 +00:00
2016-04-30 18:11:26 +00:00
// clear all events/input for this frame
Input ( ) - > Clear ( ) ;
2009-01-11 15:51:43 +00:00
// clear new tick flags
2010-05-29 07:25:38 +00:00
m_NewTick = false ;
m_NewPredictedTick = false ;
2014-04-28 13:34:56 +00:00
if ( g_Config . m_ClDummy & & ! Client ( ) - > DummyConnected ( ) )
g_Config . m_ClDummy = 0 ;
2015-04-19 11:11:45 +00:00
// resend player and dummy info if it was filtered by server
if ( Client ( ) - > State ( ) = = IClient : : STATE_ONLINE & & ! m_pMenus - > IsActive ( ) ) {
2015-04-19 12:03:40 +00:00
if ( m_CheckInfo [ 0 ] = = 0 ) {
2015-04-19 11:11:45 +00:00
if (
2017-02-28 09:08:14 +00:00
str_comp ( m_aClients [ m_LocalIDs [ 0 ] ] . m_aName , g_Config . m_PlayerName ) | |
str_comp ( m_aClients [ m_LocalIDs [ 0 ] ] . m_aClan , g_Config . m_PlayerClan ) | |
m_aClients [ m_LocalIDs [ 0 ] ] . m_Country ! = g_Config . m_PlayerCountry | |
str_comp ( m_aClients [ m_LocalIDs [ 0 ] ] . m_aSkinName , g_Config . m_ClPlayerSkin ) | |
m_aClients [ m_LocalIDs [ 0 ] ] . m_UseCustomColor ! = g_Config . m_ClPlayerUseCustomColor | |
m_aClients [ m_LocalIDs [ 0 ] ] . m_ColorBody ! = g_Config . m_ClPlayerColorBody | |
m_aClients [ m_LocalIDs [ 0 ] ] . m_ColorFeet ! = g_Config . m_ClPlayerColorFeet
2015-04-19 11:11:45 +00:00
)
2014-04-28 13:19:57 +00:00
SendInfo ( false ) ;
2015-04-19 11:11:45 +00:00
else
2015-04-19 12:03:40 +00:00
m_CheckInfo [ 0 ] = - 1 ;
2015-04-19 11:11:45 +00:00
}
2015-04-19 12:03:40 +00:00
if ( m_CheckInfo [ 0 ] > 0 )
m_CheckInfo [ 0 ] - - ;
2015-04-19 11:11:45 +00:00
if ( Client ( ) - > DummyConnected ( ) ) {
2015-04-19 12:03:40 +00:00
if ( m_CheckInfo [ 1 ] = = 0 ) {
2015-04-19 11:11:45 +00:00
if (
2017-02-28 09:08:14 +00:00
str_comp ( m_aClients [ m_LocalIDs [ 1 ] ] . m_aName , g_Config . m_ClDummyName ) | |
str_comp ( m_aClients [ m_LocalIDs [ 1 ] ] . m_aClan , g_Config . m_ClDummyClan ) | |
m_aClients [ m_LocalIDs [ 1 ] ] . m_Country ! = g_Config . m_ClDummyCountry | |
str_comp ( m_aClients [ m_LocalIDs [ 1 ] ] . m_aSkinName , g_Config . m_ClDummySkin ) | |
m_aClients [ m_LocalIDs [ 1 ] ] . m_UseCustomColor ! = g_Config . m_ClDummyUseCustomColor | |
m_aClients [ m_LocalIDs [ 1 ] ] . m_ColorBody ! = g_Config . m_ClDummyColorBody | |
m_aClients [ m_LocalIDs [ 1 ] ] . m_ColorFeet ! = g_Config . m_ClDummyColorFeet
2015-04-19 11:11:45 +00:00
)
SendDummyInfo ( false ) ;
else
2015-04-19 12:03:40 +00:00
m_CheckInfo [ 1 ] = - 1 ;
2015-04-19 11:11:45 +00:00
}
2015-04-19 12:03:40 +00:00
if ( m_CheckInfo [ 1 ] > 0 )
m_CheckInfo [ 1 ] - - ;
2010-05-29 07:25:38 +00:00
}
}
2008-08-27 15:48:50 +00:00
}
2014-04-28 14:47:44 +00:00
void CGameClient : : OnDummyDisconnect ( )
{
m_DDRaceMsgSent [ 1 ] = false ;
m_ShowOthers [ 1 ] = - 1 ;
2014-05-23 21:59:26 +00:00
m_LastNewPredictedTick [ 1 ] = - 1 ;
2014-04-28 14:47:44 +00:00
}
2019-03-25 19:02:50 +00:00
int CGameClient : : GetLastRaceTick ( )
{
return m_pGhost - > GetLastRaceTick ( ) ;
}
2010-09-12 10:43:03 +00:00
void CGameClient : : OnRelease ( )
{
// release all systems
for ( int i = 0 ; i < m_All . m_Num ; i + + )
m_All . m_paComponents [ i ] - > OnRelease ( ) ;
}
2014-05-03 00:30:05 +00:00
void CGameClient : : OnMessage ( int MsgId , CUnpacker * pUnpacker , bool IsDummy )
2008-08-27 15:48:50 +00:00
{
2008-08-29 05:34:18 +00:00
// special messages
2014-05-03 00:30:05 +00:00
if ( MsgId = = NETMSGTYPE_SV_EXTRAPROJECTILE & & ! IsDummy )
2008-08-29 05:34:18 +00:00
{
2011-04-03 08:11:23 +00:00
int Num = pUnpacker - > GetInt ( ) ;
2011-04-13 18:37:12 +00:00
2011-04-03 08:11:23 +00:00
for ( int k = 0 ; k < Num ; k + + )
2008-08-29 05:34:18 +00:00
{
2011-04-03 08:11:23 +00:00
CNetObj_Projectile Proj ;
for ( unsigned i = 0 ; i < sizeof ( CNetObj_Projectile ) / sizeof ( int ) ; i + + )
( ( int * ) & Proj ) [ i ] = pUnpacker - > GetInt ( ) ;
2011-04-13 18:37:12 +00:00
2011-04-03 08:11:23 +00:00
if ( pUnpacker - > Error ( ) )
2008-08-29 05:34:18 +00:00
return ;
2011-04-13 18:37:12 +00:00
2011-04-03 08:11:23 +00:00
g_GameClient . m_pItems - > AddExtraProjectile ( & Proj ) ;
2008-08-29 05:34:18 +00:00
}
2011-04-13 18:37:12 +00:00
2011-04-03 08:11:23 +00:00
return ;
2008-08-29 05:34:18 +00:00
}
2010-05-29 07:25:38 +00:00
else if ( MsgId = = NETMSGTYPE_SV_TUNEPARAMS )
2008-08-29 05:34:18 +00:00
{
// unpack the new tuning
2010-05-29 07:25:38 +00:00
CTuningParams NewTuning ;
int * pParams = ( int * ) & NewTuning ;
2015-01-09 21:18:11 +00:00
// No jetpack on DDNet incompatible servers:
NewTuning . m_JetpackStrength = 0 ;
2010-05-29 07:25:38 +00:00
for ( unsigned i = 0 ; i < sizeof ( CTuningParams ) / sizeof ( int ) ; i + + )
2014-04-12 09:12:29 +00:00
{
2014-12-27 11:05:02 +00:00
int value = pUnpacker - > GetInt ( ) ;
2008-08-29 05:34:18 +00:00
2014-04-12 09:12:29 +00:00
// check for unpacking errors
if ( pUnpacker - > Error ( ) )
break ;
2014-12-27 11:05:02 +00:00
pParams [ i ] = value ;
2014-04-12 09:12:29 +00:00
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
m_ServerMode = SERVERMODE_PURE ;
2011-04-13 18:37:12 +00:00
2008-08-29 05:34:18 +00:00
// apply new tuning
2014-05-03 00:30:05 +00:00
m_Tuning [ IsDummy ? ! g_Config . m_ClDummy : g_Config . m_ClDummy ] = NewTuning ;
2008-08-29 05:34:18 +00:00
return ;
}
2014-12-01 00:31:58 +00:00
2010-05-29 07:25:38 +00:00
void * pRawMsg = m_NetObjHandler . SecureUnpackMsg ( MsgId , pUnpacker ) ;
if ( ! pRawMsg )
2008-08-27 15:48:50 +00:00
{
2010-08-17 22:06:00 +00:00
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " dropped weird message '%s' (%d), failed on '%s' " , m_NetObjHandler . GetMsgName ( MsgId ) , MsgId , m_NetObjHandler . FailedMsgOn ( ) ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " client " , aBuf ) ;
2008-08-27 15:48:50 +00:00
return ;
}
2014-05-07 01:34:21 +00:00
if ( IsDummy )
{
if ( MsgId = = NETMSGTYPE_SV_CHAT
2017-02-28 09:08:14 +00:00
& & m_LocalIDs [ 0 ] > = 0
& & m_LocalIDs [ 1 ] > = 0 )
2014-05-07 01:34:21 +00:00
{
CNetMsg_Sv_Chat * pMsg = ( CNetMsg_Sv_Chat * ) pRawMsg ;
if ( ( pMsg - > m_Team = = 1
2017-02-28 09:08:14 +00:00
& & ( m_aClients [ m_LocalIDs [ 0 ] ] . m_Team ! = m_aClients [ m_LocalIDs [ 1 ] ] . m_Team
| | m_Teams . Team ( m_LocalIDs [ 0 ] ) ! = m_Teams . Team ( m_LocalIDs [ 1 ] ) ) )
2014-05-07 01:34:21 +00:00
| | pMsg - > m_Team > 1 )
{
m_pChat - > OnMessage ( MsgId , pRawMsg ) ;
}
}
return ; // no need of all that stuff for the dummy
}
2008-08-27 15:48:50 +00:00
// TODO: this should be done smarter
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < m_All . m_Num ; i + + )
m_All . m_paComponents [ i ] - > OnMessage ( MsgId , pRawMsg ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
if ( MsgId = = NETMSGTYPE_SV_READYTOENTER )
2008-08-27 20:17:04 +00:00
{
2010-05-29 07:25:38 +00:00
Client ( ) - > EnterGame ( ) ;
2008-08-27 20:17:04 +00:00
}
2018-03-13 20:55:47 +00:00
else if ( MsgId = = NETMSGTYPE_SV_EMOTICON )
2008-08-27 20:17:04 +00:00
{
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_Emoticon * pMsg = ( CNetMsg_Sv_Emoticon * ) pRawMsg ;
2008-08-27 20:17:04 +00:00
// apply
2011-02-12 10:40:36 +00:00
m_aClients [ pMsg - > m_ClientID ] . m_Emoticon = pMsg - > m_Emoticon ;
m_aClients [ pMsg - > m_ClientID ] . m_EmoticonStart = Client ( ) - > GameTick ( ) ;
2008-08-27 20:17:04 +00:00
}
2010-05-29 07:25:38 +00:00
else if ( MsgId = = NETMSGTYPE_SV_SOUNDGLOBAL )
2008-08-27 20:17:04 +00:00
{
2010-05-29 07:25:38 +00:00
if ( m_SuppressEvents )
2009-01-11 15:51:43 +00:00
return ;
2011-04-13 18:37:12 +00:00
2010-07-17 17:55:17 +00:00
// don't enqueue pseudo-global sounds from demos (created by PlayAndRecord)
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_SoundGlobal * pMsg = ( CNetMsg_Sv_SoundGlobal * ) pRawMsg ;
2011-02-12 10:40:36 +00:00
if ( pMsg - > m_SoundID = = SOUND_CTF_DROP | | pMsg - > m_SoundID = = SOUND_CTF_RETURN | |
pMsg - > m_SoundID = = SOUND_CTF_CAPTURE | | pMsg - > m_SoundID = = SOUND_CTF_GRAB_EN | |
pMsg - > m_SoundID = = SOUND_CTF_GRAB_PL )
2014-10-25 00:52:08 +00:00
{
if ( g_Config . m_SndGame )
g_GameClient . m_pSounds - > Enqueue ( CSounds : : CHN_GLOBAL , pMsg - > m_SoundID ) ;
}
2010-07-17 17:55:17 +00:00
else
2014-10-25 00:52:08 +00:00
{
if ( g_Config . m_SndGame )
g_GameClient . m_pSounds - > Play ( CSounds : : CHN_GLOBAL , pMsg - > m_SoundID , 1.0f ) ;
}
2011-04-13 18:37:12 +00:00
}
2014-01-21 23:08:30 +00:00
else if ( MsgId = = NETMSGTYPE_SV_TEAMSSTATE )
2011-01-06 05:30:19 +00:00
{
2014-01-21 23:08:30 +00:00
unsigned int i ;
for ( i = 0 ; i < MAX_CLIENTS ; i + + )
{
2014-02-08 22:41:12 +00:00
int Team = pUnpacker - > GetInt ( ) ;
bool WentWrong = false ;
2014-01-21 23:08:30 +00:00
if ( pUnpacker - > Error ( ) )
2014-02-08 22:41:12 +00:00
WentWrong = true ;
if ( ! WentWrong & & Team > = 0 & & Team < MAX_CLIENTS )
m_Teams . Team ( i , Team ) ;
2018-03-13 20:55:47 +00:00
else if ( Team ! = MAX_CLIENTS )
2014-02-08 22:41:12 +00:00
WentWrong = true ;
if ( WentWrong )
2014-01-21 23:08:30 +00:00
{
m_Teams . Team ( i , 0 ) ;
break ;
}
}
2018-03-13 20:55:47 +00:00
if ( i < = 16 )
2014-01-21 23:08:30 +00:00
m_Teams . m_IsDDRace16 = true ;
2017-09-09 19:38:41 +00:00
2017-09-12 20:54:29 +00:00
m_pGhost - > m_AllowRestart = true ;
m_pRaceDemo - > m_AllowRestart = true ;
2011-01-06 05:30:19 +00:00
}
else if ( MsgId = = NETMSGTYPE_SV_PLAYERTIME )
{
2010-11-04 16:39:04 +00:00
CNetMsg_Sv_PlayerTime * pMsg = ( CNetMsg_Sv_PlayerTime * ) pRawMsg ;
2011-02-13 05:35:13 +00:00
m_aClients [ pMsg - > m_ClientID ] . m_Score = pMsg - > m_Time ;
2010-10-24 10:47:25 +00:00
}
2019-04-11 22:46:54 +00:00
else if ( MsgId = = NETMSGTYPE_SV_KILLMSG )
{
CNetMsg_Sv_KillMsg * pMsg = ( CNetMsg_Sv_KillMsg * ) pRawMsg ;
// reset character prediction
if ( ! ( m_GameWorld . m_WorldConfig . m_IsFNG & & pMsg - > m_Weapon = = WEAPON_RIFLE ) )
{
m_CharOrder . GiveWeak ( pMsg - > m_Victim ) ;
m_aLastWorldCharacters [ pMsg - > m_Victim ] . m_Alive = false ;
m_GameWorld . ReleaseHooked ( pMsg - > m_Victim ) ;
}
}
2008-08-27 15:48:50 +00:00
}
2010-05-29 07:25:38 +00:00
void CGameClient : : OnStateChange ( int NewState , int OldState )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
// reset everything when not already connected (to keep gathered stuff)
if ( NewState < IClient : : STATE_ONLINE )
OnReset ( ) ;
2011-04-13 18:37:12 +00:00
2008-10-17 11:23:21 +00:00
// then change the state
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < m_All . m_Num ; i + + )
m_All . m_paComponents [ i ] - > OnStateChange ( NewState , OldState ) ;
2008-08-27 15:48:50 +00:00
}
2011-02-04 17:25:04 +00:00
void CGameClient : : OnShutdown ( )
{
2017-09-09 21:10:42 +00:00
m_pRaceDemo - > OnReset ( ) ;
2017-09-09 16:25:32 +00:00
m_pGhost - > OnReset ( ) ;
2011-02-04 17:25:04 +00:00
}
2014-09-03 12:17:44 +00:00
void CGameClient : : OnEnterGame ( )
{
g_GameClient . m_pEffects - > ResetDamageIndicator ( ) ;
}
2008-08-27 15:48:50 +00:00
2010-12-12 15:48:13 +00:00
void CGameClient : : OnGameOver ( )
{
2012-04-19 23:04:12 +00:00
if ( Client ( ) - > State ( ) ! = IClient : : STATE_DEMOPLAYBACK & & g_Config . m_ClEditor = = 0 )
2010-12-12 15:48:13 +00:00
Client ( ) - > AutoScreenshot_Start ( ) ;
}
2011-01-06 22:21:51 +00:00
void CGameClient : : OnStartGame ( )
{
if ( Client ( ) - > State ( ) ! = IClient : : STATE_DEMOPLAYBACK )
Client ( ) - > DemoRecorder_HandleAutoStart ( ) ;
2015-05-21 09:41:59 +00:00
m_pStatboard - > OnReset ( ) ;
2015-05-20 20:23:58 +00:00
}
void CGameClient : : OnFlagGrab ( int TeamID )
{
if ( TeamID = = TEAM_RED )
m_aStats [ m_Snap . m_pGameDataObj - > m_FlagCarrierRed ] . m_FlagGrabs + + ;
else
m_aStats [ m_Snap . m_pGameDataObj - > m_FlagCarrierBlue ] . m_FlagGrabs + + ;
2011-01-06 22:21:51 +00:00
}
2018-03-21 14:54:51 +00:00
void CGameClient : : OnWindowResize ( )
{
for ( int i = 0 ; i < m_All . m_Num ; i + + )
m_All . m_paComponents [ i ] - > OnWindowResize ( ) ;
TextRender ( ) - > OnWindowResize ( ) ;
}
void CGameClient : : OnWindowResizeCB ( void * pUser )
{
CGameClient * pClient = ( CGameClient * ) pUser ;
pClient - > OnWindowResize ( ) ;
}
2017-07-24 19:43:55 +00:00
void CGameClient : : OnRconType ( bool UsernameReq )
{
m_pGameConsole - > RequireUsername ( UsernameReq ) ;
}
2010-05-29 07:25:38 +00:00
void CGameClient : : OnRconLine ( const char * pLine )
{
2010-11-17 12:01:46 +00:00
m_pGameConsole - > PrintLine ( CGameConsole : : CONSOLETYPE_REMOTE , pLine ) ;
2010-05-29 07:25:38 +00:00
}
2008-08-27 15:48:50 +00:00
2019-01-11 14:08:40 +00:00
void CGameClient : : OnTimeScore ( int AllowTimeScore , bool Dummy )
2018-11-24 13:56:03 +00:00
{
2019-01-11 14:08:40 +00:00
m_AllowTimeScore [ Dummy ] = AllowTimeScore ;
2018-11-24 13:56:03 +00:00
}
2010-05-29 07:25:38 +00:00
void CGameClient : : ProcessEvents ( )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
if ( m_SuppressEvents )
2008-12-19 11:41:17 +00:00
return ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
int SnapType = IClient : : SNAP_CURRENT ;
int Num = Client ( ) - > SnapNumItems ( SnapType ) ;
for ( int Index = 0 ; Index < Num ; Index + + )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
IClient : : CSnapItem Item ;
const void * pData = Client ( ) - > SnapGetItem ( SnapType , Index , & Item ) ;
2008-08-27 15:48:50 +00:00
2010-05-29 07:25:38 +00:00
if ( Item . m_Type = = NETEVENTTYPE_DAMAGEIND )
2008-08-27 15:48:50 +00:00
{
2011-06-01 17:43:48 +00:00
CNetEvent_DamageInd * ev = ( CNetEvent_DamageInd * ) pData ;
2010-05-29 07:25:38 +00:00
g_GameClient . m_pEffects - > DamageIndicator ( vec2 ( ev - > m_X , ev - > m_Y ) , GetDirection ( ev - > m_Angle ) ) ;
2008-08-27 15:48:50 +00:00
}
2010-05-29 07:25:38 +00:00
else if ( Item . m_Type = = NETEVENTTYPE_EXPLOSION )
2008-08-27 15:48:50 +00:00
{
2011-06-01 17:43:48 +00:00
CNetEvent_Explosion * ev = ( CNetEvent_Explosion * ) pData ;
2010-05-29 07:25:38 +00:00
g_GameClient . m_pEffects - > Explosion ( vec2 ( ev - > m_X , ev - > m_Y ) ) ;
2008-08-27 15:48:50 +00:00
}
2010-05-29 07:25:38 +00:00
else if ( Item . m_Type = = NETEVENTTYPE_HAMMERHIT )
2008-10-17 11:23:21 +00:00
{
2011-06-01 17:43:48 +00:00
CNetEvent_HammerHit * ev = ( CNetEvent_HammerHit * ) pData ;
2010-05-29 07:25:38 +00:00
g_GameClient . m_pEffects - > HammerHit ( vec2 ( ev - > m_X , ev - > m_Y ) ) ;
2008-10-17 11:23:21 +00:00
}
2010-05-29 07:25:38 +00:00
else if ( Item . m_Type = = NETEVENTTYPE_SPAWN )
2008-08-27 15:48:50 +00:00
{
2011-06-01 17:43:48 +00:00
CNetEvent_Spawn * ev = ( CNetEvent_Spawn * ) pData ;
2010-05-29 07:25:38 +00:00
g_GameClient . m_pEffects - > PlayerSpawn ( vec2 ( ev - > m_X , ev - > m_Y ) ) ;
2008-08-27 15:48:50 +00:00
}
2010-05-29 07:25:38 +00:00
else if ( Item . m_Type = = NETEVENTTYPE_DEATH )
2008-08-27 15:48:50 +00:00
{
2011-06-01 17:43:48 +00:00
CNetEvent_Death * ev = ( CNetEvent_Death * ) pData ;
2011-02-12 10:40:36 +00:00
g_GameClient . m_pEffects - > PlayerDeath ( vec2 ( ev - > m_X , ev - > m_Y ) , ev - > m_ClientID ) ;
2008-08-27 15:48:50 +00:00
}
2010-05-29 07:25:38 +00:00
else if ( Item . m_Type = = NETEVENTTYPE_SOUNDWORLD )
2008-08-27 15:48:50 +00:00
{
2011-06-01 17:43:48 +00:00
CNetEvent_SoundWorld * ev = ( CNetEvent_SoundWorld * ) pData ;
2017-06-06 16:58:23 +00:00
if ( g_Config . m_SndGame & & ( ev - > m_SoundID ! = SOUND_GUN_FIRE | | g_Config . m_SndGun ) & & ( ev - > m_SoundID ! = SOUND_PLAYER_PAIN_LONG | | g_Config . m_SndLongPain ) )
2014-10-25 00:52:08 +00:00
g_GameClient . m_pSounds - > PlayAt ( CSounds : : CHN_WORLD , ev - > m_SoundID , 1.0f , vec2 ( ev - > m_X , ev - > m_Y ) ) ;
2008-08-27 15:48:50 +00:00
}
}
}
2010-05-29 07:25:38 +00:00
void CGameClient : : OnNewSnapshot ( )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
m_NewTick = true ;
2011-04-13 18:37:12 +00:00
2008-08-27 15:48:50 +00:00
// clear out the invalid pointers
2010-05-29 07:25:38 +00:00
mem_zero ( & g_GameClient . m_Snap , sizeof ( g_GameClient . m_Snap ) ) ;
2011-02-12 10:40:36 +00:00
m_Snap . m_LocalClientID = - 1 ;
2008-08-27 15:48:50 +00:00
// secure snapshot
{
2010-05-29 07:25:38 +00:00
int Num = Client ( ) - > SnapNumItems ( IClient : : SNAP_CURRENT ) ;
for ( int Index = 0 ; Index < Num ; Index + + )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
IClient : : CSnapItem Item ;
void * pData = Client ( ) - > SnapGetItem ( IClient : : SNAP_CURRENT , Index , & Item ) ;
if ( m_NetObjHandler . ValidateObj ( Item . m_Type , pData , Item . m_DataSize ) ! = 0 )
2008-08-27 15:48:50 +00:00
{
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-02-12 10:40:36 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " invalidated index=%d type=%d (%s) size=%d id=%d " , Index , Item . m_Type , m_NetObjHandler . GetObjName ( Item . m_Type ) , Item . m_DataSize , Item . m_ID ) ;
2010-08-17 22:06:00 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " game " , aBuf ) ;
}
2010-05-29 07:25:38 +00:00
Client ( ) - > SnapInvalidateItem ( IClient : : SNAP_CURRENT , Index ) ;
2008-08-27 15:48:50 +00:00
}
}
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
ProcessEvents ( ) ;
2008-08-27 15:48:50 +00:00
2017-06-02 18:45:09 +00:00
# ifdef CONF_DEBUG
2010-05-29 07:25:38 +00:00
if ( g_Config . m_DbgStress )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
if ( ( Client ( ) - > GameTick ( ) % 100 ) = = 0 )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
char aMessage [ 64 ] ;
int MsgLen = rand ( ) % ( sizeof ( aMessage ) - 1 ) ;
for ( int i = 0 ; i < MsgLen ; i + + )
2018-10-02 18:52:21 +00:00
aMessage [ i ] = ( char ) ( ' a ' + ( rand ( ) % ( ' z ' - ' a ' ) ) ) ;
2010-05-29 07:25:38 +00:00
aMessage [ MsgLen ] = 0 ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
CNetMsg_Cl_Say Msg ;
Msg . m_Team = rand ( ) & 1 ;
Msg . m_pMessage = aMessage ;
Client ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL ) ;
2008-08-27 15:48:50 +00:00
}
}
2017-06-02 18:45:09 +00:00
# endif
2008-08-27 15:48:50 +00:00
2008-09-23 07:43:41 +00:00
// go trough all the items in the snapshot and gather the info we want
2008-08-27 15:48:50 +00:00
{
2011-01-03 11:50:38 +00:00
m_Snap . m_aTeamSize [ TEAM_RED ] = m_Snap . m_aTeamSize [ TEAM_BLUE ] = 0 ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
int Num = Client ( ) - > SnapNumItems ( IClient : : SNAP_CURRENT ) ;
for ( int i = 0 ; i < Num ; i + + )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
IClient : : CSnapItem Item ;
const void * pData = Client ( ) - > SnapGetItem ( IClient : : SNAP_CURRENT , i , & Item ) ;
2008-08-27 15:48:50 +00:00
2010-05-29 07:25:38 +00:00
if ( Item . m_Type = = NETOBJTYPE_CLIENTINFO )
2008-10-08 20:47:56 +00:00
{
2010-05-29 07:25:38 +00:00
const CNetObj_ClientInfo * pInfo = ( const CNetObj_ClientInfo * ) pData ;
2011-02-12 10:40:36 +00:00
int ClientID = Item . m_ID ;
2011-03-15 10:23:49 +00:00
IntsToStr ( & pInfo - > m_Name0 , 4 , m_aClients [ ClientID ] . m_aName ) ;
IntsToStr ( & pInfo - > m_Clan0 , 3 , m_aClients [ ClientID ] . m_aClan ) ;
2011-06-29 20:27:32 +00:00
m_aClients [ ClientID ] . m_Country = pInfo - > m_Country ;
2011-02-12 10:40:36 +00:00
IntsToStr ( & pInfo - > m_Skin0 , 6 , m_aClients [ ClientID ] . m_aSkinName ) ;
2011-04-13 18:37:12 +00:00
2011-02-12 10:40:36 +00:00
m_aClients [ ClientID ] . m_UseCustomColor = pInfo - > m_UseCustomColor ;
m_aClients [ ClientID ] . m_ColorBody = pInfo - > m_ColorBody ;
m_aClients [ ClientID ] . m_ColorFeet = pInfo - > m_ColorFeet ;
2011-04-13 18:37:12 +00:00
2008-10-08 20:47:56 +00:00
// prepare the info
2011-02-12 10:40:36 +00:00
if ( m_aClients [ ClientID ] . m_aSkinName [ 0 ] = = ' x ' | | m_aClients [ ClientID ] . m_aSkinName [ 1 ] = = ' _ ' )
str_copy ( m_aClients [ ClientID ] . m_aSkinName , " default " , 64 ) ;
2011-04-13 18:37:12 +00:00
2011-02-12 10:40:36 +00:00
m_aClients [ ClientID ] . m_SkinInfo . m_ColorBody = m_pSkins - > GetColorV4 ( m_aClients [ ClientID ] . m_ColorBody ) ;
m_aClients [ ClientID ] . m_SkinInfo . m_ColorFeet = m_pSkins - > GetColorV4 ( m_aClients [ ClientID ] . m_ColorFeet ) ;
m_aClients [ ClientID ] . m_SkinInfo . m_Size = 64 ;
2011-04-13 18:37:12 +00:00
2008-10-08 20:47:56 +00:00
// find new skin
2015-03-14 11:30:17 +00:00
m_aClients [ ClientID ] . m_SkinID = g_GameClient . m_pSkins - > Find ( m_aClients [ ClientID ] . m_aSkinName ) ;
2011-04-13 18:37:12 +00:00
2011-02-12 10:40:36 +00:00
if ( m_aClients [ ClientID ] . m_UseCustomColor )
m_aClients [ ClientID ] . m_SkinInfo . m_Texture = g_GameClient . m_pSkins - > Get ( m_aClients [ ClientID ] . m_SkinID ) - > m_ColorTexture ;
2008-10-08 20:47:56 +00:00
else
{
2011-02-12 10:40:36 +00:00
m_aClients [ ClientID ] . m_SkinInfo . m_Texture = g_GameClient . m_pSkins - > Get ( m_aClients [ ClientID ] . m_SkinID ) - > m_OrgTexture ;
m_aClients [ ClientID ] . m_SkinInfo . m_ColorBody = vec4 ( 1 , 1 , 1 , 1 ) ;
m_aClients [ ClientID ] . m_SkinInfo . m_ColorFeet = vec4 ( 1 , 1 , 1 , 1 ) ;
2008-10-08 20:47:56 +00:00
}
2011-02-12 10:40:36 +00:00
m_aClients [ ClientID ] . UpdateRenderInfo ( ) ;
2011-04-13 18:37:12 +00:00
2008-10-08 20:47:56 +00:00
}
2010-05-29 07:25:38 +00:00
else if ( Item . m_Type = = NETOBJTYPE_PLAYERINFO )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
const CNetObj_PlayerInfo * pInfo = ( const CNetObj_PlayerInfo * ) pData ;
2011-04-13 18:37:12 +00:00
2011-02-12 10:40:36 +00:00
m_aClients [ pInfo - > m_ClientID ] . m_Team = pInfo - > m_Team ;
2011-03-22 21:41:27 +00:00
m_aClients [ pInfo - > m_ClientID ] . m_Active = true ;
2011-02-12 10:40:36 +00:00
m_Snap . m_paPlayerInfos [ pInfo - > m_ClientID ] = pInfo ;
2011-03-22 21:41:27 +00:00
m_Snap . m_NumPlayers + + ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
if ( pInfo - > m_Local )
2008-08-27 15:48:50 +00:00
{
2011-02-12 10:40:36 +00:00
m_Snap . m_LocalClientID = Item . m_ID ;
2010-05-29 07:25:38 +00:00
m_Snap . m_pLocalInfo = pInfo ;
2011-04-13 18:37:12 +00:00
2011-01-03 11:50:38 +00:00
if ( pInfo - > m_Team = = TEAM_SPECTATORS )
2011-03-12 17:07:57 +00:00
{
m_Snap . m_SpecInfo . m_Active = true ;
m_Snap . m_SpecInfo . m_SpectatorID = SPEC_FREEVIEW ;
}
2008-08-27 15:48:50 +00:00
}
2011-04-13 18:37:12 +00:00
2008-09-01 18:17:01 +00:00
// calculate team-balance
2011-01-03 11:50:38 +00:00
if ( pInfo - > m_Team ! = TEAM_SPECTATORS )
2015-05-19 22:51:02 +00:00
{
2010-05-29 07:25:38 +00:00
m_Snap . m_aTeamSize [ pInfo - > m_Team ] + + ;
2017-02-15 15:43:45 +00:00
if ( ! m_aStats [ pInfo - > m_ClientID ] . IsActive ( ) )
m_aStats [ pInfo - > m_ClientID ] . JoinGame ( Client ( ) - > GameTick ( ) ) ;
2015-05-19 22:51:02 +00:00
}
2017-02-15 15:43:45 +00:00
else if ( m_aStats [ pInfo - > m_ClientID ] . IsActive ( ) )
m_aStats [ pInfo - > m_ClientID ] . JoinSpec ( Client ( ) - > GameTick ( ) ) ;
2011-04-13 18:37:12 +00:00
2008-08-27 15:48:50 +00:00
}
2010-05-29 07:25:38 +00:00
else if ( Item . m_Type = = NETOBJTYPE_CHARACTER )
2008-08-27 15:48:50 +00:00
{
2011-02-12 10:40:36 +00:00
const void * pOld = Client ( ) - > SnapFindItem ( IClient : : SNAP_PREV , NETOBJTYPE_CHARACTER , Item . m_ID ) ;
2011-03-10 09:08:14 +00:00
m_Snap . m_aCharacters [ Item . m_ID ] . m_Cur = * ( ( const CNetObj_Character * ) pData ) ;
2010-05-29 07:25:38 +00:00
if ( pOld )
2008-09-23 07:43:41 +00:00
{
2011-02-12 10:40:36 +00:00
m_Snap . m_aCharacters [ Item . m_ID ] . m_Active = true ;
m_Snap . m_aCharacters [ Item . m_ID ] . m_Prev = * ( ( const CNetObj_Character * ) pOld ) ;
if ( m_Snap . m_aCharacters [ Item . m_ID ] . m_Prev . m_Tick )
Evolve ( & m_Snap . m_aCharacters [ Item . m_ID ] . m_Prev , Client ( ) - > PrevGameTick ( ) ) ;
if ( m_Snap . m_aCharacters [ Item . m_ID ] . m_Cur . m_Tick )
Evolve ( & m_Snap . m_aCharacters [ Item . m_ID ] . m_Cur , Client ( ) - > GameTick ( ) ) ;
2008-09-23 07:43:41 +00:00
}
2008-08-27 15:48:50 +00:00
}
2019-04-17 21:47:32 +00:00
else if ( Item . m_Type = = NETOBJTYPE_DDNETCHARACTER )
{
2019-04-19 09:17:28 +00:00
const CNetObj_DDNetCharacter * pCharacterData = ( const CNetObj_DDNetCharacter * ) pData ;
2019-04-21 22:38:24 +00:00
m_Snap . m_aCharacters [ Item . m_ID ] . m_ExtendedData = * pCharacterData ;
m_Snap . m_aCharacters [ Item . m_ID ] . m_HasExtendedData = true ;
2019-04-19 09:17:28 +00:00
// Collision
2019-04-17 21:47:32 +00:00
m_aClients [ Item . m_ID ] . m_Solo = m_aClients [ Item . m_ID ] . m_Predicted . m_Solo =
2019-04-19 09:17:28 +00:00
pCharacterData - > m_Flags & CHARACTERFLAG_SOLO ;
m_aClients [ Item . m_ID ] . m_NoCollision = m_aClients [ Item . m_ID ] . m_Predicted . m_NoCollision =
pCharacterData - > m_Flags & CHARACTERFLAG_NO_COLLISION ;
m_aClients [ Item . m_ID ] . m_NoHammerHit = m_aClients [ Item . m_ID ] . m_Predicted . m_NoHammerHit =
2019-04-19 09:59:09 +00:00
pCharacterData - > m_Flags & CHARACTERFLAG_NO_HAMMER_HIT ;
2019-04-19 09:17:28 +00:00
m_aClients [ Item . m_ID ] . m_NoGrenadeHit = m_aClients [ Item . m_ID ] . m_Predicted . m_NoGrenadeHit =
2019-04-19 09:59:09 +00:00
pCharacterData - > m_Flags & CHARACTERFLAG_NO_GRENADE_HIT ;
2019-04-19 09:17:28 +00:00
m_aClients [ Item . m_ID ] . m_NoRifleHit = m_aClients [ Item . m_ID ] . m_Predicted . m_NoRifleHit =
2019-04-19 09:59:09 +00:00
pCharacterData - > m_Flags & CHARACTERFLAG_NO_RIFLE_HIT ;
2019-04-19 09:17:28 +00:00
m_aClients [ Item . m_ID ] . m_NoShotgunHit = m_aClients [ Item . m_ID ] . m_Predicted . m_NoShotgunHit =
2019-04-19 09:59:09 +00:00
pCharacterData - > m_Flags & CHARACTERFLAG_NO_SHOTGUN_HIT ;
2019-04-19 09:17:28 +00:00
m_aClients [ Item . m_ID ] . m_NoHookHit = m_aClients [ Item . m_ID ] . m_Predicted . m_NoHookHit =
2019-04-19 09:59:09 +00:00
pCharacterData - > m_Flags & CHARACTERFLAG_NO_HOOK ;
2019-04-19 09:17:28 +00:00
m_aClients [ Item . m_ID ] . m_Super = m_aClients [ Item . m_ID ] . m_Predicted . m_Super =
pCharacterData - > m_Flags & CHARACTERFLAG_SUPER ;
// Endless
m_aClients [ Item . m_ID ] . m_EndlessHook = m_aClients [ Item . m_ID ] . m_Predicted . m_EndlessHook =
pCharacterData - > m_Flags & CHARACTERFLAG_ENDLESS_HOOK ;
m_aClients [ Item . m_ID ] . m_EndlessJump = m_aClients [ Item . m_ID ] . m_Predicted . m_EndlessJump =
pCharacterData - > m_Flags & CHARACTERFLAG_ENDLESS_JUMP ;
// Freeze
m_aClients [ Item . m_ID ] . m_Frozen = m_aClients [ Item . m_ID ] . m_Predicted . m_Frozen =
pCharacterData - > m_Flags & CHARACTERFLAG_FROZEN ;
m_aClients [ Item . m_ID ] . m_DeepFrozen = m_aClients [ Item . m_ID ] . m_Predicted . m_DeepFrozen =
pCharacterData - > m_Flags & CHARACTERFLAG_DEEP_FROZEN ;
// Telegun
m_aClients [ Item . m_ID ] . m_HasTelegunGrenade = m_aClients [ Item . m_ID ] . m_Predicted . m_HasTelegunGrenade =
pCharacterData - > m_Flags & CHARACTERFLAG_TELEGUN_GRENADE ;
m_aClients [ Item . m_ID ] . m_HasTelegunGun = m_aClients [ Item . m_ID ] . m_Predicted . m_HasTelegunGun =
pCharacterData - > m_Flags & CHARACTERFLAG_TELEGUN_GUN ;
m_aClients [ Item . m_ID ] . m_HasTelegunLaser = m_aClients [ Item . m_ID ] . m_Predicted . m_HasTelegunLaser =
pCharacterData - > m_Flags & CHARACTERFLAG_TELEGUN_LASER ;
// Other
2019-04-19 09:46:54 +00:00
m_aClients [ Item . m_ID ] . m_Spectating = pCharacterData - > m_Flags & CHARACTERFLAG_SPECTATING ;
2019-04-17 21:47:32 +00:00
}
2011-03-10 09:08:14 +00:00
else if ( Item . m_Type = = NETOBJTYPE_SPECTATORINFO )
{
m_Snap . m_pSpectatorInfo = ( const CNetObj_SpectatorInfo * ) pData ;
m_Snap . m_pPrevSpectatorInfo = ( const CNetObj_SpectatorInfo * ) Client ( ) - > SnapFindItem ( IClient : : SNAP_PREV , NETOBJTYPE_SPECTATORINFO , Item . m_ID ) ;
2011-03-12 17:07:57 +00:00
m_Snap . m_SpecInfo . m_SpectatorID = m_Snap . m_pSpectatorInfo - > m_SpectatorID ;
2011-03-10 09:08:14 +00:00
}
2011-03-04 16:08:10 +00:00
else if ( Item . m_Type = = NETOBJTYPE_GAMEINFO )
2010-12-12 15:48:13 +00:00
{
2011-03-04 16:08:10 +00:00
static bool s_GameOver = 0 ;
2015-11-12 09:06:05 +00:00
static bool s_GamePaused = 0 ;
2011-03-04 16:08:10 +00:00
m_Snap . m_pGameInfoObj = ( const CNetObj_GameInfo * ) pData ;
2018-10-02 18:52:21 +00:00
bool CurrentTickGameOver = ( bool ) ( m_Snap . m_pGameInfoObj - > m_GameStateFlags & GAMESTATEFLAG_GAMEOVER ) ;
2015-11-12 09:06:05 +00:00
if ( ! s_GameOver & & CurrentTickGameOver )
2010-12-12 15:48:13 +00:00
OnGameOver ( ) ;
2015-11-12 09:06:05 +00:00
else if ( s_GameOver & & ! CurrentTickGameOver )
2011-01-06 22:21:51 +00:00
OnStartGame ( ) ;
2015-11-12 09:06:05 +00:00
// Reset statboard when new round is started (RoundStartTick changed)
// New round is usually started after `restart` on server
2015-11-13 10:33:12 +00:00
if ( m_Snap . m_pGameInfoObj - > m_RoundStartTick ! = m_LastRoundStartTick
2015-11-12 09:06:05 +00:00
// In GamePaused or GameOver state RoundStartTick is updated on each tick
// hence no need to reset stats until player leaves GameOver
// and it would be a mistake to reset stats after or during the pause
& & ! ( CurrentTickGameOver | | m_Snap . m_pGameInfoObj - > m_GameStateFlags & GAMESTATEFLAG_PAUSED | | s_GamePaused ) )
m_pStatboard - > OnReset ( ) ;
m_LastRoundStartTick = m_Snap . m_pGameInfoObj - > m_RoundStartTick ;
s_GameOver = CurrentTickGameOver ;
2018-10-02 18:52:21 +00:00
s_GamePaused = ( bool ) ( m_Snap . m_pGameInfoObj - > m_GameStateFlags & GAMESTATEFLAG_PAUSED ) ;
2011-03-04 16:08:10 +00:00
}
else if ( Item . m_Type = = NETOBJTYPE_GAMEDATA )
{
m_Snap . m_pGameDataObj = ( const CNetObj_GameData * ) pData ;
m_Snap . m_GameDataSnapID = Item . m_ID ;
2011-07-05 21:15:24 +00:00
if ( m_Snap . m_pGameDataObj - > m_FlagCarrierRed = = FLAG_TAKEN )
{
if ( m_FlagDropTick [ TEAM_RED ] = = 0 )
m_FlagDropTick [ TEAM_RED ] = Client ( ) - > GameTick ( ) ;
}
else if ( m_FlagDropTick [ TEAM_RED ] ! = 0 )
m_FlagDropTick [ TEAM_RED ] = 0 ;
if ( m_Snap . m_pGameDataObj - > m_FlagCarrierBlue = = FLAG_TAKEN )
{
if ( m_FlagDropTick [ TEAM_BLUE ] = = 0 )
m_FlagDropTick [ TEAM_BLUE ] = Client ( ) - > GameTick ( ) ;
}
else if ( m_FlagDropTick [ TEAM_BLUE ] ! = 0 )
m_FlagDropTick [ TEAM_BLUE ] = 0 ;
2015-05-20 20:23:58 +00:00
if ( m_LastFlagCarrierRed = = FLAG_ATSTAND & & m_Snap . m_pGameDataObj - > m_FlagCarrierRed > = 0 )
OnFlagGrab ( TEAM_RED ) ;
else if ( m_LastFlagCarrierBlue = = FLAG_ATSTAND & & m_Snap . m_pGameDataObj - > m_FlagCarrierBlue > = 0 )
OnFlagGrab ( TEAM_BLUE ) ;
m_LastFlagCarrierRed = m_Snap . m_pGameDataObj - > m_FlagCarrierRed ;
m_LastFlagCarrierBlue = m_Snap . m_pGameDataObj - > m_FlagCarrierBlue ;
2010-12-12 15:48:13 +00:00
}
2010-05-29 07:25:38 +00:00
else if ( Item . m_Type = = NETOBJTYPE_FLAG )
2011-02-12 10:40:36 +00:00
m_Snap . m_paFlags [ Item . m_ID % 2 ] = ( const CNetObj_Flag * ) pData ;
2019-03-02 10:50:33 +00:00
else if ( Item . m_Type = = NETOBJTYPE_AUTHINFO )
m_aClients [ Item . m_ID ] . m_AuthLevel = ( ( const CNetObj_AuthInfo * ) pData ) - > m_AuthLevel ;
2008-09-23 07:43:41 +00:00
}
}
2011-04-13 18:37:12 +00:00
2008-09-23 07:43:41 +00:00
// setup local pointers
2011-02-12 10:40:36 +00:00
if ( m_Snap . m_LocalClientID > = 0 )
2008-09-23 07:43:41 +00:00
{
2011-02-12 10:40:36 +00:00
CSnapState : : CCharacterInfo * c = & m_Snap . m_aCharacters [ m_Snap . m_LocalClientID ] ;
2010-05-29 07:25:38 +00:00
if ( c - > m_Active )
2008-09-23 07:43:41 +00:00
{
2016-09-20 14:34:49 +00:00
if ( ! m_Snap . m_SpecInfo . m_Active )
{
m_Snap . m_pLocalCharacter = & c - > m_Cur ;
m_Snap . m_pLocalPrevCharacter = & c - > m_Prev ;
m_LocalCharacterPos = vec2 ( m_Snap . m_pLocalCharacter - > m_X , m_Snap . m_pLocalCharacter - > m_Y ) ;
}
2008-08-27 15:48:50 +00:00
}
2011-02-12 10:40:36 +00:00
else if ( Client ( ) - > SnapFindItem ( IClient : : SNAP_PREV , NETOBJTYPE_CHARACTER , m_Snap . m_LocalClientID ) )
2010-08-10 11:54:13 +00:00
{
// player died
m_pControls - > OnPlayerDeath ( ) ;
}
2008-08-27 15:48:50 +00:00
}
2015-07-22 19:32:02 +00:00
if ( Client ( ) - > State ( ) = = IClient : : STATE_DEMOPLAYBACK )
2011-03-12 17:07:57 +00:00
{
2015-07-26 16:21:51 +00:00
if ( m_DemoSpecID ! = SPEC_FOLLOW )
{
m_Snap . m_SpecInfo . m_Active = true ;
2015-07-22 19:32:02 +00:00
m_Snap . m_SpecInfo . m_SpectatorID = m_Snap . m_LocalClientID ;
2015-07-26 16:21:51 +00:00
if ( m_DemoSpecID > SPEC_FREEVIEW & & m_Snap . m_aCharacters [ m_DemoSpecID ] . m_Active )
m_Snap . m_SpecInfo . m_SpectatorID = m_DemoSpecID ;
else
m_Snap . m_SpecInfo . m_SpectatorID = SPEC_FREEVIEW ;
}
2011-03-12 17:07:57 +00:00
}
2011-01-11 22:03:01 +00:00
2011-03-22 21:41:27 +00:00
// clear out unneeded client data
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
if ( ! m_Snap . m_paPlayerInfos [ i ] & & m_aClients [ i ] . m_Active )
2017-02-15 15:43:45 +00:00
{
2011-03-22 21:41:27 +00:00
m_aClients [ i ] . Reset ( ) ;
2017-02-15 15:43:45 +00:00
m_aStats [ i ] . Reset ( ) ;
}
2011-03-22 21:41:27 +00:00
}
2011-03-23 12:06:35 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
2018-11-21 20:26:05 +00:00
// update friend state
m_aClients [ i ] . m_Friend = ! ( i = = m_Snap . m_LocalClientID
| | ! m_Snap . m_paPlayerInfos [ i ]
| | ! Friends ( ) - > IsFriend ( m_aClients [ i ] . m_aName , m_aClients [ i ] . m_aClan , true ) ) ;
// update foe state
m_aClients [ i ] . m_Foe = ! ( i = = m_Snap . m_LocalClientID
| | ! m_Snap . m_paPlayerInfos [ i ]
| | ! Foes ( ) - > IsFriend ( m_aClients [ i ] . m_aName , m_aClients [ i ] . m_aClan , true ) ) ;
2015-07-22 20:16:49 +00:00
}
2014-02-08 21:24:57 +00:00
// sort player infos by name
mem_copy ( m_Snap . m_paInfoByName , m_Snap . m_paPlayerInfos , sizeof ( m_Snap . m_paInfoByName ) ) ;
2018-11-21 20:26:05 +00:00
std : : stable_sort ( m_Snap . m_paInfoByName , m_Snap . m_paInfoByName + MAX_CLIENTS ,
[ this ] ( const CNetObj_PlayerInfo * p1 , const CNetObj_PlayerInfo * p2 ) - > bool
2014-02-08 21:24:57 +00:00
{
2018-11-21 20:26:05 +00:00
if ( ! p2 )
2018-12-06 06:56:58 +00:00
return static_cast < bool > ( p1 ) ;
2018-11-24 21:57:15 +00:00
if ( ! p1 )
return false ;
2018-11-21 20:26:05 +00:00
return str_comp_nocase ( m_aClients [ p1 - > m_ClientID ] . m_aName , m_aClients [ p2 - > m_ClientID ] . m_aName ) < 0 ;
} ) ;
2018-11-24 21:57:15 +00:00
CServerInfo CurrentServerInfo ;
Client ( ) - > GetServerInfo ( & CurrentServerInfo ) ;
bool IsGameTypeRace = IsRace ( & CurrentServerInfo ) ;
2014-02-08 21:24:57 +00:00
2011-01-11 22:03:01 +00:00
// sort player infos by score
2014-02-08 21:24:57 +00:00
mem_copy ( m_Snap . m_paInfoByScore , m_Snap . m_paInfoByName , sizeof ( m_Snap . m_paInfoByScore ) ) ;
2018-11-21 20:26:05 +00:00
std : : stable_sort ( m_Snap . m_paInfoByScore , m_Snap . m_paInfoByScore + MAX_CLIENTS ,
[ IsGameTypeRace ] ( const CNetObj_PlayerInfo * p1 , const CNetObj_PlayerInfo * p2 ) - > bool
2011-01-11 22:03:01 +00:00
{
2018-11-21 20:26:05 +00:00
if ( ! p2 )
2018-12-06 06:56:58 +00:00
return static_cast < bool > ( p1 ) ;
2018-11-24 21:57:15 +00:00
if ( ! p1 )
return false ;
2018-11-21 20:26:05 +00:00
return ( ( ( IsGameTypeRace & & p1 - > m_Score = = - 9999 ) ? std : : numeric_limits < int > : : min ( ) : p1 - > m_Score ) >
( ( IsGameTypeRace & & p2 - > m_Score = = - 9999 ) ? std : : numeric_limits < int > : : min ( ) : p2 - > m_Score ) ) ;
} ) ;
2011-04-13 18:37:12 +00:00
2018-02-04 15:00:47 +00:00
// sort player infos by DDRace Team (and score between)
2018-11-21 20:26:05 +00:00
int Index = 0 ;
2014-01-28 18:52:46 +00:00
for ( int Team = 0 ; Team < = MAX_CLIENTS ; + + Team )
2014-01-22 00:39:18 +00:00
{
for ( int i = 0 ; i < MAX_CLIENTS & & Index < MAX_CLIENTS ; + + i )
{
if ( m_Snap . m_paInfoByScore [ i ] & & m_Teams . Team ( m_Snap . m_paInfoByScore [ i ] - > m_ClientID ) = = Team )
m_Snap . m_paInfoByDDTeam [ Index + + ] = m_Snap . m_paInfoByScore [ i ] ;
}
}
2010-05-29 07:25:38 +00:00
CTuningParams StandardTuning ;
if ( CurrentServerInfo . m_aGameType [ 0 ] ! = ' 0 ' )
2009-01-11 10:40:14 +00:00
{
2010-05-29 07:25:38 +00:00
if ( str_comp ( CurrentServerInfo . m_aGameType , " DM " ) ! = 0 & & str_comp ( CurrentServerInfo . m_aGameType , " TDM " ) ! = 0 & & str_comp ( CurrentServerInfo . m_aGameType , " CTF " ) ! = 0 )
m_ServerMode = SERVERMODE_MOD ;
2014-04-29 01:34:23 +00:00
else if ( mem_comp ( & StandardTuning , & m_Tuning [ g_Config . m_ClDummy ] , 33 ) = = 0 )
2010-05-29 07:25:38 +00:00
m_ServerMode = SERVERMODE_PURE ;
2009-01-11 10:40:14 +00:00
else
2010-05-29 07:25:38 +00:00
m_ServerMode = SERVERMODE_PUREMOD ;
2009-01-11 10:40:14 +00:00
}
2011-01-06 03:46:10 +00:00
2012-01-08 23:49:20 +00:00
// add tuning to demo
2014-10-16 15:42:13 +00:00
bool AnyRecording = false ;
for ( int i = 0 ; i < RECORDER_MAX ; i + + )
if ( DemoRecorder ( i ) - > IsRecording ( ) )
{
AnyRecording = true ;
break ;
}
if ( AnyRecording & & mem_comp ( & StandardTuning , & m_Tuning [ g_Config . m_ClDummy ] , sizeof ( CTuningParams ) ) ! = 0 )
2012-01-08 23:49:20 +00:00
{
CMsgPacker Msg ( NETMSGTYPE_SV_TUNEPARAMS ) ;
2014-04-29 01:34:23 +00:00
int * pParams = ( int * ) & m_Tuning [ g_Config . m_ClDummy ] ;
for ( unsigned i = 0 ; i < sizeof ( m_Tuning [ 0 ] ) / sizeof ( int ) ; i + + )
2012-01-08 23:49:20 +00:00
Msg . AddInt ( pParams [ i ] ) ;
Client ( ) - > SendMsg ( & Msg , MSGFLAG_RECORD | MSGFLAG_NOSEND ) ;
}
2013-02-02 13:08:02 +00:00
2014-04-28 14:47:44 +00:00
if ( ! m_DDRaceMsgSent [ 0 ] & & m_Snap . m_pLocalInfo )
{
CMsgPacker Msg ( NETMSGTYPE_CL_ISDDNET ) ;
Msg . AddInt ( CLIENT_VERSIONNR ) ;
Client ( ) - > SendMsgExY ( & Msg , MSGFLAG_VITAL , false , 0 ) ;
m_DDRaceMsgSent [ 0 ] = true ;
}
if ( ! m_DDRaceMsgSent [ 1 ] & & m_Snap . m_pLocalInfo & & Client ( ) - > DummyConnected ( ) )
2010-10-23 19:26:10 +00:00
{
2014-01-30 15:49:15 +00:00
CMsgPacker Msg ( NETMSGTYPE_CL_ISDDNET ) ;
2014-02-19 21:29:46 +00:00
Msg . AddInt ( CLIENT_VERSIONNR ) ;
2014-04-28 14:47:44 +00:00
Client ( ) - > SendMsgExY ( & Msg , MSGFLAG_VITAL , false , 1 ) ;
m_DDRaceMsgSent [ 1 ] = true ;
2013-02-02 13:08:02 +00:00
}
2011-02-23 20:22:05 +00:00
2014-05-24 22:59:52 +00:00
if ( m_ShowOthers [ g_Config . m_ClDummy ] = = - 1 | | ( m_ShowOthers [ g_Config . m_ClDummy ] ! = - 1 & & m_ShowOthers [ g_Config . m_ClDummy ] ! = g_Config . m_ClShowOthers ) )
2013-02-02 13:08:02 +00:00
{
// no need to send, default settings
//if(!(m_ShowOthers == -1 && g_Config.m_ClShowOthers))
{
CNetMsg_Cl_ShowOthers Msg ;
2014-05-24 22:59:52 +00:00
Msg . m_Show = g_Config . m_ClShowOthers ;
2013-02-02 13:08:02 +00:00
Client ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL ) ;
}
// update state
2014-05-24 22:59:52 +00:00
m_ShowOthers [ g_Config . m_ClDummy ] = g_Config . m_ClShowOthers ;
2010-10-23 19:26:10 +00:00
}
2017-10-06 20:01:33 +00:00
m_pGhost - > OnNewSnapshot ( ) ;
m_pRaceDemo - > OnNewSnapshot ( ) ;
2019-04-11 22:46:54 +00:00
// detect air jump for unpredicted players
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
if ( m_Snap . m_aCharacters [ i ] . m_Active & & ( m_Snap . m_aCharacters [ i ] . m_Cur . m_Jumped & 2 ) & & ! ( m_Snap . m_aCharacters [ i ] . m_Prev . m_Jumped & 2 ) )
if ( ! Predict ( ) | | ( ! AntiPingPlayers ( ) & & i ! = m_Snap . m_LocalClientID ) )
{
vec2 Pos = mix ( vec2 ( m_Snap . m_aCharacters [ i ] . m_Prev . m_X , m_Snap . m_aCharacters [ i ] . m_Prev . m_Y ) ,
vec2 ( m_Snap . m_aCharacters [ i ] . m_Cur . m_X , m_Snap . m_aCharacters [ i ] . m_Cur . m_Y ) ,
Client ( ) - > IntraGameTick ( ) ) ;
m_pEffects - > AirJump ( Pos ) ;
}
// update prediction data
if ( Client ( ) - > State ( ) ! = IClient : : STATE_DEMOPLAYBACK )
UpdatePrediction ( ) ;
2008-08-27 15:48:50 +00:00
}
2010-05-29 07:25:38 +00:00
void CGameClient : : OnPredict ( )
2008-08-27 15:48:50 +00:00
{
2008-09-23 07:43:41 +00:00
// store the previous values so we can detect prediction errors
2010-05-29 07:25:38 +00:00
CCharacterCore BeforePrevChar = m_PredictedPrevChar ;
CCharacterCore BeforeChar = m_PredictedChar ;
2008-08-27 15:48:50 +00:00
2008-09-23 07:43:41 +00:00
// we can't predict without our own id or own character
2011-02-12 10:40:36 +00:00
if ( m_Snap . m_LocalClientID = = - 1 | | ! m_Snap . m_aCharacters [ m_Snap . m_LocalClientID ] . m_Active )
2008-09-23 07:43:41 +00:00
return ;
2011-04-13 18:37:12 +00:00
2008-11-16 15:10:57 +00:00
// don't predict anything if we are paused
2011-03-04 16:08:10 +00:00
if ( m_Snap . m_pGameInfoObj & & m_Snap . m_pGameInfoObj - > m_GameStateFlags & GAMESTATEFLAG_PAUSED )
2008-11-16 15:10:57 +00:00
{
2010-05-29 07:25:38 +00:00
if ( m_Snap . m_pLocalCharacter )
2014-04-14 08:56:14 +00:00
{
2010-05-29 07:25:38 +00:00
m_PredictedChar . Read ( m_Snap . m_pLocalCharacter ) ;
2014-04-14 08:56:14 +00:00
m_PredictedChar . m_ActiveWeapon = m_Snap . m_pLocalCharacter - > m_Weapon ;
}
2010-05-29 07:25:38 +00:00
if ( m_Snap . m_pLocalPrevCharacter )
2014-04-14 08:56:14 +00:00
{
2010-05-29 07:25:38 +00:00
m_PredictedPrevChar . Read ( m_Snap . m_pLocalPrevCharacter ) ;
2014-04-14 08:56:14 +00:00
m_PredictedPrevChar . m_ActiveWeapon = m_Snap . m_pLocalPrevCharacter - > m_Weapon ;
}
2008-11-16 15:10:57 +00:00
return ;
}
2008-09-23 07:43:41 +00:00
2019-04-11 22:46:54 +00:00
vec2 aBeforeRender [ MAX_CLIENTS ] ;
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
aBeforeRender [ i ] = GetSmoothPos ( i ) ;
2015-01-11 16:36:38 +00:00
2019-04-11 22:46:54 +00:00
// init
m_PredictedWorld . CopyWorld ( & m_GameWorld ) ;
2008-08-27 15:48:50 +00:00
2019-04-11 22:46:54 +00:00
// don't predict inactive players
2008-09-23 07:43:41 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2019-04-11 22:46:54 +00:00
if ( CCharacter * pChar = m_PredictedWorld . GetCharacterByID ( i ) )
if ( ! m_Snap . m_aCharacters [ i ] . m_Active & & pChar - > m_SnapTicks > 10 )
pChar - > Destroy ( ) ;
2011-04-13 18:37:12 +00:00
2019-04-11 22:46:54 +00:00
CCharacter * pLocalChar = m_PredictedWorld . GetCharacterByID ( m_Snap . m_LocalClientID ) ;
if ( ! pLocalChar )
return ;
2014-12-01 00:31:58 +00:00
2019-04-11 22:46:54 +00:00
// predict
for ( int Tick = Client ( ) - > GameTick ( ) + 1 ; Tick < = Client ( ) - > PredGameTick ( ) ; Tick + + )
2014-12-01 00:31:58 +00:00
{
2019-04-11 22:46:54 +00:00
// fetch the previous characters
if ( Tick = = Client ( ) - > PredGameTick ( ) )
2014-12-01 00:31:58 +00:00
{
2019-04-11 22:46:54 +00:00
m_PrevPredictedWorld . CopyWorld ( & m_PredictedWorld ) ;
m_PredictedPrevChar = pLocalChar - > GetCore ( ) ;
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
if ( CCharacter * pChar = m_PredictedWorld . GetCharacterByID ( i ) )
m_aClients [ i ] . m_PrevPredicted = pChar - > GetCore ( ) ;
2014-12-01 00:31:58 +00:00
}
2019-04-11 22:46:54 +00:00
// apply inputs and tick
2019-04-22 23:49:38 +00:00
CNetObj_PlayerInput * pInputData = ( CNetObj_PlayerInput * ) Client ( ) - > GetDirectInput ( Tick ) ;
2019-04-11 22:46:54 +00:00
if ( pInputData )
pLocalChar - > OnDirectInput ( pInputData ) ;
m_PredictedWorld . m_GameTick = Tick ;
if ( pInputData )
pLocalChar - > OnPredictedInput ( pInputData ) ;
m_PredictedWorld . Tick ( ) ;
// fetch the current characters
if ( Tick = = Client ( ) - > PredGameTick ( ) )
2014-12-01 00:31:58 +00:00
{
2019-04-11 22:46:54 +00:00
m_PredictedChar = pLocalChar - > GetCore ( ) ;
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
if ( CCharacter * pChar = m_PredictedWorld . GetCharacterByID ( i ) )
m_aClients [ i ] . m_Predicted = pChar - > GetCore ( ) ;
2014-12-01 00:31:58 +00:00
}
2019-04-11 22:46:54 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
if ( CCharacter * pChar = m_PredictedWorld . GetCharacterByID ( i ) )
{
m_aClients [ i ] . m_PredPos [ Tick % 200 ] = pChar - > Core ( ) - > m_Pos ;
m_aClients [ i ] . m_PredTick [ Tick % 200 ] = Tick ;
}
2014-12-01 00:31:58 +00:00
2019-04-11 22:46:54 +00:00
// check if we want to trigger effects
2019-04-22 23:49:38 +00:00
if ( Tick > m_LastNewPredictedTick [ g_Config . m_ClDummy ] )
2014-12-01 00:31:58 +00:00
{
2019-04-22 23:49:38 +00:00
m_LastNewPredictedTick [ g_Config . m_ClDummy ] = Tick ;
2019-04-11 22:46:54 +00:00
m_NewPredictedTick = true ;
vec2 Pos = pLocalChar - > Core ( ) - > m_Pos ;
int Events = pLocalChar - > Core ( ) - > m_TriggeredEvents ;
if ( g_Config . m_ClPredict )
if ( Events & COREEVENT_AIR_JUMP )
m_pEffects - > AirJump ( Pos ) ;
if ( g_Config . m_SndGame )
2008-08-27 15:48:50 +00:00
{
2019-04-11 22:46:54 +00:00
if ( Events & COREEVENT_GROUND_JUMP )
m_pSounds - > PlayAndRecord ( CSounds : : CHN_WORLD , SOUND_PLAYER_JUMP , 1.0f , Pos ) ;
if ( Events & COREEVENT_HOOK_ATTACH_GROUND )
m_pSounds - > PlayAndRecord ( CSounds : : CHN_WORLD , SOUND_HOOK_ATTACH_GROUND , 1.0f , Pos ) ;
if ( Events & COREEVENT_HOOK_HIT_NOHOOK )
m_pSounds - > PlayAndRecord ( CSounds : : CHN_WORLD , SOUND_HOOK_NOATTACH , 1.0f , Pos ) ;
2014-12-01 00:31:58 +00:00
}
}
2019-04-11 22:46:54 +00:00
}
2014-12-01 00:31:58 +00:00
2019-04-11 22:46:54 +00:00
// detect mispredictions of other players and make corrections smoother when possible
static vec2 s_aLastPos [ MAX_CLIENTS ] = { { 0 , 0 } } ;
static bool s_aLastActive [ MAX_CLIENTS ] = { 0 } ;
2014-12-01 00:31:58 +00:00
2019-04-11 22:46:54 +00:00
if ( g_Config . m_ClAntiPingSmooth & & Predict ( ) & & AntiPingPlayers ( ) & & m_NewTick & & abs ( m_PredictedTick - Client ( ) - > PredGameTick ( ) ) < = 1 & & abs ( Client ( ) - > GameTick ( ) - Client ( ) - > PrevGameTick ( ) ) < = 2 )
{
int PredTime = clamp ( Client ( ) - > GetPredictionTime ( ) , 0 , 800 ) ;
float SmoothPace = 4 - 1.5f * PredTime / 800.f ; // smoothing pace (a lower value will make the smoothing quicker)
int64 Len = 1000 * PredTime * SmoothPace ;
2018-10-02 18:45:44 +00:00
2019-04-11 22:46:54 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( ! m_Snap . m_aCharacters [ i ] . m_Active | | i = = m_Snap . m_LocalClientID | | ! s_aLastActive [ i ] )
continue ;
vec2 NewPos = ( m_PredictedTick = = Client ( ) - > PredGameTick ( ) ) ? m_aClients [ i ] . m_Predicted . m_Pos : m_aClients [ i ] . m_PrevPredicted . m_Pos ;
vec2 PredErr = ( s_aLastPos [ i ] - NewPos ) / ( float ) min ( Client ( ) - > GetPredictionTime ( ) , 200 ) ;
if ( in_range ( length ( PredErr ) , 0.05f , 5.f ) )
2018-10-02 18:45:44 +00:00
{
2019-04-11 22:46:54 +00:00
vec2 PredPos = mix ( m_aClients [ i ] . m_PrevPredicted . m_Pos , m_aClients [ i ] . m_Predicted . m_Pos , Client ( ) - > PredIntraGameTick ( ) ) ;
vec2 CurPos = mix (
vec2 ( m_Snap . m_aCharacters [ i ] . m_Prev . m_X , m_Snap . m_aCharacters [ i ] . m_Prev . m_Y ) ,
vec2 ( m_Snap . m_aCharacters [ i ] . m_Cur . m_X , m_Snap . m_aCharacters [ i ] . m_Cur . m_Y ) ,
Client ( ) - > IntraGameTick ( ) ) ;
vec2 RenderDiff = PredPos - aBeforeRender [ i ] ;
vec2 PredDiff = PredPos - CurPos ;
float MixAmount [ 2 ] ;
for ( int j = 0 ; j < 2 ; j + + )
2018-10-02 18:45:44 +00:00
{
2019-04-11 22:46:54 +00:00
MixAmount [ j ] = 1.0 ;
if ( fabs ( PredErr [ j ] ) > 0.05f )
2018-10-02 18:45:44 +00:00
{
2019-04-11 22:46:54 +00:00
MixAmount [ j ] = 0.0 ;
if ( fabs ( RenderDiff [ j ] ) > 0.01f )
2018-10-02 18:45:44 +00:00
{
2019-04-11 22:46:54 +00:00
MixAmount [ j ] = 1.f - clamp ( RenderDiff [ j ] / PredDiff [ j ] , 0.f , 1.f ) ;
MixAmount [ j ] = 1.f - powf ( 1.f - MixAmount [ j ] , 1 / 1.2f ) ;
}
2018-10-02 18:45:44 +00:00
}
2019-04-11 22:46:54 +00:00
int64 TimePassed = time_get ( ) - m_aClients [ i ] . m_SmoothStart [ j ] ;
if ( in_range ( TimePassed , ( int64 ) 0 , Len - 1 ) )
MixAmount [ j ] = min ( MixAmount [ j ] , ( float ) ( TimePassed / ( double ) Len ) ) ;
2018-10-02 12:32:59 +00:00
2014-12-01 00:31:58 +00:00
}
2019-04-11 22:46:54 +00:00
for ( int j = 0 ; j < 2 ; j + + )
if ( fabs ( RenderDiff [ j ] ) < 0.01f & & fabs ( PredDiff [ j ] ) < 0.01f & & fabs ( m_aClients [ i ] . m_PrevPredicted . m_Pos [ j ] - m_aClients [ i ] . m_Predicted . m_Pos [ j ] ) < 0.01f & & MixAmount [ j ] > MixAmount [ j ^ 1 ] )
MixAmount [ j ] = MixAmount [ j ^ 1 ] ;
for ( int j = 0 ; j < 2 ; j + + )
2014-12-01 00:31:58 +00:00
{
2019-04-11 22:46:54 +00:00
int64 Remaining = min ( ( 1.f - MixAmount [ j ] ) * Len , min ( time_freq ( ) * 0.700f , ( 1.f - MixAmount [ j ^ 1 ] ) * Len + time_freq ( ) * 0.300f ) ) ; // don't smooth for longer than 700ms, or more than 300ms longer along one axis than the other axis
int64 Start = time_get ( ) - ( Len - Remaining ) ;
if ( ! in_range ( Start + Len , m_aClients [ i ] . m_SmoothStart [ j ] , m_aClients [ i ] . m_SmoothStart [ j ] + Len ) )
2014-12-01 00:31:58 +00:00
{
2019-04-11 22:46:54 +00:00
m_aClients [ i ] . m_SmoothStart [ j ] = Start ;
m_aClients [ i ] . m_SmoothLen [ j ] = Len ;
2014-12-01 00:31:58 +00:00
}
}
}
}
2019-04-11 22:46:54 +00:00
}
2014-12-01 00:31:58 +00:00
2019-04-11 22:46:54 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( m_Snap . m_aCharacters [ i ] . m_Active )
2014-12-01 00:31:58 +00:00
{
2019-04-11 22:46:54 +00:00
s_aLastPos [ i ] = m_aClients [ i ] . m_Predicted . m_Pos ;
s_aLastActive [ i ] = true ;
2015-01-11 16:36:38 +00:00
}
else
2019-04-11 22:46:54 +00:00
s_aLastActive [ i ] = false ;
2008-08-27 15:48:50 +00:00
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
if ( g_Config . m_Debug & & g_Config . m_ClPredict & & m_PredictedTick = = Client ( ) - > PredGameTick ( ) )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
CNetObj_CharacterCore Before = { 0 } , Now = { 0 } , BeforePrev = { 0 } , NowPrev = { 0 } ;
BeforeChar . Write ( & Before ) ;
BeforePrevChar . Write ( & BeforePrev ) ;
m_PredictedChar . Write ( & Now ) ;
m_PredictedPrevChar . Write ( & NowPrev ) ;
2008-08-27 15:48:50 +00:00
2010-05-29 07:25:38 +00:00
if ( mem_comp ( & Before , & Now , sizeof ( CNetObj_CharacterCore ) ) ! = 0 )
2008-08-27 15:48:50 +00:00
{
2010-08-17 22:06:00 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " client " , " prediction error " ) ;
2010-05-29 07:25:38 +00:00
for ( unsigned i = 0 ; i < sizeof ( CNetObj_CharacterCore ) / sizeof ( int ) ; i + + )
if ( ( ( int * ) & Before ) [ i ] ! = ( ( int * ) & Now ) [ i ] )
2008-09-23 07:43:41 +00:00
{
2010-08-17 22:06:00 +00:00
char aBuf [ 256 ] ;
2011-04-13 18:37:12 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %d %d %d (%d %d) " , i , ( ( int * ) & Before ) [ i ] , ( ( int * ) & Now ) [ i ] , ( ( int * ) & BeforePrev ) [ i ] , ( ( int * ) & NowPrev ) [ i ] ) ;
2010-08-17 22:06:00 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " client " , aBuf ) ;
2008-09-23 07:43:41 +00:00
}
2008-08-27 15:48:50 +00:00
}
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
m_PredictedTick = Client ( ) - > PredGameTick ( ) ;
2017-10-06 20:01:33 +00:00
if ( m_NewPredictedTick )
2017-10-28 12:23:24 +00:00
m_pGhost - > OnNewPredictedSnapshot ( ) ;
2008-08-27 15:48:50 +00:00
}
2011-01-17 11:28:37 +00:00
void CGameClient : : OnActivateEditor ( )
{
OnRelease ( ) ;
}
2015-05-19 22:51:02 +00:00
CGameClient : : CClientStats : : CClientStats ( )
{
2017-02-15 15:43:45 +00:00
Reset ( ) ;
2015-05-19 22:51:02 +00:00
}
void CGameClient : : CClientStats : : Reset ( )
{
2017-02-15 15:43:45 +00:00
m_JoinTick = 0 ;
m_IngameTicks = 0 ;
2015-05-19 22:51:02 +00:00
m_Active = false ;
m_Frags = 0 ;
m_Deaths = 0 ;
m_Suicides = 0 ;
m_BestSpree = 0 ;
m_CurrentSpree = 0 ;
for ( int j = 0 ; j < NUM_WEAPONS ; j + + )
{
m_aFragsWith [ j ] = 0 ;
m_aDeathsFrom [ j ] = 0 ;
}
m_FlagGrabs = 0 ;
m_FlagCaptures = 0 ;
}
2010-05-29 07:25:38 +00:00
void CGameClient : : CClientData : : UpdateRenderInfo ( )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
m_RenderInfo = m_SkinInfo ;
2008-08-27 15:48:50 +00:00
// force team colors
2011-03-04 16:08:10 +00:00
if ( g_GameClient . m_Snap . m_pGameInfoObj & & g_GameClient . m_Snap . m_pGameInfoObj - > m_GameFlags & GAMEFLAG_TEAMS )
2008-08-27 15:48:50 +00:00
{
2011-03-27 09:52:16 +00:00
m_RenderInfo . m_Texture = g_GameClient . m_pSkins - > Get ( m_SkinID ) - > m_ColorTexture ;
2010-05-29 07:25:38 +00:00
const int TeamColors [ 2 ] = { 65387 , 10223467 } ;
2011-01-03 11:50:38 +00:00
if ( m_Team > = TEAM_RED & & m_Team < = TEAM_BLUE )
2008-08-27 15:48:50 +00:00
{
2010-11-24 00:11:56 +00:00
m_RenderInfo . m_ColorBody = g_GameClient . m_pSkins - > GetColorV4 ( TeamColors [ m_Team ] ) ;
m_RenderInfo . m_ColorFeet = g_GameClient . m_pSkins - > GetColorV4 ( TeamColors [ m_Team ] ) ;
2008-08-27 15:48:50 +00:00
}
2011-03-27 09:52:16 +00:00
else
{
m_RenderInfo . m_ColorBody = g_GameClient . m_pSkins - > GetColorV4 ( 12895054 ) ;
m_RenderInfo . m_ColorFeet = g_GameClient . m_pSkins - > GetColorV4 ( 12895054 ) ;
}
2011-04-13 18:37:12 +00:00
}
2008-08-27 15:48:50 +00:00
}
2011-03-22 21:41:27 +00:00
void CGameClient : : CClientData : : Reset ( )
{
m_aName [ 0 ] = 0 ;
m_aClan [ 0 ] = 0 ;
m_Country = - 1 ;
m_SkinID = 0 ;
m_Team = 0 ;
m_Angle = 0 ;
m_Emoticon = 0 ;
m_EmoticonStart = - 1 ;
m_Active = false ;
m_ChatIgnore = false ;
2019-03-19 21:29:39 +00:00
m_Friend = false ;
m_Foe = false ;
m_AuthLevel = AUTHED_NO ;
2011-03-22 21:41:27 +00:00
m_SkinInfo . m_Texture = g_GameClient . m_pSkins - > Get ( 0 ) - > m_ColorTexture ;
m_SkinInfo . m_ColorBody = vec4 ( 1 , 1 , 1 , 1 ) ;
m_SkinInfo . m_ColorFeet = vec4 ( 1 , 1 , 1 , 1 ) ;
2019-04-19 09:17:28 +00:00
// DDNet Character
2019-04-12 14:16:21 +00:00
m_Solo = false ;
2019-04-19 09:17:28 +00:00
m_Jetpack = false ;
m_NoCollision = false ;
m_EndlessHook = false ;
m_EndlessJump = false ;
m_NoHammerHit = false ;
m_NoGrenadeHit = false ;
m_NoRifleHit = false ;
m_NoShotgunHit = false ;
m_NoHookHit = false ;
m_Super = false ;
m_HasTelegunGun = false ;
m_HasTelegunGrenade = false ;
m_HasTelegunLaser = false ;
m_Frozen = false ;
m_DeepFrozen = false ;
m_Spectating = false ;
2011-03-22 21:41:27 +00:00
UpdateRenderInfo ( ) ;
}
2010-05-29 07:25:38 +00:00
void CGameClient : : SendSwitchTeam ( int Team )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
CNetMsg_Cl_SetTeam Msg ;
Msg . m_Team = Team ;
2011-04-13 18:37:12 +00:00
Client ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL ) ;
2013-07-11 15:25:51 +00:00
2018-03-13 20:55:47 +00:00
if ( Team ! = TEAM_SPECTATORS )
2013-07-11 15:25:51 +00:00
m_pCamera - > OnReset ( ) ;
2008-08-27 15:48:50 +00:00
}
2010-05-29 07:25:38 +00:00
void CGameClient : : SendInfo ( bool Start )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
if ( Start )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
CNetMsg_Cl_StartInfo Msg ;
Msg . m_pName = g_Config . m_PlayerName ;
2011-03-15 10:23:49 +00:00
Msg . m_pClan = g_Config . m_PlayerClan ;
Msg . m_Country = g_Config . m_PlayerCountry ;
2015-08-06 20:16:33 +00:00
Msg . m_pSkin = g_Config . m_ClPlayerSkin ;
Msg . m_UseCustomColor = g_Config . m_ClPlayerUseCustomColor ;
Msg . m_ColorBody = g_Config . m_ClPlayerColorBody ;
Msg . m_ColorFeet = g_Config . m_ClPlayerColorFeet ;
2014-04-28 13:19:57 +00:00
CMsgPacker Packer ( Msg . MsgID ( ) ) ;
Msg . Pack ( & Packer ) ;
2014-08-17 17:10:08 +00:00
Client ( ) - > SendMsgExY ( & Packer , MSGFLAG_VITAL , false , 0 ) ;
2015-04-19 12:03:40 +00:00
m_CheckInfo [ 0 ] = - 1 ;
2008-08-27 15:48:50 +00:00
}
else
{
2010-05-29 07:25:38 +00:00
CNetMsg_Cl_ChangeInfo Msg ;
Msg . m_pName = g_Config . m_PlayerName ;
2011-03-15 10:23:49 +00:00
Msg . m_pClan = g_Config . m_PlayerClan ;
Msg . m_Country = g_Config . m_PlayerCountry ;
2015-08-06 20:16:33 +00:00
Msg . m_pSkin = g_Config . m_ClPlayerSkin ;
Msg . m_UseCustomColor = g_Config . m_ClPlayerUseCustomColor ;
Msg . m_ColorBody = g_Config . m_ClPlayerColorBody ;
Msg . m_ColorFeet = g_Config . m_ClPlayerColorFeet ;
2014-04-28 13:19:57 +00:00
CMsgPacker Packer ( Msg . MsgID ( ) ) ;
Msg . Pack ( & Packer ) ;
2014-08-17 17:10:08 +00:00
Client ( ) - > SendMsgExY ( & Packer , MSGFLAG_VITAL , false , 0 ) ;
2015-04-19 12:03:40 +00:00
m_CheckInfo [ 0 ] = Client ( ) - > GameTickSpeed ( ) ;
2008-08-27 15:48:50 +00:00
}
}
2014-04-28 13:19:57 +00:00
void CGameClient : : SendDummyInfo ( bool Start )
{
if ( Start )
{
CNetMsg_Cl_StartInfo Msg ;
2015-08-06 20:16:33 +00:00
Msg . m_pName = g_Config . m_ClDummyName ;
Msg . m_pClan = g_Config . m_ClDummyClan ;
Msg . m_Country = g_Config . m_ClDummyCountry ;
Msg . m_pSkin = g_Config . m_ClDummySkin ;
Msg . m_UseCustomColor = g_Config . m_ClDummyUseCustomColor ;
Msg . m_ColorBody = g_Config . m_ClDummyColorBody ;
Msg . m_ColorFeet = g_Config . m_ClDummyColorFeet ;
2014-04-28 13:19:57 +00:00
CMsgPacker Packer ( Msg . MsgID ( ) ) ;
Msg . Pack ( & Packer ) ;
2014-08-17 17:10:08 +00:00
Client ( ) - > SendMsgExY ( & Packer , MSGFLAG_VITAL , false , 1 ) ;
2015-04-19 12:03:40 +00:00
m_CheckInfo [ 1 ] = - 1 ;
2014-04-28 13:19:57 +00:00
}
else
{
CNetMsg_Cl_ChangeInfo Msg ;
2015-08-06 20:16:33 +00:00
Msg . m_pName = g_Config . m_ClDummyName ;
Msg . m_pClan = g_Config . m_ClDummyClan ;
Msg . m_Country = g_Config . m_ClDummyCountry ;
Msg . m_pSkin = g_Config . m_ClDummySkin ;
Msg . m_UseCustomColor = g_Config . m_ClDummyUseCustomColor ;
Msg . m_ColorBody = g_Config . m_ClDummyColorBody ;
Msg . m_ColorFeet = g_Config . m_ClDummyColorFeet ;
2014-04-28 13:19:57 +00:00
CMsgPacker Packer ( Msg . MsgID ( ) ) ;
Msg . Pack ( & Packer ) ;
Client ( ) - > SendMsgExY ( & Packer , MSGFLAG_VITAL , false , 1 ) ;
2015-04-19 12:03:40 +00:00
m_CheckInfo [ 1 ] = Client ( ) - > GameTickSpeed ( ) ;
2014-04-28 13:19:57 +00:00
}
}
2011-02-12 10:40:36 +00:00
void CGameClient : : SendKill ( int ClientID )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
CNetMsg_Cl_Kill Msg ;
2011-04-13 18:37:12 +00:00
Client ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL ) ;
2015-02-18 13:23:25 +00:00
if ( g_Config . m_ClDummyCopyMoves )
{
CMsgPacker Msg ( NETMSGTYPE_CL_KILL ) ;
Client ( ) - > SendMsgExY ( & Msg , MSGFLAG_VITAL , false , ! g_Config . m_ClDummy ) ;
}
2008-08-27 15:48:50 +00:00
}
2008-08-31 13:36:30 +00:00
2011-08-13 00:11:06 +00:00
void CGameClient : : ConTeam ( IConsole : : IResult * pResult , void * pUserData )
2008-08-31 13:36:30 +00:00
{
2010-05-29 07:25:38 +00:00
( ( CGameClient * ) pUserData ) - > SendSwitchTeam ( pResult - > GetInteger ( 0 ) ) ;
2008-08-31 13:36:30 +00:00
}
2011-08-13 00:11:06 +00:00
void CGameClient : : ConKill ( IConsole : : IResult * pResult , void * pUserData )
2008-08-31 13:36:30 +00:00
{
2010-05-29 07:25:38 +00:00
( ( CGameClient * ) pUserData ) - > SendKill ( - 1 ) ;
2008-08-31 13:36:30 +00:00
}
2009-06-15 14:01:36 +00:00
2019-04-10 06:58:08 +00:00
void CGameClient : : ConColorFromRgb ( IConsole : : IResult * pResult , void * pUserData )
2019-04-06 15:40:03 +00:00
{
CGameClient * pThis = ( CGameClient * ) pUserData ;
const char * pString = pResult - > GetString ( 0 ) ;
2019-04-10 15:57:56 +00:00
const size_t Length = str_length ( pString ) ;
2019-04-06 15:40:03 +00:00
vec3 Hsl ;
vec3 Rgb ;
if ( Length = = 3 )
{
const int Num = str_toint_base ( pString , 16 ) ;
Rgb . r = ( float ) ( ( ( Num & 0xF00 ) > > 8 ) + ( ( Num & 0xF00 ) > > 4 ) ) / 255.0f ;
Rgb . g = ( float ) ( ( ( Num & 0x0F0 ) > > 4 ) + ( ( Num & 0x0F0 ) > > 0 ) ) / 255.0f ;
Rgb . b = ( float ) ( ( ( Num & 0x00F ) > > 0 ) + ( ( Num & 0x00F ) < < 4 ) ) / 255.0f ;
}
else if ( Length = = 6 )
{
const int Num = str_toint_base ( pString , 16 ) ;
Rgb . r = ( float ) ( ( Num & 0xFF0000 ) > > 16 ) / 255.0f ;
Rgb . g = ( float ) ( ( Num & 0x00FF00 ) > > 8 ) / 255.0f ;
Rgb . b = ( float ) ( ( Num & 0x0000FF ) > > 0 ) / 255.0f ;
}
else
{
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " color " , " Unknown color format " ) ;
return ;
}
char aBuf [ 32 ] ;
Hsl = RgbToHsl ( Rgb ) ;
// full lightness range for GUI colors
str_format ( aBuf , sizeof ( aBuf ) , " Hue: %d, Sat: %d, Lht: %d " , ( int ) Hsl . h , ( int ) Hsl . s , ( int ) Hsl . l ) ;
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " color " , aBuf ) ;
// limited lightness range to prevent too dark colors for player colors
Hsl . l = clamp ( ( Hsl . l - 127.0 ) * 2.0 , 0.0 , 255.0 ) ;
str_format ( aBuf , sizeof ( aBuf ) , " %d " , ( ( int ) Hsl . h < < 16 ) + ( ( int ) Hsl . s < < 8 ) + ( int ) Hsl . l ) ;
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " color " , aBuf ) ;
}
2019-04-10 20:43:57 +00:00
void CGameClient : : ConColorToRgb ( IConsole : : IResult * pResult , void * pUserData )
{
CGameClient * pThis = ( CGameClient * ) pUserData ;
vec3 Rgb ;
if ( pResult - > NumArguments ( ) = = 1 )
{
const int v = pResult - > GetInteger ( 0 ) ;
Rgb = HslToRgb ( vec3 ( ( ( v > > 16 ) & 0xff ) / 255.0f , ( ( v > > 8 ) & 0xff ) / 255.0f , 0.5f + ( v & 0xff ) / 255.0f * 0.5f ) ) ;
}
else if ( pResult - > NumArguments ( ) = = 3 )
{
const int Hue = pResult - > GetInteger ( 0 ) ;
const int Sat = pResult - > GetInteger ( 1 ) ;
const int Lht = pResult - > GetInteger ( 2 ) ;
Rgb = HslToRgb ( vec3 ( Hue / 255.0f , Sat / 255.0f , Lht / 255.0f ) ) ;
}
else
{
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " color " , " Pass 1 integer in player_color format or 3 ints as hue sat lht " ) ;
return ;
}
char aBuf [ 32 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " %06X " , ( ( int ) ( Rgb . r * 255 ) < < 16 ) + ( ( int ) ( Rgb . g * 255 ) < < 8 ) + ( int ) ( Rgb . b * 255 ) ) ;
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " color " , aBuf ) ;
}
2010-05-29 07:25:38 +00:00
void CGameClient : : ConchainSpecialInfoupdate ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
2009-06-15 14:01:36 +00:00
{
2011-08-13 00:11:06 +00:00
pfnCallback ( pResult , pCallbackUserData ) ;
2010-05-29 07:25:38 +00:00
if ( pResult - > NumArguments ( ) )
( ( CGameClient * ) pUserData ) - > SendInfo ( false ) ;
2009-10-27 14:38:53 +00:00
}
2014-04-28 13:19:57 +00:00
void CGameClient : : ConchainSpecialDummyInfoupdate ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
pfnCallback ( pResult , pCallbackUserData ) ;
if ( pResult - > NumArguments ( ) )
( ( CGameClient * ) pUserData ) - > SendDummyInfo ( false ) ;
}
2014-04-28 13:34:56 +00:00
void CGameClient : : ConchainSpecialDummy ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
pfnCallback ( pResult , pCallbackUserData ) ;
if ( pResult - > NumArguments ( ) )
if ( g_Config . m_ClDummy & & ! ( ( CGameClient * ) pUserData ) - > Client ( ) - > DummyConnected ( ) )
g_Config . m_ClDummy = 0 ;
}
2010-05-29 07:25:38 +00:00
IGameClient * CreateGameClient ( )
2009-10-27 14:38:53 +00:00
{
2010-05-29 07:25:38 +00:00
return & g_GameClient ;
2011-01-06 05:30:19 +00:00
}
2013-08-23 23:50:35 +00:00
2014-01-30 03:10:52 +00:00
int CGameClient : : IntersectCharacter ( vec2 HookPos , vec2 NewPos , vec2 & NewPos2 , int ownID )
2013-08-23 23:50:35 +00:00
{
2014-01-27 04:06:23 +00:00
float PhysSize = 28.0f ;
float Distance = 0.0f ;
2013-08-23 23:50:35 +00:00
int ClosestID = - 1 ;
2018-03-13 20:55:47 +00:00
if ( ! m_Tuning [ g_Config . m_ClDummy ] . m_PlayerHooking )
2014-02-08 20:55:08 +00:00
return ClosestID ;
2018-03-13 20:55:47 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2013-08-23 23:50:35 +00:00
{
2014-01-11 23:45:25 +00:00
CClientData cData = m_aClients [ i ] ;
CNetObj_Character Prev = m_Snap . m_aCharacters [ i ] . m_Prev ;
CNetObj_Character Player = m_Snap . m_aCharacters [ i ] . m_Cur ;
2013-08-23 23:50:35 +00:00
2014-01-11 23:45:25 +00:00
vec2 Position = mix ( vec2 ( Prev . m_X , Prev . m_Y ) , vec2 ( Player . m_X , Player . m_Y ) , Client ( ) - > IntraGameTick ( ) ) ;
2013-08-23 23:50:35 +00:00
2019-04-12 14:16:21 +00:00
if ( ! cData . m_Active | | i = = ownID | | ! m_Teams . SameTeam ( i , ownID ) | | cData . m_Solo )
2014-01-11 23:45:25 +00:00
continue ;
2013-08-23 23:50:35 +00:00
2014-01-27 04:06:23 +00:00
vec2 ClosestPoint = closest_point_on_line ( HookPos , NewPos , Position ) ;
if ( distance ( Position , ClosestPoint ) < PhysSize + 2.0f )
2013-08-23 23:50:35 +00:00
{
2014-01-27 04:06:23 +00:00
if ( ClosestID = = - 1 | | distance ( HookPos , Position ) < Distance )
2013-08-23 23:50:35 +00:00
{
2014-01-27 04:06:23 +00:00
NewPos2 = ClosestPoint ;
2013-08-23 23:50:35 +00:00
ClosestID = i ;
2014-01-27 04:06:23 +00:00
Distance = distance ( HookPos , Position ) ;
2013-08-23 23:50:35 +00:00
}
}
}
2014-10-23 15:31:29 +00:00
2013-08-23 23:50:35 +00:00
return ClosestID ;
}
2014-12-01 00:31:58 +00:00
2019-04-11 22:46:54 +00:00
vec3 CalculateNameColor ( vec3 TextColorHSL )
2014-12-01 00:31:58 +00:00
{
2019-04-11 22:46:54 +00:00
return HslToRgb ( vec3 ( TextColorHSL . h , TextColorHSL . s * 0.68f , TextColorHSL . l * 0.81f ) ) ;
}
2014-12-01 00:31:58 +00:00
2019-04-11 22:46:54 +00:00
void CGameClient : : UpdatePrediction ( )
{
if ( ! m_Snap . m_pLocalCharacter )
2014-12-01 00:31:58 +00:00
{
2019-04-11 22:46:54 +00:00
if ( CCharacter * pLocalChar = m_GameWorld . GetCharacterByID ( m_Snap . m_LocalClientID ) )
pLocalChar - > Destroy ( ) ;
return ;
}
2014-12-01 00:31:58 +00:00
2019-04-21 22:38:24 +00:00
m_TeamsPredicted = m_Teams ;
2019-04-11 22:46:54 +00:00
CServerInfo CurrentServerInfo ;
Client ( ) - > GetServerInfo ( & CurrentServerInfo ) ;
m_GameWorld . m_WorldConfig . m_IsVanilla = IsVanilla ( & CurrentServerInfo ) ;
m_GameWorld . m_WorldConfig . m_IsDDRace = IsDDRace ( & CurrentServerInfo ) ;
m_GameWorld . m_WorldConfig . m_IsFNG = IsFNG ( & CurrentServerInfo ) ;
m_GameWorld . m_WorldConfig . m_PredictTiles = g_Config . m_ClPredictDDRace & & m_GameWorld . m_WorldConfig . m_IsDDRace & & ! IsBlockWorlds ( & CurrentServerInfo ) ;
m_GameWorld . m_WorldConfig . m_PredictFreeze = g_Config . m_ClPredictFreeze ;
m_GameWorld . m_WorldConfig . m_PredictWeapons = AntiPingWeapons ( ) ;
m_GameWorld . m_Core . m_Tuning [ g_Config . m_ClDummy ] = m_Tuning [ g_Config . m_ClDummy ] ;
if ( m_Snap . m_pLocalCharacter - > m_AmmoCount > 0 & & m_Snap . m_pLocalCharacter - > m_Weapon ! = WEAPON_NINJA )
m_GameWorld . m_WorldConfig . m_InfiniteAmmo = false ;
// restore characters from previously saved ones if they temporarily left the snapshot
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
if ( m_aLastWorldCharacters [ i ] . IsAlive ( ) & & m_Snap . m_aCharacters [ i ] . m_Active & & ! m_GameWorld . GetCharacterByID ( i ) )
if ( CCharacter * pCopy = new CCharacter ( m_aLastWorldCharacters [ i ] ) )
2014-12-01 00:31:58 +00:00
{
2019-04-11 22:46:54 +00:00
m_GameWorld . InsertEntity ( pCopy ) ;
if ( pCopy - > m_FreezeTime > 0 )
pCopy - > m_FreezeTime = 0 ;
if ( pCopy - > Core ( ) - > m_HookedPlayer > 0 )
{
pCopy - > Core ( ) - > m_HookedPlayer = - 1 ;
pCopy - > Core ( ) - > m_HookState = HOOK_IDLE ;
}
2014-12-01 00:31:58 +00:00
}
2019-04-11 22:46:54 +00:00
CCharacter * pLocalChar = m_GameWorld . GetCharacterByID ( m_Snap . m_LocalClientID ) ;
2014-12-01 00:31:58 +00:00
2019-04-11 22:46:54 +00:00
// update strong and weak hook
if ( pLocalChar & & AntiPingPlayers ( ) )
DetectStrongHook ( ) ;
for ( int i : m_CharOrder . m_IDs )
if ( CCharacter * pChar = m_GameWorld . GetCharacterByID ( i ) )
{
m_GameWorld . RemoveEntity ( pChar ) ;
m_GameWorld . InsertEntity ( pChar ) ;
}
2014-12-01 00:31:58 +00:00
2019-04-11 22:46:54 +00:00
// advance the gameworld to the current gametick
if ( pLocalChar & & abs ( m_GameWorld . GameTick ( ) - Client ( ) - > GameTick ( ) ) < SERVER_TICK_SPEED )
2014-12-01 00:31:58 +00:00
{
2019-04-11 22:46:54 +00:00
for ( int Tick = m_GameWorld . GameTick ( ) + 1 ; Tick < = Client ( ) - > GameTick ( ) ; Tick + + )
{
CNetObj_PlayerInput * pInput = ( CNetObj_PlayerInput * ) Client ( ) - > GetDirectInput ( Tick ) ;
if ( pInput )
pLocalChar - > OnDirectInput ( pInput ) ;
m_GameWorld . m_GameTick = Tick ;
if ( pInput )
pLocalChar - > OnPredictedInput ( pInput ) ;
m_GameWorld . Tick ( ) ;
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
if ( CCharacter * pChar = m_GameWorld . GetCharacterByID ( i ) )
{
m_aClients [ i ] . m_PredPos [ Tick % 200 ] = pChar - > Core ( ) - > m_Pos ;
m_aClients [ i ] . m_PredTick [ Tick % 200 ] = Tick ;
}
}
2014-12-01 00:31:58 +00:00
}
else
{
2019-04-11 22:46:54 +00:00
// skip to current gametick
m_GameWorld . m_GameTick = Client ( ) - > GameTick ( ) ;
if ( pLocalChar )
if ( CNetObj_PlayerInput * pInput = ( CNetObj_PlayerInput * ) Client ( ) - > GetInput ( Client ( ) - > GameTick ( ) ) )
pLocalChar - > SetInput ( pInput ) ;
2014-12-01 00:31:58 +00:00
}
2019-04-11 22:46:54 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
if ( CCharacter * pChar = m_GameWorld . GetCharacterByID ( i ) )
{
m_aClients [ i ] . m_PredPos [ Client ( ) - > GameTick ( ) % 200 ] = pChar - > Core ( ) - > m_Pos ;
m_aClients [ i ] . m_PredTick [ Client ( ) - > GameTick ( ) % 200 ] = Client ( ) - > GameTick ( ) ;
}
2014-12-01 00:31:58 +00:00
2019-04-11 22:46:54 +00:00
// update the local gameworld with the new snapshot
m_GameWorld . NetObjBegin ( ) ;
int Num = Client ( ) - > SnapNumItems ( IClient : : SNAP_CURRENT ) ;
for ( int Index = 0 ; Index < Num ; Index + + )
2014-12-01 00:31:58 +00:00
{
2019-04-11 22:46:54 +00:00
IClient : : CSnapItem Item ;
const void * pData = Client ( ) - > SnapGetItem ( IClient : : SNAP_CURRENT , Index , & Item ) ;
m_GameWorld . NetObjAdd ( Item . m_ID , Item . m_Type , pData ) ;
2014-12-01 00:31:58 +00:00
}
2019-04-11 22:46:54 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
if ( m_Snap . m_aCharacters [ i ] . m_Active )
2014-12-01 00:31:58 +00:00
{
2019-04-22 23:49:38 +00:00
bool IsLocal = ( i = = m_Snap . m_LocalClientID ) ;
2019-04-11 22:46:54 +00:00
int GameTeam = ( m_Snap . m_pGameInfoObj - > m_GameFlags & GAMEFLAG_TEAMS ) ? m_aClients [ i ] . m_Team : i ;
2019-04-21 22:38:24 +00:00
m_GameWorld . NetCharAdd ( i , & m_Snap . m_aCharacters [ i ] . m_Cur ,
m_Snap . m_aCharacters [ i ] . m_HasExtendedData ? & m_Snap . m_aCharacters [ i ] . m_ExtendedData : 0 ,
GameTeam , IsLocal ) ;
2014-12-01 00:31:58 +00:00
}
2019-04-11 22:46:54 +00:00
m_GameWorld . NetObjEnd ( m_Snap . m_LocalClientID ) ;
2014-12-01 00:31:58 +00:00
2019-04-11 22:46:54 +00:00
// save the characters that are currently active
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
if ( CCharacter * pChar = m_GameWorld . GetCharacterByID ( i ) )
2014-12-01 00:31:58 +00:00
{
2019-04-11 22:46:54 +00:00
m_aLastWorldCharacters [ i ] = * pChar ;
m_aLastWorldCharacters [ i ] . DetachFromGameWorld ( ) ;
2014-12-01 00:31:58 +00:00
}
}
2019-04-11 22:46:54 +00:00
void CGameClient : : UpdateRenderedCharacters ( )
2014-12-01 00:31:58 +00:00
{
2019-04-11 22:46:54 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2014-12-01 00:31:58 +00:00
{
2019-04-11 22:46:54 +00:00
if ( ! m_Snap . m_aCharacters [ i ] . m_Active )
2014-12-01 00:31:58 +00:00
continue ;
2019-04-11 22:46:54 +00:00
m_aClients [ i ] . m_RenderCur = m_Snap . m_aCharacters [ i ] . m_Cur ;
m_aClients [ i ] . m_RenderPrev = m_Snap . m_aCharacters [ i ] . m_Prev ;
m_aClients [ i ] . m_IsPredicted = false ;
vec2 UnpredPos = mix (
vec2 ( m_Snap . m_aCharacters [ i ] . m_Prev . m_X , m_Snap . m_aCharacters [ i ] . m_Prev . m_Y ) ,
vec2 ( m_Snap . m_aCharacters [ i ] . m_Cur . m_X , m_Snap . m_aCharacters [ i ] . m_Cur . m_Y ) ,
Client ( ) - > IntraGameTick ( ) ) ;
vec2 Pos = UnpredPos ;
2014-12-01 00:31:58 +00:00
2019-04-11 22:46:54 +00:00
if ( Predict ( ) & & ( i = = m_Snap . m_LocalClientID | | AntiPingPlayers ( ) ) )
{
m_aClients [ i ] . m_Predicted . Write ( & m_aClients [ i ] . m_RenderCur ) ;
m_aClients [ i ] . m_PrevPredicted . Write ( & m_aClients [ i ] . m_RenderPrev ) ;
m_aClients [ i ] . m_IsPredicted = true ;
Pos = mix (
vec2 ( m_aClients [ i ] . m_RenderPrev . m_X , m_aClients [ i ] . m_RenderPrev . m_Y ) ,
vec2 ( m_aClients [ i ] . m_RenderCur . m_X , m_aClients [ i ] . m_RenderCur . m_Y ) ,
m_aClients [ i ] . m_IsPredicted ? Client ( ) - > PredIntraGameTick ( ) : Client ( ) - > IntraGameTick ( ) ) ;
if ( i = = m_Snap . m_LocalClientID )
m_aClients [ i ] . m_IsPredictedLocal = true ;
else
{
// use unpredicted values for other players
m_aClients [ i ] . m_RenderPrev . m_Angle = m_Snap . m_aCharacters [ i ] . m_Prev . m_Angle ;
m_aClients [ i ] . m_RenderPrev . m_AttackTick = m_Snap . m_aCharacters [ i ] . m_Prev . m_AttackTick ;
m_aClients [ i ] . m_RenderCur . m_Angle = m_Snap . m_aCharacters [ i ] . m_Cur . m_Angle ;
m_aClients [ i ] . m_RenderCur . m_AttackTick = m_Snap . m_aCharacters [ i ] . m_Cur . m_AttackTick ;
if ( g_Config . m_ClAntiPingSmooth )
Pos = GetSmoothPos ( i ) ;
}
}
m_Snap . m_aCharacters [ i ] . m_Position = Pos ;
m_aClients [ i ] . m_RenderPos = Pos ;
if ( Predict ( ) & & i = = m_Snap . m_LocalClientID )
m_LocalCharacterPos = Pos ;
2014-12-01 00:31:58 +00:00
}
}
2019-04-11 22:46:54 +00:00
void CGameClient : : DetectStrongHook ( )
2015-01-11 16:36:38 +00:00
{
2019-04-11 22:46:54 +00:00
static int s_LastUpdateTick [ MAX_CLIENTS ] = { 0 } ;
// attempt to detect strong/weak between players
for ( int FromPlayer = 0 ; FromPlayer < MAX_CLIENTS ; FromPlayer + + )
2015-01-11 16:36:38 +00:00
{
2019-04-11 22:46:54 +00:00
if ( ! m_Snap . m_aCharacters [ FromPlayer ] . m_Active )
continue ;
int ToPlayer = m_Snap . m_aCharacters [ FromPlayer ] . m_Prev . m_HookedPlayer ;
if ( ToPlayer < 0 | | ToPlayer > = MAX_CLIENTS | | ! m_Snap . m_aCharacters [ ToPlayer ] . m_Active | | ToPlayer ! = m_Snap . m_aCharacters [ FromPlayer ] . m_Cur . m_HookedPlayer )
continue ;
if ( abs ( min ( s_LastUpdateTick [ ToPlayer ] , s_LastUpdateTick [ FromPlayer ] ) - Client ( ) - > GameTick ( ) ) < SERVER_TICK_SPEED / 4 )
continue ;
if ( m_Snap . m_aCharacters [ FromPlayer ] . m_Prev . m_Direction ! = m_Snap . m_aCharacters [ FromPlayer ] . m_Cur . m_Direction
| | m_Snap . m_aCharacters [ ToPlayer ] . m_Prev . m_Direction ! = m_Snap . m_aCharacters [ ToPlayer ] . m_Cur . m_Direction )
continue ;
s_LastUpdateTick [ ToPlayer ] = s_LastUpdateTick [ FromPlayer ] = Client ( ) - > GameTick ( ) ;
2015-01-11 16:36:38 +00:00
float PredictErr [ 2 ] ;
2019-04-11 22:46:54 +00:00
CCharacterCore ToCharCur ;
ToCharCur . Read ( & m_Snap . m_aCharacters [ ToPlayer ] . m_Cur ) ;
CWorldCore World ;
World . m_Tuning [ g_Config . m_ClDummy ] = m_Tuning [ g_Config . m_ClDummy ] ;
CCharacterCore ToChar ;
CCharacterCore FromChar ;
2015-01-11 16:36:38 +00:00
for ( int dir = 0 ; dir < 2 ; dir + + )
{
2019-04-11 22:46:54 +00:00
ToChar . Init ( & World , Collision ( ) , & m_Teams ) ;
World . m_apCharacters [ ToPlayer ] = & ToChar ;
ToChar . Read ( & m_Snap . m_aCharacters [ ToPlayer ] . m_Prev ) ;
2015-01-11 16:36:38 +00:00
2019-04-11 22:46:54 +00:00
FromChar . Init ( & World , Collision ( ) , & m_Teams ) ;
World . m_apCharacters [ FromPlayer ] = & FromChar ;
FromChar . Read ( & m_Snap . m_aCharacters [ FromPlayer ] . m_Prev ) ;
2015-01-11 16:36:38 +00:00
for ( int Tick = Client ( ) - > PrevGameTick ( ) ; Tick < Client ( ) - > GameTick ( ) ; Tick + + )
{
if ( dir = = 0 )
{
2019-04-11 22:46:54 +00:00
FromChar . Tick ( false ) ;
ToChar . Tick ( false ) ;
2015-01-11 16:36:38 +00:00
}
else
{
2019-04-11 22:46:54 +00:00
ToChar . Tick ( false ) ;
FromChar . Tick ( false ) ;
2015-01-11 16:36:38 +00:00
}
2019-04-11 22:46:54 +00:00
FromChar . Move ( ) ;
FromChar . Quantize ( ) ;
ToChar . Move ( ) ;
ToChar . Quantize ( ) ;
2015-01-11 16:36:38 +00:00
}
2019-04-11 22:46:54 +00:00
PredictErr [ dir ] = distance ( ToChar . m_Vel , ToCharCur . m_Vel ) ;
2015-01-11 16:36:38 +00:00
}
2019-04-11 22:46:54 +00:00
const float LOW = 0.0001f ;
const float HIGH = 0.07f ;
2017-09-06 08:54:29 +00:00
if ( PredictErr [ 1 ] < LOW & & PredictErr [ 0 ] > HIGH )
2019-04-11 22:46:54 +00:00
{
if ( m_CharOrder . HasStrongAgainst ( ToPlayer , FromPlayer ) )
{
if ( ToPlayer ! = m_Snap . m_LocalClientID )
m_CharOrder . GiveWeak ( ToPlayer ) ;
else
m_CharOrder . GiveStrong ( FromPlayer ) ;
}
}
2017-09-06 08:54:29 +00:00
else if ( PredictErr [ 0 ] < LOW & & PredictErr [ 1 ] > HIGH )
2019-04-11 22:46:54 +00:00
{
if ( m_CharOrder . HasStrongAgainst ( FromPlayer , ToPlayer ) )
{
if ( ToPlayer ! = m_Snap . m_LocalClientID )
m_CharOrder . GiveStrong ( ToPlayer ) ;
else
m_CharOrder . GiveWeak ( FromPlayer ) ;
}
}
2015-01-11 16:36:38 +00:00
}
}
2017-03-06 13:04:09 +00:00
2019-04-11 22:46:54 +00:00
vec2 CGameClient : : GetSmoothPos ( int ClientID )
2017-03-06 13:04:09 +00:00
{
2019-04-11 22:46:54 +00:00
vec2 Pos = mix ( m_aClients [ ClientID ] . m_PrevPredicted . m_Pos , m_aClients [ ClientID ] . m_Predicted . m_Pos , Client ( ) - > PredIntraGameTick ( ) ) ;
int64 Now = time_get ( ) ;
for ( int i = 0 ; i < 2 ; i + + )
{
int64 Len = clamp ( m_aClients [ ClientID ] . m_SmoothLen [ i ] , ( int64 ) 1 , time_freq ( ) ) ;
int64 TimePassed = Now - m_aClients [ ClientID ] . m_SmoothStart [ i ] ;
if ( in_range ( TimePassed , ( int64 ) 0 , Len - 1 ) )
{
float MixAmount = 1.f - powf ( 1.f - TimePassed / ( float ) Len , 1.2f ) ;
int SmoothTick ;
float SmoothIntra ;
Client ( ) - > GetSmoothTick ( & SmoothTick , & SmoothIntra , MixAmount ) ;
if ( SmoothTick > 0 & & m_aClients [ ClientID ] . m_PredTick [ ( SmoothTick - 1 ) % 200 ] > = Client ( ) - > PrevGameTick ( ) & & m_aClients [ ClientID ] . m_PredTick [ SmoothTick % 200 ] < = Client ( ) - > PredGameTick ( ) )
Pos [ i ] = mix ( m_aClients [ ClientID ] . m_PredPos [ ( SmoothTick - 1 ) % 200 ] [ i ] , m_aClients [ ClientID ] . m_PredPos [ SmoothTick % 200 ] [ i ] , SmoothIntra ) ;
}
}
return Pos ;
2017-03-06 13:04:09 +00:00
}