Rewritten program storage, closes #534

master
krzys-h 2015-08-15 23:29:21 +02:00
parent 0eaf0d6f65
commit bc7d0c1c51
9 changed files with 239 additions and 349 deletions

View File

@ -3266,10 +3266,11 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
if (line->GetParam("script")->IsDefined()) if (line->GetParam("script")->IsDefined())
{ {
Program* program = dynamic_cast<CProgramStorageObject*>(m_controller)->AddProgram(); CProgramStorageObject* programStorage = dynamic_cast<CProgramStorageObject*>(m_controller);
program->filename = "../" + line->GetParam("script")->AsPath("ai"); Program* program = programStorage->AddProgram();
programStorage->ReadProgram(program, "../" + line->GetParam("script")->AsPath("ai"));
program->readOnly = true; program->readOnly = true;
dynamic_cast<CProgrammableObject*>(m_controller)->SetScriptRun(program); dynamic_cast<CProgrammableObject*>(m_controller)->RunProgram(program);
} }
continue; continue;
} }
@ -3308,41 +3309,22 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
if (obj->Implements(ObjectInterfaceType::Old)) if (obj->Implements(ObjectInterfaceType::Old))
dynamic_cast<COldObject*>(obj)->SetDefRank(rankObj); // TODO: do we really need this? dynamic_cast<COldObject*>(obj)->SetDefRank(rankObj); // TODO: do we really need this?
std::map<int, Program*> loadedPrograms;
if (obj->Implements(ObjectInterfaceType::ProgramStorage)) if (obj->Implements(ObjectInterfaceType::ProgramStorage))
{ {
bool allFilled = true; CProgramStorageObject* programStorage = dynamic_cast<CProgramStorageObject*>(obj);
for (int i = 0; i < 10 || allFilled; i++)
{
std::string op = "script" + StrUtils::ToString<int>(i+1); // script1..script10
std::string opReadOnly = "scriptReadOnly" + StrUtils::ToString<int>(i+1); // scriptReadOnly1..scriptReadOnly10
std::string opRunnable = "scriptRunnable" + StrUtils::ToString<int>(i+1); // scriptRunnable1..scriptRunnable10
if (line->GetParam(op)->IsDefined())
{
Program* program = dynamic_cast<CProgramStorageObject*>(obj)->AddProgram();
program->filename = "../" + line->GetParam(op)->AsPath("ai");
program->readOnly = line->GetParam(opReadOnly)->AsBool(true);
program->runnable = line->GetParam(opRunnable)->AsBool(true);
loadedPrograms[i] = program;
}
else
{
allFilled = false;
}
}
}
if (obj->Implements(ObjectInterfaceType::Programmable)) if (obj->Implements(ObjectInterfaceType::Controllable) && dynamic_cast<CControllableObject*>(obj)->GetSelectable() && obj->GetType() != OBJECT_HUMAN)
{
int i = line->GetParam("run")->AsInt(0);
if (i != 0)
{ {
dynamic_cast<CProgrammableObject*>(obj)->SetScriptRun(loadedPrograms[i-1]); programStorage->SetProgramStorageIndex(rankObj);
} }
}
if (soluce && obj->Implements(ObjectInterfaceType::ProgramStorage) && line->GetParam("soluce")->IsDefined()) char categoryChar = GetLevelCategoryDir(m_levelCategory)[0];
dynamic_cast<CProgramStorageObject*>(obj)->SetSoluceName(line->GetParam("soluce")->AsPath("ai")); programStorage->LoadAllProgramsForLevel(
line.get(),
m_playerProfile->GetSaveFile(StrUtils::Format("%c%.3d%.3d", categoryChar, m_levelChap, m_levelRank)),
soluce
);
}
} }
catch (const CObjectCreateException& e) catch (const CObjectCreateException& e)
{ {
@ -3567,9 +3549,6 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
throw CLevelParserException("Unknown command: '" + line->GetCommand() + "' in " + line->GetLevelFilename() + ":" + 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())
CompileScript(soluce); // compiles all scripts
m_ui->GetLoadingScreen()->SetProgress(1.0f, RT_LOADING_FINISHED); m_ui->GetLoadingScreen()->SetProgress(1.0f, RT_LOADING_FINISHED);
if (m_ui->GetLoadingScreen()->IsVisible()) if (m_ui->GetLoadingScreen()->IsVisible())
{ {
@ -4293,124 +4272,6 @@ void CRobotMain::FrameShowLimit(float rTime)
} }
} }
//! Compiles all scripts of robots
void CRobotMain::CompileScript(bool soluce)
{
m_ui->GetLoadingScreen()->SetProgress(0.75f, RT_LOADING_PROGRAMS);
int numObjects = m_objMan->CountObjectsImplementing(ObjectInterfaceType::Programmable);
int objCounter = 0;
for (CObject* obj : m_objMan->GetAllObjects())
{
if (! obj->Implements(ObjectInterfaceType::ProgramStorage)) continue;
float objectProgress = static_cast<float>(objCounter) / static_cast<float>(numObjects);
m_ui->GetLoadingScreen()->SetProgress(0.75f+objectProgress*0.25f, RT_LOADING_PROGRAMS, "for object "+StrUtils::ToString<int>(objCounter+1)+" / "+StrUtils::ToString<int>(numObjects));
objCounter++;
CProgramStorageObject* programStorage = dynamic_cast<CProgramStorageObject*>(obj);
for (auto& prog : programStorage->GetPrograms())
{
Program* program = prog.get();
if (program->filename.empty()) continue;
std::string name = "ai/" + program->filename;
if (! programStorage->ReadProgram(program, const_cast<char*>(name.c_str())))
{
GetLogger()->Error("Unable to read script from file \"%s\"\n", name.c_str());
}
//? if (!programStorage->GetCompile(program)) nbError++;
}
if (soluce)
{
std::string name = programStorage->GetSoluceName();
if (!name.empty())
{
programStorage->ReadSoluce(name); // load solution
}
}
LoadOneScript(obj);
}
// Start all programs according to the command "run".
for (CObject* obj : m_objMan->GetAllObjects())
{
if (! obj->Implements(ObjectInterfaceType::Programmable)) continue;
CProgrammableObject* programmable = dynamic_cast<CProgrammableObject*>(obj);
Program* program = programmable->GetScriptRun();
if (program != nullptr)
{
programmable->RunProgram(program); // starts the program
}
}
}
//! Load all programs of the robot
void CRobotMain::LoadOneScript(CObject *obj)
{
if (! obj->Implements(ObjectInterfaceType::ProgramStorage)) return;
CProgramStorageObject* programStorage = dynamic_cast<CProgramStorageObject*>(obj);
if (!IsSelectable(obj)) return;
ObjectType type = obj->GetType();
if (type == OBJECT_HUMAN) return;
int objRank = obj->GetDefRank();
if (objRank == -1) return;
char categoryChar = GetLevelCategoryDir(m_levelCategory)[0];
for (unsigned int i = 0; i <= 999; i++)
{
char file[MAX_FNAME];
sprintf(file, "%c%.3d%.3d%.3d%.3d.txt", categoryChar, m_levelChap, m_levelRank, objRank, i);
std::string filename = m_playerProfile->GetSaveFile(file);
if (CResourceManager::Exists(filename))
{
Program* program = programStorage->GetOrAddProgram(i);
if(programStorage->GetCompile(program)) continue; // If already loaded (e.g. from level file), skip
programStorage->ReadProgram(program, filename.c_str());
//? if (!programStorage->GetCompile(program)) nbError++;
}
}
}
//! Load all programs of the robot
void CRobotMain::LoadFileScript(CObject *obj, const char* filename, int objRank)
{
if (objRank == -1) return;
if (! obj->Implements(ObjectInterfaceType::ProgramStorage)) return;
CProgramStorageObject* programStorage = dynamic_cast<CProgramStorageObject*>(obj);
ObjectType type = obj->GetType();
if (type == OBJECT_HUMAN) return;
std::string dirname = filename;
dirname = dirname.substr(0, dirname.find_last_of("/"));
char fn[MAX_FNAME]; //TODO: Refactor to std::string
for (unsigned int i = 0; i <= 999; i++)
{
sprintf(fn, "%s/prog%.3d%.3d.txt", dirname.c_str(), objRank, i);
if (CResourceManager::Exists(fn))
{
Program* program = programStorage->GetOrAddProgram(i);
programStorage->ReadProgram(program, fn);
//? if (!programStorage->GetCompile(program)) nbError++;
}
}
}
//! Saves all programs of all the robots //! Saves all programs of all the robots
void CRobotMain::SaveAllScript() void CRobotMain::SaveAllScript()
{ {
@ -4428,65 +4289,8 @@ void CRobotMain::SaveOneScript(CObject *obj)
CProgramStorageObject* programStorage = dynamic_cast<CProgramStorageObject*>(obj); CProgramStorageObject* programStorage = dynamic_cast<CProgramStorageObject*>(obj);
if (!IsSelectable(obj)) return;
ObjectType type = obj->GetType();
if (type == OBJECT_HUMAN) return;
int objRank = obj->GetDefRank();
if (objRank == -1) return;
char categoryChar = GetLevelCategoryDir(m_levelCategory)[0]; char categoryChar = GetLevelCategoryDir(m_levelCategory)[0];
auto& programs = programStorage->GetPrograms(); programStorage->SaveAllUserPrograms(m_playerProfile->GetSaveFile(StrUtils::Format("%c%.3d%.3d", categoryChar, m_levelChap, m_levelRank)));
// TODO: Find a better way to do that
for (unsigned int i = 0; i <= 999; i++)
{
char file[MAX_FNAME];
sprintf(file, "%c%.3d%.3d%.3d%.3d.txt", categoryChar, m_levelChap, m_levelRank, objRank, i);
std::string filename = m_playerProfile->GetSaveFile(file);
if (i < programs.size())
{
programStorage->WriteProgram(programs[i].get(), filename.c_str());
}
else
{
CResourceManager::Remove(filename);
}
}
}
//! Saves all programs of the robot.
//! If a program does not exist, the corresponding file is destroyed.
void CRobotMain::SaveFileScript(CObject *obj, const char* filename, int objRank)
{
if (objRank == -1) return;
if (! obj->Implements(ObjectInterfaceType::ProgramStorage)) return;
CProgramStorageObject* programStorage = dynamic_cast<CProgramStorageObject*>(obj);
ObjectType type = obj->GetType();
if (type == OBJECT_HUMAN) return;
std::string dirname = filename;
dirname = dirname.substr(0, dirname.find_last_of("/"));
char fn[MAX_FNAME]; //TODO: Refactor to std::string
auto& programs = programStorage->GetPrograms();
// TODO: Find a better way to do that
for (unsigned int i = 0; i <= 999; i++)
{
sprintf(fn, "%s/prog%.3d%.3d.txt", dirname.c_str(), objRank, i);
if (i < programs.size())
{
programStorage->WriteProgram(programs[i].get(), fn);
}
else
{
CResourceManager::Remove(fn);
}
}
} }
//! Saves the stack of the program in execution of a robot //! Saves the stack of the program in execution of a robot
@ -4579,7 +4383,7 @@ bool CRobotMain::IOIsBusy()
} }
//! Writes an object into the backup file //! Writes an object into the backup file
void CRobotMain::IOWriteObject(CLevelParserLine* line, CObject* obj) void CRobotMain::IOWriteObject(CLevelParserLine* line, CObject* obj, const std::string& programDir, int objRank)
{ {
if (obj->GetType() == OBJECT_FIX) return; if (obj->GetType() == OBJECT_FIX) return;
@ -4634,23 +4438,29 @@ void CRobotMain::IOWriteObject(CLevelParserLine* line, CObject* obj)
if (obj->GetType() == OBJECT_BASE) if (obj->GetType() == OBJECT_BASE)
line->AddParam("run", MakeUnique<CLevelParserParam>(3)); // stops and open (PARAM_FIXSCENE) line->AddParam("run", MakeUnique<CLevelParserParam>(3)); // stops and open (PARAM_FIXSCENE)
if (obj->Implements(ObjectInterfaceType::Programmable) && obj->Implements(ObjectInterfaceType::ProgramStorage))
{
int run = dynamic_cast<CProgramStorageObject*>(obj)->GetProgramIndex(dynamic_cast<CProgrammableObject*>(obj)->GetCurrentProgram());
if (run != -1)
{
line->AddParam("run", MakeUnique<CLevelParserParam>(run+1));
}
}
if (obj->Implements(ObjectInterfaceType::ProgramStorage)) if (obj->Implements(ObjectInterfaceType::ProgramStorage))
{ {
auto& programs = dynamic_cast<CProgramStorageObject*>(obj)->GetPrograms(); CProgramStorageObject* programStorage = dynamic_cast<CProgramStorageObject*>(obj);
for (unsigned int i = 0; i < programs.size(); i++) if(programStorage->GetProgramStorageIndex() >= 0)
{ {
if (programs[i]->readOnly) programStorage->SaveAllProgramsForSavedScene(line, programDir);
}
else
{
// Probably an object created after the scene started, not loaded from level file
// This means it doesn't normally store programs so it doesn't have program storage id assigned
programStorage->SetProgramStorageIndex(999-objRank); // Set something that won't collide with normal programs
programStorage->SaveAllProgramsForSavedScene(line, programDir);
programStorage->SetProgramStorageIndex(-1); // Disable again
}
if (obj->Implements(ObjectInterfaceType::Programmable))
{
int run = dynamic_cast<CProgramStorageObject*>(obj)->GetProgramIndex(dynamic_cast<CProgrammableObject*>(obj)->GetCurrentProgram());
if (run != -1)
{ {
line->AddParam("scriptReadOnly" + boost::lexical_cast<std::string>(i+1), MakeUnique<CLevelParserParam>(true)); line->AddParam("run", MakeUnique<CLevelParserParam>(run+1));
} }
} }
} }
@ -4663,6 +4473,8 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s
ShowSaveIndicator(true); ShowSaveIndicator(true);
m_app->Render(); // update m_app->Render(); // update
std::string dirname = filename.substr(0, filename.find_last_of("/"));
CLevelParser levelParser(filename); CLevelParser levelParser(filename);
CLevelParserLineUPtr line; CLevelParserLineUPtr line;
@ -4727,7 +4539,7 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s
if (cargo != nullptr) // object transported? if (cargo != nullptr) // object transported?
{ {
line = MakeUnique<CLevelParserLine>("CreateFret"); line = MakeUnique<CLevelParserLine>("CreateFret");
IOWriteObject(line.get(), cargo); IOWriteObject(line.get(), cargo, dirname, objRank++);
levelParser.AddLine(std::move(line)); levelParser.AddLine(std::move(line));
} }
} }
@ -4738,17 +4550,15 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s
if (power != nullptr) // battery transported? if (power != nullptr) // battery transported?
{ {
line = MakeUnique<CLevelParserLine>("CreatePower"); line = MakeUnique<CLevelParserLine>("CreatePower");
IOWriteObject(line.get(), power); IOWriteObject(line.get(), power, dirname, objRank++);
levelParser.AddLine(std::move(line)); levelParser.AddLine(std::move(line));
} }
} }
line = MakeUnique<CLevelParserLine>("CreateObject"); line = MakeUnique<CLevelParserLine>("CreateObject");
IOWriteObject(line.get(), obj); IOWriteObject(line.get(), obj, dirname, objRank++);
levelParser.AddLine(std::move(line)); levelParser.AddLine(std::move(line));
SaveFileScript(obj, filename.c_str(), objRank++);
} }
try try
{ {
@ -4809,7 +4619,7 @@ void CRobotMain::IOWriteSceneFinished()
} }
//! Resumes the game //! Resumes the game
CObject* CRobotMain::IOReadObject(CLevelParserLine *line, const char* filename, const std::string& objCounterText, float objectProgress, int objRank) CObject* CRobotMain::IOReadObject(CLevelParserLine *line, const std::string& programDir, const std::string& objCounterText, float objectProgress, int objRank)
{ {
ObjectCreateParams params = CObject::ReadCreateParams(line); ObjectCreateParams params = CObject::ReadCreateParams(line);
params.power = -1.0f; params.power = -1.0f;
@ -4828,10 +4638,8 @@ CObject* CRobotMain::IOReadObject(CLevelParserLine *line, const char* filename,
{ {
COldObject* oldObj = dynamic_cast<COldObject*>(obj); COldObject* oldObj = dynamic_cast<COldObject*>(obj);
oldObj->SetRotation(line->GetParam("angle")->AsPoint() * Math::DEG_TO_RAD); // Who decided to call this argument differently than in main scene files? :/ oldObj->SetPosition(line->GetParam("pos")->AsPoint() * g_unit);
// TODO: Also, why doesn't CStaticObject implement SetRotation? oldObj->SetRotation(line->GetParam("angle")->AsPoint() * Math::DEG_TO_RAD);
oldObj->SetDefRank(objRank);
for (int i = 1; i < OBJECTMAXPART; i++) for (int i = 1; i < OBJECTMAXPART; i++)
{ {
@ -4869,25 +4677,12 @@ CObject* CRobotMain::IOReadObject(CLevelParserLine *line, const char* filename,
automat->Start(run); // starts the film automat->Start(run); // starts the film
} }
if (obj->Implements(ObjectInterfaceType::Programmable))
{
if (run != -1)
{
Program* program = dynamic_cast<CProgramStorageObject*>(obj)->GetOrAddProgram(run-1);
dynamic_cast<CProgrammableObject*>(obj)->SetScriptRun(program); // marks the program to be started
}
}
if (obj->Implements(ObjectInterfaceType::ProgramStorage)) if (obj->Implements(ObjectInterfaceType::ProgramStorage))
{ {
for (unsigned int i = 0; i <= 999; i++) CProgramStorageObject* programStorage = dynamic_cast<CProgramStorageObject*>(obj);
{ if (!line->GetParam("programStorageIndex")->IsDefined()) // Backwards combatibility
if (line->GetParam("scriptReadOnly" + boost::lexical_cast<std::string>(i+1))->AsBool(false)) programStorage->SetProgramStorageIndex(objRank);
{ programStorage->LoadAllProgramsForSavedScene(line, programDir);
Program* prog = dynamic_cast<CProgramStorageObject*>(obj)->GetOrAddProgram(i);
prog->readOnly = true;
}
}
} }
return obj; return obj;
@ -4896,6 +4691,8 @@ CObject* CRobotMain::IOReadObject(CLevelParserLine *line, const char* filename,
//! Resumes some part of the game //! Resumes some part of the game
CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot) CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot)
{ {
std::string dirname = filename.substr(0, filename.find_last_of("/"));
CLevelParser levelParser(filename); CLevelParser levelParser(filename);
levelParser.Load(); levelParser.Load();
int numObjects = levelParser.CountLines("CreateObject") + levelParser.CountLines("CreatePower") + levelParser.CountLines("CreateFret"); int numObjects = levelParser.CountLines("CreateObject") + levelParser.CountLines("CreatePower") + levelParser.CountLines("CreateFret");
@ -4926,19 +4723,19 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot)
if (line->GetCommand() == "CreateFret") if (line->GetCommand() == "CreateFret")
{ {
cargo = IOReadObject(line.get(), filename.c_str(), StrUtils::ToString<int>(objCounter+1)+" / "+StrUtils::ToString<int>(numObjects), static_cast<float>(objCounter) / static_cast<float>(numObjects), -1); cargo = IOReadObject(line.get(), dirname, StrUtils::ToString<int>(objCounter+1)+" / "+StrUtils::ToString<int>(numObjects), static_cast<float>(objCounter) / static_cast<float>(numObjects));
objCounter++; objCounter++;
} }
if (line->GetCommand() == "CreatePower") if (line->GetCommand() == "CreatePower")
{ {
power = IOReadObject(line.get(), filename.c_str(), StrUtils::ToString<int>(objCounter+1)+" / "+StrUtils::ToString<int>(numObjects), static_cast<float>(objCounter) / static_cast<float>(numObjects), -1); power = IOReadObject(line.get(), dirname, StrUtils::ToString<int>(objCounter+1)+" / "+StrUtils::ToString<int>(numObjects), static_cast<float>(objCounter) / static_cast<float>(numObjects));
objCounter++; objCounter++;
} }
if (line->GetCommand() == "CreateObject") if (line->GetCommand() == "CreateObject")
{ {
CObject* obj = IOReadObject(line.get(), filename.c_str(), StrUtils::ToString<int>(objCounter+1)+" / "+StrUtils::ToString<int>(numObjects), static_cast<float>(objCounter) / static_cast<float>(numObjects), objRank++); CObject* obj = IOReadObject(line.get(), dirname, StrUtils::ToString<int>(objCounter+1)+" / "+StrUtils::ToString<int>(numObjects), static_cast<float>(objCounter) / static_cast<float>(numObjects), objRank++);
if (line->GetParam("select")->AsBool(false)) if (line->GetParam("select")->AsBool(false))
sel = obj; sel = obj;
@ -4966,42 +4763,6 @@ CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot)
} }
} }
// Compiles scripts.
m_ui->GetLoadingScreen()->SetProgress(0.75f, RT_LOADING_PROGRAMS);
numObjects = m_objMan->CountObjectsImplementing(ObjectInterfaceType::Programmable);
objCounter = 0;
for (CObject* obj : m_objMan->GetAllObjects())
{
if (! obj->Implements(ObjectInterfaceType::Programmable)) continue;
float objectProgress = static_cast<float>(objCounter) / static_cast<float>(numObjects);
m_ui->GetLoadingScreen()->SetProgress(0.75f+objectProgress*0.2f, RT_LOADING_PROGRAMS, "for object "+StrUtils::ToString<int>(objCounter+1)+" / "+StrUtils::ToString<int>(numObjects));
objCounter++;
if (IsObjectBeingTransported(obj)) continue; // TODO: WTF, programmable transportable objects?
objRank = obj->GetDefRank();
if (objRank == -1) continue;
LoadFileScript(obj, filename.c_str(), objRank);
}
// Starts scripts
for (CObject* obj : m_objMan->GetAllObjects())
{
if (! obj->Implements(ObjectInterfaceType::Programmable)) continue;
if (obj->GetDefRank() == -1) continue;
CProgrammableObject* programmable = dynamic_cast<CProgrammableObject*>(obj);
Program* program = programmable->GetScriptRun();
if (program != nullptr)
{
programmable->RunProgram(program); // starts the program
}
}
m_ui->GetLoadingScreen()->SetProgress(0.95f, RT_LOADING_CBOT_SAVE); m_ui->GetLoadingScreen()->SetProgress(0.95f, RT_LOADING_CBOT_SAVE);
// Reads the file of stacks of execution. // Reads the file of stacks of execution.

View File

@ -273,12 +273,8 @@ public:
void StartShowLimit(); void StartShowLimit();
void FrameShowLimit(float rTime); void FrameShowLimit(float rTime);
void CompileScript(bool soluce);
void LoadOneScript(CObject *pObj);
void LoadFileScript(CObject *pObj, const char* filename, int objRank);
void SaveAllScript(); void SaveAllScript();
void SaveOneScript(CObject *pObj); void SaveOneScript(CObject *pObj);
void SaveFileScript(CObject *pObj, const char* filename, int objRank);
bool SaveFileStack(CObject *pObj, FILE *file, int objRank); bool SaveFileStack(CObject *pObj, FILE *file, int objRank);
bool ReadFileStack(CObject *pObj, FILE *file, int objRank); bool ReadFileStack(CObject *pObj, FILE *file, int objRank);
@ -293,8 +289,8 @@ public:
bool IOWriteScene(std::string filename, std::string filecbot, std::string filescreenshot, char *info); bool IOWriteScene(std::string filename, std::string filecbot, std::string filescreenshot, char *info);
void IOWriteSceneFinished(); void IOWriteSceneFinished();
CObject* IOReadScene(std::string filename, std::string filecbot); CObject* IOReadScene(std::string filename, std::string filecbot);
void IOWriteObject(CLevelParserLine *line, CObject* obj); void IOWriteObject(CLevelParserLine *line, CObject* obj, const std::string& programDir, int objRank);
CObject* IOReadObject(CLevelParserLine *line, const char* filename, const std::string& objCounterText, float objectProgress, int objRank); CObject* IOReadObject(CLevelParserLine *line, const std::string& programDir, const std::string& objCounterText, float objectProgress, int objRank = -1);
int CreateSpot(Math::Vector pos, Gfx::Color color); int CreateSpot(Math::Vector pos, Gfx::Color color);

View File

@ -20,9 +20,15 @@
#include "object/implementation/programmable_impl.h" #include "object/implementation/programmable_impl.h"
#include "common/global.h" #include "common/global.h"
#include "common/logger.h"
#include "common/stringutils.h"
#include "common/resources/resourcemanager.h"
#include "level/robotmain.h" #include "level/robotmain.h"
#include "level/parser/parserline.h"
#include "math/all.h" #include "math/all.h"
#include "object/object.h" #include "object/object.h"
@ -48,7 +54,9 @@ CProgramStorageObjectImpl::CProgramStorageObjectImpl(ObjectInterfaceTypes& types
m_object(object), m_object(object),
m_program(), m_program(),
m_activeVirus(false), m_activeVirus(false),
m_soluceName("") m_soluceName(""),
m_programStorageIndex(-1),
m_allowProgramSave(true)
{ {
} }
@ -193,33 +201,6 @@ const std::string& CProgramStorageObjectImpl::GetSoluceName()
return m_soluceName; return m_soluceName;
} }
// Load a script solution, in the first free script.
// If there is already an identical script, nothing is loaded.
bool CProgramStorageObjectImpl::ReadSoluce(const std::string& filename)
{
Program* prog = AddProgram();
if ( !ReadProgram(prog, filename) ) return false; // load solution
prog->readOnly = true;
for(unsigned int i = 0; i < m_program.size(); i++)
{
if(m_program[i].get() == prog) continue;
//TODO: This is bad. It's very sensitive to things like \n vs \r\n etc.
if ( m_program[i]->script->Compare(prog->script.get()) ) // the same already?
{
m_program[i]->readOnly = true; // Mark is as read-only
RemoveProgram(prog);
return false;
}
}
return true;
}
// Load a script with a text file. // Load a script with a text file.
bool CProgramStorageObjectImpl::ReadProgram(Program* program, const std::string& filename) bool CProgramStorageObjectImpl::ReadProgram(Program* program, const std::string& filename)
@ -244,3 +225,148 @@ bool CProgramStorageObjectImpl::WriteProgram(Program* program, const std::string
return false; return false;
} }
void CProgramStorageObjectImpl::SetProgramStorageIndex(int programStorageIndex)
{
m_programStorageIndex = programStorageIndex;
}
int CProgramStorageObjectImpl::GetProgramStorageIndex()
{
return m_programStorageIndex;
}
void CProgramStorageObjectImpl::SaveAllUserPrograms(const std::string& userSource)
{
if (!m_allowProgramSave) return;
if (m_programStorageIndex < 0) return;
GetLogger()->Debug("Saving user programs to '%s%.3d___.txt'\n", userSource.c_str(), m_programStorageIndex);
for (unsigned int i = 0; i <= 999; i++)
{
std::string filename = userSource + StrUtils::Format("%.3d%.3d.txt", m_programStorageIndex, i);
if (i < m_program.size() && !m_program[i]->loadedFromLevel)
{
GetLogger()->Trace("Loading program '%s' into user directory\n", filename.c_str());
WriteProgram(m_program[i].get(), filename);
}
else
{
CResourceManager::Remove(filename);
}
}
}
void CProgramStorageObjectImpl::LoadAllProgramsForLevel(CLevelParserLine* levelSource, const std::string& userSource, bool loadSoluce)
{
int run = levelSource->GetParam("run")->AsInt(0)-1;
bool allFilled = true;
for (int i = 0; i < 10 || allFilled; i++)
{
std::string op = "script" + StrUtils::ToString<int>(i+1); // script1..script10
std::string opReadOnly = "scriptReadOnly" + StrUtils::ToString<int>(i+1); // scriptReadOnly1..scriptReadOnly10
std::string opRunnable = "scriptRunnable" + StrUtils::ToString<int>(i+1); // scriptRunnable1..scriptRunnable10
if (levelSource->GetParam(op)->IsDefined())
{
std::string filename = levelSource->GetParam(op)->AsPath("ai");
GetLogger()->Trace("Loading program '%s' from level file\n", filename.c_str());
Program* program = AddProgram();
ReadProgram(program, filename);
program->readOnly = levelSource->GetParam(opReadOnly)->AsBool(true);
program->runnable = levelSource->GetParam(opRunnable)->AsBool(true);
program->loadedFromLevel = true;
if (m_object->Implements(ObjectInterfaceType::Programmable) && i == run)
{
dynamic_cast<CProgrammableObject*>(m_object)->RunProgram(program);
}
}
else
{
allFilled = false;
}
}
if (loadSoluce && levelSource->GetParam("soluce")->IsDefined())
{
std::string filename = levelSource->GetParam("soluce")->AsPath("ai");
GetLogger()->Trace("Loading program '%s' as soluce file\n", filename.c_str());
Program* program = AddProgram();
ReadProgram(program, filename);
program->readOnly = true;
program->runnable = false;
program->loadedFromLevel = true;
}
if (m_programStorageIndex >= 0)
{
GetLogger()->Debug("Loading user programs from '%s%.3d___.txt'\n", userSource.c_str(), m_programStorageIndex);
for (unsigned int i = 0; i <= 999; i++)
{
std::string filename = userSource + StrUtils::Format("%.3d%.3d.txt", m_programStorageIndex, i);
if (CResourceManager::Exists(filename))
{
Program* program = GetOrAddProgram(i);
if(GetCompile(program)) continue; // If already loaded from level file, skip
GetLogger()->Trace("Loading program '%s' from user directory\n", filename.c_str());
ReadProgram(program, filename);
}
}
}
}
void CProgramStorageObjectImpl::SaveAllProgramsForSavedScene(CLevelParserLine* levelSourceLine, const std::string& levelSource)
{
levelSourceLine->AddParam("programStorageIndex", MakeUnique<CLevelParserParam>(m_programStorageIndex));
assert(m_programStorageIndex != -1);
GetLogger()->Debug("Saving saved scene programs to '%s/prog%.3d___.txt'\n", levelSource.c_str(), m_programStorageIndex);
for (int i = 0; i < 999; i++)
{
std::string filename = levelSource + StrUtils::Format("/prog%.3d%.3d.txt", m_programStorageIndex, i);
if (i >= static_cast<int>(m_program.size()))
{
CResourceManager::Remove(filename);
continue;
}
levelSourceLine->AddParam("scriptReadOnly" + StrUtils::ToString<int>(i+1), MakeUnique<CLevelParserParam>(m_program[i]->readOnly));
levelSourceLine->AddParam("scriptRunnable" + StrUtils::ToString<int>(i+1), MakeUnique<CLevelParserParam>(m_program[i]->runnable));
GetLogger()->Trace("Saving program '%s' to saved scene\n", filename.c_str());
WriteProgram(m_program[i].get(), filename);
}
}
void CProgramStorageObjectImpl::LoadAllProgramsForSavedScene(CLevelParserLine* levelSourceLine, const std::string& levelSource)
{
m_programStorageIndex = levelSourceLine->GetParam("programStorageIndex")->AsInt(-1);
if(m_programStorageIndex == -1) return;
GetLogger()->Debug("Loading saved scene programs from '%s/prog%.3d___.txt'\n", levelSource.c_str(), m_programStorageIndex);
int run = levelSourceLine->GetParam("run")->AsInt(0)-1;
for (int i = 0; i <= 999; i++)
{
std::string opReadOnly = "scriptReadOnly" + StrUtils::ToString<int>(i+1); // scriptReadOnly1..scriptReadOnly10
std::string opRunnable = "scriptRunnable" + StrUtils::ToString<int>(i+1); // scriptRunnable1..scriptRunnable10
std::string filename = levelSource + StrUtils::Format("/prog%.3d%.3d.txt", m_programStorageIndex, i);
if (CResourceManager::Exists(filename))
{
GetLogger()->Trace("Loading program '%s' from saved scene\n", filename.c_str());
Program* program = GetOrAddProgram(i);
ReadProgram(program, filename);
program->readOnly = levelSourceLine->GetParam(opReadOnly)->AsBool(true);
program->runnable = levelSourceLine->GetParam(opRunnable)->AsBool(true);
if (m_object->Implements(ObjectInterfaceType::Programmable) && i == run)
{
dynamic_cast<CProgrammableObject*>(m_object)->RunProgram(program);
}
}
}
// Disable automatic user program storage now!!
// This is to prevent overwriting auto-saved user programs with older versions from saved scenes
m_allowProgramSave = false;
}

View File

@ -40,7 +40,6 @@ public:
void SetSoluceName(const std::string& name) override; void SetSoluceName(const std::string& name) override;
const std::string& GetSoluceName() override; const std::string& GetSoluceName() override;
bool ReadSoluce(const std::string& filename) override;
bool ReadProgram(Program* program, const std::string& filename) override; bool ReadProgram(Program* program, const std::string& filename) override;
bool GetCompile(Program* program) override; bool GetCompile(Program* program) override;
bool WriteProgram(Program* program, const std::string& filename) override; bool WriteProgram(Program* program, const std::string& filename) override;
@ -55,6 +54,16 @@ public:
Program* GetProgram(int index) override; Program* GetProgram(int index) override;
Program* GetOrAddProgram(int index) override; Program* GetOrAddProgram(int index) override;
int GetProgramIndex(Program* program) override; int GetProgramIndex(Program* program) override;
void SetProgramStorageIndex(int programStorageIndex) override;
int GetProgramStorageIndex() override;
void SaveAllUserPrograms(const std::string& userSource) override;
void LoadAllProgramsForLevel(CLevelParserLine* levelSource, const std::string& userSource, bool loadSoluce) override;
void SaveAllProgramsForSavedScene(CLevelParserLine* levelSourceLine, const std::string& levelSource) override;
void LoadAllProgramsForSavedScene(CLevelParserLine* levelSourceLine, const std::string& levelSource) override;
private: private:
CObject* m_object; CObject* m_object;
@ -64,4 +73,7 @@ private:
bool m_activeVirus; bool m_activeVirus;
std::string m_soluceName; std::string m_soluceName;
int m_programStorageIndex;
bool m_allowProgramSave;
}; };

View File

@ -49,7 +49,6 @@ CProgrammableObjectImpl::CProgrammableObjectImpl(ObjectInterfaceTypes& types, CO
m_activity(true), m_activity(true),
m_cmdLine(), m_cmdLine(),
m_currentProgram(nullptr), m_currentProgram(nullptr),
m_scriptRun(nullptr),
m_traceRecord(false), m_traceRecord(false),
m_traceOper(TO_STOP), m_traceOper(TO_STOP),
m_traceAngle(0.0f), m_traceAngle(0.0f),
@ -137,16 +136,6 @@ bool CProgrammableObjectImpl::IsProgram()
} }
void CProgrammableObjectImpl::SetScriptRun(Program* program)
{
m_scriptRun = program;
}
Program* CProgrammableObjectImpl::GetScriptRun()
{
return m_scriptRun;
}
// Load a stack of script implementation from a file. // Load a stack of script implementation from a file.
bool CProgrammableObjectImpl::ReadStack(FILE *file) bool CProgrammableObjectImpl::ReadStack(FILE *file)

View File

@ -57,9 +57,6 @@ public:
Program* GetCurrentProgram() override; Program* GetCurrentProgram() override;
void StopProgram() override; void StopProgram() override;
void SetScriptRun(Program* rank) override;
Program* GetScriptRun() override;
bool ReadStack(FILE *file) override; bool ReadStack(FILE *file) override;
bool WriteStack(FILE *file) override; bool WriteStack(FILE *file) override;
@ -92,8 +89,6 @@ private:
Program* m_currentProgram; Program* m_currentProgram;
Program* m_scriptRun;
bool m_traceRecord; bool m_traceRecord;
TraceOper m_traceOper; TraceOper m_traceOper;
Math::Vector m_tracePos; Math::Vector m_tracePos;

