src/ai/api/ai_controller.cpp
author truebrain
Fri, 13 Jun 2008 20:19:00 +0000
branchnoai
changeset 10958 65088d587094
parent 10902 57b380ee1607
child 10971 aaf89f8c59b9
permissions -rw-r--r--
(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);
}