# HG changeset patch # User truebrain # Date 1213876514 0 # Node ID 631db8573db216dccea8668f4bb403e939f7c8b0 # Parent 13060e4514d57344a54fab1b710d3094e8cb8cee (svn r13580) [NoAI] -Add: allow multiple version of a single library to exist. If you name your directory, say, pathfinder/road.1, and put Road Pathfinder version 1 in it, you can load version 1 and version 2. The system ignores everything after the '.' (dot), and accepts it if the versions differ. diff -r 13060e4514d5 -r 631db8573db2 src/ai/ai_squirrel.cpp --- a/src/ai/ai_squirrel.cpp Wed Jun 18 20:58:42 2008 +0000 +++ b/src/ai/ai_squirrel.cpp Thu Jun 19 11:55:14 2008 +0000 @@ -92,10 +92,17 @@ if (FioCheckFileExists(script_name, AI_DIR)) { char load_script[MAX_PATH]; char dir_name[MAX_PATH]; + char d_name_2[MAX_PATH]; + /* In case the directory has a dot in it, ignore it, as that is the + * indicator for multiple versions of the same library */ + ttd_strlcpy(d_name_2, d_name, sizeof(d_name_2)); + char *e = strrchr(d_name_2, '.'); + if (e != NULL) *e = '\0'; + ttd_strlcpy(load_script, script_name, sizeof(load_script)); ttd_strlcpy(dir_name, library_depth, sizeof(dir_name)); ttd_strlcat(dir_name, ".", sizeof(dir_name)); - ttd_strlcat(dir_name, d_name, sizeof(dir_name)); + ttd_strlcat(dir_name, d_name_2, sizeof(dir_name)); /* Remove the 'library.nut' part and replace it with 'main.nut' */ script_name[strlen(script_name) - 11] = '\0'; @@ -164,19 +171,22 @@ bool AISquirrel::ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm, AIController *controller) { - AILibraryList::iterator iter = this->library_list.find(library); - /* Check if the library exists */ + /* Internally we store libraries as 'library.version' */ + char library_name[1024]; + snprintf(library_name, sizeof(library_name), "%s.%d", library, version); + + /* Check if the library + version exists */ + AILibraryList::iterator iter = this->library_list.find(library_name); if (iter == this->library_list.end()) { char error[1024]; - snprintf(error, sizeof(error), "couldn't find library '%s'", library); - sq_throwerror(vm, OTTD2FS(error)); - return false; - } - /* Check if the version matches */ - if ((*iter).second->GetVersion() != version) { - char error[1024]; - snprintf(error, sizeof(error), "this AI is expected library '%s' to be version %d, but it is version %d", library, version, (*iter).second->GetVersion()); + /* Now see if the version doesn't exist, or the library */ + iter = this->library_list.find(library); + if (iter == this->library_list.end()) { + snprintf(error, sizeof(error), "couldn't find library '%s'", library); + } else { + snprintf(error, sizeof(error), "this AI is expecting library '%s' to be version %d, but the latest available is version %d", library, version, (*iter).second->GetVersion()); + } sq_throwerror(vm, OTTD2FS(error)); return false; } @@ -189,7 +199,7 @@ int next_number; /* Check if we already have this library loaded.. if so, fill fake_class * with the class-name it is nested in */ - if (!controller->LoadedLibrary(library, &next_number, &fake_class[0], sizeof(fake_class))) { + if (!controller->LoadedLibrary(library_name, &next_number, &fake_class[0], sizeof(fake_class))) { /* Create a new fake internal name */ snprintf(fake_class, sizeof(fake_class), "_internalNA%d", next_number); @@ -200,7 +210,7 @@ /* Load the library */ if (!Squirrel::LoadScript(vm, (*iter).second->GetScriptName(), false)) { char error[1024]; - snprintf(error, sizeof(error), "there was a compile error when importing '%s'", library); + snprintf(error, sizeof(error), "there was a compile error when importing '%s' version %d", library, version); sq_throwerror(vm, OTTD2FS(error)); return false; } @@ -208,7 +218,7 @@ sq_newslot(vm, -3, SQFalse); sq_pop(vm, 1); - controller->AddLoadedLibrary(library, fake_class); + controller->AddLoadedLibrary(library_name, fake_class); } /* Find the real class inside the fake class (like 'sets.Vector') */ @@ -221,7 +231,7 @@ sq_pushstring(vm, OTTD2FS((*iter).second->GetInstanceName()), -1); if (SQ_FAILED(sq_get(vm, -2))) { char error[1024]; - snprintf(error, sizeof(error), "unable to find class '%s' in the library '%s'", (*iter).second->GetInstanceName(), library); + snprintf(error, sizeof(error), "unable to find class '%s' in the library '%s' version %d", (*iter).second->GetInstanceName(), library, version); sq_throwerror(vm, OTTD2FS(error)); return false; } @@ -248,13 +258,15 @@ void AISquirrel::RegisterLibrary(AILibrary *library) { - const char *ai_name = library->GetDirName(); + const char *ai_name_without_version = library->GetDirName(); + char ai_name[1024]; + snprintf(ai_name, sizeof(ai_name), "%s.%d", library->GetDirName(), library->GetVersion()); /* Check if we register twice; than the first always wins */ if (this->library_list.find(ai_name) != this->library_list.end()) { /* In case they are not the same dir, give a warning */ if (strcasecmp(library->GetScriptName(), this->library_list[ai_name]->GetScriptName()) != 0) { - DEBUG(ai, 0, "Registering two Libraries with the same name"); + DEBUG(ai, 0, "Registering two libraries with the same name"); DEBUG(ai, 0, " 1: %s", this->library_list[ai_name]->GetScriptName()); DEBUG(ai, 0, " 2: %s", library->GetScriptName()); DEBUG(ai, 0, "The first is taking precedence"); @@ -263,7 +275,14 @@ delete library; return; } - this->library_list[ai_name] = library; + + this->library_list[strdup(ai_name)] = library; + /* Insert the global name too, so we if the library is known at all */ + if (this->library_list.find(ai_name_without_version) == this->library_list.end()) { + this->library_list[strdup(ai_name_without_version)] = library; + } else if (this->library_list[ai_name_without_version]->GetVersion() < library->GetVersion()) { + this->library_list[ai_name_without_version] = library; + } } void AISquirrel::RegisterAI(AIInfo *info) @@ -283,7 +302,8 @@ delete info; return; } - this->info_list[ai_name] = info; + + this->info_list[strdup(ai_name)] = info; } void AISquirrel::UnregisterAI(AIInfo *info)