changeset 18451:ae9def3e6284 draft

(svn r23295) -Codechange: put ImportLibrary in AIController (and document the parameters for NoAI docs)
author truebrain <truebrain@openttd.org>
date Wed, 23 Nov 2011 13:39:36 +0000
parents 0fb6b658b347
children 062368eed9c3
files src/ai/ai.hpp src/ai/ai_core.cpp src/ai/ai_info.cpp src/ai/ai_info.hpp src/ai/ai_instance.cpp src/ai/ai_instance.hpp src/ai/ai_scanner.cpp src/ai/ai_scanner.hpp src/ai/api/ai_controller.cpp src/ai/api/ai_controller.hpp src/ai/api/ai_controller.hpp.sq src/script/squirrel.hpp src/script/squirrel_helper.hpp
diffstat 13 files changed, 106 insertions(+), 132 deletions(-) [+]
line wrap: on
line diff
--- a/src/ai/ai.hpp
+++ b/src/ai/ai.hpp
@@ -134,8 +134,8 @@
 	static const AIInfoList *GetUniqueInfoList();
 	/** Wrapper function for AIScanner::FindInfo */
 	static AIInfo *FindInfo(const char *name, int version, bool force_exact_match);
-	/** Wrapper function for AIScanner::ImportLibrary */
-	static bool ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm);
+	/** Wrapper function for AIScanner::FindLibrary */
+	static class AILibrary *FindLibrary(const char *library, int version);
 
 	/**
 	 * Rescans all searchpaths for available AIs. If a used AI is no longer
--- a/src/ai/ai_core.cpp
+++ b/src/ai/ai_core.cpp
@@ -322,9 +322,9 @@
 	return AI::ai_scanner->FindInfo(name, version, force_exact_match);
 }
 
-/* static */ bool AI::ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm)
+/* static */ AILibrary *AI::FindLibrary(const char *library, int version)
 {
-	return AI::ai_scanner->ImportLibrary(library, class_name, version, vm, AIObject::GetActiveInstance()->GetController());
+	return AI::ai_scanner->FindLibrary(library, version);
 }
 
 /* static */ void AI::Rescan()
--- a/src/ai/ai_info.cpp
+++ b/src/ai/ai_info.cpp
@@ -372,14 +372,3 @@
 
 	return 0;
 }
-
-/* static */ SQInteger AILibrary::Import(HSQUIRRELVM vm)
-{
-	SQConvert::SQAutoFreePointers ptr;
-	const char *library = GetParam(SQConvert::ForceType<const char *>(), vm, 2, &ptr);
-	const char *class_name = GetParam(SQConvert::ForceType<const char *>(), vm, 3, &ptr);
-	int version = GetParam(SQConvert::ForceType<int>(), vm, 4, &ptr);
-
-	if (!AI::ImportLibrary(library, class_name, version, vm)) return -1;
-	return 1;
-}
--- a/src/ai/ai_info.hpp
+++ b/src/ai/ai_info.hpp
@@ -147,13 +147,6 @@
 	static SQInteger Constructor(HSQUIRRELVM vm);
 
 	/**
-	 * Import a library in the current AI. This function can be used by AIs
-	 * by calling import.
-	 * @param vm The squirrel vm of the calling AI.
-	 */
-	static SQInteger Import(HSQUIRRELVM vm);
-
-	/**
 	 * Get the category this library is in.
 	 */
 	const char *GetCategory() const { return this->category; }
--- a/src/ai/ai_instance.cpp
+++ b/src/ai/ai_instance.cpp
@@ -122,10 +122,7 @@
 
 	this->controller = new AIController();
 
-	/* The import method is available at a very early stage */
-	this->engine->AddMethod("import", &AILibrary::Import, 4, ".ssi");
-
-	/* Register the AIController */
+	/* Register the AIController (including the "import" command) */
 	SQAIController_Register(this->engine);
 
 	/* Register the API functions and classes */
--- a/src/ai/ai_instance.hpp
+++ b/src/ai/ai_instance.hpp
@@ -78,6 +78,7 @@
 class AIInstance {
 public:
 	friend class AIObject;
+	friend class AIController;
 
 	/**
 	 * Create a new AI.
--- a/src/ai/ai_scanner.cpp
+++ b/src/ai/ai_scanner.cpp
@@ -95,7 +95,7 @@
 	delete this->info_dummy;
 }
 
-bool AIScanner::ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm, AIController *controller)
+AILibrary *AIScanner::FindLibrary(const char *library, int version)
 {
 	/* Internally we store libraries as 'library.version' */
 	char library_name[1024];
@@ -104,82 +104,9 @@
 
 	/* Check if the library + version exists */
 	AILibraryList::iterator iter = this->library_list.find(library_name);
-	if (iter == this->library_list.end()) {
-		char error[1024];
-
-		/* 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), "couldn't find library '%s' version %d. The latest version available is %d", library, version, (*iter).second->GetVersion());
-		}
-		sq_throwerror(vm, OTTD2SQ(error));
-		return false;
-	}
-
-	/* Get the current table/class we belong to */
-	HSQOBJECT parent;
-	sq_getstackobj(vm, 1, &parent);
-
-	char fake_class[1024];
-	int next_number;
-
-	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);
+	if (iter == this->library_list.end()) return NULL;
 
-		/* Load the library in a 'fake' namespace, so we can link it to the name the user requested */
-		sq_pushroottable(vm);
-		sq_pushstring(vm, OTTD2SQ(fake_class), -1);
-		sq_newclass(vm, SQFalse);
-		/* Load the library */
-		if (!this->engine->LoadScript(vm, (*iter).second->GetMainScript(), false)) {
-			char error[1024];
-			snprintf(error, sizeof(error), "there was a compile error when importing '%s' version %d", library, version);
-			sq_throwerror(vm, OTTD2SQ(error));
-			return false;
-		}
-		/* Create the fake class */
-		sq_newslot(vm, -3, SQFalse);
-		sq_pop(vm, 1);
-
-		controller->AddLoadedLibrary(library_name, fake_class);
-	}
-
-	/* Find the real class inside the fake class (like 'sets.Vector') */
-	sq_pushroottable(vm);
-	sq_pushstring(vm, OTTD2SQ(fake_class), -1);
-	if (SQ_FAILED(sq_get(vm, -2))) {
-		sq_throwerror(vm, _SC("internal error assigning library class"));
-		return false;
-	}
-	sq_pushstring(vm, OTTD2SQ((*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' version %d", (*iter).second->GetInstanceName(), library, version);
-		sq_throwerror(vm, OTTD2SQ(error));
-		return false;
-	}
-	HSQOBJECT obj;
-	sq_getstackobj(vm, -1, &obj);
-	sq_pop(vm, 3);
-
-	if (StrEmpty(class_name)) {
-		sq_pushobject(vm, obj);
-		return true;
-	}
-
-	/* Now link the name the user wanted to our 'fake' class */
-	sq_pushobject(vm, parent);
-	sq_pushstring(vm, OTTD2SQ(class_name), -1);
-	sq_pushobject(vm, obj);
-	sq_newclass(vm, SQTrue);
-	sq_newslot(vm, -3, SQFalse);
-	sq_pop(vm, 1);
-
-	sq_pushobject(vm, obj);
-	return true;
+	return (*iter).second;
 }
 
 void AIScanner::RegisterLibrary(AILibrary *library)
--- a/src/ai/ai_scanner.hpp
+++ b/src/ai/ai_scanner.hpp
@@ -24,9 +24,12 @@
 	~AIScanner();
 
 	/**
-	 * Import a library inside the Squirrel VM.
+	 * Find a library by name + version.
+	 * @param library The name of the library to find.
+	 * @param version The prefered version of the library.
+	 * @return The library if found, NULL otherwise.
 	 */
-	bool ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm, class AIController *controller);
+	AILibrary *FindLibrary(const char *library, int version);
 
 	/**
 	 * Register a library to be put in the available list.
--- a/src/ai/api/ai_controller.cpp
+++ b/src/ai/api/ai_controller.cpp
@@ -13,11 +13,13 @@
 #include "../../string_func.h"
 #include "../../company_base.h"
 #include "../../company_func.h"
+#include "../../script/squirrel.hpp"
 #include "../../rev.h"
 
 #include "ai_controller.hpp"
 #include "../ai_instance.hpp"
 #include "../ai_config.hpp"
+#include "../ai.hpp"
 #include "ai_log.hpp"
 
 /* static */ void AIController::SetCommandDelay(int ticks)
