1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-16 11:33:03 +01:00
Files
OpenRCT2/src/openrct2/scripting/ScriptEngine.h
kyphii 39790779bb Extend color selection dropdown with more colors (#19446)
* Setup for extended palette

* Define order for color picker cells

* Init G2 Palettes in ColoursInitMaps

* Add Glass Palettes

* Use special sprite for Invisible color

* Set up new cheat for special colors

* Add glass palettes to palette_to_g1_offset

* Add entries for new colors in TranslucentWindowPalettes

* Finish implementation of special colors cheat

* Some cleanup

* New colors almost work

* Correct g2 palette loading indices

* Invisible color sprite displays properly

* Repaint works with large scenery and walls

* Prevent random shop items from overflowing to junk palettes

* More cleanup

* Fix glass palettes

* Add mapping of new colors to original colors for UI themes

* Fix junk palettes for random shop items

* Fix missing highlight color in software renderer

* Convert small scenery support flag to allow use of new colors

* Progress on displaying new colors in software renderer

* Fix invisible color scheme sprite

* Formatting cleanup

* Resolve comparison of integer expressions of different signedness

* Index g2 palette maps to fix visible chain lift

* Progress on fixing new colors in software renderer

* Fix station and support colors

* Fix dropdown selected index

* Get invisible color (mostly) working in software renderer

* Use forceBmp for palette resources

* Remove test function definition left in by mistake

* Remove some obsolete range checks for original color values

* Add changelog entry

* Reorder color dropdown based on NE user feedback

* Some cleanup

* Further cleanup

* Formatting

* Add include for GetPaletteMapIndexForColour

* Fix a couple things I broke

* Fix function placement

* Revert "Add include for GetPaletteMapIndexForColour"

This reverts commit 0af9611e6656d792adb7a36efe7dbf3387a4a759.

* Use color constants for color order list

* Make remappable colors contiguous

* turn off clang format for ordered color list

* Appease clang

* Use all colors for random shop item animation

* Improvements to palette map resources

* Fix chain lifts again + adjustments to a few colors

* Update changelog and contributors.md

* Revert changes to S4 and S6 importers which are no longer needed

* Bump network, plugin, and minimum park versions

* Revert "Progress on displaying new colors in software renderer"

This reverts commit 337602e4a7.

* Remove unnecessary comment

---------

Co-authored-by: Trevor Finney <8711258+finneyt@users.noreply.github.com>
2023-04-06 08:36:07 +01:00

317 lines
9.8 KiB
C++

/*****************************************************************************
* Copyright (c) 2014-2023 OpenRCT2 developers
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
*****************************************************************************/
#pragma once
#ifdef ENABLE_SCRIPTING
# include "../actions/CustomAction.h"
# include "../common.h"
# include "../core/FileWatcher.h"
# include "../management/Finance.h"
# include "../world/Location.hpp"
# include "HookEngine.h"
# include "Plugin.h"
# include <future>
# include <list>
# include <memory>
# include <mutex>
# include <queue>
# include <string>
# include <unordered_map>
# include <unordered_set>
# include <vector>
struct duk_hthread;
typedef struct duk_hthread duk_context;
class GameAction;
namespace GameActions
{
class Result;
}
class FileWatcher;
class InteractiveConsole;
namespace OpenRCT2
{
struct IPlatformEnvironment;
}
namespace OpenRCT2::Scripting
{
static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 72;
// Versions marking breaking changes.
static constexpr int32_t API_VERSION_33_PEEP_DEPRECATION = 33;
static constexpr int32_t API_VERSION_63_G2_REORDER = 63;
static constexpr int32_t API_VERSION_68_CUSTOM_ACTION_ARGS = 68;
# ifndef DISABLE_NETWORK
class ScSocketBase;
# endif
class ScriptExecutionInfo
{
private:
std::shared_ptr<Plugin> _plugin;
bool _isGameStateMutable{};
public:
class PluginScope
{
private:
ScriptExecutionInfo& _execInfo;
std::shared_ptr<Plugin> _plugin;
std::shared_ptr<Plugin> _backupPlugin;
bool _backupIsGameStateMutable;
public:
PluginScope(ScriptExecutionInfo& execInfo, std::shared_ptr<Plugin> plugin, bool isGameStateMutable)
: _execInfo(execInfo)
, _plugin(plugin)
{
_backupPlugin = _execInfo._plugin;
_backupIsGameStateMutable = _execInfo._isGameStateMutable;
_execInfo._plugin = std::move(plugin);
_execInfo._isGameStateMutable = isGameStateMutable;
}
PluginScope(const PluginScope&) = delete;
~PluginScope()
{
_execInfo._plugin = _backupPlugin;
_execInfo._isGameStateMutable = _backupIsGameStateMutable;
}
};
std::shared_ptr<Plugin> GetCurrentPlugin()
{
return _plugin;
}
bool IsGameStateMutable()
{
return _isGameStateMutable;
}
};
class DukContext
{
private:
duk_context* _context{};
public:
DukContext();
DukContext(DukContext&) = delete;
DukContext(DukContext&& src) noexcept
: _context(std::move(src._context))
{
src._context = {};
}
~DukContext();
operator duk_context*()
{
return _context;
}
};
using IntervalHandle = int32_t;
struct ScriptInterval
{
std::shared_ptr<Plugin> Owner;
IntervalHandle Handle{};
uint32_t Delay{};
int64_t LastTimestamp{};
DukValue Callback;
bool Repeat{};
bool IsValid() const
{
return Handle != 0;
}
};
class ScriptEngine
{
private:
InteractiveConsole& _console;
IPlatformEnvironment& _env;
DukContext _context;
bool _initialised{};
bool _hotReloadingInitialised{};
bool _transientPluginsEnabled{};
bool _transientPluginsStarted{};
bool _intransientPluginsStarted{};
std::queue<std::tuple<std::promise<void>, std::string>> _evalQueue;
std::vector<std::shared_ptr<Plugin>> _plugins;
uint32_t _lastHotReloadCheckTick{};
HookEngine _hookEngine;
ScriptExecutionInfo _execInfo;
DukValue _sharedStorage;
DukValue _parkStorage;
uint32_t _lastIntervalTimestamp{};
std::vector<ScriptInterval> _intervals;
std::unique_ptr<FileWatcher> _pluginFileWatcher;
std::unordered_set<std::string> _changedPluginFiles;
std::mutex _changedPluginFilesMutex;
std::vector<std::function<void(std::shared_ptr<Plugin>)>> _pluginStoppedSubscriptions;
struct CustomActionInfo
{
std::shared_ptr<Plugin> Owner;
std::string Name;
DukValue Query;
DukValue Execute;
};
std::unordered_map<std::string, CustomActionInfo> _customActions;
# ifndef DISABLE_NETWORK
std::list<std::shared_ptr<ScSocketBase>> _sockets;
# endif
public:
ScriptEngine(InteractiveConsole& console, IPlatformEnvironment& env);
ScriptEngine(ScriptEngine&) = delete;
duk_context* GetContext()
{
return _context;
}
HookEngine& GetHookEngine()
{
return _hookEngine;
}
ScriptExecutionInfo& GetExecInfo()
{
return _execInfo;
}
DukValue GetSharedStorage()
{
return _sharedStorage;
}
DukValue GetParkStorage()
{
return _parkStorage;
}
std::vector<std::shared_ptr<Plugin>>& GetPlugins()
{
return _plugins;
}
std::vector<std::shared_ptr<Plugin>> GetRemotePlugins()
{
std::vector<std::shared_ptr<Plugin>> res;
for (const auto& plugin : _plugins)
{
const auto& metadata = plugin->GetMetadata();
if (metadata.Type == OpenRCT2::Scripting::PluginType::Remote)
{
res.push_back(plugin);
}
}
return res;
}
void ClearParkStorage();
std::string GetParkStorageAsJSON();
void SetParkStorageFromJSON(std::string_view value);
void Initialise();
void LoadTransientPlugins();
void UnloadTransientPlugins();
void StopUnloadRegisterAllPlugins();
void Tick();
std::future<void> Eval(const std::string& s);
DukValue ExecutePluginCall(
const std::shared_ptr<Plugin>& plugin, const DukValue& func, const std::vector<DukValue>& args,
bool isGameStateMutable);
DukValue ExecutePluginCall(
std::shared_ptr<Plugin> plugin, const DukValue& func, const DukValue& thisValue, const std::vector<DukValue>& args,
bool isGameStateMutable);
void LogPluginInfo(std::string_view message);
void LogPluginInfo(const std::shared_ptr<Plugin>& plugin, std::string_view message);
void SubscribeToPluginStoppedEvent(std::function<void(std::shared_ptr<Plugin>)> callback)
{
_pluginStoppedSubscriptions.push_back(callback);
}
void AddNetworkPlugin(std::string_view code);
void RemoveNetworkPlugins();
[[nodiscard]] GameActions::Result QueryOrExecuteCustomGameAction(const CustomAction& action, bool isExecute);
bool RegisterCustomAction(
const std::shared_ptr<Plugin>& plugin, std::string_view action, const DukValue& query, const DukValue& execute);
void RunGameActionHooks(const GameAction& action, GameActions::Result& result, bool isExecute);
[[nodiscard]] std::unique_ptr<GameAction> CreateGameAction(const std::string& actionid, const DukValue& args);
[[nodiscard]] DukValue GameActionResultToDuk(const GameAction& action, const GameActions::Result& result);
void SaveSharedStorage();
IntervalHandle AddInterval(const std::shared_ptr<Plugin>& plugin, int32_t delay, bool repeat, DukValue&& callback);
void RemoveInterval(const std::shared_ptr<Plugin>& plugin, IntervalHandle handle);
# ifndef DISABLE_NETWORK
void AddSocket(const std::shared_ptr<ScSocketBase>& socket);
# endif
private:
void RegisterConstants();
void RefreshPlugins();
std::vector<std::string> GetPluginFiles() const;
void UnregisterPlugin(std::string_view path);
void RegisterPlugin(std::string_view path);
void CheckAndStartPlugins();
void StartIntransientPlugins();
void StartTransientPlugins();
void LoadPlugin(const std::string& path);
void LoadPlugin(std::shared_ptr<Plugin>& plugin);
void UnloadPlugin(std::shared_ptr<Plugin>& plugin);
void StartPlugin(std::shared_ptr<Plugin> plugin);
void StopPlugin(std::shared_ptr<Plugin> plugin);
void ReloadPlugin(std::shared_ptr<Plugin> plugin);
static bool ShouldLoadScript(std::string_view path);
bool ShouldStartPlugin(const std::shared_ptr<Plugin>& plugin);
void SetupHotReloading();
void DoAutoReloadPluginCheck();
void AutoReloadPlugins();
void ProcessREPL();
void RemoveCustomGameActions(const std::shared_ptr<Plugin>& plugin);
[[nodiscard]] GameActions::Result DukToGameActionResult(const DukValue& d);
static std::string_view ExpenditureTypeToString(ExpenditureType expenditureType);
static ExpenditureType StringToExpenditureType(std::string_view expenditureType);
void InitSharedStorage();
void LoadSharedStorage();
IntervalHandle AllocateHandle();
void UpdateIntervals();
void RemoveIntervals(const std::shared_ptr<Plugin>& plugin);
void UpdateSockets();
void RemoveSockets(const std::shared_ptr<Plugin>& plugin);
};
bool IsGameStateMutable();
void ThrowIfGameStateNotMutable();
int32_t GetTargetAPIVersion();
std::string Stringify(const DukValue& value);
} // namespace OpenRCT2::Scripting
#endif