View File

@ -26,13 +26,14 @@
#include <vector> #include <vector>
class CScript; class CScript;
class CLevelParserLine;
struct Program struct Program
{ {
std::unique_ptr<CScript> script; std::unique_ptr<CScript> script;
std::string filename;
bool readOnly = false; bool readOnly = false;
bool runnable = true; bool runnable = true;
bool loadedFromLevel = false;
}; };
/** /**
@ -56,7 +57,6 @@ public:
virtual void SetSoluceName(const std::string& name) = 0; virtual void SetSoluceName(const std::string& name) = 0;
virtual const std::string& GetSoluceName() = 0; virtual const std::string& GetSoluceName() = 0;
virtual bool ReadSoluce(const std::string& filename) = 0;
virtual bool ReadProgram(Program* program, const std::string& filename) = 0; virtual bool ReadProgram(Program* program, const std::string& filename) = 0;
virtual bool GetCompile(Program* program) = 0; virtual bool GetCompile(Program* program) = 0;
virtual bool WriteProgram(Program* program, const std::string& filename) = 0; virtual bool WriteProgram(Program* program, const std::string& filename) = 0;
@ -71,4 +71,18 @@ public:
virtual Program* GetProgram(int index) = 0; virtual Program* GetProgram(int index) = 0;
virtual Program* GetOrAddProgram(int index) = 0; virtual Program* GetOrAddProgram(int index) = 0;
virtual int GetProgramIndex(Program* program) = 0; virtual int GetProgramIndex(Program* program) = 0;
//! Set index for use in filename for saved programs (-1 to disable)
virtual void SetProgramStorageIndex(int programStorageIndex) = 0;
virtual int GetProgramStorageIndex() = 0;
//! Save all user programs
virtual void SaveAllUserPrograms(const std::string& userSource) = 0;
//! Load all programs when loading the level including previously saved user programs
virtual void LoadAllProgramsForLevel(CLevelParserLine* levelSource, const std::string& userSource, bool loadSoluce) = 0;
//! Save all programs when saving the saved scene
virtual void SaveAllProgramsForSavedScene(CLevelParserLine* levelSourceLine, const std::string& levelSource) = 0;
//! Load all programs when loading the saved scene
virtual void LoadAllProgramsForSavedScene(CLevelParserLine* levelSourceLine, const std::string& levelSource) = 0;
}; };

View File

@ -48,9 +48,6 @@ public:
virtual Program* GetCurrentProgram() = 0; virtual Program* GetCurrentProgram() = 0;
virtual void StopProgram() = 0; virtual void StopProgram() = 0;
virtual void SetScriptRun(Program* rank) = 0;
virtual Program* GetScriptRun() = 0;
virtual bool ReadStack(FILE *file) = 0; virtual bool ReadStack(FILE *file) = 0;
virtual bool WriteStack(FILE *file) = 0; virtual bool WriteStack(FILE *file) = 0;

View File

@ -1623,10 +1623,10 @@ void CObjectInterface::UpdateInterface()
EnableInterface(pw, EVENT_OBJECT_PROGEDIT, !m_programmable->IsTraceRecord() && m_selScript < m_programStorage->GetProgramCount() && m_main->CanPlayerInteract()); EnableInterface(pw, EVENT_OBJECT_PROGEDIT, !m_programmable->IsTraceRecord() && m_selScript < m_programStorage->GetProgramCount() && m_main->CanPlayerInteract());
EnableInterface(pw, EVENT_OBJECT_PROGLIST, bEnable && !m_programmable->IsTraceRecord()); EnableInterface(pw, EVENT_OBJECT_PROGLIST, bEnable && !m_programmable->IsTraceRecord());
EnableInterface(pw, EVENT_OBJECT_PROGADD, !m_programmable->IsProgram() && m_main->CanPlayerInteract()); EnableInterface(pw, EVENT_OBJECT_PROGADD, !m_programmable->IsProgram() && m_main->CanPlayerInteract());
EnableInterface(pw, EVENT_OBJECT_PROGREMOVE, !m_programmable->IsProgram() && m_selScript < m_programStorage->GetProgramCount() && !m_programStorage->GetProgram(m_selScript)->readOnly && m_main->CanPlayerInteract()); EnableInterface(pw, EVENT_OBJECT_PROGREMOVE, !m_programmable->IsProgram() && m_selScript >= 0 && m_selScript < m_programStorage->GetProgramCount() && !m_programStorage->GetProgram(m_selScript)->readOnly && m_main->CanPlayerInteract());
EnableInterface(pw, EVENT_OBJECT_PROGCLONE, !m_programmable->IsProgram() && m_selScript < m_programStorage->GetProgramCount() && m_programStorage->GetProgram(m_selScript)->runnable && m_main->CanPlayerInteract()); EnableInterface(pw, EVENT_OBJECT_PROGCLONE, !m_programmable->IsProgram() && m_selScript >= 0 && m_selScript < m_programStorage->GetProgramCount() && m_programStorage->GetProgram(m_selScript)->runnable && m_main->CanPlayerInteract());
EnableInterface(pw, EVENT_OBJECT_PROGMOVEUP, !m_programmable->IsProgram() && m_programStorage->GetProgramCount() >= 2 && m_selScript > 0 && m_main->CanPlayerInteract()); EnableInterface(pw, EVENT_OBJECT_PROGMOVEUP, !m_programmable->IsProgram() && m_programStorage->GetProgramCount() >= 2 && m_selScript > 0 && m_main->CanPlayerInteract());
EnableInterface(pw, EVENT_OBJECT_PROGMOVEDOWN,!m_programmable->IsProgram() && m_programStorage->GetProgramCount() >= 2 && m_selScript < m_programStorage->GetProgramCount()-1 && m_main->CanPlayerInteract()); EnableInterface(pw, EVENT_OBJECT_PROGMOVEDOWN,!m_programmable->IsProgram() && m_programStorage->GetProgramCount() >= 2 && m_selScript >= 0 && m_selScript < m_programStorage->GetProgramCount()-1 && m_main->CanPlayerInteract());
EnableInterface(pw, EVENT_OBJECT_LEFT, bEnable); EnableInterface(pw, EVENT_OBJECT_LEFT, bEnable);
EnableInterface(pw, EVENT_OBJECT_RIGHT, bEnable); EnableInterface(pw, EVENT_OBJECT_RIGHT, bEnable);
EnableInterface(pw, EVENT_OBJECT_UP, bEnable); EnableInterface(pw, EVENT_OBJECT_UP, bEnable);