mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-12 18:40:29 +00:00
(svn r23295) -Codechange: put ImportLibrary in AIController (and document the parameters for NoAI docs)
This commit is contained in:
parent
492c96d214
commit
d03bbdd4ac
@ -134,8 +134,8 @@ public:
|
||||
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
|
||||
|
@ -322,9 +322,9 @@ void CcAI(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
|
||||
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()
|
||||
|
@ -372,14 +372,3 @@ int AIInfo::GetSettingDefaultValue(const char *name) const
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -146,13 +146,6 @@ public:
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
|
@ -122,10 +122,7 @@ void AIInstance::Initialize(AIInfo *info)
|
||||
|
||||
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 */
|
||||
|
@ -78,6 +78,7 @@ private:
|
||||
class AIInstance {
|
||||
public:
|
||||
friend class AIObject;
|
||||
friend class AIController;
|
||||
|
||||
/**
|
||||
* Create a new AI.
|
||||
|
@ -95,7 +95,7 @@ AIScanner::~AIScanner()
|
||||
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 @@ bool AIScanner::ImportLibrary(const char *library, const char *class_name, int v
|
||||
|
||||
/* Check if the library + version exists */
|
||||
AILibraryList::iterator iter = this->library_list.find(library_name);
|
||||
if (iter == this->library_list.end()) {
|
||||
char error[1024];
|
||||
if (iter == this->library_list.end()) return NULL;
|
||||
|
||||
/* 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);
|
||||
|
||||
/* 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)
|
||||
|
@ -24,9 +24,12 @@ public:
|
||||
~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.
|
||||
|
@ -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 @@ AIController::~AIController()
|
||||
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);
|
||||
|
||||
void AIController::AddLoadedLibrary(const char *library_name, const char *fake_class_name)
|
||||
{
|
||||
this->loaded_library[strdup(library_name)] = strdup(fake_class_name);
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -109,6 +109,16 @@ public:
|
||||
*/
|
||||
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 @@ private:
|
||||
* 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 */
|
||||
|
@ -15,6 +15,7 @@ void SQAIController_Register(Squirrel *engine)
|
||||
{
|
||||
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 @@ void SQAIController_Register(Squirrel *engine)
|
||||
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");
|
||||
}
|
||||
|
@ -58,6 +58,7 @@ protected:
|
||||
public:
|
||||
friend class AIScanner;
|
||||
friend class AIInstance;
|
||||
friend class AIController;
|
||||
friend void squirrel_register_std(Squirrel *engine);
|
||||
|
||||
Squirrel();
|
||||
|
@ -92,6 +92,7 @@ namespace SQConvert {
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user