Added #Include support in level files
parent
6ad63e0f08
commit
47d79c9977
|
@ -169,31 +169,3 @@ void CPathManager::LoadModsFromDir(const std::string &dir)
|
|||
GetLogger()->Warn("Unable to load mods from directory '%s': %s\n", dir.c_str(), e.what());
|
||||
}
|
||||
}
|
||||
|
||||
std::string CPathManager::InjectLevelDir(std::string path, const std::string& defaultDir)
|
||||
{
|
||||
std::string newPath = path;
|
||||
std::string lvlDir = CLevelParser::BuildScenePath(CRobotMain::GetInstancePointer()->GetLevelCategory(), CRobotMain::GetInstancePointer()->GetLevelChap(), CRobotMain::GetInstancePointer()->GetLevelRank(), false);
|
||||
boost::replace_all(newPath, "%lvl%", lvlDir);
|
||||
std::string chapDir = CLevelParser::BuildScenePath(CRobotMain::GetInstancePointer()->GetLevelCategory(), CRobotMain::GetInstancePointer()->GetLevelChap(), 0, false);
|
||||
boost::replace_all(newPath, "%chap%", chapDir);
|
||||
std::string catDir = CLevelParser::BuildCategoryPath(CRobotMain::GetInstancePointer()->GetLevelCategory());
|
||||
boost::replace_all(newPath, "%cat%", catDir);
|
||||
if(newPath == path && !path.empty())
|
||||
{
|
||||
newPath = defaultDir + (!defaultDir.empty() ? "/" : "") + newPath;
|
||||
}
|
||||
|
||||
std::string langPath = newPath;
|
||||
std::string langStr(1, CApplication::GetInstancePointer()->GetLanguageChar());
|
||||
boost::replace_all(langPath, "%lng%", langStr);
|
||||
if(CResourceManager::Exists(langPath))
|
||||
return langPath;
|
||||
|
||||
// Fallback to English if file doesn't exist
|
||||
boost::replace_all(newPath, "%lng%", "E");
|
||||
if(CResourceManager::Exists(newPath))
|
||||
return newPath;
|
||||
|
||||
return langPath; // Return current language file if none of the files exist
|
||||
}
|
||||
|
|
|
@ -52,9 +52,6 @@ public:
|
|||
//! Loads configured paths
|
||||
void InitPaths();
|
||||
|
||||
//! Does the %lvl%, %chap%, %cat% and %lng% replacements (with fallback to English when translations are not available)
|
||||
static std::string InjectLevelDir(std::string path, const std::string& defaultDir = "");
|
||||
|
||||
private:
|
||||
//! Loads all mods from given directory
|
||||
void LoadModsFromDir(const std::string &dir);
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "app/app.h"
|
||||
|
||||
#include "common/make_unique.h"
|
||||
#include "common/stringutils.h"
|
||||
|
||||
#include "common/resources/inputstream.h"
|
||||
#include "common/resources/outputstream.h"
|
||||
|
@ -44,16 +45,28 @@
|
|||
CLevelParser::CLevelParser()
|
||||
{
|
||||
m_filename = "";
|
||||
|
||||
m_pathCat = "";
|
||||
m_pathChap = "";
|
||||
m_pathLvl = "";
|
||||
}
|
||||
|
||||
CLevelParser::CLevelParser(std::string filename)
|
||||
{
|
||||
m_filename = filename;
|
||||
|
||||
m_pathCat = "";
|
||||
m_pathChap = "";
|
||||
m_pathLvl = "";
|
||||
}
|
||||
|
||||
CLevelParser::CLevelParser(std::string category, int chapter, int rank)
|
||||
{
|
||||
m_filename = BuildScenePath(category, chapter, rank);
|
||||
|
||||
m_pathCat = BuildCategoryPath(category);
|
||||
m_pathChap = BuildScenePath(category, chapter, 0, false);
|
||||
m_pathLvl = BuildScenePath(category, chapter, rank, false);
|
||||
}
|
||||
|
||||
CLevelParser::CLevelParser(LevelCategory category, int chapter, int rank)
|
||||
|
@ -187,6 +200,7 @@ void CLevelParser::Load()
|
|||
continue;
|
||||
|
||||
auto parserLine = MakeUnique<CLevelParserLine>(lineNumber, command);
|
||||
parserLine->SetLevel(this);
|
||||
|
||||
if (command.length() > 2 && command[command.length() - 2] == '.')
|
||||
{
|
||||
|
@ -265,7 +279,27 @@ void CLevelParser::Load()
|
|||
boost::algorithm::trim(line);
|
||||
}
|
||||
|
||||
AddLine(std::move(parserLine));
|
||||
if (parserLine->GetCommand().length() > 1 && parserLine->GetCommand()[0] == '#')
|
||||
{
|
||||
std::string cmd = parserLine->GetCommand().substr(1, std::string::npos);
|
||||
if(cmd == "Include")
|
||||
{
|
||||
std::unique_ptr<CLevelParser> includeParser = MakeUnique<CLevelParser>(parserLine->GetParam("file")->AsPath(""));
|
||||
includeParser->Load();
|
||||
for(CLevelParserLineUPtr& line : includeParser->m_lines)
|
||||
{
|
||||
AddLine(std::move(line));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw CLevelParserException("Unknown preprocessor command '#" + cmd + "' (in " + m_filename + ":" + StrUtils::ToString<int>(lineNumber) + ")");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddLine(std::move(parserLine));
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
@ -286,6 +320,31 @@ void CLevelParser::Save()
|
|||
file.close();
|
||||
}
|
||||
|
||||
std::string CLevelParser::InjectLevelPaths(const std::string& path, const std::string& defaultDir)
|
||||
{
|
||||
std::string newPath = path;
|
||||
if(!m_pathLvl.empty() ) boost::replace_all(newPath, "%lvl%", m_pathLvl);
|
||||
if(!m_pathChap.empty()) boost::replace_all(newPath, "%chap%", m_pathChap);
|
||||
if(!m_pathCat.empty() ) boost::replace_all(newPath, "%cat%", m_pathCat);
|
||||
if(newPath == path && !path.empty())
|
||||
{
|
||||
newPath = defaultDir + (!defaultDir.empty() ? "/" : "") + newPath;
|
||||
}
|
||||
|
||||
std::string langPath = newPath;
|
||||
std::string langStr(1, CApplication::GetInstancePointer()->GetLanguageChar());
|
||||
boost::replace_all(langPath, "%lng%", langStr);
|
||||
if(CResourceManager::Exists(langPath))
|
||||
return langPath;
|
||||
|
||||
// Fallback to English if file doesn't exist
|
||||
boost::replace_all(newPath, "%lng%", "E");
|
||||
if(CResourceManager::Exists(newPath))
|
||||
return newPath;
|
||||
|
||||
return langPath; // Return current language file if none of the files exist
|
||||
}
|
||||
|
||||
const std::string& CLevelParser::GetFilename()
|
||||
{
|
||||
return m_filename;
|
||||
|
|
|
@ -26,6 +26,10 @@
|
|||
|
||||
#include "object/level_category.h"
|
||||
|
||||
#include "common/make_unique.h"
|
||||
|
||||
#include "object/robotmain.h"
|
||||
|
||||
#include "object/level/parserexceptions.h"
|
||||
#include "object/level/parserline.h"
|
||||
#include "object/level/parserparam.h"
|
||||
|
@ -65,6 +69,9 @@ public:
|
|||
//! Save file
|
||||
void Save();
|
||||
|
||||
//! Inject %something% paths
|
||||
std::string InjectLevelPaths(const std::string& path, const std::string& defaultDir = "");
|
||||
|
||||
//! Get filename
|
||||
const std::string& GetFilename();
|
||||
|
||||
|
@ -83,4 +90,15 @@ public:
|
|||
private:
|
||||
std::string m_filename;
|
||||
std::vector<CLevelParserLineUPtr> m_lines;
|
||||
|
||||
std::string m_pathCat;
|
||||
std::string m_pathChap;
|
||||
std::string m_pathLvl;
|
||||
};
|
||||
|
||||
inline std::string InjectLevelPathsForCurrentLevel(const std::string& path, const std::string& defaultDir = "")
|
||||
{
|
||||
CRobotMain* main = CRobotMain::GetInstancePointer();
|
||||
auto levelParser = MakeUnique<CLevelParser>(main->GetLevelCategory(), main->GetLevelChap(), main->GetLevelRank());
|
||||
return levelParser->InjectLevelPaths(path, "ai");
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ std::string FormatMissingParamError(CLevelParserParam* thisParam) NOEXCEPT
|
|||
{
|
||||
auto paramName = thisParam->GetName();
|
||||
auto lineNumber = boost::lexical_cast<std::string>(thisParam->GetLine()->GetLineNumber());
|
||||
auto fileName = thisParam->GetLine()->GetLevel()->GetFilename();
|
||||
auto fileName = thisParam->GetLine()->GetLevelFilename();
|
||||
return "Missing required param '" + paramName + "' (in " + fileName + ":" + lineNumber + ")";
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ std::string FormatBadParamError(CLevelParserParam* thisParam, std::string reques
|
|||
auto paramName = thisParam->GetName();
|
||||
auto paramValue = thisParam->GetValue();
|
||||
auto lineNumber = boost::lexical_cast<std::string>(thisParam->GetLine()->GetLineNumber());
|
||||
auto fileName = thisParam->GetLine()->GetLevel()->GetFilename();
|
||||
auto fileName = thisParam->GetLine()->GetLevelFilename();
|
||||
return "Unable to parse '" + paramValue + "' as " + requestedType + " (param '" + paramName + "' in " + fileName + ":" + lineNumber + ")";
|
||||
}
|
||||
|
||||
|
|
|
@ -27,12 +27,14 @@
|
|||
CLevelParserLine::CLevelParserLine(std::string command)
|
||||
{
|
||||
m_command = command;
|
||||
m_levelFilename = "";
|
||||
m_lineNumber = 0;
|
||||
}
|
||||
|
||||
CLevelParserLine::CLevelParserLine(int lineNumber, std::string command)
|
||||
{
|
||||
m_command = command;
|
||||
m_levelFilename = "";
|
||||
m_lineNumber = lineNumber;
|
||||
}
|
||||
|
||||
|
@ -49,6 +51,17 @@ CLevelParser* CLevelParserLine::GetLevel()
|
|||
void CLevelParserLine::SetLevel(CLevelParser* level)
|
||||
{
|
||||
m_level = level;
|
||||
|
||||
// Only on the first call - this makes sure the level name doesn't change if the file is loaded using #Include
|
||||
if (m_levelFilename.empty())
|
||||
{
|
||||
m_levelFilename = m_level->GetFilename();
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& CLevelParserLine::GetLevelFilename()
|
||||
{
|
||||
return m_levelFilename;
|
||||
}
|
||||
|
||||
std::string CLevelParserLine::GetCommand()
|
||||
|
|
|
@ -48,6 +48,8 @@ public:
|
|||
//! Set CLevelParser this line is part of
|
||||
void SetLevel(CLevelParser* level);
|
||||
|
||||
const std::string& GetLevelFilename();
|
||||
|
||||
std::string GetCommand();
|
||||
void SetCommand(std::string command);
|
||||
|
||||
|
@ -58,6 +60,7 @@ public:
|
|||
|
||||
private:
|
||||
CLevelParser* m_level;
|
||||
std::string m_levelFilename;
|
||||
int m_lineNumber;
|
||||
std::string m_command;
|
||||
std::map<std::string, CLevelParserParamUPtr> m_params;
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
|
||||
#include "common/logger.h"
|
||||
#include "common/make_unique.h"
|
||||
#include "common/pathman.h"
|
||||
|
||||
#include "common/resources/resourcemanager.h"
|
||||
|
||||
|
@ -227,7 +226,7 @@ std::string CLevelParserParam::ToPath(std::string path, const std::string defaul
|
|||
if (defaultDir == "" && path.find("%lvl%") != std::string::npos)
|
||||
throw CLevelParserException("TODO: Param "+m_name+" does not yet support %lvl%! :(");
|
||||
|
||||
return CPathManager::InjectLevelDir(path, defaultDir);
|
||||
return GetLine()->GetLevel()->InjectLevelPaths(path, defaultDir);
|
||||
}
|
||||
|
||||
std::string CLevelParserParam::AsPath(const std::string defaultDir)
|
||||
|
@ -241,7 +240,7 @@ std::string CLevelParserParam::AsPath(const std::string defaultDir)
|
|||
std::string CLevelParserParam::AsPath(const std::string defaultDir, std::string def)
|
||||
{
|
||||
if (m_empty)
|
||||
return CPathManager::InjectLevelDir(def, defaultDir);
|
||||
return GetLine()->GetLevel()->InjectLevelPaths(def, defaultDir);
|
||||
|
||||
return ToPath(AsString(def), defaultDir);
|
||||
}
|
||||
|
|
|
@ -3816,7 +3816,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
|
|||
if (!m_sceneReadPath.empty()) continue; // ignore errors when loading saved game (TODO: don't report ones that are just not loaded when loading saved game)
|
||||
if (resetObject) continue; // ignore when reseting just objects (TODO: see above)
|
||||
|
||||
throw CLevelParserException("Unknown command: '" + line->GetCommand() + "' in " + line->GetLevel()->GetFilename() + ":" + boost::lexical_cast<std::string>(line->GetLineNumber()));
|
||||
throw CLevelParserException("Unknown command: '" + line->GetCommand() + "' in " + line->GetLevelFilename() + ":" + boost::lexical_cast<std::string>(line->GetLineNumber()));
|
||||
}
|
||||
|
||||
if (m_sceneReadPath.empty())
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
|
||||
#include "common/logger.h"
|
||||
#include "common/make_unique.h"
|
||||
#include "common/pathman.h"
|
||||
|
||||
#include "common/resources/inputstream.h"
|
||||
#include "common/resources/outputstream.h"
|
||||
|
@ -46,6 +45,8 @@
|
|||
#include "object/auto/autobase.h"
|
||||
#include "object/auto/autofactory.h"
|
||||
|
||||
#include "object/level/parser.h"
|
||||
|
||||
#include "object/motion/motionvehicle.h"
|
||||
|
||||
#include "object/subclass/exchange_post.h"
|
||||
|
@ -1614,7 +1615,7 @@ bool CScriptFunctions::rProduce(CBotVar* var, CBotVar* result, int& exception, v
|
|||
|
||||
if (name[0] != 0)
|
||||
{
|
||||
std::string name2 = CPathManager::InjectLevelDir(name, "ai");
|
||||
std::string name2 = InjectLevelPathsForCurrentLevel(name, "ai");
|
||||
if (object->Implements(ObjectInterfaceType::Programmable))
|
||||
{
|
||||
CBrain* brain = dynamic_cast<CProgrammableObject*>(object)->GetBrain();
|
||||
|
|
|
@ -27,11 +27,12 @@
|
|||
|
||||
#include "common/logger.h"
|
||||
#include "common/misc.h"
|
||||
#include "common/pathman.h"
|
||||
|
||||
#include "common/resources/inputstream.h"
|
||||
#include "common/resources/outputstream.h"
|
||||
|
||||
#include "object/level/parser.h"
|
||||
|
||||
#include "object/robotmain.h"
|
||||
|
||||
#include "ui/scroll.h"
|
||||
|
@ -788,7 +789,7 @@ void CEdit::HyperJump(std::string name, std::string marker)
|
|||
sMarker = marker;
|
||||
|
||||
filename = name + std::string(".txt");
|
||||
filename = CPathManager::InjectLevelDir(filename, "help/%lng%");
|
||||
filename = InjectLevelPathsForCurrentLevel(filename, "help/%lng%");
|
||||
boost::replace_all(filename, "\\", "/"); //TODO: Fix this in files
|
||||
|
||||
if ( ReadText(filename) )
|
||||
|
@ -1144,7 +1145,7 @@ void CEdit::DrawImage(Math::Point pos, std::string name, float width,
|
|||
std::string filename;
|
||||
|
||||
filename = name + ".png";
|
||||
filename = CPathManager::InjectLevelDir(filename, "icons");
|
||||
filename = InjectLevelPathsForCurrentLevel(filename, "icons");
|
||||
boost::replace_all(filename, "\\", "/"); //TODO: Fix this in files
|
||||
|
||||
m_engine->SetTexture(filename);
|
||||
|
@ -1434,7 +1435,7 @@ void CEdit::LoadImage(std::string name)
|
|||
{
|
||||
std::string filename;
|
||||
filename = name + ".png";
|
||||
filename = CPathManager::InjectLevelDir(filename, "icons");
|
||||
filename = InjectLevelPathsForCurrentLevel(filename, "icons");
|
||||
boost::replace_all(filename, "\\", "/"); //TODO: Fix this in files
|
||||
m_engine->LoadTexture(filename);
|
||||
}
|
||||
|
@ -3221,4 +3222,3 @@ void CEdit::UpdateScroll()
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue