summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ai/ai_core.cpp17
-rw-r--r--src/ai/ai_gui.cpp17
-rw-r--r--src/ai/ai_instance.cpp57
-rw-r--r--src/ai/ai_instance.hpp32
-rw-r--r--src/ai/api/ai_controller.cpp4
-rw-r--r--src/ai/api/ai_execmode.cpp3
-rw-r--r--src/ai/api/ai_object.cpp27
-rw-r--r--src/ai/api/ai_object.hpp30
-rw-r--r--src/ai/api/ai_testmode.cpp3
9 files changed, 138 insertions, 52 deletions
diff --git a/src/ai/ai_core.cpp b/src/ai/ai_core.cpp
index b98c88c30..18eeef3b0 100644
--- a/src/ai/ai_core.cpp
+++ b/src/ai/ai_core.cpp
@@ -52,7 +52,8 @@
c->ai_info = info;
assert(c->ai_instance == NULL);
- c->ai_instance = new AIInstance(info);
+ c->ai_instance = new AIInstance();
+ c->ai_instance->Initialize(info);
cur_company.Restore();
@@ -214,7 +215,7 @@
/* Queue the event */
Backup<CompanyByte> cur_company(_current_company, company, FILE_LINE);
- AIEventController::InsertEvent(event);
+ Company::Get(_current_company)->ai_instance->InsertEvent(event);
cur_company.Restore();
event->Release();
@@ -248,15 +249,7 @@
*/
void CcAI(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
{
- AIObject::SetLastCommandRes(result.Succeeded());
-
- if (result.Failed()) {
- AIObject::SetLastError(AIError::StringToError(result.GetErrorMessage()));
- } else {
- AIObject::IncreaseDoCommandCosts(result.GetCost());
- AIObject::SetLastCost(result.GetCost());
- }
-
+ Company::Get(_current_company)->ai_instance->DoCommandCallback(result, tile, p1, p2);
Company::Get(_current_company)->ai_instance->Continue();
}
@@ -327,7 +320,7 @@ void CcAI(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
/* static */ bool AI::ImportLibrary(const char *library, const char *class_name, int version, HSQUIRRELVM vm)
{
- return AI::ai_scanner->ImportLibrary(library, class_name, version, vm, Company::Get(_current_company)->ai_instance->GetController());
+ return AI::ai_scanner->ImportLibrary(library, class_name, version, vm, AIObject::GetActiveInstance()->GetController());
}
/* static */ void AI::Rescan()
diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp
index 96c5bb0ed..d8b55c6c2 100644
--- a/src/ai/ai_gui.cpp
+++ b/src/ai/ai_gui.cpp
@@ -931,9 +931,7 @@ struct AIDebugWindow : public QueryStringBaseWindow {
/* If there are no active companies, don't display anything else. */
if (ai_debug_company == INVALID_COMPANY) return;
- Backup<CompanyByte> cur_company(_current_company, ai_debug_company, FILE_LINE);
- AILog::LogData *log = (AILog::LogData *)AIObject::GetLogPointer();
- cur_company.Restore();
+ AILog::LogData *log = (AILog::LogData *)Company::Get(ai_debug_company)->ai_instance->GetLogPointer();
int scroll_count = (log == NULL) ? 0 : log->used;
if (this->vscroll->GetCount() != scroll_count) {
@@ -986,9 +984,7 @@ struct AIDebugWindow : public QueryStringBaseWindow {
switch (widget) {
case AID_WIDGET_LOG_PANEL: {
- Backup<CompanyByte> cur_company(_current_company, ai_debug_company, FILE_LINE);
- AILog::LogData *log = (AILog::LogData *)AIObject::GetLogPointer();
- cur_company.Restore();
+ AILog::LogData *log = (AILog::LogData *)Company::Get(ai_debug_company)->ai_instance->GetLogPointer();
if (log == NULL) return;
int y = this->top_offset;
@@ -1029,9 +1025,7 @@ struct AIDebugWindow : public QueryStringBaseWindow {
this->RaiseWidget(ai_debug_company + AID_WIDGET_COMPANY_BUTTON_START);
ai_debug_company = show_ai;
- Backup<CompanyByte> cur_company(_current_company, ai_debug_company, FILE_LINE);
- AILog::LogData *log = (AILog::LogData *)AIObject::GetLogPointer();
- cur_company.Restore();
+ AILog::LogData *log = (AILog::LogData *)Company::Get(ai_debug_company)->ai_instance->GetLogPointer();
this->vscroll->SetCount((log == NULL) ? 0 : log->used);
this->LowerWidget(ai_debug_company + AID_WIDGET_COMPANY_BUTTON_START);
@@ -1130,8 +1124,7 @@ struct AIDebugWindow : public QueryStringBaseWindow {
* This needs to be done in gameloop-scope, so the AI is suspended immediately. */
if (!gui_scope && data == ai_debug_company && this->break_check_enabled && !StrEmpty(this->edit_str_buf)) {
/* Get the log instance of the active company */
- Backup<CompanyByte> cur_company(_current_company, ai_debug_company, FILE_LINE);
- AILog::LogData *log = (AILog::LogData *)AIObject::GetLogPointer();
+ AILog::LogData *log = (AILog::LogData *)Company::Get(ai_debug_company)->ai_instance->GetLogPointer();
if (log != NULL && case_sensitive_break_check?
strstr(log->lines[log->pos], this->edit_str_buf) != 0 :
@@ -1149,8 +1142,6 @@ struct AIDebugWindow : public QueryStringBaseWindow {
/* Highlight row that matched */
this->highlight_row = log->pos;
}
-
- cur_company.Restore();
}
}
diff --git a/src/ai/ai_instance.cpp b/src/ai/ai_instance.cpp
index dbc8970b1..2333ddd2e 100644
--- a/src/ai/ai_instance.cpp
+++ b/src/ai/ai_instance.cpp
@@ -100,7 +100,7 @@ static void PrintFunc(bool error_msg, const SQChar *message)
AIController::Print(error_msg, SQ2OTTD(message));
}
-AIInstance::AIInstance(AIInfo *info) :
+AIInstance::AIInstance() :
controller(NULL),
storage(NULL),
engine(NULL),
@@ -111,13 +111,16 @@ AIInstance::AIInstance(AIInfo *info) :
suspend(0),
callback(NULL)
{
- /* Set the instance already, so we can use AIObject::Set commands */
- Company::Get(_current_company)->ai_instance = this;
+ this->storage = new AIStorage();
+ this->engine = new Squirrel();
+ this->engine->SetPrintFunction(&PrintFunc);
+}
+
+void AIInstance::Initialize(AIInfo *info)
+{
+ AIObject::ActiveInstance active(this);
this->controller = new AIController();
- this->storage = new AIStorage();
- this->engine = new Squirrel();
- this->engine->SetPrintFunction(&PrintFunc);
/* The import method is available at a very early stage */
this->engine->AddMethod("import", &AILibrary::Import, 4, ".ssi");
@@ -163,6 +166,8 @@ AIInstance::AIInstance(AIInfo *info) :
AIInstance::~AIInstance()
{
+ AIObject::ActiveInstance active(this);
+
if (instance != NULL) this->engine->ReleaseObject(this->instance);
if (engine != NULL) delete this->engine;
delete this->storage;
@@ -316,6 +321,8 @@ void AIInstance::Died()
void AIInstance::GameLoop()
{
+ AIObject::ActiveInstance active(this);
+
if (this->IsDead()) return;
if (this->engine->HasScriptCrashed()) {
/* The script crashed during saving, kill it here. */
@@ -423,10 +430,16 @@ void AIInstance::CollectGarbage() const
instance->engine->InsertResult(AIObject::GetNewGroupID());
}
-/* static */ AIStorage *AIInstance::GetStorage()
+AIStorage *AIInstance::GetStorage()
{
- assert(Company::IsValidAiID(_current_company));
- return Company::Get(_current_company)->ai_instance->storage;
+ return this->storage;
+}
+
+void *AIInstance::GetLogPointer()
+{
+ AIObject::ActiveInstance active(this);
+
+ return AIObject::GetLogPointer();
}
/*
@@ -598,6 +611,8 @@ static const uint AISAVE_MAX_DEPTH = 25; ///< The maximum recursive depth for it
void AIInstance::Save()
{
+ AIObject::ActiveInstance active(this);
+
/* Don't save data if the AI didn't start yet or if it crashed. */
if (this->engine == NULL || this->engine->HasScriptCrashed()) {
SaveEmpty();
@@ -662,7 +677,6 @@ void AIInstance::Save()
_ai_sl_byte = 0;
SlObject(NULL, _ai_byte);
}
-
}
void AIInstance::Suspend()
@@ -739,6 +753,8 @@ void AIInstance::Suspend()
void AIInstance::Load(int version)
{
+ AIObject::ActiveInstance active(this);
+
if (this->engine == NULL || version == -1) {
LoadEmpty();
return;
@@ -795,3 +811,24 @@ SQInteger AIInstance::GetOpsTillSuspend()
{
return this->engine->GetOpsTillSuspend();
}
+
+void AIInstance::DoCommandCallback(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
+{
+ AIObject::ActiveInstance active(this);
+
+ AIObject::SetLastCommandRes(result.Succeeded());
+
+ if (result.Failed()) {
+ AIObject::SetLastError(AIError::StringToError(result.GetErrorMessage()));
+ } else {
+ AIObject::IncreaseDoCommandCosts(result.GetCost());
+ AIObject::SetLastCost(result.GetCost());
+ }
+}
+
+void AIInstance::InsertEvent(class AIEvent *event)
+{
+ AIObject::ActiveInstance active(this);
+
+ AIEventController::InsertEvent(event);
+}
diff --git a/src/ai/ai_instance.hpp b/src/ai/ai_instance.hpp
index 65884dc71..b0b32b3b5 100644
--- a/src/ai/ai_instance.hpp
+++ b/src/ai/ai_instance.hpp
@@ -81,12 +81,17 @@ public:
/**
* Create a new AI.
- * @param info The AI to create the instance of.
*/
- AIInstance(class AIInfo *info);
+ AIInstance();
~AIInstance();
/**
+ * Initialize the AI and prepare it for its first run.
+ * @param info The AI to create the instance of.
+ */
+ void Initialize(class AIInfo *info);
+
+ /**
* An AI in multiplayer waits for the server to handle his DoCommand.
* It keeps waiting for this until this function is called.
*/
@@ -105,7 +110,12 @@ public:
/**
* Get the storage of this AI.
*/
- static class AIStorage *GetStorage();
+ class AIStorage *GetStorage();
+
+ /**
+ * Get the log pointer of this AI.
+ */
+ void *GetLogPointer();
/**
* Return a true/false reply for a DoCommand.
@@ -173,6 +183,22 @@ public:
* @return The number of operations to execute.
*/
SQInteger GetOpsTillSuspend();
+
+ /**
+ * DoCommand callback function for all commands executed by AIs.
+ * @param result The result of the command.
+ * @param tile The tile on which the command was executed.
+ * @param p1 p1 as given to DoCommandPInternal.
+ * @param p2 p2 as given to DoCommandPInternal.
+ */
+ void DoCommandCallback(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2);
+
+ /**
+ * Insert an event for this AI.
+ * @param event The event to insert.
+ */
+ void InsertEvent(class AIEvent *event);
+
private:
class AIController *controller; ///< The AI main class.
class AIStorage *storage; ///< Some global information for each running AI.
diff --git a/src/ai/api/ai_controller.cpp b/src/ai/api/ai_controller.cpp
index 0c478cf4a..78dee1d21 100644
--- a/src/ai/api/ai_controller.cpp
+++ b/src/ai/api/ai_controller.cpp
@@ -63,12 +63,12 @@ AIController::~AIController()
/* static */ uint AIController::GetTick()
{
- return ::Company::Get(_current_company)->ai_instance->GetController()->ticks;
+ return AIObject::GetActiveInstance()->GetController()->ticks;
}
/* static */ int AIController::GetOpsTillSuspend()
{
- return ::Company::Get(_current_company)->ai_instance->GetOpsTillSuspend();
+ return AIObject::GetActiveInstance()->GetOpsTillSuspend();
}
/* static */ int AIController::GetSetting(const char *name)
diff --git a/src/ai/api/ai_execmode.cpp b/src/ai/api/ai_execmode.cpp
index e661a1068..f5e1e502b 100644
--- a/src/ai/api/ai_execmode.cpp
+++ b/src/ai/api/ai_execmode.cpp
@@ -32,9 +32,8 @@ AIExecMode::AIExecMode()
AIExecMode::~AIExecMode()
{
if (this->GetDoCommandModeInstance() != this) {
- AIInstance *instance = Company::Get(_current_company)->ai_instance;
/* Ignore this error if the AI already died. */
- if (!instance->IsDead()) {
+ if (!AIObject::GetActiveInstance()->IsDead()) {
throw AI_FatalError("AIExecMode object was removed while it was not the latest AI*Mode object created.");
}
}
diff --git a/src/ai/api/ai_object.cpp b/src/ai/api/ai_object.cpp
index 4c415524b..53f2f2b55 100644
--- a/src/ai/api/ai_object.cpp
+++ b/src/ai/api/ai_object.cpp
@@ -12,8 +12,6 @@
#include "../../stdafx.h"
#include "../../script/squirrel.hpp"
#include "../../command_func.h"
-#include "../../company_base.h"
-#include "../../company_func.h"
#include "../../network/network.h"
#include "../../tunnelbridge.h"
@@ -27,9 +25,30 @@
*/
static AIStorage *GetStorage()
{
- return AIInstance::GetStorage();
+ return AIObject::GetActiveInstance()->GetStorage();
}
+
+/* static */ AIInstance *AIObject::ActiveInstance::active = NULL;
+
+AIObject::ActiveInstance::ActiveInstance(AIInstance *instance)
+{
+ this->last_active = AIObject::ActiveInstance::active;
+ AIObject::ActiveInstance::active = instance;
+}
+
+AIObject::ActiveInstance::~ActiveInstance()
+{
+ AIObject::ActiveInstance::active = this->last_active;
+}
+
+/* static */ AIInstance *AIObject::GetActiveInstance()
+{
+ assert(AIObject::ActiveInstance::active != NULL);
+ return AIObject::ActiveInstance::active;
+}
+
+
/* static */ void AIObject::SetDoCommandDelay(uint ticks)
{
assert(ticks > 0);
@@ -179,7 +198,7 @@ static AIStorage *GetStorage()
/* static */ bool AIObject::CanSuspend()
{
- Squirrel *squirrel = Company::Get(_current_company)->ai_instance->engine;
+ Squirrel *squirrel = AIObject::GetActiveInstance()->engine;
return GetStorage()->allow_do_command && squirrel->CanSuspend();
}
diff --git a/src/ai/api/ai_object.hpp b/src/ai/api/ai_object.hpp
index 3df150bac..deac277dd 100644
--- a/src/ai/api/ai_object.hpp
+++ b/src/ai/api/ai_object.hpp
@@ -35,10 +35,26 @@ typedef bool (AIModeProc)();
* command processing, and command-validation checks.
*/
class AIObject : public SimpleCountedObject {
-friend void CcAI(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2);
friend class AIInstance;
-friend class AIController;
#ifndef DOXYGEN_AI_DOCS
+protected:
+ /**
+ * A class that handles the current active instance. By instantiating it at
+ * the beginning of a function with the current active instance, it remains
+ * active till the scope of the variable closes. It then automatically
+ * reverts to the active instance it was before instantiating.
+ */
+ class ActiveInstance {
+ friend class AIObject;
+ public:
+ ActiveInstance(AIInstance *instance);
+ ~ActiveInstance();
+ private:
+ AIInstance *last_active; ///< The active instance before we go instantiated.
+
+ static AIInstance *active; ///< The global current active instance.
+ };
+
public:
/**
* Store the latest result of a DoCommand per company.
@@ -47,9 +63,10 @@ public:
static void SetLastCommandRes(bool res);
/**
- * Get the pointer to store log message in.
+ * Get the currently active instance.
+ * @return The instance.
*/
- static void *&GetLogPointer();
+ static class AIInstance *GetActiveInstance();
protected:
/**
@@ -197,6 +214,11 @@ protected:
*/
static void *&GetEventPointer();
+ /**
+ * Get the pointer to store log message in.
+ */
+ static void *&GetLogPointer();
+
private:
/**
* Store a new_vehicle_id per company.
diff --git a/src/ai/api/ai_testmode.cpp b/src/ai/api/ai_testmode.cpp
index 996b27874..6e2f515b4 100644
--- a/src/ai/api/ai_testmode.cpp
+++ b/src/ai/api/ai_testmode.cpp
@@ -32,9 +32,8 @@ AITestMode::AITestMode()
AITestMode::~AITestMode()
{
if (this->GetDoCommandModeInstance() != this) {
- AIInstance *instance = Company::Get(_current_company)->ai_instance;
/* Ignore this error if the AI already died. */
- if (!instance->IsDead()) {
+ if (!AIObject::GetActiveInstance()->IsDead()) {
throw AI_FatalError("AITestmode object was removed while it was not the latest AI*Mode object created.");
}
}