text: // CryEngine Header File.
  // Copyright (C), Crytek, 1999-2014.
  
  
  #ifndef __LEVELSYSTEM_H__
  #define __LEVELSYSTEM_H__
  
  #if _MSC_VER > 1000
  # pragma once
  #endif
  
  #include "ILevelSystem.h"
  
  #define LEVEL_ROTATION_DEBUG 0
  
  #if LEVEL_ROTATION_DEBUG
  #define Log_LevelRotation(...) CryLog( "CLevelRotation" __VA_ARGS__)
  #else
  #define Log_LevelRotation(...)
  #endif
  
  class CLevelInfo :
  	public ILevelInfo
  {
  	friend class CLevelSystem;
  public:
  	CLevelInfo(): m_heightmapSize(0), m_bMetaDataRead(false), m_isModLevel(false), m_scanTag(ILevelSystem::TAG_UNKNOWN), m_levelTag(ILevelSystem::TAG_UNKNOWN)
  	{
  		SwapEndian(m_scanTag, eBigEndian);
  		SwapEndian(m_levelTag, eBigEndian);
  	};
  
  	// ILevelInfo
  	VIRTUAL const char *GetName() const { return m_levelName.c_str(); };
  	VIRTUAL const bool IsOfType(const char* sType) const;
  	VIRTUAL const char *GetPath() const { return m_levelPath.c_str(); };
  	VIRTUAL const char *GetPaks() const { return m_levelPaks.c_str(); };
  	VIRTUAL bool GetIsModLevel() const { return m_isModLevel; }
  	VIRTUAL const uint32 GetScanTag() const { return m_scanTag; }
  	VIRTUAL const uint32 GetLevelTag() const { return m_levelTag; }
  	VIRTUAL const char* GetDisplayName() const;
  	VIRTUAL const char *GetPreviewImagePath() const { return m_previewImagePath.c_str(); }
  	VIRTUAL const char *GetBackgroundImagePath() const { return m_backgroundImagePath.c_str(); }
  	VIRTUAL const char *GetMinimapImagePath() const {return m_minimapImagePath.c_str(); }
    //VIRTUAL const ILevelInfo::TStringVec& GetMusicLibs() const { return m_musicLibs; }; // Gets reintroduced when level specific music data loading is implemented.
  	VIRTUAL int GetHeightmapSize() const { return m_heightmapSize; };
  	VIRTUAL const bool MetadataLoaded() const { return m_bMetaDataRead; }
  
  	VIRTUAL int GetGameTypeCount() const { return m_gameTypes.size(); };
  	VIRTUAL const ILevelInfo::TGameTypeInfo *GetGameType(int gameType) const { return &m_gameTypes[gameType]; };
  	VIRTUAL bool SupportsGameType(const char *gameTypeName) const;
  	VIRTUAL const ILevelInfo::TGameTypeInfo *GetDefaultGameType() const;
  	VIRTUAL bool HasGameRules() const{ return !m_gamerules.empty(); }
  
  	VIRTUAL const ILevelInfo::SMinimapInfo& GetMinimapInfo() const { return m_minimapInfo; }
  
  	VIRTUAL const char* GetDefaultGameRules() const{ return m_gamerules.empty() ? NULL : m_gamerules[0].c_str(); }
  	VIRTUAL ILevelInfo::TStringVec GetGameRules() const{ return m_gamerules; }
  	VIRTUAL bool GetAttribute(const char* name, TFlowInputData& val) const;
  	// ~ILevelInfo
  
  
  	void GetMemoryUsage(ICrySizer * ) const;
  	
  private:
    void        ReadMetaData();
  	bool        ReadInfo();
  
  	bool        OpenLevelPak();
  	void        CloseLevelPak();
  
  	string			m_levelName;
  	string			m_levelPath;
  	string			m_levelPaks;
  	string      m_levelDisplayName;
  	string			m_previewImagePath;
  	string			m_backgroundImagePath;
  	string			m_minimapImagePath;
  	
  	string			m_levelPakFullPath;
  	string			m_levelMMPakFullPath;
  
  	//TStringVec	m_musicLibs;
  	TStringVec  m_gamerules;
  	int					m_heightmapSize;
  	uint32			m_scanTag;
  	uint32			m_levelTag;
  	bool				m_bMetaDataRead;
  	std::vector<ILevelInfo::TGameTypeInfo> m_gameTypes;
  	bool        m_isModLevel;
  	SMinimapInfo m_minimapInfo;
  	typedef std::map< string, TFlowInputData, stl::less_stricmp<string> > TAttributeList;
  	TAttributeList m_levelAttributes;
  
  	DynArray<string>		m_levelTypeList;
  };
  
  
  class CLevelRotation : public ILevelRotation
  {
  public:
  	CLevelRotation();
  	virtual ~CLevelRotation();
  
  	typedef struct SLevelRotationEntry
  	{
  		string levelName;
  		std::vector<string> gameRulesNames;
  		std::vector<int> gameRulesShuffle;
  		int currentModeIndex;
  
  		const char* GameModeName() const; //will return next game mode/rules according to shuffle
  	} SLevelRotationEntry;
  
  	typedef std::vector<SLevelRotationEntry> TLevelRotationVector;
  
  	// ILevelRotation
  	VIRTUAL bool Load(ILevelRotationFile* file);
  	VIRTUAL bool LoadFromXmlRootNode(const XmlNodeRef rootNode, const char* altRootTag);
  	
  	VIRTUAL void Reset();
  	VIRTUAL int  AddLevel(const char *level);
  	VIRTUAL void AddGameMode(int level, const char* gameMode);
  
  	VIRTUAL int  AddLevel(const char *level, const char* gameMode);
  
  	//call to set the playlist ready for a new session
  	VIRTUAL void Initialise( int nSeed );
  
  	VIRTUAL bool First();
  	VIRTUAL bool Advance();
  
  	VIRTUAL bool AdvanceAndLoopIfNeeded();
  
  	VIRTUAL const char *GetNextLevel() const;
  	VIRTUAL const char *GetNextGameRules() const;
  
  	VIRTUAL const char*	GetLevel( uint32 idx, bool accessShuffled = true ) const;
  	VIRTUAL int GetNGameRulesForEntry( uint32 idx, bool accessShuffled = true ) const;
  	VIRTUAL const char*	GetGameRules( uint32 idx, uint32 iMode, bool accessShuffled = true ) const;
  
  	VIRTUAL const char* GetNextGameRulesForEntry( int idx ) const; //always matches shuffling
  
  	VIRTUAL const int NumAdvancesTaken() const;
  	VIRTUAL void ResetAdvancement();
  
  	VIRTUAL int GetLength() const;
  	VIRTUAL int GetTotalGameModeEntries() const;
  	VIRTUAL int GetNext() const;
  
  	VIRTUAL void ChangeLevel(IConsoleCmdArgs* pArgs = NULL);
  
  	VIRTUAL bool NextPairMatch() const;
  
  	VIRTUAL TRandomisationFlags GetRandomisationFlags() const { return m_randFlags; }
  	VIRTUAL void SetRandomisationFlags( TRandomisationFlags flags );
  
  	VIRTUAL bool IsRandom()const;
  	//~ILevelRotation
  
  	ILINE void SetExtendedInfoId(const ILevelRotation::TExtInfoId id) { m_extInfoId = id; }
  	ILINE ILevelRotation::TExtInfoId  GetExtendedInfoId() { return m_extInfoId; }
  
  protected:
  
  	void ModeShuffle();
  	void ShallowShuffle();
  	void AddGameMode(SLevelRotationEntry& level, const char* gameMode);
  	void AddLevelFromNode( const char* levelName, XmlNodeRef& levelNode );
  
  	ILINE int GetRealRotationIndex( uint idx, bool accessShuffled ) const
  	{
  		int realId = idx;
  		if( idx < m_rotation.size() )
  		{
  			if( accessShuffled && (m_randFlags & ePRF_Shuffle) )
  			{
  				realId = m_shuffle[ idx ];
  			}
  		}
  		else
  		{
  			realId = -1;
  		}
  
  		Log_LevelRotation( " GetRealRotationIndex passed %d returning %d", idx, realId );
  		return realId;
  	}
  
  	TLevelRotationVector m_rotation;
  	TRandomisationFlags  m_randFlags;
  	int                  m_next;
  	std::vector<uint>    m_shuffle;
  	int                  m_advancesTaken;
  
  	ILevelRotation::TExtInfoId  m_extInfoId;	//if this ID is set, we disable implicit shuffling
  	bool m_hasGameModesDecks;
  };
  
  class CLevelSystem :
  	public ILevelSystem,
  	public ISystem::ILoadingProgressListener
  {
  public:
  	CLevelSystem(ISystem *pSystem, const char *levelsFolder);
  	virtual ~CLevelSystem();
  
  	void Release() { delete this; };
  
  	// ILevelSystem
  	VIRTUAL DynArray<string>* GetLevelTypeList();
  	VIRTUAL void Rescan(const char *levelsFolder, const uint32 tag);
    VIRTUAL void LoadRotation();
  	VIRTUAL int GetLevelCount();
  	VIRTUAL ILevelInfo *GetLevelInfo(int level);
  	VIRTUAL ILevelInfo *GetLevelInfo(const char *levelName);
  
  	VIRTUAL void AddListener(ILevelSystemListener *pListener);
  	VIRTUAL void RemoveListener(ILevelSystemListener *pListener);
  
  	VIRTUAL ILevel *GetCurrentLevel() const { return m_pCurrentLevel;	}
  	VIRTUAL ILevel *LoadLevel(const char *levelName);
  	VIRTUAL void UnLoadLevel();
  	VIRTUAL ILevel *SetEditorLoadedLevel(const char *levelName, bool bReadLevelInfoMetaData = false);
  	VIRTUAL void PrepareNextLevel(const char *levelName);
  	VIRTUAL float GetLastLevelLoadTime() { return m_fLastLevelLoadTime; };
  	VIRTUAL bool IsLevelLoaded() { return m_bLevelLoaded; }
  
  	VIRTUAL ILevelRotation* GetLevelRotation() { return &m_levelRotation; };
  
  	VIRTUAL ILevelRotation* FindLevelRotationForExtInfoId(const ILevelRotation::TExtInfoId findId);
  
  	VIRTUAL bool AddExtendedLevelRotationFromXmlRootNode(const XmlNodeRef rootNode, const char* altRootTag, const ILevelRotation::TExtInfoId extInfoId);
  	VIRTUAL void ClearExtendedLevelRotations();
  	VIRTUAL ILevelRotation *CreateNewRotation(const ILevelRotation::TExtInfoId id);
  	// ~ILevelSystem
  
  	// ILevelSystemListener
  	virtual void OnLevelNotFound(const char *levelName);
  	virtual void OnLoadingStart(ILevelInfo *pLevel);
  	virtual void OnLoadingComplete(ILevel *pLevel);
  	virtual void OnLoadingError(ILevelInfo *pLevel, const char *error);
  	virtual void OnLoadingProgress(ILevelInfo *pLevel, int progressAmount);
  	virtual void OnUnloadComplete(ILevel* pLevel);
  	// ~ILevelSystemListener
  
  	// ILoadingProgessListener
  	virtual void OnLoadingProgress(int steps);
  	// ~ILoadingProgessListener
  
  	void PrecacheLevelRenderData();
  	void GetMemoryUsage(ICrySizer * s) const;
  
  	void SaveOpenedFilesList();
  
  private:
  	// lowercase string and replace backslashes with forward slashes
  	// TODO: move this to a more general place in CryEngine
  	string&	UnifyName(string&	name);
  	CHEAT_PROTECTION_EXPORT void ScanFolder(const char *subfolder, bool modFolder, const uint32 tag);
  	void LogLoadingTime();
  	bool LoadLevelInfo( CLevelInfo &levelInfo );
  
  	// internal get functions for the level infos ... they preserve the type and don't
  	// directly cast to the interface
  	CLevelInfo *GetLevelInfoInternal(int level);
  	CLevelInfo *GetLevelInfoInternal(const char *levelName);
  
  	typedef std::vector<CLevelRotation>  TExtendedLevelRotations;
  
  	ISystem									*m_pSystem;
  	std::vector<CLevelInfo> m_levelInfos;
  	string									m_levelsFolder;
  	ILevel									*m_pCurrentLevel;
  	ILevelInfo							*m_pLoadingLevelInfo;
  
  	TExtendedLevelRotations	m_extLevelRotations;
  	CLevelRotation					m_levelRotation;
  
  	string                  m_lastLevelName;
  	float                   m_fLastLevelLoadTime;
  	float										m_fFilteredProgress;
  	float										m_fLastTime;
  
  	bool                    m_bLevelLoaded;
  	bool                    m_bRecordingFileOpens;
  
  	int                     m_nLoadedLevelsCount;
  
  	CTimeValue              m_levelLoadStartTime;
  
  	static int							s_loadCount;
  
  	std::vector<ILevelSystemListener *> m_listeners;
  
  	DynArray<string>		m_levelTypeList;
  };
  
  #endif //__LEVELSYSTEM_H__
  