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>
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-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"
2017-06-06 05:31:56 +00:00
# include <game/extrainfo.h>
2010-05-29 07:25:38 +00:00
# include <game/localization.h>
# include <game/version.h>
# 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 g_GameClient ;
2008-08-27 15:48:50 +00:00
2018-07-10 09:29:02 +00:00
// instantiate all systems
2010-05-29 07:25:38 +00:00
static CKillMessages gs_KillMessages ;
static CCamera gs_Camera ;
static CChat gs_Chat ;
static CMotd gs_Motd ;
static CBroadcast gs_Broadcast ;
static CGameConsole gs_GameConsole ;
static CBinds gs_Binds ;
static CParticles gs_Particles ;
static CMenus gs_Menus ;
static CSkins gs_Skins ;
2011-03-16 11:09:22 +00:00
static CCountryFlags gs_CountryFlags ;
2010-05-29 07:25:38 +00:00
static CFlow gs_Flow ;
static CHud gs_Hud ;
static CDebugHud gs_DebugHud ;
static CControls gs_Controls ;
static CEffects gs_Effects ;
static CScoreboard gs_Scoreboard ;
2015-05-21 09:41:59 +00:00
static CStatboard gs_Statboard ;
2010-05-29 07:25:38 +00:00
static CSounds gs_Sounds ;
static CEmoticon gs_Emoticon ;
static CDamageInd gsDamageInd ;
static CVoting gs_Voting ;
2011-03-10 09:08:14 +00:00
static CSpectator gs_Spectator ;
2010-05-29 07:25:38 +00:00
static CPlayers gs_Players ;
2013-10-09 14:23:18 +00:00
static CNamePlates gs_NamePlates ;
2010-05-29 07:25:38 +00:00
static CItems gs_Items ;
static CMapImages gs_MapImages ;
static CMapLayers gs_MapLayersBackGround ( CMapLayers : : TYPE_BACKGROUND ) ;
static CMapLayers gs_MapLayersForeGround ( CMapLayers : : TYPE_FOREGROUND ) ;
2015-08-25 00:11:04 +00:00
static CBackground gs_BackGround ;
2020-09-18 16:45:42 +00:00
static CMenuBackground gs_MenuBackground ;
2010-05-29 07:25:38 +00:00
2014-10-10 17:10:57 +00:00
static CMapSounds gs_MapSounds ;
2011-04-09 06:41:31 +00:00
static CRaceDemo gs_RaceDemo ;
static CGhost gs_Ghost ;
2010-05-29 07:25:38 +00:00
CGameClient : : CStack : : CStack ( ) { m_Num = 0 ; }
void CGameClient : : CStack : : Add ( class CComponent * pComponent ) { m_paComponents [ m_Num + + ] = pComponent ; }
const char * CGameClient : : Version ( ) { return GAME_VERSION ; }
const char * CGameClient : : NetVersion ( ) { return GAME_NETVERSION ; }
2020-05-22 15:58:41 +00:00
int CGameClient : : DDNetVersion ( ) { return CLIENT_VERSIONNR ; }
const char * CGameClient : : DDNetVersionStr ( ) { return m_aDDNetVersionStr ; }
2010-05-29 07:25:38 +00:00
const char * CGameClient : : GetItemName ( int Type ) { return m_NetObjHandler . GetObjName ( Type ) ; }
2009-06-15 06:45:44 +00:00
2010-05-29 07:25:38 +00:00
void CGameClient : : OnConsoleInit ( )
{
2011-02-27 16:56:03 +00:00
m_pEngine = Kernel ( ) - > RequestInterface < IEngine > ( ) ;
2010-05-29 07:25:38 +00:00
m_pClient = Kernel ( ) - > RequestInterface < IClient > ( ) ;
m_pTextRender = Kernel ( ) - > RequestInterface < ITextRender > ( ) ;
m_pSound = Kernel ( ) - > RequestInterface < ISound > ( ) ;
m_pInput = Kernel ( ) - > RequestInterface < IInput > ( ) ;
m_pConsole = Kernel ( ) - > RequestInterface < IConsole > ( ) ;
m_pStorage = Kernel ( ) - > RequestInterface < IStorage > ( ) ;
m_pDemoPlayer = Kernel ( ) - > RequestInterface < IDemoPlayer > ( ) ;
m_pServerBrowser = Kernel ( ) - > RequestInterface < IServerBrowser > ( ) ;
2011-03-21 23:31:42 +00:00
m_pEditor = Kernel ( ) - > RequestInterface < IEditor > ( ) ;
2011-03-23 12:06:35 +00:00
m_pFriends = Kernel ( ) - > RequestInterface < IFriends > ( ) ;
2015-07-22 20:16:49 +00:00
m_pFoes = Client ( ) - > Foes ( ) ;
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
2008-08-27 15:48:50 +00:00
// setup pointers
2020-09-18 16:45:42 +00:00
m_pMenuBackground = & : : gs_MenuBackground ;
2010-05-29 07:25:38 +00:00
m_pBinds = & : : gs_Binds ;
m_pGameConsole = & : : gs_GameConsole ;
m_pParticles = & : : gs_Particles ;
m_pMenus = & : : gs_Menus ;
m_pSkins = & : : gs_Skins ;
2011-03-16 11:09:22 +00:00
m_pCountryFlags = & : : gs_CountryFlags ;
2010-05-29 07:25:38 +00:00
m_pChat = & : : gs_Chat ;
m_pFlow = & : : gs_Flow ;
m_pCamera = & : : gs_Camera ;
m_pControls = & : : gs_Controls ;
m_pEffects = & : : gs_Effects ;
m_pSounds = & : : gs_Sounds ;
m_pMotd = & : : gs_Motd ;
m_pDamageind = & : : gsDamageInd ;
m_pMapimages = & : : gs_MapImages ;
m_pVoting = & : : gs_Voting ;
2010-08-18 01:57:35 +00:00
m_pScoreboard = & : : gs_Scoreboard ;
2015-05-21 09:41:59 +00:00
m_pStatboard = & : : gs_Statboard ;
2011-04-03 08:11:23 +00:00
m_pItems = & : : gs_Items ;
2011-12-04 13:04:12 +00:00
m_pMapLayersBackGround = & : : gs_MapLayersBackGround ;
m_pMapLayersForeGround = & : : gs_MapLayersForeGround ;
2015-08-25 00:11:04 +00:00
m_pBackGround = & : : gs_BackGround ;
2011-04-13 18:37:12 +00:00
2014-10-10 17:10:57 +00:00
m_pMapSounds = & : : gs_MapSounds ;
2017-09-09 22:57:32 +00:00
m_pPlayers = & : : gs_Players ;
2014-10-10 17:10:57 +00:00
2011-02-04 17:25:04 +00:00
m_pRaceDemo = & : : gs_RaceDemo ;
m_pGhost = & : : gs_Ghost ;
2011-04-09 06:41:31 +00:00
2020-09-18 16:45:42 +00:00
m_pMenus - > SetMenuBackground ( m_pMenuBackground ) ;
2018-03-13 20:55:47 +00:00
gs_NamePlates . SetPlayers ( m_pPlayers ) ;
2015-05-19 22:51:02 +00:00
// make a list of all the systems, make sure to add them in the correct render order
2010-05-29 07:25:38 +00:00
m_All . Add ( m_pSkins ) ;
2011-03-16 11:09:22 +00:00
m_All . Add ( m_pCountryFlags ) ;
2010-05-29 07:25:38 +00:00
m_All . Add ( m_pMapimages ) ;
m_All . Add ( m_pEffects ) ; // doesn't render anything, just updates effects
m_All . Add ( m_pParticles ) ;
m_All . Add ( m_pBinds ) ;
2019-04-28 17:34:34 +00:00
m_All . Add ( & m_pBinds - > m_SpecialBinds ) ;
2010-05-29 07:25:38 +00:00
m_All . Add ( m_pControls ) ;
m_All . Add ( m_pCamera ) ;
m_All . Add ( m_pSounds ) ;
m_All . Add ( m_pVoting ) ;
m_All . Add ( m_pParticles ) ; // doesn't render anything, just updates all the particles
2011-02-04 17:25:04 +00:00
m_All . Add ( m_pRaceDemo ) ;
2014-10-10 17:10:57 +00:00
m_All . Add ( m_pMapSounds ) ;
2011-04-13 18:37:12 +00:00
2020-09-26 19:41:58 +00:00
m_All . Add ( & gs_BackGround ) ; //render instead of gs_MapLayersBackGround when g_Config.m_ClOverlayEntities == 100
2010-05-29 07:25:38 +00:00
m_All . Add ( & gs_MapLayersBackGround ) ; // first to render
m_All . Add ( & m_pParticles - > m_RenderTrail ) ;
2011-04-03 08:11:23 +00:00
m_All . Add ( m_pItems ) ;
2017-09-09 22:57:32 +00:00
m_All . Add ( m_pPlayers ) ;
2011-02-04 17:25:04 +00:00
m_All . Add ( m_pGhost ) ;
2010-05-29 07:25:38 +00:00
m_All . Add ( & gs_MapLayersForeGround ) ;
2010-10-11 10:32:34 +00:00
m_All . Add ( & m_pParticles - > m_RenderExplosions ) ;
2013-10-09 14:23:18 +00:00
m_All . Add ( & gs_NamePlates ) ;
2010-05-29 07:25:38 +00:00
m_All . Add ( & m_pParticles - > m_RenderGeneral ) ;
m_All . Add ( m_pDamageind ) ;
m_All . Add ( & gs_Hud ) ;
2011-03-10 09:08:14 +00:00
m_All . Add ( & gs_Spectator ) ;
2010-05-29 07:25:38 +00:00
m_All . Add ( & gs_Emoticon ) ;
m_All . Add ( & gs_KillMessages ) ;
m_All . Add ( m_pChat ) ;
m_All . Add ( & gs_Broadcast ) ;
m_All . Add ( & gs_DebugHud ) ;
m_All . Add ( & gs_Scoreboard ) ;
2015-05-21 09:41:59 +00:00
m_All . Add ( & gs_Statboard ) ;
2010-05-29 07:25:38 +00:00
m_All . Add ( m_pMotd ) ;
m_All . Add ( m_pMenus ) ;
2019-04-28 17:22:19 +00:00
m_All . Add ( & m_pMenus - > m_Binder ) ;
2010-05-29 07:25:38 +00:00
m_All . Add ( m_pGameConsole ) ;
2011-04-13 18:37:12 +00:00
2020-09-18 16:45:42 +00:00
m_All . Add ( m_pMenuBackground ) ;
2008-08-27 15:48:50 +00:00
// build the input stack
2010-05-29 07:25:38 +00:00
m_Input . Add ( & m_pMenus - > m_Binder ) ; // this will take over all input when we want to bind a key
m_Input . Add ( & m_pBinds - > m_SpecialBinds ) ;
m_Input . Add ( m_pGameConsole ) ;
m_Input . Add ( m_pChat ) ; // chat has higher prio due to tha you can quit it by pressing esc
m_Input . Add ( m_pMotd ) ; // for pressing esc to remove it
m_Input . Add ( m_pMenus ) ;
2011-03-10 09:08:14 +00:00
m_Input . Add ( & gs_Spectator ) ;
2010-05-29 07:25:38 +00:00
m_Input . Add ( & gs_Emoticon ) ;
m_Input . Add ( m_pControls ) ;
m_Input . Add ( m_pBinds ) ;
2011-04-13 18:37:12 +00:00
2008-09-04 21:36:44 +00:00
// add the some console commands
2015-12-28 15:14:52 +00:00
Console ( ) - > Register ( " team " , " i[team-id] " , CFGFLAG_CLIENT , ConTeam , this , " Switch team " ) ;
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 " ) ;
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
m_UI . SetGraphics ( Graphics ( ) , TextRender ( ) ) ;
m_RenderTools . m_pGraphics = Graphics ( ) ;
m_RenderTools . m_pUI = UI ( ) ;
2014-12-01 00:31:58 +00:00
2011-02-13 12:58:59 +00:00
int64 Start = time_get ( ) ;
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
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 )
2011-02-27 16:56:03 +00:00
m_All . m_paComponents [ i ] - > OnInit ( ) ;
2014-04-27 22:41:19 +00:00
char aBuf [ 256 ] ;
2011-02-27 16:56:03 +00:00
// setup load amount// load textures
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < g_pData - > m_NumImages ; i + + )
2008-08-30 22:38:56 +00:00
{
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 ) ;
2011-02-27 16:56:03 +00:00
g_GameClient . m_pMenus - > RenderLoading ( ) ;
2010-05-29 07:25:38 +00:00
}
2008-10-08 18:19:45 +00:00
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < m_All . m_Num ; i + + )
m_All . m_paComponents [ i ] - > OnReset ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
m_ServerMode = SERVERMODE_PURE ;
2011-01-06 03:46:10 +00:00
2014-04-27 11:44:04 +00:00
m_DDRaceMsgSent [ 0 ] = false ;
m_DDRaceMsgSent [ 1 ] = false ;
m_ShowOthers [ 0 ] = - 1 ;
m_ShowOthers [ 1 ] = - 1 ;
2011-04-17 17:14:49 +00:00
// Set free binds to DDRace binds if it's active
2020-09-05 21:15:14 +00:00
gs_Binds . SetDDRaceBinds ( true ) ;
2014-08-09 17:17:21 +00:00
2014-08-10 10:54:01 +00:00
if ( g_Config . m_ClTimeoutCode [ 0 ] = = ' \0 ' | | str_comp ( g_Config . m_ClTimeoutCode , " hGuEYnfxicsXGwFq " ) = = 0 )
2014-08-09 17:17:21 +00:00
{
for ( unsigned int i = 0 ; i < 16 ; i + + )
{
2018-03-13 20:55:47 +00:00
if ( rand ( ) % 2 )
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
int64 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
m_pMapimages - > 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 ) ;
2008-08-27 15:48:50 +00:00
}
2016-04-29 21:05:20 +00:00
void CGameClient : : OnUpdate ( )
2008-08-27 15:48:50 +00:00
{
// handle mouse movement
2010-10-13 10:47:42 +00:00
float x = 0.0f , y = 0.0f ;
2010-05-29 07:25:38 +00:00
Input ( ) - > MouseRelative ( & x , & y ) ;
2010-10-13 10:47:42 +00:00
if ( x ! = 0.0f | | y ! = 0.0f )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
for ( int h = 0 ; h < m_Input . m_Num ; h + + )
2008-09-12 07:20:26 +00:00
{
2010-05-29 07:25:38 +00:00
if ( m_Input . m_paComponents [ h ] - > OnMouseMove ( x , y ) )
2008-09-12 07:20:26 +00:00
break ;
}
2008-08-27 15:48:50 +00:00
}
2011-04-13 18:37:12 +00:00
2008-08-27 15:48:50 +00:00
// handle key presses
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < Input ( ) - > NumEvents ( ) ; i + + )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
IInput : : CEvent e = Input ( ) - > GetEvent ( i ) ;
2016-04-30 18:11:26 +00:00
if ( ! Input ( ) - > IsEventValid ( & e ) )
continue ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
for ( int h = 0 ; h < m_Input . m_Num ; h + + )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
if ( m_Input . m_paComponents [ h ] - > OnInput ( e ) )
2008-08-27 15:48:50 +00:00
break ;
}
}
}
2017-02-28 09:08:14 +00:00
void CGameClient : : OnDummySwap ( )
{
2018-03-13 20:55:47 +00:00
if ( g_Config . m_ClDummyResetOnSwitch )
2017-02-28 09:08:14 +00:00
{
2019-10-25 01:03:00 +00:00
int PlayerOrDummy = ( g_Config . m_ClDummyResetOnSwitch = = 2 ) ? g_Config . m_ClDummy : ( ! g_Config . m_ClDummy ) ;
m_pControls - > ResetInput ( PlayerOrDummy ) ;
m_pControls - > 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 ;
2017-02-28 09:08:14 +00:00
m_DummyInput = m_pControls - > m_InputData [ ! g_Config . m_ClDummy ] ;
2018-06-04 09:06:54 +00:00
m_pControls - > m_InputData [ g_Config . m_ClDummy ] . m_Fire = tmp ;
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
{
return m_pControls - > SnapInput ( pData ) ;
}
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
{
2019-07-08 21:08:42 +00:00
if ( ( m_DummyFire / 12.5f ) - ( int ) ( m_DummyFire / 12.5f ) > 0.01f )
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
vec2 Main = m_LocalCharacterPos ;
vec2 Dummy = m_aClients [ m_LocalIDs [ ! g_Config . m_ClDummy ] ] . m_Predicted . m_Pos ;
vec2 Dir = Main - Dummy ;
2018-10-02 18:52:21 +00:00
m_HammerInput . m_TargetX = ( int ) ( Dir . x ) ;
m_HammerInput . m_TargetY = ( int ) ( Dir . y ) ;
2017-02-28 09:08:14 +00:00
mem_copy ( pData , & m_HammerInput , sizeof ( m_HammerInput ) ) ;
return sizeof ( m_HammerInput ) ;
}
2008-08-27 15:48:50 +00:00
}
2010-05-29 07:25:38 +00:00
void CGameClient : : OnConnected ( )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
m_Layers . Init ( Kernel ( ) ) ;
m_Collision . Init ( Layers ( ) ) ;
2011-04-13 18:37:12 +00:00
2013-12-20 11:27:10 +00:00
RenderTools ( ) - > RenderTilemapGenerateSkip ( Layers ( ) ) ;
2008-10-06 18:05:01 +00:00
2017-09-09 18:54:49 +00:00
CRaceHelper : : ms_aFlagIndex [ 0 ] = - 1 ;
CRaceHelper : : ms_aFlagIndex [ 1 ] = - 1 ;
CTile * pGameTiles = static_cast < CTile * > ( Layers ( ) - > Map ( ) - > GetData ( Layers ( ) - > GameLayer ( ) - > m_Data ) ) ;
// get flag positions
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 ;
2020-04-18 20:16:25 +00:00
m_PredictedDummyID = - 1 ;
2019-04-11 22:46:54 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
m_aLastWorldCharacters [ i ] . 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
InvalidateSnapshot ( ) ;
2008-08-27 15:48:50 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2011-03-22 21:41:27 +00:00
m_aClients [ i ] . Reset ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < m_All . m_Num ; i + + )
m_All . m_paComponents [ i ] - > OnReset ( ) ;
2011-01-06 03:46:10 +00:00
2015-07-26 16:21:51 +00:00
m_DemoSpecID = SPEC_FOLLOW ;
2011-07-05 21:15:24 +00:00
m_FlagDropTick [ TEAM_RED ] = 0 ;
m_FlagDropTick [ TEAM_BLUE ] = 0 ;
2015-05-20 20:23:58 +00:00
m_LastRoundStartTick = - 1 ;
m_LastFlagCarrierRed = - 4 ;
m_LastFlagCarrierBlue = - 4 ;
2014-04-30 14:02:28 +00:00
m_Tuning [ g_Config . m_ClDummy ] = CTuningParams ( ) ;
2011-08-13 00:11:06 +00:00
m_Teams . Reset ( ) ;
2014-04-27 11:44:04 +00:00
m_DDRaceMsgSent [ 0 ] = false ;
m_DDRaceMsgSent [ 1 ] = false ;
m_ShowOthers [ 0 ] = - 1 ;
m_ShowOthers [ 1 ] = - 1 ;
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
static void Evolve ( CNetObj_Character * pCharacter , int Tick )
2008-10-06 18:05:01 +00:00
{
2010-05-29 07:25:38 +00:00
CWorldCore TempWorld ;
CCharacterCore TempCore ;
2010-09-30 20:31:11 +00:00
CTeamsCore TempTeams ;
2010-05-29 07:25:38 +00:00
mem_zero ( & TempCore , sizeof ( TempCore ) ) ;
2011-01-06 03:46:10 +00:00
mem_zero ( & TempTeams , sizeof ( TempTeams ) ) ;
2010-09-30 20:31:11 +00:00
TempCore . Init ( & TempWorld , g_GameClient . Collision ( ) , & TempTeams ) ;
2010-05-29 07:25:38 +00:00
TempCore . Read ( pCharacter ) ;
2014-04-14 08:56:14 +00:00
TempCore . m_ActiveWeapon = pCharacter - > m_Weapon ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
while ( pCharacter - > m_Tick < Tick )
2008-10-06 18:05:01 +00:00
{
2010-05-29 07:25:38 +00:00
pCharacter - > m_Tick + + ;
2019-04-11 22:46:54 +00:00
TempCore . Tick ( false ) ;
2018-08-22 06:33:21 +00:00
TempCore . Move ( ) ;
2010-05-29 07:25:38 +00:00
TempCore . Quantize ( ) ;
2008-10-06 18:05:01 +00:00
}
2008-11-16 15:10:57 +00:00
2010-05-29 07:25:38 +00:00
TempCore . Write ( pCharacter ) ;
2008-10-06 18:05:01 +00:00
}
2010-05-29 07:25:38 +00:00
void CGameClient : : OnRender ( )
2008-08-27 15:48:50 +00:00
{
2011-03-10 09:08:14 +00:00
// update the local character and spectate position
UpdatePositions ( ) ;
2011-04-13 18:37:12 +00:00
2020-08-29 10:49:45 +00:00
// display gfx warnings
if ( g_Config . m_GfxShowWarnings = = 1 )
{
2020-10-02 13:43:52 +00:00
SWarning * pWarning = Graphics ( ) - > GetCurWarning ( ) ;
2020-08-29 10:49:45 +00:00
if ( pWarning ! = NULL )
{
if ( m_pMenus - > CanDisplayWarning ( ) )
{
2020-09-11 07:59:05 +00:00
m_pMenus - > PopupWarning ( Localize ( " Warning " ) , pWarning - > m_aWarningMsg , " Ok " , 10000000 ) ;
2020-08-29 10:49:45 +00:00
pWarning - > m_WasShown = true ;
}
}
}
2020-10-02 13:43:52 +00:00
// display client warnings
SWarning * pWarning = Client ( ) - > GetCurWarning ( ) ;
if ( pWarning ! = NULL )
{
if ( m_pMenus - > CanDisplayWarning ( ) )
{
m_pMenus - > PopupWarning ( Localize ( " Warning " ) , pWarning - > m_aWarningMsg , " Ok " , 10000000 ) ;
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
2020-09-26 19:41:58 +00:00
if ( Client ( ) - > State ( ) = = IClient : : STATE_ONLINE & & ! m_pMenus - > IsActive ( ) )
{
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 ;
m_ShowOthers [ 1 ] = - 1 ;
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 ( )
{
return m_pGhost - > GetLastRaceTick ( ) ;
}
2010-09-12 10:43:03 +00:00
void CGameClient : : OnRelease ( )
{
// release all systems
for ( int i = 0 ; i < m_All . m_Num ; i + + )
m_All . m_paComponents [ i ] - > OnRelease ( ) ;
}
2014-05-03 00:30:05 +00:00
void CGameClient : : OnMessage ( int MsgId , CUnpacker * pUnpacker , bool IsDummy )
2008-08-27 15:48:50 +00:00
{
2008-08-29 05:34:18 +00:00
// special messages
2014-05-03 00:30:05 +00:00
if ( MsgId = = NETMSGTYPE_SV_EXTRAPROJECTILE & & ! IsDummy )
2008-08-29 05:34:18 +00:00
{
2011-04-03 08:11:23 +00:00
int Num = pUnpacker - > GetInt ( ) ;
2011-04-13 18:37:12 +00:00
2011-04-03 08:11:23 +00:00
for ( int k = 0 ; k < Num ; k + + )
2008-08-29 05:34:18 +00:00
{
2011-04-03 08:11:23 +00:00
CNetObj_Projectile Proj ;
2020-09-26 19:41:58 +00:00
for ( unsigned i = 0 ; i < sizeof ( CNetObj_Projectile ) / sizeof ( int ) ; i + + )
2011-04-03 08:11:23 +00:00
( ( int * ) & Proj ) [ i ] = pUnpacker - > GetInt ( ) ;
2011-04-13 18:37:12 +00:00
2011-04-03 08:11:23 +00:00
if ( pUnpacker - > Error ( ) )
2008-08-29 05:34:18 +00:00
return ;
2011-04-13 18:37:12 +00:00
2011-04-03 08:11:23 +00:00
g_GameClient . m_pItems - > AddExtraProjectile ( & Proj ) ;
2008-08-29 05:34:18 +00:00
}
2011-04-13 18:37:12 +00:00
2011-04-03 08:11:23 +00:00
return ;
2008-08-29 05:34:18 +00:00
}
2010-05-29 07:25:38 +00:00
else if ( MsgId = = NETMSGTYPE_SV_TUNEPARAMS )
2008-08-29 05:34:18 +00:00
{
// unpack the new tuning
2010-05-29 07:25:38 +00:00
CTuningParams NewTuning ;
int * pParams = ( int * ) & NewTuning ;
2015-01-09 21:18:11 +00:00
// No jetpack on DDNet incompatible servers:
NewTuning . m_JetpackStrength = 0 ;
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
2008-08-29 05:34:18 +00:00
// apply new tuning
2014-05-03 00:30:05 +00:00
m_Tuning [ IsDummy ? ! g_Config . m_ClDummy : g_Config . m_ClDummy ] = NewTuning ;
2008-08-29 05:34:18 +00:00
return ;
}
2014-12-01 00:31:58 +00:00
2010-05-29 07:25:38 +00:00
void * pRawMsg = m_NetObjHandler . SecureUnpackMsg ( MsgId , pUnpacker ) ;
if ( ! pRawMsg )
2008-08-27 15:48:50 +00:00
{
2010-08-17 22:06:00 +00:00
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " dropped weird message '%s' (%d), failed on '%s' " , m_NetObjHandler . GetMsgName ( MsgId ) , MsgId , m_NetObjHandler . FailedMsgOn ( ) ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " client " , aBuf ) ;
2008-08-27 15:48:50 +00:00
return ;
}
2014-05-07 01:34:21 +00:00
if ( IsDummy )
{
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
{
m_pChat - > OnMessage ( MsgId , pRawMsg ) ;
}
}
return ; // no need of all that stuff for the dummy
}
2008-08-27 15:48:50 +00:00
// TODO: this should be done smarter
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < m_All . m_Num ; i + + )
m_All . m_paComponents [ i ] - > OnMessage ( MsgId , pRawMsg ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
if ( MsgId = = NETMSGTYPE_SV_READYTOENTER )
2008-08-27 20:17:04 +00:00
{
2010-05-29 07:25:38 +00:00
Client ( ) - > EnterGame ( ) ;
2008-08-27 20:17:04 +00:00
}
2018-03-13 20:55:47 +00:00
else if ( MsgId = = NETMSGTYPE_SV_EMOTICON )
2008-08-27 20:17:04 +00:00
{
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_Emoticon * pMsg = ( CNetMsg_Sv_Emoticon * ) pRawMsg ;
2008-08-27 20:17:04 +00:00
// apply
2011-02-12 10:40:36 +00:00
m_aClients [ pMsg - > m_ClientID ] . m_Emoticon = pMsg - > m_Emoticon ;
2020-02-19 10:24:58 +00:00
m_aClients [ pMsg - > m_ClientID ] . m_EmoticonStart = Client ( ) - > GameTick ( g_Config . m_ClDummy ) ;
2008-08-27 20:17:04 +00:00
}
2010-05-29 07:25:38 +00:00
else if ( MsgId = = NETMSGTYPE_SV_SOUNDGLOBAL )
2008-08-27 20:17:04 +00:00
{
2010-05-29 07:25:38 +00:00
if ( m_SuppressEvents )
2009-01-11 15:51:43 +00:00
return ;
2011-04-13 18:37:12 +00:00
2010-07-17 17:55:17 +00:00
// don't enqueue pseudo-global sounds from demos (created by PlayAndRecord)
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_SoundGlobal * pMsg = ( CNetMsg_Sv_SoundGlobal * ) pRawMsg ;
2011-02-12 10:40:36 +00:00
if ( pMsg - > m_SoundID = = SOUND_CTF_DROP | | pMsg - > m_SoundID = = SOUND_CTF_RETURN | |
pMsg - > m_SoundID = = SOUND_CTF_CAPTURE | | pMsg - > m_SoundID = = SOUND_CTF_GRAB_EN | |
pMsg - > m_SoundID = = SOUND_CTF_GRAB_PL )
2014-10-25 00:52:08 +00:00
{
if ( g_Config . m_SndGame )
g_GameClient . m_pSounds - > Enqueue ( CSounds : : CHN_GLOBAL , pMsg - > m_SoundID ) ;
}
2010-07-17 17:55:17 +00:00
else
2014-10-25 00:52:08 +00:00
{
if ( g_Config . m_SndGame )
g_GameClient . m_pSounds - > Play ( CSounds : : CHN_GLOBAL , pMsg - > m_SoundID , 1.0f ) ;
}
2011-04-13 18:37:12 +00:00
}
2014-01-21 23:08:30 +00:00
else if ( MsgId = = NETMSGTYPE_SV_TEAMSSTATE )
2011-01-06 05:30:19 +00:00
{
2014-01-21 23:08:30 +00:00
unsigned int i ;
for ( i = 0 ; i < MAX_CLIENTS ; i + + )
{
2014-02-08 22:41:12 +00:00
int Team = pUnpacker - > GetInt ( ) ;
bool WentWrong = false ;
2014-01-21 23:08:30 +00:00
if ( pUnpacker - > Error ( ) )
2014-02-08 22:41:12 +00:00
WentWrong = true ;
if ( ! WentWrong & & Team > = 0 & & Team < MAX_CLIENTS )
m_Teams . Team ( i , Team ) ;
2018-03-13 20:55:47 +00:00
else if ( Team ! = MAX_CLIENTS )
2014-02-08 22:41:12 +00:00
WentWrong = true ;
if ( WentWrong )
2014-01-21 23:08:30 +00:00
{
m_Teams . Team ( i , 0 ) ;
break ;
}
}
2018-03-13 20:55:47 +00:00
if ( i < = 16 )
2014-01-21 23:08:30 +00:00
m_Teams . m_IsDDRace16 = true ;
2017-09-09 19:38:41 +00:00
2017-09-12 20:54:29 +00:00
m_pGhost - > m_AllowRestart = true ;
m_pRaceDemo - > m_AllowRestart = true ;
2011-01-06 05:30:19 +00:00
}
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 ( )
{
2020-09-17 22:30:29 +00:00
m_pMenus - > KillServer ( ) ;
2017-09-09 21:10:42 +00:00
m_pRaceDemo - > OnReset ( ) ;
2017-09-09 16:25:32 +00:00
m_pGhost - > OnReset ( ) ;
2011-02-04 17:25:04 +00:00
}
2014-09-03 12:17:44 +00:00
void CGameClient : : OnEnterGame ( )
{
g_GameClient . m_pEffects - > ResetDamageIndicator ( ) ;
}
2008-08-27 15:48:50 +00:00
2010-12-12 15:48:13 +00:00
void CGameClient : : OnGameOver ( )
{
2012-04-19 23:04:12 +00:00
if ( Client ( ) - > State ( ) ! = IClient : : STATE_DEMOPLAYBACK & & g_Config . m_ClEditor = = 0 )
2010-12-12 15:48:13 +00:00
Client ( ) - > AutoScreenshot_Start ( ) ;
}
2011-01-06 22:21:51 +00:00
void CGameClient : : OnStartGame ( )
{
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 ( ) ;
2015-05-21 09:41:59 +00:00
m_pStatboard - > OnReset ( ) ;
2015-05-20 20:23:58 +00:00
}
void CGameClient : : OnFlagGrab ( int TeamID )
{
if ( TeamID = = TEAM_RED )
m_aStats [ m_Snap . m_pGameDataObj - > m_FlagCarrierRed ] . m_FlagGrabs + + ;
else
m_aStats [ m_Snap . m_pGameDataObj - > m_FlagCarrierBlue ] . m_FlagGrabs + + ;
2011-01-06 22:21:51 +00:00
}
2018-03-21 14:54:51 +00:00
void CGameClient : : OnWindowResize ( )
{
for ( int i = 0 ; i < m_All . m_Num ; i + + )
m_All . m_paComponents [ i ] - > OnWindowResize ( ) ;
TextRender ( ) - > OnWindowResize ( ) ;
}
void CGameClient : : OnWindowResizeCB ( void * pUser )
{
2020-09-26 19:41:58 +00:00
CGameClient * pClient = ( CGameClient * ) pUser ;
2018-03-21 14:54:51 +00:00
pClient - > OnWindowResize ( ) ;
}
2017-07-24 19:43:55 +00:00
void CGameClient : : OnRconType ( bool UsernameReq )
{
m_pGameConsole - > RequireUsername ( UsernameReq ) ;
}
2010-05-29 07:25:38 +00:00
void CGameClient : : OnRconLine ( const char * pLine )
{
2010-11-17 12:01:46 +00:00
m_pGameConsole - > PrintLine ( CGameConsole : : CONSOLETYPE_REMOTE , pLine ) ;
2010-05-29 07:25:38 +00:00
}
2008-08-27 15:48:50 +00:00
2010-05-29 07:25:38 +00:00
void CGameClient : : ProcessEvents ( )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
if ( m_SuppressEvents )
2008-12-19 11:41:17 +00:00
return ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
int SnapType = IClient : : SNAP_CURRENT ;
int Num = Client ( ) - > SnapNumItems ( SnapType ) ;
for ( int Index = 0 ; Index < Num ; Index + + )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
IClient : : CSnapItem Item ;
const void * pData = Client ( ) - > SnapGetItem ( SnapType , Index , & Item ) ;
2008-08-27 15:48:50 +00:00
2010-05-29 07:25:38 +00:00
if ( Item . m_Type = = NETEVENTTYPE_DAMAGEIND )
2008-08-27 15:48:50 +00:00
{
2011-06-01 17:43:48 +00:00
CNetEvent_DamageInd * ev = ( CNetEvent_DamageInd * ) pData ;
2010-05-29 07:25:38 +00:00
g_GameClient . m_pEffects - > DamageIndicator ( vec2 ( ev - > m_X , ev - > m_Y ) , GetDirection ( ev - > m_Angle ) ) ;
2008-08-27 15:48:50 +00:00
}
2010-05-29 07:25:38 +00:00
else if ( Item . m_Type = = NETEVENTTYPE_EXPLOSION )
2008-08-27 15:48:50 +00:00
{
2011-06-01 17:43:48 +00:00
CNetEvent_Explosion * ev = ( CNetEvent_Explosion * ) pData ;
2010-05-29 07:25:38 +00:00
g_GameClient . m_pEffects - > Explosion ( vec2 ( ev - > m_X , ev - > m_Y ) ) ;
2008-08-27 15:48:50 +00:00
}
2010-05-29 07:25:38 +00:00
else if ( Item . m_Type = = NETEVENTTYPE_HAMMERHIT )
2008-10-17 11:23:21 +00:00
{
2011-06-01 17:43:48 +00:00
CNetEvent_HammerHit * ev = ( CNetEvent_HammerHit * ) pData ;
2010-05-29 07:25:38 +00:00
g_GameClient . m_pEffects - > HammerHit ( vec2 ( ev - > m_X , ev - > m_Y ) ) ;
2008-10-17 11:23:21 +00:00
}
2010-05-29 07:25:38 +00:00
else if ( Item . m_Type = = NETEVENTTYPE_SPAWN )
2008-08-27 15:48:50 +00:00
{
2011-06-01 17:43:48 +00:00
CNetEvent_Spawn * ev = ( CNetEvent_Spawn * ) pData ;
2010-05-29 07:25:38 +00:00
g_GameClient . m_pEffects - > PlayerSpawn ( vec2 ( ev - > m_X , ev - > m_Y ) ) ;
2008-08-27 15:48:50 +00:00
}
2010-05-29 07:25:38 +00:00
else if ( Item . m_Type = = NETEVENTTYPE_DEATH )
2008-08-27 15:48:50 +00:00
{
2011-06-01 17:43:48 +00:00
CNetEvent_Death * ev = ( CNetEvent_Death * ) pData ;
2011-02-12 10:40:36 +00:00
g_GameClient . m_pEffects - > PlayerDeath ( vec2 ( ev - > m_X , ev - > m_Y ) , ev - > m_ClientID ) ;
2008-08-27 15:48:50 +00:00
}
2010-05-29 07:25:38 +00:00
else if ( Item . m_Type = = NETEVENTTYPE_SOUNDWORLD )
2008-08-27 15:48:50 +00:00
{
2011-06-01 17:43:48 +00:00
CNetEvent_SoundWorld * ev = ( CNetEvent_SoundWorld * ) pData ;
2017-06-06 16:58:23 +00:00
if ( g_Config . m_SndGame & & ( ev - > m_SoundID ! = SOUND_GUN_FIRE | | g_Config . m_SndGun ) & & ( ev - > m_SoundID ! = SOUND_PLAYER_PAIN_LONG | | g_Config . m_SndLongPain ) )
2014-10-25 00:52:08 +00:00
g_GameClient . m_pSounds - > PlayAt ( CSounds : : CHN_WORLD , ev - > m_SoundID , 1.0f , vec2 ( ev - > m_X , ev - > m_Y ) ) ;
2008-08-27 15:48:50 +00:00
}
}
}
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 ;
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 ) ;
}
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 ;
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.
2019-06-03 19:52:14 +00:00
DDRace = DDRace | | DDNet ;
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 ) ;
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 ;
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 ;
}
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
2010-05-29 07:25:38 +00:00
mem_zero ( & g_GameClient . m_Snap , sizeof ( g_GameClient . m_Snap ) ) ;
2011-02-12 10:40:36 +00:00
m_Snap . m_LocalClientID = - 1 ;
2020-07-12 15:32:56 +00:00
}
void CGameClient : : OnNewSnapshot ( )
{
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 ;
Client ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL ) ;
2008-08-27 15:48:50 +00:00
}
}
2017-06-02 18:45:09 +00:00
# endif
2008-08-27 15:48:50 +00:00
2019-06-03 19:52:14 +00:00
bool FoundGameInfoEx = false ;
2020-06-25 12:56:23 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
m_aClients [ i ] . m_SpecCharPresent = false ;
}
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-09-24 09:38:27 +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
pClient - > m_SkinID = g_GameClient . m_pSkins - > Find ( pClient - > m_aSkinName ) ;
if ( pClient - > m_UseCustomColor )
pClient - > m_SkinInfo . m_Texture = g_GameClient . m_pSkins - > Get ( pClient - > m_SkinID ) - > m_ColorTexture ;
else
{
pClient - > m_SkinInfo . m_Texture = g_GameClient . m_pSkins - > Get ( pClient - > m_SkinID ) - > m_OrgTexture ;
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
2020-06-25 16:29:56 +00:00
pClient - > UpdateRenderInfo ( ) ;
}
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 ;
m_Snap . m_SpecInfo . m_SpectatorID = SPEC_FREEVIEW ;
}
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 ;
}
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 ) ;
// reuse the result from the previous evolve if the snapped character didn't change since the previous snapshot
if ( m_aClients [ Item . m_ID ] . m_Evolved . m_Tick = = Client ( ) - > PrevGameTick ( g_Config . m_ClDummy ) )
{
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 ;
}
if ( m_Snap . m_aCharacters [ Item . m_ID ] . m_Prev . m_Tick )
Evolve ( & m_Snap . m_aCharacters [ Item . m_ID ] . m_Prev , Client ( ) - > PrevGameTick ( g_Config . m_ClDummy ) ) ;
if ( m_Snap . m_aCharacters [ Item . m_ID ] . m_Cur . m_Tick )
Evolve ( & m_Snap . m_aCharacters [ Item . m_ID ] . m_Cur , Client ( ) - > GameTick ( g_Config . m_ClDummy ) ) ;
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 ;
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 ;
// 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
{
2011-03-04 16:08:10 +00:00
static bool s_GameOver = 0 ;
2015-11-12 09:06:05 +00:00
static bool s_GamePaused = 0 ;
2011-03-04 16:08:10 +00:00
m_Snap . m_pGameInfoObj = ( const CNetObj_GameInfo * ) pData ;
2018-10-02 18:52:21 +00:00
bool CurrentTickGameOver = ( bool ) ( m_Snap . m_pGameInfoObj - > m_GameStateFlags & GAMESTATEFLAG_GAMEOVER ) ;
2015-11-12 09:06:05 +00:00
if ( ! s_GameOver & & CurrentTickGameOver )
2010-12-12 15:48:13 +00:00
OnGameOver ( ) ;
2015-11-12 09:06:05 +00:00
else if ( s_GameOver & & ! CurrentTickGameOver )
2011-01-06 22:21:51 +00:00
OnStartGame ( ) ;
2015-11-12 09:06:05 +00:00
// Reset statboard when new round is started (RoundStartTick changed)
// New round is usually started after `restart` on server
2015-11-13 10:33:12 +00:00
if ( m_Snap . m_pGameInfoObj - > m_RoundStartTick ! = m_LastRoundStartTick
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 ) )
2015-11-12 09:06:05 +00:00
m_pStatboard - > OnReset ( ) ;
m_LastRoundStartTick = m_Snap . m_pGameInfoObj - > m_RoundStartTick ;
s_GameOver = CurrentTickGameOver ;
2018-10-02 18:52:21 +00:00
s_GamePaused = ( bool ) ( m_Snap . m_pGameInfoObj - > m_GameStateFlags & GAMESTATEFLAG_PAUSED ) ;
2011-03-04 16:08:10 +00:00
}
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 ;
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
m_pControls - > OnPlayerDeath ( ) ;
}
2008-08-27 15:48:50 +00:00
}
2015-07-22 19:32:02 +00:00
if ( Client ( ) - > State ( ) = = IClient : : STATE_DEMOPLAYBACK )
2011-03-12 17:07:57 +00:00
{
2015-07-26 16:21:51 +00:00
if ( m_DemoSpecID ! = SPEC_FOLLOW )
{
m_Snap . m_SpecInfo . m_Active = true ;
2015-07-22 19:32:02 +00:00
m_Snap . m_SpecInfo . m_SpectatorID = m_Snap . m_LocalClientID ;
2015-07-26 16:21:51 +00:00
if ( m_DemoSpecID > SPEC_FREEVIEW & & m_Snap . m_aCharacters [ m_DemoSpecID ] . m_Active )
m_Snap . m_SpecInfo . m_SpectatorID = m_DemoSpecID ;
else
m_Snap . m_SpecInfo . m_SpectatorID = SPEC_FREEVIEW ;
}
2011-03-12 17:07:57 +00:00
}
2011-01-11 22:03:01 +00:00
2011-03-22 21:41:27 +00:00
// clear out unneeded client data
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
if ( ! m_Snap . m_paPlayerInfos [ i ] & & m_aClients [ i ] . m_Active )
2017-02-15 15:43:45 +00:00
{
2011-03-22 21:41:27 +00:00
m_aClients [ i ] . Reset ( ) ;
2017-02-15 15:43:45 +00:00
m_aStats [ i ] . Reset ( ) ;
}
2011-03-22 21:41:27 +00:00
}
2011-03-23 12:06:35 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
2018-11-21 20:26:05 +00:00
// update friend state
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 ;
2014-01-28 18:52:46 +00:00
for ( int Team = 0 ; Team < = MAX_CLIENTS ; + + Team )
2014-01-22 00:39:18 +00:00
{
for ( int i = 0 ; i < MAX_CLIENTS & & Index < MAX_CLIENTS ; + + i )
{
if ( m_Snap . m_paInfoByScore [ i ] & & m_Teams . Team ( m_Snap . m_paInfoByScore [ i ] - > m_ClientID ) = = Team )
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 ;
for ( int Team = 0 ; Team < = MAX_CLIENTS ; + + Team )
{
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 ] ) ;
2020-09-26 19:41:58 +00:00
Client ( ) - > SendMsg ( & Msg , MSGFLAG_RECORD | MSGFLAG_NOSEND ) ;
2012-01-08 23:49:20 +00:00
}
2013-02-02 13:08:02 +00:00
2014-04-28 14:47:44 +00:00
if ( ! m_DDRaceMsgSent [ 0 ] & & m_Snap . m_pLocalInfo )
{
2012-08-09 08:30:04 +00:00
CMsgPacker Msg ( NETMSGTYPE_CL_ISDDNET , false ) ;
2014-04-28 14:47:44 +00:00
Msg . AddInt ( CLIENT_VERSIONNR ) ;
2012-08-09 08:30:04 +00:00
Client ( ) - > SendMsgY ( & Msg , MSGFLAG_VITAL , 0 ) ;
2014-04-28 14:47:44 +00:00
m_DDRaceMsgSent [ 0 ] = true ;
}
if ( ! m_DDRaceMsgSent [ 1 ] & & m_Snap . m_pLocalInfo & & Client ( ) - > DummyConnected ( ) )
2010-10-23 19:26:10 +00:00
{
2012-08-09 08:30:04 +00:00
CMsgPacker Msg ( NETMSGTYPE_CL_ISDDNET , false ) ;
2014-02-19 21:29:46 +00:00
Msg . AddInt ( CLIENT_VERSIONNR ) ;
2012-08-09 08:30:04 +00:00
Client ( ) - > SendMsgY ( & Msg , MSGFLAG_VITAL , 1 ) ;
2014-04-28 14:47:44 +00:00
m_DDRaceMsgSent [ 1 ] = true ;
2013-02-02 13:08:02 +00:00
}
2011-02-23 20:22:05 +00:00
2014-05-24 22:59:52 +00:00
if ( m_ShowOthers [ g_Config . m_ClDummy ] = = - 1 | | ( m_ShowOthers [ g_Config . m_ClDummy ] ! = - 1 & & m_ShowOthers [ g_Config . m_ClDummy ] ! = g_Config . m_ClShowOthers ) )
2013-02-02 13:08:02 +00:00
{
{
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 ;
2013-02-02 13:08:02 +00:00
Client ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL ) ;
}
// update state
2014-05-24 22:59:52 +00:00
m_ShowOthers [ g_Config . m_ClDummy ] = g_Config . m_ClShowOthers ;
2010-10-23 19:26:10 +00:00
}
2017-10-06 20:01:33 +00:00
2020-06-28 09:48:25 +00:00
static float LastZoom = .0 ;
static float LastScreenAspect = .0 ;
2020-07-08 21:25:07 +00:00
static bool LastDummyConnected = false ;
2020-07-08 06:29:04 +00:00
float ZoomToSend = m_pCamera - > m_ZoomSmoothingTarget = = .0 ? m_pCamera - > m_Zoom // Initial
2020-09-26 19:41:58 +00:00
:
m_pCamera - > m_ZoomSmoothingTarget > m_pCamera - > m_Zoom ? m_pCamera - > m_ZoomSmoothingTarget // Zooming out
:
m_pCamera - > m_ZoomSmoothingTarget < m_pCamera - > m_Zoom ? LastZoom // Zooming in
:
m_pCamera - > m_Zoom ; // Not zooming
2020-07-08 21:25:07 +00:00
if ( ZoomToSend ! = LastZoom | | Graphics ( ) - > ScreenAspect ( ) ! = LastScreenAspect | | ( Client ( ) - > DummyConnected ( ) & & ! LastDummyConnected ) )
2020-06-28 09:48:25 +00:00
{
CNetMsg_Cl_ShowDistance Msg ;
float x , y ;
2020-08-24 18:11:51 +00:00
RenderTools ( ) - > CalcScreenParams ( Graphics ( ) - > ScreenAspect ( ) , ZoomToSend * 1.25 , & x , & y ) ;
2020-06-28 09:48:25 +00:00
Msg . m_X = x ;
Msg . m_Y = y ;
2020-07-08 21:25:07 +00:00
CMsgPacker Packer ( Msg . MsgID ( ) , false ) ;
Msg . Pack ( & Packer ) ;
if ( ZoomToSend ! = LastZoom )
Client ( ) - > SendMsgY ( & Packer , MSGFLAG_VITAL , 0 ) ;
if ( Client ( ) - > DummyConnected ( ) )
Client ( ) - > SendMsgY ( & Packer , MSGFLAG_VITAL , 1 ) ;
LastZoom = ZoomToSend ;
LastScreenAspect = Graphics ( ) - > ScreenAspect ( ) ;
2020-06-28 09:48:25 +00:00
}
2020-07-08 21:25:07 +00:00
LastDummyConnected = Client ( ) - > DummyConnected ( ) ;
2020-06-28 09:48:25 +00:00
2017-10-06 20:01:33 +00:00
m_pGhost - > OnNewSnapshot ( ) ;
m_pRaceDemo - > OnNewSnapshot ( ) ;
2019-04-11 22:46:54 +00:00
// detect air jump for unpredicted players
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
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 ) )
2019-04-11 22:46:54 +00:00
if ( ! Predict ( ) | | ( ! AntiPingPlayers ( ) & & i ! = m_Snap . m_LocalClientID ) )
{
vec2 Pos = mix ( vec2 ( m_Snap . m_aCharacters [ i ] . m_Prev . m_X , m_Snap . m_aCharacters [ i ] . m_Prev . m_Y ) ,
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 ) ) ;
2019-04-11 22:46:54 +00:00
m_pEffects - > AirJump ( Pos ) ;
}
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 ;
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
2019-04-11 22:46:54 +00:00
// don't predict inactive players
2008-09-23 07:43:41 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2019-04-11 22:46:54 +00:00
if ( CCharacter * pChar = m_PredictedWorld . GetCharacterByID ( i ) )
if ( ! m_Snap . m_aCharacters [ i ] . m_Active & & pChar - > m_SnapTicks > 10 )
pChar - > Destroy ( ) ;
2011-04-13 18:37:12 +00:00
2019-04-11 22:46:54 +00:00
CCharacter * pLocalChar = m_PredictedWorld . GetCharacterByID ( m_Snap . m_LocalClientID ) ;
if ( ! pLocalChar )
return ;
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 )
2019-04-11 22:46:54 +00:00
m_pEffects - > AirJump ( Pos ) ;
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 )
2019-04-11 22:46:54 +00:00
m_pSounds - > PlayAndRecord ( CSounds : : CHN_WORLD , SOUND_PLAYER_JUMP , 1.0f , Pos ) ;
2020-09-26 19:41:58 +00:00
if ( Events & COREEVENT_HOOK_ATTACH_GROUND )
2019-04-11 22:46:54 +00:00
m_pSounds - > 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 )
2019-04-11 22:46:54 +00:00
m_pSounds - > PlayAndRecord ( CSounds : : CHN_WORLD , SOUND_HOOK_NOATTACH , 1.0f , Pos ) ;
2014-12-01 00:31:58 +00:00
}
}
2019-04-11 22:46:54 +00:00
}
2014-12-01 00:31:58 +00:00
2019-04-11 22:46:54 +00:00
// detect mispredictions of other players and make corrections smoother when possible
2020-09-26 19:41:58 +00:00
static vec2 s_aLastPos [ MAX_CLIENTS ] = { { 0 , 0 } } ;
2019-04-11 22:46:54 +00:00
static bool s_aLastActive [ MAX_CLIENTS ] = { 0 } ;
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)
2019-04-11 22:46:54 +00:00
int64 Len = 1000 * PredTime * SmoothPace ;
2018-10-02 18:45:44 +00:00
2019-04-11 22:46:54 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( ! m_Snap . m_aCharacters [ i ] . m_Active | | i = = m_Snap . m_LocalClientID | | ! s_aLastActive [ i ] )
continue ;
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
}
2019-04-11 22:46:54 +00:00
int64 TimePassed = time_get ( ) - m_aClients [ i ] . m_SmoothStart [ j ] ;
2020-09-26 19:41:58 +00:00
if ( in_range ( TimePassed , ( int64 ) 0 , Len - 1 ) )
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
{
2020-09-26 19:41:58 +00:00
int64 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
2019-04-11 22:46:54 +00:00
int64 Start = time_get ( ) - ( Len - Remaining ) ;
if ( ! in_range ( Start + Len , m_aClients [ i ] . m_SmoothStart [ j ] , m_aClients [ i ] . m_SmoothStart [ j ] + Len ) )
2014-12-01 00:31:58 +00:00
{
2019-04-11 22:46:54 +00:00
m_aClients [ i ] . m_SmoothStart [ j ] = Start ;
m_aClients [ i ] . m_SmoothLen [ j ] = Len ;
2014-12-01 00:31:58 +00:00
}
}
}
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 )
2017-10-28 12:23:24 +00:00
m_pGhost - > OnNewPredictedSnapshot ( ) ;
2008-08-27 15:48:50 +00:00
}
2011-01-17 11:28:37 +00:00
void CGameClient : : OnActivateEditor ( )
{
OnRelease ( ) ;
}
2015-05-19 22:51:02 +00:00
CGameClient : : CClientStats : : CClientStats ( )
{
2017-02-15 15:43:45 +00:00
Reset ( ) ;
2015-05-19 22:51:02 +00:00
}
void CGameClient : : CClientStats : : Reset ( )
{
2017-02-15 15:43:45 +00:00
m_JoinTick = 0 ;
m_IngameTicks = 0 ;
2015-05-19 22:51:02 +00:00
m_Active = false ;
m_Frags = 0 ;
m_Deaths = 0 ;
m_Suicides = 0 ;
m_BestSpree = 0 ;
m_CurrentSpree = 0 ;
for ( int j = 0 ; j < NUM_WEAPONS ; j + + )
{
m_aFragsWith [ j ] = 0 ;
m_aDeathsFrom [ j ] = 0 ;
}
m_FlagGrabs = 0 ;
m_FlagCaptures = 0 ;
}
2010-05-29 07:25:38 +00:00
void CGameClient : : CClientData : : UpdateRenderInfo ( )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
m_RenderInfo = m_SkinInfo ;
2008-08-27 15:48:50 +00:00
// force team colors
2020-09-26 19:41:58 +00:00
if ( g_GameClient . m_Snap . m_pGameInfoObj & & g_GameClient . m_Snap . m_pGameInfoObj - > m_GameFlags & GAMEFLAG_TEAMS )
2008-08-27 15:48:50 +00:00
{
2011-03-27 09:52:16 +00:00
m_RenderInfo . m_Texture = g_GameClient . m_pSkins - > Get ( m_SkinID ) - > m_ColorTexture ;
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 ;
2019-09-17 14:45:44 +00:00
m_SkinID = - 1 ;
2011-03-22 21:41:27 +00:00
m_Team = 0 ;
m_Angle = 0 ;
m_Emoticon = 0 ;
m_EmoticonStart = - 1 ;
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 ;
2019-09-17 14:45:44 +00:00
m_SkinInfo . m_Texture = g_GameClient . m_pSkins - > Get ( - 1 ) - > m_OrgTexture ;
2020-09-26 19:41:58 +00:00
m_SkinInfo . m_ColorBody = ColorRGBA ( 1 , 1 , 1 ) ;
m_SkinInfo . m_ColorFeet = ColorRGBA ( 1 , 1 , 1 ) ;
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 ;
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
2011-03-22 21:41:27 +00:00
UpdateRenderInfo ( ) ;
}
2010-05-29 07:25:38 +00:00
void CGameClient : : SendSwitchTeam ( int Team )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
CNetMsg_Cl_SetTeam Msg ;
Msg . m_Team = Team ;
2011-04-13 18:37:12 +00:00
Client ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL ) ;
2013-07-11 15:25:51 +00:00
2018-03-13 20:55:47 +00:00
if ( Team ! = TEAM_SPECTATORS )
2013-07-11 15:25:51 +00:00
m_pCamera - > OnReset ( ) ;
2008-08-27 15:48:50 +00:00
}
2010-05-29 07:25:38 +00:00
void CGameClient : : SendInfo ( bool Start )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
if ( Start )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
CNetMsg_Cl_StartInfo Msg ;
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 ) ;
2012-08-09 08:30:04 +00:00
Client ( ) - > SendMsgY ( & Packer , MSGFLAG_VITAL , 0 ) ;
2015-04-19 12:03:40 +00:00
m_CheckInfo [ 0 ] = - 1 ;
2008-08-27 15:48:50 +00:00
}
else
{
2010-05-29 07:25:38 +00:00
CNetMsg_Cl_ChangeInfo Msg ;
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 ) ;
2012-08-09 08:30:04 +00:00
Client ( ) - > SendMsgY ( & Packer , MSGFLAG_VITAL , 0 ) ;
2015-04-19 12:03:40 +00:00
m_CheckInfo [ 0 ] = Client ( ) - > GameTickSpeed ( ) ;
2008-08-27 15:48:50 +00:00
}
}
2014-04-28 13:19:57 +00:00
void CGameClient : : SendDummyInfo ( bool Start )
{
if ( Start )
{
CNetMsg_Cl_StartInfo Msg ;
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 ) ;
2012-08-09 08:30:04 +00:00
Client ( ) - > SendMsgY ( & Packer , MSGFLAG_VITAL , 1 ) ;
2015-04-19 12:03:40 +00:00
m_CheckInfo [ 1 ] = - 1 ;
2014-04-28 13:19:57 +00:00
}
else
{
CNetMsg_Cl_ChangeInfo Msg ;
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 ) ;
2012-08-09 08:30:04 +00:00
Client ( ) - > SendMsgY ( & Packer , MSGFLAG_VITAL , 1 ) ;
2015-04-19 12:03:40 +00:00
m_CheckInfo [ 1 ] = Client ( ) - > GameTickSpeed ( ) ;
2014-04-28 13:19:57 +00:00
}
}
2011-02-12 10:40:36 +00:00
void CGameClient : : SendKill ( int ClientID )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
CNetMsg_Cl_Kill Msg ;
2011-04-13 18:37:12 +00:00
Client ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL ) ;
2015-02-18 13:23:25 +00:00
if ( g_Config . m_ClDummyCopyMoves )
{
2012-08-09 08:30:04 +00:00
CMsgPacker Msg ( NETMSGTYPE_CL_KILL , false ) ;
Client ( ) - > SendMsgY ( & Msg , MSGFLAG_VITAL , ! g_Config . m_ClDummy ) ;
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 ;
2019-05-06 12:19:10 +00:00
pGameClient - > m_pMapimages - > SetTextureScale ( g_Config . m_ClTextEntitiesSize ) ;
}
}
2010-05-29 07:25:38 +00:00
IGameClient * CreateGameClient ( )
2009-10-27 14:38:53 +00:00
{
2010-05-29 07:25:38 +00:00
return & g_GameClient ;
2011-01-06 05:30:19 +00:00
}
2013-08-23 23:50:35 +00:00
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
2014-01-27 04:06:23 +00:00
vec2 ClosestPoint = closest_point_on_line ( HookPos , NewPos , Position ) ;
2019-04-21 17:35:07 +00:00
if ( distance ( Position , ClosestPoint ) < PhysSize + 2.0f )
2013-08-23 23:50:35 +00:00
{
2014-01-27 04:06:23 +00:00
if ( ClosestID = = - 1 | | distance ( HookPos , Position ) < Distance )
2013-08-23 23:50:35 +00:00
{
2014-01-27 04:06:23 +00:00
NewPos2 = ClosestPoint ;
2013-08-23 23:50:35 +00:00
ClosestID = i ;
2014-01-27 04:06:23 +00:00
Distance = distance ( HookPos , Position ) ;
2013-08-23 23:50:35 +00:00
}
}
}
2014-10-23 15:31:29 +00:00
2013-08-23 23:50:35 +00:00
return ClosestID ;
}
2014-12-01 00:31:58 +00:00
2019-04-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 ( )
{
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-06-03 19:52:14 +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 ;
2019-05-03 18:57:01 +00:00
m_GameWorld . m_WorldConfig . m_PredictDDRace = g_Config . m_ClPredictDDRace ;
2019-06-03 19:52:14 +00:00
m_GameWorld . m_WorldConfig . m_PredictTiles = g_Config . m_ClPredictDDRace & & m_GameInfo . m_PredictDDRaceTiles ;
2019-04-11 22:46:54 +00:00
m_GameWorld . m_WorldConfig . m_PredictFreeze = g_Config . m_ClPredictFreeze ;
m_GameWorld . m_WorldConfig . m_PredictWeapons = AntiPingWeapons ( ) ;
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
int TuneZone = Collision ( ) - > IsTune ( Collision ( ) - > GetMapIndex ( vec2 ( m_Snap . m_pLocalCharacter - > m_X , m_Snap . m_pLocalCharacter - > m_Y ) ) ) ;
2019-09-08 22:53:07 +00:00
if ( ! TuneZone | | ! m_GameWorld . m_WorldConfig . m_PredictTiles )
2019-09-15 22:07:42 +00:00
m_GameWorld . m_Tuning [ g_Config . m_ClDummy ] = m_Tuning [ g_Config . m_ClDummy ] ;
2019-09-08 22:53:07 +00:00
else
m_GameWorld . TuningList ( ) [ TuneZone ] = m_GameWorld . m_Core . m_Tuning [ g_Config . m_ClDummy ] = m_Tuning [ g_Config . m_ClDummy ] ;
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
if ( pLocalChar & & AntiPingPlayers ( ) )
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 ] ;
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
aIDs [ i ] = - 1 ;
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
if ( CCharacter * pChar = m_GameWorld . GetCharacterByID ( i ) )
aIDs [ pChar - > GetStrongWeakID ( ) ] = i ;
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
if ( aIDs [ i ] > = 0 )
m_CharOrder . GiveStrong ( aIDs [ i ] ) ;
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 ( ) ;
int Num = Client ( ) - > SnapNumItems ( IClient : : SNAP_CURRENT ) ;
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
}
2019-05-11 19:13:09 +00:00
for ( int Index = 0 ; Index < Num ; Index + + )
{
IClient : : CSnapItem Item ;
const void * pData = Client ( ) - > SnapGetItem ( IClient : : SNAP_CURRENT , Index , & Item ) ;
m_GameWorld . NetObjAdd ( Item . m_ID , Item . m_Type , pData ) ;
}
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
2019-04-11 22:46:54 +00:00
if ( Predict ( ) & & ( i = = m_Snap . m_LocalClientID | | AntiPingPlayers ( ) ) )
{
m_aClients [ i ] . m_Predicted . Write ( & m_aClients [ i ] . m_RenderCur ) ;
m_aClients [ i ] . m_PrevPredicted . Write ( & m_aClients [ i ] . m_RenderPrev ) ;
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 ) ) ;
2019-04-11 22:46:54 +00:00
int64 Now = time_get ( ) ;
for ( int i = 0 ; i < 2 ; i + + )
{
2020-09-26 19:41:58 +00:00
int64 Len = clamp ( m_aClients [ ClientID ] . m_SmoothLen [ i ] , ( int64 ) 1 , time_freq ( ) ) ;
2019-04-11 22:46:54 +00:00
int64 TimePassed = Now - m_aClients [ ClientID ] . m_SmoothStart [ i ] ;
2020-09-26 19:41:58 +00:00
if ( in_range ( TimePassed , ( int64 ) 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 )
{
m_pChat - > Echo ( pString ) ;
}
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 ;
else if ( ( m_aClients [ m_Snap . m_LocalClientID ] . m_Team = = TEAM_SPECTATORS & & 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 )
return m_Teams . Team ( ClientID ) ! = m_Teams . Team ( m_Snap . m_SpecInfo . m_SpectatorID ) ;
else if ( ( m_aClients [ m_Snap . m_LocalClientID ] . m_Solo | | m_aClients [ ClientID ] . m_Solo ) & & ! Local )
return true ;
return m_Teams . Team ( ClientID ) ! = m_Teams . Team ( m_Snap . m_LocalClientID ) ;
}
2019-09-08 22:53:07 +00:00
2020-09-26 07:37:35 +00:00
void CGameClient : : LoadGameSkin ( const char * pPath , bool AsDir )
{
if ( g_pData - > m_aImages [ IMAGE_GAME ] . m_Id ! = - 1 )
{
Graphics ( ) - > UnloadTexture ( g_pData - > m_aImages [ IMAGE_GAME ] . m_Id ) ;
g_pData - > m_aImages [ IMAGE_GAME ] . m_Id = IGraphics : : CTextureHandle ( ) ;
}
char aPath [ MAX_PATH_LENGTH ] ;
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 ) ;
}
else if ( PngLoaded )
{
g_pData - > m_aImages [ IMAGE_GAME ] . m_Id = Graphics ( ) - > LoadTextureRaw ( ImgInfo . m_Width , ImgInfo . m_Height , ImgInfo . m_Format , ImgInfo . m_pData , ImgInfo . m_Format , 0 , aPath ) ;
2020-09-30 21:42:00 +00:00
free ( ImgInfo . m_pData ) ;
2020-09-26 07:37:35 +00:00
}
}
void CGameClient : : LoadEmoticonsSkin ( const char * pPath , bool AsDir )
{
if ( g_pData - > m_aImages [ IMAGE_EMOTICONS ] . m_Id ! = - 1 )
{
Graphics ( ) - > UnloadTexture ( g_pData - > m_aImages [ IMAGE_EMOTICONS ] . m_Id ) ;
g_pData - > m_aImages [ IMAGE_EMOTICONS ] . m_Id = IGraphics : : CTextureHandle ( ) ;
}
char aPath [ MAX_PATH_LENGTH ] ;
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 ) ;
}
else if ( PngLoaded )
{
g_pData - > m_aImages [ IMAGE_EMOTICONS ] . m_Id = Graphics ( ) - > LoadTextureRaw ( ImgInfo . m_Width , ImgInfo . m_Height , ImgInfo . m_Format , ImgInfo . m_pData , ImgInfo . m_Format , 0 , aPath ) ;
2020-09-30 21:42:00 +00:00
free ( ImgInfo . m_pData ) ;
2020-09-26 07:37:35 +00:00
}
}
void CGameClient : : LoadParticlesSkin ( const char * pPath , bool AsDir )
{
if ( g_pData - > m_aImages [ IMAGE_PARTICLES ] . m_Id ! = - 1 )
{
Graphics ( ) - > UnloadTexture ( g_pData - > m_aImages [ IMAGE_PARTICLES ] . m_Id ) ;
g_pData - > m_aImages [ IMAGE_PARTICLES ] . m_Id = IGraphics : : CTextureHandle ( ) ;
}
char aPath [ MAX_PATH_LENGTH ] ;
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 ) ;
}
else if ( PngLoaded )
{
g_pData - > m_aImages [ IMAGE_PARTICLES ] . m_Id = Graphics ( ) - > LoadTextureRaw ( ImgInfo . m_Width , ImgInfo . m_Height , ImgInfo . m_Format , ImgInfo . m_pData , ImgInfo . m_Format , 0 , aPath ) ;
2020-09-30 21:42:00 +00:00
free ( ImgInfo . m_pData ) ;
2020-09-26 07:37:35 +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 ;
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 ) ;
}
// 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-09-26 19:41:58 +00:00
dbg_msg ( " New 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 ) ) ;
pSelf - > m_pMenuBackground - > LoadMenuBackground ( ) ;
}
}
else
pfnCallback ( pResult , pCallbackUserData ) ;
}
2020-10-02 13:43:52 +00:00
bool CGameClient : : CanDisplayWarning ( )
{
return m_pMenus - > CanDisplayWarning ( ) ;
}