@@ -81,19 +83,81 @@
 	return _openttd_newgrf_version;
 }
 
-bool AIController::LoadedLibrary(const char *library_name, int *next_number, char *fake_class_name, int fake_class_name_len)
+/* static */ HSQOBJECT AIController::Import(const char *library, const char *class_name, int version)
 {
-	LoadedLibraryList::iterator iter = this->loaded_library.find(library_name);
-	if (iter == this->loaded_library.end()) {
-		*next_number = ++this->loaded_library_count;
-		return false;
+	AIController *controller = AIObject::GetActiveInstance()->GetController();
+	Squirrel *engine = AIObject::GetActiveInstance()->engine;
+	HSQUIRRELVM vm = engine->GetVM();
+
+	/* Internally we store libraries as 'library.version' */
+	char library_name[1024];
+	snprintf(library_name, sizeof(library_name), "%s.%d", library, version);
+	strtolower(library_name);
+
+	AILibrary *lib = AI::FindLibrary(library, version);
+	if (lib == NULL) {
+		char error[1024];
+		snprintf(error, sizeof(error), "couldn't find library '%s' with version %d", library, version);
+		throw sq_throwerror(vm, OTTD2SQ(error));
 	}
 
-	ttd_strlcpy(fake_class_name, (*iter).second, fake_class_name_len);
-	return true;
-}
+	/* Get the current table/class we belong to */
+	HSQOBJECT parent;
+	sq_getstackobj(vm, 1, &parent);
+
+	char fake_class[1024];
+
+	LoadedLibraryList::iterator iter = controller->loaded_library.find(library_name);
+	if (iter != controller->loaded_library.end()) {
+		ttd_strlcpy(fake_class, (*iter).second, sizeof(fake_class));
+	} else {
+		int next_number = ++controller->loaded_library_count;
+
+		/* Create a new fake internal name */
+		snprintf(fake_class, sizeof(fake_class), "_internalNA%d", next_number);
+
+		/* Load the library in a 'fake' namespace, so we can link it to the name the user requested */
+		sq_pushroottable(vm);
+		sq_pushstring(vm, OTTD2SQ(fake_class), -1);
+		sq_newclass(vm, SQFalse);
+		/* Load the library */
+		if (!engine->LoadScript(vm, lib->GetMainScript(), false)) {
+			char error[1024];
+			snprintf(error, sizeof(error), "there was a compile error when importing '%s' version %d", library, version);
+			throw sq_throwerror(vm, OTTD2SQ(error));
+		}
+		/* Create the fake class */
+		sq_newslot(vm, -3, SQFalse);
+		sq_pop(vm, 1);
 
-void AIController::AddLoadedLibrary(const char *library_name, const char *fake_class_name)
-{
-	this->loaded_library[strdup(library_name)] = strdup(fake_class_name);
+		controller->loaded_library[strdup(library_name)] = strdup(fake_class);
+	}
+
+	/* Find the real class inside the fake class (like 'sets.Vector') */
+	sq_pushroottable(vm);
+	sq_pushstring(vm, OTTD2SQ(fake_class), -1);
+	if (SQ_FAILED(sq_get(vm, -2))) {
+		throw sq_throwerror(vm, _SC("internal error assigning library class"));
+	}
+	sq_pushstring(vm, OTTD2SQ(lib->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' version %d", lib->GetInstanceName(), library, version);
+		throw sq_throwerror(vm, OTTD2SQ(error));
+	}
+	HSQOBJECT obj;
+	sq_getstackobj(vm, -1, &obj);
+	sq_pop(vm, 3);
+
+	if (StrEmpty(class_name)) return obj;
+
+	/* Now link the name the user wanted to our 'fake' class */
+	sq_pushobject(vm, parent);
+	sq_pushstring(vm, OTTD2SQ(class_name), -1);
+	sq_pushobject(vm, obj);
+	sq_newclass(vm, SQTrue);
+	sq_newslot(vm, -3, SQFalse);
+	sq_pop(vm, 1);
+
+	return obj;
 }
--- a/src/ai/api/ai_controller.hpp
+++ b/src/ai/api/ai_controller.hpp
@@ -109,6 +109,16 @@
 	 */
 	static void Print(bool error_msg, const char *message);
 
+	/**
+	 * Import a library.
+	 * @param library The name of the library to import.
+	 * @param class_name Under which name you want it to be available (or "" if you just want the returning object).
+	 * @param version Which version you want specificly.
+	 * @return The loaded library object. If class_name is set, it is also available (under the scope of the import) under that name.
+	 * @note This command can be called from the global space, and does not need an instance.
+	 */
+	static HSQOBJECT Import(const char *library, const char *class_name, int version);
+
 private:
 	typedef std::map<const char *, const char *, StringCompare> LoadedLibraryList; ///< The type for loaded libraries.
 
@@ -120,23 +130,6 @@
 	 * Register all classes that are known inside the NoAI API.
 	 */
 	void RegisterClasses();
-
-	/**
-	 * Check if a library is already loaded. If found, fake_class_name is filled
-	 *  with the fake class name as given via AddLoadedLibrary. If not found,
-	 *  next_number is set to the next number available for the fake namespace.
-	 * @param library_name The library to check if already loaded.
-	 * @param next_number The next available number for a library if not already loaded.
-	 * @param fake_class_name The name the library has if already loaded.
-	 * @param fake_class_name_len The maximum length of fake_class_name.
-	 * @return True if the library is already loaded.
-	 */
-	bool LoadedLibrary(const char *library_name, int *next_number, char *fake_class_name, int fake_class_name_len);
-
-	/**
-	 * Add a library as loaded.
-	 */
-	void AddLoadedLibrary(const char *library_name, const char *fake_class_name);
 };
 
 #endif /* AI_CONTROLLER_HPP */
--- a/src/ai/api/ai_controller.hpp.sq
+++ b/src/ai/api/ai_controller.hpp.sq
@@ -15,6 +15,7 @@
 {
 	DefSQClass <AIController> SQAIController("AIController");
 	SQAIController.PreRegister(engine);
+
 	SQAIController.DefSQStaticMethod(engine, &AIController::GetTick,           "GetTick",           1, ".");
 	SQAIController.DefSQStaticMethod(engine, &AIController::GetOpsTillSuspend, "GetOpsTillSuspend", 1, ".");
 	SQAIController.DefSQStaticMethod(engine, &AIController::SetCommandDelay,   "SetCommandDelay",   2, ".i");
@@ -22,5 +23,9 @@
 	SQAIController.DefSQStaticMethod(engine, &AIController::GetSetting,        "GetSetting",        2, ".s");
 	SQAIController.DefSQStaticMethod(engine, &AIController::GetVersion,        "GetVersion",        1, ".");
 	SQAIController.DefSQStaticMethod(engine, &AIController::Print,             "Print",             3, ".bs");
+
 	SQAIController.PostRegister(engine);
+
+	/* Register the import statement to the global scope */
+	SQAIController.DefSQStaticMethod(engine, &AIController::Import,            "import",            4, ".ssi");
 }
--- a/src/script/squirrel.hpp
+++ b/src/script/squirrel.hpp
@@ -58,6 +58,7 @@
 public:
 	friend class AIScanner;
 	friend class AIInstance;
+	friend class AIController;
 	friend void squirrel_register_std(Squirrel *engine);
 
 	Squirrel();
--- a/src/script/squirrel_helper.hpp
+++ b/src/script/squirrel_helper.hpp
@@ -92,6 +92,7 @@
 	template <> inline int Return<char *>      (HSQUIRRELVM vm, char *res)       { if (res == NULL) sq_pushnull(vm); else { sq_pushstring(vm, OTTD2SQ(res), -1); free(res); } return 1; }
 	template <> inline int Return<const char *>(HSQUIRRELVM vm, const char *res) { if (res == NULL) sq_pushnull(vm); else { sq_pushstring(vm, OTTD2SQ(res), -1); } return 1; }
 	template <> inline int Return<void *>      (HSQUIRRELVM vm, void *res)       { sq_pushuserpointer(vm, res); return 1; }
+	template <> inline int Return<HSQOBJECT>   (HSQUIRRELVM vm, HSQOBJECT res)   { sq_pushobject(vm, res); return 1; }
 
 	/**
 	 * To get a param from squirrel, we call this function. It converts to the right format.