2010-11-20 10:37:14 +00:00
|
|
|
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
|
|
|
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
2011-03-21 23:31:42 +00:00
|
|
|
#include <engine/editor.h>
|
2011-02-27 16:56:03 +00:00
|
|
|
#include <engine/engine.h>
|
2011-03-23 12:06:35 +00:00
|
|
|
#include <engine/friends.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <engine/graphics.h>
|
|
|
|
#include <engine/textrender.h>
|
|
|
|
#include <engine/demo.h>
|
|
|
|
#include <engine/map.h>
|
|
|
|
#include <engine/storage.h>
|
2011-02-27 16:56:03 +00:00
|
|
|
#include <engine/sound.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <engine/serverbrowser.h>
|
2015-04-18 19:17:27 +00:00
|
|
|
#include <engine/updater.h>
|
2010-09-12 10:16:51 +00:00
|
|
|
#include <engine/shared/demo.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <engine/shared/config.h>
|
|
|
|
|
|
|
|
#include <game/generated/protocol.h>
|
|
|
|
#include <game/generated/client_data.h>
|
|
|
|
|
2013-08-23 23:50:35 +00:00
|
|
|
#include <base/math.h>
|
|
|
|
#include <base/vmath.h>
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
#include <game/localization.h>
|
|
|
|
#include <game/version.h>
|
|
|
|
#include "render.h"
|
|
|
|
|
|
|
|
#include "gameclient.h"
|
|
|
|
|
|
|
|
#include "components/binds.h"
|
|
|
|
#include "components/broadcast.h"
|
|
|
|
#include "components/camera.h"
|
|
|
|
#include "components/chat.h"
|
|
|
|
#include "components/console.h"
|
|
|
|
#include "components/controls.h"
|
2011-03-16 11:09:22 +00:00
|
|
|
#include "components/countryflags.h"
|
2010-05-29 07:25:38 +00:00
|
|
|
#include "components/damageind.h"
|
|
|
|
#include "components/debughud.h"
|
|
|
|
#include "components/effects.h"
|
|
|
|
#include "components/emoticon.h"
|
|
|
|
#include "components/flow.h"
|
|
|
|
#include "components/hud.h"
|
|
|
|
#include "components/items.h"
|
|
|
|
#include "components/killmessages.h"
|
|
|
|
#include "components/mapimages.h"
|
|
|
|
#include "components/maplayers.h"
|
2014-10-10 17:10:57 +00:00
|
|
|
#include "components/mapsounds.h"
|
2010-05-29 07:25:38 +00:00
|
|
|
#include "components/menus.h"
|
|
|
|
#include "components/motd.h"
|
|
|
|
#include "components/particles.h"
|
|
|
|
#include "components/players.h"
|
2013-10-09 14:23:18 +00:00
|
|
|
#include "components/nameplates.h"
|
2010-05-29 07:25:38 +00:00
|
|
|
#include "components/scoreboard.h"
|
|
|
|
#include "components/skins.h"
|
|
|
|
#include "components/sounds.h"
|
2011-03-10 09:08:14 +00:00
|
|
|
#include "components/spectator.h"
|
2010-05-29 07:25:38 +00:00
|
|
|
#include "components/voting.h"
|
|
|
|
|
2011-08-31 11:56:04 +00:00
|
|
|
#include <base/system.h>
|
2011-02-04 17:25:04 +00:00
|
|
|
#include "components/race_demo.h"
|
|
|
|
#include "components/ghost.h"
|
2011-08-31 11:56:04 +00:00
|
|
|
#include <base/tl/sorted_array.h>
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
CGameClient g_GameClient;
|
2008-08-27 15:48:50 +00:00
|
|
|
|
|
|
|
// instanciate 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;
|
|
|
|
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);
|
|
|
|
|
2014-10-10 17:10:57 +00:00
|
|
|
static CMapSounds gs_MapSounds;
|
|
|
|
|
2011-04-09 06:41:31 +00:00
|
|
|
static CRaceDemo gs_RaceDemo;
|
|
|
|
static CGhost gs_Ghost;
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
CGameClient::CStack::CStack() { m_Num = 0; }
|
|
|
|
void CGameClient::CStack::Add(class CComponent *pComponent) { m_paComponents[m_Num++] = pComponent; }
|
|
|
|
|
|
|
|
const char *CGameClient::Version() { return GAME_VERSION; }
|
|
|
|
const char *CGameClient::NetVersion() { return GAME_NETVERSION; }
|
|
|
|
const char *CGameClient::GetItemName(int Type) { return m_NetObjHandler.GetObjName(Type); }
|
2009-06-15 06:45:44 +00:00
|
|
|
|
2014-07-07 23:41:45 +00:00
|
|
|
void CGameClient::ResetDummyInput()
|
|
|
|
{
|
2015-04-19 12:03:40 +00:00
|
|
|
m_pControls->ResetInput(!g_Config.m_ClDummy);
|
2014-07-07 23:41:45 +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-03-13 14:13:19 +00:00
|
|
|
#if defined(CONF_FAMILY_WINDOWS) || (defined(CONF_PLATFORM_LINUX) && !defined(__ANDROID__))
|
2015-04-18 19:17:27 +00:00
|
|
|
m_pUpdater = Kernel()->RequestInterface<IUpdater>();
|
2015-03-13 14:13:19 +00:00
|
|
|
#endif
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// setup pointers
|
2010-05-29 07:25:38 +00:00
|
|
|
m_pBinds = &::gs_Binds;
|
|
|
|
m_pGameConsole = &::gs_GameConsole;
|
|
|
|
m_pParticles = &::gs_Particles;
|
|
|
|
m_pMenus = &::gs_Menus;
|
|
|
|
m_pSkins = &::gs_Skins;
|
2011-03-16 11:09:22 +00:00
|
|
|
m_pCountryFlags = &::gs_CountryFlags;
|
2010-05-29 07:25:38 +00:00
|
|
|
m_pChat = &::gs_Chat;
|
|
|
|
m_pFlow = &::gs_Flow;
|
|
|
|
m_pCamera = &::gs_Camera;
|
|
|
|
m_pControls = &::gs_Controls;
|
|
|
|
m_pEffects = &::gs_Effects;
|
|
|
|
m_pSounds = &::gs_Sounds;
|
|
|
|
m_pMotd = &::gs_Motd;
|
|
|
|
m_pDamageind = &::gsDamageInd;
|
|
|
|
m_pMapimages = &::gs_MapImages;
|
|
|
|
m_pVoting = &::gs_Voting;
|
2010-08-18 01:57:35 +00:00
|
|
|
m_pScoreboard = &::gs_Scoreboard;
|
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;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2014-10-10 17:10:57 +00:00
|
|
|
m_pMapSounds = &::gs_MapSounds;
|
|
|
|
|
2011-02-04 17:25:04 +00:00
|
|
|
m_pRaceDemo = &::gs_RaceDemo;
|
|
|
|
m_pGhost = &::gs_Ghost;
|
2011-04-09 06:41:31 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// make a list of all the systems, make sure to add them in the corrent render order
|
2010-05-29 07:25:38 +00:00
|
|
|
m_All.Add(m_pSkins);
|
2011-03-16 11:09:22 +00:00
|
|
|
m_All.Add(m_pCountryFlags);
|
2010-05-29 07:25:38 +00:00
|
|
|
m_All.Add(m_pMapimages);
|
|
|
|
m_All.Add(m_pEffects); // doesn't render anything, just updates effects
|
|
|
|
m_All.Add(m_pParticles);
|
|
|
|
m_All.Add(m_pBinds);
|
|
|
|
m_All.Add(m_pControls);
|
|
|
|
m_All.Add(m_pCamera);
|
|
|
|
m_All.Add(m_pSounds);
|
|
|
|
m_All.Add(m_pVoting);
|
|
|
|
m_All.Add(m_pParticles); // doesn't render anything, just updates all the particles
|
2011-02-04 17:25:04 +00:00
|
|
|
m_All.Add(m_pRaceDemo);
|
2014-10-10 17:10:57 +00:00
|
|
|
m_All.Add(m_pMapSounds);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
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);
|
2010-05-29 07:25:38 +00:00
|
|
|
m_All.Add(&gs_Players);
|
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);
|
|
|
|
m_All.Add(m_pMotd);
|
|
|
|
m_All.Add(m_pMenus);
|
|
|
|
m_All.Add(m_pGameConsole);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// build the input stack
|
2010-05-29 07:25:38 +00:00
|
|
|
m_Input.Add(&m_pMenus->m_Binder); // this will take over all input when we want to bind a key
|
|
|
|
m_Input.Add(&m_pBinds->m_SpecialBinds);
|
|
|
|
m_Input.Add(m_pGameConsole);
|
|
|
|
m_Input.Add(m_pChat); // chat has higher prio due to tha you can quit it by pressing esc
|
|
|
|
m_Input.Add(m_pMotd); // for pressing esc to remove it
|
|
|
|
m_Input.Add(m_pMenus);
|
2011-03-10 09:08:14 +00:00
|
|
|
m_Input.Add(&gs_Spectator);
|
2010-05-29 07:25:38 +00:00
|
|
|
m_Input.Add(&gs_Emoticon);
|
|
|
|
m_Input.Add(m_pControls);
|
|
|
|
m_Input.Add(m_pBinds);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-09-04 21:36:44 +00:00
|
|
|
// add the some console commands
|
2011-08-13 00:11:06 +00:00
|
|
|
Console()->Register("team", "i", CFGFLAG_CLIENT, ConTeam, this, "Switch team");
|
|
|
|
Console()->Register("kill", "", CFGFLAG_CLIENT, ConKill, this, "Kill yourself");
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2009-01-24 12:16:02 +00:00
|
|
|
// register server dummy commands for tab completion
|
2010-08-06 22:01:43 +00:00
|
|
|
Console()->Register("tune", "si", CFGFLAG_SERVER, 0, 0, "Tune variable to value");
|
|
|
|
Console()->Register("tune_reset", "", CFGFLAG_SERVER, 0, 0, "Reset tuning");
|
|
|
|
Console()->Register("tune_dump", "", CFGFLAG_SERVER, 0, 0, "Dump tuning");
|
2010-11-17 11:50:01 +00:00
|
|
|
Console()->Register("change_map", "?r", CFGFLAG_SERVER, 0, 0, "Change map");
|
2010-08-06 22:01:43 +00:00
|
|
|
Console()->Register("restart", "?i", CFGFLAG_SERVER, 0, 0, "Restart in x seconds");
|
|
|
|
Console()->Register("broadcast", "r", CFGFLAG_SERVER, 0, 0, "Broadcast message");
|
|
|
|
Console()->Register("say", "r", CFGFLAG_SERVER, 0, 0, "Say in chat");
|
2011-05-23 11:06:38 +00:00
|
|
|
Console()->Register("set_team", "ii?i", CFGFLAG_SERVER, 0, 0, "Set team of player to team");
|
2011-01-06 12:37:28 +00:00
|
|
|
Console()->Register("set_team_all", "i", CFGFLAG_SERVER, 0, 0, "Set team of all players to team");
|
2011-03-25 08:49:21 +00:00
|
|
|
Console()->Register("add_vote", "sr", CFGFLAG_SERVER, 0, 0, "Add a voting option");
|
2011-03-25 10:49:35 +00:00
|
|
|
Console()->Register("remove_vote", "s", CFGFLAG_SERVER, 0, 0, "remove a voting option");
|
2011-03-25 11:06:45 +00:00
|
|
|
Console()->Register("force_vote", "ss?r", 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");
|
2010-08-06 22:01:43 +00:00
|
|
|
Console()->Register("vote", "r", CFGFLAG_SERVER, 0, 0, "Force a vote to yes/no");
|
2011-09-04 09:13:30 +00:00
|
|
|
Console()->Register("swap_teams", "", CFGFLAG_SERVER, 0, 0, "Swap the current teams");
|
|
|
|
Console()->Register("shuffle_teams", "", CFGFLAG_SERVER, 0, 0, "Shuffle the current teams");
|
2010-05-29 07:25:38 +00:00
|
|
|
|
2010-08-25 14:15:59 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
for(int i = 0; i < m_All.m_Num; i++)
|
|
|
|
m_All.m_paComponents[i]->m_pClient = this;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-09-23 07:43:41 +00:00
|
|
|
// let all the other components register their console commands
|
2010-05-29 07:25:38 +00:00
|
|
|
for(int i = 0; i < m_All.m_Num; i++)
|
|
|
|
m_All.m_paComponents[i]->OnConsoleInit();
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
|
|
|
2009-06-15 14:01:36 +00:00
|
|
|
//
|
2010-05-29 07:25:38 +00:00
|
|
|
Console()->Chain("player_name", ConchainSpecialInfoupdate, this);
|
2011-03-20 10:17:51 +00:00
|
|
|
Console()->Chain("player_clan", ConchainSpecialInfoupdate, this);
|
|
|
|
Console()->Chain("player_country", ConchainSpecialInfoupdate, this);
|
2010-05-29 07:25:38 +00:00
|
|
|
Console()->Chain("player_use_custom_color", ConchainSpecialInfoupdate, this);
|
|
|
|
Console()->Chain("player_color_body", ConchainSpecialInfoupdate, this);
|
|
|
|
Console()->Chain("player_color_feet", ConchainSpecialInfoupdate, this);
|
|
|
|
Console()->Chain("player_skin", ConchainSpecialInfoupdate, this);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2014-04-28 13:19:57 +00:00
|
|
|
Console()->Chain("dummy_name", ConchainSpecialDummyInfoupdate, this);
|
|
|
|
Console()->Chain("dummy_clan", ConchainSpecialDummyInfoupdate, this);
|
|
|
|
Console()->Chain("dummy_country", ConchainSpecialDummyInfoupdate, this);
|
|
|
|
Console()->Chain("dummy_use_custom_color", ConchainSpecialDummyInfoupdate, this);
|
|
|
|
Console()->Chain("dummy_color_body", ConchainSpecialDummyInfoupdate, this);
|
|
|
|
Console()->Chain("dummy_color_feet", ConchainSpecialDummyInfoupdate, this);
|
|
|
|
Console()->Chain("dummy_skin", ConchainSpecialDummyInfoupdate, this);
|
|
|
|
|
2014-04-28 13:34:56 +00:00
|
|
|
Console()->Chain("cl_dummy", ConchainSpecialDummy, this);
|
|
|
|
|
2008-12-19 11:41:17 +00:00
|
|
|
//
|
2010-05-29 07:25:38 +00:00
|
|
|
m_SuppressEvents = false;
|
2008-09-04 21:36:44 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameClient::OnInit()
|
2008-09-04 21:36:44 +00:00
|
|
|
{
|
2011-12-31 09:29:25 +00:00
|
|
|
m_pGraphics = Kernel()->RequestInterface<IGraphics>();
|
|
|
|
|
|
|
|
// propagate pointers
|
|
|
|
m_UI.SetGraphics(Graphics(), TextRender());
|
|
|
|
m_RenderTools.m_pGraphics = Graphics();
|
|
|
|
m_RenderTools.m_pUI = UI();
|
2014-12-01 00:31:58 +00:00
|
|
|
|
2011-02-13 12:58:59 +00:00
|
|
|
int64 Start = time_get();
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
// set the language
|
2010-10-06 21:07:35 +00:00
|
|
|
g_Localization.Load(g_Config.m_ClLanguagefile, Storage(), Console());
|
2011-02-27 16:56:03 +00:00
|
|
|
|
|
|
|
// TODO: this should be different
|
2008-08-30 22:38:56 +00:00
|
|
|
// setup item sizes
|
|
|
|
for(int i = 0; i < NUM_NETOBJTYPES; i++)
|
2010-05-29 07:25:38 +00:00
|
|
|
Client()->SnapSetStaticsize(i, m_NetObjHandler.GetObjSize(i));
|
2011-02-27 16:56:03 +00:00
|
|
|
|
2011-04-13 18:37:12 +00:00
|
|
|
// load default font
|
2011-01-06 21:18:19 +00:00
|
|
|
static CFont *pDefaultFont = 0;
|
2010-10-06 21:07:35 +00:00
|
|
|
char aFilename[512];
|
2010-10-29 21:44:08 +00:00
|
|
|
IOHANDLE File = Storage()->OpenFile("fonts/DejaVuSans.ttf", IOFLAG_READ, IStorage::TYPE_ALL, aFilename, sizeof(aFilename));
|
2010-10-06 21:07:35 +00:00
|
|
|
if(File)
|
2011-01-06 21:18:19 +00:00
|
|
|
{
|
2010-10-06 21:07:35 +00:00
|
|
|
io_close(File);
|
2011-01-06 21:18:19 +00:00
|
|
|
pDefaultFont = TextRender()->LoadFont(aFilename);
|
|
|
|
TextRender()->SetDefaultFont(pDefaultFont);
|
|
|
|
}
|
|
|
|
if(!pDefaultFont)
|
|
|
|
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "gameclient", "failed to load font. filename='fonts/DejaVuSans.ttf'");
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-02-27 16:56:03 +00:00
|
|
|
// init all components
|
|
|
|
for(int i = m_All.m_Num-1; i >= 0; --i)
|
|
|
|
m_All.m_paComponents[i]->OnInit();
|
|
|
|
|
2014-04-27 22:41:19 +00:00
|
|
|
char aBuf[256];
|
|
|
|
|
2011-02-27 16:56:03 +00:00
|
|
|
// setup load amount// load textures
|
2010-05-29 07:25:38 +00:00
|
|
|
for(int i = 0; i < g_pData->m_NumImages; i++)
|
2008-08-30 22:38:56 +00:00
|
|
|
{
|
2010-10-06 21:07:35 +00:00
|
|
|
g_pData->m_aImages[i].m_Id = Graphics()->LoadTexture(g_pData->m_aImages[i].m_pFilename, IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0);
|
2011-02-27 16:56:03 +00:00
|
|
|
g_GameClient.m_pMenus->RenderLoading();
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
2008-10-08 18:19:45 +00:00
|
|
|
|
2014-06-16 11:29:18 +00:00
|
|
|
#if defined(__ANDROID__)
|
|
|
|
m_pMapimages->OnMapLoad(); // Reload map textures on Android
|
|
|
|
#endif
|
|
|
|
|
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
|
|
|
int64 End = time_get();
|
2010-09-29 17:55:33 +00:00
|
|
|
str_format(aBuf, sizeof(aBuf), "initialisation finished after %.2fms", ((End-Start)*1000)/(float)time_freq());
|
2010-08-17 22:06:00 +00:00
|
|
|
Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "gameclient", aBuf);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
m_ServerMode = SERVERMODE_PURE;
|
2011-01-06 03:46:10 +00:00
|
|
|
|
2014-04-27 11:44:04 +00:00
|
|
|
m_DDRaceMsgSent[0] = false;
|
|
|
|
m_DDRaceMsgSent[1] = false;
|
|
|
|
m_ShowOthers[0] = -1;
|
|
|
|
m_ShowOthers[1] = -1;
|
2011-04-17 17:14:49 +00:00
|
|
|
|
|
|
|
// Set free binds to DDRace binds if it's active
|
|
|
|
if(!g_Config.m_ClDDRaceBindsSet && g_Config.m_ClDDRaceBinds)
|
|
|
|
gs_Binds.SetDDRaceBinds(true);
|
2014-08-09 17:17:21 +00:00
|
|
|
|
2014-08-10 10:54:01 +00:00
|
|
|
if(g_Config.m_ClTimeoutCode[0] == '\0' || str_comp(g_Config.m_ClTimeoutCode, "hGuEYnfxicsXGwFq") == 0)
|
2014-08-09 17:17:21 +00:00
|
|
|
{
|
|
|
|
for(unsigned int i = 0; i < 16; i++)
|
|
|
|
{
|
|
|
|
if (rand() % 2)
|
|
|
|
g_Config.m_ClTimeoutCode[i] = (rand() % 26) + 97;
|
|
|
|
else
|
|
|
|
g_Config.m_ClTimeoutCode[i] = (rand() % 26) + 65;
|
|
|
|
}
|
|
|
|
}
|
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++)
|
|
|
|
{
|
|
|
|
if (rand() % 2)
|
|
|
|
g_Config.m_ClDummyTimeoutCode[i] = (rand() % 26) + 97;
|
|
|
|
else
|
|
|
|
g_Config.m_ClDummyTimeoutCode[i] = (rand() % 26) + 65;
|
|
|
|
}
|
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameClient::DispatchInput()
|
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);
|
2014-06-16 11:29:18 +00:00
|
|
|
#if !defined(__ANDROID__) // No relative mouse on Android
|
2010-10-13 10:47:42 +00:00
|
|
|
if(x != 0.0f || y != 0.0f)
|
2014-06-16 11:29:18 +00:00
|
|
|
#endif
|
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);
|
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
|
|
|
{
|
|
|
|
//dbg_msg("", "%d char=%d key=%d flags=%d", h, e.ch, e.key, e.flags);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// clear all events for this frame
|
2011-04-13 18:37:12 +00:00
|
|
|
Input()->ClearEvents();
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
int CGameClient::OnSnapInput(int *pData)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
return m_pControls->SnapInput(pData);
|
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
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
for(int i = 0; i < m_All.m_Num; i++)
|
2008-10-08 18:19:45 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
m_All.m_paComponents[i]->OnMapLoad();
|
|
|
|
m_All.m_paComponents[i]->OnReset();
|
2008-10-08 18:19:45 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
CServerInfo CurrentServerInfo;
|
|
|
|
Client()->GetServerInfo(&CurrentServerInfo);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
m_ServerMode = SERVERMODE_PURE;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// send the inital 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");
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameClient::OnReset()
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
|
|
|
// clear out the invalid pointers
|
2014-05-23 21:59:26 +00:00
|
|
|
m_LastNewPredictedTick[0] = -1;
|
|
|
|
m_LastNewPredictedTick[1] = -1;
|
2010-05-29 07:25:38 +00:00
|
|
|
mem_zero(&g_GameClient.m_Snap, sizeof(g_GameClient.m_Snap));
|
2008-08-27 15:48:50 +00:00
|
|
|
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
2011-03-22 21:41:27 +00:00
|
|
|
m_aClients[i].Reset();
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
for(int i = 0; i < m_All.m_Num; i++)
|
|
|
|
m_All.m_paComponents[i]->OnReset();
|
2011-01-06 03:46:10 +00:00
|
|
|
|
2011-03-12 17:07:57 +00:00
|
|
|
m_DemoSpecID = SPEC_FREEVIEW;
|
2011-07-05 21:15:24 +00:00
|
|
|
m_FlagDropTick[TEAM_RED] = 0;
|
|
|
|
m_FlagDropTick[TEAM_BLUE] = 0;
|
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;
|
2014-12-01 00:31:58 +00:00
|
|
|
|
|
|
|
for(int i = 0; i < 150; i++)
|
|
|
|
m_aWeaponData[i].m_Tick = -1;
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-03-10 09:08:14 +00:00
|
|
|
void CGameClient::UpdatePositions()
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2011-03-10 09:08:14 +00:00
|
|
|
// local character position
|
2010-05-29 07:25:38 +00:00
|
|
|
if(g_Config.m_ClPredict && Client()->State() != IClient::STATE_DEMOPLAYBACK)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2014-12-08 12:49:39 +00:00
|
|
|
if (!g_Config.m_ClAntiPingPlayers)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2013-10-09 14:02:23 +00:00
|
|
|
if(!m_Snap.m_pLocalCharacter || (m_Snap.m_pGameInfoObj && m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER))
|
|
|
|
{
|
|
|
|
// don't use predicted
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_LocalCharacterPos = mix(m_PredictedPrevChar.m_Pos, m_PredictedChar.m_Pos, Client()->PredIntraGameTick());
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
else
|
2013-10-09 14:02:23 +00:00
|
|
|
{
|
|
|
|
if(!(m_Snap.m_pGameInfoObj && m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER))
|
|
|
|
{
|
|
|
|
if (m_Snap.m_pLocalCharacter)
|
|
|
|
m_LocalCharacterPos = mix(m_PredictedPrevChar.m_Pos, m_PredictedChar.m_Pos, Client()->PredIntraGameTick());
|
|
|
|
}
|
|
|
|
// else
|
|
|
|
// m_LocalCharacterPos = mix(m_PredictedPrevChar.m_Pos, m_PredictedChar.m_Pos, Client()->PredIntraGameTick());
|
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
else if(m_Snap.m_pLocalCharacter && m_Snap.m_pLocalPrevCharacter)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
m_LocalCharacterPos = mix(
|
|
|
|
vec2(m_Snap.m_pLocalPrevCharacter->m_X, m_Snap.m_pLocalPrevCharacter->m_Y),
|
|
|
|
vec2(m_Snap.m_pLocalCharacter->m_X, m_Snap.m_pLocalCharacter->m_Y), Client()->IntraGameTick());
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2014-12-01 00:31:58 +00:00
|
|
|
|
2014-12-08 12:49:39 +00:00
|
|
|
if (g_Config.m_ClAntiPingPlayers)
|
2013-10-09 14:02:23 +00:00
|
|
|
{
|
|
|
|
for (int i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
{
|
|
|
|
if (!m_Snap.m_aCharacters[i].m_Active)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (m_Snap.m_pLocalCharacter && m_Snap.m_pLocalPrevCharacter && g_Config.m_ClPredict /* && g_Config.m_AntiPing */ && !(m_Snap.m_LocalClientID == -1 || !m_Snap.m_aCharacters[m_Snap.m_LocalClientID].m_Active))
|
|
|
|
m_Snap.m_aCharacters[i].m_Position = mix(m_aClients[i].m_PrevPredicted.m_Pos, m_aClients[i].m_Predicted.m_Pos, Client()->PredIntraGameTick());
|
|
|
|
else
|
|
|
|
m_Snap.m_aCharacters[i].m_Position = mix(vec2(m_Snap.m_aCharacters[i].m_Prev.m_X, m_Snap.m_aCharacters[i].m_Prev.m_Y), vec2(m_Snap.m_aCharacters[i].m_Cur.m_X, m_Snap.m_aCharacters[i].m_Cur.m_Y), Client()->IntraGameTick());
|
|
|
|
}
|
|
|
|
}
|
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
|
|
|
{
|
2011-03-12 17:07:57 +00:00
|
|
|
if(Client()->State() == IClient::STATE_DEMOPLAYBACK && DemoPlayer()->GetDemoType() == IDemoPlayer::DEMOTYPE_SERVER &&
|
|
|
|
m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW)
|
|
|
|
{
|
|
|
|
m_Snap.m_SpecInfo.m_Position = mix(
|
|
|
|
vec2(m_Snap.m_aCharacters[m_Snap.m_SpecInfo.m_SpectatorID].m_Prev.m_X, m_Snap.m_aCharacters[m_Snap.m_SpecInfo.m_SpectatorID].m_Prev.m_Y),
|
|
|
|
vec2(m_Snap.m_aCharacters[m_Snap.m_SpecInfo.m_SpectatorID].m_Cur.m_X, m_Snap.m_aCharacters[m_Snap.m_SpecInfo.m_SpectatorID].m_Cur.m_Y),
|
|
|
|
Client()->IntraGameTick());
|
|
|
|
m_Snap.m_SpecInfo.m_UsePosition = true;
|
|
|
|
}
|
|
|
|
else if(m_Snap.m_pSpectatorInfo && (Client()->State() == IClient::STATE_DEMOPLAYBACK || m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW))
|
|
|
|
{
|
|
|
|
if(m_Snap.m_pPrevSpectatorInfo)
|
|
|
|
m_Snap.m_SpecInfo.m_Position = mix(vec2(m_Snap.m_pPrevSpectatorInfo->m_X, m_Snap.m_pPrevSpectatorInfo->m_Y),
|
|
|
|
vec2(m_Snap.m_pSpectatorInfo->m_X, m_Snap.m_pSpectatorInfo->m_Y), Client()->IntraGameTick());
|
|
|
|
else
|
|
|
|
m_Snap.m_SpecInfo.m_Position = vec2(m_Snap.m_pSpectatorInfo->m_X, m_Snap.m_pSpectatorInfo->m_Y);
|
|
|
|
m_Snap.m_SpecInfo.m_UsePosition = true;
|
|
|
|
}
|
2011-03-10 09:08:14 +00:00
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
|
2008-10-06 18:05:01 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
static void Evolve(CNetObj_Character *pCharacter, int Tick)
|
2008-10-06 18:05:01 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
CWorldCore TempWorld;
|
|
|
|
CCharacterCore TempCore;
|
2010-09-30 20:31:11 +00:00
|
|
|
CTeamsCore TempTeams;
|
2010-05-29 07:25:38 +00:00
|
|
|
mem_zero(&TempCore, sizeof(TempCore));
|
2011-01-06 03:46:10 +00:00
|
|
|
mem_zero(&TempTeams, sizeof(TempTeams));
|
2010-09-30 20:31:11 +00:00
|
|
|
TempCore.Init(&TempWorld, g_GameClient.Collision(), &TempTeams);
|
2010-05-29 07:25:38 +00:00
|
|
|
TempCore.Read(pCharacter);
|
2014-04-14 08:56:14 +00:00
|
|
|
TempCore.m_ActiveWeapon = pCharacter->m_Weapon;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
while(pCharacter->m_Tick < Tick)
|
2008-10-06 18:05:01 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
pCharacter->m_Tick++;
|
2014-03-25 00:13:46 +00:00
|
|
|
TempCore.Tick(false, true);
|
2010-05-29 07:25:38 +00:00
|
|
|
TempCore.Move();
|
|
|
|
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
|
|
|
{
|
2009-10-27 14:38:53 +00:00
|
|
|
/*Graphics()->Clear(1,0,0);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2009-10-27 14:38:53 +00:00
|
|
|
menus->render_background();
|
|
|
|
return;*/
|
|
|
|
/*
|
|
|
|
Graphics()->Clear(1,0,0);
|
|
|
|
Graphics()->MapScreen(0,0,100,100);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2009-10-27 14:38:53 +00:00
|
|
|
Graphics()->QuadsBegin();
|
|
|
|
Graphics()->SetColor(1,1,1,1);
|
|
|
|
Graphics()->QuadsDraw(50, 50, 30, 30);
|
|
|
|
Graphics()->QuadsEnd();
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2009-10-27 14:38:53 +00:00
|
|
|
return;*/
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-03-10 09:08:14 +00:00
|
|
|
// update the local character and spectate position
|
|
|
|
UpdatePositions();
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// dispatch all input to systems
|
2010-05-29 07:25:38 +00:00
|
|
|
DispatchInput();
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// render all systems
|
2010-05-29 07:25:38 +00:00
|
|
|
for(int i = 0; i < m_All.m_Num; i++)
|
|
|
|
m_All.m_paComponents[i]->OnRender();
|
2011-04-13 18:37:12 +00:00
|
|
|
|
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-12-08 12:49:39 +00:00
|
|
|
if(g_Config.m_ClAntiPing != m_CurrentAntiPing)
|
|
|
|
{
|
|
|
|
g_Config.m_ClAntiPingPlayers = g_Config.m_ClAntiPing;
|
|
|
|
g_Config.m_ClAntiPingGrenade = g_Config.m_ClAntiPing;
|
|
|
|
g_Config.m_ClAntiPingWeapons = g_Config.m_ClAntiPing;
|
|
|
|
m_CurrentAntiPing = g_Config.m_ClAntiPing;
|
|
|
|
}
|
|
|
|
|
2014-04-28 13:34:56 +00:00
|
|
|
if(g_Config.m_ClDummy && !Client()->DummyConnected())
|
|
|
|
g_Config.m_ClDummy = 0;
|
|
|
|
|
2015-04-19 11:11:45 +00:00
|
|
|
// resend player and dummy info if it was filtered by server
|
|
|
|
if(Client()->State() == IClient::STATE_ONLINE && !m_pMenus->IsActive()) {
|
2015-04-19 12:03:40 +00:00
|
|
|
if(m_CheckInfo[0] == 0) {
|
2015-04-19 11:11:45 +00:00
|
|
|
if(
|
|
|
|
str_comp(m_aClients[Client()->m_LocalIDs[0]].m_aName, g_Config.m_PlayerName) ||
|
|
|
|
str_comp(m_aClients[Client()->m_LocalIDs[0]].m_aClan, g_Config.m_PlayerClan) ||
|
|
|
|
m_aClients[Client()->m_LocalIDs[0]].m_Country != g_Config.m_PlayerCountry ||
|
|
|
|
str_comp(m_aClients[Client()->m_LocalIDs[0]].m_aSkinName, g_Config.m_PlayerSkin) ||
|
|
|
|
m_aClients[Client()->m_LocalIDs[0]].m_UseCustomColor != g_Config.m_PlayerUseCustomColor ||
|
|
|
|
m_aClients[Client()->m_LocalIDs[0]].m_ColorBody != g_Config.m_PlayerColorBody ||
|
|
|
|
m_aClients[Client()->m_LocalIDs[0]].m_ColorFeet != g_Config.m_PlayerColorFeet
|
|
|
|
)
|
2014-04-28 13:19:57 +00:00
|
|
|
SendInfo(false);
|
2015-04-19 11:11:45 +00:00
|
|
|
else
|
2015-04-19 12:03:40 +00:00
|
|
|
m_CheckInfo[0] = -1;
|
2015-04-19 11:11:45 +00:00
|
|
|
}
|
|
|
|
|
2015-04-19 12:03:40 +00:00
|
|
|
if(m_CheckInfo[0] > 0)
|
|
|
|
m_CheckInfo[0]--;
|
2015-04-19 11:11:45 +00:00
|
|
|
|
|
|
|
if(Client()->DummyConnected()) {
|
2015-04-19 12:03:40 +00:00
|
|
|
if(m_CheckInfo[1] == 0) {
|
2015-04-19 11:11:45 +00:00
|
|
|
if(
|
|
|
|
str_comp(m_aClients[Client()->m_LocalIDs[1]].m_aName, g_Config.m_DummyName) ||
|
|
|
|
str_comp(m_aClients[Client()->m_LocalIDs[1]].m_aClan, g_Config.m_DummyClan) ||
|
|
|
|
m_aClients[Client()->m_LocalIDs[1]].m_Country != g_Config.m_DummyCountry ||
|
|
|
|
str_comp(m_aClients[Client()->m_LocalIDs[1]].m_aSkinName, g_Config.m_DummySkin) ||
|
|
|
|
m_aClients[Client()->m_LocalIDs[1]].m_UseCustomColor != g_Config.m_DummyUseCustomColor ||
|
|
|
|
m_aClients[Client()->m_LocalIDs[1]].m_ColorBody != g_Config.m_DummyColorBody ||
|
|
|
|
m_aClients[Client()->m_LocalIDs[1]].m_ColorFeet != g_Config.m_DummyColorFeet
|
|
|
|
)
|
|
|
|
SendDummyInfo(false);
|
|
|
|
else
|
2015-04-19 12:03:40 +00:00
|
|
|
m_CheckInfo[1] = -1;
|
2015-04-19 11:11:45 +00:00
|
|
|
}
|
|
|
|
|
2015-04-19 12:03:40 +00:00
|
|
|
if(m_CheckInfo[1] > 0)
|
|
|
|
m_CheckInfo[1]--;
|
2010-05-29 07:25:38 +00:00
|
|
|
}
|
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
|
2014-04-28 14:47:44 +00:00
|
|
|
void CGameClient::OnDummyDisconnect()
|
|
|
|
{
|
|
|
|
m_DDRaceMsgSent[1] = false;
|
|
|
|
m_ShowOthers[1] = -1;
|
2014-05-23 21:59:26 +00:00
|
|
|
m_LastNewPredictedTick[1] = -1;
|
2014-04-28 14:47:44 +00:00
|
|
|
}
|
|
|
|
|
2010-09-12 10:43:03 +00:00
|
|
|
void CGameClient::OnRelease()
|
|
|
|
{
|
|
|
|
// release all systems
|
|
|
|
for(int i = 0; i < m_All.m_Num; i++)
|
|
|
|
m_All.m_paComponents[i]->OnRelease();
|
|
|
|
}
|
|
|
|
|
2014-05-03 00:30:05 +00:00
|
|
|
void CGameClient::OnMessage(int MsgId, CUnpacker *pUnpacker, bool IsDummy)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2008-08-29 05:34:18 +00:00
|
|
|
// special messages
|
2014-05-03 00:30:05 +00:00
|
|
|
if(MsgId == NETMSGTYPE_SV_EXTRAPROJECTILE && !IsDummy)
|
2008-08-29 05:34:18 +00:00
|
|
|
{
|
2011-04-03 08:11:23 +00:00
|
|
|
int Num = pUnpacker->GetInt();
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-04-03 08:11:23 +00:00
|
|
|
for(int k = 0; k < Num; k++)
|
2008-08-29 05:34:18 +00:00
|
|
|
{
|
2011-04-03 08:11:23 +00:00
|
|
|
CNetObj_Projectile Proj;
|
|
|
|
for(unsigned i = 0; i < sizeof(CNetObj_Projectile)/sizeof(int); i++)
|
|
|
|
((int *)&Proj)[i] = pUnpacker->GetInt();
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-04-03 08:11:23 +00:00
|
|
|
if(pUnpacker->Error())
|
2008-08-29 05:34:18 +00:00
|
|
|
return;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-04-03 08:11:23 +00:00
|
|
|
g_GameClient.m_pItems->AddExtraProjectile(&Proj);
|
2014-12-01 00:31:58 +00:00
|
|
|
|
|
|
|
if(g_Config.m_ClAntiPingWeapons && Proj.m_Type == WEAPON_GRENADE && !UseExtraInfo(&Proj))
|
|
|
|
{
|
|
|
|
vec2 StartPos;
|
|
|
|
vec2 Direction;
|
|
|
|
ExtractInfo(&Proj, &StartPos, &Direction, 1);
|
|
|
|
if(CWeaponData *pCurrentData = GetWeaponData(Proj.m_StartTick))
|
|
|
|
{
|
|
|
|
if(CWeaponData *pMatchingData = FindWeaponData(Proj.m_StartTick))
|
|
|
|
{
|
|
|
|
if(distance(pMatchingData->m_Direction, Direction) < 0.015)
|
|
|
|
Direction = pMatchingData->m_Direction;
|
|
|
|
else if(int *pData = Client()->GetInput(Proj.m_StartTick+2))
|
|
|
|
{
|
|
|
|
CNetObj_PlayerInput *pNextInput = (CNetObj_PlayerInput*) pData;
|
|
|
|
vec2 NextDirection = normalize(vec2(pNextInput->m_TargetX, pNextInput->m_TargetY));
|
|
|
|
if(distance(NextDirection, Direction) < 0.015)
|
|
|
|
Direction = NextDirection;
|
|
|
|
}
|
|
|
|
if(distance(pMatchingData->StartPos(), StartPos) < 1)
|
|
|
|
StartPos = pMatchingData->StartPos();
|
|
|
|
}
|
|
|
|
pCurrentData->m_Tick = Proj.m_StartTick;
|
|
|
|
pCurrentData->m_Direction = Direction;
|
|
|
|
pCurrentData->m_Pos = StartPos - Direction * 28.0f * 0.75f;
|
|
|
|
}
|
|
|
|
}
|
2008-08-29 05:34:18 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-04-03 08:11:23 +00:00
|
|
|
return;
|
2008-08-29 05:34:18 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
else if(MsgId == NETMSGTYPE_SV_TUNEPARAMS)
|
2008-08-29 05:34:18 +00:00
|
|
|
{
|
|
|
|
// unpack the new tuning
|
2010-05-29 07:25:38 +00:00
|
|
|
CTuningParams NewTuning;
|
|
|
|
int *pParams = (int *)&NewTuning;
|
2015-01-09 21:18:11 +00:00
|
|
|
// No jetpack on DDNet incompatible servers:
|
|
|
|
NewTuning.m_JetpackStrength = 0;
|
2010-05-29 07:25:38 +00:00
|
|
|
for(unsigned i = 0; i < sizeof(CTuningParams)/sizeof(int); i++)
|
2014-04-12 09:12:29 +00:00
|
|
|
{
|
2014-12-27 11:05:02 +00:00
|
|
|
int value = pUnpacker->GetInt();
|
2008-08-29 05:34:18 +00:00
|
|
|
|
2014-04-12 09:12:29 +00:00
|
|
|
// check for unpacking errors
|
|
|
|
if(pUnpacker->Error())
|
|
|
|
break;
|
2014-12-27 11:05:02 +00:00
|
|
|
|
|
|
|
pParams[i] = value;
|
2014-04-12 09:12:29 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
m_ServerMode = SERVERMODE_PURE;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-08-29 05:34:18 +00:00
|
|
|
// apply new tuning
|
2014-05-03 00:30:05 +00:00
|
|
|
m_Tuning[IsDummy ? !g_Config.m_ClDummy : g_Config.m_ClDummy] = NewTuning;
|
2008-08-29 05:34:18 +00:00
|
|
|
return;
|
|
|
|
}
|
2014-12-01 00:31:58 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void *pRawMsg = m_NetObjHandler.SecureUnpackMsg(MsgId, pUnpacker);
|
|
|
|
if(!pRawMsg)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-08-17 22:06:00 +00:00
|
|
|
char aBuf[256];
|
|
|
|
str_format(aBuf, sizeof(aBuf), "dropped weird message '%s' (%d), failed on '%s'", m_NetObjHandler.GetMsgName(MsgId), MsgId, m_NetObjHandler.FailedMsgOn());
|
|
|
|
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client", aBuf);
|
2008-08-27 15:48:50 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-05-07 01:34:21 +00:00
|
|
|
if(IsDummy)
|
|
|
|
{
|
|
|
|
if(MsgId == NETMSGTYPE_SV_CHAT
|
|
|
|
&& Client()->m_LocalIDs[0] >= 0
|
|
|
|
&& Client()->m_LocalIDs[1] >= 0)
|
|
|
|
{
|
|
|
|
CNetMsg_Sv_Chat *pMsg = (CNetMsg_Sv_Chat *)pRawMsg;
|
|
|
|
|
|
|
|
if((pMsg->m_Team == 1
|
|
|
|
&& (m_aClients[Client()->m_LocalIDs[0]].m_Team != m_aClients[Client()->m_LocalIDs[1]].m_Team
|
|
|
|
|| m_Teams.Team(Client()->m_LocalIDs[0]) != m_Teams.Team(Client()->m_LocalIDs[1])))
|
|
|
|
|| pMsg->m_Team > 1)
|
|
|
|
{
|
|
|
|
m_pChat->OnMessage(MsgId, pRawMsg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return; // no need of all that stuff for the dummy
|
|
|
|
}
|
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// TODO: this should be done smarter
|
2010-05-29 07:25:38 +00:00
|
|
|
for(int i = 0; i < m_All.m_Num; i++)
|
|
|
|
m_All.m_paComponents[i]->OnMessage(MsgId, pRawMsg);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(MsgId == NETMSGTYPE_SV_READYTOENTER)
|
2008-08-27 20:17:04 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
Client()->EnterGame();
|
2008-08-27 20:17:04 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
else if (MsgId == NETMSGTYPE_SV_EMOTICON)
|
2008-08-27 20:17:04 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
CNetMsg_Sv_Emoticon *pMsg = (CNetMsg_Sv_Emoticon *)pRawMsg;
|
2008-08-27 20:17:04 +00:00
|
|
|
|
|
|
|
// apply
|
2011-02-12 10:40:36 +00:00
|
|
|
m_aClients[pMsg->m_ClientID].m_Emoticon = pMsg->m_Emoticon;
|
|
|
|
m_aClients[pMsg->m_ClientID].m_EmoticonStart = Client()->GameTick();
|
2008-08-27 20:17:04 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
else if(MsgId == NETMSGTYPE_SV_SOUNDGLOBAL)
|
2008-08-27 20:17:04 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(m_SuppressEvents)
|
2009-01-11 15:51:43 +00:00
|
|
|
return;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-07-17 17:55:17 +00:00
|
|
|
// don't enqueue pseudo-global sounds from demos (created by PlayAndRecord)
|
2010-05-29 07:25:38 +00:00
|
|
|
CNetMsg_Sv_SoundGlobal *pMsg = (CNetMsg_Sv_SoundGlobal *)pRawMsg;
|
2011-02-12 10:40:36 +00:00
|
|
|
if(pMsg->m_SoundID == SOUND_CTF_DROP || pMsg->m_SoundID == SOUND_CTF_RETURN ||
|
|
|
|
pMsg->m_SoundID == SOUND_CTF_CAPTURE || pMsg->m_SoundID == SOUND_CTF_GRAB_EN ||
|
|
|
|
pMsg->m_SoundID == SOUND_CTF_GRAB_PL)
|
2014-10-25 00:52:08 +00:00
|
|
|
{
|
|
|
|
if(g_Config.m_SndGame)
|
|
|
|
g_GameClient.m_pSounds->Enqueue(CSounds::CHN_GLOBAL, pMsg->m_SoundID);
|
|
|
|
}
|
2010-07-17 17:55:17 +00:00
|
|
|
else
|
2014-10-25 00:52:08 +00:00
|
|
|
{
|
|
|
|
if(g_Config.m_SndGame)
|
|
|
|
g_GameClient.m_pSounds->Play(CSounds::CHN_GLOBAL, pMsg->m_SoundID, 1.0f);
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
}
|
2014-01-21 23:08:30 +00:00
|
|
|
else if(MsgId == NETMSGTYPE_SV_TEAMSSTATE)
|
2011-01-06 05:30:19 +00:00
|
|
|
{
|
2014-01-21 23:08:30 +00:00
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for(i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
{
|
2014-02-08 22:41:12 +00:00
|
|
|
int Team = pUnpacker->GetInt();
|
|
|
|
bool WentWrong = false;
|
2014-01-21 23:08:30 +00:00
|
|
|
|
|
|
|
if(pUnpacker->Error())
|
2014-02-08 22:41:12 +00:00
|
|
|
WentWrong = true;
|
|
|
|
|
|
|
|
if(!WentWrong && Team >= 0 && Team < MAX_CLIENTS)
|
|
|
|
m_Teams.Team(i, Team);
|
2014-02-08 22:46:55 +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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i <= 16)
|
|
|
|
m_Teams.m_IsDDRace16 = true;
|
2011-01-06 05:30:19 +00:00
|
|
|
}
|
|
|
|
else if(MsgId == NETMSGTYPE_SV_PLAYERTIME)
|
|
|
|
{
|
2010-11-04 16:39:04 +00:00
|
|
|
CNetMsg_Sv_PlayerTime *pMsg = (CNetMsg_Sv_PlayerTime *)pRawMsg;
|
2011-02-13 05:35:13 +00:00
|
|
|
m_aClients[pMsg->m_ClientID].m_Score = pMsg->m_Time;
|
2010-10-24 10:47:25 +00:00
|
|
|
}
|
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()
|
|
|
|
{
|
|
|
|
m_pRaceDemo->OnShutdown();
|
|
|
|
}
|
|
|
|
|
2014-09-03 12:17:44 +00:00
|
|
|
void CGameClient::OnEnterGame()
|
|
|
|
{
|
|
|
|
g_GameClient.m_pEffects->ResetDamageIndicator();
|
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2010-12-12 15:48:13 +00:00
|
|
|
void CGameClient::OnGameOver()
|
|
|
|
{
|
2012-04-19 23:04:12 +00:00
|
|
|
if(Client()->State() != IClient::STATE_DEMOPLAYBACK && g_Config.m_ClEditor == 0)
|
2010-12-12 15:48:13 +00:00
|
|
|
Client()->AutoScreenshot_Start();
|
|
|
|
}
|
|
|
|
|
2011-01-06 22:21:51 +00:00
|
|
|
void CGameClient::OnStartGame()
|
|
|
|
{
|
|
|
|
if(Client()->State() != IClient::STATE_DEMOPLAYBACK)
|
|
|
|
Client()->DemoRecorder_HandleAutoStart();
|
|
|
|
}
|
|
|
|
|
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;
|
2014-10-25 23:00:30 +00:00
|
|
|
if(g_Config.m_SndGame && (ev->m_SoundID != SOUND_GUN_FIRE || g_Config.m_SndGun))
|
2014-10-25 00:52:08 +00:00
|
|
|
g_GameClient.m_pSounds->PlayAt(CSounds::CHN_WORLD, ev->m_SoundID, 1.0f, vec2(ev->m_X, ev->m_Y));
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameClient::OnNewSnapshot()
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
m_NewTick = true;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// clear out the invalid pointers
|
2010-05-29 07:25:38 +00:00
|
|
|
mem_zero(&g_GameClient.m_Snap, sizeof(g_GameClient.m_Snap));
|
2011-02-12 10:40:36 +00:00
|
|
|
m_Snap.m_LocalClientID = -1;
|
2008-08-27 15:48:50 +00:00
|
|
|
|
|
|
|
// secure snapshot
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
int Num = Client()->SnapNumItems(IClient::SNAP_CURRENT);
|
|
|
|
for(int Index = 0; Index < Num; Index++)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
IClient::CSnapItem Item;
|
|
|
|
void *pData = Client()->SnapGetItem(IClient::SNAP_CURRENT, Index, &Item);
|
|
|
|
if(m_NetObjHandler.ValidateObj(Item.m_Type, pData, Item.m_DataSize) != 0)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(g_Config.m_Debug)
|
2010-08-17 22:06:00 +00:00
|
|
|
{
|
|
|
|
char aBuf[256];
|
2011-02-12 10:40:36 +00:00
|
|
|
str_format(aBuf, sizeof(aBuf), "invalidated index=%d type=%d (%s) size=%d id=%d", Index, Item.m_Type, m_NetObjHandler.GetObjName(Item.m_Type), Item.m_DataSize, Item.m_ID);
|
2010-08-17 22:06:00 +00:00
|
|
|
Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "game", aBuf);
|
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
Client()->SnapInvalidateItem(IClient::SNAP_CURRENT, Index);
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
ProcessEvents();
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(g_Config.m_DbgStress)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if((Client()->GameTick()%100) == 0)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
char aMessage[64];
|
|
|
|
int MsgLen = rand()%(sizeof(aMessage)-1);
|
|
|
|
for(int i = 0; i < MsgLen; i++)
|
|
|
|
aMessage[i] = 'a'+(rand()%('z'-'a'));
|
|
|
|
aMessage[MsgLen] = 0;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
CNetMsg_Cl_Say Msg;
|
|
|
|
Msg.m_Team = rand()&1;
|
|
|
|
Msg.m_pMessage = aMessage;
|
|
|
|
Client()->SendPackMsg(&Msg, MSGFLAG_VITAL);
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-23 07:43:41 +00:00
|
|
|
// go trough all the items in the snapshot and gather the info we want
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2011-01-03 11:50:38 +00:00
|
|
|
m_Snap.m_aTeamSize[TEAM_RED] = m_Snap.m_aTeamSize[TEAM_BLUE] = 0;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
int Num = Client()->SnapNumItems(IClient::SNAP_CURRENT);
|
|
|
|
for(int i = 0; i < Num; i++)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
IClient::CSnapItem Item;
|
|
|
|
const void *pData = Client()->SnapGetItem(IClient::SNAP_CURRENT, i, &Item);
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(Item.m_Type == NETOBJTYPE_CLIENTINFO)
|
2008-10-08 20:47:56 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
const CNetObj_ClientInfo *pInfo = (const CNetObj_ClientInfo *)pData;
|
2011-02-12 10:40:36 +00:00
|
|
|
int ClientID = Item.m_ID;
|
2011-03-15 10:23:49 +00:00
|
|
|
IntsToStr(&pInfo->m_Name0, 4, m_aClients[ClientID].m_aName);
|
|
|
|
IntsToStr(&pInfo->m_Clan0, 3, m_aClients[ClientID].m_aClan);
|
2011-06-29 20:27:32 +00:00
|
|
|
m_aClients[ClientID].m_Country = pInfo->m_Country;
|
2011-02-12 10:40:36 +00:00
|
|
|
IntsToStr(&pInfo->m_Skin0, 6, m_aClients[ClientID].m_aSkinName);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-02-12 10:40:36 +00:00
|
|
|
m_aClients[ClientID].m_UseCustomColor = pInfo->m_UseCustomColor;
|
|
|
|
m_aClients[ClientID].m_ColorBody = pInfo->m_ColorBody;
|
|
|
|
m_aClients[ClientID].m_ColorFeet = pInfo->m_ColorFeet;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-10-08 20:47:56 +00:00
|
|
|
// prepare the info
|
2011-02-12 10:40:36 +00:00
|
|
|
if(m_aClients[ClientID].m_aSkinName[0] == 'x' || m_aClients[ClientID].m_aSkinName[1] == '_')
|
|
|
|
str_copy(m_aClients[ClientID].m_aSkinName, "default", 64);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-02-12 10:40:36 +00:00
|
|
|
m_aClients[ClientID].m_SkinInfo.m_ColorBody = m_pSkins->GetColorV4(m_aClients[ClientID].m_ColorBody);
|
|
|
|
m_aClients[ClientID].m_SkinInfo.m_ColorFeet = m_pSkins->GetColorV4(m_aClients[ClientID].m_ColorFeet);
|
|
|
|
m_aClients[ClientID].m_SkinInfo.m_Size = 64;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-10-08 20:47:56 +00:00
|
|
|
// find new skin
|
2015-03-14 11:30:17 +00:00
|
|
|
m_aClients[ClientID].m_SkinID = g_GameClient.m_pSkins->Find(m_aClients[ClientID].m_aSkinName);
|
2011-02-12 10:40:36 +00:00
|
|
|
if(m_aClients[ClientID].m_SkinID < 0)
|
2009-01-21 21:00:06 +00:00
|
|
|
{
|
2011-02-12 10:40:36 +00:00
|
|
|
m_aClients[ClientID].m_SkinID = g_GameClient.m_pSkins->Find("default");
|
|
|
|
if(m_aClients[ClientID].m_SkinID < 0)
|
|
|
|
m_aClients[ClientID].m_SkinID = 0;
|
2009-01-21 21:00:06 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-02-12 10:40:36 +00:00
|
|
|
if(m_aClients[ClientID].m_UseCustomColor)
|
|
|
|
m_aClients[ClientID].m_SkinInfo.m_Texture = g_GameClient.m_pSkins->Get(m_aClients[ClientID].m_SkinID)->m_ColorTexture;
|
2008-10-08 20:47:56 +00:00
|
|
|
else
|
|
|
|
{
|
2011-02-12 10:40:36 +00:00
|
|
|
m_aClients[ClientID].m_SkinInfo.m_Texture = g_GameClient.m_pSkins->Get(m_aClients[ClientID].m_SkinID)->m_OrgTexture;
|
|
|
|
m_aClients[ClientID].m_SkinInfo.m_ColorBody = vec4(1,1,1,1);
|
|
|
|
m_aClients[ClientID].m_SkinInfo.m_ColorFeet = vec4(1,1,1,1);
|
2008-10-08 20:47:56 +00:00
|
|
|
}
|
|
|
|
|
2011-02-12 10:40:36 +00:00
|
|
|
m_aClients[ClientID].UpdateRenderInfo();
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-10-08 20:47:56 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
else if(Item.m_Type == NETOBJTYPE_PLAYERINFO)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
const CNetObj_PlayerInfo *pInfo = (const CNetObj_PlayerInfo *)pData;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-02-12 10:40:36 +00:00
|
|
|
m_aClients[pInfo->m_ClientID].m_Team = pInfo->m_Team;
|
2011-03-22 21:41:27 +00:00
|
|
|
m_aClients[pInfo->m_ClientID].m_Active = true;
|
2011-02-12 10:40:36 +00:00
|
|
|
m_Snap.m_paPlayerInfos[pInfo->m_ClientID] = pInfo;
|
2011-03-22 21:41:27 +00:00
|
|
|
m_Snap.m_NumPlayers++;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(pInfo->m_Local)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2011-02-12 10:40:36 +00:00
|
|
|
m_Snap.m_LocalClientID = Item.m_ID;
|
2010-05-29 07:25:38 +00:00
|
|
|
m_Snap.m_pLocalInfo = pInfo;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-01-03 11:50:38 +00:00
|
|
|
if(pInfo->m_Team == TEAM_SPECTATORS)
|
2011-03-12 17:07:57 +00:00
|
|
|
{
|
|
|
|
m_Snap.m_SpecInfo.m_Active = true;
|
|
|
|
m_Snap.m_SpecInfo.m_SpectatorID = SPEC_FREEVIEW;
|
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-09-01 18:17:01 +00:00
|
|
|
// calculate team-balance
|
2011-01-03 11:50:38 +00:00
|
|
|
if(pInfo->m_Team != TEAM_SPECTATORS)
|
2010-05-29 07:25:38 +00:00
|
|
|
m_Snap.m_aTeamSize[pInfo->m_Team]++;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
else if(Item.m_Type == NETOBJTYPE_CHARACTER)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2011-02-12 10:40:36 +00:00
|
|
|
const void *pOld = Client()->SnapFindItem(IClient::SNAP_PREV, NETOBJTYPE_CHARACTER, Item.m_ID);
|
2011-03-10 09:08:14 +00:00
|
|
|
m_Snap.m_aCharacters[Item.m_ID].m_Cur = *((const CNetObj_Character *)pData);
|
2010-05-29 07:25:38 +00:00
|
|
|
if(pOld)
|
2008-09-23 07:43:41 +00:00
|
|
|
{
|
2011-02-12 10:40:36 +00:00
|
|
|
m_Snap.m_aCharacters[Item.m_ID].m_Active = true;
|
|
|
|
m_Snap.m_aCharacters[Item.m_ID].m_Prev = *((const CNetObj_Character *)pOld);
|
|
|
|
|
|
|
|
if(m_Snap.m_aCharacters[Item.m_ID].m_Prev.m_Tick)
|
|
|
|
Evolve(&m_Snap.m_aCharacters[Item.m_ID].m_Prev, Client()->PrevGameTick());
|
|
|
|
if(m_Snap.m_aCharacters[Item.m_ID].m_Cur.m_Tick)
|
|
|
|
Evolve(&m_Snap.m_aCharacters[Item.m_ID].m_Cur, Client()->GameTick());
|
2008-09-23 07:43:41 +00:00
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
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;
|
|
|
|
m_Snap.m_pGameInfoObj = (const CNetObj_GameInfo *)pData;
|
|
|
|
if(!s_GameOver && m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER)
|
2010-12-12 15:48:13 +00:00
|
|
|
OnGameOver();
|
2011-03-04 16:08:10 +00:00
|
|
|
else if(s_GameOver && !(m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER))
|
2011-01-06 22:21:51 +00:00
|
|
|
OnStartGame();
|
2011-03-04 16:08:10 +00:00
|
|
|
s_GameOver = m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER;
|
|
|
|
}
|
|
|
|
else if(Item.m_Type == NETOBJTYPE_GAMEDATA)
|
|
|
|
{
|
|
|
|
m_Snap.m_pGameDataObj = (const CNetObj_GameData *)pData;
|
|
|
|
m_Snap.m_GameDataSnapID = Item.m_ID;
|
2011-07-05 21:15:24 +00:00
|
|
|
if(m_Snap.m_pGameDataObj->m_FlagCarrierRed == FLAG_TAKEN)
|
|
|
|
{
|
|
|
|
if(m_FlagDropTick[TEAM_RED] == 0)
|
|
|
|
m_FlagDropTick[TEAM_RED] = Client()->GameTick();
|
|
|
|
}
|
|
|
|
else if(m_FlagDropTick[TEAM_RED] != 0)
|
|
|
|
m_FlagDropTick[TEAM_RED] = 0;
|
|
|
|
if(m_Snap.m_pGameDataObj->m_FlagCarrierBlue == FLAG_TAKEN)
|
|
|
|
{
|
|
|
|
if(m_FlagDropTick[TEAM_BLUE] == 0)
|
|
|
|
m_FlagDropTick[TEAM_BLUE] = Client()->GameTick();
|
|
|
|
}
|
|
|
|
else if(m_FlagDropTick[TEAM_BLUE] != 0)
|
|
|
|
m_FlagDropTick[TEAM_BLUE] = 0;
|
2010-12-12 15:48:13 +00:00
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
else if(Item.m_Type == NETOBJTYPE_FLAG)
|
2011-02-12 10:40:36 +00:00
|
|
|
m_Snap.m_paFlags[Item.m_ID%2] = (const CNetObj_Flag *)pData;
|
2008-09-23 07:43:41 +00:00
|
|
|
}
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-09-23 07:43:41 +00:00
|
|
|
// setup local pointers
|
2011-02-12 10:40:36 +00:00
|
|
|
if(m_Snap.m_LocalClientID >= 0)
|
2008-09-23 07:43:41 +00:00
|
|
|
{
|
2011-02-12 10:40:36 +00:00
|
|
|
CSnapState::CCharacterInfo *c = &m_Snap.m_aCharacters[m_Snap.m_LocalClientID];
|
2010-05-29 07:25:38 +00:00
|
|
|
if(c->m_Active)
|
2008-09-23 07:43:41 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
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
|
|
|
}
|
2008-11-16 13:58:27 +00:00
|
|
|
else
|
2011-03-12 17:07:57 +00:00
|
|
|
{
|
|
|
|
m_Snap.m_SpecInfo.m_Active = true;
|
|
|
|
if(Client()->State() == IClient::STATE_DEMOPLAYBACK && DemoPlayer()->GetDemoType() == IDemoPlayer::DEMOTYPE_SERVER &&
|
|
|
|
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-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)
|
|
|
|
m_aClients[i].Reset();
|
|
|
|
}
|
|
|
|
|
2011-03-23 12:06:35 +00:00
|
|
|
// update friend state
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; ++i)
|
|
|
|
{
|
2011-04-02 17:51:05 +00:00
|
|
|
if(i == m_Snap.m_LocalClientID || !m_Snap.m_paPlayerInfos[i] || !Friends()->IsFriend(m_aClients[i].m_aName, m_aClients[i].m_aClan, true))
|
2011-03-23 12:06:35 +00:00
|
|
|
m_aClients[i].m_Friend = false;
|
|
|
|
else
|
|
|
|
m_aClients[i].m_Friend = true;
|
|
|
|
}
|
2011-01-11 22:03:01 +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));
|
|
|
|
for(int k = 0; k < MAX_CLIENTS-1; k++) // ffs, bubblesort
|
|
|
|
{
|
|
|
|
for(int i = 0; i < MAX_CLIENTS-k-1; i++)
|
|
|
|
{
|
2014-07-27 09:41:31 +00:00
|
|
|
if(m_Snap.m_paInfoByName[i+1] && (!m_Snap.m_paInfoByName[i] || str_comp_nocase(m_aClients[m_Snap.m_paInfoByName[i]->m_ClientID].m_aName, m_aClients[m_Snap.m_paInfoByName[i+1]->m_ClientID].m_aName) > 0))
|
2014-02-08 21:24:57 +00:00
|
|
|
{
|
|
|
|
const CNetObj_PlayerInfo *pTmp = m_Snap.m_paInfoByName[i];
|
|
|
|
m_Snap.m_paInfoByName[i] = m_Snap.m_paInfoByName[i+1];
|
|
|
|
m_Snap.m_paInfoByName[i+1] = pTmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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));
|
2011-01-11 22:03:01 +00:00
|
|
|
for(int k = 0; k < MAX_CLIENTS-1; k++) // ffs, bubblesort
|
|
|
|
{
|
|
|
|
for(int i = 0; i < MAX_CLIENTS-k-1; i++)
|
|
|
|
{
|
|
|
|
if(m_Snap.m_paInfoByScore[i+1] && (!m_Snap.m_paInfoByScore[i] || m_Snap.m_paInfoByScore[i]->m_Score < m_Snap.m_paInfoByScore[i+1]->m_Score))
|
|
|
|
{
|
|
|
|
const CNetObj_PlayerInfo *pTmp = m_Snap.m_paInfoByScore[i];
|
|
|
|
m_Snap.m_paInfoByScore[i] = m_Snap.m_paInfoByScore[i+1];
|
|
|
|
m_Snap.m_paInfoByScore[i+1] = pTmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-02-08 21:24:57 +00:00
|
|
|
|
2011-08-04 21:43:39 +00:00
|
|
|
// sort player infos by team
|
2014-09-23 07:52:18 +00:00
|
|
|
//int Teams[3] = { TEAM_RED, TEAM_BLUE, TEAM_SPECTATORS };
|
2011-08-04 21:43:39 +00:00
|
|
|
int Index = 0;
|
2014-09-23 07:52:18 +00:00
|
|
|
//for(int Team = 0; Team < 3; ++Team)
|
|
|
|
//{
|
|
|
|
// for(int i = 0; i < MAX_CLIENTS && Index < MAX_CLIENTS; ++i)
|
|
|
|
// {
|
|
|
|
// if(m_Snap.m_paPlayerInfos[i] && m_Snap.m_paPlayerInfos[i]->m_Team == Teams[Team])
|
|
|
|
// m_Snap.m_paInfoByTeam[Index++] = m_Snap.m_paPlayerInfos[i];
|
|
|
|
// }
|
|
|
|
//}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2014-01-22 00:39:18 +00:00
|
|
|
// sort player infos by DDRace Team (and score inbetween)
|
|
|
|
Index = 0;
|
2014-01-28 18:52:46 +00:00
|
|
|
for(int Team = 0; Team <= MAX_CLIENTS; ++Team)
|
2014-01-22 00:39:18 +00:00
|
|
|
{
|
|
|
|
for(int i = 0; i < MAX_CLIENTS && Index < MAX_CLIENTS; ++i)
|
|
|
|
{
|
|
|
|
if(m_Snap.m_paInfoByScore[i] && m_Teams.Team(m_Snap.m_paInfoByScore[i]->m_ClientID) == Team)
|
|
|
|
m_Snap.m_paInfoByDDTeam[Index++] = m_Snap.m_paInfoByScore[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
CTuningParams StandardTuning;
|
|
|
|
CServerInfo CurrentServerInfo;
|
|
|
|
Client()->GetServerInfo(&CurrentServerInfo);
|
|
|
|
if(CurrentServerInfo.m_aGameType[0] != '0')
|
2009-01-11 10:40:14 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(str_comp(CurrentServerInfo.m_aGameType, "DM") != 0 && str_comp(CurrentServerInfo.m_aGameType, "TDM") != 0 && str_comp(CurrentServerInfo.m_aGameType, "CTF") != 0)
|
|
|
|
m_ServerMode = SERVERMODE_MOD;
|
2014-04-29 01:34:23 +00:00
|
|
|
else if(mem_comp(&StandardTuning, &m_Tuning[g_Config.m_ClDummy], 33) == 0)
|
2010-05-29 07:25:38 +00:00
|
|
|
m_ServerMode = SERVERMODE_PURE;
|
2009-01-11 10:40:14 +00:00
|
|
|
else
|
2010-05-29 07:25:38 +00:00
|
|
|
m_ServerMode = SERVERMODE_PUREMOD;
|
2009-01-11 10:40:14 +00:00
|
|
|
}
|
2011-01-06 03:46:10 +00:00
|
|
|
|
2012-01-08 23:49:20 +00:00
|
|
|
// add tuning to demo
|
2014-10-16 15:42:13 +00:00
|
|
|
bool AnyRecording = false;
|
|
|
|
for(int i = 0; i < RECORDER_MAX; i++)
|
|
|
|
if(DemoRecorder(i)->IsRecording())
|
|
|
|
{
|
|
|
|
AnyRecording = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(AnyRecording && mem_comp(&StandardTuning, &m_Tuning[g_Config.m_ClDummy], sizeof(CTuningParams)) != 0)
|
2012-01-08 23:49:20 +00:00
|
|
|
{
|
|
|
|
CMsgPacker Msg(NETMSGTYPE_SV_TUNEPARAMS);
|
2014-04-29 01:34:23 +00:00
|
|
|
int *pParams = (int *)&m_Tuning[g_Config.m_ClDummy];
|
|
|
|
for(unsigned i = 0; i < sizeof(m_Tuning[0])/sizeof(int); i++)
|
2012-01-08 23:49:20 +00:00
|
|
|
Msg.AddInt(pParams[i]);
|
|
|
|
Client()->SendMsg(&Msg, MSGFLAG_RECORD|MSGFLAG_NOSEND);
|
|
|
|
}
|
2013-02-02 13:08:02 +00:00
|
|
|
|
2014-04-28 14:47:44 +00:00
|
|
|
if(!m_DDRaceMsgSent[0] && m_Snap.m_pLocalInfo)
|
|
|
|
{
|
|
|
|
CMsgPacker Msg(NETMSGTYPE_CL_ISDDNET);
|
|
|
|
Msg.AddInt(CLIENT_VERSIONNR);
|
|
|
|
Client()->SendMsgExY(&Msg, MSGFLAG_VITAL,false, 0);
|
|
|
|
m_DDRaceMsgSent[0] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!m_DDRaceMsgSent[1] && m_Snap.m_pLocalInfo && Client()->DummyConnected())
|
2010-10-23 19:26:10 +00:00
|
|
|
{
|
2014-01-30 15:49:15 +00:00
|
|
|
CMsgPacker Msg(NETMSGTYPE_CL_ISDDNET);
|
2014-02-19 21:29:46 +00:00
|
|
|
Msg.AddInt(CLIENT_VERSIONNR);
|
2014-04-28 14:47:44 +00:00
|
|
|
Client()->SendMsgExY(&Msg, MSGFLAG_VITAL,false, 1);
|
|
|
|
m_DDRaceMsgSent[1] = true;
|
2013-02-02 13:08:02 +00:00
|
|
|
}
|
2011-02-23 20:22:05 +00:00
|
|
|
|
2014-05-24 22:59:52 +00:00
|
|
|
if(m_ShowOthers[g_Config.m_ClDummy] == -1 || (m_ShowOthers[g_Config.m_ClDummy] != -1 && m_ShowOthers[g_Config.m_ClDummy] != g_Config.m_ClShowOthers))
|
2013-02-02 13:08:02 +00:00
|
|
|
{
|
|
|
|
// no need to send, default settings
|
|
|
|
//if(!(m_ShowOthers == -1 && g_Config.m_ClShowOthers))
|
|
|
|
{
|
|
|
|
CNetMsg_Cl_ShowOthers Msg;
|
2014-05-24 22:59:52 +00:00
|
|
|
Msg.m_Show = g_Config.m_ClShowOthers;
|
2013-02-02 13:08:02 +00:00
|
|
|
Client()->SendPackMsg(&Msg, MSGFLAG_VITAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
// update state
|
2014-05-24 22:59:52 +00:00
|
|
|
m_ShowOthers[g_Config.m_ClDummy] = g_Config.m_ClShowOthers;
|
2010-10-23 19:26:10 +00:00
|
|
|
}
|
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
|
|
|
{
|
2014-12-01 00:31:58 +00:00
|
|
|
|
2008-09-23 07:43:41 +00:00
|
|
|
// store the previous values so we can detect prediction errors
|
2010-05-29 07:25:38 +00:00
|
|
|
CCharacterCore BeforePrevChar = m_PredictedPrevChar;
|
|
|
|
CCharacterCore BeforeChar = m_PredictedChar;
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2008-09-23 07:43:41 +00:00
|
|
|
// we can't predict without our own id or own character
|
2011-02-12 10:40:36 +00:00
|
|
|
if(m_Snap.m_LocalClientID == -1 || !m_Snap.m_aCharacters[m_Snap.m_LocalClientID].m_Active)
|
2008-09-23 07:43:41 +00:00
|
|
|
return;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-11-16 15:10:57 +00:00
|
|
|
// don't predict anything if we are paused
|
2011-03-04 16:08:10 +00:00
|
|
|
if(m_Snap.m_pGameInfoObj && m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_PAUSED)
|
2008-11-16 15:10:57 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(m_Snap.m_pLocalCharacter)
|
2014-04-14 08:56:14 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
m_PredictedChar.Read(m_Snap.m_pLocalCharacter);
|
2014-04-14 08:56:14 +00:00
|
|
|
m_PredictedChar.m_ActiveWeapon = m_Snap.m_pLocalCharacter->m_Weapon;
|
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
if(m_Snap.m_pLocalPrevCharacter)
|
2014-04-14 08:56:14 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
m_PredictedPrevChar.Read(m_Snap.m_pLocalPrevCharacter);
|
2014-04-14 08:56:14 +00:00
|
|
|
m_PredictedPrevChar.m_ActiveWeapon = m_Snap.m_pLocalPrevCharacter->m_Weapon;
|
|
|
|
}
|
2008-11-16 15:10:57 +00:00
|
|
|
return;
|
|
|
|
}
|
2008-09-23 07:43:41 +00:00
|
|
|
|
2015-04-18 20:29:28 +00:00
|
|
|
static bool IsWeaker[2][MAX_CLIENTS] = {{0}};
|
2015-01-11 16:36:38 +00:00
|
|
|
if(g_Config.m_ClAntiPingPlayers)
|
|
|
|
FindWeaker(IsWeaker);
|
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// repredict character
|
2010-05-29 07:25:38 +00:00
|
|
|
CWorldCore World;
|
2014-04-29 01:34:23 +00:00
|
|
|
World.m_Tuning[g_Config.m_ClDummy] = m_Tuning[g_Config.m_ClDummy];
|
2008-08-27 15:48:50 +00:00
|
|
|
|
|
|
|
// search for players
|
2008-09-23 07:43:41 +00:00
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2011-03-09 17:54:24 +00:00
|
|
|
if(!m_Snap.m_aCharacters[i].m_Active || !m_Snap.m_paPlayerInfos[i])
|
2008-09-23 07:43:41 +00:00
|
|
|
continue;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-09-30 20:31:11 +00:00
|
|
|
g_GameClient.m_aClients[i].m_Predicted.Init(&World, Collision(), &m_Teams);
|
2010-05-29 07:25:38 +00:00
|
|
|
World.m_apCharacters[i] = &g_GameClient.m_aClients[i].m_Predicted;
|
2011-02-13 05:35:13 +00:00
|
|
|
World.m_apCharacters[i]->m_Id = m_Snap.m_paPlayerInfos[i]->m_ClientID;
|
2010-05-29 07:25:38 +00:00
|
|
|
g_GameClient.m_aClients[i].m_Predicted.Read(&m_Snap.m_aCharacters[i].m_Cur);
|
2014-04-14 08:56:14 +00:00
|
|
|
g_GameClient.m_aClients[i].m_Predicted.m_ActiveWeapon = m_Snap.m_aCharacters[i].m_Cur.m_Weapon;
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2014-12-01 00:31:58 +00:00
|
|
|
CServerInfo Info;
|
|
|
|
Client()->GetServerInfo(&Info);
|
|
|
|
const int MaxProjectiles = 128;
|
|
|
|
class CLocalProjectile PredictedProjectiles[MaxProjectiles];
|
|
|
|
int NumProjectiles = 0;
|
|
|
|
int ReloadTimer = 0;
|
|
|
|
vec2 PrevPos;
|
|
|
|
|
|
|
|
if(g_Config.m_ClAntiPingWeapons)
|
|
|
|
{
|
|
|
|
for(int Index = 0; Index < MaxProjectiles; Index++)
|
|
|
|
PredictedProjectiles[Index].Deactivate();
|
|
|
|
|
|
|
|
int Num = Client()->SnapNumItems(IClient::SNAP_CURRENT);
|
|
|
|
for(int Index = 0; Index < Num && NumProjectiles < MaxProjectiles; Index++)
|
|
|
|
{
|
|
|
|
IClient::CSnapItem Item;
|
|
|
|
const void *pData = Client()->SnapGetItem(IClient::SNAP_CURRENT, Index, &Item);
|
|
|
|
if(Item.m_Type == NETOBJTYPE_PROJECTILE)
|
|
|
|
{
|
|
|
|
CNetObj_Projectile* pProj = (CNetObj_Projectile*) pData;
|
|
|
|
if(pProj->m_Type == WEAPON_GRENADE || (pProj->m_Type == WEAPON_SHOTGUN && UseExtraInfo(pProj)))
|
|
|
|
{
|
|
|
|
CLocalProjectile NewProj;
|
|
|
|
NewProj.Init(this, &World, Collision(), pProj);
|
2014-12-01 17:34:16 +00:00
|
|
|
if(fabs(1.0f - length(NewProj.m_Direction)) < 0.015)
|
2014-12-01 00:31:58 +00:00
|
|
|
{
|
|
|
|
if(!NewProj.m_ExtraInfo)
|
|
|
|
{
|
|
|
|
if(CWeaponData *pData = FindWeaponData(NewProj.m_StartTick))
|
|
|
|
{
|
|
|
|
NewProj.m_Pos = pData->StartPos();
|
|
|
|
NewProj.m_Direction = pData->m_Direction;
|
|
|
|
NewProj.m_Owner = m_Snap.m_LocalClientID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PredictedProjectiles[NumProjectiles] = NewProj;
|
|
|
|
NumProjectiles++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int AttackTick = m_Snap.m_aCharacters[m_Snap.m_LocalClientID].m_Cur.m_AttackTick;
|
|
|
|
if(World.m_apCharacters[m_Snap.m_LocalClientID]->m_ActiveWeapon == WEAPON_HAMMER)
|
|
|
|
{
|
|
|
|
CWeaponData *pWeaponData = GetWeaponData(AttackTick);
|
|
|
|
if(pWeaponData && pWeaponData->m_Tick == AttackTick)
|
|
|
|
ReloadTimer = SERVER_TICK_SPEED / 3 - (Client()->GameTick() - AttackTick);
|
|
|
|
else
|
|
|
|
ReloadTimer = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ReloadTimer = g_pData->m_Weapons.m_aId[World.m_apCharacters[m_Snap.m_LocalClientID]->m_ActiveWeapon].m_Firedelay * SERVER_TICK_SPEED / 1000 - (Client()->GameTick() - AttackTick);
|
|
|
|
ReloadTimer = max(ReloadTimer, 0);
|
|
|
|
}
|
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
// predict
|
2010-05-29 07:25:38 +00:00
|
|
|
for(int Tick = Client()->GameTick()+1; Tick <= Client()->PredGameTick(); Tick++)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
|
|
|
// fetch the local
|
2011-02-12 10:40:36 +00:00
|
|
|
if(Tick == Client()->PredGameTick() && World.m_apCharacters[m_Snap.m_LocalClientID])
|
|
|
|
m_PredictedPrevChar = *World.m_apCharacters[m_Snap.m_LocalClientID];
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
for(int c = 0; c < MAX_CLIENTS; c++)
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(!World.m_apCharacters[c])
|
2008-08-27 15:48:50 +00:00
|
|
|
continue;
|
2014-12-01 00:31:58 +00:00
|
|
|
|
2014-12-08 12:49:39 +00:00
|
|
|
if(g_Config.m_ClAntiPingPlayers && Tick == Client()->PredGameTick())
|
2013-10-09 14:02:23 +00:00
|
|
|
g_GameClient.m_aClients[c].m_PrevPredicted = *World.m_apCharacters[c];
|
2014-12-01 00:31:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// input
|
|
|
|
for(int c = 0; c < MAX_CLIENTS; c++)
|
|
|
|
{
|
|
|
|
if(!World.m_apCharacters[c])
|
|
|
|
continue;
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
mem_zero(&World.m_apCharacters[c]->m_Input, sizeof(World.m_apCharacters[c]->m_Input));
|
2011-02-12 10:40:36 +00:00
|
|
|
if(m_Snap.m_LocalClientID == c)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
|
|
|
// apply player input
|
2010-05-29 07:25:38 +00:00
|
|
|
int *pInput = Client()->GetInput(Tick);
|
|
|
|
if(pInput)
|
|
|
|
World.m_apCharacters[c]->m_Input = *((CNetObj_PlayerInput*)pInput);
|
2014-12-01 00:31:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(g_Config.m_ClAntiPingWeapons)
|
|
|
|
{
|
|
|
|
const float ProximityRadius = 28.0f;
|
|
|
|
CNetObj_PlayerInput Input;
|
|
|
|
CNetObj_PlayerInput PrevInput;
|
|
|
|
mem_zero(&Input, sizeof(Input));
|
|
|
|
mem_zero(&PrevInput, sizeof(PrevInput));
|
|
|
|
int *pInput = Client()->GetInput(Tick);
|
|
|
|
if(pInput)
|
|
|
|
Input = *((CNetObj_PlayerInput*)pInput);
|
|
|
|
int *pPrevInput = Client()->GetInput(Tick-1);
|
|
|
|
if(pPrevInput)
|
|
|
|
PrevInput = *((CNetObj_PlayerInput*)pPrevInput);
|
|
|
|
|
|
|
|
CCharacterCore *Local = World.m_apCharacters[m_Snap.m_LocalClientID];
|
|
|
|
vec2 Direction = normalize(vec2(Input.m_TargetX, Input.m_TargetY));
|
|
|
|
vec2 Pos = Local->m_Pos;
|
|
|
|
vec2 ProjStartPos = Pos + Direction * ProximityRadius * 0.75f;
|
|
|
|
|
|
|
|
bool WeaponFired = false;
|
|
|
|
bool NewPresses = false;
|
|
|
|
// handle weapons
|
|
|
|
do
|
|
|
|
{
|
|
|
|
if(ReloadTimer)
|
|
|
|
break;
|
|
|
|
if(!World.m_apCharacters[m_Snap.m_LocalClientID])
|
|
|
|
break;
|
|
|
|
if(!pInput || !pPrevInput)
|
|
|
|
break;
|
|
|
|
|
|
|
|
bool FullAuto = false;
|
|
|
|
if(Local->m_ActiveWeapon == WEAPON_GRENADE || Local->m_ActiveWeapon == WEAPON_SHOTGUN || Local->m_ActiveWeapon == WEAPON_RIFLE)
|
|
|
|
FullAuto = true;
|
|
|
|
|
|
|
|
bool WillFire = false;
|
|
|
|
|
|
|
|
if(CountInput(PrevInput.m_Fire, Input.m_Fire).m_Presses)
|
|
|
|
{
|
|
|
|
WillFire = true;
|
|
|
|
NewPresses = true;
|
|
|
|
}
|
|
|
|
if(FullAuto && (Input.m_Fire&1))
|
|
|
|
WillFire = true;
|
|
|
|
if(!WillFire)
|
|
|
|
break;
|
2014-12-10 02:39:15 +00:00
|
|
|
if(!IsRace(&Info) && !m_Snap.m_pLocalCharacter->m_AmmoCount && Local->m_ActiveWeapon != WEAPON_HAMMER)
|
2014-12-01 00:31:58 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
int ExpectedStartTick = Tick-1;
|
|
|
|
ReloadTimer = g_pData->m_Weapons.m_aId[Local->m_ActiveWeapon].m_Firedelay * SERVER_TICK_SPEED / 1000;
|
|
|
|
|
|
|
|
bool DirectInput = Client()->InputExists(Tick);
|
|
|
|
if(!DirectInput)
|
|
|
|
{
|
|
|
|
ReloadTimer++;
|
|
|
|
ExpectedStartTick++;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(Local->m_ActiveWeapon)
|
|
|
|
{
|
|
|
|
case WEAPON_RIFLE:
|
|
|
|
case WEAPON_SHOTGUN:
|
|
|
|
case WEAPON_GUN:
|
|
|
|
{
|
|
|
|
WeaponFired = true;
|
|
|
|
} break;
|
|
|
|
case WEAPON_GRENADE:
|
|
|
|
{
|
|
|
|
if(NumProjectiles >= MaxProjectiles)
|
|
|
|
break;
|
|
|
|
PredictedProjectiles[NumProjectiles].Init(
|
|
|
|
this, &World, Collision(),
|
|
|
|
Direction, //StartDir
|
|
|
|
ProjStartPos, //StartPos
|
|
|
|
ExpectedStartTick, //StartTick
|
|
|
|
WEAPON_GRENADE, //Type
|
|
|
|
m_Snap.m_LocalClientID, //Owner
|
|
|
|
WEAPON_GRENADE, //Weapon
|
|
|
|
1, 0, 0, 1); //Explosive, Bouncing, Freeze, ExtraInfo
|
|
|
|
NumProjectiles++;
|
|
|
|
WeaponFired = true;
|
|
|
|
} break;
|
|
|
|
case WEAPON_HAMMER:
|
|
|
|
{
|
|
|
|
vec2 ProjPos = ProjStartPos;
|
|
|
|
float Radius = ProximityRadius*0.5f;
|
|
|
|
|
|
|
|
int Hits = 0;
|
|
|
|
bool OwnerCanProbablyHitOthers = (m_Tuning[g_Config.m_ClDummy].m_PlayerCollision || m_Tuning[g_Config.m_ClDummy].m_PlayerHooking);
|
|
|
|
if(!OwnerCanProbablyHitOthers)
|
|
|
|
break;
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
{
|
|
|
|
if(!World.m_apCharacters[i])
|
|
|
|
continue;
|
|
|
|
if(i == m_Snap.m_LocalClientID)
|
|
|
|
continue;
|
|
|
|
if(!(distance(World.m_apCharacters[i]->m_Pos, ProjPos) < Radius+ProximityRadius))
|
|
|
|
continue;;
|
|
|
|
|
|
|
|
CCharacterCore *pTarget = World.m_apCharacters[i];
|
|
|
|
|
|
|
|
if(m_aClients[i].m_Active && !m_Teams.CanCollide(i, m_Snap.m_LocalClientID))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
vec2 Dir;
|
|
|
|
if (length(pTarget->m_Pos - Pos) > 0.0f)
|
|
|
|
Dir = normalize(pTarget->m_Pos - Pos);
|
|
|
|
else
|
|
|
|
Dir = vec2(0.f, -1.f);
|
|
|
|
|
|
|
|
float Strength;
|
|
|
|
Strength = World.m_Tuning[g_Config.m_ClDummy].m_HammerStrength;
|
|
|
|
|
|
|
|
vec2 Temp = pTarget->m_Vel + normalize(Dir + vec2(0.f, -1.1f)) * 10.0f;
|
|
|
|
|
|
|
|
pTarget->LimitForce(&Temp);
|
|
|
|
|
|
|
|
Temp -= pTarget->m_Vel;
|
|
|
|
pTarget->ApplyForce((vec2(0.f, -1.0f) + Temp) * Strength);
|
|
|
|
Hits++;
|
|
|
|
}
|
|
|
|
// if we Hit anything, we have to wait for the reload
|
|
|
|
if(Hits)
|
|
|
|
{
|
|
|
|
ReloadTimer = SERVER_TICK_SPEED/3;
|
|
|
|
WeaponFired = true;
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
if(!ReloadTimer)
|
|
|
|
{
|
|
|
|
ReloadTimer = g_pData->m_Weapons.m_aId[Local->m_ActiveWeapon].m_Firedelay * SERVER_TICK_SPEED / 1000;
|
|
|
|
if(!DirectInput)
|
|
|
|
ReloadTimer++;
|
|
|
|
}
|
|
|
|
} while(false);
|
|
|
|
|
|
|
|
if(ReloadTimer)
|
|
|
|
ReloadTimer--;
|
|
|
|
|
|
|
|
if(Tick > Client()->GameTick()+1)
|
|
|
|
if(CWeaponData *pWeaponData = GetWeaponData(Tick-1))
|
|
|
|
pWeaponData->m_Pos = Pos;
|
|
|
|
if(WeaponFired)
|
|
|
|
{
|
|
|
|
if(CWeaponData *pWeaponData = GetWeaponData(Tick-1))
|
|
|
|
{
|
|
|
|
pWeaponData->m_Direction = Direction;
|
|
|
|
pWeaponData->m_Tick = Tick-1;
|
|
|
|
}
|
|
|
|
if(NewPresses)
|
|
|
|
{
|
|
|
|
if(CWeaponData *pWeaponData = GetWeaponData(Tick-2))
|
|
|
|
{
|
|
|
|
pWeaponData->m_Direction = Direction;
|
|
|
|
pWeaponData->m_Tick = Tick-2;
|
|
|
|
}
|
|
|
|
if(CWeaponData *pWeaponData = GetWeaponData(Tick))
|
|
|
|
{
|
|
|
|
pWeaponData->m_Direction = Direction;
|
|
|
|
pWeaponData->m_Tick = Tick;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// projectiles
|
|
|
|
for(int g = 0; g < MaxProjectiles; g++)
|
|
|
|
if(PredictedProjectiles[g].m_Active)
|
|
|
|
PredictedProjectiles[g].Tick(Tick, Client()->GameTickSpeed(), m_Snap.m_LocalClientID);
|
|
|
|
}
|
|
|
|
|
2015-01-11 16:36:38 +00:00
|
|
|
// calculate where everyone should move
|
|
|
|
if(g_Config.m_ClAntiPingPlayers)
|
2014-12-01 00:31:58 +00:00
|
|
|
{
|
2015-01-11 16:36:38 +00:00
|
|
|
//first apply Tick to weaker players (players that the local client has strong hook against), then local, then stronger players
|
|
|
|
for(int h = 0; h < 3; h++)
|
2014-12-01 00:31:58 +00:00
|
|
|
{
|
2015-01-11 16:36:38 +00:00
|
|
|
if(h == 1)
|
|
|
|
{
|
|
|
|
if(World.m_apCharacters[m_Snap.m_LocalClientID])
|
|
|
|
World.m_apCharacters[m_Snap.m_LocalClientID]->Tick(true, true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
for(int c = 0; c < MAX_CLIENTS; c++)
|
|
|
|
if(c != m_Snap.m_LocalClientID && World.m_apCharacters[c] && ((h == 0 && IsWeaker[g_Config.m_ClDummy][c]) || (h == 2 && !IsWeaker[g_Config.m_ClDummy][c])))
|
|
|
|
World.m_apCharacters[c]->Tick(false, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for(int c = 0; c < MAX_CLIENTS; c++)
|
|
|
|
{
|
|
|
|
if(!World.m_apCharacters[c])
|
|
|
|
continue;
|
|
|
|
if(m_Snap.m_LocalClientID == c)
|
|
|
|
World.m_apCharacters[c]->Tick(true, true);
|
|
|
|
else
|
|
|
|
World.m_apCharacters[c]->Tick(false, true);
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// move all players and quantize their data
|
|
|
|
for(int c = 0; c < MAX_CLIENTS; c++)
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(!World.m_apCharacters[c])
|
2008-08-27 15:48:50 +00:00
|
|
|
continue;
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
World.m_apCharacters[c]->Move();
|
|
|
|
World.m_apCharacters[c]->Quantize();
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-09-23 07:43:41 +00:00
|
|
|
// check if we want to trigger effects
|
2014-05-23 21:59:26 +00:00
|
|
|
if(Tick > m_LastNewPredictedTick[g_Config.m_ClDummy])
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2014-05-23 21:59:26 +00:00
|
|
|
m_LastNewPredictedTick[g_Config.m_ClDummy] = Tick;
|
2010-05-29 07:25:38 +00:00
|
|
|
m_NewPredictedTick = true;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2011-02-12 10:40:36 +00:00
|
|
|
if(m_Snap.m_LocalClientID != -1 && World.m_apCharacters[m_Snap.m_LocalClientID])
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2011-02-12 10:40:36 +00:00
|
|
|
vec2 Pos = World.m_apCharacters[m_Snap.m_LocalClientID]->m_Pos;
|
|
|
|
int Events = World.m_apCharacters[m_Snap.m_LocalClientID]->m_TriggeredEvents;
|
2014-10-25 00:52:08 +00:00
|
|
|
if(Events&COREEVENT_GROUND_JUMP)
|
|
|
|
if(g_Config.m_SndGame)
|
|
|
|
g_GameClient.m_pSounds->PlayAndRecord(CSounds::CHN_WORLD, SOUND_PLAYER_JUMP, 1.0f, Pos);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2009-01-11 15:51:43 +00:00
|
|
|
/*if(events&COREEVENT_AIR_JUMP)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
GameClient.effects->air_jump(pos);
|
|
|
|
GameClient.sounds->play_and_record(SOUNDS::CHN_WORLD, SOUND_PLAYER_AIRJUMP, 1.0f, pos);
|
2009-01-11 15:51:43 +00:00
|
|
|
}*/
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2008-08-27 15:48:50 +00:00
|
|
|
//if(events&COREEVENT_HOOK_LAUNCH) snd_play_random(CHN_WORLD, SOUND_HOOK_LOOP, 1.0f, pos);
|
|
|
|
//if(events&COREEVENT_HOOK_ATTACH_PLAYER) snd_play_random(CHN_WORLD, SOUND_HOOK_ATTACH_PLAYER, 1.0f, pos);
|
2014-10-25 00:52:08 +00:00
|
|
|
if(Events&COREEVENT_HOOK_ATTACH_GROUND)
|
|
|
|
if(g_Config.m_SndGame)
|
|
|
|
g_GameClient.m_pSounds->PlayAndRecord(CSounds::CHN_WORLD, SOUND_HOOK_ATTACH_GROUND, 1.0f, Pos);
|
|
|
|
if(Events&COREEVENT_HOOK_HIT_NOHOOK)
|
|
|
|
if(g_Config.m_SndGame)
|
|
|
|
g_GameClient.m_pSounds->PlayAndRecord(CSounds::CHN_WORLD, SOUND_HOOK_NOATTACH, 1.0f, Pos);
|
2008-08-27 15:48:50 +00:00
|
|
|
//if(events&COREEVENT_HOOK_RETRACT) snd_play_random(CHN_WORLD, SOUND_PLAYER_JUMP, 1.0f, pos);
|
|
|
|
}
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2014-12-01 00:31:58 +00:00
|
|
|
|
2011-02-12 10:40:36 +00:00
|
|
|
if(Tick == Client()->PredGameTick() && World.m_apCharacters[m_Snap.m_LocalClientID])
|
2013-10-09 14:02:23 +00:00
|
|
|
{
|
2011-02-12 10:40:36 +00:00
|
|
|
m_PredictedChar = *World.m_apCharacters[m_Snap.m_LocalClientID];
|
2013-10-09 14:02:23 +00:00
|
|
|
|
2014-12-08 12:49:39 +00:00
|
|
|
if (g_Config.m_ClAntiPingPlayers)
|
2013-10-09 14:02:23 +00:00
|
|
|
{
|
|
|
|
for (int c = 0; c < MAX_CLIENTS; c++)
|
|
|
|
{
|
|
|
|
if(!World.m_apCharacters[c])
|
|
|
|
continue;
|
|
|
|
|
|
|
|
g_GameClient.m_aClients[c].m_Predicted = *World.m_apCharacters[c];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(g_Config.m_Debug && g_Config.m_ClPredict && m_PredictedTick == Client()->PredGameTick())
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
CNetObj_CharacterCore Before = {0}, Now = {0}, BeforePrev = {0}, NowPrev = {0};
|
|
|
|
BeforeChar.Write(&Before);
|
|
|
|
BeforePrevChar.Write(&BeforePrev);
|
|
|
|
m_PredictedChar.Write(&Now);
|
|
|
|
m_PredictedPrevChar.Write(&NowPrev);
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(mem_comp(&Before, &Now, sizeof(CNetObj_CharacterCore)) != 0)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-08-17 22:06:00 +00:00
|
|
|
Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client", "prediction error");
|
2010-05-29 07:25:38 +00:00
|
|
|
for(unsigned i = 0; i < sizeof(CNetObj_CharacterCore)/sizeof(int); i++)
|
|
|
|
if(((int *)&Before)[i] != ((int *)&Now)[i])
|
2008-09-23 07:43:41 +00:00
|
|
|
{
|
2010-08-17 22:06:00 +00:00
|
|
|
char aBuf[256];
|
2011-04-13 18:37:12 +00:00
|
|
|
str_format(aBuf, sizeof(aBuf), " %d %d %d (%d %d)", i, ((int *)&Before)[i], ((int *)&Now)[i], ((int *)&BeforePrev)[i], ((int *)&NowPrev)[i]);
|
2010-08-17 22:06:00 +00:00
|
|
|
Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client", aBuf);
|
2008-09-23 07:43:41 +00:00
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
m_PredictedTick = Client()->PredGameTick();
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
|
2011-01-17 11:28:37 +00:00
|
|
|
void CGameClient::OnActivateEditor()
|
|
|
|
{
|
|
|
|
OnRelease();
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameClient::CClientData::UpdateRenderInfo()
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
m_RenderInfo = m_SkinInfo;
|
2008-08-27 15:48:50 +00:00
|
|
|
|
|
|
|
// force team colors
|
2011-03-04 16:08:10 +00:00
|
|
|
if(g_GameClient.m_Snap.m_pGameInfoObj && g_GameClient.m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_TEAMS)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2011-03-27 09:52:16 +00:00
|
|
|
m_RenderInfo.m_Texture = g_GameClient.m_pSkins->Get(m_SkinID)->m_ColorTexture;
|
2010-05-29 07:25:38 +00:00
|
|
|
const int TeamColors[2] = {65387, 10223467};
|
2011-01-03 11:50:38 +00:00
|
|
|
if(m_Team >= TEAM_RED && m_Team <= TEAM_BLUE)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-11-24 00:11:56 +00:00
|
|
|
m_RenderInfo.m_ColorBody = g_GameClient.m_pSkins->GetColorV4(TeamColors[m_Team]);
|
|
|
|
m_RenderInfo.m_ColorFeet = g_GameClient.m_pSkins->GetColorV4(TeamColors[m_Team]);
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2011-03-27 09:52:16 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
m_RenderInfo.m_ColorBody = g_GameClient.m_pSkins->GetColorV4(12895054);
|
|
|
|
m_RenderInfo.m_ColorFeet = g_GameClient.m_pSkins->GetColorV4(12895054);
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
|
2011-03-22 21:41:27 +00:00
|
|
|
void CGameClient::CClientData::Reset()
|
|
|
|
{
|
|
|
|
m_aName[0] = 0;
|
|
|
|
m_aClan[0] = 0;
|
|
|
|
m_Country = -1;
|
|
|
|
m_SkinID = 0;
|
|
|
|
m_Team = 0;
|
|
|
|
m_Angle = 0;
|
|
|
|
m_Emoticon = 0;
|
|
|
|
m_EmoticonStart = -1;
|
|
|
|
m_Active = false;
|
|
|
|
m_ChatIgnore = false;
|
|
|
|
m_SkinInfo.m_Texture = g_GameClient.m_pSkins->Get(0)->m_ColorTexture;
|
|
|
|
m_SkinInfo.m_ColorBody = vec4(1,1,1,1);
|
|
|
|
m_SkinInfo.m_ColorFeet = vec4(1,1,1,1);
|
|
|
|
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
|
|
|
|
|
|
|
if (Team != TEAM_SPECTATORS)
|
|
|
|
m_pCamera->OnReset();
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameClient::SendInfo(bool Start)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
if(Start)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
CNetMsg_Cl_StartInfo Msg;
|
|
|
|
Msg.m_pName = g_Config.m_PlayerName;
|
2011-03-15 10:23:49 +00:00
|
|
|
Msg.m_pClan = g_Config.m_PlayerClan;
|
|
|
|
Msg.m_Country = g_Config.m_PlayerCountry;
|
2010-05-29 07:25:38 +00:00
|
|
|
Msg.m_pSkin = g_Config.m_PlayerSkin;
|
|
|
|
Msg.m_UseCustomColor = g_Config.m_PlayerUseCustomColor;
|
|
|
|
Msg.m_ColorBody = g_Config.m_PlayerColorBody;
|
|
|
|
Msg.m_ColorFeet = g_Config.m_PlayerColorFeet;
|
2014-04-28 13:19:57 +00:00
|
|
|
CMsgPacker Packer(Msg.MsgID());
|
|
|
|
Msg.Pack(&Packer);
|
2014-08-17 17:10:08 +00:00
|
|
|
Client()->SendMsgExY(&Packer, MSGFLAG_VITAL, false, 0);
|
2015-04-19 12:03:40 +00:00
|
|
|
m_CheckInfo[0] = -1;
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
CNetMsg_Cl_ChangeInfo Msg;
|
|
|
|
Msg.m_pName = g_Config.m_PlayerName;
|
2011-03-15 10:23:49 +00:00
|
|
|
Msg.m_pClan = g_Config.m_PlayerClan;
|
|
|
|
Msg.m_Country = g_Config.m_PlayerCountry;
|
2010-05-29 07:25:38 +00:00
|
|
|
Msg.m_pSkin = g_Config.m_PlayerSkin;
|
|
|
|
Msg.m_UseCustomColor = g_Config.m_PlayerUseCustomColor;
|
|
|
|
Msg.m_ColorBody = g_Config.m_PlayerColorBody;
|
|
|
|
Msg.m_ColorFeet = g_Config.m_PlayerColorFeet;
|
2014-04-28 13:19:57 +00:00
|
|
|
CMsgPacker Packer(Msg.MsgID());
|
|
|
|
Msg.Pack(&Packer);
|
2014-08-17 17:10:08 +00:00
|
|
|
Client()->SendMsgExY(&Packer, MSGFLAG_VITAL, false, 0);
|
2015-04-19 12:03:40 +00:00
|
|
|
m_CheckInfo[0] = Client()->GameTickSpeed();
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-28 13:19:57 +00:00
|
|
|
void CGameClient::SendDummyInfo(bool Start)
|
|
|
|
{
|
|
|
|
if(Start)
|
|
|
|
{
|
|
|
|
CNetMsg_Cl_StartInfo Msg;
|
|
|
|
Msg.m_pName = g_Config.m_DummyName;
|
|
|
|
Msg.m_pClan = g_Config.m_DummyClan;
|
|
|
|
Msg.m_Country = g_Config.m_DummyCountry;
|
|
|
|
Msg.m_pSkin = g_Config.m_DummySkin;
|
|
|
|
Msg.m_UseCustomColor = g_Config.m_DummyUseCustomColor;
|
|
|
|
Msg.m_ColorBody = g_Config.m_DummyColorBody;
|
|
|
|
Msg.m_ColorFeet = g_Config.m_DummyColorFeet;
|
|
|
|
CMsgPacker Packer(Msg.MsgID());
|
|
|
|
Msg.Pack(&Packer);
|
2014-08-17 17:10:08 +00:00
|
|
|
Client()->SendMsgExY(&Packer, MSGFLAG_VITAL, false, 1);
|
2015-04-19 12:03:40 +00:00
|
|
|
m_CheckInfo[1] = -1;
|
2014-04-28 13:19:57 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CNetMsg_Cl_ChangeInfo Msg;
|
|
|
|
Msg.m_pName = g_Config.m_DummyName;
|
|
|
|
Msg.m_pClan = g_Config.m_DummyClan;
|
|
|
|
Msg.m_Country = g_Config.m_DummyCountry;
|
|
|
|
Msg.m_pSkin = g_Config.m_DummySkin;
|
|
|
|
Msg.m_UseCustomColor = g_Config.m_DummyUseCustomColor;
|
|
|
|
Msg.m_ColorBody = g_Config.m_DummyColorBody;
|
|
|
|
Msg.m_ColorFeet = g_Config.m_DummyColorFeet;
|
|
|
|
CMsgPacker Packer(Msg.MsgID());
|
|
|
|
Msg.Pack(&Packer);
|
|
|
|
Client()->SendMsgExY(&Packer, MSGFLAG_VITAL,false, 1);
|
2015-04-19 12:03:40 +00:00
|
|
|
m_CheckInfo[1] = Client()->GameTickSpeed();
|
2014-04-28 13:19:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-12 10:40:36 +00:00
|
|
|
void CGameClient::SendKill(int ClientID)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
CNetMsg_Cl_Kill Msg;
|
2011-04-13 18:37:12 +00:00
|
|
|
Client()->SendPackMsg(&Msg, MSGFLAG_VITAL);
|
2015-02-18 13:23:25 +00:00
|
|
|
|
|
|
|
if(g_Config.m_ClDummyCopyMoves)
|
|
|
|
{
|
|
|
|
CMsgPacker Msg(NETMSGTYPE_CL_KILL);
|
|
|
|
Client()->SendMsgExY(&Msg, MSGFLAG_VITAL, false, !g_Config.m_ClDummy);
|
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2008-08-31 13:36:30 +00:00
|
|
|
|
2011-08-13 00:11:06 +00:00
|
|
|
void CGameClient::ConTeam(IConsole::IResult *pResult, void *pUserData)
|
2008-08-31 13:36:30 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
((CGameClient*)pUserData)->SendSwitchTeam(pResult->GetInteger(0));
|
2008-08-31 13:36:30 +00:00
|
|
|
}
|
|
|
|
|
2011-08-13 00:11:06 +00:00
|
|
|
void CGameClient::ConKill(IConsole::IResult *pResult, void *pUserData)
|
2008-08-31 13:36:30 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
((CGameClient*)pUserData)->SendKill(-1);
|
2008-08-31 13:36:30 +00:00
|
|
|
}
|
2009-06-15 14:01:36 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CGameClient::ConchainSpecialInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
|
2009-06-15 14:01:36 +00:00
|
|
|
{
|
2011-08-13 00:11:06 +00:00
|
|
|
pfnCallback(pResult, pCallbackUserData);
|
2010-05-29 07:25:38 +00:00
|
|
|
if(pResult->NumArguments())
|
|
|
|
((CGameClient*)pUserData)->SendInfo(false);
|
2009-10-27 14:38:53 +00:00
|
|
|
}
|
|
|
|
|
2014-04-28 13:19:57 +00:00
|
|
|
void CGameClient::ConchainSpecialDummyInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
|
|
|
|
{
|
|
|
|
pfnCallback(pResult, pCallbackUserData);
|
|
|
|
if(pResult->NumArguments())
|
|
|
|
((CGameClient*)pUserData)->SendDummyInfo(false);
|
|
|
|
}
|
|
|
|
|
2014-04-28 13:34:56 +00:00
|
|
|
void CGameClient::ConchainSpecialDummy(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
|
|
|
|
{
|
|
|
|
pfnCallback(pResult, pCallbackUserData);
|
|
|
|
if(pResult->NumArguments())
|
|
|
|
if(g_Config.m_ClDummy && !((CGameClient*)pUserData)->Client()->DummyConnected())
|
|
|
|
g_Config.m_ClDummy = 0;
|
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
IGameClient *CreateGameClient()
|
2009-10-27 14:38:53 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
return &g_GameClient;
|
2011-01-06 05:30:19 +00:00
|
|
|
}
|
2013-08-23 23:50:35 +00:00
|
|
|
|
2014-01-30 03:10:52 +00:00
|
|
|
int CGameClient::IntersectCharacter(vec2 HookPos, vec2 NewPos, vec2& NewPos2, int ownID)
|
2013-08-23 23:50:35 +00:00
|
|
|
{
|
2014-01-27 04:06:23 +00:00
|
|
|
float PhysSize = 28.0f;
|
|
|
|
float Distance = 0.0f;
|
2013-08-23 23:50:35 +00:00
|
|
|
int ClosestID = -1;
|
|
|
|
|
2014-04-29 01:34:23 +00:00
|
|
|
if (!m_Tuning[g_Config.m_ClDummy].m_PlayerHooking)
|
2014-02-08 20:55:08 +00:00
|
|
|
return ClosestID;
|
|
|
|
|
2013-08-23 23:50:35 +00:00
|
|
|
for (int i=0; i<MAX_CLIENTS; i++)
|
|
|
|
{
|
2014-01-11 23:45:25 +00:00
|
|
|
CClientData cData = m_aClients[i];
|
|
|
|
CNetObj_Character Prev = m_Snap.m_aCharacters[i].m_Prev;
|
|
|
|
CNetObj_Character Player = m_Snap.m_aCharacters[i].m_Cur;
|
2013-08-23 23:50:35 +00:00
|
|
|
|
2014-01-11 23:45:25 +00:00
|
|
|
vec2 Position = mix(vec2(Prev.m_X, Prev.m_Y), vec2(Player.m_X, Player.m_Y), Client()->IntraGameTick());
|
2013-08-23 23:50:35 +00:00
|
|
|
|
2014-04-10 18:33:26 +00:00
|
|
|
if (!cData.m_Active || i == ownID || !m_Teams.SameTeam(i, ownID))
|
2014-01-11 23:45:25 +00:00
|
|
|
continue;
|
2013-08-23 23:50:35 +00:00
|
|
|
|
2014-01-27 04:06:23 +00:00
|
|
|
vec2 ClosestPoint = closest_point_on_line(HookPos, NewPos, Position);
|
|
|
|
if(distance(Position, ClosestPoint) < PhysSize+2.0f)
|
2013-08-23 23:50:35 +00:00
|
|
|
{
|
2014-01-27 04:06:23 +00:00
|
|
|
if(ClosestID == -1 || distance(HookPos, Position) < Distance)
|
2013-08-23 23:50:35 +00:00
|
|
|
{
|
2014-01-27 04:06:23 +00:00
|
|
|
NewPos2 = ClosestPoint;
|
2013-08-23 23:50:35 +00:00
|
|
|
ClosestID = i;
|
2014-01-27 04:06:23 +00:00
|
|
|
Distance = distance(HookPos, Position);
|
2013-08-23 23:50:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-10-23 15:31:29 +00:00
|
|
|
|
2013-08-23 23:50:35 +00:00
|
|
|
return ClosestID;
|
|
|
|
}
|
2014-12-01 00:31:58 +00:00
|
|
|
|
|
|
|
|
|
|
|
int CGameClient::IntersectCharacter(vec2 OldPos, vec2 NewPos, float Radius, vec2 *NewPos2, int ownID, CWorldCore *World)
|
|
|
|
{
|
|
|
|
float PhysSize = 28.0f;
|
|
|
|
float Distance = 0.0f;
|
|
|
|
int ClosestID = -1;
|
|
|
|
|
|
|
|
if(!World)
|
|
|
|
return ClosestID;
|
|
|
|
|
|
|
|
for (int i=0; i<MAX_CLIENTS; i++)
|
|
|
|
{
|
|
|
|
if(!World->m_apCharacters[i])
|
|
|
|
continue;
|
|
|
|
CClientData cData = m_aClients[i];
|
|
|
|
|
|
|
|
if(!cData.m_Active || i == ownID || !m_Teams.CanCollide(i, ownID))
|
|
|
|
continue;
|
|
|
|
vec2 Position = World->m_apCharacters[i]->m_Pos;
|
|
|
|
vec2 ClosestPoint = closest_point_on_line(OldPos, NewPos, Position);
|
|
|
|
if(distance(Position, ClosestPoint) < PhysSize+Radius)
|
|
|
|
{
|
|
|
|
if(ClosestID == -1 || distance(OldPos, Position) < Distance)
|
|
|
|
{
|
|
|
|
*NewPos2 = ClosestPoint;
|
|
|
|
ClosestID = i;
|
|
|
|
Distance = distance(OldPos, Position);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ClosestID;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CLocalProjectile::Init(CGameClient *pGameClient, CWorldCore *pWorld, CCollision *pCollision, const CNetObj_Projectile *pProj)
|
|
|
|
{
|
|
|
|
m_Active = 1;
|
|
|
|
m_pGameClient = pGameClient;
|
|
|
|
m_pWorld = pWorld;
|
|
|
|
m_pCollision = pCollision;
|
|
|
|
m_StartTick = pProj->m_StartTick;
|
|
|
|
m_Type = pProj->m_Type;
|
|
|
|
m_Weapon = m_Type;
|
|
|
|
|
|
|
|
ExtractInfo(pProj, &m_Pos, &m_Direction, 1);
|
|
|
|
|
|
|
|
if(UseExtraInfo(pProj))
|
|
|
|
{
|
|
|
|
ExtractExtraInfo(pProj, &m_Owner, &m_Explosive, &m_Bouncing, &m_Freeze);
|
|
|
|
m_ExtraInfo = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-12-01 17:34:16 +00:00
|
|
|
bool StandardVel = (fabs(1.0f - length(m_Direction)) < 0.015);
|
2014-12-01 00:31:58 +00:00
|
|
|
m_Owner = -1;
|
|
|
|
m_Explosive = ((m_Type == WEAPON_GRENADE && StandardVel) ? true : false);
|
|
|
|
m_Bouncing = 0;
|
|
|
|
m_Freeze = 0;
|
|
|
|
m_ExtraInfo = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CLocalProjectile::Init(CGameClient *pGameClient, CWorldCore *pWorld, CCollision *pCollision, vec2 Direction, vec2 Pos, int StartTick, int Type, int Owner, int Weapon, bool Explosive, int Bouncing, bool Freeze, bool ExtraInfo)
|
|
|
|
{
|
|
|
|
m_Active = 1;
|
|
|
|
m_pGameClient = pGameClient;
|
|
|
|
m_pWorld = pWorld;
|
|
|
|
m_pCollision = pCollision;
|
|
|
|
m_Direction = Direction;
|
|
|
|
m_Pos = Pos;
|
|
|
|
m_StartTick = StartTick;
|
|
|
|
m_Type = Type;
|
|
|
|
m_Weapon = Weapon;
|
|
|
|
m_Owner = Owner;
|
|
|
|
m_Explosive = Explosive;
|
|
|
|
m_Bouncing = Bouncing;
|
|
|
|
m_Freeze = Freeze;
|
|
|
|
m_ExtraInfo = ExtraInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
vec2 CLocalProjectile::GetPos(float Time)
|
|
|
|
{
|
|
|
|
float Curvature = 0;
|
|
|
|
float Speed = 0;
|
|
|
|
|
|
|
|
switch(m_Type)
|
|
|
|
{
|
|
|
|
case WEAPON_GRENADE:
|
|
|
|
Curvature = m_pWorld->m_Tuning[g_Config.m_ClDummy].m_GrenadeCurvature;
|
|
|
|
Speed = m_pWorld->m_Tuning[g_Config.m_ClDummy].m_GrenadeSpeed;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WEAPON_SHOTGUN:
|
|
|
|
Curvature = m_pWorld->m_Tuning[g_Config.m_ClDummy].m_ShotgunCurvature;
|
|
|
|
Speed = m_pWorld->m_Tuning[g_Config.m_ClDummy].m_ShotgunSpeed;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WEAPON_GUN:
|
|
|
|
Curvature = m_pWorld->m_Tuning[g_Config.m_ClDummy].m_GunCurvature;
|
|
|
|
Speed = m_pWorld->m_Tuning[g_Config.m_ClDummy].m_GunSpeed;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return CalcPos(m_Pos, m_Direction, Curvature, Speed, Time);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CLocalProjectile::GameLayerClipped(vec2 CheckPos)
|
|
|
|
{
|
|
|
|
return round_to_int(CheckPos.x)/32 < -200 || round_to_int(CheckPos.x)/32 > m_pCollision->GetWidth()+200 ||
|
|
|
|
round_to_int(CheckPos.y)/32 < -200 || round_to_int(CheckPos.y)/32 > m_pCollision->GetHeight()+200 ? true : false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CLocalProjectile::Tick(int CurrentTick, int GameTickSpeed, int LocalClientID)
|
|
|
|
{
|
|
|
|
if(!m_pWorld)
|
|
|
|
return;
|
|
|
|
if(CurrentTick <= m_StartTick)
|
|
|
|
return;
|
|
|
|
float Pt = (CurrentTick-m_StartTick-1)/(float)GameTickSpeed;
|
|
|
|
float Ct = (CurrentTick-m_StartTick)/(float)GameTickSpeed;
|
|
|
|
|
|
|
|
vec2 PrevPos = GetPos(Pt);
|
|
|
|
vec2 CurPos = GetPos(Ct);
|
|
|
|
vec2 ColPos;
|
|
|
|
vec2 NewPos;
|
|
|
|
int Collide = 0;
|
|
|
|
if(m_pCollision)
|
|
|
|
Collide = m_pCollision->IntersectLine(PrevPos, CurPos, &ColPos, &NewPos, false);
|
|
|
|
int Target = m_pGameClient->IntersectCharacter(PrevPos, ColPos, m_Freeze ? 1.0f : 6.0f, &ColPos, m_Owner, m_pWorld);
|
|
|
|
|
|
|
|
bool isWeaponCollide = false;
|
|
|
|
if(m_Owner >= 0 && Target >= 0 && m_pGameClient->m_aClients[m_Owner].m_Active && m_pGameClient->m_aClients[Target].m_Active && !m_pGameClient->m_Teams.CanCollide(m_Owner, Target))
|
|
|
|
isWeaponCollide = true;
|
|
|
|
|
|
|
|
bool OwnerCanProbablyHitOthers = (m_pWorld->m_Tuning[g_Config.m_ClDummy].m_PlayerCollision || m_pWorld->m_Tuning[g_Config.m_ClDummy].m_PlayerHooking);
|
|
|
|
|
|
|
|
if(((Target >= 0 && (m_Owner >= 0 ? OwnerCanProbablyHitOthers : 1 || Target == m_Owner)) || Collide || GameLayerClipped(CurPos)) && !isWeaponCollide)
|
|
|
|
{
|
|
|
|
if(m_Explosive && (Target < 0 || (Target >= 0 && (!m_Freeze || (m_Weapon == WEAPON_SHOTGUN && Collide)))))
|
|
|
|
CreateExplosion(ColPos, m_Owner);
|
|
|
|
if(Collide && m_Bouncing != 0)
|
|
|
|
{
|
|
|
|
m_StartTick = CurrentTick;
|
|
|
|
m_Pos = NewPos+(-(m_Direction*4));
|
|
|
|
if (m_Bouncing == 1)
|
|
|
|
m_Direction.x = -m_Direction.x;
|
|
|
|
else if(m_Bouncing == 2)
|
2015-04-18 20:29:28 +00:00
|
|
|
m_Direction.y = -m_Direction.y;
|
2014-12-01 00:31:58 +00:00
|
|
|
if (fabs(m_Direction.x) < 1e-6)
|
|
|
|
m_Direction.x = 0;
|
|
|
|
if (fabs(m_Direction.y) < 1e-6)
|
|
|
|
m_Direction.y = 0;
|
|
|
|
m_Pos += m_Direction;
|
|
|
|
}
|
|
|
|
else if(!m_Bouncing)
|
|
|
|
Deactivate();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!m_Bouncing)
|
|
|
|
{
|
|
|
|
int Lifetime = 0;
|
|
|
|
if(m_Weapon == WEAPON_GRENADE)
|
|
|
|
Lifetime = m_pGameClient->m_Tuning[g_Config.m_ClDummy].m_GrenadeLifetime * SERVER_TICK_SPEED;
|
|
|
|
else if(m_Weapon == WEAPON_GUN)
|
|
|
|
Lifetime = m_pGameClient->m_Tuning[g_Config.m_ClDummy].m_GrenadeLifetime * SERVER_TICK_SPEED;
|
|
|
|
else if(m_Weapon == WEAPON_SHOTGUN)
|
|
|
|
Lifetime = m_pGameClient->m_Tuning[g_Config.m_ClDummy].m_ShotgunLifetime * SERVER_TICK_SPEED;
|
|
|
|
int LifeSpan = Lifetime - (CurrentTick - m_StartTick);
|
|
|
|
if(LifeSpan == -1)
|
|
|
|
{
|
|
|
|
if(m_Explosive)
|
|
|
|
CreateExplosion(ColPos, LocalClientID);
|
|
|
|
Deactivate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CLocalProjectile::CreateExplosion(vec2 Pos, int LocalClientID)
|
|
|
|
{
|
|
|
|
if(!m_pWorld)
|
|
|
|
return;
|
|
|
|
float Radius = 135.0f;
|
|
|
|
float InnerRadius = 48.0f;
|
|
|
|
|
|
|
|
bool OwnerCanProbablyHitOthers = (m_pWorld->m_Tuning[g_Config.m_ClDummy].m_PlayerCollision || m_pWorld->m_Tuning[g_Config.m_ClDummy].m_PlayerHooking);
|
|
|
|
|
|
|
|
for(int c = 0; c < MAX_CLIENTS; c++)
|
|
|
|
{
|
|
|
|
if(!m_pWorld->m_apCharacters[c])
|
|
|
|
continue;
|
|
|
|
if(m_Owner >= 0 && c >= 0)
|
|
|
|
if(m_pGameClient->m_aClients[c].m_Active && !m_pGameClient->m_Teams.CanCollide(c, m_Owner))
|
|
|
|
continue;
|
|
|
|
if(c != LocalClientID && !OwnerCanProbablyHitOthers)
|
|
|
|
continue;
|
|
|
|
vec2 Diff = m_pWorld->m_apCharacters[c]->m_Pos - Pos;
|
|
|
|
vec2 ForceDir(0,1);
|
|
|
|
float l = length(Diff);
|
|
|
|
if(l)
|
|
|
|
ForceDir = normalize(Diff);
|
|
|
|
l = 1-clamp((l-InnerRadius)/(Radius-InnerRadius), 0.0f, 1.0f);
|
|
|
|
|
|
|
|
float Strength = m_pWorld->m_Tuning[g_Config.m_ClDummy].m_ExplosionStrength;
|
|
|
|
float Dmg = Strength * l;
|
|
|
|
|
|
|
|
if((int)Dmg)
|
|
|
|
m_pWorld->m_apCharacters[c]->ApplyForce(ForceDir*Dmg*2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CWeaponData *CGameClient::FindWeaponData(int TargetTick)
|
|
|
|
{
|
|
|
|
CWeaponData *pData;
|
|
|
|
int TickDiff[3] = {0, -1, 1};
|
|
|
|
for(unsigned int i = 0; i < sizeof(TickDiff)/sizeof(int); i++)
|
|
|
|
if((pData = GetWeaponData(TargetTick + TickDiff[i])))
|
|
|
|
if(pData->m_Tick == TargetTick + TickDiff[i])
|
|
|
|
return GetWeaponData(TargetTick + TickDiff[i]);
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-01-11 16:36:38 +00:00
|
|
|
|
|
|
|
void CGameClient::FindWeaker(bool IsWeaker[2][MAX_CLIENTS])
|
|
|
|
{
|
|
|
|
// attempts to detect strong/weak against the player we are hooking
|
2015-04-18 20:29:28 +00:00
|
|
|
static int DirAccumulated[2][MAX_CLIENTS] = {{0}};
|
2015-01-11 16:36:38 +00:00
|
|
|
if(!m_Snap.m_aCharacters[m_Snap.m_LocalClientID].m_Active || !m_Snap.m_paPlayerInfos[m_Snap.m_LocalClientID])
|
|
|
|
return;
|
|
|
|
int HookedPlayer = m_Snap.m_aCharacters[m_Snap.m_LocalClientID].m_Prev.m_HookedPlayer;
|
|
|
|
if(HookedPlayer >= 0 && m_Snap.m_aCharacters[HookedPlayer].m_Active && m_Snap.m_paPlayerInfos[HookedPlayer])
|
|
|
|
{
|
|
|
|
CCharacterCore OtherCharCur;
|
|
|
|
OtherCharCur.Read(&m_Snap.m_aCharacters[HookedPlayer].m_Cur);
|
|
|
|
float PredictErr[2];
|
|
|
|
for(int dir = 0; dir < 2; dir++)
|
|
|
|
{
|
|
|
|
CWorldCore World;
|
|
|
|
World.m_Tuning[g_Config.m_ClDummy] = m_Tuning[g_Config.m_ClDummy];
|
|
|
|
|
|
|
|
CCharacterCore OtherChar;
|
|
|
|
OtherChar.Init(&World, Collision(), &m_Teams);
|
|
|
|
World.m_apCharacters[HookedPlayer] = &OtherChar;
|
|
|
|
OtherChar.Read(&m_Snap.m_aCharacters[HookedPlayer].m_Prev);
|
|
|
|
|
|
|
|
CCharacterCore LocalChar;
|
|
|
|
LocalChar.Init(&World, Collision(), &m_Teams);
|
|
|
|
World.m_apCharacters[m_Snap.m_LocalClientID] = &LocalChar;
|
|
|
|
LocalChar.Read(&m_Snap.m_aCharacters[m_Snap.m_LocalClientID].m_Prev);
|
|
|
|
|
|
|
|
for(int Tick = Client()->PrevGameTick(); Tick < Client()->GameTick(); Tick++)
|
|
|
|
{
|
|
|
|
if(dir == 0)
|
|
|
|
{
|
|
|
|
LocalChar.Tick(false, true);
|
|
|
|
OtherChar.Tick(false, true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
OtherChar.Tick(false, true);
|
|
|
|
LocalChar.Tick(false, true);
|
|
|
|
}
|
|
|
|
LocalChar.Move();
|
|
|
|
LocalChar.Quantize();
|
|
|
|
OtherChar.Move();
|
|
|
|
OtherChar.Quantize();
|
|
|
|
}
|
|
|
|
PredictErr[dir] = distance(OtherChar.m_Vel, OtherCharCur.m_Vel);
|
|
|
|
}
|
|
|
|
const float Low = 0.0001, High = 0.07;
|
|
|
|
if(PredictErr[1] < Low && PredictErr[0] > High)
|
|
|
|
DirAccumulated[g_Config.m_ClDummy][HookedPlayer] = SaturatedAdd(-1, 2, DirAccumulated[g_Config.m_ClDummy][HookedPlayer], 1);
|
|
|
|
else if(PredictErr[0] < Low && PredictErr[1] > High)
|
|
|
|
DirAccumulated[g_Config.m_ClDummy][HookedPlayer] = SaturatedAdd(-1, 2, DirAccumulated[g_Config.m_ClDummy][HookedPlayer], -1);
|
|
|
|
IsWeaker[g_Config.m_ClDummy][HookedPlayer] = (DirAccumulated[g_Config.m_ClDummy][HookedPlayer] > 0);
|
|
|
|
}
|
|
|
|
}
|