# HG changeset patch # User truebrain # Date 1213388340 0 # Node ID 65088d587094c8c80d9110e9e9f28d8217734561 # Parent 7a140b4cd91d366626b1a9481e8542888347f1b9 (svn r13512) [NoAI] -Fix: don't load a library over and over, but keep track of which libraries we have loaded (per AI) and re-use it where possible (reduces memory-footprint) [NoAI] -Fix: change the fake-library-name-counter to a per AI value, not global [NoAI] -Fix: Load the script inside the thread, not in the main thread. This avoids unneeded error-handling diff -r 7a140b4cd91d -r 65088d587094 src/ai/ai.cpp --- a/src/ai/ai.cpp Fri Jun 13 19:57:25 2008 +0000 +++ b/src/ai/ai.cpp Fri Jun 13 20:19:00 2008 +0000 @@ -218,7 +218,7 @@ bool AI_ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm) { - return _ai_squirrel->ImportLibrary(library, class_name, version, vm); + return _ai_squirrel->ImportLibrary(library, class_name, version, vm, _ai_player[_current_player]); } void AI_Rescan() diff -r 7a140b4cd91d -r 65088d587094 src/ai/ai_squirrel.cpp --- a/src/ai/ai_squirrel.cpp Fri Jun 13 19:57:25 2008 +0000 +++ b/src/ai/ai_squirrel.cpp Fri Jun 13 20:19:00 2008 +0000 @@ -17,6 +17,7 @@ #include "../squirrel.hpp" #include "ai_info.hpp" #include "ai_squirrel.hpp" +#include "api/ai_controller.hpp" void AISquirrel::ScanDir(const char *dirname, bool library_dir, char *library_depth) { @@ -132,7 +133,6 @@ AISquirrel::AISquirrel() { - this->library_instance_count = 0; this->engine = new Squirrel(); /* Create the AIInfo class, and add the RegisterAI function */ @@ -162,7 +162,7 @@ delete this->engine; } -bool AISquirrel::ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm) +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 */ @@ -181,28 +181,35 @@ return false; } - /* Create a fake internal name */ - char fake_class[1024]; - snprintf(fake_class, sizeof(fake_class), "_internalNA%d", ++this->library_instance_count); - /* Get the current table/class we belong to */ HSQOBJECT parent; sq_getstackobj(vm, 1, &parent); - /* Load the library in a 'fake' namespace, so we can link it to the name the user requested */ - sq_pushroottable(vm); - sq_pushstring(vm, OTTD2FS(fake_class), -1); - sq_newclass(vm, SQFalse); - /* 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); - sq_throwerror(vm, OTTD2FS(error)); - return false; + char fake_class[1024]; + 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))) { + /* 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, OTTD2FS(fake_class), -1); + sq_newclass(vm, SQFalse); + /* 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); + sq_throwerror(vm, OTTD2FS(error)); + return false; + } + /* Create the fake class */ + sq_newslot(vm, -3, SQFalse); + sq_pop(vm, 1); + + controller->AddLoadedLibrary(library, fake_class); } - /* Create the fake class */ - sq_newslot(vm, -3, SQFalse); - sq_pop(vm, 1); /* Find the real class inside the fake class (like 'sets.Vector') */ sq_pushroottable(vm); diff -r 7a140b4cd91d -r 65088d587094 src/ai/ai_squirrel.hpp --- a/src/ai/ai_squirrel.hpp Fri Jun 13 19:57:25 2008 +0000 +++ b/src/ai/ai_squirrel.hpp Fri Jun 13 20:19:00 2008 +0000 @@ -6,7 +6,9 @@ #define AI_SQUIRREL_HPP #include +#ifndef AI_CONTROLLER_HPP struct ltstr { bool operator()(const char *s1, const char *s2) const { return strcmp(s1, s2) < 0; } }; +#endif /* AI_CONTROLLER_HPP */ class AISquirrel { public: @@ -16,7 +18,7 @@ /** * Import a library inside the Squirrel VM. */ - bool ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm); + bool ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm, AIController *controller); /** * Register a library to be put in the available list. @@ -91,7 +93,6 @@ class Squirrel *engine; char *current_script; char *current_dir; - int library_instance_count; }; #endif /* AI_SQUIRREL_HPP */ diff -r 7a140b4cd91d -r 65088d587094 src/ai/api/ai_controller.cpp --- a/src/ai/api/ai_controller.cpp Fri Jun 13 19:57:25 2008 +0000 +++ b/src/ai/api/ai_controller.cpp Fri Jun 13 20:19:00 2008 +0000 @@ -6,6 +6,7 @@ #include "../../openttd.h" #include "../../player_func.h" #include "../../core/alloc_func.hpp" +#include "../../string_func.h" #include "table/strings.h" #include @@ -152,32 +153,36 @@ AIController::Print(error_msg, FS2OTTD(message)); } -AIController::AIController(const char *script, const char *class_name) +AIController::AIController(const char *script, const char *class_name) : + tick(0), + engine(NULL), + SQ_instance(NULL), + loaded_library_count(0) { - this->tick = 0; - this->SQ_instance = NULL; + this->script = strdup(script); + this->class_name = strdup(class_name); +} + +void AIController::Start() +{ + assert(this->engine == NULL); /* Create the Squirrel Engine and assign all required classes and settings */ this->engine = new Squirrel(); this->engine->SetPrintFunction(&PrintFunc); this->RegisterClasses(); - if (!this->engine->LoadScript(script)) { + if (!this->engine->LoadScript(this->script)) { delete this->engine; this->engine = NULL; return; } /* Create the main-class */ this->SQ_instance = MallocT(sizeof(SQObject)); - if (!this->engine->CreateClassInstance(class_name, this, this->SQ_instance)) { + if (!this->engine->CreateClassInstance(this->class_name, this, this->SQ_instance)) { delete this->engine; this->engine = NULL; return; } -} - -void AIController::Start() -{ - if (this->engine == NULL) return; /* Run the constructor first */ if (this->engine->MethodExists(*this->SQ_instance, "constructor")) { @@ -191,6 +196,15 @@ { if (this->engine != NULL) delete this->engine; free(this->SQ_instance); + free((void *)this->script); + free((void *)this->class_name); + + for (LoadedLibraryList::iterator iter = this->loaded_library.begin(); iter != this->loaded_library.end(); iter++) { + free((void *)(*iter).second); + free((void *)(*iter).first); + } + + this->loaded_library.clear(); } void AIController::IncreaseTick() @@ -202,3 +216,20 @@ { return this->tick; } + +bool AIController::LoadedLibrary(const char *library_name, int *next_number, char *fake_class_name, int fake_class_name_len) +{ + LoadedLibraryList::iterator iter = this->loaded_library.find(library_name); + if (iter == this->loaded_library.end()) { + *next_number = ++this->loaded_library_count; + return false; + } + + ttd_strlcpy(fake_class_name, (*iter).second, fake_class_name_len); + return true; +} + +void AIController::AddLoadedLibrary(const char *library_name, const char *fake_class_name) +{ + this->loaded_library[strdup(library_name)] = strdup(fake_class_name); +} diff -r 7a140b4cd91d -r 65088d587094 src/ai/api/ai_controller.hpp --- a/src/ai/api/ai_controller.hpp Fri Jun 13 19:57:25 2008 +0000 +++ b/src/ai/api/ai_controller.hpp Fri Jun 13 20:19:00 2008 +0000 @@ -5,13 +5,17 @@ #ifndef AI_CONTROLLER_HPP #define AI_CONTROLLER_HPP +#include +#ifndef AI_SQUIRREL_HPP +struct ltstr { bool operator()(const char *s1, const char *s2) const { return strcmp(s1, s2) < 0; } }; +#endif /* AI_SQUIRREL_HPP */ + /** * The Controller, the class each AI should extend. It creates the AI, makes * sure the logic kicks in correctly, and that GetTick() has a valid value. */ class AIController { -private: - uint tick; + friend class AISquirrel; public: static const char *GetClassName() { return "AIController"; } @@ -70,13 +74,37 @@ static void Print(bool error_msg, const char *message); private: + typedef std::map LoadedLibraryList; + + uint tick; class Squirrel *engine; HSQOBJECT *SQ_instance; + LoadedLibraryList loaded_library; + int loaded_library_count; + const char *script; + const char *class_name; /** * 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 */