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())
{
Program* program = dynamic_cast<CProgramStorageObject*>(m_controller)->AddProgram();
program->filename = "../" + line->GetParam("script")->AsPath("ai");
CProgramStorageObject* programStorage = dynamic_cast<CProgramStorageObject*>(m_controller);
Program* program = programStorage->AddProgram();
programStorage->ReadProgram(program, "../" + line->GetParam("script")->AsPath("ai"));
program->readOnly = true;
dynamic_cast<CProgrammableObject*>(m_controller)->SetScriptRun(program);
dynamic_cast<CProgrammableObject*>(m_controller)->RunProgram(program);
}
continue;
}
@ -3308,41 +3309,22 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
if (obj->Implements(ObjectInterfaceType::Old))
dynamic_cast<COldObject*>(obj)->SetDefRank(rankObj); // TODO: do we really need this?
std::map<int, Program*> loadedPrograms;
if (obj->Implements(ObjectInterfaceType::ProgramStorage))
{
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 (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;
}
}
}
CProgramStorageObject* programStorage = dynamic_cast<CProgramStorageObject*>(obj);
if (obj->Implements(ObjectInterfaceType::Programmable))
{
int i = line->GetParam("run")->AsInt(0);
if (i != 0)
if (obj->Implements(ObjectInterfaceType::Controllable) && dynamic_cast<CControllableObject*>(obj)->GetSelectable() && obj->GetType() != OBJECT_HUMAN)
{
dynamic_cast<CProgrammableObject*>(obj)->SetScriptRun(loadedPrograms[i-1]);
programStorage->SetProgramStorageIndex(rankObj);
}
}
if (soluce && obj->Implements(ObjectInterfaceType::ProgramStorage) && line->GetParam("soluce")->IsDefined())
dynamic_cast<CProgramStorageObject*>(obj)->SetSoluceName(line->GetParam("soluce")->AsPath("ai"));
char categoryChar = GetLevelCategoryDir(m_levelCategory)[0];
programStorage->LoadAllProgramsForLevel(
line.get(),
m_playerProfile->GetSaveFile(StrUtils::Format("%c%.3d%.3d", categoryChar, m_levelChap, m_levelRank)),
soluce
);
}
}
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()));
}
if (m_sceneReadPath.empty())
CompileScript(soluce); // compiles all scripts
m_ui->GetLoadingScreen()->SetProgress(1.0f, RT_LOADING_FINISHED);
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
void CRobotMain::SaveAllScript()
{
@ -4428,65 +4289,8 @@ void CRobotMain::SaveOneScript(CObject *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];
auto& programs = programStorage->GetPrograms();
// 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);
}
}
programStorage->SaveAllUserPrograms(m_playerProfile->GetSaveFile(StrUtils::Format("%c%.3d%.3d", categoryChar, m_levelChap, m_levelRank)));
}
//! 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
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;
@ -4634,23 +4438,29 @@ void CRobotMain::IOWriteObject(CLevelParserLine* line, CObject* obj)
if (obj->GetType() == OBJECT_BASE)
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))
{
auto& programs = dynamic_cast<CProgramStorageObject*>(obj)->GetPrograms();
for (unsigned int i = 0; i < programs.size(); i++)
CProgramStorageObject* programStorage = dynamic_cast<CProgramStorageObject*>(obj);
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);
m_app->Render(); // update
std::string dirname = filename.substr(0, filename.find_last_of("/"));
CLevelParser levelParser(filename);
CLevelParserLineUPtr line;
@ -4727,7 +4539,7 @@ bool CRobotMain::IOWriteScene(std::string filename, std::string filecbot, std::s
if (cargo != nullptr) // object transported?
{
line = MakeUnique<CLevelParserLine>("CreateFret");
IOWriteObject(line.get(), cargo);
IOWriteObject(line.get(), cargo, dirname, objRank++);
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?
{
line = MakeUnique<CLevelParserLine>("CreatePower");
IOWriteObject(line.get(), power);
IOWriteObject(line.get(), power, dirname, objRank++);
levelParser.AddLine(std::move(line));
}
}
line = MakeUnique<CLevelParserLine>("CreateObject");
IOWriteObject(line.get(), obj);
IOWriteObject(line.get(), obj, dirname, objRank++);
levelParser.AddLine(std::move(line));
SaveFileScript(obj, filename.c_str(), objRank++);
}
try
{
@ -4809,7 +4619,7 @@ void CRobotMain::IOWriteSceneFinished()
}
//! 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);
params.power = -1.0f;
@ -4828,10 +4638,8 @@ CObject* CRobotMain::IOReadObject(CLevelParserLine *line, const char* filename,
{
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? :/
// TODO: Also, why doesn't CStaticObject implement SetRotation?
oldObj->SetDefRank(objRank);
oldObj->SetPosition(line->GetParam("pos")->AsPoint() * g_unit);
oldObj->SetRotation(line->GetParam("angle")->AsPoint() * Math::DEG_TO_RAD);
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
}
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))
{
for (unsigned int i = 0; i <= 999; i++)
{
if (line->GetParam("scriptReadOnly" + boost::lexical_cast<std::string>(i+1))->AsBool(false))
{
Program* prog = dynamic_cast<CProgramStorageObject*>(obj)->GetOrAddProgram(i);
prog->readOnly = true;
}
}
CProgramStorageObject* programStorage = dynamic_cast<CProgramStorageObject*>(obj);
if (!line->GetParam("programStorageIndex")->IsDefined()) // Backwards combatibility
programStorage->SetProgramStorageIndex(objRank);
programStorage->LoadAllProgramsForSavedScene(line, programDir);
}
return obj;
@ -4896,6 +4691,8 @@ CObject* CRobotMain::IOReadObject(CLevelParserLine *line, const char* filename,
//! Resumes some part of the game
CObject* CRobotMain::IOReadScene(std::string filename, std::string filecbot)
{
std::string dirname = filename.substr(0, filename.find_last_of("/"));
CLevelParser levelParser(filename);
levelParser.Load();
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")
{
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++;
}
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++;
}
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))
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);
// Reads the file of stacks of execution.

