From 821fe5c3baedc5e93445836830326c8e0b6e45e6 Mon Sep 17 00:00:00 2001 From: rubidium Date: Mon, 15 Mar 2010 22:52:39 +0000 Subject: [PATCH] (svn r19430) [1.0] -Backport from trunk: - Fix: [NoAI] When the title game contains an AIPL block the AI settings where overwritten by those from the title game (r19429) - Fix: Gracefully handle the case where we cannot open a .tar file (r19427) - Fix: [YAPP] A train on a bridge/tunnel was not always found when checking for trains on a reserved path (r19425) - Fix: [NoAI] The AI Debug window did not open if an AI or library fails to compile when loading a savegame [FS#3669] (r19395) - Change: Make the drive through and cargo list consistency checks only run when 'desync' debugging is enabled (r19403, r19398) --- src/ai/ai_config.cpp | 8 +- src/ai/ai_config.hpp | 10 ++- src/ai/ai_gui.cpp | 12 +++ src/ai/ai_gui.hpp | 5 ++ src/fileio.cpp | 6 +- src/misc.cpp | 2 +- src/openttd.cpp | 176 ++++++++++++++++++++----------------- src/pbs.cpp | 5 ++ src/saveload/afterload.cpp | 2 + src/saveload/ai_sl.cpp | 4 +- src/settings.cpp | 6 +- 11 files changed, 142 insertions(+), 94 deletions(-) diff --git a/src/ai/ai_config.cpp b/src/ai/ai_config.cpp index c0ae018480..aab8b1f187 100644 --- a/src/ai/ai_config.cpp +++ b/src/ai/ai_config.cpp @@ -93,13 +93,13 @@ const AIConfigItemList *AIConfig::GetConfigList() return this->config_list; } -AIConfig *AIConfig::GetConfig(CompanyID company, bool forceNewgameSetting) +AIConfig *AIConfig::GetConfig(CompanyID company, AISettingSource source) { AIConfig **config; - if (!forceNewgameSetting) { - config = (_game_mode == GM_MENU) ? &_settings_newgame.ai_config[company] : &_settings_game.ai_config[company]; - } else { + if (source == AISS_FORCE_NEWGAME || (source == AISS_DEFAULT && _game_mode == GM_MENU)) { config = &_settings_newgame.ai_config[company]; + } else { + config = &_settings_game.ai_config[company]; } if (*config == NULL) *config = new AIConfig(); return *config; diff --git a/src/ai/ai_config.hpp b/src/ai/ai_config.hpp index 05afda9d65..43d35d2a1c 100644 --- a/src/ai/ai_config.hpp +++ b/src/ai/ai_config.hpp @@ -61,10 +61,18 @@ public: */ const AIConfigItemList *GetConfigList(); + /* Where to get the config from, either default (depends on current game + * mode) or force either newgame or normal */ + enum AISettingSource { + AISS_DEFAULT, ///< Get the AI config from the current game mode + AISS_FORCE_NEWGAME, ///< Get the newgame AI config + AISS_FORCE_GAME, ///< Get the AI config from the current game + }; + /** * Get the config of a company. */ - static AIConfig *GetConfig(CompanyID company, bool forceNewgameSetting = false); + static AIConfig *GetConfig(CompanyID company, AISettingSource source = AISS_DEFAULT); /** * Get the value of a setting for this config. It might fallback to his diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp index 6a536f5d64..571a3ef0d5 100644 --- a/src/ai/ai_gui.cpp +++ b/src/ai/ai_gui.cpp @@ -1024,3 +1024,15 @@ void InitializeAIGui() { AIDebugWindow::ai_debug_company = INVALID_COMPANY; } + +/** Open the AI debug window if one of the AI scripts has crashed. */ +void ShowAIDebugWindowIfAIError() +{ + Company *c; + FOR_ALL_COMPANIES(c) { + if (c->is_ai && c->ai_instance->IsDead()) { + ShowAIDebugWindow(c->index); + break; + } + } +} diff --git a/src/ai/ai_gui.hpp b/src/ai/ai_gui.hpp index 254e2955cb..b6a3d2b2eb 100644 --- a/src/ai/ai_gui.hpp +++ b/src/ai/ai_gui.hpp @@ -17,7 +17,10 @@ #ifdef ENABLE_AI void ShowAIDebugWindow(CompanyID show_company = INVALID_COMPANY); void ShowAIConfigWindow(); +void ShowAIDebugWindowIfAIError(); +void InitializeAIGui(); #else +#include "../gui.h" #include "table/strings.h" static inline void ShowAIConfigWindow() @@ -25,6 +28,8 @@ static inline void ShowAIConfigWindow() ShowErrorMessage(STR_ERROR_NO_AI, STR_ERROR_NO_AI_SUB, 0, 0); } static inline void ShowAIDebugWindow(CompanyID show_company = INVALID_COMPANY) {ShowAIConfigWindow();} +static inline void ShowAIDebugWindowIfAIError() {} +static inline void InitializeAIGui() {} #endif /* ENABLE_AI */ #endif /* AI_GUI_HPP */ diff --git a/src/fileio.cpp b/src/fileio.cpp index 1ae3c7e5e6..b05e5a6486 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -563,7 +563,11 @@ bool TarListAddFile(const char *filename) if (it != _tar_list.end()) return false; FILE *f = fopen(filename, "rb"); - assert(f != NULL); + /* Although the file has been found there can be + * a number of reasons we cannot open the file. + * Most common case is when we simply have not + * been given read access. */ + if (f == NULL) return false; const char *dupped_filename = strdup(filename); _tar_list[filename].filename = dupped_filename; diff --git a/src/misc.cpp b/src/misc.cpp index 7ec606b5a4..2d8c6b06f2 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -14,6 +14,7 @@ #include "news_func.h" #include "variables.h" #include "ai/ai.hpp" +#include "ai/ai_gui.hpp" #include "newgrf_house.h" #include "group.h" #include "economy_func.h" @@ -41,7 +42,6 @@ void InitializeRailGui(); void InitializeRoadGui(); void InitializeAirportGui(); void InitializeDockGui(); -void InitializeAIGui(); void InitializeIndustries(); void InitializeTowns(); void InitializeSubsidies(); diff --git a/src/openttd.cpp b/src/openttd.cpp index 5a27ef46ce..f5a4f8ac8b 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -1086,6 +1086,99 @@ void SwitchToMode(SwitchMode new_mode) } +/** + * Check the validity of some of the caches. + * Especially in the sense of desyncs between + * the cached value and what the value would + * be when calculated from the 'base' data. + */ +static void CheckCaches() +{ + /* Return here so it is easy to add checks that are run + * always to aid testing of caches. */ + if (_debug_desync_level <= 1) return; + + /* Strict checking of the road stop cache entries */ + const RoadStop *rs; + FOR_ALL_ROADSTOPS(rs) { + if (IsStandardRoadStopTile(rs->xy)) continue; + + assert(rs->GetEntry(DIAGDIR_NE) != rs->GetEntry(DIAGDIR_NW)); + rs->GetEntry(DIAGDIR_NE)->CheckIntegrity(rs); + rs->GetEntry(DIAGDIR_NW)->CheckIntegrity(rs); + } + + Vehicle *v; + FOR_ALL_VEHICLES(v) { + if (v != v->First()) continue; + + switch (v->type) { + case VEH_ROAD: { + RoadVehicle *rv = RoadVehicle::From(v); + RoadVehicleCache cache = rv->rcache; + RoadVehUpdateCache(rv); + + if (memcmp(&cache, &rv->rcache, sizeof(RoadVehicleCache)) != 0) { + DEBUG(desync, 2, "cache mismatch: vehicle %i, company %i, unit number %i\n", v->index, (int)v->owner, v->unitnumber); + } + } break; + + case VEH_TRAIN: { + uint length = 0; + Train *t = Train::From(v); + for (Vehicle *u = t; u != NULL; u = u->Next()) length++; + + TrainCache *wagons = MallocT(length); + length = 0; + for (Train *u = t; u != NULL; u = u->Next()) wagons[length++] = u->tcache; + + t->ConsistChanged(true); + + length = 0; + for (Train *u = t; u != NULL; u = u->Next()) { + if (memcmp(&wagons[length], &u->tcache, sizeof(TrainCache)) != 0) { + DEBUG(desync, 2, "cache mismatch: vehicle %i, company %i, unit number %i, wagon %i\n", v->index, (int)v->owner, v->unitnumber, length); + } + length++; + } + + free(wagons); + } break; + + case VEH_AIRCRAFT: { + Aircraft *a = Aircraft::From(v); + AircraftCache cache = a->acache; + UpdateAircraftCache(a); + + if (memcmp(&cache, &a->acache, sizeof(AircraftCache)) != 0) { + DEBUG(desync, 2, "cache mismatch: vehicle %i, company %i, unit number %i\n", v->index, (int)v->owner, v->unitnumber); + } + } break; + + default: + break; + } + } + + /* Check whether the caches are still valid */ + FOR_ALL_VEHICLES(v) { + byte buff[sizeof(VehicleCargoList)]; + memcpy(buff, &v->cargo, sizeof(VehicleCargoList)); + v->cargo.InvalidateCache(); + assert(memcmp(&v->cargo, buff, sizeof(VehicleCargoList)) == 0); + } + + Station *st; + FOR_ALL_STATIONS(st) { + for (CargoID c = 0; c < NUM_CARGO; c++) { + byte buff[sizeof(StationCargoList)]; + memcpy(buff, &st->goods[c].cargo, sizeof(StationCargoList)); + st->goods[c].cargo.InvalidateCache(); + assert(memcmp(&st->goods[c].cargo, buff, sizeof(StationCargoList)) == 0); + } + } +} + /** * State controlling game loop. * The state must not be changed from anywhere but here. @@ -1111,88 +1204,7 @@ void StateGameLoop() CallWindowTickEvent(); NewsLoop(); } else { - /* Temporary strict checking of the road stop cache entries */ - const RoadStop *rs; - FOR_ALL_ROADSTOPS(rs) { - if (IsStandardRoadStopTile(rs->xy)) continue; - - assert(rs->GetEntry(DIAGDIR_NE) != rs->GetEntry(DIAGDIR_NW)); - rs->GetEntry(DIAGDIR_NE)->CheckIntegrity(rs); - rs->GetEntry(DIAGDIR_NW)->CheckIntegrity(rs); - } - - if (_debug_desync_level > 1) { - Vehicle *v; - FOR_ALL_VEHICLES(v) { - if (v != v->First()) continue; - - switch (v->type) { - case VEH_ROAD: { - RoadVehicle *rv = RoadVehicle::From(v); - RoadVehicleCache cache = rv->rcache; - RoadVehUpdateCache(rv); - - if (memcmp(&cache, &rv->rcache, sizeof(RoadVehicleCache)) != 0) { - DEBUG(desync, 2, "cache mismatch: vehicle %i, company %i, unit number %i\n", v->index, (int)v->owner, v->unitnumber); - } - } break; - - case VEH_TRAIN: { - uint length = 0; - Train *t = Train::From(v); - for (Vehicle *u = t; u != NULL; u = u->Next()) length++; - - TrainCache *wagons = MallocT(length); - length = 0; - for (Train *u = t; u != NULL; u = u->Next()) wagons[length++] = u->tcache; - - t->ConsistChanged(true); - - length = 0; - for (Train *u = t; u != NULL; u = u->Next()) { - if (memcmp(&wagons[length], &u->tcache, sizeof(TrainCache)) != 0) { - DEBUG(desync, 2, "cache mismatch: vehicle %i, company %i, unit number %i, wagon %i\n", v->index, (int)v->owner, v->unitnumber, length); - } - length++; - } - - free(wagons); - } break; - - case VEH_AIRCRAFT: { - Aircraft *a = Aircraft::From(v); - AircraftCache cache = a->acache; - UpdateAircraftCache(a); - - if (memcmp(&cache, &a->acache, sizeof(AircraftCache)) != 0) { - DEBUG(desync, 2, "cache mismatch: vehicle %i, company %i, unit number %i\n", v->index, (int)v->owner, v->unitnumber); - } - } break; - - default: - break; - } - } - } - - /* Check whether the caches are still valid */ - Vehicle *v; - FOR_ALL_VEHICLES(v) { - byte buff[sizeof(VehicleCargoList)]; - memcpy(buff, &v->cargo, sizeof(VehicleCargoList)); - v->cargo.InvalidateCache(); - assert(memcmp(&v->cargo, buff, sizeof(VehicleCargoList)) == 0); - } - - Station *st; - FOR_ALL_STATIONS(st) { - for (CargoID c = 0; c < NUM_CARGO; c++) { - byte buff[sizeof(StationCargoList)]; - memcpy(buff, &st->goods[c].cargo, sizeof(StationCargoList)); - st->goods[c].cargo.InvalidateCache(); - assert(memcmp(&st->goods[c].cargo, buff, sizeof(StationCargoList)) == 0); - } - } + CheckCaches(); /* All these actions has to be done from OWNER_NONE * for multiplayer compatibility */ diff --git a/src/pbs.cpp b/src/pbs.cpp index 173902a802..863f98b3b1 100644 --- a/src/pbs.cpp +++ b/src/pbs.cpp @@ -287,6 +287,11 @@ PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res) if (ftoti.best != NULL) *train_on_res = ftoti.best->First(); } } + if (*train_on_res == NULL && IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) { + /* The target tile is a bridge/tunnel, also check the other end tile. */ + FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum); + if (ftoti.best != NULL) *train_on_res = ftoti.best->First(); + } } return ftoti.res; } diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index dfb379c11b..d85b5d2328 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -41,6 +41,7 @@ #include "../company_func.h" #include "../road_cmd.h" #include "../ai/ai.hpp" +#include "../ai/ai_gui.hpp" #include "../town.h" #include "../economy_base.h" #include "../animated_tile_func.h" @@ -263,6 +264,7 @@ static void InitializeWindowsAndCaches() CheckTrainsLengths(); ShowNewGRFError(); + ShowAIDebugWindowIfAIError(); } typedef void (CDECL *SignalHandlerPointer)(int); diff --git a/src/saveload/ai_sl.cpp b/src/saveload/ai_sl.cpp index a9ae300203..6a8fb2b1a3 100644 --- a/src/saveload/ai_sl.cpp +++ b/src/saveload/ai_sl.cpp @@ -61,7 +61,7 @@ static void Load_AIPL() { /* Free all current data */ for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { - AIConfig::GetConfig(c)->ChangeAI(NULL); + AIConfig::GetConfig(c, AIConfig::AISS_FORCE_GAME)->ChangeAI(NULL); } CompanyID index; @@ -74,7 +74,7 @@ static void Load_AIPL() continue; } - AIConfig *config = AIConfig::GetConfig(index); + AIConfig *config = AIConfig::GetConfig(index, AIConfig::AISS_FORCE_GAME); if (StrEmpty(_ai_saveload_name)) { /* A random AI. */ config->ChangeAI(NULL, -1, false, true); diff --git a/src/settings.cpp b/src/settings.cpp index 81f6462de5..2e6c425013 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1162,7 +1162,7 @@ static void AILoadConfig(IniFile *ini, const char *grpname) /* Clean any configured AI */ for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { - AIConfig::GetConfig(c, true)->ChangeAI(NULL); + AIConfig::GetConfig(c, AIConfig::AISS_FORCE_NEWGAME)->ChangeAI(NULL); } /* If no group exists, return */ @@ -1170,7 +1170,7 @@ static void AILoadConfig(IniFile *ini, const char *grpname) CompanyID c = COMPANY_FIRST; for (item = group->item; c < MAX_COMPANIES && item != NULL; c++, item = item->next) { - AIConfig *config = AIConfig::GetConfig(c, true); + AIConfig *config = AIConfig::GetConfig(c, AIConfig::AISS_FORCE_NEWGAME); config->ChangeAI(item->name); if (!config->HasAI()) { @@ -1274,7 +1274,7 @@ static void AISaveConfig(IniFile *ini, const char *grpname) group->Clear(); for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) { - AIConfig *config = AIConfig::GetConfig(c, true); + AIConfig *config = AIConfig::GetConfig(c, AIConfig::AISS_FORCE_NEWGAME); const char *name; char value[1024]; config->SettingsToString(value, lengthof(value));