BVB Source Codes

CRYENGINE Show LevelSystem.cpp Source code

Return Download CRYENGINE: download LevelSystem.cpp Source code - Download CRYENGINE Source code - Type:.cpp
  1. // Copyright 2001-2016 Crytek GmbH / Crytek Group. All rights reserved.
  2.  
  3. #include "StdAfx.h"
  4. #include "LevelSystem.h"
  5. #include "ActorSystem.h"
  6. #include <CryMovie/IMovieSystem.h>
  7. #include "CryAction.h"
  8. #include <CryGame/IGameTokens.h>
  9. #include <CryAudio/Dialog/IDialogSystem.h>
  10. #include "TimeOfDayScheduler.h"
  11. #include "IGameRulesSystem.h"
  12. #include <CryAction/IMaterialEffects.h>
  13. #include "IPlayerProfiles.h"
  14. #include <CryLiveCreate/ILiveCreateHost.h>
  15. #include <CrySystem/File/IResourceManager.h>
  16. #include <CrySystem/ILocalizationManager.h>
  17. #include "Network/GameContext.h"
  18. #include "ICooperativeAnimationManager.h"
  19. #include <CryPhysics/IDeferredCollisionEvent.h>
  20. #include <CryCore/Platform/IPlatformOS.h>
  21. #include <CryAction/ICustomActions.h>
  22. #include "CustomEvents/CustomEventsManager.h"
  23.  
  24. #include <CryGame/IGameVolumes.h>
  25.  
  26. #define LOCAL_WARNING(cond, msg) do { if (!(cond)) { CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "%s", msg); } } while (0)
  27. //#define LOCAL_WARNING(cond, msg)  CRY_ASSERT_MESSAGE(cond, msg)
  28.  
  29. #define LEVEL_SYSTEM_SPAWN_ENTITIES_DURING_LOADING_COMPLETE_NOTIFICATION 1
  30.  
  31. int CLevelSystem::s_loadCount = 0;
  32.  
  33. //------------------------------------------------------------------------
  34. CLevelRotation::CLevelRotation() :
  35.         m_randFlags(ePRF_None),
  36.         m_next(0),
  37.         m_extInfoId(0),
  38.         m_advancesTaken(0),
  39.         m_hasGameModesDecks(false)
  40. {
  41. }
  42.  
  43. //------------------------------------------------------------------------
  44. CLevelRotation::~CLevelRotation()
  45. {
  46. }
  47.  
  48. //------------------------------------------------------------------------
  49. bool CLevelRotation::Load(ILevelRotationFile* file)
  50. {
  51.         return LoadFromXmlRootNode(file->Load(), NULL);
  52. }
  53.  
  54. //------------------------------------------------------------------------
  55. bool CLevelRotation::LoadFromXmlRootNode(const XmlNodeRef rootNode, const char* altRootTag)
  56. {
  57.         if (rootNode)
  58.         {
  59.                 if (!stricmp(rootNode->getTag(), "levelrotation") || (altRootTag && !stricmp(rootNode->getTag(), altRootTag)))
  60.                 {
  61.                         Reset();
  62.  
  63.                         TRandomisationFlags randFlags = ePRF_None;
  64.  
  65.                         bool r = false;
  66.                         rootNode->getAttr("randomize", r);
  67.                         if (r)
  68.                         {
  69.                                 randFlags |= ePRF_Shuffle;
  70.                         }
  71.  
  72.                         bool pairs = false;
  73.                         rootNode->getAttr("maintainPairs", pairs);
  74.                         if (pairs)
  75.                         {
  76.                                 randFlags |= ePRF_MaintainPairs;
  77.                         }
  78.  
  79.                         SetRandomisationFlags(randFlags);
  80.  
  81.                         bool includeNonPresentLevels = false;
  82.                         rootNode->getAttr("includeNonPresentLevels", includeNonPresentLevels);
  83.  
  84.                         int n = rootNode->getChildCount();
  85.  
  86.                         XmlNodeRef lastLevelNode;
  87.  
  88.                         for (int i = 0; i < n; ++i)
  89.                         {
  90.                                 XmlNodeRef child = rootNode->getChild(i);
  91.                                 if (child && !stricmp(child->getTag(), "level"))
  92.                                 {
  93.                                         const char* levelName = child->getAttr("name");
  94.                                         if (!levelName || !levelName[0])
  95.                                         {
  96.                                                 continue;
  97.                                         }
  98.  
  99.                                         if (!includeNonPresentLevels)
  100.                                         {
  101.                                                 if (!CCryAction::GetCryAction()->GetILevelSystem()->GetLevelInfo(levelName)) //skipping non-present levels
  102.                                                 {
  103.                                                         continue;
  104.                                                 }
  105.                                         }
  106.  
  107.                                         //capture this good level child node in case it is last
  108.                                         lastLevelNode = child;
  109.  
  110.                                         AddLevelFromNode(levelName, child);
  111.                                 }
  112.                         }
  113.  
  114.                         //if we're a maintain pairs playlist, need an even number of entries
  115.                         //also if there's only one entry, we should increase to 2 for safety
  116.                         int nAdded = m_rotation.size();
  117.                         if (nAdded == 1 || (pairs && (nAdded % 2) == 1))
  118.                         {
  119.                                 //so duplicate last
  120.                                 const char* levelName = lastLevelNode->getAttr("name");   //we know there was at least 1 level node if we have an odd number
  121.                                 AddLevelFromNode(levelName, lastLevelNode);
  122.                         }
  123.                         return true;
  124.                 }
  125.         }
  126.  
  127.         return false;
  128. }
  129.  
  130. //------------------------------------------------------------------------
  131. void CLevelRotation::AddLevelFromNode(const char* levelName, XmlNodeRef& levelNode)
  132. {
  133.         int lvl = AddLevel(levelName);
  134.  
  135.         SLevelRotationEntry& level = m_rotation[lvl];
  136.  
  137.         const char* gameRulesName = levelNode->getAttr("gamerules");
  138.         if (gameRulesName && gameRulesName[0])
  139.         {
  140.                 AddGameMode(level, gameRulesName);
  141.         }
  142.         else
  143.         {
  144.                 //look for child Game Rules nodes
  145.                 int nModeNodes = levelNode->getChildCount();
  146.  
  147.                 for (int iNode = 0; iNode < nModeNodes; ++iNode)
  148.                 {
  149.                         XmlNodeRef modeNode = levelNode->getChild(iNode);
  150.  
  151.                         if (!stricmp(modeNode->getTag(), "gameRules"))
  152.                         {
  153.                                 gameRulesName = modeNode->getAttr("name");
  154.  
  155.                                 if (gameRulesName && gameRulesName[0])
  156.                                 {
  157.                                         //found some
  158.                                         AddGameMode(level, gameRulesName);
  159.                                 }
  160.                         }
  161.                 }
  162.         }
  163. }
  164.  
  165. //------------------------------------------------------------------------
  166. void CLevelRotation::Reset()
  167. {
  168.         m_randFlags = ePRF_None;
  169.         m_next = 0;
  170.         m_rotation.resize(0);
  171.         m_shuffle.resize(0);
  172.         m_extInfoId = 0;
  173.         m_hasGameModesDecks = false;
  174. }
  175.  
  176. //------------------------------------------------------------------------
  177. int CLevelRotation::AddLevel(const char* level)
  178. {
  179.         SLevelRotationEntry entry;
  180.         entry.levelName = level;
  181.         entry.currentModeIndex = 0;
  182.  
  183.         int idx = m_rotation.size();
  184.         m_rotation.push_back(entry);
  185.         m_shuffle.push_back(idx);
  186.         return idx;
  187. }
  188.  
  189. //------------------------------------------------------------------------
  190. int CLevelRotation::AddLevel(const char* level, const char* gameMode)
  191. {
  192.         int iLevel = AddLevel(level);
  193.         AddGameMode(iLevel, gameMode);
  194.         return iLevel;
  195. }
  196.  
  197. //------------------------------------------------------------------------
  198. void CLevelRotation::AddGameMode(int level, const char* gameMode)
  199. {
  200.         CRY_ASSERT(level >= 0 && level < m_rotation.size());
  201.         AddGameMode(m_rotation[level], gameMode);
  202. }
  203.  
  204. //------------------------------------------------------------------------
  205. void CLevelRotation::AddGameMode(SLevelRotationEntry& level, const char* gameMode)
  206. {
  207.         const char* pActualGameModeName = CCryAction::GetCryAction()->GetIGameRulesSystem()->GetGameRulesName(gameMode);
  208.         if (pActualGameModeName)
  209.         {
  210.                 int idx = level.gameRulesNames.size();
  211.                 level.gameRulesNames.push_back(pActualGameModeName);
  212.                 level.gameRulesShuffle.push_back(idx);
  213.  
  214.                 if (level.gameRulesNames.size() > 1)
  215.                 {
  216.                         //more than one game mode per level is a deck of game modes
  217.                         m_hasGameModesDecks = true;
  218.                 }
  219.         }
  220. }
  221.  
  222. //------------------------------------------------------------------------
  223. bool CLevelRotation::First()
  224. {
  225.         Log_LevelRotation("First called");
  226.         m_next = 0;
  227.         return !m_rotation.empty();
  228. }
  229.  
  230. //------------------------------------------------------------------------
  231. bool CLevelRotation::Advance()
  232. {
  233.         Log_LevelRotation("::Advance()");
  234.         ++m_advancesTaken;
  235.  
  236.         if (m_next >= 0 && m_next < m_rotation.size())
  237.         {
  238.                 SLevelRotationEntry& currLevel = m_rotation[(m_randFlags & ePRF_Shuffle) ? m_shuffle[m_next] : m_next];
  239.  
  240.                 int nModes = currLevel.gameRulesNames.size();
  241.  
  242.                 if (nModes > 1)
  243.                 {
  244.                         //also advance game mode for level
  245.                         currLevel.currentModeIndex++;
  246.  
  247.                         Log_LevelRotation(" advanced level entry %d currentModeIndex to %d", m_next, currLevel.currentModeIndex);
  248.  
  249.                         if (currLevel.currentModeIndex >= nModes)
  250.                         {
  251.                                 Log_LevelRotation(" looped modes");
  252.                                 currLevel.currentModeIndex = 0;
  253.                         }
  254.                 }
  255.         }
  256.  
  257.         ++m_next;
  258.  
  259.         Log_LevelRotation("CLevelRotation::Advance advancesTaken = %d, next = %d", m_advancesTaken, m_next);
  260.  
  261.         if (m_next >= m_rotation.size())
  262.                 return false;
  263.         return true;
  264. }
  265.  
  266. //------------------------------------------------------------------------
  267. bool CLevelRotation::AdvanceAndLoopIfNeeded()
  268. {
  269.         bool looped = false;
  270.         if (!Advance())
  271.         {
  272.                 Log_LevelRotation("AdvanceAndLoopIfNeeded Looping");
  273.                 looped = true;
  274.                 First();
  275.  
  276.                 if (m_randFlags & ePRF_Shuffle)
  277.                 {
  278.                         ShallowShuffle();
  279.                 }
  280.         }
  281.  
  282.         return looped;
  283. }
  284.  
  285. //------------------------------------------------------------------------
  286. const char* CLevelRotation::GetNextLevel() const
  287. {
  288.         if (m_next >= 0 && m_next < m_rotation.size())
  289.         {
  290.                 int next = (m_randFlags & ePRF_Shuffle) ? m_shuffle[m_next] : m_next;
  291.                 return m_rotation[next].levelName.c_str();
  292.         }
  293.         return 0;
  294. }
  295.  
  296. //------------------------------------------------------------------------
  297. const char* CLevelRotation::GetNextGameRules() const
  298. {
  299.         if (m_next >= 0 && m_next < m_rotation.size())
  300.         {
  301.                 int next = (m_randFlags & ePRF_Shuffle) ? m_shuffle[m_next] : m_next;
  302.  
  303.                 const SLevelRotationEntry& nextLevel = m_rotation[next];
  304.  
  305.                 Log_LevelRotation("::GetNextGameRules() accessing level %d mode %d (shuffled %d)", next, nextLevel.currentModeIndex, nextLevel.gameRulesShuffle[nextLevel.currentModeIndex]);
  306.                 return nextLevel.GameModeName();
  307.         }
  308.         return 0;
  309. }
  310.  
  311. //------------------------------------------------------------------------
  312. const char* CLevelRotation::GetLevel(uint32 idx, bool accessShuffled /*=true*/) const
  313. {
  314.         int realIndex = GetRealRotationIndex(idx, accessShuffled);
  315.  
  316.         if (realIndex >= 0)
  317.         {
  318.                 return m_rotation[realIndex].levelName.c_str();
  319.         }
  320.  
  321.         return 0;
  322. }
  323.  
  324. //------------------------------------------------------------------------
  325. int CLevelRotation::GetNGameRulesForEntry(uint32 idx, bool accessShuffled /*=true*/) const
  326. {
  327.         int realIndex = GetRealRotationIndex(idx, accessShuffled);
  328.  
  329.         if (realIndex >= 0)
  330.         {
  331.                 return m_rotation[realIndex].gameRulesNames.size();
  332.         }
  333.  
  334.         return 0;
  335. }
  336.  
  337. //------------------------------------------------------------------------
  338. const char* CLevelRotation::GetGameRules(uint32 idx, uint32 iMode, bool accessShuffled /*=true*/) const
  339. {
  340.         int realIndex = GetRealRotationIndex(idx, accessShuffled);
  341.  
  342.         if (realIndex >= 0)
  343.         {
  344.                 int nRules = m_rotation[realIndex].gameRulesNames.size();
  345.  
  346.                 if (iMode < nRules)
  347.                 {
  348.                         if (accessShuffled && (m_randFlags & ePRF_Shuffle))
  349.                         {
  350.                                 iMode = m_rotation[realIndex].gameRulesShuffle[iMode];
  351.                         }
  352.  
  353.                         return m_rotation[realIndex].gameRulesNames[iMode].c_str();
  354.                 }
  355.         }
  356.  
  357.         return 0;
  358. }
  359.  
  360. //------------------------------------------------------------------------
  361. const char* CLevelRotation::GetNextGameRulesForEntry(int idx) const
  362. {
  363.         int realIndex = GetRealRotationIndex(idx, true);
  364.  
  365.         if (realIndex >= 0)
  366.         {
  367. #if LEVEL_ROTATION_DEBUG
  368.                 const SLevelRotationEntry& curLevel = m_rotation[realIndex];
  369.                 const char* gameModeName = curLevel.GameModeName();
  370.  
  371.                 Log_LevelRotation("::GetNextGameRulesForEntry() idx %d, realIndex %d, level name %s, currentModeIndex %d, shuffled index %d, mode name %s",
  372.                                   idx, realIndex, curLevel.levelName.c_str(), curLevel.currentModeIndex, curLevel.gameRulesShuffle[curLevel.currentModeIndex], gameModeName);
  373. #endif //LEVEL_ROTATION_DEBUG
  374.  
  375.                 return m_rotation[realIndex].GameModeName();
  376.         }
  377.  
  378.         return 0;
  379. }
  380.  
  381. //------------------------------------------------------------------------
  382. const int CLevelRotation::NumAdvancesTaken() const
  383. {
  384.         return m_advancesTaken;
  385. }
  386.  
  387. //------------------------------------------------------------------------
  388. void CLevelRotation::ResetAdvancement()
  389. {
  390.         Log_LevelRotation("::ResetAdvancement(), m_advancesTaken, m_next and currentModeIndex all set to 0");
  391.  
  392.         m_advancesTaken = 0;
  393.         m_next = 0;
  394.  
  395.         int nEntries = m_rotation.size();
  396.         for (int iLevel = 0; iLevel < nEntries; ++iLevel)
  397.         {
  398.                 m_rotation[iLevel].currentModeIndex = 0;
  399.         }
  400.  
  401. }
  402.  
  403. //------------------------------------------------------------------------
  404. int CLevelRotation::GetLength() const
  405. {
  406.         return (int)m_rotation.size();
  407. }
  408.  
  409. int CLevelRotation::GetTotalGameModeEntries() const
  410. {
  411.         int nLevels = m_rotation.size();
  412.  
  413.         int nGameModes = 0;
  414.  
  415.         for (int iLevel = 0; iLevel < nLevels; ++iLevel)
  416.         {
  417.                 nGameModes += m_rotation[iLevel].gameRulesNames.size();
  418.         }
  419.  
  420.         return nGameModes;
  421. }
  422.  
  423. //------------------------------------------------------------------------
  424. int CLevelRotation::GetNext() const
  425. {
  426.         return m_next;
  427. }
  428.  
  429. //------------------------------------------------------------------------
  430. void CLevelRotation::SetRandomisationFlags(TRandomisationFlags randMode)
  431. {
  432.         //check there's nothing in here apart from our flags
  433.         CRY_ASSERT((randMode & ~(ePRF_Shuffle | ePRF_MaintainPairs)) == 0);
  434.  
  435.         m_randFlags = randMode;
  436. }
  437.  
  438. //------------------------------------------------------------------------
  439.  
  440. bool CLevelRotation::IsRandom() const
  441. {
  442.         return (m_randFlags & ePRF_Shuffle) != 0;
  443. }
  444.  
  445. //------------------------------------------------------------------------
  446. void CLevelRotation::ChangeLevel(IConsoleCmdArgs* pArgs)
  447. {
  448.         SGameContextParams ctx;
  449.         const char* nextGameRules = GetNextGameRules();
  450.         if (nextGameRules && nextGameRules[0])
  451.                 ctx.gameRules = nextGameRules;
  452.         else if (IEntity* pEntity = CCryAction::GetCryAction()->GetIGameRulesSystem()->GetCurrentGameRulesEntity())
  453.                 ctx.gameRules = pEntity->GetClass()->GetName();
  454.         else if (ILevelInfo* pLevelInfo = CCryAction::GetCryAction()->GetILevelSystem()->GetLevelInfo(GetNextLevel()))
  455.                 ctx.gameRules = pLevelInfo->GetDefaultGameType()->name;
  456.  
  457.         ctx.levelName = GetNextLevel();
  458.  
  459.         if (CCryAction::GetCryAction()->StartedGameContext())
  460.         {
  461.                 CCryAction::GetCryAction()->ChangeGameContext(&ctx);
  462.         }
  463.         else
  464.         {
  465.                 gEnv->pConsole->ExecuteString(string("sv_gamerules ") + ctx.gameRules);
  466.  
  467.                 string command = string("map ") + ctx.levelName;
  468.                 if (pArgs)
  469.                         for (int i = 1; i < pArgs->GetArgCount(); ++i)
  470.                                 command += string(" ") + pArgs->GetArg(i);
  471.                 command += " s";
  472.                 gEnv->pConsole->ExecuteString(command);
  473.         }
  474.  
  475.         if (!Advance())
  476.                 First();
  477. }
  478.  
  479. //------------------------------------------------------------------------
  480. void CLevelRotation::Initialise(int nSeed)
  481. {
  482.         Log_LevelRotation("::Initalise()");
  483.         m_advancesTaken = 0;
  484.  
  485.         First();
  486.  
  487.         if (nSeed >= 0)
  488.         {
  489.                 gEnv->pSystem->GetRandomGenerator().Seed(nSeed);
  490.                 Log_LevelRotation("Seeded random generator with %d", nSeed);
  491.         }
  492.  
  493.         if (!m_rotation.empty() && m_randFlags & ePRF_Shuffle)
  494.         {
  495.                 ShallowShuffle();
  496.                 ModeShuffle();
  497.         }
  498.  
  499. }
  500.  
  501. //------------------------------------------------------------------------
  502. void CLevelRotation::ModeShuffle()
  503. {
  504.         if (m_hasGameModesDecks)
  505.         {
  506.                 //shuffle every map's modes.
  507.                 int nEntries = m_rotation.size();
  508.  
  509.                 for (int iLevel = 0; iLevel < nEntries; ++iLevel)
  510.                 {
  511.                         int nModes = m_rotation[iLevel].gameRulesNames.size();
  512.  
  513.                         std::vector<int>& gameModesShuffle = m_rotation[iLevel].gameRulesShuffle;
  514.                         gameModesShuffle.resize(nModes);
  515.  
  516.                         for (int iMode = 0; iMode < nModes; ++iMode)
  517.                         {
  518.                                 gameModesShuffle[iMode] = iMode;
  519.                         }
  520.  
  521.                         for (int iMode = 0; iMode < nModes; ++iMode)
  522.                         {
  523.                                 int idx = cry_random(0, nModes - 1);
  524.                                 Log_LevelRotation("Called cry_random()");
  525.                                 std::swap(gameModesShuffle[iMode], gameModesShuffle[idx]);
  526.                         }
  527.  
  528. #if LEVEL_ROTATION_DEBUG
  529.                         Log_LevelRotation("ModeShuffle Level entry %d Order", iLevel);
  530.  
  531.                         for (int iMode = 0; iMode < nModes; ++iMode)
  532.                         {
  533.                                 Log_LevelRotation("Slot %d Mode %d", iMode, gameModesShuffle[iMode]);
  534.                         }
  535. #endif //LEVEL_ROTATION_DEBUG
  536.                         m_rotation[iLevel].currentModeIndex = 0;
  537.                 }
  538.         }
  539. }
  540.  
  541. //------------------------------------------------------------------------
  542. void CLevelRotation::ShallowShuffle()
  543. {
  544.         //shuffle levels only
  545.         int nEntries = m_rotation.size();
  546.         m_shuffle.resize(nEntries);
  547.  
  548.         for (int i = 0; i < nEntries; ++i)
  549.         {
  550.                 m_shuffle[i] = i;
  551.         }
  552.  
  553.         if (m_randFlags & ePRF_MaintainPairs)
  554.         {
  555.                 Log_LevelRotation("CLevelRotation::ShallowShuffle doing pair shuffle");
  556.                 CRY_ASSERT_MESSAGE(nEntries % 2 == 0, "CLevelRotation::Shuffle Set to maintain pairs shuffle, require even number of entries, but we have odd. Should have been handled during initialisation");
  557.  
  558.                 //swap, but only even indices with even indices, and the ones after the same
  559.                 int nPairs = nEntries / 2;
  560.  
  561.                 for (int i = 0; i < nPairs; ++i)
  562.                 {
  563.                         int idx = cry_random(0, nPairs - 1);
  564.                         Log_LevelRotation("Called cry_random()");
  565.                         std::swap(m_shuffle[2 * i], m_shuffle[2 * idx]);
  566.                         std::swap(m_shuffle[2 * i + 1], m_shuffle[2 * idx + 1]);
  567.                 }
  568.         }
  569.         else
  570.         {
  571.                 for (int i = 0; i < nEntries; ++i)
  572.                 {
  573.                         int idx = cry_random(0, nEntries - 1);
  574.                         Log_LevelRotation("Called cry_random()");
  575.                         std::swap(m_shuffle[i], m_shuffle[idx]);
  576.                 }
  577.         }
  578.  
  579.         Log_LevelRotation("ShallowShuffle new order:");
  580.  
  581.         for (int iShuff = 0; iShuff < m_shuffle.size(); ++iShuff)
  582.         {
  583.                 Log_LevelRotation(" %d - %s", m_shuffle[iShuff], m_rotation[m_shuffle[iShuff]].levelName.c_str());
  584.         }
  585. }
  586.  
  587. //------------------------------------------------------------------------
  588. bool CLevelRotation::NextPairMatch() const
  589. {
  590.         bool match = true;
  591.         if (m_next >= 0 && m_next < m_rotation.size())
  592.         {
  593.                 bool shuffled = (m_randFlags & ePRF_Shuffle) != 0;
  594.  
  595.                 int next = shuffled ? m_shuffle[m_next] : m_next;
  596.  
  597.                 int nextPlus1 = m_next + 1;
  598.                 if (nextPlus1 >= m_rotation.size())
  599.                 {
  600.                         nextPlus1 = 0;
  601.                 }
  602.                 if (shuffled)
  603.                 {
  604.                         nextPlus1 = m_shuffle[nextPlus1];
  605.                 }
  606.  
  607.                 if (stricmp(m_rotation[next].levelName.c_str(), m_rotation[nextPlus1].levelName.c_str()) != 0)
  608.                 {
  609.                         match = false;
  610.                 }
  611.                 else if (stricmp(m_rotation[next].GameModeName(), m_rotation[nextPlus1].GameModeName()) != 0)
  612.                 {
  613.                         match = false;
  614.                 }
  615.         }
  616.  
  617.         return match;
  618. }
  619.  
  620. //------------------------------------------------------------------------
  621. const char* CLevelRotation::SLevelRotationEntry::GameModeName() const
  622. {
  623.         if (currentModeIndex >= 0 && currentModeIndex < gameRulesNames.size())
  624.         {
  625.                 //we can always use the shuffle list. If we aren't shuffled, it will still contain ordered indicies from creation
  626.                 int iMode = gameRulesShuffle[currentModeIndex];
  627.  
  628.                 return gameRulesNames[iMode].c_str();
  629.         }
  630.  
  631.         return NULL;
  632. }
  633.  
  634. //------------------------------------------------------------------------
  635. bool CLevelInfo::SupportsGameType(const char* gameTypeName) const
  636. {
  637.         //read level meta data
  638.         for (int i = 0; i < m_gamerules.size(); ++i)
  639.         {
  640.                 if (!stricmp(m_gamerules[i].c_str(), gameTypeName))
  641.                         return true;
  642.         }
  643.         return false;
  644. }
  645.  
  646. //------------------------------------------------------------------------
  647. const char* CLevelInfo::GetDisplayName() const
  648. {
  649.         return m_levelDisplayName.c_str();
  650. }
  651.  
  652. //------------------------------------------------------------------------
  653. bool CLevelInfo::GetAttribute(const char* name, TFlowInputData& val) const
  654. {
  655.         TAttributeList::const_iterator it = m_levelAttributes.find(name);
  656.         if (it != m_levelAttributes.end())
  657.         {
  658.                 val = it->second;
  659.                 return true;
  660.         }
  661.         return false;
  662. }
  663.  
  664. //////////////////////////////////////////////////////////////////////////
  665. bool CLevelInfo::ReadInfo()
  666. {
  667.         string levelPath = m_levelPath;
  668.         string xmlFile = levelPath + string("/LevelInfo.xml");
  669.         XmlNodeRef rootNode = GetISystem()->LoadXmlFromFile(xmlFile.c_str());
  670.  
  671.         if (rootNode)
  672.         {
  673.                 const char* sandboxVersion = rootNode->getAttr("SandboxVersion");
  674.                 if (sandboxVersion)
  675.                 {
  676.                         int major, minor, bugfix;
  677.                         int buildNumber = 0;
  678.                         if (sscanf(sandboxVersion, "%i.%i.%i.%i", &major, &minor, &bugfix, &buildNumber) == 4)
  679.                         {
  680.                                 const int leakedBuildNumber = 5620;
  681.                                 if (buildNumber == leakedBuildNumber)
  682.                                         return false;
  683.                         }
  684.                 }
  685.  
  686.                 m_heightmapSize = atoi(rootNode->getAttr("HeightmapSize"));
  687.  
  688.                 string dataFile = levelPath + string("/LevelDataAction.xml");
  689.                 XmlNodeRef dataNode = GetISystem()->LoadXmlFromFile(dataFile.c_str());
  690.                 if (!dataNode)
  691.                 {
  692.                         dataFile = levelPath + string("/LevelData.xml");
  693.                         dataNode = GetISystem()->LoadXmlFromFile(dataFile.c_str());
  694.                 }
  695.  
  696.                 if (dataNode)
  697.                 {
  698.                         XmlNodeRef gameTypesNode = dataNode->findChild("Missions");
  699.  
  700.                         if ((gameTypesNode != 0) && (gameTypesNode->getChildCount() > 0))
  701.                         {
  702.                                 m_gameTypes.clear();
  703.  
  704.                                 for (int i = 0; i < gameTypesNode->getChildCount(); i++)
  705.                                 {
  706.                                         XmlNodeRef gameTypeNode = gameTypesNode->getChild(i);
  707.  
  708.                                         if (gameTypeNode->isTag("Mission"))
  709.                                         {
  710.                                                 const char* gameTypeName = gameTypeNode->getAttr("Name");
  711.  
  712.                                                 if (gameTypeName)
  713.                                                 {
  714.                                                         ILevelInfo::TGameTypeInfo info;
  715.  
  716.                                                         info.cgfCount = 0;
  717.                                                         gameTypeNode->getAttr("CGFCount", info.cgfCount);
  718.                                                         info.name = gameTypeNode->getAttr("Name");
  719.                                                         info.xmlFile = gameTypeNode->getAttr("File");
  720.                                                         m_gameTypes.push_back(info);
  721.                                                 }
  722.                                         }
  723.                                 }
  724.                         }
  725.                 }
  726.         }
  727.         return rootNode != 0;
  728. }
  729.  
  730. //////////////////////////////////////////////////////////////////////////
  731. void CLevelInfo::ReadMetaData()
  732. {
  733.         string fullPath(GetPath());
  734.         int slashPos = fullPath.find_last_of("\\/");
  735.         string mapName = fullPath.substr(slashPos + 1, fullPath.length() - slashPos);
  736.         fullPath.append("/");
  737.         fullPath.append(mapName);
  738.         fullPath.append(".xml");
  739.         m_levelAttributes.clear();
  740.  
  741.         m_levelDisplayName = string("@ui_") + mapName;
  742.  
  743.         if (!gEnv->pCryPak->IsFileExist(fullPath.c_str()))
  744.                 return;
  745.  
  746.         XmlNodeRef mapInfo = GetISystem()->LoadXmlFromFile(fullPath.c_str());
  747.         //retrieve the coordinates of the map
  748.         bool foundMinimapInfo = false;
  749.         if (mapInfo)
  750.         {
  751.                 for (int n = 0; n < mapInfo->getChildCount(); ++n)
  752.                 {
  753.                         XmlNodeRef rulesNode = mapInfo->getChild(n);
  754.                         const char* name = rulesNode->getTag();
  755.                         if (!stricmp(name, "Gamerules"))
  756.                         {
  757.                                 for (int a = 0; a < rulesNode->getNumAttributes(); ++a)
  758.                                 {
  759.                                         const char* key, * value;
  760.                                         rulesNode->getAttributeByIndex(a, &key, &value);
  761.                                         m_gamerules.push_back(value);
  762.                                 }
  763.                         }
  764.                         else if (!stricmp(name, "Display"))
  765.                         {
  766.                                 XmlString v;
  767.                                 if (rulesNode->getAttr("Name", v))
  768.                                         m_levelDisplayName = v.c_str();
  769.                         }
  770.                         else if (!stricmp(name, "PreviewImage"))
  771.                         {
  772.                                 const char* pFilename = NULL;
  773.                                 if (rulesNode->getAttr("Filename", &pFilename))
  774.                                 {
  775.                                         m_previewImagePath = pFilename;
  776.                                 }
  777.                         }
  778.                         else if (!stricmp(name, "BackgroundImage"))
  779.                         {
  780.                                 const char* pFilename = NULL;
  781.                                 if (rulesNode->getAttr("Filename", &pFilename))
  782.                                 {
  783.                                         m_backgroundImagePath = pFilename;
  784.                                 }
  785.                         }
  786.                         else if (!stricmp(name, "Minimap"))
  787.                         {
  788.                                 foundMinimapInfo = true;
  789.  
  790.                                 const char* minimap_dds = "";
  791.                                 foundMinimapInfo &= rulesNode->getAttr("Filename", &minimap_dds);
  792.                                 m_minimapImagePath = minimap_dds;
  793.                                 m_minimapInfo.sMinimapName = GetPath();
  794.                                 m_minimapInfo.sMinimapName.append("/");
  795.                                 m_minimapInfo.sMinimapName.append(minimap_dds);
  796.  
  797.                                 foundMinimapInfo &= rulesNode->getAttr("startX", m_minimapInfo.fStartX);
  798.                                 foundMinimapInfo &= rulesNode->getAttr("startY", m_minimapInfo.fStartY);
  799.                                 foundMinimapInfo &= rulesNode->getAttr("endX", m_minimapInfo.fEndX);
  800.                                 foundMinimapInfo &= rulesNode->getAttr("endY", m_minimapInfo.fEndY);
  801.                                 foundMinimapInfo &= rulesNode->getAttr("width", m_minimapInfo.iWidth);
  802.                                 foundMinimapInfo &= rulesNode->getAttr("height", m_minimapInfo.iHeight);
  803.                                 m_minimapInfo.fDimX = m_minimapInfo.fEndX - m_minimapInfo.fStartX;
  804.                                 m_minimapInfo.fDimY = m_minimapInfo.fEndY - m_minimapInfo.fStartY;
  805.                                 m_minimapInfo.fDimX = m_minimapInfo.fDimX > 0 ? m_minimapInfo.fDimX : 1;
  806.                                 m_minimapInfo.fDimY = m_minimapInfo.fDimY > 0 ? m_minimapInfo.fDimY : 1;
  807.                         }
  808.                         else if (!stricmp(name, "Tag"))
  809.                         {
  810.                                 m_levelTag = ILevelSystem::TAG_UNKNOWN;
  811.                                 SwapEndian(m_levelTag, eBigEndian);
  812.                                 const char* pTag = NULL;
  813.                                 if (rulesNode->getAttr("Value", &pTag))
  814.                                 {
  815.                                         m_levelTag = 0;
  816.                                         memcpy(&m_levelTag, pTag, std::min(sizeof(m_levelTag), strlen(pTag)));
  817.                                 }
  818.                         }
  819.                         else if (!stricmp(name, "Attributes"))
  820.                         {
  821.                                 for (int a = 0; a < rulesNode->getChildCount(); ++a)
  822.                                 {
  823.                                         XmlNodeRef attrib = rulesNode->getChild(a);
  824.                                         assert(m_levelAttributes.find(attrib->getTag()) == m_levelAttributes.end());
  825.                                         m_levelAttributes[attrib->getTag()] = TFlowInputData(string(attrib->getAttr("value")));
  826.                                         ;
  827.                                 }
  828.                         }
  829.                         else if (!stricmp(name, "LevelType"))
  830.                         {
  831.                                 const char* levelType;
  832.                                 if (rulesNode->getAttr("value", &levelType))
  833.                                 {
  834.                                         m_levelTypeList.push_back(levelType);
  835.                                 }
  836.                         }
  837.                 }
  838.                 m_bMetaDataRead = true;
  839.         }
  840.         if (!foundMinimapInfo)
  841.         {
  842.                 gEnv->pLog->LogWarning("Map %s: Missing or invalid minimap info!", mapName.c_str());
  843.         }
  844. }
  845.  
  846. //------------------------------------------------------------------------
  847. const ILevelInfo::TGameTypeInfo* CLevelInfo::GetDefaultGameType() const
  848. {
  849.         if (!m_gameTypes.empty())
  850.         {
  851.                 return &m_gameTypes[0];
  852.         }
  853.  
  854.         return 0;
  855. };
  856.  
  857. /// Used by console auto completion.
  858. struct SLevelNameAutoComplete : public IConsoleArgumentAutoComplete
  859. {
  860.         std::vector<string> levels;
  861.         virtual int         GetCount() const           { return levels.size(); };
  862.         virtual const char* GetValue(int nIndex) const { return levels[nIndex].c_str(); };
  863. };
  864. // definition and declaration must be separated for devirtualization
  865. SLevelNameAutoComplete g_LevelNameAutoComplete;
  866.  
  867. //------------------------------------------------------------------------
  868. CLevelSystem::CLevelSystem(ISystem* pSystem, const char* levelsFolder)
  869.         : m_pSystem(pSystem),
  870.         m_pCurrentLevelInfo(nullptr),
  871.         m_pLoadingLevelInfo(nullptr)
  872. {
  873.         LOADING_TIME_PROFILE_SECTION;
  874.         CRY_ASSERT(pSystem);
  875.  
  876.         //Load user defined level types
  877.         if (XmlNodeRef levelTypeNode = m_pSystem->LoadXmlFromFile("Libs/Levels/leveltypes.xml"))
  878.         {
  879.                 for (unsigned int i = 0; i < levelTypeNode->getChildCount(); ++i)
  880.                 {
  881.                         XmlNodeRef child = levelTypeNode->getChild(i);
  882.                         const char* levelType;
  883.  
  884.                         if (child->getAttr("value", &levelType))
  885.                         {
  886.                                 m_levelTypeList.push_back(string(levelType));
  887.                         }
  888.                 }
  889.         }
  890.  
  891.         //if (!gEnv->IsEditor())
  892.         Rescan(levelsFolder, ILevelSystem::TAG_MAIN);
  893.  
  894.         // register with system to get loading progress events
  895.         m_pSystem->SetLoadingProgressListener(this);
  896.         m_fLastLevelLoadTime = 0;
  897.         m_fFilteredProgress = 0;
  898.         m_fLastTime = 0;
  899.         m_bLevelLoaded = false;
  900.         m_bRecordingFileOpens = false;
  901.  
  902.         m_levelLoadStartTime.SetValue(0);
  903.  
  904.         m_nLoadedLevelsCount = 0;
  905.  
  906.         m_extLevelRotations.resize(0);
  907.  
  908.         gEnv->pConsole->RegisterAutoComplete("map", &g_LevelNameAutoComplete);
  909. }
  910.  
  911. //------------------------------------------------------------------------
  912. CLevelSystem::~CLevelSystem()
  913. {
  914.         // register with system to get loading progress events
  915.         m_pSystem->SetLoadingProgressListener(0);
  916.  
  917.         // clean up the listeners
  918.         stl::free_container(m_listeners);
  919. }
  920.  
  921. //------------------------------------------------------------------------
  922. void CLevelSystem::Rescan(const char* levelsFolder, const uint32 tag)
  923. {
  924.         if (levelsFolder)
  925.         {
  926.                 if (const ICmdLineArg* pModArg = m_pSystem->GetICmdLine()->FindArg(eCLAT_Pre, "MOD"))
  927.                 {
  928.                         if (m_pSystem->IsMODValid(pModArg->GetValue()))
  929.                         {
  930.                                 m_levelsFolder.Format("Mods/%s/%s/%s", pModArg->GetValue(), PathUtil::GetGameFolder().c_str(), levelsFolder);
  931.                                 ScanFolder(0, true, tag);
  932.                         }
  933.                 }
  934.  
  935.                 m_levelsFolder = levelsFolder;
  936.         }
  937.  
  938.         CRY_ASSERT(!m_levelsFolder.empty());
  939.  
  940.         m_levelInfos.reserve(64);
  941.         ScanFolder(0, false, tag);
  942.  
  943.         g_LevelNameAutoComplete.levels.clear();
  944.         for (int i = 0; i < (int)m_levelInfos.size(); i++)
  945.         {
  946.                 g_LevelNameAutoComplete.levels.push_back(PathUtil::GetFileName(m_levelInfos[i].GetName()));
  947.         }
  948. }
  949.  
  950. void CLevelSystem::LoadRotation()
  951. {
  952.         if (ICVar* pLevelRotation = gEnv->pConsole->GetCVar("sv_levelrotation"))
  953.         {
  954.                 ILevelRotationFile* file = 0;
  955.                 IPlayerProfileManager* pProfileMan = CCryAction::GetCryAction()->GetIPlayerProfileManager();
  956.                 if (pProfileMan)
  957.                 {
  958.                         const char* userName = pProfileMan->GetCurrentUser();
  959.                         IPlayerProfile* pProfile = pProfileMan->GetCurrentProfile(userName);
  960.                         if (pProfile)
  961.                         {
  962.                                 file = pProfile->GetLevelRotationFile(pLevelRotation->GetString());
  963.                         }
  964.                         else if (pProfile = pProfileMan->GetDefaultProfile())
  965.                         {
  966.                                 file = pProfile->GetLevelRotationFile(pLevelRotation->GetString());
  967.                         }
  968.                 }
  969.                 bool ok = false;
  970.                 if (file)
  971.                 {
  972.                         ok = m_levelRotation.Load(file);
  973.                         file->Complete();
  974.                 }
  975.  
  976.                 if (!ok)
  977.                         CryWarning(VALIDATOR_MODULE_GAME, VALIDATOR_WARNING, "Failed to load '%s' as level rotation!", pLevelRotation->GetString());
  978.         }
  979. }
  980.  
  981. //------------------------------------------------------------------------
  982. void CLevelSystem::ScanFolder(const char* subfolder, bool modFolder, const uint32 tag)
  983. {
  984.         //CryLog("[DLC] ScanFolder:'%s' tag:'%.4s'", subfolder, (char*)&tag);
  985.         string folder;
  986.         if (subfolder && subfolder[0])
  987.                 folder = subfolder;
  988.  
  989.         string search(m_levelsFolder);
  990.         if (!folder.empty())
  991.                 search += string("/") + folder;
  992.         search += "/*.*";
  993.  
  994.         ICryPak* pPak = gEnv->pCryPak;
  995.  
  996.         _finddata_t fd;
  997.         intptr_t handle = 0;
  998.  
  999.         //CryLog("[DLC] ScanFolder: search:'%s'", search.c_str());
  1000.         // --kenzo
  1001.         // allow this find first to actually touch the file system
  1002.         // (causes small overhead but with minimal amount of levels this should only be around 150ms on actual DVD Emu)
  1003.         handle = pPak->FindFirst(search.c_str(), &fd, 0, true);
  1004.  
  1005.         if (handle > -1)
  1006.         {
  1007.                 do
  1008.                 {
  1009.                         if (!(fd.attrib & _A_SUBDIR) || !strcmp(fd.name, ".") || !strcmp(fd.name, ".."))
  1010.                         {
  1011.                                 continue;
  1012.                         }
  1013.  
  1014.                         CLevelInfo levelInfo;
  1015.  
  1016.                         string levelFolder = (folder.empty() ? "" : (folder + "/")) + string(fd.name);
  1017.                         string levelPath = m_levelsFolder + "/" + levelFolder;
  1018.                         string paks = levelPath + string("/*.pak");
  1019.  
  1020.                         //CryLog("[DLC] ScanFolder fd:'%s' levelPath:'%s'", fd.name, levelPath.c_str());
  1021.  
  1022.                         const string levelPakName = levelPath + "/level.pak";
  1023.                         const string levelXmlName = levelPath + "/" + fd.name + ".xml";
  1024. #if 0
  1025.                         if (pPak->IsFileExist(levelPakName.c_str(), ICryPak::eFileLocation_OnDisk))
  1026.                         {
  1027.                                 CryLog("[DLC] %s found on disk", levelPakName.c_str());
  1028.                         }
  1029.                         if (pPak->IsFileExist(levelXmlName.c_str()))
  1030.                         {
  1031.                                 CryLog("[DLC] %s found", levelXmlName.c_str());
  1032.                         }
  1033. #endif
  1034.  
  1035.                         if (!pPak->IsFileExist(levelPakName.c_str(), ICryPak::eFileLocation_OnDisk) && !pPak->IsFileExist(levelXmlName.c_str()))
  1036.                         {
  1037.                                 ScanFolder(levelFolder.c_str(), modFolder, tag);
  1038.                                 continue;
  1039.                         }
  1040.  
  1041.                         //CryLog("[DLC] ScanFolder adding level:'%s'", levelPath.c_str());
  1042.                         levelInfo.m_levelPath = levelPath;
  1043.                         levelInfo.m_levelPaks = paks;
  1044.                         levelInfo.m_levelName = levelFolder;
  1045.                         levelInfo.m_levelName = UnifyName(levelInfo.m_levelName);
  1046.                         levelInfo.m_isModLevel = modFolder;
  1047.                         levelInfo.m_scanTag = tag;
  1048.                         levelInfo.m_levelTag = ILevelSystem::TAG_UNKNOWN;
  1049.  
  1050.                         SwapEndian(levelInfo.m_scanTag, eBigEndian);
  1051.                         SwapEndian(levelInfo.m_levelTag, eBigEndian);
  1052.  
  1053.                         CLevelInfo* pExistingInfo = GetLevelInfoInternal(levelInfo.m_levelName);
  1054.                         if (pExistingInfo && pExistingInfo->MetadataLoaded() == false)
  1055.                         {
  1056.                                 //Reload metadata if it failed to load
  1057.                                 pExistingInfo->ReadMetaData();
  1058.                         }
  1059.  
  1060.                         // Don't add the level if it is already in the list
  1061.                         if (pExistingInfo == NULL)
  1062.                         {
  1063.                                 levelInfo.ReadMetaData();
  1064.  
  1065.                                 m_levelInfos.push_back(levelInfo);
  1066.                         }
  1067.                         else
  1068.                         {
  1069.                                 // Update the scan tag
  1070.                                 pExistingInfo->m_scanTag = tag;
  1071.                         }
  1072.  
  1073.                 }
  1074.                 while (pPak->FindNext(handle, &fd) >= 0);
  1075.  
  1076.                 pPak->FindClose(handle);
  1077.         }
  1078. }
  1079.  
  1080. //------------------------------------------------------------------------
  1081. int CLevelSystem::GetLevelCount()
  1082. {
  1083.         return (int)m_levelInfos.size();
  1084. }
  1085.  
  1086. //------------------------------------------------------------------------
  1087. ILevelInfo* CLevelSystem::GetLevelInfo(int level)
  1088. {
  1089.         return GetLevelInfoInternal(level);
  1090. }
  1091.  
  1092. //------------------------------------------------------------------------
  1093. CLevelInfo* CLevelSystem::GetLevelInfoInternal(int level)
  1094. {
  1095.         if ((level >= 0) && (level < GetLevelCount()))
  1096.         {
  1097.                 return &m_levelInfos[level];
  1098.         }
  1099.  
  1100.         return 0;
  1101. }
  1102.  
  1103. //------------------------------------------------------------------------
  1104. ILevelInfo* CLevelSystem::GetLevelInfo(const char* levelName)
  1105. {
  1106.         return GetLevelInfoInternal(levelName);
  1107. }
  1108.  
  1109. //------------------------------------------------------------------------
  1110. CLevelInfo* CLevelSystem::GetLevelInfoInternal(const char* levelName)
  1111. {
  1112.         // If level not found by full name try comparing with only filename
  1113.         for (std::vector<CLevelInfo>::iterator it = m_levelInfos.begin(); it != m_levelInfos.end(); ++it)
  1114.         {
  1115.                 if (!strcmpi(it->GetName(), levelName))
  1116.                 {
  1117.                         return &(*it);
  1118.                 }
  1119.         }
  1120.  
  1121.         //////////////////////////////////////////////////////////////////////////
  1122.         for (std::vector<CLevelInfo>::iterator it = m_levelInfos.begin(); it != m_levelInfos.end(); ++it)
  1123.         {
  1124.                 if (!strcmpi(PathUtil::GetFileName(it->GetName()), levelName))
  1125.                 {
  1126.                         return &(*it);
  1127.                 }
  1128.         }
  1129.  
  1130.         // Try stripping out the folder to find the raw filename
  1131.         string sLevelName(levelName);
  1132.         size_t lastSlash = sLevelName.find_last_of('\\');
  1133.         if (lastSlash == string::npos)
  1134.                 lastSlash = sLevelName.find_last_of('/');
  1135.         if (lastSlash != string::npos)
  1136.         {
  1137.                 sLevelName = sLevelName.substr(lastSlash + 1, sLevelName.size() - lastSlash - 1);
  1138.                 return GetLevelInfoInternal(sLevelName.c_str());
  1139.         }
  1140.  
  1141.         return 0;
  1142. }
  1143.  
  1144. //------------------------------------------------------------------------
  1145. void CLevelSystem::AddListener(ILevelSystemListener* pListener)
  1146. {
  1147.         std::vector<ILevelSystemListener*>::iterator it = std::find(m_listeners.begin(), m_listeners.end(), pListener);
  1148.  
  1149.         if (it == m_listeners.end())
  1150.         {
  1151.                 m_listeners.reserve(12);
  1152.                 m_listeners.push_back(pListener);
  1153.         }
  1154. }
  1155.  
  1156. //------------------------------------------------------------------------
  1157. void CLevelSystem::RemoveListener(ILevelSystemListener* pListener)
  1158. {
  1159.         std::vector<ILevelSystemListener*>::iterator it = std::find(m_listeners.begin(), m_listeners.end(), pListener);
  1160.  
  1161.         if (it != m_listeners.end())
  1162.         {
  1163.                 m_listeners.erase(it);
  1164.  
  1165.                 if (m_listeners.empty())
  1166.                 {
  1167.                         stl::free_container(m_listeners);
  1168.                 }
  1169.         }
  1170. }
  1171.  
  1172. // a guard scope that ensured that LiveCreate commands are not executed while level is loading
  1173. #ifndef NO_LIVECREATE
  1174. class CLiveCreateLevelLoadingBracket
  1175. {
  1176. public:
  1177.         CLiveCreateLevelLoadingBracket()
  1178.         {
  1179.                 gEnv->pLiveCreateHost->SuppressCommandExecution();
  1180.         }
  1181.  
  1182.         ~CLiveCreateLevelLoadingBracket()
  1183.         {
  1184.                 gEnv->pLiveCreateHost->ResumeCommandExecution();
  1185.         }
  1186. };
  1187. #endif
  1188.  
  1189. //------------------------------------------------------------------------
  1190. ILevelInfo* CLevelSystem::LoadLevel(const char* _levelName)
  1191. {
  1192. #ifndef NO_LIVECREATE
  1193.         CLiveCreateLevelLoadingBracket liveCreateLoadingBracket;
  1194. #endif
  1195.  
  1196.         gEnv->pSystem->SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START);
  1197.  
  1198.         MEMSTAT_CONTEXT_FMT(EMemStatContextTypes::MSC_Other, 0, "Level load (%s)", _levelName);
  1199.  
  1200.         CryLog("Level system is loading \"%s\"", _levelName);
  1201.         INDENT_LOG_DURING_SCOPE();
  1202.  
  1203.         char levelName[256];
  1204.         string sNextLevel(_levelName);
  1205.         cry_strcpy(levelName, _levelName);
  1206.  
  1207.         // Not remove a scope!!!
  1208.         {
  1209.                 LOADING_TIME_PROFILE_SECTION;
  1210.  
  1211.                 //m_levelLoadStartTime = gEnv->pTimer->GetAsyncTime();
  1212.  
  1213.                 CLevelInfo* pLevelInfo = GetLevelInfoInternal(levelName);
  1214.  
  1215.                 if (!pLevelInfo)
  1216.                 {
  1217.                         // alert the listener
  1218.                         OnLevelNotFound(levelName);
  1219.  
  1220.                         return 0;
  1221.                 }
  1222.  
  1223.                 m_bLevelLoaded = false;
  1224.  
  1225.                 m_lastLevelName = levelName;
  1226.  
  1227.                 //////////////////////////////////////////////////////////////////////////
  1228.                 // Read main level info.
  1229.                 if (!pLevelInfo->ReadInfo())
  1230.                 {
  1231.                         OnLoadingError(pLevelInfo, "Failed to read level info (level.pak might be corrupted)!");
  1232.                         return 0;
  1233.                 }
  1234.                 //////////////////////////////////////////////////////////////////////////
  1235.  
  1236.                 m_pCurrentLevelInfo = pLevelInfo;
  1237.  
  1238.                 gEnv->pConsole->SetScrollMax(600);
  1239.                 ICVar* con_showonload = gEnv->pConsole->GetCVar("con_showonload");
  1240.                 if (con_showonload && con_showonload->GetIVal() != 0)
  1241.                 {
  1242.                         gEnv->pConsole->ShowConsole(true);
  1243.                         ICVar* g_enableloadingscreen = gEnv->pConsole->GetCVar("g_enableloadingscreen");
  1244.                         if (g_enableloadingscreen)
  1245.                                 g_enableloadingscreen->Set(0);
  1246.                         ICVar* gfx_loadtimethread = gEnv->pConsole->GetCVar("gfx_loadtimethread");
  1247.                         if (gfx_loadtimethread)
  1248.                                 gfx_loadtimethread->Set(0);
  1249.                 }
  1250.  
  1251.                 // Reset the camera to (0,0,0) which is the invalid/uninitialised state
  1252.                 CCamera defaultCam;
  1253.                 m_pSystem->SetViewCamera(defaultCam);
  1254.                 IGameTokenSystem* pGameTokenSystem = CCryAction::GetCryAction()->GetIGameTokenSystem();
  1255.                 pGameTokenSystem->Reset();
  1256.  
  1257.                 m_pLoadingLevelInfo = pLevelInfo;
  1258.                 OnLoadingStart(pLevelInfo);
  1259.  
  1260.                 // ensure a physical global area is present
  1261.                 IPhysicalWorld* pPhysicalWorld = gEnv->pPhysicalWorld;
  1262.                 pPhysicalWorld->AddGlobalArea();
  1263.  
  1264.                 ICryPak* pPak = gEnv->pCryPak;
  1265.  
  1266.                 string levelPath = pLevelInfo->GetPath();
  1267.  
  1268.                 /*
  1269.                    ICVar *pFileCache = gEnv->pConsole->GetCVar("sys_FileCache");                CRY_ASSERT(pFileCache);
  1270.  
  1271.                    if(pFileCache->GetIVal())
  1272.                    {
  1273.                    if(pPak->OpenPack("",pLevelInfo->GetPath()+string("/FileCache.dat")))
  1274.                    gEnv->pLog->Log("FileCache.dat loaded");
  1275.                    else
  1276.                    gEnv->pLog->Log("FileCache.dat not loaded");
  1277.                    }
  1278.                  */
  1279.  
  1280.                 m_pSystem->SetThreadState(ESubsys_Physics, false);
  1281.  
  1282.                 ICVar* pSpamDelay = gEnv->pConsole->GetCVar("log_SpamDelay");
  1283.                 float spamDelay = 0.0f;
  1284.                 if (pSpamDelay)
  1285.                 {
  1286.                         spamDelay = pSpamDelay->GetFVal();
  1287.                         pSpamDelay->Set(0.0f);
  1288.                 }
  1289.  
  1290.                 // load all GameToken libraries this level uses incl. LevelLocal
  1291.                 pGameTokenSystem->LoadLibs(pLevelInfo->GetPath() + string("/GameTokens/*.xml"));
  1292.  
  1293.                 if (gEnv->pEntitySystem)
  1294.                 {
  1295.                         // load layer infos before load level by 3dEngine and EntitySystem
  1296.                         gEnv->pEntitySystem->LoadLayers(pLevelInfo->GetPath() + string("/LevelData.xml"));
  1297.                 }
  1298.  
  1299.                 if (!gEnv->p3DEngine->LoadLevel(pLevelInfo->GetPath(), pLevelInfo->GetDefaultGameType()->name))
  1300.                 {
  1301.                         OnLoadingError(pLevelInfo, "3DEngine failed to handle loading the level");
  1302.  
  1303.                         return 0;
  1304.                 }
  1305.  
  1306.                 OnLoadingLevelEntitiesStart(pLevelInfo);
  1307.  
  1308.                 gEnv->pSystem->SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_ENTITIES);
  1309.                 if (!gEnv->pEntitySystem || !gEnv->pEntitySystem->OnLoadLevel(pLevelInfo->GetPath()))
  1310.                 {
  1311.                         OnLoadingError(pLevelInfo, "EntitySystem failed to handle loading the level");
  1312.  
  1313.                         return 0;
  1314.                 }
  1315.  
  1316.                 // reset all the script timers
  1317.                 gEnv->pScriptSystem->ResetTimers();
  1318.  
  1319.                 if (gEnv->pAISystem)
  1320.                 {
  1321.                         gEnv->pAISystem->Reset(IAISystem::RESET_LOAD_LEVEL);
  1322.                 }
  1323.  
  1324.                 // Reset TimeOfDayScheduler
  1325.                 CCryAction::GetCryAction()->GetTimeOfDayScheduler()->Reset();
  1326.                 CCryAction::GetCryAction()->OnActionEvent(SActionEvent(eAE_loadLevel));
  1327.  
  1328.                 CCryAction::GetCryAction()->CreatePhysicsQueues();
  1329.  
  1330.                 // Reset dialog system
  1331.                 if (gEnv->pDialogSystem)
  1332.                 {
  1333.                         gEnv->pDialogSystem->Reset(false);
  1334.                         gEnv->pDialogSystem->Init();
  1335.                 }
  1336.  
  1337.                 if (gEnv->pAISystem && gEnv->pAISystem->IsEnabled())
  1338.                 {
  1339.                         gEnv->pAISystem->FlushSystem();
  1340.                         gEnv->pAISystem->LoadLevelData(pLevelInfo->GetPath(), pLevelInfo->GetDefaultGameType()->name);
  1341.                 }
  1342.  
  1343.                 if (auto* pGame = gEnv->pGameFramework->GetIGame())
  1344.                 {
  1345.                         pGame->LoadExportedLevelData(pLevelInfo->GetPath(), pLevelInfo->GetDefaultGameType()->name.c_str());
  1346.                 }
  1347.  
  1348.                 ICustomActionManager* pCustomActionManager = gEnv->pGameFramework->GetICustomActionManager();
  1349.                 if (pCustomActionManager)
  1350.                 {
  1351.                         pCustomActionManager->LoadLibraryActions(CUSTOM_ACTIONS_PATH);
  1352.                 }
  1353.  
  1354.                 if (gEnv->pEntitySystem)
  1355.                 {
  1356.                         gEnv->pEntitySystem->ReserveEntityId(1);
  1357.                         gEnv->pEntitySystem->ReserveEntityId(LOCAL_PLAYER_ENTITY_ID);
  1358.                 }
  1359.  
  1360.                 CCryAction::GetCryAction()->GetIGameRulesSystem()->CreateGameRules(CCryAction::GetCryAction()->GetGameContext()->GetRequestedGameRules());
  1361.  
  1362.                 string missionXml = pLevelInfo->GetDefaultGameType()->xmlFile;
  1363.                 string xmlFile = string(pLevelInfo->GetPath()) + "/" + missionXml;
  1364.  
  1365.                 XmlNodeRef rootNode = m_pSystem->LoadXmlFromFile(xmlFile.c_str());
  1366.                 if (rootNode)
  1367.                 {
  1368.                         INDENT_LOG_DURING_SCOPE(true, "Reading '%s'", xmlFile.c_str());
  1369.                         const char* script = rootNode->getAttr("Script");
  1370.  
  1371.                         if (script && script[0])
  1372.                         {
  1373.                                 CryLog("Executing script '%s'", script);
  1374.                                 INDENT_LOG_DURING_SCOPE();
  1375.                                 gEnv->pScriptSystem->ExecuteFile(script, true, true);
  1376.                         }
  1377.  
  1378.                         XmlNodeRef objectsNode = rootNode->findChild("Objects");
  1379.  
  1380.                         if (objectsNode)
  1381.                         {
  1382.                                 // Stop the network ticker thread before loading entities - otherwise the network queues
  1383.                                 // can get polled mid way through spawning an entity resulting in tasks being handled in
  1384.                                 // the wrong order.
  1385.                                 // Note: The network gets ticked after every 8 entity spawns so we are still ticking, just
  1386.                                 // not from the ticker thread.
  1387.                                 SCOPED_TICKER_LOCK;
  1388.  
  1389.                                 gEnv->pEntitySystem->LoadEntities(objectsNode, true);
  1390.                         }
  1391.                 }
  1392.  
  1393.                 // Now that we've registered our AI objects, we can init
  1394.                 if (gEnv->pAISystem)
  1395.                         gEnv->pAISystem->Reset(IAISystem::RESET_ENTER_GAME);
  1396.  
  1397.                 //////////////////////////////////////////////////////////////////////////
  1398.                 // Movie system must be loaded after entities.
  1399.                 //////////////////////////////////////////////////////////////////////////
  1400.                 string movieXml = pLevelInfo->GetPath() + string("/moviedata.xml");
  1401.                 IMovieSystem* movieSys = gEnv->pMovieSystem;
  1402.                 if (movieSys != NULL)
  1403.                 {
  1404.                         movieSys->Load(movieXml, pLevelInfo->GetDefaultGameType()->name);
  1405.                         movieSys->Reset(true, false); // bSeekAllToStart needs to be false here as it's only of interest in the editor (double checked with Timur Davidenko)
  1406.                 }
  1407.  
  1408.                 CCryAction::GetCryAction()->GetIMaterialEffects()->PreLoadAssets();
  1409.  
  1410.                 gEnv->pFlowSystem->Reset(false);
  1411.  
  1412.                 {
  1413. #if LEVEL_SYSTEM_SPAWN_ENTITIES_DURING_LOADING_COMPLETE_NOTIFICATION
  1414.                         // We spawn entities in this callback, so we need the network locked so it
  1415.                         // won't try to sync info for entities being spawned.
  1416.                         SCOPED_TICKER_LOCK;
  1417. #endif
  1418.  
  1419.                         LOADING_TIME_PROFILE_SECTION_NAMED("OnLoadingComplete");
  1420.                         // Inform Level system listeners that loading of the level is complete.
  1421.                         for (std::vector<ILevelSystemListener*>::const_iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
  1422.                         {
  1423.                                 (*it)->OnLoadingComplete(m_pCurrentLevelInfo);
  1424.                         }
  1425.                 }
  1426.  
  1427.                 gEnv->pSystem->SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_PRECACHE);
  1428.                 // Let gamerules precache anything needed
  1429.                 if (IGameRules* pGameRules = CCryAction::GetCryAction()->GetIGameRulesSystem()->GetCurrentGameRules())
  1430.                 {
  1431.                         pGameRules->PrecacheLevel();
  1432.                 }
  1433.  
  1434.                 //////////////////////////////////////////////////////////////////////////
  1435.                 // Notify 3D engine that loading finished
  1436.                 //////////////////////////////////////////////////////////////////////////
  1437.                 gEnv->p3DEngine->PostLoadLevel();
  1438.  
  1439.                 if (gEnv->pScriptSystem)
  1440.                 {
  1441.                         // After level was loaded force GC cycle in Lua
  1442.                         gEnv->pScriptSystem->ForceGarbageCollection();
  1443.                 }
  1444.                 //////////////////////////////////////////////////////////////////////////
  1445.  
  1446.                 //////////////////////////////////////////////////////////////////////////
  1447.                 //////////////////////////////////////////////////////////////////////////
  1448.                 gEnv->pConsole->SetScrollMax(600 / 2);
  1449.  
  1450.                 pPak->GetResourceList(ICryPak::RFOM_NextLevel)->Clear();
  1451.  
  1452.                 if (pSpamDelay)
  1453.                         pSpamDelay->Set(spamDelay);
  1454.  
  1455. #if CAPTURE_REPLAY_LOG
  1456.                 CryGetIMemReplay()->AddLabelFmt("loadEnd%d_%s", s_loadCount++, levelName);
  1457. #endif
  1458.  
  1459.                 gEnv->pConsole->GetCVar("sv_map")->Set(levelName);
  1460.  
  1461.                 m_bLevelLoaded = true;
  1462.         }
  1463.  
  1464.         return m_pCurrentLevelInfo;
  1465. }
  1466.  
  1467. //------------------------------------------------------------------------
  1468. ILevelInfo* CLevelSystem::SetEditorLoadedLevel(const char* levelName, bool bReadLevelInfoMetaData)
  1469. {
  1470.         CLevelInfo* pLevelInfo = GetLevelInfoInternal(levelName);
  1471.  
  1472.         if (!pLevelInfo)
  1473.         {
  1474.                 gEnv->pLog->LogError("Failed to get level info for level %s!", levelName);
  1475.                 return 0;
  1476.         }
  1477.  
  1478.         if (bReadLevelInfoMetaData)
  1479.                 pLevelInfo->ReadMetaData();
  1480.  
  1481.         m_lastLevelName = levelName;
  1482.  
  1483.         m_pCurrentLevelInfo = pLevelInfo;
  1484.         m_bLevelLoaded = true;
  1485.  
  1486.         return m_pCurrentLevelInfo;
  1487. }
  1488.  
  1489. //------------------------------------------------------------------------
  1490. // Search positions of all entities with class "PrecacheCamera" and pass it to the 3dengine
  1491. void CLevelSystem::PrecacheLevelRenderData()
  1492. {
  1493.         if (gEnv->IsDedicated())
  1494.                 return;
  1495.  
  1496.         //      gEnv->pSystem->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_LEVEL_PRECACHE_START, NULL, NULL);
  1497. #ifndef CONSOLE_CONST_CVAR_MODE
  1498.         ICVar* pPrecacheVar = gEnv->pConsole->GetCVar("e_PrecacheLevel");
  1499.         CRY_ASSERT(pPrecacheVar);
  1500.  
  1501.         if (pPrecacheVar && pPrecacheVar->GetIVal() > 0)
  1502.         {
  1503.                 if (I3DEngine* p3DEngine = gEnv->p3DEngine)
  1504.                 {
  1505.                         std::vector<Vec3> arrCamOutdoorPositions;
  1506.  
  1507.                         IEntitySystem* pEntitySystem = gEnv->pEntitySystem;
  1508.                         IEntityItPtr pEntityIter = pEntitySystem->GetEntityIterator();
  1509.  
  1510.                         IEntityClass* pPrecacheCameraClass = pEntitySystem->GetClassRegistry()->FindClass("PrecacheCamera");
  1511.                         IEntity* pEntity = nullptr;
  1512.                         while (pEntity = pEntityIter->Next())
  1513.                         {
  1514.                                 if (pEntity->GetClass() == pPrecacheCameraClass)
  1515.                                 {
  1516.                                         arrCamOutdoorPositions.push_back(pEntity->GetWorldPos());
  1517.                                 }
  1518.                         }
  1519.                         Vec3* pPoints = 0;
  1520.                         if (arrCamOutdoorPositions.size() > 0)
  1521.                         {
  1522.                                 pPoints = &arrCamOutdoorPositions[0];
  1523.                         }
  1524.  
  1525.                         p3DEngine->PrecacheLevel(true, pPoints, arrCamOutdoorPositions.size());
  1526.                 }
  1527.         }
  1528. #endif
  1529.         //      gEnv->pSystem->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_LEVEL_PRECACHE_END, NULL, NULL);
  1530. }
  1531.  
  1532. //------------------------------------------------------------------------
  1533. void CLevelSystem::PrepareNextLevel(const char* levelName)
  1534. {
  1535.         m_levelLoadStartTime = gEnv->pTimer->GetAsyncTime();
  1536.         CLevelInfo* pLevelInfo = GetLevelInfoInternal(levelName);
  1537.         if (!pLevelInfo)
  1538.         {
  1539.                 // alert the listener
  1540.                 //OnLevelNotFound(levelName);
  1541.                 return;
  1542.         }
  1543.  
  1544.         gEnv->pConsole->SetScrollMax(600);
  1545.         ICVar* con_showonload = gEnv->pConsole->GetCVar("con_showonload");
  1546.         if (con_showonload && con_showonload->GetIVal() != 0)
  1547.         {
  1548.                 gEnv->pConsole->ShowConsole(true);
  1549.                 ICVar* g_enableloadingscreen = gEnv->pConsole->GetCVar("g_enableloadingscreen");
  1550.                 if (g_enableloadingscreen)
  1551.                         g_enableloadingscreen->Set(0);
  1552.                 ICVar* gfx_loadtimethread = gEnv->pConsole->GetCVar("gfx_loadtimethread");
  1553.                 if (gfx_loadtimethread)
  1554.                         gfx_loadtimethread->Set(0);
  1555.         }
  1556.  
  1557.         // force a Lua deep garbage collection
  1558.         {
  1559.                 gEnv->pScriptSystem->ForceGarbageCollection();
  1560.         }
  1561.  
  1562. #if CAPTURE_REPLAY_LOG
  1563.         static int loadCount = 0;
  1564.         if (levelName)
  1565.         {
  1566.                 CryGetIMemReplay()->AddLabelFmt("?loadStart%d_%s", loadCount++, levelName);
  1567.         }
  1568.         else
  1569.         {
  1570.                 CryGetIMemReplay()->AddLabelFmt("?loadStart%d", loadCount++);
  1571.         }
  1572. #endif
  1573.  
  1574.         // Open pak file for a new level.
  1575.         pLevelInfo->OpenLevelPak();
  1576.  
  1577.         gEnv->pSystem->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_LEVEL_LOAD_START_LOADINGSCREEN, (UINT_PTR)pLevelInfo, 0);
  1578.         gEnv->pSystem->SetSystemGlobalState(ESYSTEM_GLOBAL_STATE_LEVEL_LOAD_START_PREPARE);
  1579.  
  1580.         // Inform resource manager about loading of the new level.
  1581.         GetISystem()->GetIResourceManager()->PrepareLevel(pLevelInfo->GetPath(), pLevelInfo->GetName());
  1582.  
  1583.         // Disable locking of resources to allow everything to be offloaded.
  1584.  
  1585.         //string filename = PathUtil::Make( pLevelInfo->GetPath(),"resourcelist.txt" );
  1586.         //gEnv->pCryPak->GetResourceList(ICryPak::RFOM_NextLevel)->Load( filename.c_str() );
  1587.  
  1588. }
  1589.  
  1590. //------------------------------------------------------------------------
  1591. void CLevelSystem::OnLevelNotFound(const char* levelName)
  1592. {
  1593.         for (std::vector<ILevelSystemListener*>::const_iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
  1594.         {
  1595.                 (*it)->OnLevelNotFound(levelName);
  1596.         }
  1597. }
  1598.  
  1599. //------------------------------------------------------------------------
  1600. void CLevelSystem::OnLoadingStart(ILevelInfo* pLevelInfo)
  1601. {
  1602.         LOADING_TIME_PROFILE_SECTION;
  1603.  
  1604.         if (gEnv->pCryPak->GetRecordFileOpenList() == ICryPak::RFOM_EngineStartup)
  1605.                 gEnv->pCryPak->RecordFileOpen(ICryPak::RFOM_Level);
  1606.  
  1607.         m_fFilteredProgress = 0.f;
  1608.         m_fLastTime = gEnv->pTimer->GetAsyncCurTime();
  1609.  
  1610.         if(gEnv->IsEditor()) //pure game calls it from CCET_LoadLevel
  1611.                 GetISystem()->GetISystemEventDispatcher()->OnSystemEvent( ESYSTEM_EVENT_LEVEL_LOAD_START,0,0 );
  1612.  
  1613. #if CRY_PLATFORM_WINDOWS
  1614.         /*
  1615.            m_bRecordingFileOpens = GetISystem()->IsDevMode() && gEnv->pCryPak->GetRecordFileOpenList() == ICryPak::RFOM_Disabled;
  1616.            if (m_bRecordingFileOpens)
  1617.            {
  1618.            gEnv->pCryPak->GetResourceList(ICryPak::RFOM_Level)->Clear();
  1619.            gEnv->pCryPak->RecordFileOpen(ICryPak::RFOM_Level);
  1620.            }
  1621.          */
  1622. #endif
  1623.  
  1624.         for (std::vector<ILevelSystemListener*>::const_iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
  1625.         {
  1626.                 (*it)->OnLoadingStart(pLevelInfo);
  1627.         }
  1628. }
  1629.  
  1630. //------------------------------------------------------------------------
  1631. void CLevelSystem::OnLoadingLevelEntitiesStart(ILevelInfo* pLevelInfo)
  1632. {
  1633.         for (std::vector<ILevelSystemListener*>::const_iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
  1634.         {
  1635.                 (*it)->OnLoadingLevelEntitiesStart(pLevelInfo);
  1636.         }
  1637. }
  1638.  
  1639. //------------------------------------------------------------------------
  1640. void CLevelSystem::OnLoadingError(ILevelInfo* pLevelInfo, const char* error)
  1641. {
  1642.         if (!pLevelInfo)
  1643.                 pLevelInfo = m_pLoadingLevelInfo;
  1644.         if (!pLevelInfo)
  1645.         {
  1646.                 CRY_ASSERT(false);
  1647.                 GameWarning("OnLoadingError without a currently loading level");
  1648.                 return;
  1649.         }
  1650.  
  1651.         if (gEnv->pRenderer)
  1652.         {
  1653.                 gEnv->pRenderer->SetTexturePrecaching(false);
  1654.         }
  1655.  
  1656.         for (std::vector<ILevelSystemListener*>::const_iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
  1657.         {
  1658.                 (*it)->OnLoadingError(pLevelInfo, error);
  1659.         }
  1660.  
  1661.         ((CLevelInfo*)pLevelInfo)->CloseLevelPak();
  1662. }
  1663.  
  1664. //------------------------------------------------------------------------
  1665. void CLevelSystem::OnLoadingComplete(ILevelInfo* pLevelInfo)
  1666. {
  1667.         PrecacheLevelRenderData();
  1668.  
  1669.         if (m_bRecordingFileOpens)
  1670.         {
  1671.                 // Stop recoding file opens.
  1672.                 gEnv->pCryPak->RecordFileOpen(ICryPak::RFOM_Disabled);
  1673.                 // Save recorded list.
  1674.                 SaveOpenedFilesList();
  1675.         }
  1676.  
  1677.         CTimeValue t = gEnv->pTimer->GetAsyncTime();
  1678.         m_fLastLevelLoadTime = (t - m_levelLoadStartTime).GetSeconds();
  1679.  
  1680.         if (!gEnv->IsEditor())
  1681.         {
  1682.                 CryLog("-----------------------------------------------------");
  1683.                 CryLog("*LOADING: Level %s loading time: %.2f seconds", m_lastLevelName.c_str(), m_fLastLevelLoadTime);
  1684.                 CryLog("-----------------------------------------------------");
  1685.         }
  1686.  
  1687.         LogLoadingTime();
  1688.  
  1689.         m_nLoadedLevelsCount++;
  1690.  
  1691.         // Hide console after loading.
  1692.         gEnv->pConsole->ShowConsole(false);
  1693.  
  1694.         //  gEnv->pCryPak->GetFileReadSequencer()->EndSection();
  1695.  
  1696.         if (!gEnv->bServer)
  1697.                 return;
  1698.  
  1699.         if (gEnv->pCharacterManager)
  1700.         {
  1701.                 SAnimMemoryTracker amt;
  1702.                 gEnv->pCharacterManager->SetAnimMemoryTracker(amt);
  1703.         }
  1704.         /*
  1705.            if( IStatsTracker* tr = CCryAction::GetCryAction()->GetIGameStatistics()->GetSessionTracker() )
  1706.            {
  1707.            string mapName = "no_map_assigned";
  1708.            if( pLevelInfo )
  1709.             if (ILevelInfo * pInfo = pLevelInfo->GetLevelInfo())
  1710.             {
  1711.               mapName = pInfo->GetName();
  1712.               PathUtil::RemoveExtension(mapName);
  1713.               mapName = PathUtil::GetFileName(mapName);
  1714.               mapName.MakeLower();
  1715.             }
  1716.            tr->StateValue(eSP_Map, mapName.c_str());
  1717.            }
  1718.          */
  1719.  
  1720.         // LoadLevel is not called in the editor, hence OnLoadingComplete is not invoked on the ILevelSystemListeners
  1721.         if (gEnv->IsEditor())
  1722.         {
  1723.                 for (std::vector<ILevelSystemListener*>::const_iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
  1724.                 {
  1725.                         (*it)->OnLoadingComplete(pLevelInfo);
  1726.                 }
  1727.  
  1728.                 SEntityEvent loadingCompleteEvent(ENTITY_EVENT_LEVEL_LOADED);
  1729.                 gEnv->pEntitySystem->SendEventToAll(loadingCompleteEvent);
  1730.         }
  1731. }
  1732.  
  1733. //------------------------------------------------------------------------
  1734. void CLevelSystem::OnLoadingProgress(ILevelInfo* pLevel, int progressAmount)
  1735. {
  1736.         for (std::vector<ILevelSystemListener*>::const_iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
  1737.         {
  1738.                 (*it)->OnLoadingProgress(pLevel, progressAmount);
  1739.         }
  1740. }
  1741.  
  1742. //------------------------------------------------------------------------
  1743. void CLevelSystem::OnUnloadComplete(ILevelInfo* pLevel)
  1744. {
  1745.         for (std::vector<ILevelSystemListener*>::const_iterator it = m_listeners.begin(); it != m_listeners.end(); ++it)
  1746.         {
  1747.                 (*it)->OnUnloadComplete(pLevel);
  1748.         }
  1749. }
  1750.  
  1751. //------------------------------------------------------------------------
  1752. void CLevelSystem::OnLoadingProgress(int steps)
  1753. {
  1754.         float fProgress = (float)gEnv->p3DEngine->GetLoadedObjectCount();
  1755.  
  1756.         m_fFilteredProgress = min(m_fFilteredProgress, fProgress);
  1757.  
  1758.         float fFrameTime = gEnv->pTimer->GetAsyncCurTime() - m_fLastTime;
  1759.  
  1760.         float t = CLAMP(fFrameTime * .25f, 0.0001f, 1.0f);
  1761.  
  1762.         m_fFilteredProgress = fProgress * t + m_fFilteredProgress * (1.f - t);
  1763.  
  1764.         m_fLastTime = gEnv->pTimer->GetAsyncCurTime();
  1765.  
  1766.         OnLoadingProgress(m_pLoadingLevelInfo, (int)m_fFilteredProgress);
  1767. }
  1768.  
  1769. //------------------------------------------------------------------------
  1770. string& CLevelSystem::UnifyName(string& name)
  1771. {
  1772.         //name.MakeLower();
  1773.         name.replace('\\', '/');
  1774.  
  1775.         return name;
  1776. }
  1777.  
  1778. //////////////////////////////////////////////////////////////////////////
  1779. void CLevelSystem::LogLoadingTime()
  1780. {
  1781.         if (gEnv->IsEditor())
  1782.                 return;
  1783.  
  1784.         if (!GetISystem()->IsDevMode())
  1785.                 return;
  1786.  
  1787. #if CRY_PLATFORM_WINDOWS
  1788.         CDebugAllowFileAccess ignoreInvalidFileAccess;
  1789.  
  1790.         string filename = gEnv->pSystem->GetRootFolder();
  1791.         filename += "Game_LevelLoadTime.log";
  1792.  
  1793.         FILE* file = fxopen(filename, "at");
  1794.         if (!file)
  1795.                 return;
  1796.  
  1797.         char vers[128];
  1798.         GetISystem()->GetFileVersion().ToString(vers);
  1799.  
  1800.         const char* sChain = "";
  1801.         if (m_nLoadedLevelsCount > 0)
  1802.                 sChain = " (Chained)";
  1803.  
  1804.         string text;
  1805.         text.Format("\n[%s] Level %s loaded in %d seconds%s", vers, m_lastLevelName.c_str(), (int)m_fLastLevelLoadTime, sChain);
  1806.         fwrite(text.c_str(), text.length(), 1, file);
  1807.         fclose(file);
  1808.  
  1809. #endif // Only log on windows.
  1810. }
  1811.  
  1812. void CLevelSystem::GetMemoryUsage(ICrySizer* pSizer) const
  1813. {
  1814.         pSizer->AddObject(this, sizeof(*this));
  1815.         pSizer->AddObject(m_levelInfos);
  1816.         pSizer->AddObject(m_levelsFolder);
  1817.         pSizer->AddObject(m_listeners);
  1818. }
  1819.  
  1820. void CLevelInfo::GetMemoryUsage(ICrySizer* pSizer) const
  1821. {
  1822.         pSizer->AddObject(m_levelName);
  1823.         pSizer->AddObject(m_levelPath);
  1824.         pSizer->AddObject(m_levelPaks);
  1825.         pSizer->AddObject(m_gamerules);
  1826.         pSizer->AddObject(m_gameTypes);
  1827. }
  1828.  
  1829. #ifndef NO_LIVECREATE
  1830.  
  1831. static bool SubsituteFile(const string& srcPath, const string& destPath)
  1832. {
  1833.         FILE* src = gEnv->pCryPak->FOpen(srcPath.c_str(), "rb", ICryPak::FOPEN_ONDISK);
  1834.         if (!src)
  1835.         {
  1836.                 CryLogAlways("SubsituteFile: Failed to open source file '%s'", srcPath.c_str());
  1837.                 return false;
  1838.         }
  1839.  
  1840.         FILE* dst = gEnv->pCryPak->FOpen(destPath.c_str(), "wb", ICryPak::FOPEN_ONDISK);
  1841.         if (!dst)
  1842.         {
  1843.                 CryLogAlways("SubsituteFile: Failed to open destination file '%s'", destPath.c_str());
  1844.                 gEnv->pCryPak->FClose(src);
  1845.                 return false;
  1846.         }
  1847.  
  1848.         const uint32 CHUNK_SIZE = 64 * 1024;
  1849.         char* buf = new char[CHUNK_SIZE];
  1850.         size_t readBytes = 0;
  1851.         size_t writtenBytes = 0;
  1852.         while (!gEnv->pCryPak->FEof(src))
  1853.         {
  1854.                 readBytes = gEnv->pCryPak->FReadRaw(buf, sizeof(char), CHUNK_SIZE, src);
  1855.                 writtenBytes = gEnv->pCryPak->FWrite(buf, sizeof(char), readBytes, dst);
  1856.  
  1857.                 if (readBytes != writtenBytes)
  1858.                 {
  1859.                         gEnv->pCryPak->FClose(src);
  1860.                         gEnv->pCryPak->FClose(dst);
  1861.  
  1862.                         delete[] buf;
  1863.                         return false;
  1864.                 }
  1865.         }
  1866.  
  1867.         delete[] buf;
  1868.         gEnv->pCryPak->FClose(src);
  1869.         gEnv->pCryPak->FClose(dst);
  1870.         return true;
  1871. }
  1872.  
  1873. #endif
  1874.  
  1875. //////////////////////////////////////////////////////////////////////////
  1876. bool CLevelInfo::OpenLevelPak()
  1877. {
  1878.         LOADING_TIME_PROFILE_SECTION;
  1879.         //////////////////////////////////////////////////////////////////////////
  1880.         //LiveCreate level reloading functionality
  1881. #ifndef NO_LIVECREATE
  1882.         // Overwrite level.pak
  1883.         {
  1884.                 const string newLevelPak = m_levelPath + string("/_level.pak");
  1885.                 const string curLevelPak = m_levelPath + string("/level.pak");
  1886.  
  1887.                 if (SubsituteFile(newLevelPak, curLevelPak))
  1888.                 {
  1889.                         if (!gEnv->pCryPak->RemoveFile(newLevelPak.c_str()))
  1890.                         {
  1891.                                 gEnv->pLog->LogWarning("Cleanup failed: _level.pak not removed");
  1892.                         }
  1893.                 }
  1894.         }
  1895.  
  1896.         // Overwrite terraintextures.pak
  1897.         {
  1898.                 const string newLevelPak = m_levelPath + string("/_terraintexture.pak");
  1899.                 const string curLevelPak = m_levelPath + string("/terraintexture.pak");
  1900.  
  1901.                 if (SubsituteFile(newLevelPak, curLevelPak))
  1902.                 {
  1903.                         if (!gEnv->pCryPak->RemoveFile(newLevelPak.c_str()))
  1904.                         {
  1905.                                 gEnv->pLog->LogWarning("Cleanup failed: terraintexture.pak not removed");
  1906.                         }
  1907.                 }
  1908.         }
  1909.  
  1910. #endif
  1911.         //////////////////////////////////////////////////////////////////////////
  1912.  
  1913.         string levelpak = m_levelPath + string("/level.pak");
  1914.         CryFixedStringT<ICryPak::g_nMaxPath> fullLevelPakPath;
  1915.         bool bOk = gEnv->pCryPak->OpenPack(levelpak, (unsigned)0, NULL, &fullLevelPakPath);
  1916.         m_levelPakFullPath.assign(fullLevelPakPath.c_str());
  1917.         if (bOk)
  1918.         {
  1919.                 string levelmmpak = m_levelPath + string("/levelmm.pak");
  1920.                 if (gEnv->pCryPak->IsFileExist(levelmmpak))
  1921.                 {
  1922.                         gEnv->pCryPak->OpenPack(levelmmpak, (unsigned)0, NULL, &fullLevelPakPath);
  1923.                         m_levelMMPakFullPath.assign(fullLevelPakPath.c_str());
  1924.                 }
  1925.         }
  1926.  
  1927.         gEnv->pCryPak->SetPacksAccessibleForLevel(GetName());
  1928.  
  1929.         return bOk;
  1930. }
  1931.  
  1932. //////////////////////////////////////////////////////////////////////////
  1933. void CLevelInfo::CloseLevelPak()
  1934. {
  1935.         LOADING_TIME_PROFILE_SECTION;
  1936.         if (!m_levelPakFullPath.empty())
  1937.         {
  1938.                 gEnv->pCryPak->ClosePack(m_levelPakFullPath.c_str(), ICryPak::FLAGS_PATH_REAL);
  1939.                 stl::free_container(m_levelPakFullPath);
  1940.         }
  1941.  
  1942.         if (!m_levelMMPakFullPath.empty())
  1943.         {
  1944.                 gEnv->pCryPak->ClosePack(m_levelMMPakFullPath.c_str(), ICryPak::FLAGS_PATH_REAL);
  1945.                 stl::free_container(m_levelMMPakFullPath);
  1946.         }
  1947. }
  1948.  
  1949. const bool CLevelInfo::IsOfType(const char* sType) const
  1950. {
  1951.         for (unsigned int i = 0; i < m_levelTypeList.size(); ++i)
  1952.         {
  1953.                 if (strcmp(m_levelTypeList[i], sType) == 0)
  1954.                         return true;
  1955.         }
  1956.  
  1957.         return false;
  1958. }
  1959.  
  1960. //////////////////////////////////////////////////////////////////////////
  1961. void CLevelSystem::SaveOpenedFilesList()
  1962. {
  1963.         if (!m_pLoadingLevelInfo)
  1964.                 return;
  1965.  
  1966.         // Write resource list to file.
  1967.         string filename = PathUtil::Make(m_pLoadingLevelInfo->GetPath(), "resourcelist.txt");
  1968.         FILE* file = fxopen(filename.c_str(), "wt", true);
  1969.         if (file)
  1970.         {
  1971.                 IResourceList* pResList = gEnv->pCryPak->GetResourceList(ICryPak::RFOM_Level);
  1972.                 for (const char* fname = pResList->GetFirst(); fname; fname = pResList->GetNext())
  1973.                 {
  1974.                         fprintf(file, "%s\n", fname);
  1975.                 }
  1976.                 fclose(file);
  1977.         }
  1978. }
  1979.  
  1980. //////////////////////////////////////////////////////////////////////////
  1981. void CLevelSystem::UnLoadLevel()
  1982. {
  1983.         if (gEnv->IsEditor())
  1984.                 return;
  1985.         if (!m_pLoadingLevelInfo)
  1986.                 return;
  1987.  
  1988.         CryLog("UnLoadLevel Start");
  1989.         INDENT_LOG_DURING_SCOPE();
  1990.  
  1991.         CTimeValue tBegin = gEnv->pTimer->GetAsyncTime();
  1992.  
  1993.         // One last update to execute pending requests.
  1994.         // Do this before the EntitySystem resets!
  1995.         if (gEnv->pFlowSystem)
  1996.         {
  1997.                 gEnv->pFlowSystem->Update();
  1998.         }
  1999.  
  2000.         I3DEngine* p3DEngine = gEnv->p3DEngine;
  2001.         if (p3DEngine)
  2002.         {
  2003.                 IDeferredPhysicsEventManager* pPhysEventManager = p3DEngine->GetDeferredPhysicsEventManager();
  2004.                 if (pPhysEventManager)
  2005.                 {
  2006.                         // clear deferred physics queues before renderer, since we could have jobs running
  2007.                         // which access a rendermesh
  2008.                         pPhysEventManager->ClearDeferredEvents();
  2009.                 }
  2010.         }
  2011.  
  2012.         //AM: Flush render thread (Flush is not exposed - using EndFrame())
  2013.         //We are about to delete resources that could be in use
  2014.         if (gEnv->pRenderer)
  2015.         {
  2016.                 gEnv->pRenderer->EndFrame();
  2017.  
  2018.                 // force a black screen as last render command
  2019.                 gEnv->pRenderer->BeginFrame();
  2020.                 gEnv->pRenderer->SetState(GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA | GS_NODEPTHTEST);
  2021.                 gEnv->pRenderer->Draw2dImage(0, 0, 800, 600, -1, 0.0f, 0.0f, 1.0f, 1.0f, 0.f,
  2022.                                              0.0f, 0.0f, 0.0f, 1.0, 0.f);
  2023.                 gEnv->pRenderer->EndFrame();
  2024.  
  2025.                 //flush any outstanding texture requests
  2026.                 gEnv->pRenderer->FlushPendingTextureTasks();
  2027.         }
  2028.  
  2029.         // Disable filecaching during level unloading
  2030.         // will be reenabled when we get back to the IIS (frontend directly)
  2031.         // or after level loading is finished (via system event system)
  2032.         gEnv->pSystem->GetPlatformOS()->AllowOpticalDriveUsage(false);
  2033.  
  2034.         if (gEnv->pScriptSystem)
  2035.         {
  2036.                 gEnv->pScriptSystem->ResetTimers();
  2037.         }
  2038.  
  2039.         CCryAction* pCryAction = CCryAction::GetCryAction();
  2040.         if (pCryAction)
  2041.         {
  2042.                 if (IItemSystem* pItemSystem = pCryAction->GetIItemSystem())
  2043.                 {
  2044.                         pItemSystem->ClearGeometryCache();
  2045.                         pItemSystem->ClearSoundCache();
  2046.                         pItemSystem->Reset();
  2047.                 }
  2048.  
  2049.                 if (ICooperativeAnimationManager* pCoopAnimManager = pCryAction->GetICooperativeAnimationManager())
  2050.                 {
  2051.                         pCoopAnimManager->Reset();
  2052.                 }
  2053.  
  2054.                 pCryAction->ClearBreakHistory();
  2055.  
  2056.                 // Custom actions (Active + Library) keep a smart ptr to flow graph and need to be cleared before get below to the gEnv->pFlowSystem->Reset(true);
  2057.                 ICustomActionManager* pCustomActionManager = pCryAction->GetICustomActionManager();
  2058.                 if (pCustomActionManager)
  2059.                 {
  2060.                         pCustomActionManager->ClearActiveActions();
  2061.                         pCustomActionManager->ClearLibraryActions();
  2062.                 }
  2063.  
  2064.                 IGameVolumes* pGameVolumes = pCryAction->GetIGameVolumesManager();
  2065.                 if (pGameVolumes)
  2066.                 {
  2067.                         pGameVolumes->Reset();
  2068.                 }
  2069.         }
  2070.  
  2071.         if (gEnv->pEntitySystem)
  2072.         {
  2073.                 gEnv->pEntitySystem->Unload(); // This needs to be called for editor and game, otherwise entities won't be released
  2074.         }
  2075.  
  2076.         if (pCryAction)
  2077.         {
  2078.                 // Custom events are used by prefab events and should have been removed once entities which have the prefab flownodes have been destroyed
  2079.                 // Just in case, clear all the events anyway
  2080.                 ICustomEventManager* pCustomEventManager = pCryAction->GetICustomEventManager();
  2081.                 CRY_ASSERT(pCustomEventManager != NULL);
  2082.                 pCustomEventManager->Clear();
  2083.  
  2084.                 pCryAction->OnActionEvent(SActionEvent(eAE_unloadLevel));
  2085.                 pCryAction->ClearPhysicsQueues();
  2086.                 pCryAction->GetTimeOfDayScheduler()->Reset();
  2087.         }
  2088.  
  2089.         // reset a bunch of subsystems
  2090.         if (gEnv->pDialogSystem)
  2091.         {
  2092.                 gEnv->pDialogSystem->Reset(true);
  2093.         }
  2094.  
  2095.         if (gEnv->pGameFramework)
  2096.         {
  2097.                 gEnv->pGameFramework->GetIMaterialEffects()->Reset(true);
  2098.         }
  2099.  
  2100.         if (gEnv->pAISystem)
  2101.         {
  2102.                 gEnv->pAISystem->FlushSystem(true);
  2103.                 gEnv->pAISystem->Reset(IAISystem::RESET_EXIT_GAME);
  2104.                 gEnv->pAISystem->Reset(IAISystem::RESET_UNLOAD_LEVEL);
  2105.         }
  2106.  
  2107.         if (gEnv->pMovieSystem)
  2108.         {
  2109.                 gEnv->pMovieSystem->Reset(false, false);
  2110.                 gEnv->pMovieSystem->RemoveAllSequences();
  2111.         }
  2112.  
  2113.         // Unload level specific audio binary data.
  2114.         SAudioManagerRequestData<eAudioManagerRequestType_UnloadAFCMDataByScope> requestData1(eAudioDataScope_LevelSpecific);
  2115.         SAudioRequest request;
  2116.         request.flags = eAudioRequestFlags_PriorityHigh | eAudioRequestFlags_ExecuteBlocking;
  2117.         request.pData = &requestData1;
  2118.         gEnv->pAudioSystem->PushRequest(request);
  2119.  
  2120.         // Now unload level specific audio config data.
  2121.         SAudioManagerRequestData<eAudioManagerRequestType_ClearControlsData> requestData2(eAudioDataScope_LevelSpecific);
  2122.         request.pData = &requestData2;
  2123.         gEnv->pAudioSystem->PushRequest(request);
  2124.  
  2125.         SAudioManagerRequestData<eAudioManagerRequestType_ClearPreloadsData> requestData3(eAudioDataScope_LevelSpecific);
  2126.         request.pData = &requestData3;
  2127.         gEnv->pAudioSystem->PushRequest(request);
  2128.  
  2129.         // Delete engine resources
  2130.         if (p3DEngine)
  2131.         {
  2132.                 p3DEngine->UnloadLevel();
  2133.         }
  2134.  
  2135.         if (pCryAction)
  2136.         {
  2137.                 IGameObjectSystem* pGameObjectSystem = pCryAction->GetIGameObjectSystem();
  2138.                 pGameObjectSystem->Reset();
  2139.         }
  2140.  
  2141.         IGameTokenSystem* pGameTokenSystem = CCryAction::GetCryAction()->GetIGameTokenSystem();
  2142.         pGameTokenSystem->RemoveLibrary("Level");
  2143.         pGameTokenSystem->Reset();
  2144.  
  2145.         if (gEnv->pFlowSystem)
  2146.         {
  2147.                 gEnv->pFlowSystem->Reset(true);
  2148.         }
  2149.  
  2150.         if (gEnv->pEntitySystem)
  2151.         {
  2152.                 gEnv->pEntitySystem->PurgeHeaps(); // This needs to be called for editor and game, otherwise entities won't be released
  2153.         }
  2154.  
  2155.         // Reset the camera to (0,0,0) which is the invalid/uninitialised state
  2156.         CCamera defaultCam;
  2157.         m_pSystem->SetViewCamera(defaultCam);
  2158.  
  2159.         if (pCryAction)
  2160.         {
  2161.                 pCryAction->OnActionEvent(SActionEvent(eAE_postUnloadLevel));
  2162.         }
  2163.  
  2164.         OnUnloadComplete(m_pCurrentLevelInfo);
  2165.  
  2166.         // -- kenzo: this will close all pack files for this level
  2167.         // (even the ones which were not added through here, if this is not desired,
  2168.         // then change code to close only level.pak)
  2169.         if (m_pLoadingLevelInfo)
  2170.         {
  2171.                 ((CLevelInfo*)m_pLoadingLevelInfo)->CloseLevelPak();
  2172.                 m_pLoadingLevelInfo = NULL;
  2173.         }
  2174.  
  2175.         stl::free_container(m_lastLevelName);
  2176.  
  2177.         GetISystem()->GetIResourceManager()->UnloadLevel();
  2178.  
  2179.         m_pCurrentLevelInfo = nullptr;
  2180.  
  2181.         // Force to clean render resources left after deleting all objects and materials.
  2182.         IRenderer* pRenderer = gEnv->pRenderer;
  2183.         if (pRenderer)
  2184.         {
  2185.                 pRenderer->FlushRTCommands(true, true, true);
  2186.  
  2187.                 CryComment("Deleting Render meshes, render resources and flush texture streaming");
  2188.                 // This may also release some of the materials.
  2189.                 int flags = FRR_DELETED_MESHES | FRR_FLUSH_TEXTURESTREAMING | FRR_OBJECTS | FRR_RENDERELEMENTS | FRR_RP_BUFFERS | FRR_POST_EFFECTS;
  2190.  
  2191.                 // Always keep the system resources around in the editor.
  2192.                 if (!gEnv->IsEditor())
  2193.                         flags |= FRR_SYSTEM_RESOURCES;
  2194.  
  2195.                 pRenderer->FreeResources(flags);
  2196.                 CryComment("done");
  2197.         }
  2198.  
  2199.         m_bLevelLoaded = false;
  2200.  
  2201.         CTimeValue tUnloadTime = gEnv->pTimer->GetAsyncTime() - tBegin;
  2202.         CryLog("UnLoadLevel End: %.1f sec", tUnloadTime.GetSeconds());
  2203.  
  2204.         // Must be sent last.
  2205.         // Cleanup all containers
  2206.         GetISystem()->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_LEVEL_POST_UNLOAD, 0, 0);
  2207. }
  2208.  
  2209. //////////////////////////////////////////////////////////////////////////
  2210. ILevelRotation* CLevelSystem::FindLevelRotationForExtInfoId(const ILevelRotation::TExtInfoId findId)
  2211. {
  2212.         CLevelRotation* pRot = NULL;
  2213.  
  2214.         TExtendedLevelRotations::iterator begin = m_extLevelRotations.begin();
  2215.         TExtendedLevelRotations::iterator end = m_extLevelRotations.end();
  2216.         for (TExtendedLevelRotations::iterator i = begin; i != end; ++i)
  2217.         {
  2218.                 CLevelRotation* pIterRot = &(*i);
  2219.                 if (pIterRot->GetExtendedInfoId() == findId)
  2220.                 {
  2221.                         pRot = pIterRot;
  2222.                         break;
  2223.                 }
  2224.         }
  2225.  
  2226.         return pRot;
  2227. }
  2228.  
  2229. //////////////////////////////////////////////////////////////////////////
  2230. bool CLevelSystem::AddExtendedLevelRotationFromXmlRootNode(const XmlNodeRef rootNode, const char* altRootTag, const ILevelRotation::TExtInfoId extInfoId)
  2231. {
  2232.         bool ok = false;
  2233.  
  2234.         CRY_ASSERT(extInfoId);
  2235.  
  2236.         if (!FindLevelRotationForExtInfoId(extInfoId))
  2237.         {
  2238.                 m_extLevelRotations.push_back(CLevelRotation());
  2239.                 CLevelRotation* pRot = &m_extLevelRotations.back();
  2240.  
  2241.                 if (pRot->LoadFromXmlRootNode(rootNode, altRootTag))
  2242.                 {
  2243.                         pRot->SetExtendedInfoId(extInfoId);
  2244.                         ok = true;
  2245.                 }
  2246.                 else
  2247.                 {
  2248.                         LOCAL_WARNING(0, string().Format("Couldn't add extended level rotation with id '%u' because couldn't read the xml info root node for some reason!", extInfoId).c_str());
  2249.                 }
  2250.         }
  2251.         else
  2252.         {
  2253.                 LOCAL_WARNING(0, string().Format("Couldn't add extended level rotation with id '%u' because there's already one with that id!", extInfoId).c_str());
  2254.         }
  2255.  
  2256.         return ok;
  2257. }
  2258.  
  2259. //////////////////////////////////////////////////////////////////////////
  2260. void CLevelSystem::ClearExtendedLevelRotations()
  2261. {
  2262.         m_extLevelRotations.clear();
  2263. }
  2264.  
  2265. //////////////////////////////////////////////////////////////////////////
  2266. ILevelRotation* CLevelSystem::CreateNewRotation(const ILevelRotation::TExtInfoId id)
  2267. {
  2268.         CLevelRotation* pRotation = static_cast<CLevelRotation*>(FindLevelRotationForExtInfoId(id));
  2269.  
  2270.         if (!pRotation)
  2271.         {
  2272.                 m_extLevelRotations.push_back(CLevelRotation());
  2273.                 pRotation = &m_extLevelRotations.back();
  2274.                 pRotation->SetExtendedInfoId(id);
  2275.         }
  2276.         else
  2277.         {
  2278.                 pRotation->Reset();
  2279.                 pRotation->SetExtendedInfoId(id);
  2280.         }
  2281.  
  2282.         return pRotation;
  2283. }
  2284.  
  2285. DynArray<string>* CLevelSystem::GetLevelTypeList()
  2286. {
  2287.         return &m_levelTypeList;
  2288. }
  2289.  
  2290. #undef LOCAL_WARNING
  2291.  
downloadLevelSystem.cpp Source code - Download CRYENGINE Source code
Related Source Codes/Software:
postal - 2017-06-11
reactide - Reactide is the first dedicated IDE for React web ... 2017-06-11
rkt - rkt is a pod-native container engine for Linux. It... 2017-06-11
uWebSockets - Tiny WebSockets https://for... 2017-06-11
realworld - TodoMVC for the RealWorld - Exemplary fullstack Me... 2017-06-11
CRYENGINE - CRYENGINE is a powerful real-time game development... 2017-06-11
goreplay - GoReplay is an open-source tool for capturing and ... 2017-06-10
pyenv - Simple Python version management 2017-06-10
redux-saga - An alternative side effect model for Redux apps ... 2017-06-10
angular-starter - 2017-06-10

 Back to top