1
0
Fork 0

(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

release/1.0
yexo 2009-08-19 16:14:15 +00:00
parent 0780dc8138
commit a4afa140f3
8 changed files with 46 additions and 5 deletions

View File

@ -311,6 +311,7 @@ SQUIRREL_API void sq_setprintfunc(HSQUIRRELVM v, SQPRINTFUNCTION printfunc);
SQUIRREL_API SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v); SQUIRREL_API SQPRINTFUNCTION sq_getprintfunc(HSQUIRRELVM v);
SQUIRREL_API SQRESULT sq_suspendvm(HSQUIRRELVM v); SQUIRREL_API SQRESULT sq_suspendvm(HSQUIRRELVM v);
SQUIRREL_API bool sq_resumecatch(HSQUIRRELVM v, int suspend = -1); 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 SQRESULT sq_wakeupvm(HSQUIRRELVM v,SQBool resumedret,SQBool retval,SQBool raiseerror,SQBool throwerror);
SQUIRREL_API SQInteger sq_getvmstate(HSQUIRRELVM v); SQUIRREL_API SQInteger sq_getvmstate(HSQUIRRELVM v);

View File

@ -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); 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) void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook)
{ {
if(sq_gettop(v) >= 1){ if(sq_gettop(v) >= 1){

View File

@ -352,6 +352,10 @@ void AIInstance::GameLoop()
} catch (AI_VMSuspend e) { } catch (AI_VMSuspend e) {
this->suspend = e.GetSuspendTime(); this->suspend = e.GetSuspendTime();
this->callback = e.GetSuspendCallback(); this->callback = e.GetSuspendCallback();
} catch (AI_FatalError e) {
this->engine->ThrowError(e.GetErrorMessage());
this->engine->ResumeError();
this->Died();
} }
this->is_started = true; this->is_started = true;
@ -368,6 +372,10 @@ void AIInstance::GameLoop()
} catch (AI_VMSuspend e) { } catch (AI_VMSuspend e) {
this->suspend = e.GetSuspendTime(); this->suspend = e.GetSuspendTime();
this->callback = e.GetSuspendCallback(); this->callback = e.GetSuspendCallback();
} catch (AI_FatalError e) {
this->engine->ThrowError(e.GetErrorMessage());
this->engine->ResumeError();
this->Died();
} }
} }

View File

@ -18,7 +18,7 @@ public:
AI_VMSuspend(int time, AISuspendCallbackProc *callback) : AI_VMSuspend(int time, AISuspendCallbackProc *callback) :
time(time), time(time),
callback(callback) callback(callback)
{} {}
int GetSuspendTime() { return time; } int GetSuspendTime() { return time; }
AISuspendCallbackProc *GetSuspendCallback() { return callback; } AISuspendCallbackProc *GetSuspendCallback() { return callback; }
@ -28,6 +28,21 @@ private:
AISuspendCallbackProc *callback; 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 { class AIInstance {
public: public:
friend class AIObject; friend class AIObject;

View File

@ -24,8 +24,7 @@
/* static */ void AIController::Sleep(int ticks) /* static */ void AIController::Sleep(int ticks)
{ {
if (!AIObject::GetAllowDoCommand()) { if (!AIObject::GetAllowDoCommand()) {
AILog::Error("You are not allowed to call Sleep in your constructor, Save(), Load(), and any valuator.\n"); throw AI_FatalError("You are not allowed to call Sleep in your constructor, Save(), Load(), and any valuator.");
return;
} }
if (ticks <= 0) { if (ticks <= 0) {

View File

@ -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) bool AIObject::DoCommand(TileIndex tile, uint32 p1, uint32 p2, uint cmd, const char *text, AISuspendCallbackProc *callback)
{ {
if (AIObject::GetAllowDoCommand() == false) { 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"); throw AI_FatalError("You are not allowed to execute any DoCommand (even indirect) in your constructor, Save(), Load(), and any valuator.");
return false;
} }
CommandCost res; CommandCost res;

View File

@ -187,6 +187,12 @@ bool Squirrel::Resume(int suspend)
return this->vm->_suspended != 0; return this->vm->_suspended != 0;
} }
void Squirrel::ResumeError()
{
assert(!this->crashed);
sq_resumeerror(this->vm);
}
void Squirrel::CollectGarbage() void Squirrel::CollectGarbage()
{ {
sq_collectgarbage(this->vm); sq_collectgarbage(this->vm);

View File

@ -106,6 +106,11 @@ public:
*/ */
bool Resume(int suspend = -1); 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. * Tell the VM to do a garbage collection run.
*/ */