(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. noai
authortruebrain
Thu, 19 Jun 2008 11:55:14 +0000
branchnoai
changeset 11024 631db8573db2
parent 11014 13060e4514d5
child 11026 5882d3402d7d
(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.
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)