(svn r11796) [NoAI] -Sync: with trunk r11502:11795.
/* $Id$ */
/** @file squirrel.cpp allows loading squirrel scripts to control an AI */
#include "../stdafx.h"
#include "../debug.h"
#include "../openttd.h"
#include "../string_func.h"
#include "../fileio.h"
#include "../fios.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <squirrel.h>
#include "../squirrel.hpp"
#include "../squirrel_helper.hpp"
#include "../squirrel_class.hpp"
#include "../squirrel_std.hpp"
#include "api/ai_controller.hpp"
#include "ai_factory.hpp"
#include "ai_squirrel.hpp"
/* Convert all AI related classes to Squirrel data.
* Note: this line a marker in squirrel_export.sh. Do not change! */
#include "api/ai_abstractlist.hpp.sq"
#include "api/ai_accounting.hpp.sq"
#include "api/ai_airport.hpp.sq"
#include "api/ai_base.hpp.sq"
#include "api/ai_cargo.hpp.sq"
#include "api/ai_company.hpp.sq"
#include "api/ai_controller.hpp.sq"
#include "api/ai_engine.hpp.sq"
#include "api/ai_enginelist.hpp.sq"
#include "api/ai_enginelist_valuator.hpp.sq"
#include "api/ai_event.hpp.sq"
#include "api/ai_event_types.hpp.sq"
#include "api/ai_execmode.hpp.sq"
#include "api/ai_industry.hpp.sq"
#include "api/ai_industrylist.hpp.sq"
#include "api/ai_industrylist_valuator.hpp.sq"
#include "api/ai_list.hpp.sq"
#include "api/ai_list_valuator.hpp.sq"
#include "api/ai_map.hpp.sq"
#include "api/ai_marine.hpp.sq"
#include "api/ai_order.hpp.sq"
#include "api/ai_pathfinder.hpp.sq"
#include "api/ai_pathfinder_stupid.hpp.sq"
#include "api/ai_road.hpp.sq"
#include "api/ai_settings.hpp.sq"
#include "api/ai_sign.hpp.sq"
#include "api/ai_station.hpp.sq"
#include "api/ai_stationlist.hpp.sq"
#include "api/ai_stationlist_valuator.hpp.sq"
#include "api/ai_testmode.hpp.sq"
#include "api/ai_tile.hpp.sq"
#include "api/ai_tilelist.hpp.sq"
#include "api/ai_tilelist_valuator.hpp.sq"
#include "api/ai_town.hpp.sq"
#include "api/ai_townlist.hpp.sq"
#include "api/ai_townlist_valuator.hpp.sq"
#include "api/ai_transactionmode.hpp.sq"
#include "api/ai_vehicle.hpp.sq"
#include "api/ai_vehiclelist.hpp.sq"
#include "api/ai_vehiclelist_valuator.hpp.sq"
static FSquirrel iFSquirrel; ///< Tell the AI-core that we have an AI with which we like to play.
/**
* Our tiny wrapper between C++ and Squirrel.
*/
class AIFactorySquirrel: public AIFactoryBase {
public:
Squirrel *engine;
HSQOBJECT SQ_instance;
char *script_name;
~AIFactorySquirrel();
/* virtual */ const char *GetAuthor() { return this->engine->CallStringMethod (this->SQ_instance, "GetAuthor"); }
/* virtual */ const char *GetName() { return this->engine->CallStringMethod (this->SQ_instance, "GetName"); }
/* virtual */ const char *GetDescription() { return this->engine->CallStringMethod (this->SQ_instance, "GetDescription"); }
/* virtual */ int GetVersion() { return this->engine->CallIntegerMethod(this->SQ_instance, "GetVersion"); }
/* virtual */ const char *GetDate() { return this->engine->CallStringMethod (this->SQ_instance, "GetDate"); }
/* virtual */ AIController *CreateInstance();
/**
* Register Squirrel script to the Factory.
*/
void RegisterSquirrel() { this->RegisterFactory(this->GetName()); }
/**
* Check if a method exists in the script.
*/
void CheckMethods(AIFactorySquirrel *fbase, SQInteger *res, const char *name);
};
AIFactorySquirrel::~AIFactorySquirrel()
{
free(this->script_name);
}
void AIFactorySquirrel::CheckMethods(AIFactorySquirrel *fbase, SQInteger *res, const char *name)
{
if (!fbase->engine->MethodExists(fbase->SQ_instance, name)) {
char error[1024];
snprintf(error, sizeof(error), "Missing method '%s' for FactoryClass", name);
fbase->engine->ThrowError(error);
*res = SQ_ERROR;
}
}
SQInteger FSquirrel::FactoryConstructor(HSQUIRRELVM vm)
{
AIFactorySquirrel *fbase = new AIFactorySquirrel();
SQInteger res = 0;
Squirrel::GetInstance(vm, &fbase->SQ_instance);
fbase->engine = ((FSquirrel *)Squirrel::GetGlobalPointer(vm))->engine;
/* Check if all needed fields are there */
fbase->CheckMethods(fbase, &res, "GetAuthor");
fbase->CheckMethods(fbase, &res, "GetName");
fbase->CheckMethods(fbase, &res, "GetDescription");
fbase->CheckMethods(fbase, &res, "GetVersion");
fbase->CheckMethods(fbase, &res, "GetDate");
fbase->CheckMethods(fbase, &res, "CreateInstance");
/* Abort if one method was missing */
if (res != 0) return res;
fbase->RegisterSquirrel();
fbase->script_name = strdup(((FSquirrel *)Squirrel::GetGlobalPointer(vm))->current_script);
return 0;
}
extern bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb);
extern bool FiosIsHiddenFile(const struct dirent *ent);
void FSquirrel::ScanDir(const char *dirname)
{
struct stat sb;
struct dirent *dirent;
DIR *dir;
char d_name[256];
char script_name[256];
dir = ttd_opendir(dirname);
/* Dir not found, so do nothing */
if (dir == NULL) return;
/* Walk all dirs trying to find a dir in which 'main.nut' exists */
while ((dirent = readdir(dir)) != NULL) {
ttd_strlcpy(d_name, FS2OTTD(dirent->d_name), sizeof(d_name));
/* Found file must be directory, but not '.' or '..' */
if (FiosIsValidFile("ai/", dirent, &sb) && (sb.st_mode & S_IFDIR) &&
(!FiosIsHiddenFile(dirent) || strncasecmp(d_name, PERSONAL_DIR, strlen(d_name)) == 0) &&
strcmp(d_name, ".") != 0 && strcmp(d_name, "..") != 0) {
/* Create the full-length script-name */
strcpy(script_name, dirname);
strcat(script_name, PATHSEP);
strcat(script_name, d_name);
strcat(script_name, PATHSEP);
strcat(script_name, "main.nut");
/* If it exists, load it up */
if (FileExists(script_name)) {
DEBUG(ai, 6, "[squirrel] Loading script '%s' for AI handling", script_name);
this->current_script = script_name;
this->engine->LoadScript(this->current_script);
}
}
}
closedir(dir);
}
void FSquirrel::Initializer()
{
this->engine = new Squirrel();
/* Create the AIFactory class, and bind the constructor */
this->engine->AddClassBegin("AIFactory");
this->engine->AddMethod("constructor", &FSquirrel::FactoryConstructor, 1, "x");
this->engine->AddClassEnd();
/* Set a dummy AIController, so script can load */
this->engine->AddClassBegin("AIController");
this->engine->AddClassEnd();
/* Mark this class as global pointer */
this->engine->SetGlobalPointer(this);
/* Scan the AI dir for scripts */
this->ScanDir("ai");
}
FSquirrel::~FSquirrel()
{
delete this->engine;
}
AIController *AIFactorySquirrel::CreateInstance()
{
const char *class_name = this->engine->CallStringMethod(this->SQ_instance, "CreateInstance");
AIControllerSquirrel *controller = new AIControllerSquirrel(this->script_name, class_name);
return controller;
}
void AIControllerSquirrel::RegisterClasses()
{
/* Ignore AIFactory if we are really starting an AI */
this->engine->AddClassBegin("AIFactory");
this->engine->AddClassEnd();
/* Register all classes */
squirrel_register_std(this->engine);
SQAIAbstractListRegister(this->engine);
SQAIAccountingRegister(this->engine);
SQAIAirportRegister(this->engine);
SQAIBaseRegister(this->engine);
SQAICargoRegister(this->engine);
SQAICompanyRegister(this->engine);
SQAIControllerRegister(this->engine);
SQAIEngineListCapacityRegister(this->engine);
SQAIEngineListCargoTypeRegister(this->engine);
SQAIEngineListMaxSpeedRegister(this->engine);
SQAIEngineListPriceRegister(this->engine);
SQAIEngineListRegister(this->engine);
SQAIEngineListReliabilityRegister(this->engine);
SQAIEngineRegister(this->engine);
SQAIEventControllerRegister(this->engine);
SQAIEventRegister(this->engine);
SQAIEventTestRegister(this->engine);
SQAIEventVehicleCrashRegister(this->engine);
SQAIExecModeRegister(this->engine);
SQAIIndustryListCargoAcceptedRegister(this->engine);
SQAIIndustryListDistanceManhattanToTileRegister(this->engine);
SQAIIndustryListDistanceSquareToTileRegister(this->engine);
SQAIIndustryListLocationRegister(this->engine);
SQAIIndustryListProductionRegister(this->engine);
SQAIIndustryListRegister(this->engine);
SQAIIndustryRegister(this->engine);
SQAIListRandomizeRegister(this->engine);
SQAIListRegister(this->engine);
SQAIMapRegister(this->engine);
SQAIMarineRegister(this->engine);
SQAIOrderRegister(this->engine);
SQAIPathFinderRegister(this->engine);
SQAIPathFinderStupidRegister(this->engine);
SQAIRoadRegister(this->engine);
SQAISettingsRegister(this->engine);
SQAISignRegister(this->engine);
SQAIStationListCargoRatingRegister(this->engine);
SQAIStationListCargoWaitingRegister(this->engine);
SQAIStationListDistanceManhattanToTileRegister(this->engine);
SQAIStationListDistanceSquareToTileRegister(this->engine);
SQAIStationListLocationRegister(this->engine);
SQAIStationListRegister(this->engine);
SQAIStationRegister(this->engine);
SQAIStationVehicleListRegister(this->engine);
SQAITestModeRegister(this->engine);
SQAITileListBuildableRectangleRegister(this->engine);
SQAITileListBuildableRegister(this->engine);
SQAITileListCargoAcceptanceRegister(this->engine);
SQAITileListDistanceManhattanToTileRegister(this->engine);
SQAITileListDistanceSquareToTileRegister(this->engine);
SQAITileListHeightRegister(this->engine);
SQAITileListNeighbourRoadCountRegister(this->engine);
SQAITileListRegister(this->engine);
SQAITileListRoadTileRegister(this->engine);
SQAITileListSlopeRegister(this->engine);
SQAITileListWaterRegister(this->engine);
SQAITileRegister(this->engine);
SQAITownListDistanceManhattanToTileRegister(this->engine);
SQAITownListDistanceSquareToTileRegister(this->engine);
SQAITownListLocationRegister(this->engine);
SQAITownListPopulationRegister(this->engine);
SQAITownListRandomizeRegister(this->engine);
SQAITownListRegister(this->engine);
SQAITownRegister(this->engine);
SQAITransactionModeRegister(this->engine);
SQAIVehicleListAgeLeftRegister(this->engine);
SQAIVehicleListAgeRegister(this->engine);
SQAIVehicleListEngineTypeRegister(this->engine);
SQAIVehicleListLocationRegister(this->engine);
SQAIVehicleListMaxAgeRegister(this->engine);
SQAIVehicleListProfitLastYearRegister(this->engine);
SQAIVehicleListProfitThisYearRegister(this->engine);
SQAIVehicleListRegister(this->engine);
SQAIVehicleListUnitNumberRegister(this->engine);
SQAIVehicleListVehicleTypeRegister(this->engine);
SQAIVehicleRegister(this->engine);
SQAIVehicleStationListRegister(this->engine);
this->engine->SetGlobalPointer(this->engine);
}
AIControllerSquirrel::AIControllerSquirrel(const char *script, const char *class_name)
{
this->engine = new Squirrel();
this->RegisterClasses();
this->engine->LoadScript(script);
/* Create the main-class */
this->engine->CreateClassInstance(class_name, this, &this->SQ_instance);
this->engine->CallMethod(this->SQ_instance, "constructor");
}
AIControllerSquirrel::~AIControllerSquirrel()
{
delete this->engine;
}
/* virtual */ void AIControllerSquirrel::Start()
{
this->engine->CallMethod(this->SQ_instance, "Start");
}
/* virtual */ void AIControllerSquirrel::Stop()
{
this->engine->CallMethod(this->SQ_instance, "Stop");
}