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 8 /** @file script_instance.hpp The ScriptInstance tracks a script. */ 9 10 #ifndef SCRIPT_INSTANCE_HPP 11 #define SCRIPT_INSTANCE_HPP 12 13 #include <squirrel.h> 14 #include "script_suspend.hpp" 15 16 #include "../command_type.h" 17 #include "../company_type.h" 18 #include "../fileio_type.h" 19 20 static const uint SQUIRREL_MAX_DEPTH = 25; ///< The maximum recursive depth for items stored in the savegame. 21 22 /** Runtime information about a script like a pointer to the squirrel vm and the current state. */ 23 class ScriptInstance { 24 public: 25 friend class ScriptObject; 26 friend class ScriptController; 27 28 /** 29 * Create a new script. 30 */ 31 ScriptInstance(const char *APIName); 32 virtual ~ScriptInstance(); 33 34 /** 35 * Initialize the script and prepare it for its first run. 36 * @param main_script The full path of the script to load. 37 * @param instance_name The name of the instance out of the script to load. 38 * @param company Which company this script is serving. 39 */ 40 void Initialize(const char *main_script, const char *instance_name, CompanyID company); 41 42 /** 43 * Get the value of a setting of the current instance. 44 * @param name The name of the setting. 45 * @return the value for the setting, or -1 if the setting is not known. 46 */ 47 virtual int GetSetting(const char *name) = 0; 48 49 /** 50 * Find a library. 51 * @param library The library name to find. 52 * @param version The version the library should have. 53 * @return The library if found, nullptr otherwise. 54 */ 55 virtual class ScriptInfo *FindLibrary(const char *library, int version) = 0; 56 57 /** 58 * A script in multiplayer waits for the server to handle its DoCommand. 59 * It keeps waiting for this until this function is called. 60 */ 61 void Continue(); 62 63 /** 64 * Run the GameLoop of a script. 65 */ 66 void GameLoop(); 67 68 /** 69 * Let the VM collect any garbage. 70 */ 71 void CollectGarbage(); 72 73 /** 74 * Get the storage of this script. 75 */ 76 class ScriptStorage *GetStorage(); 77 78 /** 79 * Get the log pointer of this script. 80 */ 81 void *GetLogPointer(); 82 83 /** 84 * Return a true/false reply for a DoCommand. 85 */ 86 static void DoCommandReturn(ScriptInstance *instance); 87 88 /** 89 * Return a VehicleID reply for a DoCommand. 90 */ 91 static void DoCommandReturnVehicleID(ScriptInstance *instance); 92 93 /** 94 * Return a SignID reply for a DoCommand. 95 */ 96 static void DoCommandReturnSignID(ScriptInstance *instance); 97 98 /** 99 * Return a GroupID reply for a DoCommand. 100 */ 101 static void DoCommandReturnGroupID(ScriptInstance *instance); 102 103 /** 104 * Return a GoalID reply for a DoCommand. 105 */ 106 static void DoCommandReturnGoalID(ScriptInstance *instance); 107 108 /** 109 * Return a StoryPageID reply for a DoCommand. 110 */ 111 static void DoCommandReturnStoryPageID(ScriptInstance *instance); 112 113 /** 114 * Return a StoryPageElementID reply for a DoCommand. 115 */ 116 static void DoCommandReturnStoryPageElementID(ScriptInstance *instance); 117 118 /** 119 * Get the controller attached to the instance. 120 */ GetController()121 class ScriptController *GetController() { return controller; } 122 123 /** 124 * Return the "this script died" value 125 */ IsDead() const126 inline bool IsDead() const { return this->is_dead; } 127 128 /** 129 * Call the script Save function and save all data in the savegame. 130 */ 131 void Save(); 132 133 /** 134 * Don't save any data in the savegame. 135 */ 136 static void SaveEmpty(); 137 138 /** 139 * Load data from a savegame and store it on the stack. 140 * @param version The version of the script when saving, or -1 if this was 141 * not the original script saving the game. 142 */ 143 void Load(int version); 144 145 /** 146 * Load and discard data from a savegame. 147 */ 148 static void LoadEmpty(); 149 150 /** 151 * Suspends the script for the current tick and then pause the execution 152 * of script. The script will not be resumed from its suspended state 153 * until the script has been unpaused. 154 */ 155 void Pause(); 156 157 /** 158 * Checks if the script is paused. 159 * @return true if the script is paused, otherwise false 160 */ 161 bool IsPaused(); 162 163 /** 164 * Resume execution of the script. This function will not actually execute 165 * the script, but set a flag so that the script is executed my the usual 166 * mechanism that executes the script. 167 */ 168 void Unpause(); 169 170 /** 171 * Get the number of operations the script can execute before being suspended. 172 * This function is safe to call from within a function called by the script. 173 * @return The number of operations to execute. 174 */ 175 SQInteger GetOpsTillSuspend(); 176 177 /** 178 * DoCommand callback function for all commands executed by scripts. 179 * @param result The result of the command. 180 * @param tile The tile on which the command was executed. 181 * @param p1 p1 as given to DoCommandPInternal. 182 * @param p2 p2 as given to DoCommandPInternal. 183 * @param cmd cmd as given to DoCommandPInternal. 184 * @return true if we handled result. 185 */ 186 bool DoCommandCallback(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint32 cmd); 187 188 /** 189 * Insert an event for this script. 190 * @param event The event to insert. 191 */ 192 void InsertEvent(class ScriptEvent *event); 193 194 /** 195 * Check if the instance is sleeping, which either happened because the 196 * script executed a DoCommand, executed this.Sleep() or it has been 197 * paused. 198 */ IsSleeping()199 bool IsSleeping() { return this->suspend != 0; } 200 201 size_t GetAllocatedMemory() const; 202 203 /** 204 * Indicate whether this instance is currently being destroyed. 205 */ InShutdown() const206 inline bool InShutdown() const { return this->in_shutdown; } 207 208 /** 209 * Decrease the ref count of a squirrel object. 210 * @param obj The object to release. 211 **/ 212 void ReleaseSQObject(HSQOBJECT *obj); 213 214 protected: 215 class Squirrel *engine; ///< A wrapper around the squirrel vm. 216 const char *versionAPI; ///< Current API used by this script. 217 218 /** 219 * Register all API functions to the VM. 220 */ 221 virtual void RegisterAPI(); 222 223 /** 224 * Load squirrel scripts to emulate an older API. 225 * @param api_version: API version to load scripts for 226 * @param dir Subdirectory to find the scripts in 227 * @return true iff script loading should proceed 228 */ 229 bool LoadCompatibilityScripts(const char *api_version, Subdirectory dir); 230 231 /** 232 * Tell the script it died. 233 */ 234 virtual void Died(); 235 236 /** 237 * Get the callback handling DoCommands in case of networking. 238 */ 239 virtual CommandCallback *GetDoCommandCallback() = 0; 240 241 /** 242 * Load the dummy script. 243 */ 244 virtual void LoadDummyScript() = 0; 245 246 private: 247 class ScriptController *controller; ///< The script main class. 248 class ScriptStorage *storage; ///< Some global information for each running script. 249 SQObject *instance; ///< Squirrel-pointer to the script main class. 250 251 bool is_started; ///< Is the scripts constructor executed? 252 bool is_dead; ///< True if the script has been stopped. 253 bool is_save_data_on_stack; ///< Is the save data still on the squirrel stack? 254 int suspend; ///< The amount of ticks to suspend this script before it's allowed to continue. 255 bool is_paused; ///< Is the script paused? (a paused script will not be executed until unpaused) 256 bool in_shutdown; ///< Is this instance currently being destructed? 257 Script_SuspendCallbackProc *callback; ///< Callback that should be called in the next tick the script runs. 258 size_t last_allocated_memory; ///< Last known allocated memory value (for display for crashed scripts) 259 260 /** 261 * Call the script Load function if it exists and data was loaded 262 * from a savegame. 263 */ 264 bool CallLoad(); 265 266 /** 267 * Save one object (int / string / array / table) to the savegame. 268 * @param vm The virtual machine to get all the data from. 269 * @param index The index on the squirrel stack of the element to save. 270 * @param max_depth The maximum depth recursive arrays / tables will be stored 271 * with before an error is returned. 272 * @param test If true, don't really store the data but only check if it is 273 * valid. 274 * @return True if the saving was successful. 275 */ 276 static bool SaveObject(HSQUIRRELVM vm, SQInteger index, int max_depth, bool test); 277 278 /** 279 * Load all objects from a savegame. 280 * @return True if the loading was successful. 281 */ 282 static bool LoadObjects(HSQUIRRELVM vm); 283 }; 284 285 #endif /* SCRIPT_INSTANCE_HPP */ 286