(svn r13440) [NoAI] -Add: introducing ai/library, a method to load libraries into your AI.
-Note: to use a library, use in your AI: import("categorie.name", "LocalName", version_number_of_library)
-Example: import("sets.priority_queue", "PQ", 1); local pq = PQ(2); pq.insert(2, 1);
[NoAI] -Add [Library]: sets.priority_queue (based on work by Morloth)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/ai/library/sets/priority_queue/library.nut Tue Jun 10 14:11:35 2008 +0000
@@ -0,0 +1,12 @@
+/* $Id$ */
+
+class PriorityQueue extends AILibrary {
+ function GetAuthor() { return "OpenTTD NoAI Developers Team"; }
+ function GetName() { return "Priority Queue"; }
+ function GetDescription() { return "An implementation of a Priority Queue"; }
+ function GetVersion() { return 1; }
+ function GetDate() { return "2008-06-10"; }
+ function CreateInstance() { return "PriorityQueue"; }
+}
+
+RegisterLibrary(PriorityQueue());
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/bin/ai/library/sets/priority_queue/main.nut Tue Jun 10 14:11:35 2008 +0000
@@ -0,0 +1,113 @@
+/* $Id$ */
+
+/**
+ * Priority Queue
+ * Peek and Remove always return the current lowest value in the list.
+ * Sort is done on insertion. When initial size runs out, array is
+ * resized to be twice as big.
+ */
+class PriorityQueue {
+ _queue = null;
+ _count = 0;
+ _size = 0;
+
+ constructor(size)
+ {
+ this._count = 0;
+ this._queue = array(size * 2);
+ this._size = size * 2;
+ }
+
+ /**
+ * Insert a new entry in the list.
+ * @param item The item to add to the list.
+ * @param priority The priority this item has.
+ */
+ function Insert(item, priority);
+
+ /**
+ * Pop the first entry of the list.
+ * This is always the item with the lowest priority.
+ * @return The item of the entry with the lowest priority.
+ */
+ function Pop();
+
+ /**
+ * Peek the first entry of the list.
+ * This is always the item with the lowest priority.
+ * @return The item of the entry with the lowest priority.
+ */
+ function Peek();
+
+ /**
+ * Get the amount of current items in the list.
+ * @return The amount of items currently in the list.
+ */
+ function Count();
+}
+
+function PriorityQueue::_checkAndExpand()
+{
+ if (this._count != this._size) return;
+
+ /* Create a new array twice the size */
+ this._size = this._size * 2;
+ local tmpArray = array(this._size);
+
+ /* Copy all elements */
+ for (local i = 0; i < this._count; i++) {
+ tmpArray[i] = this._queue[i];
+ }
+
+ this._queue = tmpArray;
+}
+
+function PriorityQueue::Insert(item, priority)
+{
+ this._checkAndExpand();
+
+ /* Find a place to insert the data */
+ if (this._count == 0) {
+ this._queue[this._count] = priority;
+ this._queue[this._count + 1] = item;
+ this._count += 2;
+ } else {
+ local i;
+ for (i = this._count - 2; i >= 0; i -= 2) {
+ if (priority > this._queue[i]) {
+ /* All items bigger move one place to the right */
+ this._queue[i + 2] = this._queue[i];
+ this._queue[i + 3] = this._queue[i + 1];
+ } else if (item == this._queue[i + 1]) {
+ /* Same item, ignore insertion */
+ return false;
+ } else {
+ /* Found place to insert at */
+ break;
+ }
+ }
+ this._queue[i + 2] = priority
+ this._queue[i + 3] = item;
+ this._count += 2;
+ }
+
+ return true;
+}
+
+function PriorityQueue::Pop()
+{
+ if (this._count == 0) return null;
+ this._count -= 2;
+ return this._queue[this._count + 1];
+}
+
+function PriorityQueue::Peek()
+{
+ if (this._count == 0) return null;
+ return this._queue[this._count - 1];
+}
+
+function PriorityQueue::Count()
+{
+ return this._count / 2;
+}
--- a/bin/ai/regression/regression.nut Tue Jun 10 14:08:39 2008 +0000
+++ b/bin/ai/regression/regression.nut Tue Jun 10 14:11:35 2008 +0000
@@ -1,3 +1,5 @@
+import("sets.priority_queue", "PQ", 1);
+
class Regression extends AIController {
function Start();
}
@@ -23,6 +25,26 @@
print("--Std--");
print(" abs(-21): " + abs(-21));
print(" abs( 21): " + abs(21));
+
+ print("");
+ print("--PriorityQueue--");
+ local pq = PQ(2);
+ pq.Insert(1, 20);
+ pq.Insert(2, 40);
+ pq.Insert(3, 10);
+ pq.Insert(4, 15);
+ pq.Insert(5, 60);
+ pq.Insert(6, 5);
+ print(" Count(): " + pq.Count());
+ print(" Peek(): " + pq.Peek());
+ print(" Pop(): " + pq.Pop());
+ print(" Pop(): " + pq.Pop())
+ print(" Pop(): " + pq.Pop())
+ print(" Pop(): " + pq.Pop())
+ print(" Pop(): " + pq.Pop())
+ print(" Pop(): " + pq.Pop())
+ print(" Peek(): " + pq.Peek());
+ print(" Pop(): " + pq.Pop());
}
function Regression::Base()
--- a/bin/ai/regression/regression.txt Tue Jun 10 14:08:39 2008 +0000
+++ b/bin/ai/regression/regression.txt Tue Jun 10 14:11:35 2008 +0000
@@ -11,6 +11,18 @@
abs(-21): 21
abs( 21): 21
+--PriorityQueue--
+ Count(): 6
+ Peek(): 6
+ Pop(): 6
+ Pop(): 3
+ Pop(): 4
+ Pop(): 1
+ Pop(): 2
+ Pop(): 5
+ Peek(): (null : 0x00000000)
+ Pop(): (null : 0x00000000)
+
--AIBase--
Rand(): 753450495
Rand(): 202826571
--- a/src/ai/ai.cpp Tue Jun 10 14:08:39 2008 +0000
+++ b/src/ai/ai.cpp Tue Jun 10 14:11:35 2008 +0000
@@ -216,6 +216,11 @@
return true;
}
+bool AI_ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm)
+{
+ return _ai_squirrel->ImportLibrary(library, class_name, version, vm);
+}
+
#else /* NO_THREADS */
/* Stub functions for when we do not have threads. */
void AI_StartNewAI(PlayerID player) { DEBUG(ai, 0, "Threading is disabled and therefor the AI too."); }
@@ -228,5 +233,6 @@
void AI_ForceAI(const char *forced_ai) {}
char *AI_GetConsoleList(char *p, const char *last) { return p; }
AIInfo *AI_GetPlayerInfo(PlayerID player) { return NULL; }
+bool AI_LoadLibrary(const char *library, HSQUIRRELVM vm) { return false; }
void CcAI(bool success, TileIndex tile, uint32 p1, uint32 p2) {}
#endif /* NO_THREADS */
--- a/src/ai/ai.h Tue Jun 10 14:08:39 2008 +0000
+++ b/src/ai/ai.h Tue Jun 10 14:11:35 2008 +0000
@@ -17,6 +17,7 @@
void AI_ForceAI(const char *forced_ai);
void AI_Event(PlayerID player, AIEvent *event);
char *AI_GetConsoleList(char *p, const char *last);
+bool AI_ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm);
void CcAI(bool success, TileIndex tile, uint32 p1, uint32 p2);
--- a/src/ai/ai_info.cpp Tue Jun 10 14:08:39 2008 +0000
+++ b/src/ai/ai_info.cpp Tue Jun 10 14:11:35 2008 +0000
@@ -1,6 +1,6 @@
/* $Id$ */
-/** @file ai_info.cpp Implementation of AIInfo */
+/** @file ai_info.cpp Implementation of AIFileInfo */
#include "../stdafx.h"
#include "../core/alloc_func.hpp"
@@ -10,88 +10,92 @@
#include "../squirrel_helper.hpp"
#include "../squirrel_class.hpp"
#include "../squirrel_std.hpp"
+#include "ai.h"
#include "ai_info.hpp"
#include "ai_squirrel.hpp"
#include "api/ai_controller.hpp"
-AIInfo::~AIInfo()
+AIFileInfo::~AIFileInfo()
{
this->engine->ReleaseObject(this->SQ_instance);
free((void *)this->author);
free((void *)this->name);
free((void *)this->description);
free((void *)this->date);
+ free((void *)this->instance_name);
free(this->script_name);
free(this->dir_name);
free(this->SQ_instance);
}
-const char *AIInfo::GetAuthor()
+const char *AIFileInfo::GetAuthor()
{
if (this->author == NULL) this->author = this->engine->CallStringMethodStrdup(*this->SQ_instance, "GetAuthor");
return this->author;
}
-const char *AIInfo::GetName()
+const char *AIFileInfo::GetName()
{
if (this->name == NULL) this->name = this->engine->CallStringMethodStrdup(*this->SQ_instance, "GetName");
return this->name;
}
-const char *AIInfo::GetDescription()
+const char *AIFileInfo::GetDescription()
{
if (this->description == NULL) this->description = this->engine->CallStringMethodStrdup(*this->SQ_instance, "GetDescription");
return this->description;
}
-int AIInfo::GetVersion()
+int AIFileInfo::GetVersion()
{
return this->engine->CallIntegerMethod(*this->SQ_instance, "GetVersion");
}
-const char *AIInfo::GetDate()
+const char *AIFileInfo::GetDate()
{
if (this->date == NULL) this->date = this->engine->CallStringMethodStrdup(*this->SQ_instance, "GetDate");
return this->date;
}
-bool AIInfo::AllowStartup()
+const char *AIFileInfo::GetInstanceName()
+{
+ if (this->instance_name == NULL) this->instance_name = this->engine->CallStringMethodStrdup(*this->SQ_instance, "CreateInstance");
+ return this->instance_name;
+}
+
+bool AIFileInfo::AllowStartup()
{
return true;
}
-AIController *AIInfo::CreateInstance()
+AIController *AIFileInfo::CreateInstance()
{
- const char *class_name = this->engine->CallStringMethodStrdup(*this->SQ_instance, "CreateInstance");
- AIController *ai_controller = new AIController(this->script_name, class_name);
- free((void *)class_name);
+ AIController *ai_controller = new AIController(this->script_name, this->GetInstanceName());
return ai_controller;
}
-const char *AIInfo::GetDirName()
+const char *AIFileInfo::GetDirName()
{
return this->dir_name;
}
-const char *AIInfo::GetScriptName()
+const char *AIFileInfo::GetScriptName()
{
return this->script_name;
}
-void AIInfo::CheckMethods(SQInteger *res, const char *name)
+void AIFileInfo::CheckMethods(SQInteger *res, const char *name)
{
if (!this->engine->MethodExists(*this->SQ_instance, name)) {
char error[1024];
- snprintf(error, sizeof(error), "your AIInfo doesn't have the method '%s'", name);
+ snprintf(error, sizeof(error), "your AIFileInfo doesn't have the method '%s'", name);
this->engine->ThrowError(error);
*res = SQ_ERROR;
}
}
-/* static */ SQInteger AIInfo::Constructor(HSQUIRRELVM vm)
+/* static */ SQInteger AIFileInfo::Constructor(HSQUIRRELVM vm, AIFileInfo *info)
{
- /* Create a new AIInfo */
- AIInfo *info = new AIInfo();
SQInteger res = 0;
/* Set some basic info from the parent */
@@ -116,8 +120,44 @@
info->script_name = strdup(info->base->GetCurrentScript());
info->dir_name = strdup(info->base->GetCurrentDirName());
+ return 0;
+}
+
+/* static */ SQInteger AIInfo::Constructor(HSQUIRRELVM vm)
+{
+ /* Create a new AIFileInfo */
+ AIInfo *info = new AIInfo();
+
+ SQInteger res = AIFileInfo::Constructor(vm, info);
+ if (res != 0) return res;
+
/* Register the AI to the base system */
info->base->RegisterAI(info);
return 0;
}
+
+/* static */ SQInteger AILibrary::Constructor(HSQUIRRELVM vm)
+{
+ /* Create a new AIFileInfo */
+ AILibrary *library = new AILibrary();
+
+ SQInteger res = AIFileInfo::Constructor(vm, library);
+ if (res != 0) return res;
+
+ /* Register the Library to the base system */
+ library->base->RegisterLibrary(library);
+
+ 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 0;
+}
--- a/src/ai/ai_info.hpp Tue Jun 10 14:08:39 2008 +0000
+++ b/src/ai/ai_info.hpp Tue Jun 10 14:11:35 2008 +0000
@@ -5,10 +5,13 @@
#ifndef AI_INFO
#define AI_INFO
-class AIInfo {
+class AIFileInfo {
public:
- AIInfo() : author(NULL), name(NULL), description(NULL), date(NULL) {};
- ~AIInfo();
+ friend class AIInfo;
+ friend class AILibrary;
+
+ AIFileInfo() : author(NULL), name(NULL), description(NULL), date(NULL), instance_name(NULL) {};
+ ~AIFileInfo();
/**
* Get the Author of the AI.
@@ -36,6 +39,11 @@
const char *GetDate();
/**
+ * Get the name of the instance of the AI to create.
+ */
+ const char *GetInstanceName();
+
+ /**
* Check if we can start this AI.
*/
bool AllowStartup();
@@ -61,9 +69,9 @@
void CheckMethods(SQInteger *res, const char *name);
/**
- * Create an AI, using this AIInfo as start-template.
+ * Process the creation of a FileInfo object.
*/
- static SQInteger Constructor(HSQUIRRELVM vm);
+ static SQInteger Constructor(HSQUIRRELVM vm, AIFileInfo *info);
private:
Squirrel *engine;
@@ -75,6 +83,25 @@
const char *name;
const char *description;
const char *date;
+ const char *instance_name;
+};
+
+class AIInfo : public AIFileInfo {
+public:
+ /**
+ * Create an AI, using this AIInfo as start-template.
+ */
+ static SQInteger Constructor(HSQUIRRELVM vm);
+};
+
+class AILibrary : public AIFileInfo {
+public:
+ /**
+ * Create an AI, using this AIInfo as start-template.
+ */
+ static SQInteger Constructor(HSQUIRRELVM vm);
+
+ static SQInteger Import(HSQUIRRELVM vm);
};
#endif /* AI_INFO */
--- a/src/ai/ai_squirrel.cpp Tue Jun 10 14:08:39 2008 +0000
+++ b/src/ai/ai_squirrel.cpp Tue Jun 10 14:11:35 2008 +0000
@@ -18,7 +18,7 @@
#include "ai_info.hpp"
#include "ai_squirrel.hpp"
-void AISquirrel::ScanDir(const char *dirname)
+void AISquirrel::ScanDir(const char *dirname, bool library_dir, char *library_depth)
{
extern bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb);
extern bool FiosIsHiddenFile(const struct dirent *ent);
@@ -46,6 +46,11 @@
ttd_strlcpy(script_name, dirname, sizeof(script_name));
ttd_strlcat(script_name, d_name, sizeof(script_name));
ttd_strlcat(script_name, PATHSEP, sizeof(script_name));
+
+ if (library_dir && library_depth == NULL) {
+ ScanDir(script_name, library_dir, d_name);
+ continue;
+ }
}
if (sb.st_mode & S_IFREG) {
char *ext = strrchr(d_name, '.');
@@ -64,20 +69,42 @@
*ext = '\0';
}
- /* We look for the file 'info.nut' inside the AI dir.. if it doesn't exists, it isn't an AI */
- ttd_strlcat(script_name, "info.nut", sizeof(script_name));
- if (FioCheckFileExists(script_name, AI_DIR)) {
- char load_script[MAX_PATH];
- snprintf(load_script, sizeof(load_script), "%s", script_name);
+ if (!library_dir) {
+ /* We look for the file 'info.nut' inside the AI dir.. if it doesn't exists, it isn't an AI */
+ ttd_strlcat(script_name, "info.nut", sizeof(script_name));
+ if (FioCheckFileExists(script_name, AI_DIR)) {
+ char load_script[MAX_PATH];
+ ttd_strlcpy(load_script, script_name, sizeof(load_script));
- /* Remove the 'info.nut' part and replace it with 'main.nut' */
- script_name[strlen(script_name) - 8] = '\0';
- ttd_strlcat(script_name, "main.nut", sizeof(script_name));
+ /* Remove the 'info.nut' part and replace it with 'main.nut' */
+ script_name[strlen(script_name) - 8] = '\0';
+ ttd_strlcat(script_name, "main.nut", sizeof(script_name));
- DEBUG(ai, 6, "[squirrel] Loading script '%s' for AI handling", load_script);
- this->current_script = script_name;
- this->current_dir = d_name;
- this->engine->LoadScript(load_script);
+ DEBUG(ai, 6, "[squirrel] Loading script '%s' for AI handling", load_script);
+ this->current_script = script_name;
+ this->current_dir = d_name;
+ this->engine->LoadScript(load_script);
+ }
+ } else {
+ /* We look for the file 'library.nut' inside the library dir.. */
+ ttd_strlcat(script_name, "library.nut", sizeof(script_name));
+ if (FioCheckFileExists(script_name, AI_DIR)) {
+ char load_script[MAX_PATH];
+ char dir_name[MAX_PATH];
+ 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));
+
+ /* Remove the 'library.nut' part and replace it with 'main.nut' */
+ script_name[strlen(script_name) - 11] = '\0';
+ ttd_strlcat(script_name, "main.nut", sizeof(script_name));
+
+ DEBUG(ai, 6, "[squirrel] Loading script '%s' for Squirrel library", load_script);
+ this->current_script = script_name;
+ this->current_dir = dir_name;
+ this->engine->LoadScript(load_script);
+ }
}
}
closedir(dir);
@@ -85,12 +112,17 @@
AISquirrel::AISquirrel()
{
+ this->library_instance_count = 0;
this->engine = new Squirrel();
/* Create the AIInfo class, and add the RegisterAI function */
this->engine->AddClassBegin("AIInfo");
this->engine->AddClassEnd();
this->engine->AddMethod("RegisterAI", &AIInfo::Constructor, 2, "tx");
+ /* Create the AILibrary class, and add the RegisterLibrary function */
+ this->engine->AddClassBegin("AILibrary");
+ this->engine->AddClassEnd();
+ this->engine->AddMethod("RegisterLibrary", &AILibrary::Constructor, 2, "tx");
/* Mark this class as global pointer */
this->engine->SetGlobalPointer(this);
@@ -101,7 +133,9 @@
FOR_ALL_SEARCHPATHS(sp) {
FioAppendDirectory(buf, MAX_PATH, sp, AI_DIR);
- if (FileExists(buf)) this->ScanDir(buf);
+ if (FileExists(buf)) this->ScanDir(buf, false);
+ ttd_strlcat(buf, "library" PATHSEP, MAX_PATH);
+ if (FileExists(buf)) this->ScanDir(buf, true);
}
}
@@ -116,6 +150,93 @@
delete this->engine;
}
+bool AISquirrel::ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm)
+{
+ AILibraryList::iterator iter = this->library_list.find(library);
+ /* Check if the library exists */
+ 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());
+ sq_throwerror(vm, OTTD2FS(error));
+ return false;
+ }
+
+ /* Create a fake internal name */
+ char fake_class[1024];
+ snprintf(fake_class, sizeof(fake_class), "_internalNA%d", ++this->library_instance_count);
+
+ /* 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);
+
+ /* Find the real class inside the fake class (like 'sets.Vector') */
+ sq_pushroottable(vm);
+ sq_pushstring(vm, OTTD2FS(fake_class), -1);
+ if (SQ_FAILED(sq_get(vm, -2))) {
+ sq_throwerror(vm, _SC("internal error assigning library class"));
+ return false;
+ }
+ 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);
+ sq_throwerror(vm, OTTD2FS(error));
+ return false;
+ }
+ HSQOBJECT obj;
+ sq_getstackobj(vm, -1, &obj);
+ sq_pop(vm, 3);
+
+ /* Now link the name the user wanted to our 'fake' class */
+ sq_pushroottable(vm);
+ sq_pushstring(vm, OTTD2FS(class_name), -1);
+ sq_pushobject(vm, obj);
+ sq_newclass(vm, SQTrue);
+ sq_newslot(vm, -3, SQFalse);
+ sq_pop(vm, 1);
+
+ return true;
+}
+
+void AISquirrel::RegisterLibrary(AILibrary *library)
+{
+ const char *ai_name = library->GetDirName();
+
+ /* 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, " 1: %s", this->library_list[ai_name]->GetScriptName());
+ DEBUG(ai, 0, " 2: %s", library->GetScriptName());
+ DEBUG(ai, 0, "The first is taking precedence");
+ }
+ /* Delete the new AILibrary, as we will be using the old one */
+ delete library;
+ return;
+ }
+ this->library_list[ai_name] = library;
+}
+
void AISquirrel::RegisterAI(AIInfo *info)
{
const char *ai_name = info->GetDirName();
--- a/src/ai/ai_squirrel.hpp Tue Jun 10 14:08:39 2008 +0000
+++ b/src/ai/ai_squirrel.hpp Tue Jun 10 14:11:35 2008 +0000
@@ -14,6 +14,16 @@
~AISquirrel();
/**
+ * Import a library inside the Squirrel VM.
+ */
+ bool ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm);
+
+ /**
+ * Register a library to be put in the available list.
+ */
+ void RegisterLibrary(class AILibrary *library);
+
+ /**
* Register an AI to be put in the available list.
*/
void RegisterAI(class AIInfo *info);
@@ -55,16 +65,23 @@
private:
typedef std::map<const char *, class AIInfo *, ltstr> AIInfoList;
+ typedef std::map<const char *, class AILibrary *, ltstr> AILibraryList;
/**
- * Scan a dir for AIs. If found, AIInfo is created, and the AI is registered to the central system.
+ * Scan a dir for AIs.
+ * For non-library-scan, if an AI is found, AIInfo is created, and the AI
+ * is registered to the central system.
+ * For library-scan, if a library is found, AILibrary is created, and the
+ * library is registered to the central system.
*/
- void ScanDir(const char *dirname);
+ void ScanDir(const char *dirname, bool library_dir, char *library_depth = NULL);
AIInfoList info_list;
+ AILibraryList library_list;
class Squirrel *engine;
char *current_script;
char *current_dir;
+ int library_instance_count;
};
#endif /* AI_SQUIRREL_HPP */
--- a/src/ai/api/ai_controller.cpp Tue Jun 10 14:08:39 2008 +0000
+++ b/src/ai/api/ai_controller.cpp Tue Jun 10 14:11:35 2008 +0000
@@ -15,6 +15,7 @@
#include "../../squirrel_std.hpp"
#include "ai_controller.hpp"
#include "../ai_threads.h"
+#include "../ai_info.hpp"
/* Convert all AI related classes to Squirrel data.
* Note: this line a marker in squirrel_export.sh. Do not change! */
@@ -72,6 +73,8 @@
void AIController::RegisterClasses()
{
+ this->engine->AddMethod("import", &AILibrary::Import, 4, "tssi");
+
/* Register all classes */
squirrel_register_std(this->engine);
SQAIAbstractList_Register(this->engine);