(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
/* $Id$ */
/** @file ai_controller.cpp Implementation of AIControler. */
#include "../../stdafx.h"
#include "../../openttd.h"
#include "../../player_func.h"
#include "../../core/alloc_func.hpp"
#include "../../string_func.h"
#include "table/strings.h"
#include <squirrel.h>
#include "../../squirrel.hpp"
#include "../../squirrel_helper.hpp"
#include "../../squirrel_class.hpp"
#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! */
#include "ai_abstractlist.hpp.sq"
#include "ai_accounting.hpp.sq"
#include "ai_airport.hpp.sq"
#include "ai_base.hpp.sq"
#include "ai_bridge.hpp.sq"
#include "ai_bridgelist.hpp.sq"
#include "ai_cargo.hpp.sq"
#include "ai_cargolist.hpp.sq"
#include "ai_company.hpp.sq"
#include "ai_controller.hpp.sq"
#include "ai_date.hpp.sq"
#include "ai_engine.hpp.sq"
#include "ai_enginelist.hpp.sq"
#include "ai_error.hpp.sq"
#include "ai_event.hpp.sq"
#include "ai_event_types.hpp.sq"
#include "ai_execmode.hpp.sq"
#include "ai_gamesettings.hpp.sq"
#include "ai_industry.hpp.sq"
#include "ai_industrylist.hpp.sq"
#include "ai_list.hpp.sq"
#include "ai_log.hpp.sq"
#include "ai_map.hpp.sq"
#include "ai_marine.hpp.sq"
#include "ai_order.hpp.sq"
#include "ai_road.hpp.sq"
#include "ai_settings.hpp.sq"
#include "ai_sign.hpp.sq"
#include "ai_station.hpp.sq"
#include "ai_stationlist.hpp.sq"
#include "ai_subsidy.hpp.sq"
#include "ai_subsidylist.hpp.sq"
#include "ai_testmode.hpp.sq"
#include "ai_tile.hpp.sq"
#include "ai_tilelist.hpp.sq"
#include "ai_town.hpp.sq"
#include "ai_townlist.hpp.sq"
#include "ai_transactionmode.hpp.sq"
#include "ai_tunnel.hpp.sq"
#include "ai_vehicle.hpp.sq"
#include "ai_vehiclelist.hpp.sq"
/* static */ void AIController::Sleep(uint ticks)
{
AI_SuspendPlayer(_current_player, ticks);
}
/* static */ void AIController::Print(bool error_msg, const char *message)
{
AILog::Log(error_msg ? AILog::LOG_SQ_ERROR : AILog::LOG_SQ_INFO, message);
}
void AIController::RegisterClasses()
{
this->engine->AddMethod("import", &AILibrary::Import, 4, "?ssi");
/* Register all classes */
squirrel_register_std(this->engine);
SQAIAbstractList_Register(this->engine);
SQAIAccounting_Register(this->engine);
SQAIAirport_Register(this->engine);
SQAIBase_Register(this->engine);
SQAIBridge_Register(this->engine);
SQAIBridgeList_Register(this->engine);
SQAIBridgeList_Length_Register(this->engine);
SQAICargo_Register(this->engine);
SQAICargoList_Register(this->engine);
SQAICompany_Register(this->engine);
SQAIController_Register(this->engine);
SQAIDate_Register(this->engine);
SQAIEngine_Register(this->engine);
SQAIEngineList_Register(this->engine);
SQAIError_Register(this->engine);
SQAIEvent_Register(this->engine);
SQAIEventCompanyBankrupt_Register(this->engine);
SQAIEventCompanyInTrouble_Register(this->engine);
SQAIEventCompanyMerger_Register(this->engine);
SQAIEventCompanyNew_Register(this->engine);
SQAIEventController_Register(this->engine);
SQAIEventEnginePreview_Register(this->engine);
SQAIEventIndustryClose_Register(this->engine);
SQAIEventIndustryOpen_Register(this->engine);
SQAIEventSubsidyAwarded_Register(this->engine);
SQAIEventSubsidyExpired_Register(this->engine);
SQAIEventSubsidyOffer_Register(this->engine);
SQAIEventSubsidyOfferExpired_Register(this->engine);
SQAIEventTest_Register(this->engine);
SQAIEventVehicleCrash_Register(this->engine);
SQAIEventVehicleLost_Register(this->engine);
SQAIEventVehicleUnprofitable_Register(this->engine);
SQAIEventVehicleWaitingInDepot_Register(this->engine);
SQAIExecMode_Register(this->engine);
SQAIGameSettings_Register(this->engine);
SQAIIndustry_Register(this->engine);
SQAIIndustryList_Register(this->engine);
SQAIIndustryList_CargoAccepting_Register(this->engine);
SQAIIndustryList_CargoProducing_Register(this->engine);
SQAIList_Register(this->engine);
SQAILog_Register(this->engine);
SQAIMap_Register(this->engine);
SQAIMarine_Register(this->engine);
SQAIOrder_Register(this->engine);
SQAIRoad_Register(this->engine);
SQAISettings_Register(this->engine);
SQAISign_Register(this->engine);
SQAIStation_Register(this->engine);
SQAIStationList_Register(this->engine);
SQAIStationList_Vehicle_Register(this->engine);
SQAISubsidy_Register(this->engine);
SQAISubsidyList_Register(this->engine);
SQAITestMode_Register(this->engine);
SQAITile_Register(this->engine);
SQAITileList_Register(this->engine);
SQAITileList_IndustryAccepting_Register(this->engine);
SQAITileList_IndustryProducing_Register(this->engine);
SQAITileList_StationType_Register(this->engine);
SQAITown_Register(this->engine);
SQAITownList_Register(this->engine);
SQAITransactionMode_Register(this->engine);
SQAITunnel_Register(this->engine);
SQAIVehicle_Register(this->engine);
SQAIVehicleList_Register(this->engine);
SQAIVehicleList_Station_Register(this->engine);
this->engine->SetGlobalPointer(this->engine);
}
static void PrintFunc(bool error_msg, const SQChar *message)
{
/* Convert to OpenTTD internal capable string */
AIController::Print(error_msg, FS2OTTD(message));
}
AIController::AIController(const char *script, const char *class_name) :
tick(0),
engine(NULL),
SQ_instance(NULL),
loaded_library_count(0)
{
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(this->script)) {
delete this->engine;
this->engine = NULL;
return;
}
/* Create the main-class */
this->SQ_instance = MallocT<SQObject>(sizeof(SQObject));
if (!this->engine->CreateClassInstance(this->class_name, this, this->SQ_instance)) {
delete this->engine;
this->engine = NULL;
return;
}
/* Run the constructor first */
if (this->engine->MethodExists(*this->SQ_instance, "constructor")) {
this->engine->CallMethod(*this->SQ_instance, "constructor");
}
/* When that is done, start the Start() function */
this->engine->CallMethod(*this->SQ_instance, "Start");
}
AIController::~AIController()
{
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()
{
this->tick++;
}
uint AIController::GetTick()
{
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);
}