ai_instance.cpp

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

Generated on Sun Nov 15 15:40:09 2009 for OpenTTD by  doxygen 1.5.6