ai_instance.cpp

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

Generated on Fri Dec 31 17:15:28 2010 for OpenTTD by  doxygen 1.6.1