OpenTTD Source  1.11.2
script_instance.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of OpenTTD.
3  * 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.
4  * 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.
5  * 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/>.
6  */
7 
10 #include "../stdafx.h"
11 #include "../debug.h"
12 #include "../saveload/saveload.h"
13 
14 #include "../script/squirrel_class.hpp"
15 
16 #include "script_fatalerror.hpp"
17 #include "script_storage.hpp"
18 #include "script_info.hpp"
19 #include "script_instance.hpp"
20 
21 #include "api/script_controller.hpp"
22 #include "api/script_error.hpp"
23 #include "api/script_event.hpp"
24 #include "api/script_log.hpp"
25 
26 #include "../company_base.h"
27 #include "../company_func.h"
28 #include "../fileio_func.h"
29 
30 #include "../safeguards.h"
31 
32 ScriptStorage::~ScriptStorage()
33 {
34  /* Free our pointers */
35  if (event_data != nullptr) ScriptEventController::FreeEventPointer();
36  if (log_data != nullptr) ScriptLog::FreeLogPointer();
37 }
38 
44 static void PrintFunc(bool error_msg, const SQChar *message)
45 {
46  /* Convert to OpenTTD internal capable string */
47  ScriptController::Print(error_msg, message);
48 }
49 
50 ScriptInstance::ScriptInstance(const char *APIName) :
51  engine(nullptr),
52  versionAPI(nullptr),
53  controller(nullptr),
54  storage(nullptr),
55  instance(nullptr),
56  is_started(false),
57  is_dead(false),
58  is_save_data_on_stack(false),
59  suspend(0),
60  is_paused(false),
61  in_shutdown(false),
62  callback(nullptr)
63 {
64  this->storage = new ScriptStorage();
65  this->engine = new Squirrel(APIName);
67 }
68 
69 void ScriptInstance::Initialize(const char *main_script, const char *instance_name, CompanyID company)
70 {
71  ScriptObject::ActiveInstance active(this);
72 
73  this->controller = new ScriptController(company);
74 
75  /* Register the API functions and classes */
76  this->engine->SetGlobalPointer(this->engine);
77  this->RegisterAPI();
78 
79  try {
80  ScriptObject::SetAllowDoCommand(false);
81  /* Load and execute the script for this script */
82  if (strcmp(main_script, "%_dummy") == 0) {
83  this->LoadDummyScript();
84  } else if (!this->engine->LoadScript(main_script) || this->engine->IsSuspended()) {
85  if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long to load script. AI is not started.");
86  this->Died();
87  return;
88  }
89 
90  /* Create the main-class */
91  this->instance = new SQObject();
92  if (!this->engine->CreateClassInstance(instance_name, this->controller, this->instance)) {
93  /* If CreateClassInstance has returned false instance has not been
94  * registered with squirrel, so avoid trying to Release it by clearing it now */
95  delete this->instance;
96  this->instance = nullptr;
97  this->Died();
98  return;
99  }
100  ScriptObject::SetAllowDoCommand(true);
101  } catch (Script_FatalError &e) {
102  this->is_dead = true;
103  this->engine->ThrowError(e.GetErrorMessage().c_str());
104  this->engine->ResumeError();
105  this->Died();
106  }
107 }
108 
110 {
111  extern void squirrel_register_std(Squirrel *engine);
112  squirrel_register_std(this->engine);
113 }
114 
115 bool ScriptInstance::LoadCompatibilityScripts(const char *api_version, Subdirectory dir)
116 {
117  char script_name[32];
118  seprintf(script_name, lastof(script_name), "compat_%s.nut", api_version);
119  Searchpath sp;
120  FOR_ALL_SEARCHPATHS(sp) {
121  std::string buf = FioGetDirectory(sp, dir);
122  buf += script_name;
123  if (!FileExists(buf)) continue;
124 
125  if (this->engine->LoadScript(buf.c_str())) return true;
126 
127  ScriptLog::Error("Failed to load API compatibility script");
128  DEBUG(script, 0, "Error compiling / running API compatibility script: %s", buf.c_str());
129  return false;
130  }
131 
132  ScriptLog::Warning("API compatibility script not found");
133  return true;
134 }
135 
136 ScriptInstance::~ScriptInstance()
137 {
138  ScriptObject::ActiveInstance active(this);
139  this->in_shutdown = true;
140 
141  if (instance != nullptr) this->engine->ReleaseObject(this->instance);
142  if (engine != nullptr) delete this->engine;
143  delete this->storage;
144  delete this->controller;
145  delete this->instance;
146 }
147 
149 {
150  assert(this->suspend < 0);
151  this->suspend = -this->suspend - 1;
152 }
153 
155 {
156  DEBUG(script, 0, "The script died unexpectedly.");
157  this->is_dead = true;
158  this->in_shutdown = true;
159 
160  this->last_allocated_memory = this->GetAllocatedMemory(); // Update cache
161 
162  if (this->instance != nullptr) this->engine->ReleaseObject(this->instance);
163  delete this->instance;
164  delete this->engine;
165  this->instance = nullptr;
166  this->engine = nullptr;
167 }
168 
170 {
171  ScriptObject::ActiveInstance active(this);
172 
173  if (this->IsDead()) return;
174  if (this->engine->HasScriptCrashed()) {
175  /* The script crashed during saving, kill it here. */
176  this->Died();
177  return;
178  }
179  if (this->is_paused) return;
180  this->controller->ticks++;
181 
182  if (this->suspend < -1) this->suspend++; // Multiplayer suspend, increase up to -1.
183  if (this->suspend < 0) return; // Multiplayer suspend, wait for Continue().
184  if (--this->suspend > 0) return; // Singleplayer suspend, decrease to 0.
185 
186  _current_company = ScriptObject::GetCompany();
187 
188  /* If there is a callback to call, call that first */
189  if (this->callback != nullptr) {
190  if (this->is_save_data_on_stack) {
191  sq_poptop(this->engine->GetVM());
192  this->is_save_data_on_stack = false;
193  }
194  try {
195  this->callback(this);
196  } catch (Script_Suspend &e) {
197  this->suspend = e.GetSuspendTime();
198  this->callback = e.GetSuspendCallback();
199 
200  return;
201  }
202  }
203 
204  this->suspend = 0;
205  this->callback = nullptr;
206 
207  if (!this->is_started) {
208  try {
209  ScriptObject::SetAllowDoCommand(false);
210  /* Run the constructor if it exists. Don't allow any DoCommands in it. */
211  if (this->engine->MethodExists(*this->instance, "constructor")) {
212  if (!this->engine->CallMethod(*this->instance, "constructor", MAX_CONSTRUCTOR_OPS) || this->engine->IsSuspended()) {
213  if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long to initialize. Script is not started.");
214  this->Died();
215  return;
216  }
217  }
218  if (!this->CallLoad() || this->engine->IsSuspended()) {
219  if (this->engine->IsSuspended()) ScriptLog::Error("This script took too long in the Load function. Script is not started.");
220  this->Died();
221  return;
222  }
223  ScriptObject::SetAllowDoCommand(true);
224  /* Start the script by calling Start() */
225  if (!this->engine->CallMethod(*this->instance, "Start", _settings_game.script.script_max_opcode_till_suspend) || !this->engine->IsSuspended()) this->Died();
226  } catch (Script_Suspend &e) {
227  this->suspend = e.GetSuspendTime();
228  this->callback = e.GetSuspendCallback();
229  } catch (Script_FatalError &e) {
230  this->is_dead = true;
231  this->engine->ThrowError(e.GetErrorMessage().c_str());
232  this->engine->ResumeError();
233  this->Died();
234  }
235 
236  this->is_started = true;
237  return;
238  }
239  if (this->is_save_data_on_stack) {
240  sq_poptop(this->engine->GetVM());
241  this->is_save_data_on_stack = false;
242  }
243 
244  /* Continue the VM */
245  try {
247  } catch (Script_Suspend &e) {
248  this->suspend = e.GetSuspendTime();
249  this->callback = e.GetSuspendCallback();
250  } catch (Script_FatalError &e) {
251  this->is_dead = true;
252  this->engine->ThrowError(e.GetErrorMessage().c_str());
253  this->engine->ResumeError();
254  this->Died();
255  }
256 }
257 
259 {
260  if (this->is_started && !this->IsDead()) this->engine->CollectGarbage();
261 }
262 
264 {
265  instance->engine->InsertResult(ScriptObject::GetLastCommandRes());
266 }
267 
269 {
270  instance->engine->InsertResult(ScriptObject::GetNewVehicleID());
271 }
272 
274 {
275  instance->engine->InsertResult(ScriptObject::GetNewSignID());
276 }
277 
279 {
280  instance->engine->InsertResult(ScriptObject::GetNewGroupID());
281 }
282 
284 {
285  instance->engine->InsertResult(ScriptObject::GetNewGoalID());
286 }
287 
289 {
290  instance->engine->InsertResult(ScriptObject::GetNewStoryPageID());
291 }
292 
294 {
295  instance->engine->InsertResult(ScriptObject::GetNewStoryPageElementID());
296 }
297 
299 {
300  return this->storage;
301 }
302 
304 {
305  ScriptObject::ActiveInstance active(this);
306 
307  return ScriptObject::GetLogPointer();
308 }
309 
310 /*
311  * All data is stored in the following format:
312  * First 1 byte indicating if there is a data blob at all.
313  * 1 byte indicating the type of data.
314  * The data itself, this differs per type:
315  * - integer: a binary representation of the integer (int32).
316  * - string: First one byte with the string length, then a 0-terminated char
317  * array. The string can't be longer than 255 bytes (including
318  * terminating '\0').
319  * - array: All data-elements of the array are saved recursive in this
320  * format, and ended with an element of the type
321  * SQSL_ARRAY_TABLE_END.
322  * - table: All key/value pairs are saved in this format (first key 1, then
323  * value 1, then key 2, etc.). All keys and values can have an
324  * arbitrary type (as long as it is supported by the save function
325  * of course). The table is ended with an element of the type
326  * SQSL_ARRAY_TABLE_END.
327  * - bool: A single byte with value 1 representing true and 0 false.
328  * - null: No data.
329  */
330 
333  SQSL_INT = 0x00,
334  SQSL_STRING = 0x01,
335  SQSL_ARRAY = 0x02,
336  SQSL_TABLE = 0x03,
337  SQSL_BOOL = 0x04,
338  SQSL_NULL = 0x05,
340 };
341 
342 static byte _script_sl_byte;
343 
345 static const SaveLoad _script_byte[] = {
346  SLEG_VAR(_script_sl_byte, SLE_UINT8),
347  SLE_END()
348 };
349 
350 /* static */ bool ScriptInstance::SaveObject(HSQUIRRELVM vm, SQInteger index, int max_depth, bool test)
351 {
352  if (max_depth == 0) {
353  ScriptLog::Error("Savedata can only be nested to 25 deep. No data saved."); // SQUIRREL_MAX_DEPTH = 25
354  return false;
355  }
356 
357  switch (sq_gettype(vm, index)) {
358  case OT_INTEGER: {
359  if (!test) {
361  SlObject(nullptr, _script_byte);
362  }
363  SQInteger res;
364  sq_getinteger(vm, index, &res);
365  if (!test) {
366  int value = (int)res;
367  SlArray(&value, 1, SLE_INT32);
368  }
369  return true;
370  }
371 
372  case OT_STRING: {
373  if (!test) {
375  SlObject(nullptr, _script_byte);
376  }
377  const SQChar *buf;
378  sq_getstring(vm, index, &buf);
379  size_t len = strlen(buf) + 1;
380  if (len >= 255) {
381  ScriptLog::Error("Maximum string length is 254 chars. No data saved.");
382  return false;
383  }
384  if (!test) {
385  _script_sl_byte = (byte)len;
386  SlObject(nullptr, _script_byte);
387  SlArray(const_cast<char *>(buf), len, SLE_CHAR);
388  }
389  return true;
390  }
391 
392  case OT_ARRAY: {
393  if (!test) {
395  SlObject(nullptr, _script_byte);
396  }
397  sq_pushnull(vm);
398  while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
399  /* Store the value */
400  bool res = SaveObject(vm, -1, max_depth - 1, test);
401  sq_pop(vm, 2);
402  if (!res) {
403  sq_pop(vm, 1);
404  return false;
405  }
406  }
407  sq_pop(vm, 1);
408  if (!test) {
410  SlObject(nullptr, _script_byte);
411  }
412  return true;
413  }
414 
415  case OT_TABLE: {
416  if (!test) {
418  SlObject(nullptr, _script_byte);
419  }
420  sq_pushnull(vm);
421  while (SQ_SUCCEEDED(sq_next(vm, index - 1))) {
422  /* Store the key + value */
423  bool res = SaveObject(vm, -2, max_depth - 1, test) && SaveObject(vm, -1, max_depth - 1, test);
424  sq_pop(vm, 2);
425  if (!res) {
426  sq_pop(vm, 1);
427  return false;
428  }
429  }
430  sq_pop(vm, 1);
431  if (!test) {
433  SlObject(nullptr, _script_byte);
434  }
435  return true;
436  }
437 
438  case OT_BOOL: {
439  if (!test) {
441  SlObject(nullptr, _script_byte);
442  }
443  SQBool res;
444  sq_getbool(vm, index, &res);
445  if (!test) {
446  _script_sl_byte = res ? 1 : 0;
447  SlObject(nullptr, _script_byte);
448  }
449  return true;
450  }
451 
452  case OT_NULL: {
453  if (!test) {
455  SlObject(nullptr, _script_byte);
456  }
457  return true;
458  }
459 
460  default:
461  ScriptLog::Error("You tried to save an unsupported type. No data saved.");
462  return false;
463  }
464 }
465 
466 /* static */ void ScriptInstance::SaveEmpty()
467 {
468  _script_sl_byte = 0;
469  SlObject(nullptr, _script_byte);
470 }
471 
473 {
474  ScriptObject::ActiveInstance active(this);
475 
476  /* Don't save data if the script didn't start yet or if it crashed. */
477  if (this->engine == nullptr || this->engine->HasScriptCrashed()) {
478  SaveEmpty();
479  return;
480  }
481 
482  HSQUIRRELVM vm = this->engine->GetVM();
483  if (this->is_save_data_on_stack) {
484  _script_sl_byte = 1;
485  SlObject(nullptr, _script_byte);
486  /* Save the data that was just loaded. */
487  SaveObject(vm, -1, SQUIRREL_MAX_DEPTH, false);
488  } else if (!this->is_started) {
489  SaveEmpty();
490  return;
491  } else if (this->engine->MethodExists(*this->instance, "Save")) {
492  HSQOBJECT savedata;
493  /* We don't want to be interrupted during the save function. */
494  bool backup_allow = ScriptObject::GetAllowDoCommand();
495  ScriptObject::SetAllowDoCommand(false);
496  try {
497  if (!this->engine->CallMethod(*this->instance, "Save", &savedata, MAX_SL_OPS)) {
498  /* The script crashed in the Save function. We can't kill
499  * it here, but do so in the next script tick. */
500  SaveEmpty();
501  this->engine->CrashOccurred();
502  return;
503  }
504  } catch (Script_FatalError &e) {
505  /* If we don't mark the script as dead here cleaning up the squirrel
506  * stack could throw Script_FatalError again. */
507  this->is_dead = true;
508  this->engine->ThrowError(e.GetErrorMessage().c_str());
509  this->engine->ResumeError();
510  SaveEmpty();
511  /* We can't kill the script here, so mark it as crashed (not dead) and
512  * kill it in the next script tick. */
513  this->is_dead = false;
514  this->engine->CrashOccurred();
515  return;
516  }
517  ScriptObject::SetAllowDoCommand(backup_allow);
518 
519  if (!sq_istable(savedata)) {
520  ScriptLog::Error(this->engine->IsSuspended() ? "This script took too long to Save." : "Save function should return a table.");
521  SaveEmpty();
522  this->engine->CrashOccurred();
523  return;
524  }
525  sq_pushobject(vm, savedata);
526  if (SaveObject(vm, -1, SQUIRREL_MAX_DEPTH, true)) {
527  _script_sl_byte = 1;
528  SlObject(nullptr, _script_byte);
529  SaveObject(vm, -1, SQUIRREL_MAX_DEPTH, false);
530  this->is_save_data_on_stack = true;
531  } else {
532  SaveEmpty();
533  this->engine->CrashOccurred();
534  }
535  } else {
536  ScriptLog::Warning("Save function is not implemented");
537  _script_sl_byte = 0;
538  SlObject(nullptr, _script_byte);
539  }
540 }
541 
543 {
544  /* Suspend script. */
545  HSQUIRRELVM vm = this->engine->GetVM();
547 
548  this->is_paused = true;
549 }
550 
552 {
553  this->is_paused = false;
554 }
555 
557 {
558  return this->is_paused;
559 }
560 
561 /* static */ bool ScriptInstance::LoadObjects(HSQUIRRELVM vm)
562 {
563  SlObject(nullptr, _script_byte);
564  switch (_script_sl_byte) {
565  case SQSL_INT: {
566  int value;
567  SlArray(&value, 1, SLE_INT32);
568  if (vm != nullptr) sq_pushinteger(vm, (SQInteger)value);
569  return true;
570  }
571 
572  case SQSL_STRING: {
573  SlObject(nullptr, _script_byte);
574  static char buf[256];
575  SlArray(buf, _script_sl_byte, SLE_CHAR);
576  if (vm != nullptr) sq_pushstring(vm, buf, -1);
577  return true;
578  }
579 
580  case SQSL_ARRAY: {
581  if (vm != nullptr) sq_newarray(vm, 0);
582  while (LoadObjects(vm)) {
583  if (vm != nullptr) sq_arrayappend(vm, -2);
584  /* The value is popped from the stack by squirrel. */
585  }
586  return true;
587  }
588 
589  case SQSL_TABLE: {
590  if (vm != nullptr) sq_newtable(vm);
591  while (LoadObjects(vm)) {
592  LoadObjects(vm);
593  if (vm != nullptr) sq_rawset(vm, -3);
594  /* The key (-2) and value (-1) are popped from the stack by squirrel. */
595  }
596  return true;
597  }
598 
599  case SQSL_BOOL: {
600  SlObject(nullptr, _script_byte);
601  if (vm != nullptr) sq_pushbool(vm, (SQBool)(_script_sl_byte != 0));
602  return true;
603  }
604 
605  case SQSL_NULL: {
606  if (vm != nullptr) sq_pushnull(vm);
607  return true;
608  }
609 
610  case SQSL_ARRAY_TABLE_END: {
611  return false;
612  }
613 
614  default: NOT_REACHED();
615  }
616 }
617 
618 /* static */ void ScriptInstance::LoadEmpty()
619 {
620  SlObject(nullptr, _script_byte);
621  /* Check if there was anything saved at all. */
622  if (_script_sl_byte == 0) return;
623 
624  LoadObjects(nullptr);
625 }
626 
627 void ScriptInstance::Load(int version)
628 {
629  ScriptObject::ActiveInstance active(this);
630 
631  if (this->engine == nullptr || version == -1) {
632  LoadEmpty();
633  return;
634  }
635  HSQUIRRELVM vm = this->engine->GetVM();
636 
637  SlObject(nullptr, _script_byte);
638  /* Check if there was anything saved at all. */
639  if (_script_sl_byte == 0) return;
640 
641  sq_pushinteger(vm, version);
642  LoadObjects(vm);
643  this->is_save_data_on_stack = true;
644 }
645 
647 {
648  HSQUIRRELVM vm = this->engine->GetVM();
649  /* Is there save data that we should load? */
650  if (!this->is_save_data_on_stack) return true;
651  /* Whatever happens, after CallLoad the savegame data is removed from the stack. */
652  this->is_save_data_on_stack = false;
653 
654  if (!this->engine->MethodExists(*this->instance, "Load")) {
655  ScriptLog::Warning("Loading failed: there was data for the script to load, but the script does not have a Load() function.");
656 
657  /* Pop the savegame data and version. */
658  sq_pop(vm, 2);
659  return true;
660  }
661 
662  /* Go to the instance-root */
663  sq_pushobject(vm, *this->instance);
664  /* Find the function-name inside the script */
665  sq_pushstring(vm, "Load", -1);
666  /* Change the "Load" string in a function pointer */
667  sq_get(vm, -2);
668  /* Push the main instance as "this" object */
669  sq_pushobject(vm, *this->instance);
670  /* Push the version data and savegame data as arguments */
671  sq_push(vm, -5);
672  sq_push(vm, -5);
673 
674  /* Call the script load function. sq_call removes the arguments (but not the
675  * function pointer) from the stack. */
676  if (SQ_FAILED(sq_call(vm, 3, SQFalse, SQFalse, MAX_SL_OPS))) return false;
677 
678  /* Pop 1) The version, 2) the savegame data, 3) the object instance, 4) the function pointer. */
679  sq_pop(vm, 4);
680  return true;
681 }
682 
684 {
685  return this->engine->GetOpsTillSuspend();
686 }
687 
688 bool ScriptInstance::DoCommandCallback(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
689 {
690  ScriptObject::ActiveInstance active(this);
691 
692  if (!ScriptObject::CheckLastCommand(tile, p1, p2, cmd)) {
693  DEBUG(script, 1, "DoCommandCallback terminating a script, last command does not match expected command");
694  return false;
695  }
696 
697  ScriptObject::SetLastCommandRes(result.Succeeded());
698 
699  if (result.Failed()) {
700  ScriptObject::SetLastError(ScriptError::StringToError(result.GetErrorMessage()));
701  } else {
702  ScriptObject::IncreaseDoCommandCosts(result.GetCost());
703  ScriptObject::SetLastCost(result.GetCost());
704  }
705 
706  ScriptObject::SetLastCommand(INVALID_TILE, 0, 0, CMD_END);
707 
708  return true;
709 }
710 
711 void ScriptInstance::InsertEvent(class ScriptEvent *event)
712 {
713  ScriptObject::ActiveInstance active(this);
714 
715  ScriptEventController::InsertEvent(event);
716 }
717 
718 size_t ScriptInstance::GetAllocatedMemory() const
719 {
720  if (this->engine == nullptr) return this->last_allocated_memory;
721  return this->engine->GetAllocatedMemory();
722 }
723 
725 {
726  if (!this->in_shutdown) this->engine->ReleaseObject(obj);
727 }
ScriptInstance::LoadDummyScript
virtual void LoadDummyScript()=0
Load the dummy script.
Script_Suspend
A throw-class that is given when the script wants to suspend.
Definition: script_suspend.hpp:21
ScriptStorage::log_data
void * log_data
Pointer to the log data storage.
Definition: script_storage.hpp:65
TileIndex
uint32 TileIndex
The index/ID of a Tile.
Definition: tile_type.h:83
ScriptInstance::SaveObject
static bool SaveObject(HSQUIRRELVM vm, SQInteger index, int max_depth, bool test)
Save one object (int / string / array / table) to the savegame.
Definition: script_instance.cpp:350
ScriptInstance::engine
class Squirrel * engine
A wrapper around the squirrel vm.
Definition: script_instance.hpp:215
_script_sl_byte
static byte _script_sl_byte
Used as source/target by the script saveload code to store/load a single byte.
Definition: script_instance.cpp:342
PrintFunc
static void PrintFunc(bool error_msg, const SQChar *message)
Callback called by squirrel when a script uses "print" and for error messages.
Definition: script_instance.cpp:44
ScriptInstance::last_allocated_memory
size_t last_allocated_memory
Last known allocated memory value (for display for crashed scripts)
Definition: script_instance.hpp:258
ScriptStorage
The storage for each script.
Definition: script_storage.hpp:31
ScriptInstance::CallLoad
bool CallLoad()
Call the script Load function if it exists and data was loaded from a savegame.
Definition: script_instance.cpp:646
ScriptInstance::is_dead
bool is_dead
True if the script has been stopped.
Definition: script_instance.hpp:252
ScriptInstance::InsertEvent
void InsertEvent(class ScriptEvent *event)
Insert an event for this script.
Definition: script_instance.cpp:711
ScriptInstance::GameLoop
void GameLoop()
Run the GameLoop of a script.
Definition: script_instance.cpp:169
Squirrel::SetPrintFunction
void SetPrintFunction(SQPrintFunc *func)
Set a custom print function, so you can handle outputs from SQ yourself.
Definition: squirrel.hpp:231
Script_Suspend::GetSuspendTime
int GetSuspendTime()
Get the amount of ticks the script should be suspended.
Definition: script_suspend.hpp:37
ScriptInstance::DoCommandCallback
bool DoCommandCallback(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd)
DoCommand callback function for all commands executed by scripts.
Definition: script_instance.cpp:688
ScriptInstance::controller
class ScriptController * controller
The script main class.
Definition: script_instance.hpp:247
ScriptInstance::Save
void Save()
Call the script Save function and save all data in the savegame.
Definition: script_instance.cpp:472
ScriptScanner::engine
class Squirrel * engine
The engine we're scanning with.
Definition: script_scanner.hpp:86
SQSL_STRING
@ SQSL_STRING
The following data is an string.
Definition: script_instance.cpp:334
SQSL_ARRAY
@ SQSL_ARRAY
The following data is an array.
Definition: script_instance.cpp:335
SQSL_INT
@ SQSL_INT
The following data is an integer.
Definition: script_instance.cpp:333
ScriptInstance
Runtime information about a script like a pointer to the squirrel vm and the current state.
Definition: script_instance.hpp:23
ScriptInstance::ScriptInstance
ScriptInstance(const char *APIName)
Create a new script.
Definition: script_instance.cpp:50
ScriptInstance::Unpause
void Unpause()
Resume execution of the script.
Definition: script_instance.cpp:551
ScriptInstance::DoCommandReturnStoryPageElementID
static void DoCommandReturnStoryPageElementID(ScriptInstance *instance)
Return a StoryPageElementID reply for a DoCommand.
Definition: script_instance.cpp:293
ScriptInstance::LoadObjects
static bool LoadObjects(HSQUIRRELVM vm)
Load all objects from a savegame.
Definition: script_instance.cpp:561
Searchpath
Searchpath
Types of searchpaths OpenTTD might use.
Definition: fileio_type.h:131
ScriptInstance::instance
SQObject * instance
Squirrel-pointer to the script main class.
Definition: script_instance.hpp:249
FOR_ALL_SEARCHPATHS
#define FOR_ALL_SEARCHPATHS(sp)
Iterator for all the search paths.
Definition: fileio_func.h:37
ScriptInstance::is_save_data_on_stack
bool is_save_data_on_stack
Is the save data still on the squirrel stack?
Definition: script_instance.hpp:253
Squirrel::GetVM
HSQUIRRELVM GetVM()
Get the squirrel VM.
Definition: squirrel.hpp:80
ScriptInstance::is_paused
bool is_paused
Is the script paused? (a paused script will not be executed until unpaused)
Definition: script_instance.hpp:255
SQSaveLoadType
SQSaveLoadType
The type of the data that follows in the savegame.
Definition: script_instance.cpp:332
Script_FatalError::GetErrorMessage
const std::string & GetErrorMessage() const
The error message associated with the fatal error.
Definition: script_fatalerror.hpp:30
Owner
Owner
Enum for all companies/owners.
Definition: company_type.h:18
CommandCost::GetErrorMessage
StringID GetErrorMessage() const
Returns the error message of a command.
Definition: command_type.h:140
SQSL_TABLE
@ SQSL_TABLE
The following data is an table.
Definition: script_instance.cpp:336
CommandCost::Succeeded
bool Succeeded() const
Did this command succeed?
Definition: command_type.h:150
ScriptInstance::GetOpsTillSuspend
SQInteger GetOpsTillSuspend()
Get the number of operations the script can execute before being suspended.
Definition: script_instance.cpp:683
SQSL_BOOL
@ SQSL_BOOL
The following data is a boolean.
Definition: script_instance.cpp:337
ScriptInstance::Pause
void Pause()
Suspends the script for the current tick and then pause the execution of script.
Definition: script_instance.cpp:542
ScriptInstance::DoCommandReturnGoalID
static void DoCommandReturnGoalID(ScriptInstance *instance)
Return a GoalID reply for a DoCommand.
Definition: script_instance.cpp:283
ScriptInstance::ReleaseSQObject
void ReleaseSQObject(HSQOBJECT *obj)
Decrease the ref count of a squirrel object.
Definition: script_instance.cpp:724
ScriptInstance::storage
class ScriptStorage * storage
Some global information for each running script.
Definition: script_instance.hpp:248
Squirrel::GetOpsTillSuspend
SQInteger GetOpsTillSuspend()
How many operations can we execute till suspension?
Definition: squirrel.cpp:816
Squirrel
Definition: squirrel.hpp:23
Squirrel::HasScriptCrashed
bool HasScriptCrashed()
Find out if the squirrel script made an error before.
Definition: squirrel.cpp:800
Squirrel::LoadScript
bool LoadScript(const char *script)
Load a script.
Definition: squirrel.cpp:743
ScriptInstance::DoCommandReturnSignID
static void DoCommandReturnSignID(ScriptInstance *instance)
Return a SignID reply for a DoCommand.
Definition: script_instance.cpp:273
CommandCost
Common return value for all commands.
Definition: command_type.h:23
ScriptInstance::in_shutdown
bool in_shutdown
Is this instance currently being destructed?
Definition: script_instance.hpp:256
script_storage.hpp
_script_byte
static const SaveLoad _script_byte[]
SaveLoad array that saves/loads exactly one byte.
Definition: script_instance.cpp:345
Squirrel::ThrowError
void ThrowError(const char *error)
Throw a Squirrel error that will be nicely displayed to the user.
Definition: squirrel.hpp:236
GameSettings::script
ScriptSettings script
settings for scripts
Definition: settings_type.h:567
DEBUG
#define DEBUG(name, level,...)
Output a line of debugging information.
Definition: debug.h:35
ScriptInstance::DoCommandReturn
static void DoCommandReturn(ScriptInstance *instance)
Return a true/false reply for a DoCommand.
Definition: script_instance.cpp:263
ScriptInstance::SaveEmpty
static void SaveEmpty()
Don't save any data in the savegame.
Definition: script_instance.cpp:466
SQSL_NULL
@ SQSL_NULL
A null variable.
Definition: script_instance.cpp:338
FileExists
bool FileExists(const std::string &filename)
Test whether the given filename exists.
Definition: fileio.cpp:280
Squirrel::SetGlobalPointer
void SetGlobalPointer(void *ptr)
Sets a pointer in the VM that is reachable from where ever you are in SQ.
Definition: squirrel.hpp:221
CommandCost::Failed
bool Failed() const
Did this command fail?
Definition: command_type.h:159
SLE_END
#define SLE_END()
End marker of a struct/class save or load.
Definition: saveload.h:687
ScriptInstance::IsDead
bool IsDead() const
Return the "this script died" value.
Definition: script_instance.hpp:126
ScriptStorage::event_data
void * event_data
Pointer to the event data storage.
Definition: script_storage.hpp:64
Squirrel::GetAllocatedMemory
size_t GetAllocatedMemory() const noexcept
Get number of bytes allocated by this VM.
Definition: squirrel.cpp:191
_settings_game
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:80
CommandCost::GetCost
Money GetCost() const
The costs as made up to this moment.
Definition: command_type.h:82
ScriptInstance::is_started
bool is_started
Is the scripts constructor executed?
Definition: script_instance.hpp:251
ScriptInstance::DoCommandReturnStoryPageID
static void DoCommandReturnStoryPageID(ScriptInstance *instance)
Return a StoryPageID reply for a DoCommand.
Definition: script_instance.cpp:288
ScriptInstance::RegisterAPI
virtual void RegisterAPI()
Register all API functions to the VM.
Definition: script_instance.cpp:109
Squirrel::CallMethod
bool CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT *ret, int suspend)
Call a method of an instance, in various flavors.
Definition: squirrel.cpp:410
ScriptInstance::Initialize
void Initialize(const char *main_script, const char *instance_name, CompanyID company)
Initialize the script and prepare it for its first run.
Definition: script_instance.cpp:69
SlObject
void SlObject(void *object, const SaveLoad *sld)
Main SaveLoad function.
Definition: saveload.cpp:1612
ScriptScanner::main_script
std::string main_script
The full path of the script.
Definition: script_scanner.hpp:87
ScriptInstance::LoadEmpty
static void LoadEmpty()
Load and discard data from a savegame.
Definition: script_instance.cpp:618
ScriptInstance::DoCommandReturnGroupID
static void DoCommandReturnGroupID(ScriptInstance *instance)
Return a GroupID reply for a DoCommand.
Definition: script_instance.cpp:278
Script_Suspend::GetSuspendCallback
Script_SuspendCallbackProc * GetSuspendCallback()
Get the callback to call when the script can run again.
Definition: script_suspend.hpp:43
squirrel_register_std
void squirrel_register_std(Squirrel *engine)
Register all standard functions we want to give to a script.
Definition: squirrel_std.cpp:102
SLEG_VAR
#define SLEG_VAR(variable, type)
Storage of a global variable in every savegame version.
Definition: saveload.h:762
Squirrel::ResumeError
void ResumeError()
Resume the VM with an error so it prints a stack trace.
Definition: squirrel.cpp:397
Squirrel::CreateClassInstance
bool CreateClassInstance(const char *class_name, void *real_instance, HSQOBJECT *instance)
Exactly the same as CreateClassInstanceVM, only callable without instance of Squirrel.
Definition: squirrel.cpp:522
_current_company
CompanyID _current_company
Company currently doing an action.
Definition: company_cmd.cpp:47
MAX_CONSTRUCTOR_OPS
static const int MAX_CONSTRUCTOR_OPS
The maximum number of operations for initial start of a script.
Definition: script_info.hpp:21
Squirrel::CollectGarbage
void CollectGarbage()
Tell the VM to do a garbage collection run.
Definition: squirrel.cpp:404
ScriptInstance::callback
Script_SuspendCallbackProc * callback
Callback that should be called in the next tick the script runs.
Definition: script_instance.hpp:257
Squirrel::MethodExists
bool MethodExists(HSQOBJECT instance, const char *method_name)
Check if a method exists in an instance.
Definition: squirrel.cpp:357
Squirrel::CrashOccurred
void CrashOccurred()
Set the script status to crashed.
Definition: squirrel.cpp:805
ScriptSettings::script_max_opcode_till_suspend
uint32 script_max_opcode_till_suspend
max opcode calls till scripts will suspend
Definition: settings_type.h:357
script_info.hpp
ScriptInstance::DoCommandReturnVehicleID
static void DoCommandReturnVehicleID(ScriptInstance *instance)
Return a VehicleID reply for a DoCommand.
Definition: script_instance.cpp:268
ScriptInstance::GetStorage
class ScriptStorage * GetStorage()
Get the storage of this script.
Definition: script_instance.cpp:298
seprintf
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
Definition: string.cpp:460
script_instance.hpp
Subdirectory
Subdirectory
The different kinds of subdirectories OpenTTD uses.
Definition: fileio_type.h:108
ScriptInstance::Died
virtual void Died()
Tell the script it died.
Definition: script_instance.cpp:154
ScriptInstance::suspend
int suspend
The amount of ticks to suspend this script before it's allowed to continue.
Definition: script_instance.hpp:254
Squirrel::Resume
bool Resume(int suspend=-1)
Resume a VM when it was suspended via a throw.
Definition: squirrel.cpp:375
Script_FatalError
A throw-class that is given when the script made a fatal error.
Definition: script_fatalerror.hpp:16
ScriptInstance::Continue
void Continue()
A script in multiplayer waits for the server to handle his DoCommand.
Definition: script_instance.cpp:148
script_fatalerror.hpp
Squirrel::ReleaseObject
void ReleaseObject(HSQOBJECT *ptr)
Release a SQ object.
Definition: squirrel.hpp:241
INVALID_TILE
static const TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition: tile_type.h:88
ScriptInstance::IsPaused
bool IsPaused()
Checks if the script is paused.
Definition: script_instance.cpp:556
Squirrel::IsSuspended
bool IsSuspended()
Did the squirrel code suspend or return normally.
Definition: squirrel.cpp:795
ScriptInstance::LoadCompatibilityScripts
bool LoadCompatibilityScripts(const char *api_version, Subdirectory dir)
Load squirrel scripts to emulate an older API.
Definition: script_instance.cpp:115
CMD_END
@ CMD_END
Must ALWAYS be on the end of this list!! (period)
Definition: command_type.h:338
ScriptInstance::Load
void Load(int version)
Load data from a savegame and store it on the stack.
Definition: script_instance.cpp:627
SQSL_ARRAY_TABLE_END
@ SQSL_ARRAY_TABLE_END
Marks the end of an array or table, no data follows.
Definition: script_instance.cpp:339
SaveLoad
SaveLoad type struct.
Definition: saveload.h:517
Squirrel::DecreaseOps
static void DecreaseOps(HSQUIRRELVM vm, int amount)
Tell the VM to remove amount ops from the number of ops till suspend.
Definition: squirrel.cpp:790
SlArray
void SlArray(void *array, size_t length, VarType conv)
Save/Load an array.
Definition: saveload.cpp:1051
lastof
#define lastof(x)
Get the last element of an fixed size array.
Definition: stdafx.h:385
ScriptInstance::GetLogPointer
void * GetLogPointer()
Get the log pointer of this script.
Definition: script_instance.cpp:303
ScriptInstance::CollectGarbage
void CollectGarbage() const
Let the VM collect any garbage.
Definition: script_instance.cpp:258
SQUIRREL_MAX_DEPTH
static const uint SQUIRREL_MAX_DEPTH
The maximum recursive depth for items stored in the savegame.
Definition: script_instance.hpp:20
MAX_SL_OPS
static const int MAX_SL_OPS
The maximum number of operations for saving or loading the data of a script.
Definition: script_info.hpp:19