00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "../stdafx.h"
00013 #include "../debug.h"
00014 #include "../saveload/saveload.h"
00015
00016 #include "../script/squirrel_class.hpp"
00017
00018 #include "script_fatalerror.hpp"
00019 #include "script_storage.hpp"
00020 #include "script_info.hpp"
00021 #include "script_instance.hpp"
00022
00023 #include "api/script_controller.hpp"
00024 #include "api/script_error.hpp"
00025 #include "api/script_event.hpp"
00026 #include "api/script_log.hpp"
00027
00028 #include "../company_base.h"
00029 #include "../company_func.h"
00030 #include "../fileio_func.h"
00031
00032 ScriptStorage::~ScriptStorage()
00033 {
00034
00035 if (event_data != NULL) ScriptEventController::FreeEventPointer();
00036 if (log_data != NULL) ScriptLog::FreeLogPointer();
00037 }
00038
00044 static void PrintFunc(bool error_msg, const SQChar *message)
00045 {
00046
00047 ScriptController::Print(error_msg, SQ2OTTD(message));
00048 }
00049
00050 ScriptInstance::ScriptInstance(const char *APIName) :
00051 engine(NULL),
00052 versionAPI(NULL),
00053 controller(NULL),
00054 storage(NULL),
00055 instance(NULL),
00056 is_started(false),
00057 is_dead(false),
00058 is_save_data_on_stack(false),
00059 suspend(0),
00060 is_paused(false),
00061 callback(NULL)
00062 {
00063 this->storage = new ScriptStorage();
00064 this->engine = new Squirrel(APIName);
00065 this->engine->SetPrintFunction(&PrintFunc);
00066 }
00067
00068 void ScriptInstance::Initialize(const char *main_script, const char *instance_name, CompanyID company)
00069 {
00070 ScriptObject::ActiveInstance active(this);
00071
00072 this->controller = new ScriptController(company);
00073
00074
00075 this->engine->SetGlobalPointer(this->engine);
00076 this->RegisterAPI();
00077
00078 try {
00079 ScriptObject::SetAllowDoCommand(false);
00080
00081 if (strcmp(main_script, "%_dummy") == 0) {
00082 this->LoadDummyScript();
00083 } else if (!this->engine->LoadScript(main_script) || this->engine->IsSuspended()) {
00084 if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long to load script. AI is not started.");
00085 this->Died();
00086 return;
00087 }
00088
00089
00090 this->instance = MallocT<SQObject>(1);
00091 if (!this->engine->CreateClassInstance(instance_name, this->controller, this->instance)) {
00092 this->Died();
00093 return;
00094 }
00095 ScriptObject::SetAllowDoCommand(true);
00096 } catch (Script_FatalError e) {
00097 this->is_dead = true;
00098 this->engine->ThrowError(e.GetErrorMessage());
00099 this->engine->ResumeError();
00100 this->Died();
00101 }
00102 }
00103
00104 void ScriptInstance::RegisterAPI()
00105 {
00106 extern void squirrel_register_std(Squirrel *engine);
00107 squirrel_register_std(this->engine);
00108 }
00109
00110 bool ScriptInstance::LoadCompatibilityScripts(const char *api_version, Subdirectory dir)
00111 {
00112 char script_name[32];
00113 seprintf(script_name, lastof(script_name), "compat_%s.nut", api_version);
00114 char buf[MAX_PATH];
00115 Searchpath sp;
00116 FOR_ALL_SEARCHPATHS(sp) {
00117 FioAppendDirectory(buf, MAX_PATH, sp, dir);
00118 ttd_strlcat(buf, script_name, MAX_PATH);
00119 if (!FileExists(buf)) continue;
00120
00121 if (this->engine->LoadScript(buf)) return true;
00122
00123 ScriptLog::Error("Failed to load API compatibility script");
00124 DEBUG(script, 0, "Error compiling / running API compatibility script: %s", buf);
00125 return false;
00126 }
00127
00128 ScriptLog::Warning("API compatibility script not found");
00129 return true;
00130 }
00131
00132 ScriptInstance::~ScriptInstance()
00133 {
00134 ScriptObject::ActiveInstance active(this);
00135
00136 if (instance != NULL) this->engine->ReleaseObject(this->instance);
00137 if (engine != NULL) delete this->engine;
00138 delete this->storage;
00139 delete this->controller;
00140 free(this->instance);
00141 }
00142
00143 void ScriptInstance::Continue()
00144 {
00145 assert(this->suspend < 0);
00146 this->suspend = -this->suspend - 1;
00147 }
00148
00149 void ScriptInstance::Died()
00150 {
00151 DEBUG(script, 0, "The script died unexpectedly.");
00152 this->is_dead = true;
00153
00154 if (this->instance != NULL) this->engine->ReleaseObject(this->instance);
00155 delete this->engine;
00156 this->instance = NULL;
00157 this->engine = NULL;
00158 }
00159
00160 void ScriptInstance::GameLoop()
00161 {
00162 ScriptObject::ActiveInstance active(this);
00163
00164 if (this->IsDead()) return;
00165 if (this->engine->HasScriptCrashed()) {
00166
00167 this->Died();
00168 return;
00169 }
00170 if (this->is_paused) return;
00171 this->controller->ticks++;
00172
00173 if (this->suspend < -1) this->suspend++;
00174 if (this->suspend < 0) return;
00175 if (--this->suspend > 0) return;
00176
00177 _current_company = ScriptObject::GetCompany();
00178
00179
00180 if (this->callback != NULL) {
00181 if (this->is_save_data_on_stack) {
00182 sq_poptop(this->engine->GetVM());
00183 this->is_save_data_on_stack = false;
00184 }
00185 try {
00186 this->callback(this);
00187 } catch (Script_Suspend e) {
00188 this->suspend = e.GetSuspendTime();
00189 this->callback = e.GetSuspendCallback();
00190
00191 return;
00192 }
00193 }
00194
00195 this->suspend = 0;
00196 this->callback = NULL;
00197
00198 if (!this->is_started) {
00199 try {
00200 ScriptObject::SetAllowDoCommand(false);
00201
00202 if (this->engine->MethodExists(*this->instance, "constructor")) {
00203 if (!this->engine->CallMethod(*this->instance, "constructor", MAX_CONSTRUCTOR_OPS) || this->engine->IsSuspended()) {
00204 if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long to initialize. Script is not started.");
00205 this->Died();
00206 return;
00207 }
00208 }
00209 if (!this->CallLoad() || this->engine->IsSuspended()) {
00210 if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long in the Load function. Script is not started.");
00211 this->Died();
00212 return;
00213 }
00214 ScriptObject::SetAllowDoCommand(true);
00215
00216 if (!this->engine->CallMethod(*this->instance, "Start", _settings_game.script.script_max_opcode_till_suspend) || !this->engine->IsSuspended()) this->Died();
00217 } catch (Script_Suspend e) {
00218 this->suspend = e.GetSuspendTime();
00219 this->callback = e.GetSuspendCallback();
00220 } catch (Script_FatalError e) {
00221 this->is_dead = true;
00222 this->engine->ThrowError(e.GetErrorMessage());
00223 this->engine->ResumeError();
00224 this->Died();
00225 }
00226
00227 this->is_started = true;
00228 return;
00229 }
00230 if (this->is_save_data_on_stack) {
00231 sq_poptop(this->engine->GetVM());
00232 this->is_save_data_on_stack = false;
00233 }
00234
00235
00236 try {
00237 if (!this->engine->Resume(_settings_game.script.script_max_opcode_till_suspend)) this->Died();
00238 } catch (Script_Suspend e) {
00239 this->suspend = e.GetSuspendTime();
00240 this->callback = e.GetSuspendCallback();
00241 } catch (Script_FatalError e) {
00242 this->is_dead = true;
00243 this->engine->ThrowError(e.GetErrorMessage());
00244 this->engine->ResumeError();
00245 this->Died();
00246 }
00247 }
00248
00249 void ScriptInstance::CollectGarbage() const
00250 {
00251 if (this->is_started && !this->IsDead()) this->engine->CollectGarbage();
00252 }
00253
00254 void ScriptInstance::DoCommandReturn(ScriptInstance *instance)
00255 {
00256 instance->engine->InsertResult(ScriptObject::GetLastCommandRes());
00257 }
00258
00259 void ScriptInstance::DoCommandReturnVehicleID(ScriptInstance *instance)
00260 {
00261 instance->engine->InsertResult(ScriptObject::GetNewVehicleID());
00262 }
00263
00264 void ScriptInstance::DoCommandReturnSignID(ScriptInstance *instance)
00265 {
00266 instance->engine->InsertResult(ScriptObject::GetNewSignID());
00267 }
00268
00269 void ScriptInstance::DoCommandReturnGroupID(ScriptInstance *instance)
00270 {
00271 instance->engine->InsertResult(ScriptObject::GetNewGroupID());
00272 }
00273
00274 void ScriptInstance::DoCommandReturnGoalID(ScriptInstance *instance)
00275 {
00276 instance->engine->InsertResult(ScriptObject::GetNewGoalID());
00277 }
00278
00279 void ScriptInstance::DoCommandReturnStoryPageID(ScriptInstance *instance)
00280 {
00281 instance->engine->InsertResult(ScriptObject::GetNewStoryPageID());
00282 }
00283
00284 void ScriptInstance::DoCommandReturnStoryPageElementID(ScriptInstance *instance)
00285 {
00286 instance->engine->InsertResult(ScriptObject::GetNewStoryPageElementID());
00287 }
00288
00289 ScriptStorage *ScriptInstance::GetStorage()
00290 {
00291 return this->storage;
00292 }
00293
00294 void *ScriptInstance::GetLogPointer()
00295 {
00296 ScriptObject::ActiveInstance active(this);
00297
00298 return ScriptObject::GetLogPointer();
00299 }
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00323 enum SQSaveLoadType {
00324 SQSL_INT = 0x00,
00325 SQSL_STRING = 0x01,
00326 SQSL_ARRAY = 0x02,
00327 SQSL_TABLE = 0x03,
00328 SQSL_BOOL = 0x04,
00329 SQSL_NULL = 0x05,
00330 SQSL_ARRAY_TABLE_END = 0xFF,
00331 };
00332
00333 static byte _script_sl_byte;
00334
00336 static const SaveLoad _script_byte[] = {
00337 SLEG_VAR(_script_sl_byte, SLE_UINT8),
00338 SLE_END()
00339 };
00340
00341 bool ScriptInstance::SaveObject(HSQUIRRELVM vm, SQInteger index, int max_depth, bool test)
00342 {
00343 if (max_depth == 0) {
00344 ScriptLog::Error("Savedata can only be nested to 25 deep. No data saved.");
00345 return false;
00346 }
00347
00348 switch (sq_gettype(vm, index)) {
00349 case OT_INTEGER: {
00350 if (!test) {
00351 _script_sl_byte = SQSL_INT;
00352 SlObject(NULL, _script_byte);
00353 }
00354 SQInteger res;
00355 sq_getinteger(vm, index, &res);
00356 if (!test) {
00357 int value = (int)res;
00358 SlArray(&value, 1, SLE_INT32);
00359 }
00360 return true;
00361 }
00362
00363 case OT_STRING: {
00364 if (!test) {
00365 _script_sl_byte = SQSL_STRING;
00366 SlObject(NULL, _script_byte);
00367 }
00368 const SQChar *res;
00369 sq_getstring(vm, index, &res);
00370
00371
00372 const char *buf = SQ2OTTD(res);
00373 size_t len = strlen(buf) + 1;
00374 if (len >= 255) {
00375 ScriptLog::Error("Maximum string length is 254 chars. No data saved.");
00376 return false;
00377 }
00378 if (!test) {
00379 _script_sl_byte = (byte)len;
00380 SlObject(NULL, _script_byte);
00381 SlArray(const_cast<char *>(buf), len, SLE_CHAR);
00382 }
00383 return true;
00384 }
00385
00386 case OT_ARRAY: {
00387 if (!test) {
00388 _script_sl_byte = SQSL_ARRAY;
00389 SlObject(NULL, _script_byte);
00390 }
00391 sq_pushnull(vm);
00392 while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
00393
00394 bool res = SaveObject(vm, -1, max_depth - 1, test);
00395 sq_pop(vm, 2);
00396 if (!res) {
00397 sq_pop(vm, 1);
00398 return false;
00399 }
00400 }
00401 sq_pop(vm, 1);
00402 if (!test) {
00403 _script_sl_byte = SQSL_ARRAY_TABLE_END;
00404 SlObject(NULL, _script_byte);
00405 }
00406 return true;
00407 }
00408
00409 case OT_TABLE: {
00410 if (!test) {
00411 _script_sl_byte = SQSL_TABLE;
00412 SlObject(NULL, _script_byte);
00413 }
00414 sq_pushnull(vm);
00415 while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
00416
00417 bool res = SaveObject(vm, -2, max_depth - 1, test) && SaveObject(vm, -1, max_depth - 1, test);
00418 sq_pop(vm, 2);
00419 if (!res) {
00420 sq_pop(vm, 1);
00421 return false;
00422 }
00423 }
00424 sq_pop(vm, 1);
00425 if (!test) {
00426 _script_sl_byte = SQSL_ARRAY_TABLE_END;
00427 SlObject(NULL, _script_byte);
00428 }
00429 return true;
00430 }
00431
00432 case OT_BOOL: {
00433 if (!test) {
00434 _script_sl_byte = SQSL_BOOL;
00435 SlObject(NULL, _script_byte);
00436 }
00437 SQBool res;
00438 sq_getbool(vm, index, &res);
00439 if (!test) {
00440 _script_sl_byte = res ? 1 : 0;
00441 SlObject(NULL, _script_byte);
00442 }
00443 return true;
00444 }
00445
00446 case OT_NULL: {
00447 if (!test) {
00448 _script_sl_byte = SQSL_NULL;
00449 SlObject(NULL, _script_byte);
00450 }
00451 return true;
00452 }
00453
00454 default:
00455 ScriptLog::Error("You tried to save an unsupported type. No data saved.");
00456 return false;
00457 }
00458 }
00459
00460 void ScriptInstance::SaveEmpty()
00461 {
00462 _script_sl_byte = 0;
00463 SlObject(NULL, _script_byte);
00464 }
00465
00466 void ScriptInstance::Save()
00467 {
00468 ScriptObject::ActiveInstance active(this);
00469
00470
00471 if (this->engine == NULL || this->engine->HasScriptCrashed()) {
00472 SaveEmpty();
00473 return;
00474 }
00475
00476 HSQUIRRELVM vm = this->engine->GetVM();
00477 if (this->is_save_data_on_stack) {
00478 _script_sl_byte = 1;
00479 SlObject(NULL, _script_byte);
00480
00481 SaveObject(vm, -1, SQUIRREL_MAX_DEPTH, false);
00482 } else if (!this->is_started) {
00483 SaveEmpty();
00484 return;
00485 } else if (this->engine->MethodExists(*this->instance, "Save")) {
00486 HSQOBJECT savedata;
00487
00488 bool backup_allow = ScriptObject::GetAllowDoCommand();
00489 ScriptObject::SetAllowDoCommand(false);
00490 try {
00491 if (!this->engine->CallMethod(*this->instance, "Save", &savedata, MAX_SL_OPS)) {
00492
00493
00494 SaveEmpty();
00495 this->engine->CrashOccurred();
00496 return;
00497 }
00498 } catch (Script_FatalError e) {
00499
00500
00501 this->is_dead = true;
00502 this->engine->ThrowError(e.GetErrorMessage());
00503 this->engine->ResumeError();
00504 SaveEmpty();
00505
00506
00507 this->is_dead = false;
00508 this->engine->CrashOccurred();
00509 return;
00510 }
00511 ScriptObject::SetAllowDoCommand(backup_allow);
00512
00513 if (!sq_istable(savedata)) {
00514 ScriptLog::Error(this->engine->IsSuspended() ? "This script took too long to Save." : "Save function should return a table.");
00515 SaveEmpty();
00516 this->engine->CrashOccurred();
00517 return;
00518 }
00519 sq_pushobject(vm, savedata);
00520 if (SaveObject(vm, -1, SQUIRREL_MAX_DEPTH, true)) {
00521 _script_sl_byte = 1;
00522 SlObject(NULL, _script_byte);
00523 SaveObject(vm, -1, SQUIRREL_MAX_DEPTH, false);
00524 this->is_save_data_on_stack = true;
00525 } else {
00526 SaveEmpty();
00527 this->engine->CrashOccurred();
00528 }
00529 } else {
00530 ScriptLog::Warning("Save function is not implemented");
00531 _script_sl_byte = 0;
00532 SlObject(NULL, _script_byte);
00533 }
00534 }
00535
00536 void ScriptInstance::Pause()
00537 {
00538
00539 HSQUIRRELVM vm = this->engine->GetVM();
00540 Squirrel::DecreaseOps(vm, _settings_game.script.script_max_opcode_till_suspend);
00541
00542 this->is_paused = true;
00543 }
00544
00545 void ScriptInstance::Unpause()
00546 {
00547 this->is_paused = false;
00548 }
00549
00550 bool ScriptInstance::IsPaused()
00551 {
00552 return this->is_paused;
00553 }
00554
00555 bool ScriptInstance::LoadObjects(HSQUIRRELVM vm)
00556 {
00557 SlObject(NULL, _script_byte);
00558 switch (_script_sl_byte) {
00559 case SQSL_INT: {
00560 int value;
00561 SlArray(&value, 1, SLE_INT32);
00562 if (vm != NULL) sq_pushinteger(vm, (SQInteger)value);
00563 return true;
00564 }
00565
00566 case SQSL_STRING: {
00567 SlObject(NULL, _script_byte);
00568 static char buf[256];
00569 SlArray(buf, _script_sl_byte, SLE_CHAR);
00570 if (vm != NULL) sq_pushstring(vm, OTTD2SQ(buf), -1);
00571 return true;
00572 }
00573
00574 case SQSL_ARRAY: {
00575 if (vm != NULL) sq_newarray(vm, 0);
00576 while (LoadObjects(vm)) {
00577 if (vm != NULL) sq_arrayappend(vm, -2);
00578
00579 }
00580 return true;
00581 }
00582
00583 case SQSL_TABLE: {
00584 if (vm != NULL) sq_newtable(vm);
00585 while (LoadObjects(vm)) {
00586 LoadObjects(vm);
00587 if (vm != NULL) sq_rawset(vm, -3);
00588
00589 }
00590 return true;
00591 }
00592
00593 case SQSL_BOOL: {
00594 SlObject(NULL, _script_byte);
00595 if (vm != NULL) sq_pushinteger(vm, (SQBool)(_script_sl_byte != 0));
00596 return true;
00597 }
00598
00599 case SQSL_NULL: {
00600 if (vm != NULL) sq_pushnull(vm);
00601 return true;
00602 }
00603
00604 case SQSL_ARRAY_TABLE_END: {
00605 return false;
00606 }
00607
00608 default: NOT_REACHED();
00609 }
00610 }
00611
00612 void ScriptInstance::LoadEmpty()
00613 {
00614 SlObject(NULL, _script_byte);
00615
00616 if (_script_sl_byte == 0) return;
00617
00618 LoadObjects(NULL);
00619 }
00620
00621 void ScriptInstance::Load(int version)
00622 {
00623 ScriptObject::ActiveInstance active(this);
00624
00625 if (this->engine == NULL || version == -1) {
00626 LoadEmpty();
00627 return;
00628 }
00629 HSQUIRRELVM vm = this->engine->GetVM();
00630
00631 SlObject(NULL, _script_byte);
00632
00633 if (_script_sl_byte == 0) return;
00634
00635 sq_pushinteger(vm, version);
00636 LoadObjects(vm);
00637 this->is_save_data_on_stack = true;
00638 }
00639
00640 bool ScriptInstance::CallLoad()
00641 {
00642 HSQUIRRELVM vm = this->engine->GetVM();
00643
00644 if (!this->is_save_data_on_stack) return true;
00645
00646 this->is_save_data_on_stack = false;
00647
00648 if (!this->engine->MethodExists(*this->instance, "Load")) {
00649 ScriptLog::Warning("Loading failed: there was data for the script to load, but the script does not have a Load() function.");
00650
00651
00652 sq_pop(vm, 2);
00653 return true;
00654 }
00655
00656
00657 sq_pushobject(vm, *this->instance);
00658
00659 sq_pushstring(vm, OTTD2SQ("Load"), -1);
00660
00661 sq_get(vm, -2);
00662
00663 sq_pushobject(vm, *this->instance);
00664
00665 sq_push(vm, -5);
00666 sq_push(vm, -5);
00667
00668
00669
00670 if (SQ_FAILED(sq_call(vm, 3, SQFalse, SQFalse, MAX_SL_OPS))) return false;
00671
00672
00673 sq_pop(vm, 4);
00674 return true;
00675 }
00676
00677 SQInteger ScriptInstance::GetOpsTillSuspend()
00678 {
00679 return this->engine->GetOpsTillSuspend();
00680 }
00681
00682 void ScriptInstance::DoCommandCallback(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
00683 {
00684 ScriptObject::ActiveInstance active(this);
00685
00686 ScriptObject::SetLastCommandRes(result.Succeeded());
00687
00688 if (result.Failed()) {
00689 ScriptObject::SetLastError(ScriptError::StringToError(result.GetErrorMessage()));
00690 } else {
00691 ScriptObject::IncreaseDoCommandCosts(result.GetCost());
00692 ScriptObject::SetLastCost(result.GetCost());
00693 }
00694 }
00695
00696 void ScriptInstance::InsertEvent(class ScriptEvent *event)
00697 {
00698 ScriptObject::ActiveInstance active(this);
00699
00700 ScriptEventController::InsertEvent(event);
00701 }