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;
|
||||
try {
|
||||
SQBool can_suspend = this->_can_suspend;
|
||||
|
@ -1152,6 +1154,7 @@ bool SQVM::CallNative(SQNativeClosure *nclosure,SQInteger nargs,SQInteger stackb
|
|||
_nnativecalls--;
|
||||
suspend = false;
|
||||
|
||||
_callsstacksize = cstksize;
|
||||
_stackbase = oldstackbase;
|
||||
_top = oldtop;
|
||||
|
||||
|
@ -1161,6 +1164,8 @@ bool SQVM::CallNative(SQNativeClosure *nclosure,SQInteger nargs,SQInteger stackb
|
|||
throw;
|
||||
}
|
||||
|
||||
assert(cstksize == _callsstacksize);
|
||||
|
||||
_nnativecalls--;
|
||||
suspend = false;
|
||||
if( ret == SQ_SUSPEND_FLAG) suspend = true;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
/* 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.");
|
||||
}
|
||||
|
||||
|
|
|
@ -161,6 +161,11 @@ void AIObject::SetAllowDoCommand(bool allow)
|
|||
}
|
||||
|
||||
bool AIObject::GetAllowDoCommand()
|
||||
{
|
||||
return GetStorage()->allow_do_command;
|
||||
}
|
||||
|
||||
bool AIObject::CanSuspend()
|
||||
{
|
||||
Squirrel *squirrel = GetCompany(_current_company)->ai_instance->engine;
|
||||
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)
|
||||
{
|
||||
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.");
|
||||
}
|
||||
|
||||
|
|
|
@ -133,8 +133,15 @@ protected:
|
|||
static GroupID GetNewGroupID();
|
||||
|
||||
/**
|
||||
* Get the latest stored allow_do_command.
|
||||
* If this is false, you are not allowed to do any DoCommands.
|
||||
* Can we suspend the AI at this moment?
|
||||
*/
|
||||
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();
|
||||
|
||||
|
|
|
@ -1799,6 +1799,20 @@ static GRFConfig *GRFLoadConfig(IniFile *ini, const char *grpname, bool is_stati
|
|||
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. */
|
||||
if (is_static) SetBit(c->flags, GCF_STATIC);
|
||||
|
||||
|
|
|
@ -374,10 +374,23 @@ CommandCost CmdCloneVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint
|
|||
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
|
||||
|
||||
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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue