2011-11-29 23:21:33 +00:00
|
|
|
/*
|
|
|
|
* This file is part of OpenTTD.
|
|
|
|
* 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.
|
|
|
|
* 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.
|
|
|
|
* 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/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** @file script_instance.hpp The ScriptInstance tracks a script. */
|
|
|
|
|
|
|
|
#ifndef SCRIPT_INSTANCE_HPP
|
|
|
|
#define SCRIPT_INSTANCE_HPP
|
|
|
|
|
2022-12-28 04:02:26 +00:00
|
|
|
#include <variant>
|
|
|
|
#include <list>
|
2011-11-29 23:21:33 +00:00
|
|
|
#include <squirrel.h>
|
2023-05-14 16:54:42 +00:00
|
|
|
#include "squirrel.hpp"
|
2011-11-29 23:21:33 +00:00
|
|
|
#include "script_suspend.hpp"
|
2023-05-06 14:54:58 +00:00
|
|
|
#include "script_log_types.hpp"
|
2011-11-29 23:21:33 +00:00
|
|
|
|
2011-11-29 23:21:42 +00:00
|
|
|
#include "../command_type.h"
|
2012-01-03 20:26:05 +00:00
|
|
|
#include "../company_type.h"
|
2012-08-13 19:22:26 +00:00
|
|
|
#include "../fileio_type.h"
|
2011-11-29 23:21:42 +00:00
|
|
|
|
2011-12-19 21:00:32 +00:00
|
|
|
static const uint SQUIRREL_MAX_DEPTH = 25; ///< The maximum recursive depth for items stored in the savegame.
|
|
|
|
|
2011-11-29 23:21:33 +00:00
|
|
|
/** Runtime information about a script like a pointer to the squirrel vm and the current state. */
|
|
|
|
class ScriptInstance {
|
2022-12-28 04:02:26 +00:00
|
|
|
private:
|
|
|
|
/** The type of the data that follows in the savegame. */
|
|
|
|
enum SQSaveLoadType {
|
|
|
|
SQSL_INT = 0x00, ///< The following data is an integer.
|
|
|
|
SQSL_STRING = 0x01, ///< The following data is an string.
|
|
|
|
SQSL_ARRAY = 0x02, ///< The following data is an array.
|
|
|
|
SQSL_TABLE = 0x03, ///< The following data is an table.
|
|
|
|
SQSL_BOOL = 0x04, ///< The following data is a boolean.
|
|
|
|
SQSL_NULL = 0x05, ///< A null variable.
|
|
|
|
SQSL_ARRAY_TABLE_END = 0xFF, ///< Marks the end of an array or table, no data follows.
|
|
|
|
};
|
|
|
|
|
2011-11-29 23:21:33 +00:00
|
|
|
public:
|
|
|
|
friend class ScriptObject;
|
|
|
|
friend class ScriptController;
|
|
|
|
|
2022-12-28 04:02:26 +00:00
|
|
|
typedef std::variant<SQInteger, std::string, SQBool, SQSaveLoadType> ScriptDataVariant;
|
|
|
|
typedef std::list<ScriptDataVariant> ScriptData;
|
|
|
|
|
2011-11-29 23:21:33 +00:00
|
|
|
/**
|
|
|
|
* Create a new script.
|
|
|
|
*/
|
2023-05-14 16:54:42 +00:00
|
|
|
ScriptInstance(const char *APIName, ScriptType script_type);
|
2011-11-29 23:21:33 +00:00
|
|
|
virtual ~ScriptInstance();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize the script and prepare it for its first run.
|
2011-11-29 23:21:59 +00:00
|
|
|
* @param main_script The full path of the script to load.
|
2011-11-29 23:21:33 +00:00
|
|
|
* @param instance_name The name of the instance out of the script to load.
|
2011-12-19 21:05:25 +00:00
|
|
|
* @param company Which company this script is serving.
|
2011-11-29 23:21:33 +00:00
|
|
|
*/
|
2023-05-06 07:44:35 +00:00
|
|
|
void Initialize(const std::string &main_script, const std::string &instance_name, CompanyID company);
|
2011-11-29 23:21:33 +00:00
|
|
|
|
2011-11-29 23:27:01 +00:00
|
|
|
/**
|
|
|
|
* Get the value of a setting of the current instance.
|
|
|
|
* @param name The name of the setting.
|
|
|
|
* @return the value for the setting, or -1 if the setting is not known.
|
|
|
|
*/
|
2023-05-06 08:07:54 +00:00
|
|
|
virtual int GetSetting(const std::string &name) = 0;
|
2011-11-29 23:27:01 +00:00
|
|
|
|
2011-11-29 23:27:08 +00:00
|
|
|
/**
|
|
|
|
* Find a library.
|
|
|
|
* @param library The library name to find.
|
|
|
|
* @param version The version the library should have.
|
2019-04-10 21:07:06 +00:00
|
|
|
* @return The library if found, nullptr otherwise.
|
2011-11-29 23:27:08 +00:00
|
|
|
*/
|
2023-05-05 07:53:34 +00:00
|
|
|
virtual class ScriptInfo *FindLibrary(const std::string &library, int version) = 0;
|
2011-11-29 23:27:08 +00:00
|
|
|
|
2011-11-29 23:21:33 +00:00
|
|
|
/**
|
2021-05-09 17:02:17 +00:00
|
|
|
* A script in multiplayer waits for the server to handle its DoCommand.
|
2011-11-29 23:21:33 +00:00
|
|
|
* It keeps waiting for this until this function is called.
|
|
|
|
*/
|
|
|
|
void Continue();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Run the GameLoop of a script.
|
|
|
|
*/
|
|
|
|
void GameLoop();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Let the VM collect any garbage.
|
|
|
|
*/
|
2021-06-12 14:45:26 +00:00
|
|
|
void CollectGarbage();
|
2011-11-29 23:21:33 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the storage of this script.
|
|
|
|
*/
|
|
|
|
class ScriptStorage *GetStorage();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the log pointer of this script.
|
|
|
|
*/
|
2023-05-06 14:54:58 +00:00
|
|
|
ScriptLogTypes::LogData &GetLogData();
|
2011-11-29 23:21:33 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a true/false reply for a DoCommand.
|
|
|
|
*/
|
|
|
|
static void DoCommandReturn(ScriptInstance *instance);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a VehicleID reply for a DoCommand.
|
|
|
|
*/
|
|
|
|
static void DoCommandReturnVehicleID(ScriptInstance *instance);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a SignID reply for a DoCommand.
|
|
|
|
*/
|
|
|
|
static void DoCommandReturnSignID(ScriptInstance *instance);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a GroupID reply for a DoCommand.
|
|
|
|
*/
|
|
|
|
static void DoCommandReturnGroupID(ScriptInstance *instance);
|
|
|
|
|
2011-12-19 21:03:17 +00:00
|
|
|
/**
|
|
|
|
* Return a GoalID reply for a DoCommand.
|
|
|
|
*/
|
|
|
|
static void DoCommandReturnGoalID(ScriptInstance *instance);
|
|
|
|
|
2013-06-09 12:19:09 +00:00
|
|
|
/**
|
|
|
|
* Return a StoryPageID reply for a DoCommand.
|
|
|
|
*/
|
|
|
|
static void DoCommandReturnStoryPageID(ScriptInstance *instance);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a StoryPageElementID reply for a DoCommand.
|
|
|
|
*/
|
|
|
|
static void DoCommandReturnStoryPageElementID(ScriptInstance *instance);
|
|
|
|
|
2022-11-26 17:03:03 +00:00
|
|
|
/**
|
|
|
|
* Return a LeagueTableID reply for a DoCommand.
|
|
|
|
*/
|
|
|
|
static void DoCommandReturnLeagueTableID(ScriptInstance *instance);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a LeagueTableElementID reply for a DoCommand.
|
|
|
|
*/
|
|
|
|
static void DoCommandReturnLeagueTableElementID(ScriptInstance *instance);
|
|
|
|
|
2011-11-29 23:21:33 +00:00
|
|
|
/**
|
|
|
|
* Get the controller attached to the instance.
|
|
|
|
*/
|
|
|
|
class ScriptController *GetController() { return controller; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return the "this script died" value
|
|
|
|
*/
|
|
|
|
inline bool IsDead() const { return this->is_dead; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Call the script Save function and save all data in the savegame.
|
|
|
|
*/
|
|
|
|
void Save();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Don't save any data in the savegame.
|
|
|
|
*/
|
|
|
|
static void SaveEmpty();
|
|
|
|
|
|
|
|
/**
|
2022-12-28 04:02:26 +00:00
|
|
|
* Load data from a savegame.
|
2011-11-29 23:21:33 +00:00
|
|
|
* @param version The version of the script when saving, or -1 if this was
|
|
|
|
* not the original script saving the game.
|
2022-12-28 04:02:26 +00:00
|
|
|
* @return a pointer to loaded data.
|
2011-11-29 23:21:33 +00:00
|
|
|
*/
|
2022-12-28 04:02:26 +00:00
|
|
|
static ScriptData *Load(int version);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Store loaded data on the stack.
|
|
|
|
* @param data The loaded data to store on the stack.
|
|
|
|
*/
|
|
|
|
void LoadOnStack(ScriptData *data);
|
2011-11-29 23:21:33 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Load and discard data from a savegame.
|
|
|
|
*/
|
|
|
|
static void LoadEmpty();
|
|
|
|
|
|
|
|
/**
|
2012-09-21 19:58:18 +00:00
|
|
|
* Suspends the script for the current tick and then pause the execution
|
|
|
|
* of script. The script will not be resumed from its suspended state
|
|
|
|
* until the script has been unpaused.
|
2011-11-29 23:21:33 +00:00
|
|
|
*/
|
2012-09-21 19:58:18 +00:00
|
|
|
void Pause();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if the script is paused.
|
|
|
|
* @return true if the script is paused, otherwise false
|
|
|
|
*/
|
|
|
|
bool IsPaused();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Resume execution of the script. This function will not actually execute
|
|
|
|
* the script, but set a flag so that the script is executed my the usual
|
|
|
|
* mechanism that executes the script.
|
|
|
|
*/
|
|
|
|
void Unpause();
|
2011-11-29 23:21:33 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the number of operations the script can execute before being suspended.
|
|
|
|
* This function is safe to call from within a function called by the script.
|
|
|
|
* @return The number of operations to execute.
|
|
|
|
*/
|
|
|
|
SQInteger GetOpsTillSuspend();
|
|
|
|
|
2020-09-14 17:04:19 +00:00
|
|
|
void LimitOpsTillSuspend(SQInteger suspend);
|
|
|
|
|
2023-05-14 17:04:42 +00:00
|
|
|
uint32 GetMaxOpsTillSuspend() const;
|
|
|
|
|
2011-11-29 23:21:33 +00:00
|
|
|
/**
|
|
|
|
* DoCommand callback function for all commands executed by scripts.
|
|
|
|
* @param result The result of the command.
|
|
|
|
* @param tile The tile on which the command was executed.
|
|
|
|
* @param p1 p1 as given to DoCommandPInternal.
|
|
|
|
* @param p2 p2 as given to DoCommandPInternal.
|
2020-10-17 13:42:46 +00:00
|
|
|
* @param p3 p3 as given to DoCommandPInternal.
|
2019-09-07 16:37:01 +00:00
|
|
|
* @param cmd cmd as given to DoCommandPInternal.
|
|
|
|
* @return true if we handled result.
|
2011-11-29 23:21:33 +00:00
|
|
|
*/
|
2020-10-17 13:42:46 +00:00
|
|
|
bool DoCommandCallback(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2, uint64 p3, uint32 cmd);
|
2011-11-29 23:21:33 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Insert an event for this script.
|
|
|
|
* @param event The event to insert.
|
|
|
|
*/
|
|
|
|
void InsertEvent(class ScriptEvent *event);
|
|
|
|
|
2011-12-19 20:56:50 +00:00
|
|
|
/**
|
|
|
|
* Check if the instance is sleeping, which either happened because the
|
2012-09-21 19:58:18 +00:00
|
|
|
* script executed a DoCommand, executed this.Sleep() or it has been
|
|
|
|
* paused.
|
2011-12-19 20:56:50 +00:00
|
|
|
*/
|
|
|
|
bool IsSleeping() { return this->suspend != 0; }
|
|
|
|
|
2019-04-15 17:49:30 +00:00
|
|
|
size_t GetAllocatedMemory() const;
|
|
|
|
|
2020-09-14 17:04:19 +00:00
|
|
|
void SetMemoryAllocationLimit(size_t limit) const;
|
|
|
|
|
2020-04-18 22:53:30 +00:00
|
|
|
/**
|
|
|
|
* Indicate whether this instance is currently being destroyed.
|
|
|
|
*/
|
|
|
|
inline bool InShutdown() const { return this->in_shutdown; }
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Decrease the ref count of a squirrel object.
|
|
|
|
* @param obj The object to release.
|
|
|
|
**/
|
|
|
|
void ReleaseSQObject(HSQOBJECT *obj);
|
|
|
|
|
2011-11-29 23:21:33 +00:00
|
|
|
protected:
|
|
|
|
class Squirrel *engine; ///< A wrapper around the squirrel vm.
|
2023-05-04 21:06:21 +00:00
|
|
|
std::string versionAPI; ///< Current API used by this script.
|
2011-11-29 23:21:33 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Register all API functions to the VM.
|
|
|
|
*/
|
|
|
|
virtual void RegisterAPI();
|
|
|
|
|
2012-08-13 19:22:26 +00:00
|
|
|
/**
|
|
|
|
* Load squirrel scripts to emulate an older API.
|
|
|
|
* @param api_version: API version to load scripts for
|
|
|
|
* @param dir Subdirectory to find the scripts in
|
|
|
|
* @return true iff script loading should proceed
|
|
|
|
*/
|
2023-05-04 21:06:21 +00:00
|
|
|
bool LoadCompatibilityScripts(const std::string &api_version, Subdirectory dir);
|
2012-08-13 19:22:26 +00:00
|
|
|
|
2011-11-29 23:21:33 +00:00
|
|
|
/**
|
|
|
|
* Tell the script it died.
|
|
|
|
*/
|
|
|
|
virtual void Died();
|
|
|
|
|
2011-11-29 23:21:42 +00:00
|
|
|
/**
|
|
|
|
* Get the callback handling DoCommands in case of networking.
|
|
|
|
*/
|
|
|
|
virtual CommandCallback *GetDoCommandCallback() = 0;
|
|
|
|
|
2011-11-29 23:26:52 +00:00
|
|
|
/**
|
|
|
|
* Load the dummy script.
|
|
|
|
*/
|
|
|
|
virtual void LoadDummyScript() = 0;
|
|
|
|
|
2011-11-29 23:21:33 +00:00
|
|
|
private:
|
|
|
|
class ScriptController *controller; ///< The script main class.
|
|
|
|
class ScriptStorage *storage; ///< Some global information for each running script.
|
|
|
|
SQObject *instance; ///< Squirrel-pointer to the script main class.
|
|
|
|
|
|
|
|
bool is_started; ///< Is the scripts constructor executed?
|
|
|
|
bool is_dead; ///< True if the script has been stopped.
|
|
|
|
bool is_save_data_on_stack; ///< Is the save data still on the squirrel stack?
|
|
|
|
int suspend; ///< The amount of ticks to suspend this script before it's allowed to continue.
|
2012-09-21 19:58:18 +00:00
|
|
|
bool is_paused; ///< Is the script paused? (a paused script will not be executed until unpaused)
|
2020-04-18 22:53:30 +00:00
|
|
|
bool in_shutdown; ///< Is this instance currently being destructed?
|
2011-11-29 23:21:33 +00:00
|
|
|
Script_SuspendCallbackProc *callback; ///< Callback that should be called in the next tick the script runs.
|
2019-04-15 17:49:30 +00:00
|
|
|
size_t last_allocated_memory; ///< Last known allocated memory value (for display for crashed scripts)
|
2020-07-01 17:21:19 +00:00
|
|
|
const char *APIName; ///< Name of the API used for this squirrel.
|
2023-05-14 16:54:42 +00:00
|
|
|
ScriptType script_type; ///< Script type.
|
2023-03-20 17:47:19 +00:00
|
|
|
bool allow_text_param_mismatch; ///< Whether ScriptText parameter mismatches are allowed
|
2011-11-29 23:21:33 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Call the script Load function if it exists and data was loaded
|
|
|
|
* from a savegame.
|
|
|
|
*/
|
|
|
|
bool CallLoad();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Save one object (int / string / array / table) to the savegame.
|
|
|
|
* @param vm The virtual machine to get all the data from.
|
|
|
|
* @param index The index on the squirrel stack of the element to save.
|
|
|
|
* @param max_depth The maximum depth recursive arrays / tables will be stored
|
|
|
|
* with before an error is returned.
|
|
|
|
* @return True if the saving was successful.
|
|
|
|
*/
|
2023-08-14 17:51:58 +00:00
|
|
|
static bool SaveObject(HSQUIRRELVM vm, SQInteger index, int max_depth);
|
2011-11-29 23:21:33 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Load all objects from a savegame.
|
|
|
|
* @return True if the loading was successful.
|
|
|
|
*/
|
2022-12-28 04:02:26 +00:00
|
|
|
static bool LoadObjects(ScriptData *data);
|
|
|
|
|
|
|
|
static bool LoadObjects(HSQUIRRELVM vm, ScriptData *data);
|
2023-03-20 17:47:19 +00:00
|
|
|
|
|
|
|
public:
|
2023-05-14 17:40:24 +00:00
|
|
|
inline ScriptType GetScriptType() const { return this->script_type; }
|
|
|
|
|
2023-03-20 17:47:19 +00:00
|
|
|
inline bool IsTextParamMismatchAllowed() const { return this->allow_text_param_mismatch; }
|
2011-11-29 23:21:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* SCRIPT_INSTANCE_HPP */
|