From f085d7775b12e77b8012ab09ae72b850367a3237 Mon Sep 17 00:00:00 2001 From: yexo Date: Wed, 15 Jul 2009 19:47:06 +0000 Subject: (svn r16834) -Fix [FS#3034]: call the AI Save() function only once so AIs can't crash OpenTTD --- src/ai/ai_instance.cpp | 45 +++++++++++++++++++++------------------------ src/ai/ai_instance.hpp | 1 + src/script/squirrel.cpp | 5 +++++ src/script/squirrel.hpp | 5 +++++ 4 files changed, 32 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/ai/ai_instance.cpp b/src/ai/ai_instance.cpp index 8dff24f78..4566e925d 100644 --- a/src/ai/ai_instance.cpp +++ b/src/ai/ai_instance.cpp @@ -101,6 +101,7 @@ AIInstance::AIInstance(AIInfo *info) : instance(NULL), is_started(false), is_dead(false), + is_save_data_on_stack(false), suspend(0), callback(NULL) { @@ -138,10 +139,6 @@ AIInstance::AIInstance(AIInfo *info) : /* Register the API functions and classes */ 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() @@ -288,6 +285,10 @@ void AIInstance::GameLoop() /* If there is a callback to call, call that first */ if (this->callback != NULL) { + if (this->is_save_data_on_stack) { + sq_poptop(this->engine->GetVM()); + this->is_save_data_on_stack = false; + } try { this->callback(this); } catch (AI_VMSuspend e) { @@ -328,6 +329,10 @@ void AIInstance::GameLoop() this->is_started = true; return; } + if (this->is_save_data_on_stack) { + sq_poptop(this->engine->GetVM()); + this->is_save_data_on_stack = false; + } /* Continue the VM */ try { @@ -546,20 +551,14 @@ void AIInstance::Save() } HSQUIRRELVM vm = this->engine->GetVM(); - if (!this->is_started) { - 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); + if (this->is_save_data_on_stack) { _ai_sl_byte = 1; SlObject(NULL, _ai_byte); /* Save the data that was just loaded. */ 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")) { HSQOBJECT savedata; /* We don't want to be interrupted during the save function. */ @@ -576,6 +575,7 @@ void AIInstance::Save() if (!sq_istable(savedata)) { AILog::Error("Save function should return a table."); SaveEmpty(); + this->engine->CrashOccurred(); return; } sq_pushobject(vm, savedata); @@ -583,11 +583,11 @@ void AIInstance::Save() _ai_sl_byte = 1; SlObject(NULL, _ai_byte); SaveObject(vm, -1, AISAVE_MAX_DEPTH, false); + this->is_save_data_on_stack = true; } else { - _ai_sl_byte = 0; - SlObject(NULL, _ai_byte); + SaveEmpty(); + this->engine->CrashOccurred(); } - sq_pop(vm, 1); } else { AILog::Warning("Save function is not implemented"); _ai_sl_byte = 0; @@ -674,21 +674,18 @@ void AIInstance::Load(int version) /* Check if there was anything saved at all. */ if (_ai_sl_byte == 0) return; - /* First remove the value "false" since we have data to load. */ - sq_poptop(vm); sq_pushinteger(vm, version); LoadObjects(vm); - sq_pushbool(vm, true); + this->is_save_data_on_stack = true; } bool AIInstance::CallLoad() { HSQUIRRELVM vm = this->engine->GetVM(); /* Is there save data that we should load? */ - SQBool res; - sq_getbool(vm, -1, &res); - sq_poptop(vm); - if (!res) return true; + if (!this->is_save_data_on_stack) return true; + /* Whatever happens, after CallLoad the savegame data is removed from the stack. */ + this->is_save_data_on_stack = false; 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."); diff --git a/src/ai/ai_instance.hpp b/src/ai/ai_instance.hpp index 2730e9bd9..4c9cb69a5 100644 --- a/src/ai/ai_instance.hpp +++ b/src/ai/ai_instance.hpp @@ -123,6 +123,7 @@ private: bool is_started; bool is_dead; + bool is_save_data_on_stack; int suspend; AISuspendCallbackProc *callback; diff --git a/src/script/squirrel.cpp b/src/script/squirrel.cpp index 6955d2d24..3fb778043 100644 --- a/src/script/squirrel.cpp +++ b/src/script/squirrel.cpp @@ -509,6 +509,11 @@ void Squirrel::ResetCrashed() this->crashed = false; } +void Squirrel::CrashOccurred() +{ + this->crashed = true; +} + bool Squirrel::CanSuspend() { return sq_can_suspend(this->vm); diff --git a/src/script/squirrel.hpp b/src/script/squirrel.hpp index b878c2b95..32f24cb11 100644 --- a/src/script/squirrel.hpp +++ b/src/script/squirrel.hpp @@ -214,6 +214,11 @@ public: */ void ResetCrashed(); + /** + * Set the AI status to crashed. + */ + void CrashOccurred(); + /** * Are we allowed to suspend the squirrel script at this moment? */ -- cgit v1.2.3-54-g00ecf