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