1
0
Fork 0

(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
release/0.7
truebrain 2009-01-13 01:46:46 +00:00
parent e6883c5cc7
commit bcbbf2c366
13 changed files with 84 additions and 73 deletions

View File

@ -86,11 +86,11 @@ public:
/** /**
* Load data for an AI from a savegame. * 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 char *GetConsoleList(char *p, const char *last);
static const AIInfoList *GetInfoList(); 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 bool ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm);
static void Rescan(); static void Rescan();

View File

@ -9,11 +9,11 @@
#include "ai_config.hpp" #include "ai_config.hpp"
#include "ai_info.hpp" #include "ai_info.hpp"
void AIConfig::ChangeAI(const char *name) void AIConfig::ChangeAI(const char *name, int version)
{ {
free((void *)this->name); free((void *)this->name);
this->name = (name == NULL) ? NULL : strdup(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(); this->version = (info == NULL) ? -1 : info->GetVersion();
for (SettingValueList::iterator it = this->settings.begin(); it != this->settings.end(); it++) { for (SettingValueList::iterator it = this->settings.begin(); it != this->settings.end(); it++) {
@ -45,7 +45,7 @@ AIInfo *AIConfig::GetInfo()
bool AIConfig::ResetInfo() bool AIConfig::ResetInfo()
{ {
this->info = AI::GetCompanyInfo(this->name); this->info = AI::FindInfo(this->name, this->version);
return this->info != NULL; return this->info != NULL;
} }

View File

@ -26,8 +26,10 @@ public:
/** /**
* Set another AI to be loaded in this slot. * 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 * When ever the AI Scanner is reloaded, all infos become invalid. This

View File

@ -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) { if (!_networking || _network_server) {
assert(IsValidCompanyID(company)); assert(IsValidCompanyID(company));
@ -219,7 +219,7 @@ void CcAI(bool success, TileIndex tile, uint32 p1, uint32 p2)
CompanyID old_company = _current_company; CompanyID old_company = _current_company;
_current_company = company; _current_company = company;
GetCompany(company)->ai_instance->Load(); GetCompany(company)->ai_instance->Load(version);
_current_company = old_company; _current_company = old_company;
} else { } else {
/* Read, but ignore, the load data */ /* 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(); 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) /* static */ bool AI::ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm)

View File

@ -70,9 +70,26 @@ const char *AIFileInfo::GetInstanceName()
return this->instance_name; 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() const char *AIFileInfo::GetDirName()

View File

