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