summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortruebrain <truebrain@openttd.org>2009-01-13 01:46:46 +0000
committertruebrain <truebrain@openttd.org>2009-01-13 01:46:46 +0000
commitbcbbf2c366b829994983513d2858762874e99964 (patch)
treea2e699a90fbe7d2ebd18ddd9ea713546f3f641bc
parente6883c5cc7dedad23dfcf7a303a7154520db7f5e (diff)
downloadopenttd-bcbbf2c366b829994983513d2858762874e99964.tar.xz
(svn r15045) -Add [NoAI API CHANGE]: in info.nut you can now have (optional) a CanLoadFromVersion(version), which should return true/false, to indicate if you can load a savegame made with your AI of version 'version'
-Add [NoAI API CHANGE]: in main.nut the Load() function now should be Load(version, data), where 'version' is the version of your AI which made the savegame -Codechange [NoAI]: various of function renames to make things more sane -Add [NoAI]: push the 'version' of the AI through various of layers -Codechange [NoAI]: various of code cleanups -Add [NoAI]: store the version of the AI in the savegame too
-rw-r--r--src/ai/ai.hpp4
-rw-r--r--src/ai/ai_config.cpp6
-rw-r--r--src/ai/ai_config.hpp4
-rw-r--r--src/ai/ai_core.cpp8
-rw-r--r--src/ai/ai_info.cpp21
-rw-r--r--src/ai/ai_info.hpp2
-rw-r--r--src/ai/ai_instance.cpp41
-rw-r--r--src/ai/ai_instance.hpp5
-rw-r--r--src/ai/ai_scanner.cpp25
-rw-r--r--src/ai/ai_scanner.hpp2
-rw-r--r--src/saveload/ai_sl.cpp36
-rw-r--r--src/saveload/saveload.cpp2
-rw-r--r--src/script/squirrel.hpp1
13 files changed, 84 insertions, 73 deletions
diff --git a/src/ai/ai.hpp b/src/ai/ai.hpp
index bd1c2a907..0bf0a1991 100644
--- a/src/ai/ai.hpp
+++ b/src/ai/ai.hpp
@@ -86,11 +86,11 @@ public:
/**
* Load data for an AI from a savegame.
*/
- static void Load(CompanyID company);
+ static void Load(CompanyID company, int version);
static char *GetConsoleList(char *p, const char *last);
static const AIInfoList *GetInfoList();
- static AIInfo *GetCompanyInfo(const char *name);
+ static AIInfo *FindInfo(const char *name, int version);
static bool ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm);
static void Rescan();
diff --git a/src/ai/ai_config.cpp b/src/ai/ai_config.cpp
index b93bf76b4..186d6d6e3 100644
--- a/src/ai/ai_config.cpp
+++ b/src/ai/ai_config.cpp
@@ -9,11 +9,11 @@
#include "ai_config.hpp"
#include "ai_info.hpp"
-void AIConfig::ChangeAI(const char *name)
+void AIConfig::ChangeAI(const char *name, int version)
{
free((void *)this->name);
this->name = (name == NULL) ? NULL : strdup(name);
- this->info = (name == NULL) ? NULL : AI::GetCompanyInfo(this->name);
+ this->info = (name == NULL) ? NULL : AI::FindInfo(this->name, version);
this->version = (info == NULL) ? -1 : info->GetVersion();
for (SettingValueList::iterator it = this->settings.begin(); it != this->settings.end(); it++) {
@@ -45,7 +45,7 @@ AIInfo *AIConfig::GetInfo()
bool AIConfig::ResetInfo()
{
- this->info = AI::GetCompanyInfo(this->name);
+ this->info = AI::FindInfo(this->name, this->version);
return this->info != NULL;
}
diff --git a/src/ai/ai_config.hpp b/src/ai/ai_config.hpp
index e6790e22a..90c52b563 100644
--- a/src/ai/ai_config.hpp
+++ b/src/ai/ai_config.hpp
@@ -26,8 +26,10 @@ public:
/**
* Set another AI to be loaded in this slot.
+ * @param name The name of the AI.
+ * @param version The version of the AI to load, or -1 of latest.
*/
- void ChangeAI(const char *name);
+ void ChangeAI(const char *name, int version = -1);
/**
* When ever the AI Scanner is reloaded, all infos become invalid. This
diff --git a/src/ai/ai_core.cpp b/src/ai/ai_core.cpp
index f0a82f771..3d8fc7707 100644
--- a/src/ai/ai_core.cpp
+++ b/src/ai/ai_core.cpp
@@ -211,7 +211,7 @@ void CcAI(bool success, TileIndex tile, uint32 p1, uint32 p2)
}
}
-/* static */ void AI::Load(CompanyID company)
+/* static */ void AI::Load(CompanyID company, int version)
{
if (!_networking || _network_server) {
assert(IsValidCompanyID(company));
@@ -219,7 +219,7 @@ void CcAI(bool success, TileIndex tile, uint32 p1, uint32 p2)
CompanyID old_company = _current_company;
_current_company = company;
- GetCompany(company)->ai_instance->Load();
+ GetCompany(company)->ai_instance->Load(version);
_current_company = old_company;
} else {
/* Read, but ignore, the load data */
@@ -237,9 +237,9 @@ void CcAI(bool success, TileIndex tile, uint32 p1, uint32 p2)
return AI::ai_scanner->GetAIInfoList();
}
-/* static */ AIInfo *AI::GetCompanyInfo(const char *name)
+/* static */ AIInfo *AI::FindInfo(const char *name, int version)
{
- return AI::ai_scanner->FindAI(name);
+ return AI::ai_scanner->FindInfo(name, version);
}
/* static */ bool AI::ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm)
diff --git a/src/ai/ai_info.cpp b/src/ai/ai_info.cpp
index 80f6f9e8d..e55affaa5 100644
--- a/src/ai/ai_info.cpp
+++ b/src/ai/ai_info.cpp
@@ -70,9 +70,26 @@ const char *AIFileInfo::GetInstanceName()
return this->instance_name;
}
-bool AIFileInfo::AllowStartup()
+bool AIFileInfo::CanLoadFromVersion(int version)
{
- return true;
+ if (version == -1) return true;
+ if (!this->engine->MethodExists(*this->SQ_instance, "CanLoadFromVersion")) return true;
+
+ HSQUIRRELVM vm = this->engine->GetVM();
+ int top = sq_gettop(vm);
+
+ sq_pushobject(vm, *this->SQ_instance);
+ sq_pushstring(vm, OTTD2FS("CanLoadFromVersion"), -1);
+ sq_get(vm, -2);
+ sq_pushobject(vm, *this->SQ_instance);
+ sq_pushinteger(vm, version);
+ sq_call(vm, 2, SQTrue, SQFalse);
+
+ HSQOBJECT ret;
+ sq_getstackobj(vm, -1, &ret);
+
+ sq_settop(vm, top);
+ return sq_objtobool(&ret);
}
const char *AIFileInfo::GetDirName()
diff --git a/src/ai/ai_info.hpp b/src/ai/ai_info.hpp
index d50b89584..205e89b38 100644
--- a/src/ai/ai_info.hpp
+++ b/src/ai/ai_info.hpp
@@ -74,7 +74,7 @@ public:
/**
* Check if we can start this AI.
*/
- bool AllowStartup();
+ bool CanLoadFromVersion(int version);
/**
* Get the name of the dir this AI is in.
diff --git a/src/ai/ai_instance.cpp b/src/ai/ai_instance.cpp
index a0612498d..1e57c6496 100644
--- a/src/ai/ai_instance.cpp
+++ b/src/ai/ai_instance.cpp
@@ -592,37 +592,38 @@ void AIInstance::Save()
LoadObjects(NULL);
}
-bool AIInstance::Load()
+void AIInstance::Load(int version)
{
- HSQUIRRELVM vm = (this->engine == NULL) ? NULL : this->engine->GetVM();
+ if (this->engine == NULL || version == -1) {
+ LoadEmpty();
+ return;
+ }
+ HSQUIRRELVM vm = this->engine->GetVM();
SlObject(NULL, _ai_byte);
/* Check if there was anything saved at all. */
- if (_ai_sl_byte == 0) return true;
+ if (_ai_sl_byte == 0) return;
AIObject::SetAllowDoCommand(false);
- if (vm != NULL) {
- /* Go to the instance-root */
- sq_pushobject(vm, *this->instance);
- /* Find the function-name inside the script */
- sq_pushstring(vm, OTTD2FS("Load"), -1);
- if (SQ_FAILED(sq_get(vm, -2))) sq_pushnull(vm);
- sq_pushobject(vm, *this->instance);
- }
+ /* Go to the instance-root */
+ sq_pushobject(vm, *this->instance);
+ /* Find the function-name inside the script */
+ sq_pushstring(vm, OTTD2FS("Load"), -1);
+ if (SQ_FAILED(sq_get(vm, -2))) sq_pushnull(vm);
+ sq_pushobject(vm, *this->instance);
+ sq_pushinteger(vm, version);
LoadObjects(vm);
- if (this->engine != NULL) {
- if (this->engine->MethodExists(*this->instance, "Load")) {
- sq_call(vm, 2, SQFalse, SQFalse);
- } else {
- AILog::Warning("Loading failed: there was data for the AI to load, but the AI does not have a Load() function.");
- }
+ if (this->engine->MethodExists(*this->instance, "Load")) {
+ sq_call(vm, 3, SQFalse, SQFalse);
+ } else {
+ AILog::Warning("Loading failed: there was data for the AI to load, but the AI does not have a Load() function.");
}
- /* Pop 1) the object instance, 2) the function name, 3) the instance again, 4) the table. */
- if (vm != NULL) sq_pop(vm, 4);
+ /* Pop 1) the object instance, 2) the function name, 3) the instance again, 4) the (null) result. */
+ sq_pop(vm, 4);
AIObject::SetAllowDoCommand(true);
- return true;
+ return;
}
diff --git a/src/ai/ai_instance.hpp b/src/ai/ai_instance.hpp
index d953c3915..5bd3b58b5 100644
--- a/src/ai/ai_instance.hpp
+++ b/src/ai/ai_instance.hpp
@@ -87,9 +87,10 @@ public:
/**
* Load data from a savegame and call the AI Load function if it
* exists.
- * @return True if the loading was successfull.
+ * @param version The version of the AI when saving, or -1 if this was
+ * not the original AI saving the game.
*/
- bool Load();
+ void Load(int version);
/**
* Load and discard data from a savegame.
diff --git a/src/ai/ai_scanner.cpp b/src/ai/ai_scanner.cpp
index 68d53660d..6bcf883e7 100644
--- a/src/ai/ai_scanner.cpp
+++ b/src/ai/ai_scanner.cpp
@@ -344,26 +344,10 @@ AIInfo *AIScanner::SelectRandomAI()
AIInfoList::iterator it = this->info_list.begin();
for (; pos > 0; pos--) it++;
AIInfoList::iterator first_it = it;
- AIInfo *i = (*it).second;
-
- if (!i->AllowStartup()) {
- /* We can't start this AI, try to find the next best */
- do {
- it++;
- if (it == this->info_list.end()) it = this->info_list.begin();
- /* Back at the beginning? We can't start an AI. */
- if (first_it == it) {
- DEBUG(ai, 0, "No suitable AI found, loading 'dummy' AI.");
- return this->info_dummy;
- }
-
- i = (*it).second;
- } while (!i->AllowStartup());
- }
- return i;
+ return (*it).second;
}
-AIInfo *AIScanner::FindAI(const char *name)
+AIInfo *AIScanner::FindInfo(const char *name, int version)
{
if (this->info_list.size() == 0) return NULL;
if (name == NULL) return NULL;
@@ -372,7 +356,7 @@ AIInfo *AIScanner::FindAI(const char *name)
for (; it != this->info_list.end(); it++) {
AIInfo *i = (*it).second;
- if (strcasecmp(name, (*it).first) == 0 && i->AllowStartup()) {
+ if (strcasecmp(name, (*it).first) == 0 && i->CanLoadFromVersion(version)) {
return i;
}
}
@@ -386,8 +370,7 @@ char *AIScanner::GetAIConsoleList(char *p, const char *last)
AIInfoList::iterator it = this->info_list.begin();
for (; it != this->info_list.end(); it++) {
AIInfo *i = (*it).second;
- if (!i->AllowStartup()) continue;
- p += seprintf(p, last, "%10s: %s\n", (*it).first, i->GetDescription());
+ p += seprintf(p, last, "%10s (v%d): %s\n", (*it).first, i->GetVersion(), i->GetDescription());
}
p += seprintf(p, last, "\n");
diff --git a/src/ai/ai_scanner.hpp b/src/ai/ai_scanner.hpp
index 2801f556a..672e5102e 100644
--- a/src/ai/ai_scanner.hpp
+++ b/src/ai/ai_scanner.hpp
@@ -42,7 +42,7 @@ public:
/**
* Find an AI by name.
*/
- class AIInfo *FindAI(const char *name);
+ class AIInfo *FindInfo(const char *name, int version);
/**
* Get the list of available AIs for the console.
diff --git a/src/saveload/ai_sl.cpp b/src/saveload/ai_sl.cpp
index 5e444ea9f..4c3e169dd 100644
--- a/src/saveload/ai_sl.cpp
+++ b/src/saveload/ai_sl.cpp
@@ -13,12 +13,14 @@
#include "../ai/ai.hpp"
#include "../ai/ai_config.hpp"
-static char _ai_saveload_ainame[64];
-static char _ai_company_convert_array[1024];
+static char _ai_saveload_name[64];
+static int _ai_saveload_version;
+static char _ai_saveload_settings[1024];
static const SaveLoad _ai_company[] = {
- SLEG_STR(_ai_saveload_ainame, SLE_STRB),
- SLEG_STR(_ai_company_convert_array, SLE_STRB),
+ SLEG_STR(_ai_saveload_name, SLE_STRB),
+ SLEG_STR(_ai_saveload_settings, SLE_STRB),
+ SLEG_CONDVAR(_ai_saveload_version, SLE_UINT32, 108, SL_MAX_VERSION),
SLE_END()
};
@@ -27,10 +29,11 @@ static void SaveReal_AIPL(int *index_ptr)
CompanyID index = (CompanyID)*index_ptr;
AIConfig *config = AIConfig::GetConfig(index);
- ttd_strlcpy(_ai_saveload_ainame, config->GetName(), lengthof(_ai_saveload_ainame));
+ ttd_strlcpy(_ai_saveload_name, config->GetName(), lengthof(_ai_saveload_name));
+ _ai_saveload_version = config->GetVersion();
- _ai_company_convert_array[0] = '\0';
- config->SettingsToString(_ai_company_convert_array, lengthof(_ai_company_convert_array));
+ _ai_saveload_settings[0] = '\0';
+ config->SettingsToString(_ai_saveload_settings, lengthof(_ai_saveload_settings));
SlObject(NULL, _ai_company);
/* If the AI was active, store his data too */
@@ -47,27 +50,30 @@ static void Load_AIPL()
CompanyID index;
while ((index = (CompanyID)SlIterateArray()) != (CompanyID)-1) {
AIConfig *config = AIConfig::GetConfig(index);
+
+ _ai_saveload_version = -1;
SlObject(NULL, _ai_company);
- if (_ai_saveload_ainame[0] == '\0' || AI::GetCompanyInfo(_ai_saveload_ainame) == NULL) {
- if (strcmp(_ai_saveload_ainame, "%_dummy") != 0) {
- DEBUG(ai, 0, "The savegame has an AI by the name '%s' which is no longer available.", _ai_saveload_ainame);
+ config->ChangeAI(_ai_saveload_name, _ai_saveload_version);
+ if (!config->HasAI()) {
+ if (strcmp(_ai_saveload_name, "%_dummy") != 0) {
+ DEBUG(ai, 0, "The savegame has an AI by the name '%s', version %d which is no longer available.", _ai_saveload_name, _ai_saveload_version);
DEBUG(ai, 0, "A random other AI will be loaded in its place.");
} else {
DEBUG(ai, 0, "The savegame had no AIs available at the time of saving.");
DEBUG(ai, 0, "A random available AI will be loaded now.");
}
- config->ChangeAI(NULL);
- } else {
- config->ChangeAI(_ai_saveload_ainame);
+ /* Make sure the AI doesn't get the saveload data, as he was not the
+ * writer of the saveload data in the first place */
+ _ai_saveload_version = -1;
}
- config->StringToSettings(_ai_company_convert_array);
+ config->StringToSettings(_ai_saveload_settings);
/* Start the AI directly if it was active in the savegame */
if (IsValidCompanyID(index) && !IsHumanCompany(index)) {
AI::StartNew(index);
- AI::Load(index);
+ AI::Load(index, _ai_saveload_version);
}
}
}
diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp
index 6e41314f3..47934e928 100644
--- a/src/saveload/saveload.cpp
+++ b/src/saveload/saveload.cpp
@@ -42,7 +42,7 @@
#include <list>
-extern const uint16 SAVEGAME_VERSION = 107;
+extern const uint16 SAVEGAME_VERSION = 108;
SavegameType _savegame_type; ///< type of savegame we are loading
diff --git a/src/script/squirrel.hpp b/src/script/squirrel.hpp
index bd9a10cfc..39357bade 100644
--- a/src/script/squirrel.hpp
+++ b/src/script/squirrel.hpp
@@ -48,6 +48,7 @@ public:
friend class AIController;
friend class AIScanner;
friend class AIInstance;
+ friend class AIFileInfo;
Squirrel();
~Squirrel();