(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:
rubidium 2009-09-12 20:59:34 +00:00
parent 6e14331cda
commit edbd568094
6 changed files with 50 additions and 6 deletions

View File

@ -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;

View File

@ -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.");
}

View File

@ -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.");
}

View File

@ -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();

View File

@ -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);

View File

@ -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);