mirror of https://github.com/OpenTTD/OpenTTD.git
(svn r17517) [0.7] -Backport from trunk:
- Fix: [Squirrel] In some cases the call stack would not be cleaned up properly during crash handling. Occasionally this causes asserts to be triggered or crashes [FS#3189] (r17515) - Fix: When loading GRFConfigs from ini file, validate them wrt. duplicate GRF IDs [FS#3197] (r17510) - Fix: When building a part fails during cloning, sell what was already cloned instead of leaving it "for free". Also make cloning multiheaded trains possible with with "max - 1" vehicles existing [FS#3196] (r17509) - Fix: The wrong value was restored to SetAllowDoCommand possible resulting in an AI that was not allowed to do any actions (r17500)
This commit is contained in:
parent
6e14331cda
commit
edbd568094
|
@ -1142,6 +1142,8 @@ bool SQVM::CallNative(SQNativeClosure *nclosure,SQInteger nargs,SQInteger stackb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Store the call stack size, so we can restore that */
|
||||||
|
SQInteger cstksize = _callsstacksize;
|
||||||
SQInteger ret;
|
SQInteger ret;
|
||||||
try {
|
try {
|
||||||
SQBool can_suspend = this->_can_suspend;
|
SQBool can_suspend = this->_can_suspend;
|
||||||
|
@ -1152,6 +1154,7 @@ bool SQVM::CallNative(SQNativeClosure *nclosure,SQInteger nargs,SQInteger stackb
|
||||||
_nnativecalls--;
|
_nnativecalls--;
|
||||||
suspend = false;
|
suspend = false;
|
||||||
|
|
||||||
|
_callsstacksize = cstksize;
|
||||||
_stackbase = oldstackbase;
|
_stackbase = oldstackbase;
|
||||||
_top = oldtop;
|
_top = oldtop;
|
||||||
|
|
||||||
|
@ -1161,6 +1164,8 @@ bool SQVM::CallNative(SQNativeClosure *nclosure,SQInteger nargs,SQInteger stackb
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(cstksize == _callsstacksize);
|
||||||
|
|
||||||
_nnativecalls--;
|
_nnativecalls--;
|
||||||
suspend = false;
|
suspend = false;
|
||||||
if( ret == SQ_SUSPEND_FLAG) suspend = true;
|
if( ret == SQ_SUSPEND_FLAG) suspend = true;
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
/* static */ void AIController::Sleep(int ticks)
|
/* static */ void AIController::Sleep(int ticks)
|
||||||
{
|
{
|
||||||
if (!AIObject::GetAllowDoCommand()) {
|
if (!AIObject::CanSuspend()) {
|
||||||
throw AI_FatalError("You are not allowed to call Sleep in your constructor, Save(), Load(), and any valuator.");
|
throw AI_FatalError("You are not allowed to call Sleep in your constructor, Save(), Load(), and any valuator.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -161,6 +161,11 @@ void AIObject::SetAllowDoCommand(bool allow)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AIObject::GetAllowDoCommand()
|
bool AIObject::GetAllowDoCommand()
|
||||||
|
{
|
||||||
|
return GetStorage()->allow_do_command;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AIObject::CanSuspend()
|
||||||
{
|
{
|
||||||
Squirrel *squirrel = GetCompany(_current_company)->ai_instance->engine;
|
Squirrel *squirrel = GetCompany(_current_company)->ai_instance->engine;
|
||||||
return GetStorage()->allow_do_command && squirrel->CanSuspend();
|
return GetStorage()->allow_do_command && squirrel->CanSuspend();
|
||||||
|
@ -189,7 +194,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::CanSuspend()) {
|
||||||
throw AI_FatalError("You are not allowed to execute any DoCommand (even indirect) in your constructor, Save(), Load(), and any valuator.");
|
throw AI_FatalError("You are not allowed to execute any DoCommand (even indirect) in your constructor, Save(), Load(), and any valuator.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -133,8 +133,15 @@ protected:
|
||||||
static GroupID GetNewGroupID();
|
static GroupID GetNewGroupID();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the latest stored allow_do_command.
|
* Can we suspend the AI at this moment?
|
||||||
* If this is false, you are not allowed to do any DoCommands.
|
*/
|
||||||
|
static bool CanSuspend();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the internal value of allow_do_command. This can differ
|
||||||
|
* from CanSuspend() if the reason we are not allowed
|
||||||
|
* to execute a DoCommand is in squirrel and not the API.
|
||||||
|
* In that case use this function to restore the previous value.
|
||||||
*/
|
*/
|
||||||
static bool GetAllowDoCommand();
|
static bool GetAllowDoCommand();
|
||||||
|
|
||||||
|
|
|
@ -1799,6 +1799,20 @@ static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_stati
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for duplicate GRFID (will also check for duplicate filenames) */
|
||||||
|
bool duplicate = false;
|
||||||
|
for (const GRFConfig *gc = first; gc != NULL; gc = gc->next) {
|
||||||
|
if (gc->grfid == c->grfid) {
|
||||||
|
ShowInfoF("ini: ignoring NewGRF '%s': duplicate GRF ID with '%s'", item->name, gc->filename);
|
||||||
|
duplicate = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (duplicate) {
|
||||||
|
ClearGRFConfig(&c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* Mark file as static to avoid saving in savegame. */
|
/* Mark file as static to avoid saving in savegame. */
|
||||||
if (is_static) SetBit(c->flags, GCF_STATIC);
|
if (is_static) SetBit(c->flags, GCF_STATIC);
|
||||||
|
|
||||||
|
|
|
@ -374,10 +374,23 @@ CommandCost CmdCloneVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
CommandCost cost = DoCommand(tile, v->engine_type, build_argument, flags, GetCmdBuildVeh(v));
|
/* In case we're building a multi headed vehicle and the maximum number of
|
||||||
|
* vehicles is almost reached (e.g. max trains - 1) not all vehicles would
|
||||||
|
* be cloned. When the non-primary engines were build they were seen as
|
||||||
|
* 'new' vehicles whereas they would immediately be joined with a primary
|
||||||
|
* engine. This caused the vehicle to be not build as 'the limit' had been
|
||||||
|
* reached, resulting in partially build vehicles and such. */
|
||||||
|
DoCommandFlag build_flags = flags;
|
||||||
|
if ((flags & DC_EXEC) && !v->IsPrimaryVehicle()) build_flags |= DC_AUTOREPLACE;
|
||||||
|
|
||||||
|
CommandCost cost = DoCommand(tile, v->engine_type, build_argument, build_flags, GetCmdBuildVeh(v));
|
||||||
build_argument = 3; // ensure that we only assign a number to the first engine
|
build_argument = 3; // ensure that we only assign a number to the first engine
|
||||||
|
|
||||||
if (CmdFailed(cost)) return cost;
|
if (CmdFailed(cost)) {
|
||||||
|
/* Can't build a part, then sell the stuff we already made; clear up the mess */
|
||||||
|
if (w_front != NULL) DoCommand(w_front->tile, w_front->index, 1, flags, GetCmdSellVeh(w_front));
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
total_cost.AddCost(cost);
|
total_cost.AddCost(cost);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue