mirror of https://github.com/OpenTTD/OpenTTD
(svn r16834) -Fix [FS#3034]: call the AI Save() function only once so AIs can't crash OpenTTD
parent
91a6af688e
commit
f085d7775b
|
@ -101,6 +101,7 @@ AIInstance::AIInstance(AIInfo *info) :
|
||||||
instance(NULL),
|
instance(NULL),
|
||||||
is_started(false),
|
is_started(false),
|
||||||
is_dead(false),
|
is_dead(false),
|
||||||
|
is_save_data_on_stack(false),
|
||||||
suspend(0),
|
suspend(0),
|
||||||
callback(NULL)
|
callback(NULL)
|
||||||
{
|
{
|
||||||
|
@ -138,10 +139,6 @@ AIInstance::AIInstance(AIInfo *info) :
|
||||||
|
|
||||||
/* Register the API functions and classes */
|
/* Register the API functions and classes */
|
||||||
this->RegisterAPI();
|
this->RegisterAPI();
|
||||||
|
|
||||||
/* The topmost stack item is true if there is data from a savegame
|
|
||||||
* and false otherwise. */
|
|
||||||
sq_pushbool(this->engine->vm, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AIInstance::~AIInstance()
|
AIInstance::~AIInstance()
|
||||||
|
@ -288,6 +285,10 @@ void AIInstance::GameLoop()
|
||||||
|
|
||||||
/* If there is a callback to call, call that first */
|
/* If there is a callback to call, call that first */
|
||||||
if (this->callback != NULL) {
|
if (this->callback != NULL) {
|
||||||
|
if (this->is_save_data_on_stack) {
|
||||||
|
sq_poptop(this->engine->GetVM());
|
||||||
|
this->is_save_data_on_stack = false;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
this->callback(this);
|
this->callback(this);
|
||||||
} catch (AI_VMSuspend e) {
|
} catch (AI_VMSuspend e) {
|
||||||
|
@ -328,6 +329,10 @@ void AIInstance::GameLoop()
|
||||||
this->is_started = true;
|
this->is_started = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (this->is_save_data_on_stack) {
|
||||||
|
sq_poptop(this->engine->GetVM());
|
||||||
|
this->is_save_data_on_stack = false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Continue the VM */
|
/* Continue the VM */
|
||||||
try {
|
try {
|
||||||
|
@ -546,20 +551,14 @@ void AIInstance::Save()
|
||||||
}
|
}
|
||||||
|
|
||||||
HSQUIRRELVM vm = this->engine->GetVM();
|
HSQUIRRELVM vm = this->engine->GetVM();
|
||||||
if (!this->is_started) {
|
if (this->is_save_data_on_stack) {
|
||||||
SQBool res;
|
|
||||||
sq_getbool(vm, -1, &res);
|
|
||||||
if (!res) {
|
|
||||||
SaveEmpty();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* Push the loaded savegame data to the top of the stack. */
|
|
||||||
sq_push(vm, -2);
|
|
||||||
_ai_sl_byte = 1;
|
_ai_sl_byte = 1;
|
||||||
SlObject(NULL, _ai_byte);
|
SlObject(NULL, _ai_byte);
|
||||||
/* Save the data that was just loaded. */
|
/* Save the data that was just loaded. */
|
||||||
SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
|
SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
|
||||||
sq_poptop(vm);
|
} else if (!this->is_started) {
|
||||||
|
SaveEmpty();
|
||||||
|
return;
|
||||||
} else if (this->engine->MethodExists(*this->instance, "Save")) {
|
} else if (this->engine->MethodExists(*this->instance, "Save")) {
|
||||||
HSQOBJECT savedata;
|
HSQOBJECT savedata;
|
||||||
/* We don't want to be interrupted during the save function. */
|
/* We don't want to be interrupted during the save function. */
|
||||||
|
@ -576,6 +575,7 @@ void AIInstance::Save()
|
||||||
if (!sq_istable(savedata)) {
|
if (!sq_istable(savedata)) {
|
||||||
AILog::Error("Save function should return a table.");
|
AILog::Error("Save function should return a table.");
|
||||||
SaveEmpty();
|
SaveEmpty();
|
||||||
|
this->engine->CrashOccurred();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sq_pushobject(vm, savedata);
|
sq_pushobject(vm, savedata);
|
||||||
|
@ -583,11 +583,11 @@ void AIInstance::Save()
|
||||||
_ai_sl_byte = 1;
|
_ai_sl_byte = 1;
|
||||||
SlObject(NULL, _ai_byte);
|
SlObject(NULL, _ai_byte);
|
||||||
SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
|
SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
|
||||||
|
this->is_save_data_on_stack = true;
|
||||||
} else {
|
} else {
|
||||||
_ai_sl_byte = 0;
|
SaveEmpty();
|
||||||
SlObject(NULL, _ai_byte);
|
this->engine->CrashOccurred();
|
||||||
}
|
}
|
||||||
sq_pop(vm, 1);
|
|
||||||
} else {
|
} else {
|
||||||
AILog::Warning("Save function is not implemented");
|
AILog::Warning("Save function is not implemented");
|
||||||
_ai_sl_byte = 0;
|
_ai_sl_byte = 0;
|
||||||
|
@ -674,21 +674,18 @@ void AIInstance::Load(int version)
|
||||||
/* Check if there was anything saved at all. */
|
/* Check if there was anything saved at all. */
|
||||||
if (_ai_sl_byte == 0) return;
|
if (_ai_sl_byte == 0) return;
|
||||||
|
|
||||||
/* First remove the value "false" since we have data to load. */
|
|
||||||
sq_poptop(vm);
|
|
||||||
sq_pushinteger(vm, version);
|
sq_pushinteger(vm, version);
|
||||||
LoadObjects(vm);
|
LoadObjects(vm);
|
||||||
sq_pushbool(vm, true);
|
this->is_save_data_on_stack = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AIInstance::CallLoad()
|
bool AIInstance::CallLoad()
|
||||||
{
|
{
|
||||||
HSQUIRRELVM vm = this->engine->GetVM();
|
HSQUIRRELVM vm = this->engine->GetVM();
|
||||||
/* Is there save data that we should load? */
|
/* Is there save data that we should load? */
|
||||||
SQBool res;
|
if (!this->is_save_data_on_stack) return true;
|
||||||
sq_getbool(vm, -1, &res);
|
/* Whatever happens, after CallLoad the savegame data is removed from the stack. */
|
||||||
sq_poptop(vm);
|
this->is_save_data_on_stack = false;
|
||||||
if (!res) return true;
|
|
||||||
|
|
||||||
if (!this->engine->MethodExists(*this->instance, "Load")) {
|
if (!this->engine->MethodExists(*this->instance, "Load")) {
|
||||||
AILog::Warning("Loading failed: there was data for the AI to load, but the AI does not have a Load() function.");
|
AILog::Warning("Loading failed: there was data for the AI to load, but the AI does not have a Load() function.");
|
||||||
|
|
|
@ -123,6 +123,7 @@ private:
|
||||||
|
|
||||||
bool is_started;
|
bool is_started;
|
||||||
bool is_dead;
|
bool is_dead;
|
||||||
|
bool is_save_data_on_stack;
|
||||||
int suspend;
|
int suspend;
|
||||||
AISuspendCallbackProc *callback;
|
AISuspendCallbackProc *callback;
|
||||||
|
|
||||||
|
|
|
@ -509,6 +509,11 @@ void Squirrel::ResetCrashed()
|
||||||
this->crashed = false;
|
this->crashed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Squirrel::CrashOccurred()
|
||||||
|
{
|
||||||
|
this->crashed = true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Squirrel::CanSuspend()
|
bool Squirrel::CanSuspend()
|
||||||
{
|
{
|
||||||
return sq_can_suspend(this->vm);
|
return sq_can_suspend(this->vm);
|
||||||
|
|
|
@ -214,6 +214,11 @@ public:
|
||||||
*/
|
*/
|
||||||
void ResetCrashed();
|
void ResetCrashed();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the AI status to crashed.
|
||||||
|
*/
|
||||||
|
void CrashOccurred();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Are we allowed to suspend the squirrel script at this moment?
|
* Are we allowed to suspend the squirrel script at this moment?
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue