From a4afa140f36673cd7dac1277aa4dd1d45618363b Mon Sep 17 00:00:00 2001 From: yexo Date: Wed, 19 Aug 2009 16:14:15 +0000 Subject: (svn r17223) -Change [NoAI] [FS#2980]: Crash an AI when it uses a DoCommand / Sleep instead of just printing an error message in the AI Debug Window --- src/3rdparty/squirrel/include/squirrel.h | 1 + src/3rdparty/squirrel/squirrel/sqapi.cpp | 8 ++++++++ src/ai/ai_instance.cpp | 8 ++++++++ src/ai/ai_instance.hpp | 17 ++++++++++++++++- src/ai/api/ai_controller.cpp | 3 +-- src/ai/api/ai_object.cpp | 3 +-- src/script/squirrel.cpp | 6 ++++++ src/script/squirrel.hpp | 5 +++++ 8 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/3rdparty/squirrel/include/squirrel.h b/src/3rdparty/squirrel/include/squirrel.h index 806454721..63fb96e39 100644 --- a/src/3rdparty/squirrel/include/squirrel.h +++ b/src/3rdparty/squirrel/include/squirrel.h @@ -311,6 +311,7 @@ SQUIRREL_API void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc); SQUIRREL_API SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v); SQUIRREL_API SQRESULT sq_suspendvm(HSQUIRRELVM v); SQUIRREL_API bool sq_resumecatch(HSQUIRRELVM v, int suspend = -1); +SQUIRREL_API bool sq_resumeerror(HSQUIRRELVM v); SQUIRREL_API SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool resumedret,SQBool retval,SQBool raiseerror,SQBool throwerror); SQUIRREL_API SQInteger sq_getvmstate(HSQUIRRELVM v); diff --git a/src/3rdparty/squirrel/squirrel/sqapi.cpp b/src/3rdparty/squirrel/squirrel/sqapi.cpp index 1e8b456f6..2d53d71bb 100644 --- a/src/3rdparty/squirrel/squirrel/sqapi.cpp +++ b/src/3rdparty/squirrel/squirrel/sqapi.cpp @@ -1012,6 +1012,14 @@ bool sq_resumecatch(HSQUIRRELVM v, int suspend) return v->Execute(_null_, v->_top, -1, -1, ret, SQTrue, SQVM::ET_RESUME_OPENTTD); } +bool sq_resumeerror(HSQUIRRELVM v) +{ + SQObjectPtr ret; + v->_can_suspend = true; + v->_ops_till_suspend = 1; + return v->Execute(_null_, v->_top, -1, -1, ret, SQTrue, SQVM::ET_RESUME_THROW_VM); +} + void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook) { if(sq_gettop(v) >= 1){ diff --git a/src/ai/ai_instance.cpp b/src/ai/ai_instance.cpp index 6d3397a70..a5ef5135b 100644 --- a/src/ai/ai_instance.cpp +++ b/src/ai/ai_instance.cpp @@ -352,6 +352,10 @@ void AIInstance::GameLoop() } catch (AI_VMSuspend e) { this->suspend = e.GetSuspendTime(); this->callback = e.GetSuspendCallback(); + } catch (AI_FatalError e) { + this->engine->ThrowError(e.GetErrorMessage()); + this->engine->ResumeError(); + this->Died(); } this->is_started = true; @@ -368,6 +372,10 @@ void AIInstance::GameLoop() } catch (AI_VMSuspend e) { this->suspend = e.GetSuspendTime(); this->callback = e.GetSuspendCallback(); + } catch (AI_FatalError e) { + this->engine->ThrowError(e.GetErrorMessage()); + this->engine->ResumeError(); + this->Died(); } } diff --git a/src/ai/ai_instance.hpp b/src/ai/ai_instance.hpp index f260d46d4..c93bf0472 100644 --- a/src/ai/ai_instance.hpp +++ b/src/ai/ai_instance.hpp @@ -18,7 +18,7 @@ public: AI_VMSuspend(int time, AISuspendCallbackProc *callback) : time(time), callback(callback) - {} + {} int GetSuspendTime() { return time; } AISuspendCallbackProc *GetSuspendCallback() { return callback; } @@ -28,6 +28,21 @@ private: AISuspendCallbackProc *callback; }; +/** + * A throw-class that is given when the AI made a fatal error. + */ +class AI_FatalError { +public: + AI_FatalError(const char *msg) : + msg(msg) + {} + + const char *GetErrorMessage() { return msg; } + +private: + const char *msg; +}; + class AIInstance { public: friend class AIObject; diff --git a/src/ai/api/ai_controller.cpp b/src/ai/api/ai_controller.cpp index 24510b7e7..7553f5944 100644 --- a/src/ai/api/ai_controller.cpp +++ b/src/ai/api/ai_controller.cpp @@ -24,8 +24,7 @@ /* static */ void AIController::Sleep(int ticks) { if (!AIObject::GetAllowDoCommand()) { - AILog::Error("You are not allowed to call Sleep in your constructor, Save(), Load(), and any valuator.\n"); - return; + throw AI_FatalError("You are not allowed to call Sleep in your constructor, Save(), Load(), and any valuator."); } if (ticks <= 0) { diff --git a/src/ai/api/ai_object.cpp b/src/ai/api/ai_object.cpp index bb17e58f8..825c76c30 100644 --- a/src/ai/api/ai_object.cpp +++ b/src/ai/api/ai_object.cpp @@ -191,8 +191,7 @@ int AIObject::GetCallbackVariable(int index) bool AIObject::DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint cmd, const char *text, AISuspendCallbackProc *callback) { if (AIObject::GetAllowDoCommand() == false) { - AILog::Error("You are not allowed to execute any DoCommand (even indirect) in your constructor, Save(), Load(), and any valuator.\n"); - return false; + throw AI_FatalError("You are not allowed to execute any DoCommand (even indirect) in your constructor, Save(), Load(), and any valuator."); } CommandCost res; diff --git a/src/script/squirrel.cpp b/src/script/squirrel.cpp index 31dcf6aea..1dd407589 100644 --- a/src/script/squirrel.cpp +++ b/src/script/squirrel.cpp @@ -187,6 +187,12 @@ bool Squirrel::Resume(int suspend) return this->vm->_suspended != 0; } +void Squirrel::ResumeError() +{ + assert(!this->crashed); + sq_resumeerror(this->vm); +} + void Squirrel::CollectGarbage() { sq_collectgarbage(this->vm); diff --git a/src/script/squirrel.hpp b/src/script/squirrel.hpp index 612c6ce2e..97dd7988d 100644 --- a/src/script/squirrel.hpp +++ b/src/script/squirrel.hpp @@ -106,6 +106,11 @@ public: */ bool Resume(int suspend = -1); + /** + * Resume the VM with an error so it prints a stack trace. + */ + void ResumeError(); + /** * Tell the VM to do a garbage collection run. */ -- cgit v1.2.3-70-g09d2