mirror of https://github.com/OpenTTD/OpenTTD
(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)release/1.0
parent
c3daa9a9fe
commit
821fe5c3ba
|
@ -93,13 +93,13 @@ const AIConfigItemList *AIConfig::GetConfigList()
|
||||||
return this->config_list;
|
return this->config_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
AIConfig *AIConfig::GetConfig(CompanyID company, bool forceNewgameSetting)
|
AIConfig *AIConfig::GetConfig(CompanyID company, AISettingSource source)
|
||||||
{
|
{
|
||||||
AIConfig **config;
|
AIConfig **config;
|
||||||
if (!forceNewgameSetting) {
|
if (source == AISS_FORCE_NEWGAME || (source == AISS_DEFAULT && _game_mode == GM_MENU)) {
|
||||||
config = (_game_mode == GM_MENU) ? &_settings_newgame.ai_config[company] : &_settings_game.ai_config[company];
|
|
||||||
} else {
|
|
||||||
config = &_settings_newgame.ai_config[company];
|
config = &_settings_newgame.ai_config[company];
|
||||||
|
} else {
|
||||||
|
config = &_settings_game.ai_config[company];
|
||||||
}
|
}
|
||||||
if (*config == NULL) *config = new AIConfig();
|
if (*config == NULL) *config = new AIConfig();
|
||||||
return *config;
|
return *config;
|
||||||
|
|
|
@ -61,10 +61,18 @@ public:
|
||||||
*/
|
*/
|
||||||
const AIConfigItemList *GetConfigList();
|
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.
|
* 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
|
* 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;
|
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
|
#ifdef ENABLE_AI
|
||||||
void ShowAIDebugWindow(CompanyID show_company = INVALID_COMPANY);
|
void ShowAIDebugWindow(CompanyID show_company = INVALID_COMPANY);
|
||||||
void ShowAIConfigWindow();
|
void ShowAIConfigWindow();
|
||||||
|
void ShowAIDebugWindowIfAIError();
|
||||||
|
void InitializeAIGui();
|
||||||
#else
|
#else
|
||||||
|
#include "../gui.h"
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
static inline void ShowAIConfigWindow()
|
static inline void ShowAIConfigWindow()
|
||||||
|
@ -25,6 +28,8 @@ static inline void ShowAIConfigWindow()
|
||||||
ShowErrorMessage(STR_ERROR_NO_AI, STR_ERROR_NO_AI_SUB, 0, 0);
|
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 ShowAIDebugWindow(CompanyID show_company = INVALID_COMPANY) {ShowAIConfigWindow();}
|
||||||
|
static inline void ShowAIDebugWindowIfAIError() {}
|
||||||
|
static inline void InitializeAIGui() {}
|
||||||
#endif /* ENABLE_AI */
|
#endif /* ENABLE_AI */
|
||||||
|
|
||||||
#endif /* AI_GUI_HPP */
|
#endif /* AI_GUI_HPP */
|
||||||
|
|
|
@ -563,7 +563,11 @@ bool TarListAddFile(const char *filename)
|
||||||
if (it != _tar_list.end()) return false;
|
if (it != _tar_list.end()) return false;
|
||||||
|
|
||||||
FILE *f = fopen(filename, "rb");
|
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);
|
const char *dupped_filename = strdup(filename);
|
||||||
_tar_list[filename].filename = dupped_filename;
|
_tar_list[filename].filename = dupped_filename;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "news_func.h"
|
#include "news_func.h"
|
||||||
#include "variables.h"
|
#include "variables.h"
|
||||||
#include "ai/ai.hpp"
|
#include "ai/ai.hpp"
|
||||||
|
#include "ai/ai_gui.hpp"
|
||||||
#include "newgrf_house.h"
|
#include "newgrf_house.h"
|
||||||
#include "group.h"
|
#include "group.h"
|
||||||
#include "economy_func.h"
|
#include "economy_func.h"
|
||||||
|
@ -41,7 +42,6 @@ void InitializeRailGui();
|
||||||
void InitializeRoadGui();
|
void InitializeRoadGui();
|
||||||
void InitializeAirportGui();
|
void InitializeAirportGui();
|
||||||
void InitializeDockGui();
|
void InitializeDockGui();
|
||||||
void InitializeAIGui();
|
|
||||||
void InitializeIndustries();
|
void InitializeIndustries();
|
||||||
void InitializeTowns();
|
void InitializeTowns();
|
||||||
void InitializeSubsidies();
|
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.
|
* State controlling game loop.
|
||||||
* The state must not be changed from anywhere but here.
|
* The state must not be changed from anywhere but here.
|
||||||
|
@ -1111,88 +1204,7 @@ void StateGameLoop()
|
||||||
CallWindowTickEvent();
|
CallWindowTickEvent();
|
||||||
NewsLoop();
|
NewsLoop();
|
||||||
} else {
|
} else {
|
||||||
/* Temporary strict checking of the road stop cache entries */
|
CheckCaches();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* All these actions has to be done from OWNER_NONE
|
/* All these actions has to be done from OWNER_NONE
|
||||||
* for multiplayer compatibility */
|
* 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 (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;
|
return ftoti.res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "../company_func.h"
|
#include "../company_func.h"
|
||||||
#include "../road_cmd.h"
|
#include "../road_cmd.h"
|
||||||
#include "../ai/ai.hpp"
|
#include "../ai/ai.hpp"
|
||||||
|
#include "../ai/ai_gui.hpp"
|
||||||
#include "../town.h"
|
#include "../town.h"
|
||||||
#include "../economy_base.h"
|
#include "../economy_base.h"
|
||||||
#include "../animated_tile_func.h"
|
#include "../animated_tile_func.h"
|
||||||
|
@ -263,6 +264,7 @@ static void InitializeWindowsAndCaches()
|
||||||
|
|
||||||
CheckTrainsLengths();
|
CheckTrainsLengths();
|
||||||
ShowNewGRFError();
|
ShowNewGRFError();
|
||||||
|
ShowAIDebugWindowIfAIError();
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef void (CDECL *SignalHandlerPointer)(int);
|
typedef void (CDECL *SignalHandlerPointer)(int);
|
||||||
|
|
|
@ -61,7 +61,7 @@ static void Load_AIPL()
|
||||||
{
|
{
|
||||||
/* Free all current data */
|
/* Free all current data */
|
||||||
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
|
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;
|
CompanyID index;
|
||||||
|
@ -74,7 +74,7 @@ static void Load_AIPL()
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
AIConfig *config = AIConfig::GetConfig(index);
|
AIConfig *config = AIConfig::GetConfig(index, AIConfig::AISS_FORCE_GAME);
|
||||||
if (StrEmpty(_ai_saveload_name)) {
|
if (StrEmpty(_ai_saveload_name)) {
|
||||||
/* A random AI. */
|
/* A random AI. */
|
||||||
config->ChangeAI(NULL, -1, false, true);
|
config->ChangeAI(NULL, -1, false, true);
|
||||||
|
|
|
@ -1162,7 +1162,7 @@ static void AILoadConfig(IniFile *ini, const char *grpname)
|
||||||
|
|
||||||
/* Clean any configured AI */
|
/* Clean any configured AI */
|
||||||
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
|
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 */
|
/* If no group exists, return */
|
||||||
|
@ -1170,7 +1170,7 @@ static void AILoadConfig(IniFile *ini, const char *grpname)
|
||||||
|
|
||||||
CompanyID c = COMPANY_FIRST;
|
CompanyID c = COMPANY_FIRST;
|
||||||
for (item = group->item; c < MAX_COMPANIES && item != NULL; c++, item = item->next) {
|
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);
|
config->ChangeAI(item->name);
|
||||||
if (!config->HasAI()) {
|
if (!config->HasAI()) {
|
||||||
|
@ -1274,7 +1274,7 @@ static void AISaveConfig(IniFile *ini, const char *grpname)
|
||||||
group->Clear();
|
group->Clear();
|
||||||
|
|
||||||
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
|
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;
|
const char *name;
|
||||||
char value[1024];
|
char value[1024];
|
||||||
config->SettingsToString(value, lengthof(value));
|
config->SettingsToString(value, lengthof(value));
|
||||||
|
|
Loading…
Reference in New Issue