mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-06 22:28:56 +00:00
(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)
This commit is contained in:
parent
c3daa9a9fe
commit
821fe5c3ba
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
176
src/openttd.cpp
176
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<TrainCache>(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<TrainCache>(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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user