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>
2022-01-31 02:11:47 +00:00
# include <engine/client/checksum.h>
2020-09-26 19:41:58 +00:00
# include <engine/demo.h>
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/map.h>
# include <engine/serverbrowser.h>
# include <engine/shared/config.h>
2020-09-26 19:41:58 +00:00
# include <engine/shared/demo.h>
# include <engine/sound.h>
# include <engine/storage.h>
# include <engine/textrender.h>
# include <engine/updater.h>
2010-05-29 07:25:38 +00:00
# include <game/generated/client_data.h>
2020-10-09 07:07:05 +00:00
# include <game/generated/client_data7.h>
2020-09-26 19:41:58 +00:00
# include <game/generated/protocol.h>
2010-05-29 07:25:38 +00:00
2013-08-23 23:50:35 +00:00
# include <base/math.h>
# include <base/vmath.h>
2020-09-26 19:41:58 +00:00
# include "race.h"
# include "render.h"
2010-05-29 07:25:38 +00:00
# include <game/localization.h>
# include <game/version.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"
2020-09-18 16:45:42 +00:00
# include "components/menu_background.h"
2010-05-29 07:25:38 +00:00
# include "components/menus.h"
# include "components/motd.h"
2020-09-18 16:45:42 +00:00
# include "components/nameplates.h"
2010-05-29 07:25:38 +00:00
# include "components/particles.h"
# include "components/players.h"
# 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-02-04 17:25:04 +00:00
# include "components/ghost.h"
2020-09-26 19:41:58 +00:00
# include "components/race_demo.h"
# include <base/system.h>
2011-08-31 11:56:04 +00:00
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 ; }
2021-02-08 21:26:26 +00:00
const char * CGameClient : : Version ( ) const { return GAME_VERSION ; }
const char * CGameClient : : NetVersion ( ) const { return GAME_NETVERSION ; }
int CGameClient : : DDNetVersion ( ) const { return CLIENT_VERSIONNR ; }
const char * CGameClient : : DDNetVersionStr ( ) const { return m_aDDNetVersionStr ; }
const char * CGameClient : : GetItemName ( int Type ) const { 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 > ( ) ;
2021-09-27 19:37:20 +00:00
m_pConfig = Kernel ( ) - > RequestInterface < IConfigManager > ( ) - > Values ( ) ;
2010-05-29 07:25:38 +00:00
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 ( ) ;
2020-07-09 22:01:00 +00:00
# if defined(CONF_AUTOUPDATE)
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
2021-07-12 09:43:56 +00:00
m_Menus . SetMenuBackground ( & m_MenuBackground ) ;
m_NamePlates . SetPlayers ( & m_Players ) ;
2018-03-13 20:55:47 +00:00
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
2021-07-12 09:43:56 +00:00
m_All . Add ( & m_Skins ) ;
m_All . Add ( & m_CountryFlags ) ;
m_All . Add ( & m_MapImages ) ;
m_All . Add ( & m_Effects ) ; // doesn't render anything, just updates effects
m_All . Add ( & m_Binds ) ;
m_All . Add ( & m_Binds . m_SpecialBinds ) ;
m_All . Add ( & m_Controls ) ;
m_All . Add ( & m_Camera ) ;
m_All . Add ( & m_Sounds ) ;
m_All . Add ( & m_Voting ) ;
m_All . Add ( & m_Particles ) ; // doesn't render anything, just updates all the particles
m_All . Add ( & m_RaceDemo ) ;
m_All . Add ( & m_MapSounds ) ;
2011-04-13 18:37:12 +00:00
2021-07-12 09:29:59 +00:00
m_All . Add ( & m_BackGround ) ; //render instead of m_MapLayersBackGround when g_Config.m_ClOverlayEntities == 100
m_All . Add ( & m_MapLayersBackGround ) ; // first to render
2021-07-12 09:43:56 +00:00
m_All . Add ( & m_Particles . m_RenderTrail ) ;
m_All . Add ( & m_Items ) ;
m_All . Add ( & m_Players ) ;
m_All . Add ( & m_Ghost ) ;
2021-07-12 09:29:59 +00:00
m_All . Add ( & m_MapLayersForeGround ) ;
2021-07-12 09:43:56 +00:00
m_All . Add ( & m_Particles . m_RenderExplosions ) ;
2021-07-12 09:29:59 +00:00
m_All . Add ( & m_NamePlates ) ;
2021-07-12 09:43:56 +00:00
m_All . Add ( & m_Particles . m_RenderGeneral ) ;
m_All . Add ( & m_DamageInd ) ;
2021-07-12 09:29:59 +00:00
m_All . Add ( & m_Hud ) ;
m_All . Add ( & m_Spectator ) ;
m_All . Add ( & m_Emoticon ) ;
m_All . Add ( & m_KillMessages ) ;
2021-07-12 09:43:56 +00:00
m_All . Add ( & m_Chat ) ;
2021-07-12 09:29:59 +00:00
m_All . Add ( & m_Broadcast ) ;
m_All . Add ( & m_DebugHud ) ;
m_All . Add ( & m_Scoreboard ) ;
m_All . Add ( & m_Statboard ) ;
2021-07-12 09:43:56 +00:00
m_All . Add ( & m_Motd ) ;
m_All . Add ( & m_Menus ) ;
2022-04-18 07:34:05 +00:00
m_All . Add ( & m_Tooltips ) ;
2022-01-22 16:34:23 +00:00
m_All . Add ( & CMenus : : m_Binder ) ;
2021-07-12 09:43:56 +00:00
m_All . Add ( & m_GameConsole ) ;
2011-04-13 18:37:12 +00:00
2021-07-12 09:43:56 +00:00
m_All . Add ( & m_MenuBackground ) ;
2020-09-18 16:45:42 +00:00
2008-08-27 15:48:50 +00:00
// build the input stack
2022-01-22 16:34:23 +00:00
m_Input . Add ( & CMenus : : m_Binder ) ; // this will take over all input when we want to bind a key
2021-07-12 09:43:56 +00:00
m_Input . Add ( & m_Binds . m_SpecialBinds ) ;
m_Input . Add ( & m_GameConsole ) ;
m_Input . Add ( & m_Chat ) ; // chat has higher prio due to tha you can quit it by pressing esc
m_Input . Add ( & m_Motd ) ; // for pressing esc to remove it
m_Input . Add ( & m_Menus ) ;
2021-07-12 09:29:59 +00:00
m_Input . Add ( & m_Spectator ) ;
m_Input . Add ( & m_Emoticon ) ;
2021-07-12 09:43:56 +00:00
m_Input . Add ( & m_Controls ) ;
m_Input . Add ( & m_Binds ) ;
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 " ) ;
2020-09-01 13:35:17 +00:00
Console ( ) - > Register ( " kill " , " " , CFGFLAG_CLIENT , ConKill , this , " Kill yourself to restart " ) ;
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 " ) ;
2020-10-17 22:05:59 +00:00
Console ( ) - > Register ( " add_map_votes " , " " , CFGFLAG_SERVER , 0 , 0 , " Automatically adds voting options for all maps " ) ;
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
2019-09-08 22:53:07 +00:00
// register tune zone command to allow the client prediction to load tunezones from the map
2020-09-26 19:41:58 +00:00
Console ( ) - > Register ( " tune_zone " , " i[zone] s[tuning] i[value] " , CFGFLAG_CLIENT | CFGFLAG_GAME , ConTuneZone , this , " Tune in zone a variable to value " ) ;
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 ) ;
2019-05-06 12:19:10 +00:00
Console ( ) - > Chain ( " cl_text_entities_size " , ConchainClTextEntitiesSize , this ) ;
2014-04-28 13:34:56 +00:00
2020-09-18 16:45:42 +00:00
Console ( ) - > Chain ( " cl_menu_map " , ConchainMenuMap , 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
2021-12-03 19:17:43 +00:00
m_UI . Init ( Graphics ( ) , TextRender ( ) ) ;
2022-05-14 11:31:07 +00:00
m_RenderTools . Init ( Graphics ( ) , TextRender ( ) ) ;
2014-12-01 00:31:58 +00:00
2021-06-23 05:05:49 +00:00
int64_t Start = time_get ( ) ;
2011-02-13 12:58:59 +00:00
2020-05-22 15:58:41 +00:00
if ( GIT_SHORTREV_HASH )
{
str_format ( m_aDDNetVersionStr , sizeof ( m_aDDNetVersionStr ) , " %s %s (%s) " , GAME_NAME , GAME_RELEASE_VERSION , GIT_SHORTREV_HASH ) ;
}
else
{
str_format ( m_aDDNetVersionStr , sizeof ( m_aDDNetVersionStr ) , " %s %s " , GAME_NAME , GAME_RELEASE_VERSION ) ;
}
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
2022-04-02 11:37:59 +00:00
// update and swap after font loading, they are quite huge
Client ( ) - > UpdateAndSwap ( ) ;
2011-02-27 16:56:03 +00:00
// init all components
2020-09-26 19:41:58 +00:00
for ( int i = m_All . m_Num - 1 ; i > = 0 ; - - i )
2022-04-02 11:37:59 +00:00
{
2011-02-27 16:56:03 +00:00
m_All . m_paComponents [ i ] - > OnInit ( ) ;
2022-04-02 11:37:59 +00:00
// try to render a frame after each component, also flushes GPU uploads
if ( m_Menus . IsInit ( ) )
m_Menus . RenderLoading ( false ) ;
}
2011-02-27 16:56:03 +00:00
2014-04-27 22:41:19 +00:00
char aBuf [ 256 ] ;
2020-10-09 07:07:05 +00:00
m_GameSkinLoaded = false ;
m_ParticlesSkinLoaded = false ;
m_EmoticonsSkinLoaded = false ;
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
{
2020-09-26 07:37:35 +00:00
if ( i = = IMAGE_GAME )
LoadGameSkin ( g_Config . m_ClAssetGame ) ;
else if ( i = = IMAGE_EMOTICONS )
LoadEmoticonsSkin ( g_Config . m_ClAssetEmoticons ) ;
else if ( i = = IMAGE_PARTICLES )
LoadParticlesSkin ( g_Config . m_ClAssetParticles ) ;
else
g_pData - > m_aImages [ i ] . m_Id = Graphics ( ) - > LoadTexture ( g_pData - > m_aImages [ i ] . m_pFilename , IStorage : : TYPE_ALL , CImageInfo : : FORMAT_AUTO , 0 ) ;
2022-04-02 11:37:59 +00:00
m_Menus . RenderLoading ( false ) ;
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 ;
2022-03-03 21:56:32 +00:00
m_ShowOthers [ 0 ] = SHOW_OTHERS_NOT_SET ;
m_ShowOthers [ 1 ] = SHOW_OTHERS_NOT_SET ;
2021-11-08 22:51:09 +00:00
m_SwitchStateTeam [ 0 ] = - 1 ;
m_SwitchStateTeam [ 1 ] = - 1 ;
2011-04-17 17:14:49 +00:00
2021-01-21 16:07:07 +00:00
m_LastZoom = .0 ;
m_LastScreenAspect = .0 ;
m_LastDummyConnected = false ;
2011-04-17 17:14:49 +00:00
// Set free binds to DDRace binds if it's active
2021-07-12 09:29:59 +00:00
m_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 )
2020-09-26 19:41:58 +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
2021-06-23 05:05:49 +00:00
int64_t End = time_get ( ) ;
2020-09-26 19:41:58 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " initialisation finished after %.2fms " , ( ( End - Start ) * 1000 ) / ( float ) time_freq ( ) ) ;
2018-12-23 21:53:27 +00:00
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-09-08 22:53:07 +00:00
m_GameWorld . m_pTuningList = m_aTuningList ;
2019-05-06 12:19:10 +00:00
2021-07-12 09:43:56 +00:00
m_MapImages . SetTextureScale ( g_Config . m_ClTextEntitiesSize ) ;
2020-09-21 09:39:14 +00:00
// Agressively try to grab window again since some Windows users report
// window not being focussed after starting client.
Graphics ( ) - > SetWindowGrab ( true ) ;
2022-01-31 02:11:47 +00:00
CChecksumData * pChecksum = Client ( ) - > ChecksumData ( ) ;
pChecksum - > m_SizeofGameClient = sizeof ( * this ) ;
pChecksum - > m_NumComponents = m_All . m_Num ;
for ( int i = 0 ; i < m_All . m_Num ; i + + )
{
2022-03-30 13:16:19 +00:00
if ( i > = ( int ) ( std : : size ( pChecksum - > m_aComponentsChecksum ) ) )
2022-01-31 02:11:47 +00:00
{
break ;
}
int Size = m_All . m_paComponents [ i ] - > Sizeof ( ) ;
pChecksum - > m_aComponentsChecksum [ i ] = Size ;
}
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 ;
2021-10-23 11:48:21 +00:00
Input ( ) - > MouseRelative ( & x , & y ) ;
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
{
2021-10-23 11:48:21 +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
{
2019-10-25 01:03:00 +00:00
int PlayerOrDummy = ( g_Config . m_ClDummyResetOnSwitch = = 2 ) ? g_Config . m_ClDummy : ( ! g_Config . m_ClDummy ) ;
2021-07-12 09:43:56 +00:00
m_Controls . ResetInput ( PlayerOrDummy ) ;
m_Controls . m_InputData [ PlayerOrDummy ] . 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 ;
2021-07-12 09:43:56 +00:00
m_DummyInput = m_Controls . m_InputData [ ! g_Config . m_ClDummy ] ;
m_Controls . m_InputData [ g_Config . m_ClDummy ] . m_Fire = tmp ;
2020-04-18 20:16:25 +00:00
m_IsDummySwapping = 1 ;
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
{
2018-03-13 20:55:47 +00:00
if ( ! Dummy )
2017-02-28 09:08:14 +00:00
{
2021-07-12 09:43:56 +00:00
return m_Controls . SnapInput ( pData ) ;
2017-02-28 09:08:14 +00:00
}
if ( ! g_Config . m_ClDummyHammer )
{
if ( m_DummyFire ! = 0 )
{
2020-09-26 19:41:58 +00:00
m_DummyInput . m_Fire = ( m_HammerInput . m_Fire + 1 ) & ~ 1 ;
2017-02-28 09:08:14 +00:00
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
{
2022-04-25 12:10:32 +00:00
if ( m_DummyFire % 25 ! = 0 )
2017-02-28 09:08:14 +00:00
{
m_DummyFire + + ;
return 0 ;
}
m_DummyFire + + ;
2020-09-26 19:41:58 +00:00
m_HammerInput . m_Fire = ( m_HammerInput . m_Fire + 1 ) | 1 ;
2019-07-10 16:04:54 +00:00
m_HammerInput . m_WantedWeapon = WEAPON_HAMMER + 1 ;
if ( ! g_Config . m_ClDummyRestoreWeapon )
{
m_DummyInput . m_WantedWeapon = WEAPON_HAMMER + 1 ;
}
2017-02-28 09:08:14 +00:00
2022-03-20 11:57:50 +00:00
vec2 MainPos = m_LocalCharacterPos ;
vec2 DummyPos = m_aClients [ m_LocalIDs [ ! g_Config . m_ClDummy ] ] . m_Predicted . m_Pos ;
vec2 Dir = MainPos - DummyPos ;
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
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
2020-09-26 19:41:58 +00:00
for ( int i = 0 ; i < m_Collision . GetWidth ( ) * m_Collision . GetHeight ( ) ; i + + )
2017-09-09 18:54:49 +00:00
{
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
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 ;
2021-09-15 14:22:50 +00:00
mem_zero ( & m_GameInfo , sizeof ( m_GameInfo ) ) ;
2020-04-18 20:16:25 +00:00
m_PredictedDummyID = - 1 ;
2020-10-26 14:14:07 +00:00
for ( auto & LastWorldCharacter : m_aLastWorldCharacters )
LastWorldCharacter . m_Alive = false ;
2019-09-08 22:53:07 +00:00
LoadMapSettings ( ) ;
2020-02-21 09:01:31 +00:00
if ( Client ( ) - > State ( ) ! = IClient : : STATE_DEMOPLAYBACK & & g_Config . m_ClAutoDemoOnConnect )
Client ( ) - > DemoRecorder_HandleAutoStart ( ) ;
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
{
2014-05-23 21:59:26 +00:00
m_LastNewPredictedTick [ 0 ] = - 1 ;
m_LastNewPredictedTick [ 1 ] = - 1 ;
2020-07-12 15:32:56 +00:00
2021-05-12 16:57:50 +00:00
m_LocalTuneZone [ 0 ] = 0 ;
m_LocalTuneZone [ 1 ] = 0 ;
m_ExpectingTuningForZone [ 0 ] = - 1 ;
m_ExpectingTuningForZone [ 1 ] = - 1 ;
m_ReceivedTuning [ 0 ] = false ;
m_ReceivedTuning [ 1 ] = false ;
2020-07-12 15:32:56 +00:00
InvalidateSnapshot ( ) ;
2008-08-27 15:48:50 +00:00
2020-10-26 14:14:07 +00:00
for ( auto & Client : m_aClients )
Client . 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 ;
2022-03-03 21:56:32 +00:00
m_ShowOthers [ 0 ] = SHOW_OTHERS_NOT_SET ;
m_ShowOthers [ 1 ] = SHOW_OTHERS_NOT_SET ;
2020-09-05 08:44:50 +00:00
2021-01-21 16:07:07 +00:00
m_LastZoom = .0 ;
m_LastScreenAspect = .0 ;
m_LastDummyConnected = false ;
2020-09-05 08:44:50 +00:00
m_ReceivedDDNetPlayer = false ;
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
{
2020-09-26 19:41:58 +00:00
if ( ! m_Snap . m_pLocalCharacter | | ( m_Snap . m_pGameInfoObj & & m_Snap . m_pGameInfoObj - > m_GameStateFlags & GAMESTATEFLAG_GAMEOVER ) )
2013-10-09 14:02:23 +00:00
{
// don't use predicted
}
else
2020-02-19 10:24:58 +00:00
m_LocalCharacterPos = mix ( m_PredictedPrevChar . m_Pos , m_PredictedChar . m_Pos , Client ( ) - > PredIntraGameTick ( g_Config . m_ClDummy ) ) ;
2008-08-27 15:48:50 +00:00
}
else
2013-10-09 14:02:23 +00:00
{
2020-09-26 19:41:58 +00:00
if ( ! ( m_Snap . m_pGameInfoObj & & m_Snap . m_pGameInfoObj - > m_GameStateFlags & GAMESTATEFLAG_GAMEOVER ) )
2013-10-09 14:02:23 +00:00
{
2018-03-13 20:55:47 +00:00
if ( m_Snap . m_pLocalCharacter )
2020-02-19 10:24:58 +00:00
m_LocalCharacterPos = mix ( m_PredictedPrevChar . m_Pos , m_PredictedChar . m_Pos , Client ( ) - > PredIntraGameTick ( g_Config . m_ClDummy ) ) ;
2013-10-09 14:02:23 +00:00
}
2020-09-26 19:41:58 +00:00
// else
// m_LocalCharacterPos = mix(m_PredictedPrevChar.m_Pos, m_PredictedChar.m_Pos, Client()->PredIntraGameTick(g_Config.m_ClDummy));
2013-10-09 14:02:23 +00:00
}
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 ) ,
2020-02-19 10:24:58 +00:00
vec2 ( m_Snap . m_pLocalCharacter - > m_X , m_Snap . m_pLocalCharacter - > m_Y ) , Client ( ) - > IntraGameTick ( g_Config . m_ClDummy ) ) ;
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 ) ,
2020-02-19 10:24:58 +00:00
Client ( ) - > IntraGameTick ( g_Config . m_ClDummy ) ) ;
2011-03-12 17:07:57 +00:00
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
{
2020-09-06 23:02:17 +00:00
if ( m_Snap . m_pPrevSpectatorInfo & & m_Snap . m_pPrevSpectatorInfo - > m_SpectatorID = = m_Snap . m_pSpectatorInfo - > m_SpectatorID )
2011-03-12 17:07:57 +00:00
m_Snap . m_SpecInfo . m_Position = mix ( vec2 ( m_Snap . m_pPrevSpectatorInfo - > m_X , m_Snap . m_pPrevSpectatorInfo - > m_Y ) ,
2020-09-26 19:41:58 +00:00
vec2 ( m_Snap . m_pSpectatorInfo - > m_X , m_Snap . m_pSpectatorInfo - > m_Y ) , Client ( ) - > IntraGameTick ( g_Config . m_ClDummy ) ) ;
2011-03-12 17:07:57 +00:00
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
}
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
2021-02-10 22:02:34 +00:00
// display gfx & client warnings
for ( SWarning * pWarning : { Graphics ( ) - > GetCurWarning ( ) , Client ( ) - > GetCurWarning ( ) } )
2020-08-29 10:49:45 +00:00
{
2021-07-12 09:43:56 +00:00
if ( pWarning ! = NULL & & m_Menus . CanDisplayWarning ( ) )
2020-10-02 13:43:52 +00:00
{
2021-07-12 09:43:56 +00:00
m_Menus . PopupWarning ( Localize ( " Warning " ) , pWarning - > m_aWarningMsg , " Ok " , 10000000 ) ;
2020-10-02 13:43:52 +00:00
pWarning - > m_WasShown = true ;
}
}
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
2021-07-12 09:43:56 +00:00
if ( Client ( ) - > State ( ) = = IClient : : STATE_ONLINE & & ! m_Menus . IsActive ( ) )
2020-09-26 19:41:58 +00:00
{
if ( m_CheckInfo [ 0 ] = = 0 )
{
2015-04-19 11:11:45 +00:00
if (
2020-09-26 19:41:58 +00:00
str_comp ( m_aClients [ m_LocalIDs [ 0 ] ] . m_aName , Client ( ) - > 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 ! = ( int ) g_Config . m_ClPlayerColorBody | |
m_aClients [ m_LocalIDs [ 0 ] ] . m_ColorFeet ! = ( int ) g_Config . m_ClPlayerColorFeet )
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
2020-09-26 19:41:58 +00:00
if ( Client ( ) - > DummyConnected ( ) )
{
if ( m_CheckInfo [ 1 ] = = 0 )
{
2015-04-19 11:11:45 +00:00
if (
2020-09-26 19:41:58 +00:00
str_comp ( m_aClients [ m_LocalIDs [ 1 ] ] . m_aName , Client ( ) - > DummyName ( ) ) | |
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 ! = ( int ) g_Config . m_ClDummyColorBody | |
m_aClients [ m_LocalIDs [ 1 ] ] . m_ColorFeet ! = ( int ) 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 ;
2022-03-03 21:56:32 +00:00
m_ShowOthers [ 1 ] = SHOW_OTHERS_NOT_SET ;
2014-05-23 21:59:26 +00:00
m_LastNewPredictedTick [ 1 ] = - 1 ;
2020-04-18 20:16:25 +00:00
m_PredictedDummyID = - 1 ;
2014-04-28 14:47:44 +00:00
}
2019-03-25 19:02:50 +00:00
int CGameClient : : GetLastRaceTick ( )
{
2021-07-12 09:43:56 +00:00
return m_Ghost . GetLastRaceTick ( ) ;
2019-03-25 19:02:50 +00:00
}
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 ( ) ;
}
2022-01-21 21:13:35 +00:00
void CGameClient : : OnMessage ( int MsgId , CUnpacker * pUnpacker , int Conn , bool Dummy )
2008-08-27 15:48:50 +00:00
{
2008-08-29 05:34:18 +00:00
// special messages
2020-12-06 18:58:04 +00:00
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 ;
2020-09-26 19:41:58 +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
2022-01-21 21:13:35 +00:00
m_ReceivedTuning [ Conn ] = true ;
2008-08-29 05:34:18 +00:00
// apply new tuning
2022-01-21 21:13:35 +00:00
m_Tuning [ Conn ] = 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 ;
}
2022-01-21 00:54:14 +00:00
if ( Dummy )
2014-05-07 01:34:21 +00:00
{
2020-09-26 19:41:58 +00:00
if ( MsgId = = NETMSGTYPE_SV_CHAT & & m_LocalIDs [ 0 ] > = 0 & & m_LocalIDs [ 1 ] > = 0 )
2014-05-07 01:34:21 +00:00
{
CNetMsg_Sv_Chat * pMsg = ( CNetMsg_Sv_Chat * ) pRawMsg ;
2020-09-26 19:41:58 +00:00
if ( ( pMsg - > m_Team = = 1 & & ( 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 ] ) ) ) | | pMsg - > m_Team > 1 )
2014-05-07 01:34:21 +00:00
{
2021-07-12 09:43:56 +00:00
m_Chat . OnMessage ( MsgId , pRawMsg ) ;
2014-05-07 01:34:21 +00:00
}
}
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
{
2022-01-21 21:13:35 +00:00
Client ( ) - > EnterGame ( Conn ) ;
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 ;
2022-01-21 21:13:35 +00:00
m_aClients [ pMsg - > m_ClientID ] . m_EmoticonStartTick = Client ( ) - > GameTick ( Conn ) ;
m_aClients [ pMsg - > m_ClientID ] . m_EmoticonStartFraction = Client ( ) - > IntraGameTickSincePrev ( Conn ) ;
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 )
2021-07-12 09:43:56 +00:00
m_Sounds . Enqueue ( CSounds : : CHN_GLOBAL , pMsg - > m_SoundID ) ;
2014-10-25 00:52:08 +00:00
}
2010-07-17 17:55:17 +00:00
else
2014-10-25 00:52:08 +00:00
{
if ( g_Config . m_SndGame )
2021-07-12 09:43:56 +00:00
m_Sounds . Play ( CSounds : : CHN_GLOBAL , pMsg - > m_SoundID , 1.0f ) ;
2014-10-25 00:52:08 +00:00
}
2011-04-13 18:37:12 +00:00
}
2021-01-10 16:23:00 +00:00
else if ( MsgId = = NETMSGTYPE_SV_TEAMSSTATE | | MsgId = = NETMSGTYPE_SV_TEAMSSTATELEGACY )
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 ;
2021-12-23 11:06:54 +00:00
if ( ! WentWrong & & Team > = TEAM_FLOCK & & Team < = TEAM_SUPER )
2014-02-08 22:41:12 +00:00
m_Teams . Team ( i , Team ) ;
2021-12-23 11:06:54 +00:00
else
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
2021-07-12 09:43:56 +00:00
m_Ghost . m_AllowRestart = true ;
m_RaceDemo . m_AllowRestart = true ;
2011-01-06 05:30:19 +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
2019-11-22 14:37:18 +00:00
if ( ! ( m_GameWorld . m_WorldConfig . m_IsFNG & & pMsg - > m_Weapon = = WEAPON_LASER ) )
2019-04-11 22:46:54 +00:00
{
m_CharOrder . GiveWeak ( pMsg - > m_Victim ) ;
m_aLastWorldCharacters [ pMsg - > m_Victim ] . m_Alive = false ;
2019-05-04 01:48:17 +00:00
if ( CCharacter * pChar = m_GameWorld . GetCharacterByID ( pMsg - > m_Victim ) )
pChar - > ResetPrediction ( ) ;
2019-04-11 22:46:54 +00:00
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 ( )
{
2022-01-20 11:19:06 +00:00
for ( int i = 0 ; i < m_All . m_Num ; i + + )
m_All . m_paComponents [ i ] - > OnShutdown ( ) ;
2011-02-04 17:25:04 +00:00
}
2014-09-03 12:17:44 +00:00
void CGameClient : : OnEnterGame ( )
{
2021-07-12 09:43:56 +00:00
m_Effects . ResetDamageIndicator ( ) ;
2014-09-03 12:17:44 +00:00
}
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 ( )
{
2020-02-21 09:01:31 +00:00
if ( Client ( ) - > State ( ) ! = IClient : : STATE_DEMOPLAYBACK & & ! g_Config . m_ClAutoDemoOnConnect )
2011-01-06 22:21:51 +00:00
Client ( ) - > DemoRecorder_HandleAutoStart ( ) ;
2021-07-12 09:43:56 +00:00
m_Statboard . 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 ( ) ;
2020-10-12 10:29:47 +00:00
UI ( ) - > OnWindowResize ( ) ;
2018-03-21 14:54:51 +00:00
TextRender ( ) - > OnWindowResize ( ) ;
}
void CGameClient : : OnWindowResizeCB ( void * pUser )
{
2020-09-26 19:41:58 +00:00
CGameClient * pClient = ( CGameClient * ) pUser ;
2018-03-21 14:54:51 +00:00
pClient - > OnWindowResize ( ) ;
}
2020-10-12 10:29:47 +00:00
void CGameClient : : OnLanguageChange ( )
{
UI ( ) - > OnLanguageChange ( ) ;
}
2017-07-24 19:43:55 +00:00
void CGameClient : : OnRconType ( bool UsernameReq )
{
2021-07-12 09:43:56 +00:00
m_GameConsole . RequireUsername ( UsernameReq ) ;
2017-07-24 19:43:55 +00:00
}
2010-05-29 07:25:38 +00:00
void CGameClient : : OnRconLine ( const char * pLine )
{
2021-07-12 09:43:56 +00:00
m_GameConsole . PrintLine ( CGameConsole : : CONSOLETYPE_REMOTE , pLine ) ;
2010-05-29 07:25:38 +00:00
}
2008-08-27 15:48:50 +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 ;
2021-07-12 09:43:56 +00:00
m_Effects . DamageIndicator ( vec2 ( ev - > m_X , ev - > m_Y ) , direction ( ev - > m_Angle / 256.0f ) ) ;
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 ;
2021-07-12 09:43:56 +00:00
m_Effects . 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 ;
2021-07-12 09:43:56 +00:00
m_Effects . 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 ;
2021-07-12 09:43:56 +00:00
m_Effects . 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 ;
2021-07-12 09:43:56 +00:00
m_Effects . 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 ;
2022-02-22 21:31:16 +00:00
if ( ! Config ( ) - > m_SndGame )
continue ;
if ( m_GameInfo . m_RaceSounds & & ( ( ev - > m_SoundID = = SOUND_GUN_FIRE & & ! g_Config . m_SndGun ) | | ( ev - > m_SoundID = = SOUND_PLAYER_PAIN_LONG & & ! g_Config . m_SndLongPain ) ) )
continue ;
m_Sounds . PlayAt ( CSounds : : CHN_WORLD , ev - > m_SoundID , 1.0f , vec2 ( ev - > m_X , ev - > m_Y ) ) ;
2008-08-27 15:48:50 +00:00
}
}
}
2019-06-03 19:52:14 +00:00
static CGameInfo GetGameInfo ( const CNetObj_GameInfoEx * pInfoEx , int InfoExSize , CServerInfo * pFallbackServerInfo )
{
int Version = - 1 ;
2020-09-25 06:17:14 +00:00
if ( InfoExSize > = 12 )
2019-06-03 19:52:14 +00:00
{
2019-06-13 22:24:50 +00:00
Version = pInfoEx - > m_Version ;
2019-06-03 19:52:14 +00:00
}
2020-09-25 06:17:14 +00:00
else if ( InfoExSize > = 8 )
{
Version = minimum ( pInfoEx - > m_Version , 4 ) ;
}
2019-06-13 22:24:50 +00:00
else if ( InfoExSize > = 4 )
2019-06-03 19:52:14 +00:00
{
2019-06-13 22:24:50 +00:00
Version = 0 ;
2019-06-03 19:52:14 +00:00
}
int Flags = 0 ;
if ( Version > = 0 )
{
Flags = pInfoEx - > m_Flags ;
}
2020-09-24 09:38:27 +00:00
int Flags2 = 0 ;
if ( Version > = 5 )
{
Flags2 = pInfoEx - > m_Flags2 ;
}
2019-06-13 22:24:50 +00:00
bool Race ;
bool FastCap ;
bool FNG ;
bool DDRace ;
bool DDNet ;
bool BlockWorlds ;
2020-09-24 10:01:12 +00:00
bool City ;
2019-06-13 22:24:50 +00:00
bool Vanilla ;
bool Plus ;
2020-12-21 15:45:19 +00:00
bool FDDrace ;
2019-06-13 22:24:50 +00:00
if ( Version < 1 )
{
Race = IsRace ( pFallbackServerInfo ) ;
FastCap = IsFastCap ( pFallbackServerInfo ) ;
FNG = IsFNG ( pFallbackServerInfo ) ;
DDRace = IsDDRace ( pFallbackServerInfo ) ;
DDNet = IsDDNet ( pFallbackServerInfo ) ;
BlockWorlds = IsBlockWorlds ( pFallbackServerInfo ) ;
2020-09-24 10:01:12 +00:00
City = IsCity ( pFallbackServerInfo ) ;
2019-06-13 22:24:50 +00:00
Vanilla = IsVanilla ( pFallbackServerInfo ) ;
Plus = IsPlus ( pFallbackServerInfo ) ;
2020-12-21 15:45:19 +00:00
FDDrace = false ;
2019-06-13 22:24:50 +00:00
}
else
2019-06-03 19:52:14 +00:00
{
2020-09-24 10:01:54 +00:00
Race = Flags & GAMEINFOFLAG_GAMETYPE_RACE ;
FastCap = Flags & GAMEINFOFLAG_GAMETYPE_FASTCAP ;
FNG = Flags & GAMEINFOFLAG_GAMETYPE_FNG ;
DDRace = Flags & GAMEINFOFLAG_GAMETYPE_DDRACE ;
DDNet = Flags & GAMEINFOFLAG_GAMETYPE_DDNET ;
BlockWorlds = Flags & GAMEINFOFLAG_GAMETYPE_BLOCK_WORLDS ;
Vanilla = Flags & GAMEINFOFLAG_GAMETYPE_VANILLA ;
Plus = Flags & GAMEINFOFLAG_GAMETYPE_PLUS ;
2020-09-25 06:17:14 +00:00
City = Version > = 5 & & Flags2 & GAMEINFOFLAG2_GAMETYPE_CITY ;
2020-12-21 15:45:19 +00:00
FDDrace = Version > = 6 & & Flags2 & GAMEINFOFLAG2_GAMETYPE_FDDRACE ;
2019-06-03 19:52:14 +00:00
2019-06-13 22:24:50 +00:00
// Ensure invariants upheld by the server info parsing business.
2020-12-21 15:45:19 +00:00
DDRace = DDRace | | DDNet | | FDDrace ;
2019-06-03 19:52:14 +00:00
Race = Race | | FastCap | | DDRace ;
}
CGameInfo Info ;
Info . m_FlagStartsRace = FastCap ;
Info . m_TimeScore = Race ;
Info . m_UnlimitedAmmo = Race ;
2019-07-19 09:28:08 +00:00
Info . m_DDRaceRecordMessage = DDRace & & ! DDNet ;
Info . m_RaceRecordMessage = DDNet | | ( Race & & ! DDRace ) ;
2022-04-16 17:36:25 +00:00
Info . m_RaceSounds = DDRace | | FNG | | BlockWorlds ;
2020-09-24 10:01:12 +00:00
Info . m_AllowEyeWheel = DDRace | | BlockWorlds | | City | | Plus ;
2019-06-03 19:52:14 +00:00
Info . m_AllowHookColl = DDRace ;
2020-09-24 10:01:12 +00:00
Info . m_AllowZoom = Race | | BlockWorlds | | City ;
2019-06-03 19:52:14 +00:00
Info . m_BugDDRaceGhost = DDRace ;
Info . m_BugDDRaceInput = DDRace ;
Info . m_BugFNGLaserRange = FNG ;
Info . m_BugVanillaBounce = Vanilla ;
Info . m_PredictFNG = FNG ;
Info . m_PredictDDRace = DDRace ;
Info . m_PredictDDRaceTiles = DDRace & & ! BlockWorlds ;
Info . m_PredictVanilla = Vanilla | | FastCap ;
Info . m_EntitiesDDNet = DDNet ;
Info . m_EntitiesDDRace = DDRace ;
Info . m_EntitiesRace = Race ;
Info . m_EntitiesFNG = FNG ;
Info . m_EntitiesVanilla = Vanilla ;
2020-05-19 14:49:28 +00:00
Info . m_EntitiesBW = BlockWorlds ;
2019-07-19 09:28:08 +00:00
Info . m_Race = Race ;
2019-07-31 19:22:11 +00:00
Info . m_DontMaskEntities = ! DDNet ;
2020-09-25 06:17:14 +00:00
Info . m_AllowXSkins = false ;
2020-12-21 15:45:19 +00:00
Info . m_EntitiesFDDrace = FDDrace ;
2019-06-03 19:52:14 +00:00
if ( Version > = 0 )
{
2020-09-26 19:41:58 +00:00
Info . m_TimeScore = Flags & GAMEINFOFLAG_TIMESCORE ;
2019-06-03 19:52:14 +00:00
}
if ( Version > = 2 )
{
2020-09-26 19:41:58 +00:00
Info . m_FlagStartsRace = Flags & GAMEINFOFLAG_FLAG_STARTS_RACE ;
Info . m_UnlimitedAmmo = Flags & GAMEINFOFLAG_UNLIMITED_AMMO ;
Info . m_DDRaceRecordMessage = Flags & GAMEINFOFLAG_DDRACE_RECORD_MESSAGE ;
Info . m_RaceRecordMessage = Flags & GAMEINFOFLAG_RACE_RECORD_MESSAGE ;
Info . m_AllowEyeWheel = Flags & GAMEINFOFLAG_ALLOW_EYE_WHEEL ;
Info . m_AllowHookColl = Flags & GAMEINFOFLAG_ALLOW_HOOK_COLL ;
Info . m_AllowZoom = Flags & GAMEINFOFLAG_ALLOW_ZOOM ;
Info . m_BugDDRaceGhost = Flags & GAMEINFOFLAG_BUG_DDRACE_GHOST ;
Info . m_BugDDRaceInput = Flags & GAMEINFOFLAG_BUG_DDRACE_INPUT ;
Info . m_BugFNGLaserRange = Flags & GAMEINFOFLAG_BUG_FNG_LASER_RANGE ;
Info . m_BugVanillaBounce = Flags & GAMEINFOFLAG_BUG_VANILLA_BOUNCE ;
Info . m_PredictFNG = Flags & GAMEINFOFLAG_PREDICT_FNG ;
Info . m_PredictDDRace = Flags & GAMEINFOFLAG_PREDICT_DDRACE ;
Info . m_PredictDDRaceTiles = Flags & GAMEINFOFLAG_PREDICT_DDRACE_TILES ;
Info . m_PredictVanilla = Flags & GAMEINFOFLAG_PREDICT_VANILLA ;
Info . m_EntitiesDDNet = Flags & GAMEINFOFLAG_ENTITIES_DDNET ;
Info . m_EntitiesDDRace = Flags & GAMEINFOFLAG_ENTITIES_DDRACE ;
Info . m_EntitiesRace = Flags & GAMEINFOFLAG_ENTITIES_RACE ;
Info . m_EntitiesFNG = Flags & GAMEINFOFLAG_ENTITIES_FNG ;
Info . m_EntitiesVanilla = Flags & GAMEINFOFLAG_ENTITIES_VANILLA ;
2019-06-03 19:52:14 +00:00
}
2019-07-19 08:21:32 +00:00
if ( Version > = 3 )
{
2020-09-26 19:41:58 +00:00
Info . m_Race = Flags & GAMEINFOFLAG_RACE ;
Info . m_DontMaskEntities = Flags & GAMEINFOFLAG_DONT_MASK_ENTITIES ;
2019-07-19 08:21:32 +00:00
}
2020-09-25 06:17:14 +00:00
if ( Version > = 4 )
2020-05-19 15:13:34 +00:00
{
2020-09-26 19:41:58 +00:00
Info . m_EntitiesBW = Flags & GAMEINFOFLAG_ENTITIES_BW ;
2020-05-19 15:13:34 +00:00
}
2020-09-25 06:17:14 +00:00
if ( Version > = 5 )
{
Info . m_AllowXSkins = Flags2 & GAMEINFOFLAG2_ALLOW_X_SKINS ;
}
2020-12-21 15:45:19 +00:00
if ( Version > = 6 )
{
Info . m_EntitiesFDDrace = Flags2 & GAMEINFOFLAG2_ENTITIES_FDDRACE ;
}
2019-06-03 19:52:14 +00:00
return Info ;
}
2020-07-12 15:32:56 +00:00
void CGameClient : : InvalidateSnapshot ( )
2008-08-27 15:48:50 +00:00
{
2020-07-12 15:32:56 +00:00
// clear all pointers
2021-07-12 09:43:56 +00:00
mem_zero ( & m_Snap , sizeof ( m_Snap ) ) ;
2011-02-12 10:40:36 +00:00
m_Snap . m_LocalClientID = - 1 ;
2020-07-12 15:32:56 +00:00
}
void CGameClient : : OnNewSnapshot ( )
{
2022-02-14 16:38:13 +00:00
auto & & Evolve = [ this ] ( CNetObj_Character * pCharacter , int Tick ) {
2021-07-12 10:04:45 +00:00
CWorldCore TempWorld ;
CCharacterCore TempCore ;
CTeamsCore TempTeams ;
mem_zero ( & TempCore , sizeof ( TempCore ) ) ;
mem_zero ( & TempTeams , sizeof ( TempTeams ) ) ;
TempCore . Init ( & TempWorld , Collision ( ) , & TempTeams ) ;
TempCore . Read ( pCharacter ) ;
TempCore . m_ActiveWeapon = pCharacter - > m_Weapon ;
while ( pCharacter - > m_Tick < Tick )
{
pCharacter - > m_Tick + + ;
TempCore . Tick ( false ) ;
TempCore . Move ( ) ;
TempCore . Quantize ( ) ;
}
TempCore . Write ( pCharacter ) ;
} ;
2020-07-12 15:32:56 +00:00
InvalidateSnapshot ( ) ;
m_NewTick = true ;
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
{
2019-06-03 22:05:28 +00:00
if ( g_Config . m_Debug & & Item . m_Type ! = UUID_UNKNOWN )
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
{
2020-09-26 19:41:58 +00:00
if ( ( Client ( ) - > GameTick ( g_Config . m_ClDummy ) % 100 ) = = 0 )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
char aMessage [ 64 ] ;
2020-09-26 19:41:58 +00:00
int MsgLen = rand ( ) % ( sizeof ( aMessage ) - 1 ) ;
2010-05-29 07:25:38 +00:00
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 ;
2020-09-26 19:41:58 +00:00
Msg . m_Team = rand ( ) & 1 ;
2010-05-29 07:25:38 +00:00
Msg . m_pMessage = aMessage ;
2022-01-21 00:54:14 +00:00
Client ( ) - > SendPackMsgActive ( & 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
2019-06-03 19:52:14 +00:00
bool FoundGameInfoEx = false ;
2021-11-08 22:51:09 +00:00
bool GotSwitchStateTeam = false ;
m_SwitchStateTeam [ g_Config . m_ClDummy ] = - 1 ;
2019-06-03 19:52:14 +00:00
2020-10-26 14:14:07 +00:00
for ( auto & Client : m_aClients )
2020-06-25 12:56:23 +00:00
{
2020-10-26 14:14:07 +00:00
Client . m_SpecCharPresent = false ;
2020-06-25 12:56:23 +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 ;
2020-06-25 16:29:56 +00:00
if ( ClientID < MAX_CLIENTS )
{
CClientData * pClient = & m_aClients [ ClientID ] ;
2011-04-13 18:37:12 +00:00
2020-06-25 16:29:56 +00:00
IntsToStr ( & pInfo - > m_Name0 , 4 , pClient - > m_aName ) ;
IntsToStr ( & pInfo - > m_Clan0 , 3 , pClient - > m_aClan ) ;
pClient - > m_Country = pInfo - > m_Country ;
IntsToStr ( & pInfo - > m_Skin0 , 6 , pClient - > m_aSkinName ) ;
2011-04-13 18:37:12 +00:00
2020-06-25 16:29:56 +00:00
pClient - > m_UseCustomColor = pInfo - > m_UseCustomColor ;
pClient - > m_ColorBody = pInfo - > m_ColorBody ;
pClient - > m_ColorFeet = pInfo - > m_ColorFeet ;
2011-04-13 18:37:12 +00:00
2020-06-25 16:29:56 +00:00
// prepare the info
2020-11-04 18:28:06 +00:00
if ( ! m_GameInfo . m_AllowXSkins & & ( pClient - > m_aSkinName [ 0 ] = = ' x ' & & pClient - > m_aSkinName [ 1 ] = = ' _ ' ) )
2020-06-25 16:29:56 +00:00
str_copy ( pClient - > m_aSkinName , " default " , 64 ) ;
2011-04-13 18:37:12 +00:00
2020-06-25 16:29:56 +00:00
pClient - > m_SkinInfo . m_ColorBody = color_cast < ColorRGBA > ( ColorHSLA ( pClient - > m_ColorBody ) . UnclampLighting ( ) ) ;
pClient - > m_SkinInfo . m_ColorFeet = color_cast < ColorRGBA > ( ColorHSLA ( pClient - > m_ColorFeet ) . UnclampLighting ( ) ) ;
pClient - > m_SkinInfo . m_Size = 64 ;
2011-04-13 18:37:12 +00:00
2020-06-25 16:29:56 +00:00
// find new skin
2021-07-12 09:43:56 +00:00
const CSkin * pSkin = m_Skins . Get ( m_Skins . Find ( pClient - > m_aSkinName ) ) ;
2020-10-09 07:07:05 +00:00
pClient - > m_SkinInfo . m_OriginalRenderSkin = pSkin - > m_OriginalSkin ;
pClient - > m_SkinInfo . m_ColorableRenderSkin = pSkin - > m_ColorableSkin ;
2020-11-08 05:39:16 +00:00
pClient - > m_SkinInfo . m_SkinMetrics = pSkin - > m_Metrics ;
2020-10-09 07:07:05 +00:00
pClient - > m_SkinInfo . m_BloodColor = pSkin - > m_BloodColor ;
pClient - > m_SkinInfo . m_CustomColoredSkin = pClient - > m_UseCustomColor ;
2020-06-25 16:29:56 +00:00
2020-10-09 07:07:05 +00:00
if ( ! pClient - > m_UseCustomColor )
2020-06-25 16:29:56 +00:00
{
2020-09-26 19:41:58 +00:00
pClient - > m_SkinInfo . m_ColorBody = ColorRGBA ( 1 , 1 , 1 ) ;
pClient - > m_SkinInfo . m_ColorFeet = ColorRGBA ( 1 , 1 , 1 ) ;
2020-06-25 16:29:56 +00:00
}
2008-10-08 20:47:56 +00:00
2021-07-12 10:04:45 +00:00
pClient - > UpdateRenderInfo ( IsTeamPlay ( ) ) ;
2020-06-25 16:29:56 +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
2020-06-25 16:29:56 +00:00
if ( pInfo - > m_ClientID < MAX_CLIENTS )
2008-08-27 15:48:50 +00:00
{
2020-06-25 16:29:56 +00:00
m_aClients [ pInfo - > m_ClientID ] . m_Team = pInfo - > m_Team ;
m_aClients [ pInfo - > m_ClientID ] . m_Active = true ;
m_Snap . m_paPlayerInfos [ pInfo - > m_ClientID ] = pInfo ;
m_Snap . m_NumPlayers + + ;
2011-04-13 18:37:12 +00:00
2020-06-25 16:29:56 +00:00
if ( pInfo - > m_Local )
2011-03-12 17:07:57 +00:00
{
2020-06-25 16:29:56 +00:00
m_Snap . m_LocalClientID = Item . m_ID ;
m_Snap . m_pLocalInfo = pInfo ;
if ( pInfo - > m_Team = = TEAM_SPECTATORS )
{
m_Snap . m_SpecInfo . m_Active = true ;
}
2011-03-12 17:07:57 +00:00
}
2011-04-13 18:37:12 +00:00
2020-06-25 16:29:56 +00:00
// calculate team-balance
if ( pInfo - > m_Team ! = TEAM_SPECTATORS )
{
m_Snap . m_aTeamSize [ pInfo - > m_Team ] + + ;
if ( ! m_aStats [ pInfo - > m_ClientID ] . IsActive ( ) )
m_aStats [ pInfo - > m_ClientID ] . JoinGame ( Client ( ) - > GameTick ( g_Config . m_ClDummy ) ) ;
}
else if ( m_aStats [ pInfo - > m_ClientID ] . IsActive ( ) )
m_aStats [ pInfo - > m_ClientID ] . JoinSpec ( Client ( ) - > GameTick ( g_Config . m_ClDummy ) ) ;
2015-05-19 22:51:02 +00:00
}
2008-08-27 15:48:50 +00:00
}
2019-05-14 23:03:30 +00:00
else if ( Item . m_Type = = NETOBJTYPE_DDNETPLAYER )
{
2020-09-05 08:44:50 +00:00
m_ReceivedDDNetPlayer = true ;
2019-05-14 23:03:30 +00:00
const CNetObj_DDNetPlayer * pInfo = ( const CNetObj_DDNetPlayer * ) pData ;
2020-06-25 16:29:56 +00:00
if ( Item . m_ID < MAX_CLIENTS )
{
m_aClients [ Item . m_ID ] . m_AuthLevel = pInfo - > m_AuthLevel ;
m_aClients [ Item . m_ID ] . m_Afk = pInfo - > m_Flags & EXPLAYERFLAG_AFK ;
m_aClients [ Item . m_ID ] . m_Paused = pInfo - > m_Flags & EXPLAYERFLAG_PAUSED ;
m_aClients [ Item . m_ID ] . m_Spec = pInfo - > m_Flags & EXPLAYERFLAG_SPEC ;
2022-03-14 12:25:47 +00:00
if ( Item . m_ID = = m_Snap . m_LocalClientID & & ( m_aClients [ Item . m_ID ] . m_Paused | | m_aClients [ Item . m_ID ] . m_Spec ) )
{
m_Snap . m_SpecInfo . m_Active = true ;
}
2020-06-25 16:29:56 +00:00
}
2019-05-14 23:03:30 +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
{
2020-06-25 16:29:56 +00:00
if ( Item . m_ID < MAX_CLIENTS )
2008-09-23 07:43:41 +00:00
{
2020-06-25 16:29:56 +00:00
const void * pOld = Client ( ) - > SnapFindItem ( IClient : : SNAP_PREV , NETOBJTYPE_CHARACTER , Item . m_ID ) ;
m_Snap . m_aCharacters [ Item . m_ID ] . m_Cur = * ( ( const CNetObj_Character * ) pData ) ;
if ( pOld )
2019-11-09 21:49:53 +00:00
{
2020-06-25 16:29:56 +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 ) ;
2022-01-21 10:30:31 +00:00
// limit evolving to 3 seconds
2022-02-07 11:16:39 +00:00
bool EvolvePrev = Client ( ) - > PrevGameTick ( g_Config . m_ClDummy ) - m_Snap . m_aCharacters [ Item . m_ID ] . m_Prev . m_Tick < = 3 * Client ( ) - > GameTickSpeed ( ) ;
bool EvolveCur = Client ( ) - > GameTick ( g_Config . m_ClDummy ) - m_Snap . m_aCharacters [ Item . m_ID ] . m_Cur . m_Tick < = 3 * Client ( ) - > GameTickSpeed ( ) ;
2022-01-21 10:30:31 +00:00
2020-06-25 16:29:56 +00:00
// reuse the result from the previous evolve if the snapped character didn't change since the previous snapshot
2022-02-07 11:16:39 +00:00
if ( EvolveCur & & m_aClients [ Item . m_ID ] . m_Evolved . m_Tick = = Client ( ) - > PrevGameTick ( g_Config . m_ClDummy ) )
2020-06-25 16:29:56 +00:00
{
if ( mem_comp ( & m_Snap . m_aCharacters [ Item . m_ID ] . m_Prev , & m_aClients [ Item . m_ID ] . m_Snapped , sizeof ( CNetObj_Character ) ) = = 0 )
m_Snap . m_aCharacters [ Item . m_ID ] . m_Prev = m_aClients [ Item . m_ID ] . m_Evolved ;
if ( mem_comp ( & m_Snap . m_aCharacters [ Item . m_ID ] . m_Cur , & m_aClients [ Item . m_ID ] . m_Snapped , sizeof ( CNetObj_Character ) ) = = 0 )
m_Snap . m_aCharacters [ Item . m_ID ] . m_Cur = m_aClients [ Item . m_ID ] . m_Evolved ;
}
2022-02-07 13:29:49 +00:00
if ( EvolvePrev & & m_Snap . m_aCharacters [ Item . m_ID ] . m_Prev . m_Tick )
2022-02-07 11:16:39 +00:00
Evolve ( & m_Snap . m_aCharacters [ Item . m_ID ] . m_Prev , Client ( ) - > PrevGameTick ( g_Config . m_ClDummy ) ) ;
2022-02-07 13:29:49 +00:00
if ( EvolveCur & & m_Snap . m_aCharacters [ Item . m_ID ] . m_Cur . m_Tick )
2022-02-07 11:16:39 +00:00
Evolve ( & m_Snap . m_aCharacters [ Item . m_ID ] . m_Cur , Client ( ) - > GameTick ( g_Config . m_ClDummy ) ) ;
2020-06-25 16:29:56 +00:00
m_aClients [ Item . m_ID ] . m_Snapped = * ( ( const CNetObj_Character * ) pData ) ;
m_aClients [ Item . m_ID ] . m_Evolved = m_Snap . m_aCharacters [ Item . m_ID ] . m_Cur ;
}
else
{
m_aClients [ Item . m_ID ] . m_Evolved . m_Tick = - 1 ;
2019-11-09 21:49:53 +00:00
}
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 ;
2020-06-25 16:29:56 +00:00
if ( Item . m_ID < MAX_CLIENTS )
{
m_Snap . m_aCharacters [ Item . m_ID ] . m_ExtendedData = * pCharacterData ;
m_Snap . m_aCharacters [ Item . m_ID ] . m_HasExtendedData = true ;
CClientData * pClient = & m_aClients [ Item . m_ID ] ;
// Collision
pClient - > m_Solo = pCharacterData - > m_Flags & CHARACTERFLAG_SOLO ;
2021-08-08 10:36:25 +00:00
pClient - > m_Jetpack = pCharacterData - > m_Flags & CHARACTERFLAG_JETPACK ;
2020-06-25 16:29:56 +00:00
pClient - > m_NoCollision = pCharacterData - > m_Flags & CHARACTERFLAG_NO_COLLISION ;
pClient - > m_NoHammerHit = pCharacterData - > m_Flags & CHARACTERFLAG_NO_HAMMER_HIT ;
pClient - > m_NoGrenadeHit = pCharacterData - > m_Flags & CHARACTERFLAG_NO_GRENADE_HIT ;
pClient - > m_NoLaserHit = pCharacterData - > m_Flags & CHARACTERFLAG_NO_LASER_HIT ;
pClient - > m_NoShotgunHit = pCharacterData - > m_Flags & CHARACTERFLAG_NO_SHOTGUN_HIT ;
pClient - > m_NoHookHit = pCharacterData - > m_Flags & CHARACTERFLAG_NO_HOOK ;
pClient - > m_Super = pCharacterData - > m_Flags & CHARACTERFLAG_SUPER ;
// Endless
pClient - > m_EndlessHook = pCharacterData - > m_Flags & CHARACTERFLAG_ENDLESS_HOOK ;
pClient - > m_EndlessJump = pCharacterData - > m_Flags & CHARACTERFLAG_ENDLESS_JUMP ;
// Freeze
pClient - > m_FreezeEnd = pCharacterData - > m_FreezeEnd ;
pClient - > m_DeepFrozen = pCharacterData - > m_FreezeEnd = = - 1 ;
2022-01-07 15:53:40 +00:00
pClient - > m_LiveFrozen = ( pCharacterData - > m_Flags & CHARACTERFLAG_NO_MOVEMENTS ) ! = 0 ;
2020-06-25 16:29:56 +00:00
// Telegun
pClient - > m_HasTelegunGrenade = pCharacterData - > m_Flags & CHARACTERFLAG_TELEGUN_GRENADE ;
pClient - > m_HasTelegunGun = pCharacterData - > m_Flags & CHARACTERFLAG_TELEGUN_GUN ;
pClient - > m_HasTelegunLaser = pCharacterData - > m_Flags & CHARACTERFLAG_TELEGUN_LASER ;
pClient - > m_Predicted . ReadDDNet ( pCharacterData ) ;
}
2019-04-17 21:47:32 +00:00
}
2020-06-24 17:01:01 +00:00
else if ( Item . m_Type = = NETOBJTYPE_SPECCHAR )
{
const CNetObj_SpecChar * pSpecCharData = ( const CNetObj_SpecChar * ) pData ;
2020-06-25 12:56:23 +00:00
2020-06-25 16:29:56 +00:00
if ( Item . m_ID < MAX_CLIENTS )
{
CClientData * pClient = & m_aClients [ Item . m_ID ] ;
pClient - > m_SpecCharPresent = true ;
pClient - > m_SpecChar . x = pSpecCharData - > m_X ;
pClient - > m_SpecChar . y = pSpecCharData - > m_Y ;
}
2020-06-24 17:01:01 +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
{
2022-02-14 23:12:52 +00:00
static bool s_GameOver = false ;
static bool s_GamePaused = false ;
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
2020-09-26 19:41:58 +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 ) )
2021-07-12 09:43:56 +00:00
m_Statboard . OnReset ( ) ;
2015-11-12 09:06:05 +00:00
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
}
2019-06-03 19:52:14 +00:00
else if ( Item . m_Type = = NETOBJTYPE_GAMEINFOEX )
2019-05-21 08:11:02 +00:00
{
2019-06-03 19:52:14 +00:00
if ( FoundGameInfoEx )
{
continue ;
}
FoundGameInfoEx = true ;
CServerInfo ServerInfo ;
Client ( ) - > GetServerInfo ( & ServerInfo ) ;
m_GameInfo = GetGameInfo ( ( const CNetObj_GameInfoEx * ) pData , Client ( ) - > SnapItemSize ( IClient : : SNAP_CURRENT , i ) , & ServerInfo ) ;
2019-05-21 08:11:02 +00:00
}
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 )
2020-02-19 10:24:58 +00:00
m_FlagDropTick [ TEAM_RED ] = Client ( ) - > GameTick ( g_Config . m_ClDummy ) ;
2011-07-05 21:15:24 +00:00
}
else if ( m_FlagDropTick [ TEAM_RED ] ! = 0 )
2020-09-26 19:41:58 +00:00
m_FlagDropTick [ TEAM_RED ] = 0 ;
2011-07-05 21:15:24 +00:00
if ( m_Snap . m_pGameDataObj - > m_FlagCarrierBlue = = FLAG_TAKEN )
{
if ( m_FlagDropTick [ TEAM_BLUE ] = = 0 )
2020-02-19 10:24:58 +00:00
m_FlagDropTick [ TEAM_BLUE ] = Client ( ) - > GameTick ( g_Config . m_ClDummy ) ;
2011-07-05 21:15:24 +00:00
}
else if ( m_FlagDropTick [ TEAM_BLUE ] ! = 0 )
2020-09-26 19:41:58 +00:00
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 )
2020-09-26 19:41:58 +00:00
m_Snap . m_paFlags [ Item . m_ID % 2 ] = ( const CNetObj_Flag * ) pData ;
2021-08-15 10:53:14 +00:00
else if ( Item . m_Type = = NETOBJTYPE_SWITCHSTATE )
{
const CNetObj_SwitchState * pSwitchStateData = ( const CNetObj_SwitchState * ) pData ;
2021-12-23 11:06:54 +00:00
int Team = clamp ( Item . m_ID , ( int ) TEAM_FLOCK , ( int ) TEAM_SUPER - 1 ) ;
2021-08-15 10:53:14 +00:00
2021-08-23 21:17:44 +00:00
int NumSwitchers = clamp ( pSwitchStateData - > m_NumSwitchers , 0 , 255 ) ;
if ( ! Collision ( ) - > m_pSwitchers | | NumSwitchers ! = Collision ( ) - > m_NumSwitchers )
{
2021-11-06 17:12:07 +00:00
delete [ ] Collision ( ) - > m_pSwitchers ;
2021-08-23 21:17:44 +00:00
Collision ( ) - > m_pSwitchers = new CCollision : : SSwitchers [ NumSwitchers + 1 ] ;
Collision ( ) - > m_NumSwitchers = NumSwitchers ;
}
2021-08-15 10:53:14 +00:00
2022-03-20 11:57:50 +00:00
for ( int j = 0 ; j < NumSwitchers + 1 ; j + + )
2021-08-15 10:53:14 +00:00
{
2022-03-20 11:57:50 +00:00
if ( j < 32 )
Collision ( ) - > m_pSwitchers [ j ] . m_Status [ Team ] = pSwitchStateData - > m_Status1 & ( 1 < < j ) ;
else if ( j < 64 )
Collision ( ) - > m_pSwitchers [ j ] . m_Status [ Team ] = pSwitchStateData - > m_Status2 & ( 1 < < ( j - 32 ) ) ;
else if ( j < 96 )
Collision ( ) - > m_pSwitchers [ j ] . m_Status [ Team ] = pSwitchStateData - > m_Status3 & ( 1 < < ( j - 64 ) ) ;
else if ( j < 128 )
Collision ( ) - > m_pSwitchers [ j ] . m_Status [ Team ] = pSwitchStateData - > m_Status4 & ( 1 < < ( j - 96 ) ) ;
else if ( j < 160 )
Collision ( ) - > m_pSwitchers [ j ] . m_Status [ Team ] = pSwitchStateData - > m_Status5 & ( 1 < < ( j - 128 ) ) ;
else if ( j < 192 )
Collision ( ) - > m_pSwitchers [ j ] . m_Status [ Team ] = pSwitchStateData - > m_Status6 & ( 1 < < ( j - 160 ) ) ;
else if ( j < 224 )
Collision ( ) - > m_pSwitchers [ j ] . m_Status [ Team ] = pSwitchStateData - > m_Status7 & ( 1 < < ( j - 192 ) ) ;
else if ( j < 256 )
Collision ( ) - > m_pSwitchers [ j ] . m_Status [ Team ] = pSwitchStateData - > m_Status8 & ( 1 < < ( j - 224 ) ) ;
2021-08-23 21:17:44 +00:00
// update
2022-03-20 11:57:50 +00:00
if ( Collision ( ) - > m_pSwitchers [ j ] . m_Status [ Team ] )
Collision ( ) - > m_pSwitchers [ j ] . m_Type [ Team ] = TILE_SWITCHOPEN ;
2021-08-23 21:17:44 +00:00
else
2022-03-20 11:57:50 +00:00
Collision ( ) - > m_pSwitchers [ j ] . m_Type [ Team ] = TILE_SWITCHCLOSE ;
Collision ( ) - > m_pSwitchers [ j ] . m_EndTick [ Team ] = 0 ;
2021-08-15 10:53:14 +00:00
}
2021-11-08 22:51:09 +00:00
if ( ! GotSwitchStateTeam )
m_SwitchStateTeam [ g_Config . m_ClDummy ] = Team ;
else
m_SwitchStateTeam [ g_Config . m_ClDummy ] = - 1 ;
GotSwitchStateTeam = true ;
2021-08-15 10:53:14 +00:00
}
2008-09-23 07:43:41 +00:00
}
}
2011-04-13 18:37:12 +00:00
2019-06-03 19:52:14 +00:00
if ( ! FoundGameInfoEx )
{
CServerInfo ServerInfo ;
Client ( ) - > GetServerInfo ( & ServerInfo ) ;
m_GameInfo = GetGameInfo ( 0 , 0 , & ServerInfo ) ;
}
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
{
2020-06-04 12:49:29 +00:00
m_LocalIDs [ g_Config . m_ClDummy ] = m_Snap . m_LocalClientID ;
2020-06-16 15:19:53 +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
2021-07-12 09:43:56 +00:00
m_Controls . OnPlayerDeath ( ) ;
2010-08-10 11:54:13 +00:00
}
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
2020-09-26 19:41:58 +00:00
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 ) ) ;
2018-11-21 20:26:05 +00:00
// update foe state
2020-09-26 19:41:58 +00:00
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 ,
2020-09-26 19:41:58 +00:00
[ this ] ( const CNetObj_PlayerInfo * p1 , const CNetObj_PlayerInfo * p2 ) - > bool {
if ( ! p2 )
2018-12-06 06:56:58 +00:00
return static_cast < bool > ( p1 ) ;
2020-09-26 19:41:58 +00:00
if ( ! p1 )
2018-11-24 21:57:15 +00:00
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 ;
} ) ;
2019-06-03 19:52:14 +00:00
bool TimeScore = m_GameInfo . m_TimeScore ;
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 ,
2020-09-26 19:41:58 +00:00
[ TimeScore ] ( const CNetObj_PlayerInfo * p1 , const CNetObj_PlayerInfo * p2 ) - > bool {
if ( ! p2 )
2018-12-06 06:56:58 +00:00
return static_cast < bool > ( p1 ) ;
2020-09-26 19:41:58 +00:00
if ( ! p1 )
2018-11-24 21:57:15 +00:00
return false ;
2019-06-03 19:52:14 +00:00
return ( ( ( TimeScore & & p1 - > m_Score = = - 9999 ) ? std : : numeric_limits < int > : : min ( ) : p1 - > m_Score ) >
( ( TimeScore & & p2 - > m_Score = = - 9999 ) ? std : : numeric_limits < int > : : min ( ) : p2 - > m_Score ) ) ;
2018-11-21 20:26:05 +00:00
} ) ;
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 ;
2021-12-23 11:06:54 +00:00
for ( int Team = TEAM_FLOCK ; Team < = TEAM_SUPER ; + + 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 )
2020-09-13 19:20:13 +00:00
m_Snap . m_paInfoByDDTeamScore [ Index + + ] = m_Snap . m_paInfoByScore [ i ] ;
}
}
// sort player infos by DDRace Team (and name between)
Index = 0 ;
2021-12-23 11:06:54 +00:00
for ( int Team = TEAM_FLOCK ; Team < = TEAM_SUPER ; + + Team )
2020-09-13 19:20:13 +00:00
{
for ( int i = 0 ; i < MAX_CLIENTS & & Index < MAX_CLIENTS ; + + i )
{
if ( m_Snap . m_paInfoByName [ i ] & & m_Teams . Team ( m_Snap . m_paInfoByName [ i ] - > m_ClientID ) = = Team )
m_Snap . m_paInfoByDDTeamName [ Index + + ] = m_Snap . m_paInfoByName [ i ] ;
2014-01-22 00:39:18 +00:00
}
}
2019-06-03 19:52:14 +00:00
CServerInfo CurrentServerInfo ;
Client ( ) - > GetServerInfo ( & CurrentServerInfo ) ;
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 ] ;
2020-09-26 19:41:58 +00:00
for ( unsigned i = 0 ; i < sizeof ( m_Tuning [ 0 ] ) / sizeof ( int ) ; i + + )
2012-01-08 23:49:20 +00:00
Msg . AddInt ( pParams [ i ] ) ;
2022-01-21 00:54:14 +00:00
Client ( ) - > SendMsgActive ( & Msg , MSGFLAG_RECORD | MSGFLAG_NOSEND ) ;
2012-01-08 23:49:20 +00:00
}
2013-02-02 13:08:02 +00:00
2022-01-21 00:54:14 +00:00
for ( int i = 0 ; i < 2 ; i + + )
2010-10-23 19:26:10 +00:00
{
2022-01-24 14:27:10 +00:00
if ( m_DDRaceMsgSent [ i ] | | ! m_Snap . m_pLocalInfo )
2022-01-21 00:54:14 +00:00
{
continue ;
}
2022-01-21 21:13:35 +00:00
if ( i = = IClient : : CONN_DUMMY & & ! Client ( ) - > DummyConnected ( ) )
2022-01-21 00:54:14 +00:00
{
continue ;
}
2021-01-10 16:41:06 +00:00
CMsgPacker Msg ( NETMSGTYPE_CL_ISDDNETLEGACY , false ) ;
2014-02-19 21:29:46 +00:00
Msg . AddInt ( CLIENT_VERSIONNR ) ;
2022-01-21 00:54:14 +00:00
Client ( ) - > SendMsg ( i , & Msg , MSGFLAG_VITAL ) ;
m_DDRaceMsgSent [ i ] = true ;
2013-02-02 13:08:02 +00:00
}
2011-02-23 20:22:05 +00:00
2022-03-03 21:56:32 +00:00
if ( m_ShowOthers [ g_Config . m_ClDummy ] = = SHOW_OTHERS_NOT_SET | | ( m_ShowOthers [ g_Config . m_ClDummy ] ! = SHOW_OTHERS_NOT_SET & & m_ShowOthers [ g_Config . m_ClDummy ] ! = g_Config . m_ClShowOthers ) )
2013-02-02 13:08:02 +00:00
{
{
2020-06-29 15:47:26 +00:00
CNetMsg_Cl_ShowOthers Msg ;
2014-05-24 22:59:52 +00:00
Msg . m_Show = g_Config . m_ClShowOthers ;
2022-01-21 00:54:14 +00:00
Client ( ) - > SendPackMsgActive ( & Msg , MSGFLAG_VITAL ) ;
2013-02-02 13:08:02 +00:00
}
// 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
2021-07-12 09:43:56 +00:00
float ZoomToSend = m_Camera . m_Zoom ;
2021-09-10 22:14:02 +00:00
if ( m_Camera . m_Zooming )
2021-02-20 21:51:36 +00:00
{
2021-07-12 09:43:56 +00:00
if ( m_Camera . m_ZoomSmoothingTarget > m_Camera . m_Zoom ) // Zooming out
ZoomToSend = m_Camera . m_ZoomSmoothingTarget ;
else if ( m_Camera . m_ZoomSmoothingTarget < m_Camera . m_Zoom & & m_LastZoom > 0 ) // Zooming in
2021-02-20 21:51:36 +00:00
ZoomToSend = m_LastZoom ;
}
2021-01-21 16:07:07 +00:00
if ( ZoomToSend ! = m_LastZoom | | Graphics ( ) - > ScreenAspect ( ) ! = m_LastScreenAspect | | ( Client ( ) - > DummyConnected ( ) & & ! m_LastDummyConnected ) )
2020-06-28 09:48:25 +00:00
{
CNetMsg_Cl_ShowDistance Msg ;
float x , y ;
2021-01-21 16:07:07 +00:00
RenderTools ( ) - > CalcScreenParams ( Graphics ( ) - > ScreenAspect ( ) , ZoomToSend , & x , & y ) ;
2020-06-28 09:48:25 +00:00
Msg . m_X = x ;
Msg . m_Y = y ;
2022-01-31 02:11:47 +00:00
Client ( ) - > ChecksumData ( ) - > m_Zoom = ZoomToSend ;
2020-07-08 21:25:07 +00:00
CMsgPacker Packer ( Msg . MsgID ( ) , false ) ;
Msg . Pack ( & Packer ) ;
2021-01-21 16:07:07 +00:00
if ( ZoomToSend ! = m_LastZoom )
2022-01-21 21:13:35 +00:00
Client ( ) - > SendMsg ( IClient : : CONN_MAIN , & Packer , MSGFLAG_VITAL ) ;
2020-07-08 21:25:07 +00:00
if ( Client ( ) - > DummyConnected ( ) )
2022-01-21 21:13:35 +00:00
Client ( ) - > SendMsg ( IClient : : CONN_DUMMY , & Packer , MSGFLAG_VITAL ) ;
2021-01-21 16:07:07 +00:00
m_LastZoom = ZoomToSend ;
m_LastScreenAspect = Graphics ( ) - > ScreenAspect ( ) ;
2020-06-28 09:48:25 +00:00
}
2021-01-21 16:07:07 +00:00
m_LastDummyConnected = Client ( ) - > DummyConnected ( ) ;
2020-06-28 09:48:25 +00:00
2021-07-12 09:43:56 +00:00
m_Ghost . OnNewSnapshot ( ) ;
m_RaceDemo . OnNewSnapshot ( ) ;
2019-04-11 22:46:54 +00:00
2021-04-22 12:52:49 +00:00
// detect air jump for other players
2019-04-11 22:46:54 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2020-09-26 19:41:58 +00:00
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 ) )
2021-04-22 12:52:49 +00:00
if ( ! Predict ( ) | | ( i ! = m_Snap . m_LocalClientID & & ( ! AntiPingPlayers ( ) | | i ! = m_PredictedDummyID ) ) )
2019-04-11 22:46:54 +00:00
{
vec2 Pos = mix ( vec2 ( m_Snap . m_aCharacters [ i ] . m_Prev . m_X , m_Snap . m_aCharacters [ i ] . m_Prev . m_Y ) ,
2020-09-26 19:41:58 +00:00
vec2 ( m_Snap . m_aCharacters [ i ] . m_Cur . m_X , m_Snap . m_aCharacters [ i ] . m_Cur . m_Y ) ,
Client ( ) - > IntraGameTick ( g_Config . m_ClDummy ) ) ;
2021-07-12 09:43:56 +00:00
m_Effects . AirJump ( Pos ) ;
2019-04-11 22:46:54 +00:00
}
2020-04-18 20:16:25 +00:00
static int PrevLocalID = - 1 ;
if ( m_Snap . m_LocalClientID ! = PrevLocalID )
m_PredictedDummyID = PrevLocalID ;
PrevLocalID = m_Snap . m_LocalClientID ;
m_IsDummySwapping = 0 ;
2021-10-21 01:18:54 +00:00
SnapCollectEntities ( ) ; // creates a collection that associates EntityEx snap items with the entities they belong to
2019-04-11 22:46:54 +00:00
// 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
2020-09-26 19:41:58 +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
2020-04-18 20:16:25 +00:00
bool Dummy = g_Config . m_ClDummy ^ m_IsDummySwapping ;
2019-04-11 22:46:54 +00:00
m_PredictedWorld . CopyWorld ( & m_GameWorld ) ;
2008-08-27 15:48:50 +00:00
2021-02-07 19:51:28 +00:00
// don't predict inactive players, or entities from other teams
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 ) )
2021-02-07 19:51:28 +00:00
if ( ( ! m_Snap . m_aCharacters [ i ] . m_Active & & pChar - > m_SnapTicks > 10 ) | | IsOtherTeam ( i ) )
2019-04-11 22:46:54 +00:00
pChar - > Destroy ( ) ;
2011-04-13 18:37:12 +00:00
2021-02-07 19:51:28 +00:00
CProjectile * pProjNext = 0 ;
for ( CProjectile * pProj = ( CProjectile * ) m_PredictedWorld . FindFirst ( CGameWorld : : ENTTYPE_PROJECTILE ) ; pProj ; pProj = pProjNext )
{
pProjNext = ( CProjectile * ) pProj - > TypeNext ( ) ;
if ( IsOtherTeam ( pProj - > GetOwner ( ) ) )
m_PredictedWorld . RemoveEntity ( pProj ) ;
}
2019-04-11 22:46:54 +00:00
CCharacter * pLocalChar = m_PredictedWorld . GetCharacterByID ( m_Snap . m_LocalClientID ) ;
if ( ! pLocalChar )
return ;
2020-04-18 20:16:25 +00:00
CCharacter * pDummyChar = 0 ;
if ( PredictDummy ( ) )
pDummyChar = m_PredictedWorld . GetCharacterByID ( m_PredictedDummyID ) ;
2014-12-01 00:31:58 +00:00
2019-04-11 22:46:54 +00:00
// predict
2020-02-19 10:24:58 +00:00
for ( int Tick = Client ( ) - > GameTick ( g_Config . m_ClDummy ) + 1 ; Tick < = Client ( ) - > PredGameTick ( g_Config . m_ClDummy ) ; Tick + + )
2014-12-01 00:31:58 +00:00
{
2019-04-11 22:46:54 +00:00
// fetch the previous characters
2020-02-19 10:24:58 +00:00
if ( Tick = = Client ( ) - > PredGameTick ( g_Config . m_ClDummy ) )
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-05-02 20:35:08 +00:00
// optionally allow some movement in freeze by not predicting freeze the last one to two ticks
2020-09-26 19:41:58 +00:00
if ( g_Config . m_ClPredictFreeze = = 2 & & Client ( ) - > PredGameTick ( g_Config . m_ClDummy ) - 1 - Client ( ) - > PredGameTick ( g_Config . m_ClDummy ) % 2 < = Tick )
2019-05-02 20:35:08 +00:00
pLocalChar - > m_CanMoveInFreeze = true ;
2019-04-11 22:46:54 +00:00
// apply inputs and tick
2020-09-26 19:41:58 +00:00
CNetObj_PlayerInput * pInputData = ( CNetObj_PlayerInput * ) Client ( ) - > GetDirectInput ( Tick , m_IsDummySwapping ) ;
CNetObj_PlayerInput * pDummyInputData = ! pDummyChar ? 0 : ( CNetObj_PlayerInput * ) Client ( ) - > GetDirectInput ( Tick , m_IsDummySwapping ^ 1 ) ;
2020-04-19 10:50:37 +00:00
bool DummyFirst = pInputData & & pDummyInputData & & pDummyChar - > GetCID ( ) < pLocalChar - > GetCID ( ) ;
if ( DummyFirst )
pDummyChar - > OnDirectInput ( pDummyInputData ) ;
2019-04-11 22:46:54 +00:00
if ( pInputData )
pLocalChar - > OnDirectInput ( pInputData ) ;
2020-04-19 10:50:37 +00:00
if ( pDummyInputData & & ! DummyFirst )
2020-04-18 20:16:25 +00:00
pDummyChar - > OnDirectInput ( pDummyInputData ) ;
2019-04-11 22:46:54 +00:00
m_PredictedWorld . m_GameTick = Tick ;
if ( pInputData )
pLocalChar - > OnPredictedInput ( pInputData ) ;
2020-04-18 20:16:25 +00:00
if ( pDummyInputData )
pDummyChar - > OnPredictedInput ( pDummyInputData ) ;
2019-04-11 22:46:54 +00:00
m_PredictedWorld . Tick ( ) ;
// fetch the current characters
2020-02-19 10:24:58 +00:00
if ( Tick = = Client ( ) - > PredGameTick ( g_Config . m_ClDummy ) )
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
2020-04-18 20:16:25 +00:00
if ( Tick > m_LastNewPredictedTick [ Dummy ] )
2014-12-01 00:31:58 +00:00
{
2020-04-18 20:16:25 +00:00
m_LastNewPredictedTick [ Dummy ] = 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 )
2020-09-26 19:41:58 +00:00
if ( Events & COREEVENT_AIR_JUMP )
2021-07-12 09:43:56 +00:00
m_Effects . AirJump ( Pos ) ;
2019-04-11 22:46:54 +00:00
if ( g_Config . m_SndGame )
2008-08-27 15:48:50 +00:00
{
2020-09-26 19:41:58 +00:00
if ( Events & COREEVENT_GROUND_JUMP )
2021-07-12 09:43:56 +00:00
m_Sounds . PlayAndRecord ( CSounds : : CHN_WORLD , SOUND_PLAYER_JUMP , 1.0f , Pos ) ;
2020-09-26 19:41:58 +00:00
if ( Events & COREEVENT_HOOK_ATTACH_GROUND )
2021-07-12 09:43:56 +00:00
m_Sounds . PlayAndRecord ( CSounds : : CHN_WORLD , SOUND_HOOK_ATTACH_GROUND , 1.0f , Pos ) ;
2020-09-26 19:41:58 +00:00
if ( Events & COREEVENT_HOOK_HIT_NOHOOK )
2021-07-12 09:43:56 +00:00
m_Sounds . PlayAndRecord ( CSounds : : CHN_WORLD , SOUND_HOOK_NOATTACH , 1.0f , Pos ) ;
2014-12-01 00:31:58 +00:00
}
}
2021-04-22 12:52:49 +00:00
// check if we want to trigger predicted airjump for dummy
if ( AntiPingPlayers ( ) & & pDummyChar & & Tick > m_LastNewPredictedTick [ ! Dummy ] )
{
m_LastNewPredictedTick [ ! Dummy ] = Tick ;
vec2 Pos = pDummyChar - > Core ( ) - > m_Pos ;
2021-04-22 12:58:30 +00:00
int Events = pDummyChar - > Core ( ) - > m_TriggeredEvents ;
2021-04-22 12:52:49 +00:00
if ( g_Config . m_ClPredict )
if ( Events & COREEVENT_AIR_JUMP )
2021-07-12 09:43:56 +00:00
m_Effects . AirJump ( Pos ) ;
2021-04-22 12:52:49 +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
2020-09-26 19:41:58 +00:00
static vec2 s_aLastPos [ MAX_CLIENTS ] = { { 0 , 0 } } ;
2022-02-14 23:12:52 +00:00
static bool s_aLastActive [ MAX_CLIENTS ] = { false } ;
2014-12-01 00:31:58 +00:00
2020-09-26 19:41:58 +00:00
if ( g_Config . m_ClAntiPingSmooth & & Predict ( ) & & AntiPingPlayers ( ) & & m_NewTick & & abs ( m_PredictedTick - Client ( ) - > PredGameTick ( g_Config . m_ClDummy ) ) < = 1 & & abs ( Client ( ) - > GameTick ( g_Config . m_ClDummy ) - Client ( ) - > PrevGameTick ( g_Config . m_ClDummy ) ) < = 2 )
2019-04-11 22:46:54 +00:00
{
int PredTime = clamp ( Client ( ) - > GetPredictionTime ( ) , 0 , 800 ) ;
2020-09-26 19:41:58 +00:00
float SmoothPace = 4 - 1.5f * PredTime / 800.f ; // smoothing pace (a lower value will make the smoothing quicker)
2021-06-23 05:05:49 +00:00
int64_t 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 ;
2020-02-19 10:24:58 +00:00
vec2 NewPos = ( m_PredictedTick = = Client ( ) - > PredGameTick ( g_Config . m_ClDummy ) ) ? m_aClients [ i ] . m_Predicted . m_Pos : m_aClients [ i ] . m_PrevPredicted . m_Pos ;
2020-09-26 19:41:58 +00:00
vec2 PredErr = ( s_aLastPos [ i ] - NewPos ) / ( float ) minimum ( Client ( ) - > GetPredictionTime ( ) , 200 ) ;
2019-04-11 22:46:54 +00:00
if ( in_range ( length ( PredErr ) , 0.05f , 5.f ) )
2018-10-02 18:45:44 +00:00
{
2020-02-19 10:24:58 +00:00
vec2 PredPos = mix ( m_aClients [ i ] . m_PrevPredicted . m_Pos , m_aClients [ i ] . m_Predicted . m_Pos , Client ( ) - > PredIntraGameTick ( g_Config . m_ClDummy ) ) ;
2019-04-11 22:46:54 +00:00
vec2 CurPos = mix (
2020-09-26 19:41:58 +00:00
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 ( g_Config . m_ClDummy ) ) ;
2019-04-11 22:46:54 +00:00
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-07-08 21:08:42 +00:00
MixAmount [ j ] = 1.0f ;
2019-04-11 22:46:54 +00:00
if ( fabs ( PredErr [ j ] ) > 0.05f )
2018-10-02 18:45:44 +00:00
{
2019-07-08 21:08:42 +00:00
MixAmount [ j ] = 0.0f ;
2019-04-11 22:46:54 +00:00
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 ) ;
2020-09-26 19:41:58 +00:00
MixAmount [ j ] = 1.f - powf ( 1.f - MixAmount [ j ] , 1 / 1.2f ) ;
2019-04-11 22:46:54 +00:00
}
2018-10-02 18:45:44 +00:00
}
2021-06-23 05:05:49 +00:00
int64_t TimePassed = time_get ( ) - m_aClients [ i ] . m_SmoothStart [ j ] ;
if ( in_range ( TimePassed , ( int64_t ) 0 , Len - 1 ) )
2020-09-26 19:41:58 +00:00
MixAmount [ j ] = minimum ( MixAmount [ j ] , ( float ) ( TimePassed / ( double ) Len ) ) ;
2014-12-01 00:31:58 +00:00
}
2019-04-11 22:46:54 +00:00
for ( int j = 0 ; j < 2 ; j + + )
2020-09-26 19:41:58 +00:00
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 ] ;
2019-04-11 22:46:54 +00:00
for ( int j = 0 ; j < 2 ; j + + )
2014-12-01 00:31:58 +00:00
{
2021-06-23 05:05:49 +00:00
int64_t Remaining = minimum ( ( 1.f - MixAmount [ j ] ) * Len , minimum ( 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_t Start = time_get ( ) - ( Len - Remaining ) ;
2019-04-11 22:46:54 +00:00
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
}
}
}
2008-08-27 15:48:50 +00:00
}
2019-04-11 22:46:54 +00:00
}
2008-08-27 15:48:50 +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 )
2015-05-04 15:53:07 +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-05-04 15:53:07 +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
2020-02-19 10:24:58 +00:00
if ( g_Config . m_Debug & & g_Config . m_ClPredict & & m_PredictedTick = = Client ( ) - > PredGameTick ( g_Config . m_ClDummy ) )
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 " ) ;
2020-09-26 19:41:58 +00:00
for ( unsigned i = 0 ; i < sizeof ( CNetObj_CharacterCore ) / sizeof ( int ) ; i + + )
2010-05-29 07:25:38 +00:00
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
2020-02-19 10:24:58 +00:00
m_PredictedTick = Client ( ) - > PredGameTick ( g_Config . m_ClDummy ) ;
2017-10-06 20:01:33 +00:00
if ( m_NewPredictedTick )
2021-07-12 09:43:56 +00:00
m_Ghost . 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 ;
}
2021-07-12 10:04:45 +00:00
void CGameClient : : CClientData : : UpdateRenderInfo ( bool IsTeamPlay )
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
2021-07-12 10:04:45 +00:00
if ( IsTeamPlay )
2008-08-27 15:48:50 +00:00
{
2020-10-09 07:07:05 +00:00
m_RenderInfo . m_CustomColoredSkin = true ;
2019-05-11 16:04:32 +00:00
const int TeamColors [ 2 ] = { 65461 , 10223541 } ;
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
{
2019-04-26 12:06:32 +00:00
m_RenderInfo . m_ColorBody = color_cast < ColorRGBA > ( ColorHSLA ( TeamColors [ m_Team ] ) ) ;
m_RenderInfo . m_ColorFeet = color_cast < ColorRGBA > ( ColorHSLA ( TeamColors [ m_Team ] ) ) ;
2008-08-27 15:48:50 +00:00
}
2011-03-27 09:52:16 +00:00
else
{
2019-05-11 16:04:32 +00:00
m_RenderInfo . m_ColorBody = color_cast < ColorRGBA > ( ColorHSLA ( 12829350 ) ) ;
m_RenderInfo . m_ColorFeet = color_cast < ColorRGBA > ( ColorHSLA ( 12829350 ) ) ;
2011-03-27 09:52:16 +00:00
}
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_Team = 0 ;
m_Angle = 0 ;
m_Emoticon = 0 ;
2021-09-14 22:37:06 +00:00
m_EmoticonStartTick = - 1 ;
m_EmoticonStartFraction = 0 ;
2011-03-22 21:41:27 +00:00
m_Active = false ;
m_ChatIgnore = false ;
2020-06-26 22:06:07 +00:00
m_EmoticonIgnore = false ;
2019-03-19 21:29:39 +00:00
m_Friend = false ;
m_Foe = false ;
m_AuthLevel = AUTHED_NO ;
2019-08-01 21:07:40 +00:00
m_Afk = false ;
2019-08-02 16:16:58 +00:00
m_Paused = false ;
m_Spec = false ;
2020-10-09 07:07:05 +00:00
m_SkinInfo . m_BloodColor = ColorRGBA ( 1 , 1 , 1 ) ;
m_SkinInfo . m_ColorableRenderSkin . Reset ( ) ;
m_SkinInfo . m_OriginalRenderSkin . Reset ( ) ;
m_SkinInfo . m_CustomColoredSkin = false ;
2020-09-26 19:41:58 +00:00
m_SkinInfo . m_ColorBody = ColorRGBA ( 1 , 1 , 1 ) ;
m_SkinInfo . m_ColorFeet = ColorRGBA ( 1 , 1 , 1 ) ;
2020-11-08 05:39:16 +00:00
m_SkinInfo . m_SkinMetrics . Reset ( ) ;
2019-04-19 09:17:28 +00:00
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 ;
2019-11-22 14:37:18 +00:00
m_NoLaserHit = false ;
2019-04-19 09:17:28 +00:00
m_NoShotgunHit = false ;
m_NoHookHit = false ;
m_Super = false ;
m_HasTelegunGun = false ;
m_HasTelegunGrenade = false ;
m_HasTelegunLaser = false ;
2019-04-23 15:57:26 +00:00
m_FreezeEnd = 0 ;
2019-04-19 09:17:28 +00:00
m_DeepFrozen = false ;
2022-01-07 15:53:40 +00:00
m_LiveFrozen = false ;
2019-04-19 09:17:28 +00:00
2019-11-09 21:49:53 +00:00
m_Evolved . m_Tick = - 1 ;
2020-06-25 12:56:23 +00:00
m_SpecChar = vec2 ( 0 , 0 ) ;
m_SpecCharPresent = false ;
2020-06-24 17:01:01 +00:00
2021-08-15 10:53:14 +00:00
mem_zero ( m_SwitchStates , sizeof ( m_SwitchStates ) ) ;
2021-07-12 10:04:45 +00:00
UpdateRenderInfo ( false ) ;
2011-03-22 21:41:27 +00:00
}
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 ;
2022-01-21 00:54:14 +00:00
Client ( ) - > SendPackMsgActive ( & Msg , MSGFLAG_VITAL ) ;
2013-07-11 15:25:51 +00:00
2018-03-13 20:55:47 +00:00
if ( Team ! = TEAM_SPECTATORS )
2021-07-12 09:43:56 +00:00
m_Camera . 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 ;
2020-08-20 10:19:03 +00:00
Msg . m_pName = Client ( ) - > 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 ;
2019-05-01 20:35:29 +00:00
Msg . m_ColorBody = g_Config . m_ClPlayerColorBody ;
Msg . m_ColorFeet = g_Config . m_ClPlayerColorFeet ;
2012-08-09 08:30:04 +00:00
CMsgPacker Packer ( Msg . MsgID ( ) , false ) ;
2014-04-28 13:19:57 +00:00
Msg . Pack ( & Packer ) ;
2022-01-21 21:13:35 +00:00
Client ( ) - > SendMsg ( IClient : : CONN_MAIN , & Packer , MSGFLAG_VITAL ) ;
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 ;
2020-08-20 10:19:03 +00:00
Msg . m_pName = Client ( ) - > 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 ;
2019-05-01 20:35:29 +00:00
Msg . m_ColorBody = g_Config . m_ClPlayerColorBody ;
Msg . m_ColorFeet = g_Config . m_ClPlayerColorFeet ;
2012-08-09 08:30:04 +00:00
CMsgPacker Packer ( Msg . MsgID ( ) , false ) ;
2014-04-28 13:19:57 +00:00
Msg . Pack ( & Packer ) ;
2022-01-21 21:13:35 +00:00
Client ( ) - > SendMsg ( IClient : : CONN_MAIN , & Packer , MSGFLAG_VITAL ) ;
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 ;
2020-08-25 14:22:03 +00:00
Msg . m_pName = Client ( ) - > DummyName ( ) ;
2015-08-06 20:16:33 +00:00
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 ;
2019-05-01 20:35:29 +00:00
Msg . m_ColorBody = g_Config . m_ClDummyColorBody ;
Msg . m_ColorFeet = g_Config . m_ClDummyColorFeet ;
2012-08-09 08:30:04 +00:00
CMsgPacker Packer ( Msg . MsgID ( ) , false ) ;
2014-04-28 13:19:57 +00:00
Msg . Pack ( & Packer ) ;
2022-01-21 21:13:35 +00:00
Client ( ) - > SendMsg ( IClient : : CONN_DUMMY , & Packer , MSGFLAG_VITAL ) ;
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 ;
2020-08-25 14:22:03 +00:00
Msg . m_pName = Client ( ) - > DummyName ( ) ;
2015-08-06 20:16:33 +00:00
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 ;
2019-05-01 20:35:29 +00:00
Msg . m_ColorBody = g_Config . m_ClDummyColorBody ;
Msg . m_ColorFeet = g_Config . m_ClDummyColorFeet ;
2012-08-09 08:30:04 +00:00
CMsgPacker Packer ( Msg . MsgID ( ) , false ) ;
2014-04-28 13:19:57 +00:00
Msg . Pack ( & Packer ) ;
2022-01-21 21:13:35 +00:00
Client ( ) - > SendMsg ( IClient : : CONN_DUMMY , & Packer , MSGFLAG_VITAL ) ;
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 ;
2022-01-21 00:54:14 +00:00
Client ( ) - > SendPackMsgActive ( & Msg , MSGFLAG_VITAL ) ;
2015-02-18 13:23:25 +00:00
if ( g_Config . m_ClDummyCopyMoves )
{
2022-03-20 11:57:50 +00:00
CMsgPacker MsgP ( NETMSGTYPE_CL_KILL , false ) ;
Client ( ) - > SendMsg ( ! g_Config . m_ClDummy , & MsgP , MSGFLAG_VITAL ) ;
2015-02-18 13:23:25 +00:00
}
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
{
2020-09-26 19:41:58 +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
{
2020-09-26 19:41:58 +00:00
( ( CGameClient * ) pUserData ) - > SendKill ( - 1 ) ;
2008-08-31 13:36:30 +00:00
}
2009-06-15 14:01:36 +00:00
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 ( ) )
2020-09-26 19:41:58 +00:00
( ( 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 ( ) )
2020-09-26 19:41:58 +00:00
( ( CGameClient * ) pUserData ) - > SendDummyInfo ( false ) ;
2014-04-28 13:19:57 +00:00
}
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 ( ) )
2020-09-26 19:41:58 +00:00
if ( g_Config . m_ClDummy & & ! ( ( CGameClient * ) pUserData ) - > Client ( ) - > DummyConnected ( ) )
2014-04-28 13:34:56 +00:00
g_Config . m_ClDummy = 0 ;
}
2019-05-06 12:19:10 +00:00
void CGameClient : : ConchainClTextEntitiesSize ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
pfnCallback ( pResult , pCallbackUserData ) ;
if ( pResult - > NumArguments ( ) )
{
2020-09-26 19:41:58 +00:00
CGameClient * pGameClient = ( CGameClient * ) pUserData ;
2021-07-12 09:43:56 +00:00
pGameClient - > m_MapImages . SetTextureScale ( g_Config . m_ClTextEntitiesSize ) ;
2019-05-06 12:19:10 +00:00
}
}
2010-05-29 07:25:38 +00:00
IGameClient * CreateGameClient ( )
2009-10-27 14:38:53 +00:00
{
2021-07-12 10:04:45 +00:00
return new CGameClient ( ) ;
2011-01-06 05:30:19 +00:00
}
2013-08-23 23:50:35 +00:00
2020-09-26 19:41:58 +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 ;
2019-06-09 17:26:20 +00:00
CClientData OwnClientData = m_aClients [ ownID ] ;
2014-02-08 20:55:08 +00:00
2019-04-21 17:35:07 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2013-08-23 23:50:35 +00:00
{
2019-06-09 17:26:20 +00:00
if ( i = = ownID )
continue ;
2014-01-11 23:45:25 +00:00
CClientData cData = m_aClients [ i ] ;
2019-06-09 17:26:20 +00:00
if ( ! cData . m_Active )
continue ;
2014-01-11 23:45:25 +00:00
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
2020-02-19 10:24:58 +00:00
vec2 Position = mix ( vec2 ( Prev . m_X , Prev . m_Y ) , vec2 ( Player . m_X , Player . m_Y ) , Client ( ) - > IntraGameTick ( g_Config . m_ClDummy ) ) ;
2013-08-23 23:50:35 +00:00
2019-06-09 17:26:20 +00:00
bool IsOneSuper = cData . m_Super | | OwnClientData . m_Super ;
bool IsOneSolo = cData . m_Solo | | OwnClientData . m_Solo ;
2019-04-21 17:35:07 +00:00
2019-06-09 17:26:20 +00:00
if ( ! IsOneSuper & & ( ! m_Teams . SameTeam ( i , ownID ) | | IsOneSolo | | OwnClientData . m_NoHookHit ) )
2014-01-11 23:45:25 +00:00
continue ;
2013-08-23 23:50:35 +00:00
2020-10-17 18:22:13 +00:00
vec2 ClosestPoint ;
if ( closest_point_on_line ( HookPos , NewPos , Position , ClosestPoint ) )
2013-08-23 23:50:35 +00:00
{
2020-10-17 18:22:13 +00:00
if ( distance ( Position , ClosestPoint ) < PhysSize + 2.0f )
2013-08-23 23:50:35 +00:00
{
2020-10-17 18:22:13 +00:00
if ( ClosestID = = - 1 | | distance ( HookPos , Position ) < Distance )
{
NewPos2 = ClosestPoint ;
ClosestID = i ;
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-25 16:49:27 +00:00
ColorRGBA CalculateNameColor ( ColorHSLA TextColorHSL )
2014-12-01 00:31:58 +00:00
{
2019-04-25 16:49:27 +00:00
return color_cast < ColorRGBA > ( ColorHSLA ( TextColorHSL . h , TextColorHSL . s * 0.68f , TextColorHSL . l * 0.81f ) ) ;
2019-04-11 22:46:54 +00:00
}
2019-04-21 17:35:07 +00:00
2019-04-11 22:46:54 +00:00
void CGameClient : : UpdatePrediction ( )
{
2021-09-15 14:05:30 +00:00
m_GameWorld . m_WorldConfig . m_IsVanilla = m_GameInfo . m_PredictVanilla ;
m_GameWorld . m_WorldConfig . m_IsDDRace = m_GameInfo . m_PredictDDRace ;
m_GameWorld . m_WorldConfig . m_IsFNG = m_GameInfo . m_PredictFNG ;
2022-04-25 13:57:10 +00:00
m_GameWorld . m_WorldConfig . m_PredictDDRace = m_GameInfo . m_PredictDDRace ;
m_GameWorld . m_WorldConfig . m_PredictTiles = m_GameInfo . m_PredictDDRace & & m_GameInfo . m_PredictDDRaceTiles ;
2021-04-23 05:17:41 +00:00
m_GameWorld . m_WorldConfig . m_UseTuneZones = m_GameInfo . m_PredictDDRaceTiles ;
2021-09-15 14:05:30 +00:00
m_GameWorld . m_WorldConfig . m_PredictFreeze = g_Config . m_ClPredictFreeze ;
m_GameWorld . m_WorldConfig . m_PredictWeapons = AntiPingWeapons ( ) ;
2021-04-23 05:17:41 +00:00
2021-09-15 20:14:16 +00:00
// always update default tune zone, even without character
if ( ! m_GameWorld . m_WorldConfig . m_UseTuneZones )
m_GameWorld . TuningList ( ) [ 0 ] = m_Tuning [ g_Config . m_ClDummy ] ;
2019-04-11 22:46:54 +00:00
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-11 22:46:54 +00:00
if ( m_Snap . m_pLocalCharacter - > m_AmmoCount > 0 & & m_Snap . m_pLocalCharacter - > m_Weapon ! = WEAPON_NINJA )
m_GameWorld . m_WorldConfig . m_InfiniteAmmo = false ;
2019-05-11 19:13:09 +00:00
m_GameWorld . m_WorldConfig . m_IsSolo = ! m_Snap . m_aCharacters [ m_Snap . m_LocalClientID ] . m_HasExtendedData & & ! m_Tuning [ g_Config . m_ClDummy ] . m_PlayerCollision & & ! m_Tuning [ g_Config . m_ClDummy ] . m_PlayerHooking ;
2019-09-15 22:07:42 +00:00
// update the tuning/tunezone at the local character position with the latest tunings received before the new snapshot
2021-05-12 16:57:50 +00:00
vec2 LocalCharPos = vec2 ( m_Snap . m_pLocalCharacter - > m_X , m_Snap . m_pLocalCharacter - > m_Y ) ;
m_GameWorld . m_Core . m_Tuning [ g_Config . m_ClDummy ] = m_Tuning [ g_Config . m_ClDummy ] ;
2021-04-23 05:53:54 +00:00
int TuneZone = 0 ;
if ( m_GameWorld . m_WorldConfig . m_UseTuneZones )
2021-05-12 16:57:50 +00:00
{
TuneZone = Collision ( ) - > IsTune ( Collision ( ) - > GetMapIndex ( LocalCharPos ) ) ;
if ( TuneZone ! = m_LocalTuneZone [ g_Config . m_ClDummy ] )
{
// our tunezone changed, expecting tuning message
m_LocalTuneZone [ g_Config . m_ClDummy ] = m_ExpectingTuningForZone [ g_Config . m_ClDummy ] = TuneZone ;
m_ExpectingTuningSince [ g_Config . m_ClDummy ] = 0 ;
}
if ( m_ExpectingTuningForZone [ g_Config . m_ClDummy ] > = 0 )
{
if ( m_ReceivedTuning [ g_Config . m_ClDummy ] )
{
dbg_msg ( " tunezone " , " got tuning for zone %d " , m_ExpectingTuningForZone [ g_Config . m_ClDummy ] ) ;
m_GameWorld . TuningList ( ) [ m_ExpectingTuningForZone [ g_Config . m_ClDummy ] ] = m_Tuning [ g_Config . m_ClDummy ] ;
m_ReceivedTuning [ g_Config . m_ClDummy ] = false ;
m_ExpectingTuningForZone [ g_Config . m_ClDummy ] = - 1 ;
}
else if ( m_ExpectingTuningSince [ g_Config . m_ClDummy ] > = 5 )
{
// if we are expecting tuning for more than 10 snaps (less than a quarter of a second)
// it is probably dropped or it was received out of order
// or applied to another tunezone.
// we need to fallback to current tuning to fix ourselves.
m_ExpectingTuningForZone [ g_Config . m_ClDummy ] = - 1 ;
m_ExpectingTuningSince [ g_Config . m_ClDummy ] = 0 ;
m_ReceivedTuning [ g_Config . m_ClDummy ] = false ;
dbg_msg ( " tunezone " , " the tuning was missed " ) ;
}
else
{
// if we are expecting tuning and have not received one yet.
// do not update any tuning, so we don't apply it to the wrong tunezone.
dbg_msg ( " tunezone " , " waiting for tuning for zone %d " , m_ExpectingTuningForZone [ g_Config . m_ClDummy ] ) ;
m_ExpectingTuningSince [ g_Config . m_ClDummy ] + + ;
}
}
else
{
// if we have processed what we need, and the tuning is still wrong due to out of order messege
// fix our tuning by using the current one
m_GameWorld . TuningList ( ) [ TuneZone ] = m_Tuning [ g_Config . m_ClDummy ] ;
m_ExpectingTuningSince [ g_Config . m_ClDummy ] = 0 ;
m_ReceivedTuning [ g_Config . m_ClDummy ] = false ;
}
}
2019-04-11 22:46:54 +00:00
2020-11-08 13:05:44 +00:00
// if ddnetcharacter is available, ignore server-wide tunings for hook and collision
if ( m_Snap . m_aCharacters [ m_Snap . m_LocalClientID ] . m_HasExtendedData )
{
2021-05-01 02:34:20 +00:00
m_GameWorld . m_Core . m_Tuning [ g_Config . m_ClDummy ] . m_PlayerCollision = 1 ;
m_GameWorld . m_Core . m_Tuning [ g_Config . m_ClDummy ] . m_PlayerHooking = 1 ;
2020-11-08 13:05:44 +00:00
}
2019-04-11 22:46:54 +00:00
// 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 ) ;
2020-04-18 20:16:25 +00:00
CCharacter * pDummyChar = 0 ;
if ( PredictDummy ( ) )
pDummyChar = m_GameWorld . GetCharacterByID ( m_PredictedDummyID ) ;
2014-12-01 00:31:58 +00:00
2019-04-11 22:46:54 +00:00
// update strong and weak hook
2021-07-20 17:39:44 +00:00
if ( pLocalChar & & ! m_Snap . m_SpecInfo . m_Active & & Client ( ) - > State ( ) ! = IClient : : STATE_DEMOPLAYBACK & & ( m_Tuning [ g_Config . m_ClDummy ] . m_PlayerCollision | | m_Tuning [ g_Config . m_ClDummy ] . m_PlayerHooking ) )
2019-06-30 21:47:33 +00:00
{
if ( m_Snap . m_aCharacters [ m_Snap . m_LocalClientID ] . m_HasExtendedData )
2019-04-11 22:46:54 +00:00
{
2019-06-30 21:47:33 +00:00
int aIDs [ MAX_CLIENTS ] ;
2020-10-26 14:14:07 +00:00
for ( int & ID : aIDs )
ID = - 1 ;
2019-06-30 21:47:33 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
if ( CCharacter * pChar = m_GameWorld . GetCharacterByID ( i ) )
aIDs [ pChar - > GetStrongWeakID ( ) ] = i ;
2020-10-26 14:14:07 +00:00
for ( int ID : aIDs )
if ( ID > = 0 )
m_CharOrder . GiveStrong ( ID ) ;
2019-04-11 22:46:54 +00:00
}
2019-06-30 21:47:33 +00:00
else
2019-04-11 22:46:54 +00:00
{
2019-06-30 21:47:33 +00:00
// manual detection
DetectStrongHook ( ) ;
2019-04-11 22:46:54 +00:00
}
2019-06-30 21:47:33 +00:00
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
2020-02-19 10:24:58 +00:00
if ( pLocalChar & & abs ( m_GameWorld . GameTick ( ) - Client ( ) - > GameTick ( g_Config . m_ClDummy ) ) < SERVER_TICK_SPEED )
2014-12-01 00:31:58 +00:00
{
2020-02-19 10:24:58 +00:00
for ( int Tick = m_GameWorld . GameTick ( ) + 1 ; Tick < = Client ( ) - > GameTick ( g_Config . m_ClDummy ) ; Tick + + )
2019-04-11 22:46:54 +00:00
{
2020-09-26 19:41:58 +00:00
CNetObj_PlayerInput * pInput = ( CNetObj_PlayerInput * ) Client ( ) - > GetDirectInput ( Tick ) ;
2020-04-18 20:16:25 +00:00
CNetObj_PlayerInput * pDummyInput = 0 ;
if ( pDummyChar )
2020-09-26 19:41:58 +00:00
pDummyInput = ( CNetObj_PlayerInput * ) Client ( ) - > GetDirectInput ( Tick , 1 ) ;
2019-04-11 22:46:54 +00:00
if ( pInput )
pLocalChar - > OnDirectInput ( pInput ) ;
2020-04-18 20:16:25 +00:00
if ( pDummyInput )
pDummyChar - > OnDirectInput ( pDummyInput ) ;
2019-04-11 22:46:54 +00:00
m_GameWorld . m_GameTick = Tick ;
if ( pInput )
pLocalChar - > OnPredictedInput ( pInput ) ;
2020-04-18 20:16:25 +00:00
if ( pDummyInput )
pDummyChar - > OnPredictedInput ( pDummyInput ) ;
2019-04-11 22:46:54 +00:00
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
2020-02-19 10:24:58 +00:00
m_GameWorld . m_GameTick = Client ( ) - > GameTick ( g_Config . m_ClDummy ) ;
2019-04-11 22:46:54 +00:00
if ( pLocalChar )
2020-09-26 19:41:58 +00:00
if ( CNetObj_PlayerInput * pInput = ( CNetObj_PlayerInput * ) Client ( ) - > GetInput ( Client ( ) - > GameTick ( g_Config . m_ClDummy ) ) )
2019-04-11 22:46:54 +00:00
pLocalChar - > SetInput ( pInput ) ;
2020-04-18 20:16:25 +00:00
if ( pDummyChar )
2020-09-26 19:41:58 +00:00
if ( CNetObj_PlayerInput * pInput = ( CNetObj_PlayerInput * ) Client ( ) - > GetInput ( Client ( ) - > GameTick ( g_Config . m_ClDummy ) , 1 ) )
2020-04-18 20:16:25 +00:00
pDummyChar - > 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 ) )
{
2020-02-19 10:24:58 +00:00
m_aClients [ i ] . m_PredPos [ Client ( ) - > GameTick ( g_Config . m_ClDummy ) % 200 ] = pChar - > Core ( ) - > m_Pos ;
m_aClients [ i ] . m_PredTick [ Client ( ) - > GameTick ( g_Config . m_ClDummy ) % 200 ] = Client ( ) - > GameTick ( g_Config . m_ClDummy ) ;
2019-04-11 22:46:54 +00:00
}
2014-12-01 00:31:58 +00:00
2019-04-11 22:46:54 +00:00
// update the local gameworld with the new snapshot
2019-06-16 14:31:06 +00:00
m_GameWorld . m_Teams = m_Teams ;
2019-04-11 22:46:54 +00:00
m_GameWorld . NetObjBegin ( ) ;
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
if ( m_Snap . m_aCharacters [ i ] . m_Active )
2014-12-01 00:31:58 +00:00
{
2020-04-18 20:16:25 +00:00
bool IsLocal = ( i = = m_Snap . m_LocalClientID | | ( PredictDummy ( ) & & i = = m_PredictedDummyID ) ) ;
2020-09-26 19:41:58 +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 ,
2020-09-26 19:41:58 +00:00
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
}
2021-02-07 19:51:28 +00:00
2021-10-21 01:18:54 +00:00
for ( const CSnapEntities & EntData : SnapEntities ( ) )
m_GameWorld . NetObjAdd ( EntData . m_Item . m_ID , EntData . m_Item . m_Type , EntData . m_pData , EntData . m_pDataEx ) ;
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 ;
2019-05-12 23:45:49 +00:00
m_aClients [ i ] . m_IsPredictedLocal = false ;
2019-04-11 22:46:54 +00:00
vec2 UnpredPos = mix (
2020-09-26 19:41:58 +00:00
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 ( g_Config . m_ClDummy ) ) ;
2019-04-11 22:46:54 +00:00
vec2 Pos = UnpredPos ;
2014-12-01 00:31:58 +00:00
2021-02-07 19:51:28 +00:00
if ( Predict ( ) & & ( i = = m_Snap . m_LocalClientID | | ( AntiPingPlayers ( ) & & ! IsOtherTeam ( i ) ) ) )
2019-04-11 22:46:54 +00:00
{
m_aClients [ i ] . m_Predicted . Write ( & m_aClients [ i ] . m_RenderCur ) ;
m_aClients [ i ] . m_PrevPredicted . Write ( & m_aClients [ i ] . m_RenderPrev ) ;
2019-05-04 18:24:48 +00:00
2019-04-11 22:46:54 +00:00
m_aClients [ i ] . m_IsPredicted = true ;
2019-05-04 18:24:48 +00:00
2019-04-11 22:46:54 +00:00
Pos = mix (
2020-09-26 19:41:58 +00:00
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 ( g_Config . m_ClDummy ) : Client ( ) - > IntraGameTick ( g_Config . m_ClDummy ) ) ;
2019-04-11 22:46:54 +00:00
if ( i = = m_Snap . m_LocalClientID )
2019-05-12 23:45:49 +00:00
{
2019-04-11 22:46:54 +00:00
m_aClients [ i ] . m_IsPredictedLocal = true ;
2019-05-12 23:45:49 +00:00
CCharacter * pChar = m_PredictedWorld . GetCharacterByID ( i ) ;
2019-06-19 00:12:57 +00:00
if ( pChar & & AntiPingGunfire ( ) & & ( ( pChar - > m_NinjaJetpack & & pChar - > m_FreezeTime = = 0 ) | | m_Snap . m_aCharacters [ i ] . m_Cur . m_Weapon ! = WEAPON_NINJA | | m_Snap . m_aCharacters [ i ] . m_Cur . m_Weapon = = m_aClients [ i ] . m_Predicted . m_ActiveWeapon ) )
2019-05-12 23:45:49 +00:00
{
m_aClients [ i ] . m_RenderCur . m_AttackTick = pChar - > GetAttackTick ( ) ;
if ( m_Snap . m_aCharacters [ i ] . m_Cur . m_Weapon ! = WEAPON_NINJA & & ! ( pChar - > m_NinjaJetpack & & pChar - > Core ( ) - > m_ActiveWeapon = = WEAPON_GUN ) )
m_aClients [ i ] . m_RenderCur . m_Weapon = m_aClients [ i ] . m_Predicted . m_ActiveWeapon ;
}
}
2019-04-11 22:46:54 +00:00
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_RenderCur . m_Angle = m_Snap . m_aCharacters [ i ] . m_Cur . m_Angle ;
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 ;
2020-09-26 19:41:58 +00:00
if ( abs ( minimum ( s_LastUpdateTick [ ToPlayer ] , s_LastUpdateTick [ FromPlayer ] ) - Client ( ) - > GameTick ( g_Config . m_ClDummy ) ) < SERVER_TICK_SPEED / 4 )
2019-04-11 22:46:54 +00:00
continue ;
2020-09-26 19:41:58 +00:00
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 )
2019-04-11 22:46:54 +00:00
continue ;
2019-06-18 01:04:03 +00:00
CCharacter * pFromCharWorld = m_GameWorld . GetCharacterByID ( FromPlayer ) ;
CCharacter * pToCharWorld = m_GameWorld . GetCharacterByID ( ToPlayer ) ;
if ( ! pFromCharWorld | | ! pToCharWorld )
continue ;
2020-02-19 10:24:58 +00:00
s_LastUpdateTick [ ToPlayer ] = s_LastUpdateTick [ FromPlayer ] = Client ( ) - > GameTick ( g_Config . m_ClDummy ) ;
2019-04-11 22:46:54 +00:00
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 ] ;
2019-06-18 01:04:03 +00:00
2015-01-11 16:36:38 +00:00
for ( int dir = 0 ; dir < 2 ; dir + + )
{
2019-06-18 01:04:03 +00:00
CCharacterCore ToChar = pFromCharWorld - > GetCore ( ) ;
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-06-18 01:04:03 +00:00
CCharacterCore FromChar = pFromCharWorld - > GetCore ( ) ;
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
2020-02-19 10:24:58 +00:00
for ( int Tick = Client ( ) - > PrevGameTick ( g_Config . m_ClDummy ) ; Tick < Client ( ) - > GameTick ( g_Config . m_ClDummy ) ; Tick + + )
2015-01-11 16:36:38 +00:00
{
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
{
2020-02-19 10:24:58 +00:00
vec2 Pos = mix ( m_aClients [ ClientID ] . m_PrevPredicted . m_Pos , m_aClients [ ClientID ] . m_Predicted . m_Pos , Client ( ) - > PredIntraGameTick ( g_Config . m_ClDummy ) ) ;
2021-06-23 05:05:49 +00:00
int64_t Now = time_get ( ) ;
2019-04-11 22:46:54 +00:00
for ( int i = 0 ; i < 2 ; i + + )
{
2021-06-23 05:05:49 +00:00
int64_t Len = clamp ( m_aClients [ ClientID ] . m_SmoothLen [ i ] , ( int64_t ) 1 , time_freq ( ) ) ;
int64_t TimePassed = Now - m_aClients [ ClientID ] . m_SmoothStart [ i ] ;
if ( in_range ( TimePassed , ( int64_t ) 0 , Len - 1 ) )
2019-04-11 22:46:54 +00:00
{
2020-09-26 19:41:58 +00:00
float MixAmount = 1.f - powf ( 1.f - TimePassed / ( float ) Len , 1.2f ) ;
2019-04-11 22:46:54 +00:00
int SmoothTick ;
float SmoothIntra ;
Client ( ) - > GetSmoothTick ( & SmoothTick , & SmoothIntra , MixAmount ) ;
2020-09-26 19:41:58 +00:00
if ( SmoothTick > 0 & & m_aClients [ ClientID ] . m_PredTick [ ( SmoothTick - 1 ) % 200 ] > = Client ( ) - > PrevGameTick ( g_Config . m_ClDummy ) & & m_aClients [ ClientID ] . m_PredTick [ SmoothTick % 200 ] < = Client ( ) - > PredGameTick ( g_Config . m_ClDummy ) )
Pos [ i ] = mix ( m_aClients [ ClientID ] . m_PredPos [ ( SmoothTick - 1 ) % 200 ] [ i ] , m_aClients [ ClientID ] . m_PredPos [ SmoothTick % 200 ] [ i ] , SmoothIntra ) ;
2019-04-11 22:46:54 +00:00
}
}
return Pos ;
2017-03-06 13:04:09 +00:00
}
2019-06-05 17:17:55 +00:00
void CGameClient : : Echo ( const char * pString )
{
2021-07-12 09:43:56 +00:00
m_Chat . Echo ( pString ) ;
2019-06-05 17:17:55 +00:00
}
2019-07-16 20:06:57 +00:00
bool CGameClient : : IsOtherTeam ( int ClientID )
{
bool Local = m_Snap . m_LocalClientID = = ClientID ;
2020-02-27 12:13:16 +00:00
if ( m_Snap . m_LocalClientID < 0 )
return false ;
2022-03-14 12:25:47 +00:00
else if ( ( m_Snap . m_SpecInfo . m_Active & & m_Snap . m_SpecInfo . m_SpectatorID = = SPEC_FREEVIEW ) | | ClientID < 0 )
2019-07-16 20:06:57 +00:00
return false ;
else if ( m_Snap . m_SpecInfo . m_Active & & m_Snap . m_SpecInfo . m_SpectatorID ! = SPEC_FREEVIEW )
2021-12-23 11:06:54 +00:00
{
if ( m_Teams . Team ( ClientID ) = = TEAM_SUPER | | m_Teams . Team ( m_Snap . m_SpecInfo . m_SpectatorID ) = = TEAM_SUPER )
return false ;
2019-07-16 20:06:57 +00:00
return m_Teams . Team ( ClientID ) ! = m_Teams . Team ( m_Snap . m_SpecInfo . m_SpectatorID ) ;
2021-12-23 11:06:54 +00:00
}
2019-07-16 20:06:57 +00:00
else if ( ( m_aClients [ m_Snap . m_LocalClientID ] . m_Solo | | m_aClients [ ClientID ] . m_Solo ) & & ! Local )
return true ;
2021-12-23 11:06:54 +00:00
if ( m_Teams . Team ( ClientID ) = = TEAM_SUPER | | m_Teams . Team ( m_Snap . m_LocalClientID ) = = TEAM_SUPER )
return false ;
2019-07-16 20:06:57 +00:00
return m_Teams . Team ( ClientID ) ! = m_Teams . Team ( m_Snap . m_LocalClientID ) ;
}
2019-09-08 22:53:07 +00:00
2021-11-08 22:51:09 +00:00
int CGameClient : : SwitchStateTeam ( )
2021-09-19 12:14:00 +00:00
{
2021-11-08 22:51:09 +00:00
if ( m_SwitchStateTeam [ g_Config . m_ClDummy ] > = 0 )
return m_SwitchStateTeam [ g_Config . m_ClDummy ] ;
else if ( m_Snap . m_LocalClientID < 0 )
2021-09-19 12:14:00 +00:00
return 0 ;
else if ( m_Snap . m_SpecInfo . m_Active & & m_Snap . m_SpecInfo . m_SpectatorID ! = SPEC_FREEVIEW )
return m_Teams . Team ( m_Snap . m_SpecInfo . m_SpectatorID ) ;
return m_Teams . Team ( m_Snap . m_LocalClientID ) ;
}
2021-10-14 20:59:39 +00:00
bool CGameClient : : IsLocalCharSuper ( )
{
if ( m_Snap . m_LocalClientID < 0 )
2022-02-14 23:12:52 +00:00
return false ;
2021-10-14 20:59:39 +00:00
return m_aClients [ m_Snap . m_LocalClientID ] . m_Super ;
}
2020-09-26 07:37:35 +00:00
void CGameClient : : LoadGameSkin ( const char * pPath , bool AsDir )
{
2020-10-09 07:07:05 +00:00
if ( m_GameSkinLoaded )
2020-09-26 07:37:35 +00:00
{
2021-09-15 11:19:54 +00:00
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteHealthFull ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteHealthEmpty ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteArmorFull ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteArmorEmpty ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponHammerCursor ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponGunCursor ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponShotgunCursor ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponGrenadeCursor ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponNinjaCursor ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponLaserCursor ) ;
2020-10-09 07:07:05 +00:00
2020-10-26 14:14:07 +00:00
for ( auto & SpriteWeaponCursor : m_GameSkin . m_SpriteWeaponCursors )
2020-10-09 07:07:05 +00:00
{
2020-10-26 14:14:07 +00:00
SpriteWeaponCursor = IGraphics : : CTextureHandle ( ) ;
2020-10-09 07:07:05 +00:00
}
2021-09-15 11:19:54 +00:00
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteHookChain ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteHookHead ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponHammer ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponGun ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponShotgun ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponGrenade ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponNinja ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponLaser ) ;
2020-10-09 07:07:05 +00:00
2020-10-26 14:14:07 +00:00
for ( auto & SpriteWeapon : m_GameSkin . m_SpriteWeapons )
2020-10-09 07:07:05 +00:00
{
2020-10-26 14:14:07 +00:00
SpriteWeapon = IGraphics : : CTextureHandle ( ) ;
2020-10-09 07:07:05 +00:00
}
2020-10-26 14:14:07 +00:00
for ( auto & SpriteParticle : m_GameSkin . m_SpriteParticles )
2020-10-09 07:07:05 +00:00
{
2021-09-15 11:19:54 +00:00
Graphics ( ) - > UnloadTexture ( & SpriteParticle ) ;
2020-10-09 07:07:05 +00:00
}
2020-10-26 14:14:07 +00:00
for ( auto & SpriteStar : m_GameSkin . m_SpriteStars )
2020-10-09 07:07:05 +00:00
{
2021-09-15 11:19:54 +00:00
Graphics ( ) - > UnloadTexture ( & SpriteStar ) ;
2020-10-09 07:07:05 +00:00
}
2021-09-15 11:19:54 +00:00
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponGunProjectile ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponShotgunProjectile ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponGrenadeProjectile ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponHammerProjectile ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponNinjaProjectile ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponLaserProjectile ) ;
2020-10-09 07:07:05 +00:00
2020-10-26 14:14:07 +00:00
for ( auto & SpriteWeaponProjectile : m_GameSkin . m_SpriteWeaponProjectiles )
2020-10-09 07:07:05 +00:00
{
2020-10-26 14:14:07 +00:00
SpriteWeaponProjectile = IGraphics : : CTextureHandle ( ) ;
2020-10-09 07:07:05 +00:00
}
for ( int i = 0 ; i < 3 ; + + i )
{
2021-09-15 11:19:54 +00:00
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponGunMuzzles [ i ] ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponShotgunMuzzles [ i ] ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteWeaponNinjaMuzzles [ i ] ) ;
2020-10-09 07:07:05 +00:00
2020-10-26 14:14:07 +00:00
for ( auto & SpriteWeaponsMuzzle : m_GameSkin . m_SpriteWeaponsMuzzles )
2020-10-09 07:07:05 +00:00
{
2020-10-26 14:14:07 +00:00
SpriteWeaponsMuzzle [ i ] = IGraphics : : CTextureHandle ( ) ;
2020-10-09 07:07:05 +00:00
}
}
2021-09-15 11:19:54 +00:00
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpritePickupHealth ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpritePickupArmor ) ;
2022-02-17 23:51:02 +00:00
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpritePickupArmorShotgun ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpritePickupArmorGrenade ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpritePickupArmorLaser ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpritePickupArmorNinja ) ;
2021-09-15 11:19:54 +00:00
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpritePickupGrenade ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpritePickupShotgun ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpritePickupLaser ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpritePickupNinja ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpritePickupGun ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpritePickupHammer ) ;
2020-10-09 07:07:05 +00:00
2020-10-26 14:14:07 +00:00
for ( auto & SpritePickupWeapon : m_GameSkin . m_SpritePickupWeapons )
2020-10-09 07:07:05 +00:00
{
2020-10-26 14:14:07 +00:00
SpritePickupWeapon = IGraphics : : CTextureHandle ( ) ;
2020-10-09 07:07:05 +00:00
}
2021-09-15 11:19:54 +00:00
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteFlagBlue ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteFlagRed ) ;
2020-10-09 07:07:05 +00:00
if ( m_GameSkin . IsSixup ( ) )
{
2021-09-15 11:19:54 +00:00
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteNinjaBarFullLeft ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteNinjaBarFull ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteNinjaBarEmpty ) ;
Graphics ( ) - > UnloadTexture ( & m_GameSkin . m_SpriteNinjaBarEmptyRight ) ;
2020-10-09 07:07:05 +00:00
}
m_GameSkinLoaded = false ;
2020-09-26 07:37:35 +00:00
}
2021-09-13 08:06:34 +00:00
char aPath [ IO_MAX_PATH_LENGTH ] ;
2020-09-26 07:37:35 +00:00
bool IsDefault = false ;
if ( str_comp ( pPath , " default " ) = = 0 )
{
str_format ( aPath , sizeof ( aPath ) , " %s " , g_pData - > m_aImages [ IMAGE_GAME ] . m_pFilename ) ;
IsDefault = true ;
}
else
{
if ( AsDir )
str_format ( aPath , sizeof ( aPath ) , " assets/game/%s/%s " , pPath , g_pData - > m_aImages [ IMAGE_GAME ] . m_pFilename ) ;
else
str_format ( aPath , sizeof ( aPath ) , " assets/game/%s.png " , pPath ) ;
}
CImageInfo ImgInfo ;
bool PngLoaded = Graphics ( ) - > LoadPNG ( & ImgInfo , aPath , IStorage : : TYPE_ALL ) ;
if ( ! PngLoaded & & ! IsDefault )
{
if ( AsDir )
LoadGameSkin ( " default " ) ;
else
LoadGameSkin ( pPath , true ) ;
}
2022-02-22 23:39:31 +00:00
else if ( PngLoaded & & Graphics ( ) - > CheckImageDivisibility ( aPath , ImgInfo , g_pData - > m_aSprites [ SPRITE_HEALTH_FULL ] . m_pSet - > m_Gridx , g_pData - > m_aSprites [ SPRITE_HEALTH_FULL ] . m_pSet - > m_Gridy , true ) & & Graphics ( ) - > IsImageFormatRGBA ( aPath , ImgInfo ) )
2020-09-26 07:37:35 +00:00
{
2020-10-09 07:07:05 +00:00
m_GameSkin . m_SpriteHealthFull = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_HEALTH_FULL ] ) ;
m_GameSkin . m_SpriteHealthEmpty = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_HEALTH_EMPTY ] ) ;
m_GameSkin . m_SpriteArmorFull = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_ARMOR_FULL ] ) ;
m_GameSkin . m_SpriteArmorEmpty = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_ARMOR_EMPTY ] ) ;
m_GameSkin . m_SpriteWeaponHammerCursor = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_WEAPON_HAMMER_CURSOR ] ) ;
m_GameSkin . m_SpriteWeaponGunCursor = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_WEAPON_GUN_CURSOR ] ) ;
m_GameSkin . m_SpriteWeaponShotgunCursor = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_WEAPON_SHOTGUN_CURSOR ] ) ;
m_GameSkin . m_SpriteWeaponGrenadeCursor = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_WEAPON_GRENADE_CURSOR ] ) ;
m_GameSkin . m_SpriteWeaponNinjaCursor = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_WEAPON_NINJA_CURSOR ] ) ;
m_GameSkin . m_SpriteWeaponLaserCursor = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_WEAPON_LASER_CURSOR ] ) ;
m_GameSkin . m_SpriteWeaponCursors [ 0 ] = m_GameSkin . m_SpriteWeaponHammerCursor ;
m_GameSkin . m_SpriteWeaponCursors [ 1 ] = m_GameSkin . m_SpriteWeaponGunCursor ;
m_GameSkin . m_SpriteWeaponCursors [ 2 ] = m_GameSkin . m_SpriteWeaponShotgunCursor ;
m_GameSkin . m_SpriteWeaponCursors [ 3 ] = m_GameSkin . m_SpriteWeaponGrenadeCursor ;
m_GameSkin . m_SpriteWeaponCursors [ 4 ] = m_GameSkin . m_SpriteWeaponLaserCursor ;
m_GameSkin . m_SpriteWeaponCursors [ 5 ] = m_GameSkin . m_SpriteWeaponNinjaCursor ;
// weapons and hook
m_GameSkin . m_SpriteHookChain = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_HOOK_CHAIN ] ) ;
m_GameSkin . m_SpriteHookHead = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_HOOK_HEAD ] ) ;
m_GameSkin . m_SpriteWeaponHammer = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_WEAPON_HAMMER_BODY ] ) ;
m_GameSkin . m_SpriteWeaponGun = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_WEAPON_GUN_BODY ] ) ;
m_GameSkin . m_SpriteWeaponShotgun = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_WEAPON_SHOTGUN_BODY ] ) ;
m_GameSkin . m_SpriteWeaponGrenade = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_WEAPON_GRENADE_BODY ] ) ;
m_GameSkin . m_SpriteWeaponNinja = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_WEAPON_NINJA_BODY ] ) ;
m_GameSkin . m_SpriteWeaponLaser = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_WEAPON_LASER_BODY ] ) ;
m_GameSkin . m_SpriteWeapons [ 0 ] = m_GameSkin . m_SpriteWeaponHammer ;
m_GameSkin . m_SpriteWeapons [ 1 ] = m_GameSkin . m_SpriteWeaponGun ;
m_GameSkin . m_SpriteWeapons [ 2 ] = m_GameSkin . m_SpriteWeaponShotgun ;
m_GameSkin . m_SpriteWeapons [ 3 ] = m_GameSkin . m_SpriteWeaponGrenade ;
m_GameSkin . m_SpriteWeapons [ 4 ] = m_GameSkin . m_SpriteWeaponLaser ;
m_GameSkin . m_SpriteWeapons [ 5 ] = m_GameSkin . m_SpriteWeaponNinja ;
// particles
for ( int i = 0 ; i < 9 ; + + i )
{
m_GameSkin . m_SpriteParticles [ i ] = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_PART1 + i ] ) ;
}
// stars
for ( int i = 0 ; i < 3 ; + + i )
{
m_GameSkin . m_SpriteStars [ i ] = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_STAR1 + i ] ) ;
}
// projectiles
m_GameSkin . m_SpriteWeaponGunProjectile = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_WEAPON_GUN_PROJ ] ) ;
m_GameSkin . m_SpriteWeaponShotgunProjectile = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_WEAPON_SHOTGUN_PROJ ] ) ;
m_GameSkin . m_SpriteWeaponGrenadeProjectile = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_WEAPON_GRENADE_PROJ ] ) ;
// these weapons have no projectiles
m_GameSkin . m_SpriteWeaponHammerProjectile = IGraphics : : CTextureHandle ( ) ;
m_GameSkin . m_SpriteWeaponNinjaProjectile = IGraphics : : CTextureHandle ( ) ;
m_GameSkin . m_SpriteWeaponLaserProjectile = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_WEAPON_LASER_PROJ ] ) ;
m_GameSkin . m_SpriteWeaponProjectiles [ 0 ] = m_GameSkin . m_SpriteWeaponHammerProjectile ;
m_GameSkin . m_SpriteWeaponProjectiles [ 1 ] = m_GameSkin . m_SpriteWeaponGunProjectile ;
m_GameSkin . m_SpriteWeaponProjectiles [ 2 ] = m_GameSkin . m_SpriteWeaponShotgunProjectile ;
m_GameSkin . m_SpriteWeaponProjectiles [ 3 ] = m_GameSkin . m_SpriteWeaponGrenadeProjectile ;
m_GameSkin . m_SpriteWeaponProjectiles [ 4 ] = m_GameSkin . m_SpriteWeaponLaserProjectile ;
m_GameSkin . m_SpriteWeaponProjectiles [ 5 ] = m_GameSkin . m_SpriteWeaponNinjaProjectile ;
// muzzles
for ( int i = 0 ; i < 3 ; + + i )
{
m_GameSkin . m_SpriteWeaponGunMuzzles [ i ] = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_WEAPON_GUN_MUZZLE1 + i ] ) ;
m_GameSkin . m_SpriteWeaponShotgunMuzzles [ i ] = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_WEAPON_SHOTGUN_MUZZLE1 + i ] ) ;
m_GameSkin . m_SpriteWeaponNinjaMuzzles [ i ] = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_WEAPON_NINJA_MUZZLE1 + i ] ) ;
m_GameSkin . m_SpriteWeaponsMuzzles [ 1 ] [ i ] = m_GameSkin . m_SpriteWeaponGunMuzzles [ i ] ;
m_GameSkin . m_SpriteWeaponsMuzzles [ 2 ] [ i ] = m_GameSkin . m_SpriteWeaponShotgunMuzzles [ i ] ;
m_GameSkin . m_SpriteWeaponsMuzzles [ 5 ] [ i ] = m_GameSkin . m_SpriteWeaponNinjaMuzzles [ i ] ;
}
// pickups
m_GameSkin . m_SpritePickupHealth = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_PICKUP_HEALTH ] ) ;
m_GameSkin . m_SpritePickupArmor = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_PICKUP_ARMOR ] ) ;
2022-02-17 23:51:02 +00:00
m_GameSkin . m_SpritePickupArmorShotgun = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_PICKUP_ARMOR_SHOTGUN ] ) ;
m_GameSkin . m_SpritePickupArmorGrenade = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_PICKUP_ARMOR_GRENADE ] ) ;
m_GameSkin . m_SpritePickupArmorLaser = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_PICKUP_ARMOR_LASER ] ) ;
m_GameSkin . m_SpritePickupArmorNinja = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_PICKUP_ARMOR_NINJA ] ) ;
2020-10-09 07:07:05 +00:00
m_GameSkin . m_SpritePickupGrenade = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & client_data7 : : g_pData - > m_aSprites [ client_data7 : : SPRITE_PICKUP_GRENADE ] ) ;
m_GameSkin . m_SpritePickupShotgun = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & client_data7 : : g_pData - > m_aSprites [ client_data7 : : SPRITE_PICKUP_SHOTGUN ] ) ;
m_GameSkin . m_SpritePickupLaser = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & client_data7 : : g_pData - > m_aSprites [ client_data7 : : SPRITE_PICKUP_LASER ] ) ;
m_GameSkin . m_SpritePickupNinja = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_PICKUP_NINJA ] ) ;
m_GameSkin . m_SpritePickupGun = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & client_data7 : : g_pData - > m_aSprites [ client_data7 : : SPRITE_PICKUP_GUN ] ) ;
m_GameSkin . m_SpritePickupHammer = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & client_data7 : : g_pData - > m_aSprites [ client_data7 : : SPRITE_PICKUP_HAMMER ] ) ;
m_GameSkin . m_SpritePickupWeapons [ 0 ] = m_GameSkin . m_SpritePickupHammer ;
m_GameSkin . m_SpritePickupWeapons [ 1 ] = m_GameSkin . m_SpritePickupGun ;
m_GameSkin . m_SpritePickupWeapons [ 2 ] = m_GameSkin . m_SpritePickupShotgun ;
m_GameSkin . m_SpritePickupWeapons [ 3 ] = m_GameSkin . m_SpritePickupGrenade ;
m_GameSkin . m_SpritePickupWeapons [ 4 ] = m_GameSkin . m_SpritePickupLaser ;
m_GameSkin . m_SpritePickupWeapons [ 5 ] = m_GameSkin . m_SpritePickupNinja ;
// flags
m_GameSkin . m_SpriteFlagBlue = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_FLAG_BLUE ] ) ;
m_GameSkin . m_SpriteFlagRed = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_FLAG_RED ] ) ;
// ninja bar (0.7)
if ( ! Graphics ( ) - > IsSpriteTextureFullyTransparent ( ImgInfo , & client_data7 : : g_pData - > m_aSprites [ client_data7 : : SPRITE_NINJA_BAR_FULL_LEFT ] ) | |
! Graphics ( ) - > IsSpriteTextureFullyTransparent ( ImgInfo , & client_data7 : : g_pData - > m_aSprites [ client_data7 : : SPRITE_NINJA_BAR_FULL ] ) | |
! Graphics ( ) - > IsSpriteTextureFullyTransparent ( ImgInfo , & client_data7 : : g_pData - > m_aSprites [ client_data7 : : SPRITE_NINJA_BAR_EMPTY ] ) | |
! Graphics ( ) - > IsSpriteTextureFullyTransparent ( ImgInfo , & client_data7 : : g_pData - > m_aSprites [ client_data7 : : SPRITE_NINJA_BAR_EMPTY_RIGHT ] ) )
{
m_GameSkin . m_SpriteNinjaBarFullLeft = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & client_data7 : : g_pData - > m_aSprites [ client_data7 : : SPRITE_NINJA_BAR_FULL_LEFT ] ) ;
m_GameSkin . m_SpriteNinjaBarFull = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & client_data7 : : g_pData - > m_aSprites [ client_data7 : : SPRITE_NINJA_BAR_FULL ] ) ;
m_GameSkin . m_SpriteNinjaBarEmpty = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & client_data7 : : g_pData - > m_aSprites [ client_data7 : : SPRITE_NINJA_BAR_EMPTY ] ) ;
m_GameSkin . m_SpriteNinjaBarEmptyRight = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & client_data7 : : g_pData - > m_aSprites [ client_data7 : : SPRITE_NINJA_BAR_EMPTY_RIGHT ] ) ;
}
m_GameSkinLoaded = true ;
2020-11-25 12:05:53 +00:00
Graphics ( ) - > FreePNG ( & ImgInfo ) ;
2020-09-26 07:37:35 +00:00
}
}
void CGameClient : : LoadEmoticonsSkin ( const char * pPath , bool AsDir )
{
2020-10-09 07:07:05 +00:00
if ( m_EmoticonsSkinLoaded )
2020-09-26 07:37:35 +00:00
{
2020-10-26 14:14:07 +00:00
for ( auto & SpriteEmoticon : m_EmoticonsSkin . m_SpriteEmoticons )
2021-09-15 11:19:54 +00:00
Graphics ( ) - > UnloadTexture ( & SpriteEmoticon ) ;
2020-10-09 07:07:05 +00:00
m_EmoticonsSkinLoaded = false ;
2020-09-26 07:37:35 +00:00
}
2021-09-13 08:06:34 +00:00
char aPath [ IO_MAX_PATH_LENGTH ] ;
2020-09-26 07:37:35 +00:00
bool IsDefault = false ;
if ( str_comp ( pPath , " default " ) = = 0 )
{
str_format ( aPath , sizeof ( aPath ) , " %s " , g_pData - > m_aImages [ IMAGE_EMOTICONS ] . m_pFilename ) ;
IsDefault = true ;
}
else
{
if ( AsDir )
str_format ( aPath , sizeof ( aPath ) , " assets/emoticons/%s/%s " , pPath , g_pData - > m_aImages [ IMAGE_EMOTICONS ] . m_pFilename ) ;
else
str_format ( aPath , sizeof ( aPath ) , " assets/emoticons/%s.png " , pPath ) ;
}
CImageInfo ImgInfo ;
bool PngLoaded = Graphics ( ) - > LoadPNG ( & ImgInfo , aPath , IStorage : : TYPE_ALL ) ;
if ( ! PngLoaded & & ! IsDefault )
{
if ( AsDir )
LoadEmoticonsSkin ( " default " ) ;
else
LoadEmoticonsSkin ( pPath , true ) ;
}
2022-02-22 23:39:31 +00:00
else if ( PngLoaded & & Graphics ( ) - > CheckImageDivisibility ( aPath , ImgInfo , g_pData - > m_aSprites [ SPRITE_OOP ] . m_pSet - > m_Gridx , g_pData - > m_aSprites [ SPRITE_OOP ] . m_pSet - > m_Gridy , true ) & & Graphics ( ) - > IsImageFormatRGBA ( aPath , ImgInfo ) )
2020-09-26 07:37:35 +00:00
{
2020-10-09 07:07:05 +00:00
for ( int i = 0 ; i < 16 ; + + i )
m_EmoticonsSkin . m_SpriteEmoticons [ i ] = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_OOP + i ] ) ;
m_EmoticonsSkinLoaded = true ;
2020-11-25 12:05:53 +00:00
Graphics ( ) - > FreePNG ( & ImgInfo ) ;
2020-09-26 07:37:35 +00:00
}
}
void CGameClient : : LoadParticlesSkin ( const char * pPath , bool AsDir )
{
2020-10-09 07:07:05 +00:00
if ( m_ParticlesSkinLoaded )
2020-09-26 07:37:35 +00:00
{
2021-09-15 11:19:54 +00:00
Graphics ( ) - > UnloadTexture ( & m_ParticlesSkin . m_SpriteParticleSlice ) ;
Graphics ( ) - > UnloadTexture ( & m_ParticlesSkin . m_SpriteParticleBall ) ;
2020-10-26 14:14:07 +00:00
for ( auto & SpriteParticleSplat : m_ParticlesSkin . m_SpriteParticleSplat )
2021-09-15 11:19:54 +00:00
Graphics ( ) - > UnloadTexture ( & SpriteParticleSplat ) ;
Graphics ( ) - > UnloadTexture ( & m_ParticlesSkin . m_SpriteParticleSmoke ) ;
Graphics ( ) - > UnloadTexture ( & m_ParticlesSkin . m_SpriteParticleShell ) ;
Graphics ( ) - > UnloadTexture ( & m_ParticlesSkin . m_SpriteParticleExpl ) ;
Graphics ( ) - > UnloadTexture ( & m_ParticlesSkin . m_SpriteParticleAirJump ) ;
Graphics ( ) - > UnloadTexture ( & m_ParticlesSkin . m_SpriteParticleHit ) ;
2020-10-09 07:07:05 +00:00
2020-10-26 14:14:07 +00:00
for ( auto & SpriteParticle : m_ParticlesSkin . m_SpriteParticles )
SpriteParticle = IGraphics : : CTextureHandle ( ) ;
2020-10-09 07:07:05 +00:00
m_ParticlesSkinLoaded = false ;
2020-09-26 07:37:35 +00:00
}
2021-09-13 08:06:34 +00:00
char aPath [ IO_MAX_PATH_LENGTH ] ;
2020-09-26 07:37:35 +00:00
bool IsDefault = false ;
if ( str_comp ( pPath , " default " ) = = 0 )
{
str_format ( aPath , sizeof ( aPath ) , " %s " , g_pData - > m_aImages [ IMAGE_PARTICLES ] . m_pFilename ) ;
IsDefault = true ;
}
else
{
if ( AsDir )
str_format ( aPath , sizeof ( aPath ) , " assets/particles/%s/%s " , pPath , g_pData - > m_aImages [ IMAGE_PARTICLES ] . m_pFilename ) ;
else
str_format ( aPath , sizeof ( aPath ) , " assets/particles/%s.png " , pPath ) ;
}
CImageInfo ImgInfo ;
bool PngLoaded = Graphics ( ) - > LoadPNG ( & ImgInfo , aPath , IStorage : : TYPE_ALL ) ;
if ( ! PngLoaded & & ! IsDefault )
{
if ( AsDir )
LoadParticlesSkin ( " default " ) ;
else
LoadParticlesSkin ( pPath , true ) ;
}
2022-02-22 23:39:31 +00:00
else if ( PngLoaded & & Graphics ( ) - > CheckImageDivisibility ( aPath , ImgInfo , g_pData - > m_aSprites [ SPRITE_PART_SLICE ] . m_pSet - > m_Gridx , g_pData - > m_aSprites [ SPRITE_PART_SLICE ] . m_pSet - > m_Gridy , true ) & & Graphics ( ) - > IsImageFormatRGBA ( aPath , ImgInfo ) )
2020-09-26 07:37:35 +00:00
{
2020-10-09 07:07:05 +00:00
m_ParticlesSkin . m_SpriteParticleSlice = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_PART_SLICE ] ) ;
m_ParticlesSkin . m_SpriteParticleBall = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_PART_BALL ] ) ;
for ( int i = 0 ; i < 3 ; + + i )
m_ParticlesSkin . m_SpriteParticleSplat [ i ] = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_PART_SPLAT01 + i ] ) ;
m_ParticlesSkin . m_SpriteParticleSmoke = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_PART_SMOKE ] ) ;
m_ParticlesSkin . m_SpriteParticleShell = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_PART_SHELL ] ) ;
m_ParticlesSkin . m_SpriteParticleExpl = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_PART_EXPL01 ] ) ;
m_ParticlesSkin . m_SpriteParticleAirJump = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_PART_AIRJUMP ] ) ;
m_ParticlesSkin . m_SpriteParticleHit = Graphics ( ) - > LoadSpriteTexture ( ImgInfo , & g_pData - > m_aSprites [ SPRITE_PART_HIT01 ] ) ;
m_ParticlesSkin . m_SpriteParticles [ 0 ] = m_ParticlesSkin . m_SpriteParticleSlice ;
m_ParticlesSkin . m_SpriteParticles [ 1 ] = m_ParticlesSkin . m_SpriteParticleBall ;
for ( int i = 0 ; i < 3 ; + + i )
m_ParticlesSkin . m_SpriteParticles [ 2 + i ] = m_ParticlesSkin . m_SpriteParticleSplat [ i ] ;
m_ParticlesSkin . m_SpriteParticles [ 5 ] = m_ParticlesSkin . m_SpriteParticleSmoke ;
m_ParticlesSkin . m_SpriteParticles [ 6 ] = m_ParticlesSkin . m_SpriteParticleShell ;
m_ParticlesSkin . m_SpriteParticles [ 7 ] = m_ParticlesSkin . m_SpriteParticleExpl ;
m_ParticlesSkin . m_SpriteParticles [ 8 ] = m_ParticlesSkin . m_SpriteParticleAirJump ;
m_ParticlesSkin . m_SpriteParticles [ 9 ] = m_ParticlesSkin . m_SpriteParticleHit ;
m_ParticlesSkinLoaded = true ;
2020-09-30 21:42:00 +00:00
free ( ImgInfo . m_pData ) ;
2020-09-26 07:37:35 +00:00
}
}
2020-10-09 07:07:05 +00:00
void CGameClient : : RefindSkins ( )
{
2020-10-26 14:14:07 +00:00
for ( auto & Client : m_aClients )
2020-10-09 07:07:05 +00:00
{
2020-11-08 05:39:16 +00:00
Client . m_SkinInfo . m_OriginalRenderSkin . Reset ( ) ;
Client . m_SkinInfo . m_ColorableRenderSkin . Reset ( ) ;
2020-10-26 14:14:07 +00:00
if ( Client . m_aSkinName [ 0 ] ! = ' \0 ' )
2020-10-09 07:07:05 +00:00
{
2021-07-12 09:43:56 +00:00
const CSkin * pSkin = m_Skins . Get ( m_Skins . Find ( Client . m_aSkinName ) ) ;
2020-10-26 14:14:07 +00:00
Client . m_SkinInfo . m_OriginalRenderSkin = pSkin - > m_OriginalSkin ;
Client . m_SkinInfo . m_ColorableRenderSkin = pSkin - > m_ColorableSkin ;
2021-07-12 10:04:45 +00:00
Client . UpdateRenderInfo ( IsTeamPlay ( ) ) ;
2020-10-09 07:07:05 +00:00
}
}
2021-07-12 09:43:56 +00:00
m_Ghost . RefindSkin ( ) ;
m_Chat . RefindSkins ( ) ;
2021-07-12 09:29:59 +00:00
m_KillMessages . RefindSkins ( ) ;
2020-10-09 07:07:05 +00:00
}
2019-09-08 22:53:07 +00:00
void CGameClient : : LoadMapSettings ( )
{
// Reset Tunezones
CTuningParams TuningParams ;
for ( int i = 0 ; i < NUM_TUNEZONES ; i + + )
{
TuningList ( ) [ i ] = TuningParams ;
2022-04-08 13:05:37 +00:00
TuningList ( ) [ i ] . Set ( " gun_curvature " , 0 ) ;
TuningList ( ) [ i ] . Set ( " gun_speed " , 1400 ) ;
TuningList ( ) [ i ] . Set ( " shotgun_curvature " , 0 ) ;
TuningList ( ) [ i ] . Set ( " shotgun_speed " , 500 ) ;
TuningList ( ) [ i ] . Set ( " shotgun_speeddiff " , 0 ) ;
2019-09-08 22:53:07 +00:00
}
// Load map tunings
IMap * pMap = Kernel ( ) - > RequestInterface < IMap > ( ) ;
int Start , Num ;
pMap - > GetType ( MAPITEMTYPE_INFO , & Start , & Num ) ;
for ( int i = Start ; i < Start + Num ; i + + )
{
int ItemID ;
CMapItemInfoSettings * pItem = ( CMapItemInfoSettings * ) pMap - > GetItem ( i , 0 , & ItemID ) ;
int ItemSize = pMap - > GetItemSize ( i ) ;
if ( ! pItem | | ItemID ! = 0 )
continue ;
if ( ItemSize < ( int ) sizeof ( CMapItemInfoSettings ) )
break ;
if ( ! ( pItem - > m_Settings > - 1 ) )
break ;
int Size = pMap - > GetDataSize ( pItem - > m_Settings ) ;
char * pSettings = ( char * ) pMap - > GetData ( pItem - > m_Settings ) ;
char * pNext = pSettings ;
2020-10-26 08:57:41 +00:00
dbg_msg ( " tune " , " %s " , pNext ) ;
2019-09-08 22:53:07 +00:00
while ( pNext < pSettings + Size )
{
int StrSize = str_length ( pNext ) + 1 ;
Console ( ) - > ExecuteLine ( pNext , IConsole : : CLIENT_ID_GAME ) ;
pNext + = StrSize ;
}
pMap - > UnloadData ( pItem - > m_Settings ) ;
break ;
}
}
void CGameClient : : ConTuneZone ( IConsole : : IResult * pResult , void * pUserData )
{
CGameClient * pSelf = ( CGameClient * ) pUserData ;
int List = pResult - > GetInteger ( 0 ) ;
const char * pParamName = pResult - > GetString ( 1 ) ;
float NewValue = pResult - > GetFloat ( 2 ) ;
if ( List > = 0 & & List < NUM_TUNEZONES )
pSelf - > TuningList ( ) [ List ] . Set ( pParamName , NewValue ) ;
}
2020-09-18 16:45:42 +00:00
void CGameClient : : ConchainMenuMap ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
CGameClient * pSelf = ( CGameClient * ) pUserData ;
if ( pResult - > NumArguments ( ) )
{
if ( str_comp ( g_Config . m_ClMenuMap , pResult - > GetString ( 0 ) ) ! = 0 )
{
str_format ( g_Config . m_ClMenuMap , sizeof ( g_Config . m_ClMenuMap ) , " %s " , pResult - > GetString ( 0 ) ) ;
2021-07-12 09:43:56 +00:00
pSelf - > m_MenuBackground . LoadMenuBackground ( ) ;
2020-09-18 16:45:42 +00:00
}
}
else
pfnCallback ( pResult , pCallbackUserData ) ;
}
2020-10-02 13:43:52 +00:00
2021-03-17 15:09:39 +00:00
void CGameClient : : DummyResetInput ( )
{
if ( ! Client ( ) - > DummyConnected ( ) )
return ;
if ( ( m_DummyInput . m_Fire & 1 ) ! = 0 )
m_DummyInput . m_Fire + + ;
2021-07-12 09:43:56 +00:00
m_Controls . ResetInput ( ! g_Config . m_ClDummy ) ;
m_Controls . m_InputData [ ! g_Config . m_ClDummy ] . m_Hook = 0 ;
m_Controls . m_InputData [ ! g_Config . m_ClDummy ] . m_Fire = m_DummyInput . m_Fire ;
2021-03-17 15:09:39 +00:00
2021-07-12 09:43:56 +00:00
m_DummyInput = m_Controls . m_InputData [ ! g_Config . m_ClDummy ] ;
2021-03-17 15:09:39 +00:00
}
2020-10-02 13:43:52 +00:00
bool CGameClient : : CanDisplayWarning ( )
{
2021-07-12 09:43:56 +00:00
return m_Menus . CanDisplayWarning ( ) ;
2020-10-02 13:43:52 +00:00
}
2020-10-04 20:46:28 +00:00
bool CGameClient : : IsDisplayingWarning ( )
{
2021-07-12 09:43:56 +00:00
return m_Menus . GetCurPopup ( ) = = CMenus : : POPUP_WARNING ;
2020-10-04 20:46:28 +00:00
}
2021-10-21 01:18:54 +00:00
void CGameClient : : SnapCollectEntities ( )
{
int NumSnapItems = Client ( ) - > SnapNumItems ( IClient : : SNAP_CURRENT ) ;
std : : vector < CSnapEntities > aItemData ;
2021-11-07 10:00:48 +00:00
std : : vector < CSnapEntities > aItemEx ;
2021-10-21 01:18:54 +00:00
for ( int Index = 0 ; Index < NumSnapItems ; Index + + )
{
IClient : : CSnapItem Item ;
const void * pData = Client ( ) - > SnapGetItem ( IClient : : SNAP_CURRENT , Index , & Item ) ;
2021-11-07 10:00:48 +00:00
if ( Item . m_Type = = NETOBJTYPE_ENTITYEX )
aItemEx . push_back ( { Item , pData , 0 } ) ;
else if ( Item . m_Type = = NETOBJTYPE_PICKUP | | Item . m_Type = = NETOBJTYPE_LASER | | Item . m_Type = = NETOBJTYPE_PROJECTILE | | Item . m_Type = = NETOBJTYPE_DDNETPROJECTILE )
2021-10-21 01:18:54 +00:00
aItemData . push_back ( { Item , pData , 0 } ) ;
}
2021-11-07 10:00:48 +00:00
// sort by id
class CEntComparer
{
public :
bool operator ( ) ( const CSnapEntities & lhs , const CSnapEntities & rhs ) const
{
return lhs . m_Item . m_ID < rhs . m_Item . m_ID ;
}
} ;
std : : sort ( aItemData . begin ( ) , aItemData . end ( ) , CEntComparer ( ) ) ;
std : : sort ( aItemEx . begin ( ) , aItemEx . end ( ) , CEntComparer ( ) ) ;
2021-10-21 01:18:54 +00:00
// merge extended items with items they belong to
m_aSnapEntities . clear ( ) ;
2021-11-07 10:00:48 +00:00
size_t IndexEx = 0 ;
for ( const CSnapEntities & Ent : aItemData )
{
2021-10-21 01:18:54 +00:00
const CNetObj_EntityEx * pDataEx = 0 ;
2021-11-07 10:00:48 +00:00
while ( IndexEx < aItemEx . size ( ) & & aItemEx [ IndexEx ] . m_Item . m_ID < Ent . m_Item . m_ID )
IndexEx + + ;
if ( IndexEx < aItemEx . size ( ) & & aItemEx [ IndexEx ] . m_Item . m_ID = = Ent . m_Item . m_ID )
pDataEx = ( const CNetObj_EntityEx * ) aItemEx [ IndexEx ] . m_pData ;
2021-10-21 01:18:54 +00:00
2021-11-07 10:00:48 +00:00
m_aSnapEntities . push_back ( { Ent . m_Item , Ent . m_pData , pDataEx } ) ;
2021-10-21 01:18:54 +00:00
}
}