# ai_instance.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00012 #include "../stdafx.h"
    00013 #include "../debug.h"
    00014 #include "../vehicle_base.h"
    00015 #include "../saveload/saveload.h"
    00016 #include "../gui.h"
    00017 #include "table/strings.h"
    00018
    00019 #include <squirrel.h>
    00020 #include "../script/squirrel.hpp"
    00021 #include "../script/squirrel_helper.hpp"
    00022 #include "../script/squirrel_class.hpp"
    00023
    00024 #include "ai_config.hpp"
    00025 #include "ai_storage.hpp"
    00026 #include "ai_instance.hpp"
    00027 #include "ai_gui.hpp"
    00028
    00029 /* Convert all AI related classes to Squirrel data.
    00030  * Note: this line a marker in squirrel_export.sh. Do not change! */
    00031 #include "api/ai_abstractlist.hpp.sq"
    00032 #include "api/ai_accounting.hpp.sq"
    00033 #include "api/ai_airport.hpp.sq"
    00034 #include "api/ai_base.hpp.sq"
    00035 #include "api/ai_basestation.hpp.sq"
    00036 #include "api/ai_bridge.hpp.sq"
    00037 #include "api/ai_bridgelist.hpp.sq"
    00038 #include "api/ai_buoylist.hpp.sq"
    00039 #include "api/ai_cargo.hpp.sq"
    00040 #include "api/ai_cargolist.hpp.sq"
    00041 #include "api/ai_company.hpp.sq"
    00042 #include "api/ai_controller.hpp.sq"
    00043 #include "api/ai_date.hpp.sq"
    00044 #include "api/ai_depotlist.hpp.sq"
    00045 #include "api/ai_engine.hpp.sq"
    00046 #include "api/ai_enginelist.hpp.sq"
    00047 #include "api/ai_error.hpp.sq"
    00048 #include "api/ai_event.hpp.sq"
    00049 #include "api/ai_event_types.hpp.sq"
    00050 #include "api/ai_execmode.hpp.sq"
    00051 #include "api/ai_gamesettings.hpp.sq"
    00052 #include "api/ai_group.hpp.sq"
    00053 #include "api/ai_grouplist.hpp.sq"
    00054 #include "api/ai_industry.hpp.sq"
    00055 #include "api/ai_industrylist.hpp.sq"
    00056 #include "api/ai_industrytype.hpp.sq"
    00057 #include "api/ai_industrytypelist.hpp.sq"
    00058 #include "api/ai_list.hpp.sq"
    00059 #include "api/ai_log.hpp.sq"
    00060 #include "api/ai_map.hpp.sq"
    00061 #include "api/ai_marine.hpp.sq"
    00062 #include "api/ai_order.hpp.sq"
    00063 #include "api/ai_rail.hpp.sq"
    00064 #include "api/ai_railtypelist.hpp.sq"
    00065 #include "api/ai_road.hpp.sq"
    00066 #include "api/ai_sign.hpp.sq"
    00067 #include "api/ai_signlist.hpp.sq"
    00068 #include "api/ai_station.hpp.sq"
    00069 #include "api/ai_stationlist.hpp.sq"
    00070 #include "api/ai_subsidy.hpp.sq"
    00071 #include "api/ai_subsidylist.hpp.sq"
    00072 #include "api/ai_testmode.hpp.sq"
    00073 #include "api/ai_tile.hpp.sq"
    00074 #include "api/ai_tilelist.hpp.sq"
    00075 #include "api/ai_town.hpp.sq"
    00076 #include "api/ai_townlist.hpp.sq"
    00077 #include "api/ai_tunnel.hpp.sq"
    00078 #include "api/ai_vehicle.hpp.sq"
    00079 #include "api/ai_vehiclelist.hpp.sq"
    00080 #include "api/ai_waypoint.hpp.sq"
    00081 #include "api/ai_waypointlist.hpp.sq"
    00082
    00083 #include "../fileio_func.h"
    00084
    00085 AIStorage::~AIStorage()
    00086 {
    00087   /* Free our pointers */
    00088   if (event_data != NULL) AIEventController::FreeEventPointer();
    00089   if (log_data != NULL) AILog::FreeLogPointer();
    00090 }
    00091
    00092 static void PrintFunc(bool error_msg, const SQChar *message)
    00093 {
    00094   /* Convert to OpenTTD internal capable string */
    00095   AIController::Print(error_msg, FS2OTTD(message));
    00096 }
    00097
    00098 AIInstance::AIInstance(AIInfo *info) :
    00099   controller(NULL),
    00100   storage(NULL),
    00101   engine(NULL),
    00102   instance(NULL),
    00103   is_started(false),
    00104   is_dead(false),
    00105   is_save_data_on_stack(false),
    00106   suspend(0),
    00107   callback(NULL)
    00108 {
    00109   /* Set the instance already, so we can use AIObject::Set commands */
    00110   Company::Get(_current_company)->ai_instance = this;
    00111
    00112   this->controller = new AIController();
    00113   this->storage    = new AIStorage();
    00114   this->engine     = new Squirrel();
    00115   this->engine->SetPrintFunction(&PrintFunc);
    00116
    00117   /* The import method is available at a very early stage */
    00118   this->engine->AddMethod("import", &AILibrary::Import, 4, ".ssi");
    00119
    00120   /* Register the AIController */
    00121   SQAIController_Register(this->engine);
    00122
    00123   /* Register the API functions and classes */
    00124   this->RegisterAPI();
    00125
    00126   if (!this->LoadCompatibilityScripts(info->GetAPIVersion())) {
    00127     this->Died();
    00128     return;
    00129   }
    00130
    00131   try {
    00132     AIObject::SetAllowDoCommand(false);
    00133     /* Load and execute the script for this AI */
    00134     const char *main_script = info->GetMainScript();
    00135     if (strcmp(main_script, "%_dummy") == 0) {
    00136       extern void AI_CreateAIDummy(HSQUIRRELVM vm);
    00137       AI_CreateAIDummy(this->engine->GetVM());
    00138     } else if (!this->engine->LoadScript(main_script) || this->engine->IsSuspended()) {
    00139       if (this->engine->IsSuspended()) AILog::Error("This AI took too long to load script. AI is not started.");
    00140       this->Died();
    00141       return;
    00142     }
    00143
    00144     /* Create the main-class */
    00145     this->instance = MallocT<SQObject>(1);
    00146     if (!this->engine->CreateClassInstance(info->GetInstanceName(), this->controller, this->instance)) {
    00147       this->Died();
    00148       return;
    00149     }
    00150     AIObject::SetAllowDoCommand(true);
    00151   } catch (AI_FatalError e) {
    00152     this->is_dead = true;
    00153     this->engine->ThrowError(e.GetErrorMessage());
    00154     this->engine->ResumeError();
    00155     this->Died();
    00156   }
    00157 }
    00158
    00159 AIInstance::~AIInstance()
    00160 {
    00161   if (instance != NULL) this->engine->ReleaseObject(this->instance);
    00162   if (engine != NULL) delete this->engine;
    00163   delete this->storage;
    00164   delete this->controller;
    00165   free(this->instance);
    00166 }
    00167
    00168 void AIInstance::RegisterAPI()
    00169 {
    00170 /* Register all classes */
    00171   squirrel_register_std(this->engine);
    00172   SQAIAbstractList_Register(this->engine);
    00173   SQAIAccounting_Register(this->engine);
    00174   SQAIAirport_Register(this->engine);
    00175   SQAIBase_Register(this->engine);
    00176   SQAIBaseStation_Register(this->engine);
    00177   SQAIBridge_Register(this->engine);
    00178   SQAIBridgeList_Register(this->engine);
    00179   SQAIBridgeList_Length_Register(this->engine);
    00180   SQAIBuoyList_Register(this->engine);
    00181   SQAICargo_Register(this->engine);
    00182   SQAICargoList_Register(this->engine);
    00183   SQAICargoList_IndustryAccepting_Register(this->engine);
    00184   SQAICargoList_IndustryProducing_Register(this->engine);
    00185   SQAICompany_Register(this->engine);
    00186   SQAIDate_Register(this->engine);
    00187   SQAIDepotList_Register(this->engine);
    00188   SQAIEngine_Register(this->engine);
    00189   SQAIEngineList_Register(this->engine);
    00190   SQAIError_Register(this->engine);
    00191   SQAIEvent_Register(this->engine);
    00192   SQAIEventCompanyAskMerger_Register(this->engine);
    00193   SQAIEventCompanyBankrupt_Register(this->engine);
    00194   SQAIEventCompanyInTrouble_Register(this->engine);
    00195   SQAIEventCompanyMerger_Register(this->engine);
    00196   SQAIEventCompanyNew_Register(this->engine);
    00197   SQAIEventController_Register(this->engine);
    00198   SQAIEventDisasterZeppelinerCleared_Register(this->engine);
    00199   SQAIEventDisasterZeppelinerCrashed_Register(this->engine);
    00200   SQAIEventEngineAvailable_Register(this->engine);
    00201   SQAIEventEnginePreview_Register(this->engine);
    00202   SQAIEventIndustryClose_Register(this->engine);
    00203   SQAIEventIndustryOpen_Register(this->engine);
    00204   SQAIEventStationFirstVehicle_Register(this->engine);
    00205   SQAIEventSubsidyAwarded_Register(this->engine);
    00206   SQAIEventSubsidyExpired_Register(this->engine);
    00207   SQAIEventSubsidyOffer_Register(this->engine);
    00208   SQAIEventSubsidyOfferExpired_Register(this->engine);
    00209   SQAIEventVehicleCrashed_Register(this->engine);
    00210   SQAIEventVehicleLost_Register(this->engine);
    00211   SQAIEventVehicleUnprofitable_Register(this->engine);
    00212   SQAIEventVehicleWaitingInDepot_Register(this->engine);
    00213   SQAIExecMode_Register(this->engine);
    00214   SQAIGameSettings_Register(this->engine);
    00215   SQAIGroup_Register(this->engine);
    00216   SQAIGroupList_Register(this->engine);
    00217   SQAIIndustry_Register(this->engine);
    00218   SQAIIndustryList_Register(this->engine);
    00219   SQAIIndustryList_CargoAccepting_Register(this->engine);
    00220   SQAIIndustryList_CargoProducing_Register(this->engine);
    00221   SQAIIndustryType_Register(this->engine);
    00222   SQAIIndustryTypeList_Register(this->engine);
    00223   SQAIList_Register(this->engine);
    00224   SQAILog_Register(this->engine);
    00225   SQAIMap_Register(this->engine);
    00226   SQAIMarine_Register(this->engine);
    00227   SQAIOrder_Register(this->engine);
    00228   SQAIRail_Register(this->engine);
    00229   SQAIRailTypeList_Register(this->engine);
    00230   SQAIRoad_Register(this->engine);
    00231   SQAISign_Register(this->engine);
    00232   SQAISignList_Register(this->engine);
    00233   SQAIStation_Register(this->engine);
    00234   SQAIStationList_Register(this->engine);
    00235   SQAIStationList_Vehicle_Register(this->engine);
    00236   SQAISubsidy_Register(this->engine);
    00237   SQAISubsidyList_Register(this->engine);
    00238   SQAITestMode_Register(this->engine);
    00239   SQAITile_Register(this->engine);
    00240   SQAITileList_Register(this->engine);
    00241   SQAITileList_IndustryAccepting_Register(this->engine);
    00242   SQAITileList_IndustryProducing_Register(this->engine);
    00243   SQAITileList_StationType_Register(this->engine);
    00244   SQAITown_Register(this->engine);
    00245   SQAITownList_Register(this->engine);
    00246   SQAITunnel_Register(this->engine);
    00247   SQAIVehicle_Register(this->engine);
    00248   SQAIVehicleList_Register(this->engine);
    00249   SQAIVehicleList_DefaultGroup_Register(this->engine);
    00250   SQAIVehicleList_Depot_Register(this->engine);
    00251   SQAIVehicleList_Group_Register(this->engine);
    00252   SQAIVehicleList_SharedOrders_Register(this->engine);
    00253   SQAIVehicleList_Station_Register(this->engine);
    00254   SQAIWaypoint_Register(this->engine);
    00255   SQAIWaypointList_Register(this->engine);
    00256   SQAIWaypointList_Vehicle_Register(this->engine);
    00257
    00258   this->engine->SetGlobalPointer(this->engine);
    00259 }
    00260
    00261 bool AIInstance::LoadCompatibilityScripts(const char *api_version)
    00262 {
    00263   char script_name[32];
    00264   seprintf(script_name, lastof(script_name), "compat_%s.nut", api_version);
    00265   char buf[MAX_PATH];
    00266   Searchpath sp;
    00267   FOR_ALL_SEARCHPATHS(sp) {
    00268     FioAppendDirectory(buf, MAX_PATH, sp, AI_DIR);
    00269     ttd_strlcat(buf, script_name, MAX_PATH);
    00270     if (!FileExists(buf)) continue;
    00271
    00272     if (this->engine->LoadScript(buf)) return true;
    00273
    00274     AILog::Error("Failed to load API compatibility script");
    00275     DEBUG(ai, 0, "Error compiling / running API compatibility script: %s", buf);
    00276     return false;
    00277   }
    00278
    00279   AILog::Warning("API compatibility script not found");
    00280   return true;
    00281 }
    00282
    00283 void AIInstance::Continue()
    00284 {
    00285   assert(this->suspend < 0);
    00286   this->suspend = -this->suspend - 1;
    00287 }
    00288
    00289 void AIInstance::Died()
    00290 {
    00291   DEBUG(ai, 0, "The AI died unexpectedly.");
    00292   this->is_dead = true;
    00293
    00294   if (this->instance != NULL) this->engine->ReleaseObject(this->instance);
    00295   delete this->engine;
    00296   this->instance = NULL;
    00297   this->engine = NULL;
    00298
    00299   ShowAIDebugWindow(_current_company);
    00300
    00301   const AIInfo *info = AIConfig::GetConfig(_current_company)->GetInfo();
    00302   if (info != NULL) {
    00303     ShowErrorMessage(STR_ERROR_AI_PLEASE_REPORT_CRASH, INVALID_STRING_ID, 0, 0);
    00304
    00305     if (info->GetURL() != NULL) {
    00306       AILog::Info("Please report the error to the following URL:");
    00307       AILog::Info(info->GetURL());
    00308     }
    00309   }
    00310 }
    00311
    00312 void AIInstance::GameLoop()
    00313 {
    00314   if (this->IsDead()) return;
    00315   if (this->engine->HasScriptCrashed()) {
    00316     /* The script crashed during saving, kill it here. */
    00317     this->Died();
    00318     return;
    00319   }
    00320   this->controller->ticks++;
    00321
    00322   if (this->suspend   < -1) this->suspend++; // Multiplayer suspend, increase up to -1.
    00323   if (this->suspend   < 0)  return;          // Multiplayer suspend, wait for Continue().
    00324   if (--this->suspend > 0)  return;          // Singleplayer suspend, decrease to 0.
    00325
    00326   /* If there is a callback to call, call that first */
    00327   if (this->callback != NULL) {
    00328     if (this->is_save_data_on_stack) {
    00329       sq_poptop(this->engine->GetVM());
    00330       this->is_save_data_on_stack = false;
    00331     }
    00332     try {
    00333       this->callback(this);
    00334     } catch (AI_VMSuspend e) {
    00335       this->suspend  = e.GetSuspendTime();
    00336       this->callback = e.GetSuspendCallback();
    00337
    00338       return;
    00339     }
    00340   }
    00341
    00342   this->suspend  = 0;
    00343   this->callback = NULL;
    00344
    00345   if (!this->is_started) {
    00346     try {
    00347       AIObject::SetAllowDoCommand(false);
    00348       /* Run the constructor if it exists. Don't allow any DoCommands in it. */
    00349       if (this->engine->MethodExists(*this->instance, "constructor")) {
    00350         if (!this->engine->CallMethod(*this->instance, "constructor", 100000) || this->engine->IsSuspended()) {
    00351           if (this->engine->IsSuspended()) AILog::Error("This AI took too long to initialize. AI is not started.");
    00352           this->Died();
    00353           return;
    00354         }
    00355       }
    00356       if (!this->CallLoad() || this->engine->IsSuspended()) {
    00357         if (this->engine->IsSuspended()) AILog::Error("This AI took too long in the Load function. AI is not started.");
    00358         this->Died();
    00359         return;
    00360       }
    00361       AIObject::SetAllowDoCommand(true);
    00362       /* Start the AI by calling Start() */
    00363       if (!this->engine->CallMethod(*this->instance, "Start",  _settings_game.ai.ai_max_opcode_till_suspend) || !this->engine->IsSuspended()) this->Died();
    00364     } catch (AI_VMSuspend e) {
    00365       this->suspend  = e.GetSuspendTime();
    00366       this->callback = e.GetSuspendCallback();
    00367     } catch (AI_FatalError e) {
    00368       this->is_dead = true;
    00369       this->engine->ThrowError(e.GetErrorMessage());
    00370       this->engine->ResumeError();
    00371       this->Died();
    00372     }
    00373
    00374     this->is_started = true;
    00375     return;
    00376   }
    00377   if (this->is_save_data_on_stack) {
    00378     sq_poptop(this->engine->GetVM());
    00379     this->is_save_data_on_stack = false;
    00380   }
    00381
    00382   /* Continue the VM */
    00383   try {
    00384     if (!this->engine->Resume(_settings_game.ai.ai_max_opcode_till_suspend)) this->Died();
    00385   } catch (AI_VMSuspend e) {
    00386     this->suspend  = e.GetSuspendTime();
    00387     this->callback = e.GetSuspendCallback();
    00388   } catch (AI_FatalError e) {
    00389     this->is_dead = true;
    00390     this->engine->ThrowError(e.GetErrorMessage());
    00391     this->engine->ResumeError();
    00392     this->Died();
    00393   }
    00394 }
    00395
    00396 void AIInstance::CollectGarbage()
    00397 {
    00398   if (this->is_started && !this->IsDead()) this->engine->CollectGarbage();
    00399 }
    00400
    00401 /* static */ void AIInstance::DoCommandReturn(AIInstance *instance)
    00402 {
    00403   instance->engine->InsertResult(AIObject::GetLastCommandRes());
    00404 }
    00405
    00406 /* static */ void AIInstance::DoCommandReturnVehicleID(AIInstance *instance)
    00407 {
    00408   instance->engine->InsertResult(AIObject::GetNewVehicleID());
    00409 }
    00410
    00411 /* static */ void AIInstance::DoCommandReturnSignID(AIInstance *instance)
    00412 {
    00413   instance->engine->InsertResult(AIObject::GetNewSignID());
    00414 }
    00415
    00416 /* static */ void AIInstance::DoCommandReturnGroupID(AIInstance *instance)
    00417 {
    00418   instance->engine->InsertResult(AIObject::GetNewGroupID());
    00419 }
    00420
    00421 /* static */ AIStorage *AIInstance::GetStorage()
    00422 {
    00423   assert(Company::IsValidAiID(_current_company));
    00424   return Company::Get(_current_company)->ai_instance->storage;
    00425 }
    00426
    00427 /*
    00428  * All data is stored in the following format:
    00429  * First 1 byte indicating if there is a data blob at all.
    00430  * 1 byte indicating the type of data.
    00431  * The data itself, this differs per type:
    00432  *  - integer: a binary representation of the integer (int32).
    00433  *  - string:  First one byte with the string length, then a 0-terminated char
    00434  *             array. The string can't be longer then 255 bytes (including
    00435  *             terminating '\0').
    00436  *  - array:   All data-elements of the array are saved recursive in this
    00437  *             format, and ended with an element of the type
    00438  *             SQSL_ARRAY_TABLE_END.
    00439  *  - table:   All key/value pairs are saved in this format (first key 1, then
    00440  *             value 1, then key 2, etc.). All keys and values can have an
    00441  *             arbitrary type (as long as it is supported by the save function
    00442  *             of course). The table is ended with an element of the type
    00443  *             SQSL_ARRAY_TABLE_END.
    00444  *  - bool:    A single byte with value 1 representing true and 0 false.
    00445  *  - null:    No data.
    00446  */
    00447
    00449 enum SQSaveLoadType {
    00450   SQSL_INT             = 0x00,
    00451   SQSL_STRING          = 0x01,
    00452   SQSL_ARRAY           = 0x02,
    00453   SQSL_TABLE           = 0x03,
    00454   SQSL_BOOL            = 0x04,
    00455   SQSL_NULL            = 0x05,
    00456   SQSL_ARRAY_TABLE_END = 0xFF,
    00457 };
    00458
    00459 static byte _ai_sl_byte;
    00460
    00461 static const SaveLoad _ai_byte[] = {
    00462   SLEG_VAR(_ai_sl_byte, SLE_UINT8),
    00463   SLE_END()
    00464 };
    00465
    00466 enum {
    00467   AISAVE_MAX_DEPTH = 25,
    00468 };
    00469
    00470 /* static */ bool AIInstance::SaveObject(HSQUIRRELVM vm, SQInteger index, int max_depth, bool test)
    00471 {
    00472   if (max_depth == 0) {
    00473     AILog::Error("Savedata can only be nested to 25 deep. No data saved.");
    00474     return false;
    00475   }
    00476
    00477   switch (sq_gettype(vm, index)) {
    00478     case OT_INTEGER: {
    00479       if (!test) {
    00480         _ai_sl_byte = SQSL_INT;
    00481         SlObject(NULL, _ai_byte);
    00482       }
    00483       SQInteger res;
    00484       sq_getinteger(vm, index, &res);
    00485       if (!test) {
    00486         int value = (int)res;
    00487         SlArray(&value, 1, SLE_INT32);
    00488       }
    00489       return true;
    00490     }
    00491
    00492     case OT_STRING: {
    00493       if (!test) {
    00494         _ai_sl_byte = SQSL_STRING;
    00495         SlObject(NULL, _ai_byte);
    00496       }
    00497       const SQChar *res;
    00498       sq_getstring(vm, index, &res);
    00499       /* @bug if a string longer than 512 characters is given to FS2OTTD, the
    00500        *  internal buffer overflows. */
    00501       const char *buf = FS2OTTD(res);
    00502       size_t len = strlen(buf) + 1;
    00503       if (len >= 255) {
    00504         AILog::Error("Maximum string length is 254 chars. No data saved.");
    00505         return false;
    00506       }
    00507       if (!test) {
    00508         _ai_sl_byte = (byte)len;
    00509         SlObject(NULL, _ai_byte);
    00510         SlArray((void*)buf, len, SLE_CHAR);
    00511       }
    00512       return true;
    00513     }
    00514
    00515     case OT_ARRAY: {
    00516       if (!test) {
    00517         _ai_sl_byte = SQSL_ARRAY;
    00518         SlObject(NULL, _ai_byte);
    00519       }
    00520       sq_pushnull(vm);
    00521       while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
    00522         /* Store the value */
    00523         bool res = SaveObject(vm, -1, max_depth - 1, test);
    00524         sq_pop(vm, 2);
    00525         if (!res) {
    00526           sq_pop(vm, 1);
    00527           return false;
    00528         }
    00529       }
    00530       sq_pop(vm, 1);
    00531       if (!test) {
    00532         _ai_sl_byte = SQSL_ARRAY_TABLE_END;
    00533         SlObject(NULL, _ai_byte);
    00534       }
    00535       return true;
    00536     }
    00537
    00538     case OT_TABLE: {
    00539       if (!test) {
    00540         _ai_sl_byte = SQSL_TABLE;
    00541         SlObject(NULL, _ai_byte);
    00542       }
    00543       sq_pushnull(vm);
    00544       while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
    00545         /* Store the key + value */
    00546         bool res = SaveObject(vm, -2, max_depth - 1, test) && SaveObject(vm, -1, max_depth - 1, test);
    00547         sq_pop(vm, 2);
    00548         if (!res) {
    00549           sq_pop(vm, 1);
    00550           return false;
    00551         }
    00552       }
    00553       sq_pop(vm, 1);
    00554       if (!test) {
    00555         _ai_sl_byte = SQSL_ARRAY_TABLE_END;
    00556         SlObject(NULL, _ai_byte);
    00557       }
    00558       return true;
    00559     }
    00560
    00561     case OT_BOOL: {
    00562       if (!test) {
    00563         _ai_sl_byte = SQSL_BOOL;
    00564         SlObject(NULL, _ai_byte);
    00565       }
    00566       SQBool res;
    00567       sq_getbool(vm, index, &res);
    00568       if (!test) {
    00569         _ai_sl_byte = res ? 1 : 0;
    00570         SlObject(NULL, _ai_byte);
    00571       }
    00572       return true;
    00573     }
    00574
    00575     case OT_NULL: {
    00576       if (!test) {
    00577         _ai_sl_byte = SQSL_NULL;
    00578         SlObject(NULL, _ai_byte);
    00579       }
    00580       return true;
    00581     }
    00582
    00583     default:
    00584       AILog::Error("You tried to save an unsupported type. No data saved.");
    00585       return false;
    00586   }
    00587 }
    00588
    00589 /* static */ void AIInstance::SaveEmpty()
    00590 {
    00591   _ai_sl_byte = 0;
    00592   SlObject(NULL, _ai_byte);
    00593 }
    00594
    00595 void AIInstance::Save()
    00596 {
    00597   /* Don't save data if the AI didn't start yet or if it crashed. */
    00598   if (this->engine == NULL || this->engine->HasScriptCrashed()) {
    00599     SaveEmpty();
    00600     return;
    00601   }
    00602
    00603   HSQUIRRELVM vm = this->engine->GetVM();
    00604   if (this->is_save_data_on_stack) {
    00605     _ai_sl_byte = 1;
    00606     SlObject(NULL, _ai_byte);
    00607     /* Save the data that was just loaded. */
    00608     SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
    00609   } else if (!this->is_started) {
    00610     SaveEmpty();
    00611     return;
    00612   } else if (this->engine->MethodExists(*this->instance, "Save")) {
    00613     HSQOBJECT savedata;
    00614     /* We don't want to be interrupted during the save function. */
    00615     bool backup_allow = AIObject::GetAllowDoCommand();
    00616     AIObject::SetAllowDoCommand(false);
    00617     try {
    00618       if (!this->engine->CallMethod(*this->instance, "Save", &savedata)) {
    00619         /* The script crashed in the Save function. We can't kill
    00620          * it here, but do so in the next AI tick. */
    00621         SaveEmpty();
    00622         this->engine->CrashOccurred();
    00623         return;
    00624       }
    00625     } catch (AI_FatalError e) {
    00626       /* If we don't mark the AI as dead here cleaning up the squirrel
    00627        * stack could throw AI_FatalError again. */
    00628       this->is_dead = true;
    00629       this->engine->ThrowError(e.GetErrorMessage());
    00630       this->engine->ResumeError();
    00631       SaveEmpty();
    00632       /* We can't kill the AI here, so mark it as crashed (not dead) and
    00633        * kill it in the next AI tick. */
    00634       this->is_dead = false;
    00635       this->engine->CrashOccurred();
    00636       return;
    00637     }
    00638     AIObject::SetAllowDoCommand(backup_allow);
    00639
    00640     if (!sq_istable(savedata)) {
    00641       AILog::Error("Save function should return a table.");
    00642       SaveEmpty();
    00643       this->engine->CrashOccurred();
    00644       return;
    00645     }
    00646     sq_pushobject(vm, savedata);
    00647     if (SaveObject(vm, -1, AISAVE_MAX_DEPTH, true)) {
    00648       _ai_sl_byte = 1;
    00649       SlObject(NULL, _ai_byte);
    00650       SaveObject(vm, -1, AISAVE_MAX_DEPTH, false);
    00651       this->is_save_data_on_stack = true;
    00652     } else {
    00653       SaveEmpty();
    00654       this->engine->CrashOccurred();
    00655     }
    00656   } else {
    00657     AILog::Warning("Save function is not implemented");
    00658     _ai_sl_byte = 0;
    00659     SlObject(NULL, _ai_byte);
    00660   }
    00661
    00662 }
    00663
    00664 /* static */ bool AIInstance::LoadObjects(HSQUIRRELVM vm)
    00665 {
    00666   SlObject(NULL, _ai_byte);
    00667   switch (_ai_sl_byte) {
    00668     case SQSL_INT: {
    00669       int value;
    00670       SlArray(&value, 1, SLE_INT32);
    00671       if (vm != NULL) sq_pushinteger(vm, (SQInteger)value);
    00672       return true;
    00673     }
    00674
    00675     case SQSL_STRING: {
    00676       SlObject(NULL, _ai_byte);
    00677       static char buf[256];
    00678       SlArray(buf, _ai_sl_byte, SLE_CHAR);
    00679       if (vm != NULL) sq_pushstring(vm, OTTD2FS(buf), -1);
    00680       return true;
    00681     }
    00682
    00683     case SQSL_ARRAY: {
    00684       if (vm != NULL) sq_newarray(vm, 0);
    00685       while (LoadObjects(vm)) {
    00686         if (vm != NULL) sq_arrayappend(vm, -2);
    00687         /* The value is popped from the stack by squirrel. */
    00688       }
    00689       return true;
    00690     }
    00691
    00692     case SQSL_TABLE: {
    00693       if (vm != NULL) sq_newtable(vm);
    00694       while (LoadObjects(vm)) {
    00695         LoadObjects(vm);
    00696         if (vm != NULL) sq_rawset(vm, -3);
    00697         /* The key (-2) and value (-1) are popped from the stack by squirrel. */
    00698       }
    00699       return true;
    00700     }
    00701
    00702     case SQSL_BOOL: {
    00703       SlObject(NULL, _ai_byte);
    00704       if (vm != NULL) sq_pushinteger(vm, (SQBool)(_ai_sl_byte != 0));
    00705       return true;
    00706     }
    00707
    00708     case SQSL_NULL: {
    00709       if (vm != NULL) sq_pushnull(vm);
    00710       return true;
    00711     }
    00712
    00713     case SQSL_ARRAY_TABLE_END: {
    00714       return false;
    00715     }
    00716
    00717     default: NOT_REACHED();
    00718   }
    00719 }
    00720
    00721 /* static */ void AIInstance::LoadEmpty()
    00722 {
    00723   SlObject(NULL, _ai_byte);
    00724   /* Check if there was anything saved at all. */
    00725   if (_ai_sl_byte == 0) return;
    00726
    00727   LoadObjects(NULL);
    00728 }
    00729
    00730 void AIInstance::Load(int version)
    00731 {
    00732   if (this->engine == NULL || version == -1) {
    00733     LoadEmpty();
    00734     return;
    00735   }
    00736   HSQUIRRELVM vm = this->engine->GetVM();
    00737
    00738   SlObject(NULL, _ai_byte);
    00739   /* Check if there was anything saved at all. */
    00740   if (_ai_sl_byte == 0) return;
    00741
    00742   sq_pushinteger(vm, version);
    00743   LoadObjects(vm);
    00744   this->is_save_data_on_stack = true;
    00745 }
    00746
    00747 bool AIInstance::CallLoad()
    00748 {
    00749   HSQUIRRELVM vm = this->engine->GetVM();
    00750   /* Is there save data that we should load? */
    00751   if (!this->is_save_data_on_stack) return true;
    00752   /* Whatever happens, after CallLoad the savegame data is removed from the stack. */
    00753   this->is_save_data_on_stack = false;
    00754
    00755   if (!this->engine->MethodExists(*this->instance, "Load")) {
    00756     AILog::Warning("Loading failed: there was data for the AI to load, but the AI does not have a Load() function.");
    00757
    00758     /* Pop the savegame data and version. */
    00759     sq_pop(vm, 2);
    00760     return true;
    00761   }
    00762
    00763   /* Go to the instance-root */
    00764   sq_pushobject(vm, *this->instance);
    00765   /* Find the function-name inside the script */
    00766   sq_pushstring(vm, OTTD2FS("Load"), -1);
    00767   /* Change the "Load" string in a function pointer */
    00768   sq_get(vm, -2);
    00769   /* Push the main instance as "this" object */
    00770   sq_pushobject(vm, *this->instance);
    00771   /* Push the version data and savegame data as arguments */
    00772   sq_push(vm, -5);
    00773   sq_push(vm, -5);
    00774
    00775   /* Call the AI load function. sq_call removes the arguments (but not the
    00776    * function pointer) from the stack. */
    00777   if (SQ_FAILED(sq_call(vm, 3, SQFalse, SQFalse, 100000))) return false;
    00778
    00779   /* Pop 1) The version, 2) the savegame data, 3) the object instance, 4) the function pointer. */
    00780   sq_pop(vm, 4);
    00781   return true;
    00782 }