Start work on custom game actions

This commit is contained in:
Ted John 2020-03-01 21:56:49 +00:00
parent 07ed0f5c0e
commit 4e4379e6ef
7 changed files with 108 additions and 7 deletions

View File

@ -98,6 +98,7 @@ enum GAME_COMMAND
GAME_COMMAND_REMOVE_FOOTPATH_SCENERY, // GA
GAME_COMMAND_GUEST_SET_FLAGS, // GA
GAME_COMMAND_SET_DATE, // GA
GAME_COMMAND_CUSTOM, // GA
GAME_COMMAND_COUNT,
};

View File

@ -0,0 +1,56 @@
/*****************************************************************************
* Copyright (c) 2014-2020 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 "../Context.h"
# include "../scripting/ScriptEngine.h"
# include "GameAction.h"
DEFINE_GAME_ACTION(CustomAction, GAME_COMMAND_CUSTOM, GameActionResult)
{
private:
std::string _id;
std::string _json;
public:
CustomAction() = default;
CustomAction(const std::string& id, const std::string& json)
: _id(id)
, _json(json)
{
}
uint16_t GetActionFlags() const override
{
return GameAction::GetActionFlags() | GA_FLAGS::ALLOW_WHILE_PAUSED;
}
void Serialise(DataSerialiser & stream) override
{
GameAction::Serialise(stream);
stream << DS_TAG(_id) << DS_TAG(_json);
}
GameActionResult::Ptr Query() const override
{
auto& scriptingEngine = OpenRCT2::GetContext()->GetScriptEngine();
return scriptingEngine.QueryOrExecuteCustomGameAction(_id, _json, false);
}
GameActionResult::Ptr Execute() const override
{
auto& scriptingEngine = OpenRCT2::GetContext()->GetScriptEngine();
return scriptingEngine.QueryOrExecuteCustomGameAction(_id, _json, true);
}
};
#endif

View File

@ -15,6 +15,7 @@
#include "BannerSetStyleAction.hpp"
#include "ClearAction.hpp"
#include "ClimateSetAction.hpp"
#include "CustomAction.hpp"
#include "FootpathPlaceAction.hpp"
#include "FootpathPlaceFromTrackAction.hpp"
#include "FootpathRemoveAction.hpp"
@ -171,5 +172,8 @@ namespace GameActions
Register<GuestSetFlagsAction>();
Register<ParkSetDateAction>();
Register<SetCheatAction>();
#ifdef __ENABLE_SCRIPTING__
Register<CustomAction>();
#endif
}
} // namespace GameActions

View File

@ -2997,12 +2997,15 @@ void Network::Server_Handle_GAME_ACTION(NetworkConnection& connection, NetworkPa
return;
}
// Check if player's group permission allows command to run
NetworkGroup* group = GetGroupByID(connection.Player->Group);
if (group == nullptr || group->CanPerformCommand(actionType) == false)
if (actionType != GAME_COMMAND_CUSTOM)
{
Server_Send_SHOWERROR(connection, STR_CANT_DO_THIS, STR_PERMISSION_DENIED);
return;
// Check if player's group permission allows command to run
NetworkGroup* group = GetGroupByID(connection.Player->Group);
if (group == nullptr || group->CanPerformCommand(actionType) == false)
{
Server_Send_SHOWERROR(connection, STR_CANT_DO_THIS, STR_PERMISSION_DENIED);
return;
}
}
// Create and enqueue the action.

View File

@ -11,6 +11,7 @@
#ifdef __ENABLE_SCRIPTING__
# include "../actions/CustomAction.hpp"
# include "../actions/ParkSetNameAction.hpp"
# include "../actions/SmallSceneryPlaceAction.hpp"
# include "Duktape.hpp"
@ -91,7 +92,7 @@ namespace OpenRCT2::Scripting
if (isExecute)
{
action->SetCallback(
[this, &plugin, &callback](const GameAction*, const GameActionResult* res) -> void {
[this, plugin, callback](const GameAction*, const GameActionResult* res) -> void {
HandleGameActionResult(plugin, *res, callback);
});
GameActions::Execute(action.get());
@ -143,7 +144,16 @@ namespace OpenRCT2::Scripting
uint8_t secondaryColour = args["secondaryColour"].as_int();
return std::make_unique<SmallSceneryPlaceAction>(loc, quadrant, sceneryType, primaryColour, secondaryColour);
}
return {};
else
{
// Serialise args to json so that it can be sent
auto ctx = args.context();
args.push();
auto jsonz = duk_json_encode(ctx, -1);
auto json = std::string(jsonz);
duk_pop(ctx);
return std::make_unique<CustomAction>(actionid, json);
}
}
void HandleGameActionResult(

View File

@ -694,6 +694,30 @@ void ScriptEngine::AddNetworkPlugin(const std::string_view& code)
LoadPlugin(plugin);
}
std::unique_ptr<GameActionResult> ScriptEngine::QueryOrExecuteCustomGameAction(
const std::string_view& id,
const std::string_view& args,
bool isExecute)
{
// Deserialise the JSON args
std::string argsz(args);
duk_push_string(_context, argsz.c_str());
duk_json_decode(_context, -1);
auto dukArgs = DukValue::take_from_stack(_context);
// Ready to call plugin handler
if (isExecute)
{
std::printf("EXECUTE: %s(%s)\n", std::string(id).c_str(), std::string(args).c_str());
}
else
{
std::printf("QUERY: %s(%s)\n", std::string(id).c_str(), std::string(args).c_str());
}
return std::make_unique<GameActionResult>();
}
std::string OpenRCT2::Scripting::Stringify(const DukValue& val)
{
return ExpressionStringifier::StringifyExpression(val);

View File

@ -27,6 +27,7 @@
struct duk_hthread;
typedef struct duk_hthread duk_context;
class GameActionResult;
class FileWatcher;
class InteractiveConsole;
@ -155,6 +156,8 @@ namespace OpenRCT2::Scripting
void AddNetworkPlugin(const std::string_view& code);
std::unique_ptr<GameActionResult> QueryOrExecuteCustomGameAction(const std::string_view& id, const std::string_view& args, bool isExecute);
private:
void Initialise();
void StartPlugins();