@ -74,7 +74,7 @@ public:
/** /**
* Check if we can start this AI. * Check if we can start this AI.
*/ */
bool AllowStartup(); bool CanLoadFromVersion(int version);
/** /**
* Get the name of the dir this AI is in. * Get the name of the dir this AI is in.

View File

@ -592,37 +592,38 @@ void AIInstance::Save()
LoadObjects(NULL); 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); SlObject(NULL, _ai_byte);
/* Check if there was anything saved at all. */ /* Check if there was anything saved at all. */
if (_ai_sl_byte == 0) return true; if (_ai_sl_byte == 0) return;
AIObject::SetAllowDoCommand(false); AIObject::SetAllowDoCommand(false);
if (vm != NULL) { /* Go to the instance-root */
/* Go to the instance-root */ sq_pushobject(vm, *this->instance);
sq_pushobject(vm, *this->instance); /* Find the function-name inside the script */
/* Find the function-name inside the script */ sq_pushstring(vm, OTTD2FS("Load"), -1);
sq_pushstring(vm, OTTD2FS("Load"), -1); if (SQ_FAILED(sq_get(vm, -2))) sq_pushnull(vm);
if (SQ_FAILED(sq_get(vm, -2))) sq_pushnull(vm); sq_pushobject(vm, *this->instance);
sq_pushobject(vm, *this->instance); sq_pushinteger(vm, version);
}
LoadObjects(vm); LoadObjects(vm);
if (this->engine != NULL) { if (this->engine->MethodExists(*this->instance, "Load")) {
if (this->engine->MethodExists(*this->instance, "Load")) { sq_call(vm, 3, SQFalse, SQFalse);
sq_call(vm, 2, SQFalse, SQFalse); } else {
} else { AILog::Warning("Loading failed: there was data for the AI to load, but the AI does not have a Load() function.");
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. */ /* Pop 1) the object instance, 2) the function name, 3) the instance again, 4) the (null) result. */
if (vm != NULL) sq_pop(vm, 4); sq_pop(vm, 4);
AIObject::SetAllowDoCommand(true); AIObject::SetAllowDoCommand(true);
return true; return;
} }

View File

@ -87,9 +87,10 @@ public:
/** /**
* Load data from a savegame and call the AI Load function if it * Load data from a savegame and call the AI Load function if it
* exists. * 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. * Load and discard data from a savegame.

View File

@ -344,26 +344,10 @@ AIInfo *AIScanner::SelectRandomAI()
AIInfoList::iterator it = this->info_list.begin(); AIInfoList::iterator it = this->info_list.begin();
for (; pos > 0; pos--) it++; for (; pos > 0; pos--) it++;
AIInfoList::iterator first_it = it; AIInfoList::iterator first_it = it;
AIInfo *i = (*it).second; return (*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;
} }
AIInfo *AIScanner::FindAI(const char *name) AIInfo *AIScanner::FindInfo(const char *name, int version)
{ {
if (this->info_list.size() == 0) return NULL; if (this->info_list.size() == 0) return NULL;
if (name == NULL) return NULL; if (name == NULL) return NULL;
@ -372,7 +356,7 @@ AIInfo *AIScanner::FindAI(const char *name)
for (; it != this->info_list.end(); it++) { for (; it != this->info_list.end(); it++) {
AIInfo *i = (*it).second; AIInfo *i = (*it).second;
if (strcasecmp(name, (*it).first) == 0 && i->AllowStartup()) { if (strcasecmp(name, (*it).first) == 0 && i->CanLoadFromVersion(version)) {
return i; return i;
} }
} }
@ -386,8 +370,7 @@ char *AIScanner::GetAIConsoleList(char *p, const char *last)
AIInfoList::iterator it = this->info_list.begin(); AIInfoList::iterator it = this->info_list.begin();
for (; it != this->info_list.end(); it++) { for (; it != this->info_list.end(); it++) {
AIInfo *i = (*it).second; AIInfo *i = (*it).second;
if (!i->AllowStartup()) continue; p += seprintf(p, last, "%10s (v%d): %s\n", (*it).first, i->GetVersion(), i->GetDescription());
p += seprintf(p, last, "%10s: %s\n", (*it).first, i->GetDescription());
} }
p += seprintf(p, last, "\n"); p += seprintf(p, last, "\n");

View File

@ -42,7 +42,7 @@ public:
/** /**
* Find an AI by name. * 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. * Get the list of available AIs for the console.

View File

@ -13,12 +13,14 @@
#include "../ai/ai.hpp" #include "../ai/ai.hpp"
#include "../ai/ai_config.hpp" #include "../ai/ai_config.hpp"
static char _ai_saveload_ainame[64]; static char _ai_saveload_name[64];
static char _ai_company_convert_array[1024]; static int _ai_saveload_version;
static char _ai_saveload_settings[1024];
static const SaveLoad _ai_company[] = { static const SaveLoad _ai_company[] = {
SLEG_STR(_ai_saveload_ainame, SLE_STRB), SLEG_STR(_ai_saveload_name, SLE_STRB),
SLEG_STR(_ai_company_convert_array, SLE_STRB), SLEG_STR(_ai_saveload_settings, SLE_STRB),
SLEG_CONDVAR(_ai_saveload_version, SLE_UINT32, 108, SL_MAX_VERSION),
SLE_END() SLE_END()
}; };
@ -27,10 +29,11 @@ static void SaveReal_AIPL(int *index_ptr)
CompanyID index = (CompanyID)*index_ptr; CompanyID index = (CompanyID)*index_ptr;
AIConfig *config = AIConfig::GetConfig(index); 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'; _ai_saveload_settings[0] = '\0';
config->SettingsToString(_ai_company_convert_array, lengthof(_ai_company_convert_array)); config->SettingsToString(_ai_saveload_settings, lengthof(_ai_saveload_settings));
SlObject(NULL, _ai_company); SlObject(NULL, _ai_company);
/* If the AI was active, store his data too */ /* If the AI was active, store his data too */
@ -47,27 +50,30 @@ static void Load_AIPL()
CompanyID index; CompanyID index;
while ((index = (CompanyID)SlIterateArray()) != (CompanyID)-1) { while ((index = (CompanyID)SlIterateArray()) != (CompanyID)-1) {
AIConfig *config = AIConfig::GetConfig(index); AIConfig *config = AIConfig::GetConfig(index);
_ai_saveload_version = -1;
SlObject(NULL, _ai_company); SlObject(NULL, _ai_company);
if (_ai_saveload_ainame[0] == '\0' || AI::GetCompanyInfo(_ai_saveload_ainame) == NULL) { config->ChangeAI(_ai_saveload_name, _ai_saveload_version);
if (strcmp(_ai_saveload_ainame, "%_dummy") != 0) { if (!config->HasAI()) {
DEBUG(ai, 0, "The savegame has an AI by the name '%s' which is no longer available.", _ai_saveload_ainame); 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."); DEBUG(ai, 0, "A random other AI will be loaded in its place.");
} else { } else {
DEBUG(ai, 0, "The savegame had no AIs available at the time of saving."); 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."); DEBUG(ai, 0, "A random available AI will be loaded now.");
} }
config->ChangeAI(NULL); /* Make sure the AI doesn't get the saveload data, as he was not the
} else { * writer of the saveload data in the first place */
config->ChangeAI(_ai_saveload_ainame); _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 */ /* Start the AI directly if it was active in the savegame */
if (IsValidCompanyID(index) && !IsHumanCompany(index)) { if (IsValidCompanyID(index) && !IsHumanCompany(index)) {
AI::StartNew(index); AI::StartNew(index);
AI::Load(index); AI::Load(index, _ai_saveload_version);
} }
} }
} }

View File

@ -42,7 +42,7 @@
#include <list> #include <list>
extern const uint16 SAVEGAME_VERSION = 107; extern const uint16 SAVEGAME_VERSION = 108;
SavegameType _savegame_type; ///< type of savegame we are loading SavegameType _savegame_type; ///< type of savegame we are loading

View File

@ -48,6 +48,7 @@ public:
friend class AIController; friend class AIController;
friend class AIScanner; friend class AIScanner;
friend class AIInstance; friend class AIInstance;
friend class AIFileInfo;
Squirrel(); Squirrel();
~Squirrel(); ~Squirrel();