View File

@ -273,12 +273,8 @@ public:
void StartShowLimit();
void FrameShowLimit(float rTime);
void CompileScript(bool soluce);
void LoadOneScript(CObject *pObj);
void LoadFileScript(CObject *pObj, const char* filename, int objRank);
void SaveAllScript();
void SaveOneScript(CObject *pObj);
void SaveFileScript(CObject *pObj, const char* filename, int objRank);
bool SaveFileStack(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);
void IOWriteSceneFinished();
CObject* IOReadScene(std::string filename, std::string filecbot);
void IOWriteObject(CLevelParserLine *line, CObject* obj);
CObject* IOReadObject(CLevelParserLine *line, const char* filename, const std::string& objCounterText, float objectProgress, int objRank);
void IOWriteObject(CLevelParserLine *line, CObject* obj, const std::string& programDir, 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);

View File

@ -20,9 +20,15 @@
#include "object/implementation/programmable_impl.h"
#include "common/global.h"
#include "common/logger.h"
#include "common/stringutils.h"
#include "common/resources/resourcemanager.h"
#include "level/robotmain.h"
#include "level/parser/parserline.h"
#include "math/all.h"
#include "object/object.h"
@ -48,7 +54,9 @@ CProgramStorageObjectImpl::CProgramStorageObjectImpl(ObjectInterfaceTypes& types
m_object(object),
m_program(),
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;
}
// 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.
bool CProgramStorageObjectImpl::ReadProgram(Program* program, const std::string& filename)
@ -244,3 +225,148 @@ bool CProgramStorageObjectImpl::WriteProgram(Program* program, const std::string
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;
const std::string& GetSoluceName() override;
bool ReadSoluce(const std::string& filename) override;
bool ReadProgram(Program* program, const std::string& filename) override;
bool GetCompile(Program* program) override;
bool WriteProgram(Program* program, const std::string& filename) override;
@ -55,6 +54,16 @@ public:
Program* GetProgram(int index) override;
Program* GetOrAddProgram(int index) 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:
CObject* m_object;
@ -64,4 +73,7 @@ private:
bool m_activeVirus;
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_cmdLine(),
m_currentProgram(nullptr),
m_scriptRun(nullptr),
m_traceRecord(false),
m_traceOper(TO_STOP),
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.
bool CProgrammableObjectImpl::ReadStack(FILE *file)

View File

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

View File

@ -26,13 +26,14 @@
#include <vector>
class CScript;
class CLevelParserLine;
struct Program
{
std::unique_ptr<CScript> script;
std::string filename;
bool readOnly = false;
bool runnable = true;
bool loadedFromLevel = false;
};
/**
@ -56,7 +57,6 @@ public:
virtual void SetSoluceName(const std::string& name) = 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 GetCompile(Program* program) = 0;
virtual bool WriteProgram(Program* program, const std::string& filename) = 0;
@ -71,4 +71,18 @@ public:
virtual Program* GetProgram(int index) = 0;
virtual Program* GetOrAddProgram(int index) = 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 void StopProgram() = 0;
virtual void SetScriptRun(Program* rank) = 0;
virtual Program* GetScriptRun() = 0;
virtual bool ReadStack(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_PROGLIST, bEnable && !m_programmable->IsTraceRecord());
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_PROGCLONE, !m_programmable->IsProgram() && m_selScript < m_programStorage->GetProgramCount() && m_programStorage->GetProgram(m_selScript)->runnable && 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 >= 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_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_RIGHT, bEnable);
EnableInterface(pw, EVENT_OBJECT_UP, bEnable);