Added #Include support in level files

master
krzys-h 2015-08-05 19:27:26 +02:00
parent 6ad63e0f08
commit 47d79c9977
11 changed files with 107 additions and 45 deletions

View File

@ -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
}

View File

@ -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);

View File

@ -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;

View File

@ -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");
}

View File

@ -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 + ")";
}

View File

@ -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()

View File

@ -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;

View File

@ -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);
}

View File

@ -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())

View File

@ -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();

View File

@ -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()
}
}