summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/3rdparty/squirrel/include/squirrel.h1
-rw-r--r--src/3rdparty/squirrel/squirrel/sqapi.cpp8
-rw-r--r--src/ai/ai_instance.cpp8
-rw-r--r--src/ai/ai_instance.hpp17
-rw-r--r--src/ai/api/ai_controller.cpp3
-rw-r--r--src/ai/api/ai_object.cpp3
-rw-r--r--src/script/squirrel.cpp6
-rw-r--r--src/script/squirrel.hpp5
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
@@ -107,6 +107,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.
*/
void CollectGarbage();