From edbd568094c9932e8c399838c550801e7405bb75 Mon Sep 17 00:00:00 2001 From: rubidium Date: Sat, 12 Sep 2009 20:59:34 +0000 Subject: [PATCH] (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) --- src/3rdparty/squirrel/squirrel/sqvm.cpp | 5 +++++ src/ai/api/ai_controller.cpp | 2 +- src/ai/api/ai_object.cpp | 7 ++++++- src/ai/api/ai_object.hpp | 11 +++++++++-- src/settings.cpp | 14 ++++++++++++++ src/vehicle_cmd.cpp | 17 +++++++++++++++-- 6 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/3rdparty/squirrel/squirrel/sqvm.cpp b/src/3rdparty/squirrel/squirrel/sqvm.cpp index d1ae4e64e8..41caf0b51c 100644 --- a/src/3rdparty/squirrel/squirrel/sqvm.cpp +++ b/src/3rdparty/squirrel/squirrel/sqvm.cpp @@ -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; diff --git a/src/ai/api/ai_controller.cpp b/src/ai/api/ai_controller.cpp index 7e7e5d0191..a9b586d1b5 100644 --- a/src/ai/api/ai_controller.cpp +++ b/src/ai/api/ai_controller.cpp @@ -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."); } diff --git a/src/ai/api/ai_object.cpp b/src/ai/api/ai_object.cpp index cdf57090cb..1629b18ddb 100644 --- a/src/ai/api/ai_object.cpp +++ b/src/ai/api/ai_object.cpp @@ -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."); } diff --git a/src/ai/api/ai_object.hpp b/src/ai/api/ai_object.hpp index 40f3b920cd..3176239609 100644 --- a/src/ai/api/ai_object.hpp +++ b/src/ai/api/ai_object.hpp @@ -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(); diff --git a/src/settings.cpp b/src/settings.cpp index a4be31153d..bcf2c49733 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -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); diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index a9910cea0a..a6fd969362 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -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);