mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-06 06:32:56 +01:00
Implement query and execute of game actions
This commit is contained in:
24
distribution/openrct2.d.ts
vendored
24
distribution/openrct2.d.ts
vendored
@@ -73,8 +73,8 @@ declare global {
|
||||
|
||||
interface GameActionResult {
|
||||
error: string;
|
||||
errorTitle: string;
|
||||
errorMessage: string;
|
||||
errorTitle?: string;
|
||||
errorMessage?: string;
|
||||
position: Coord3;
|
||||
cost: number;
|
||||
expenditureType: ExpenditureType;
|
||||
@@ -125,6 +125,24 @@ declare global {
|
||||
*/
|
||||
registerGameAction(desc: GameActionDesc): void;
|
||||
|
||||
/**
|
||||
* Query the result of running a game action. This allows you to check the outcome and validity of
|
||||
* an action without actually executing it.
|
||||
* @param action The name of the action.
|
||||
* @param args The action parameters.
|
||||
* @param callback The function to be called with the result of the action.
|
||||
*/
|
||||
queryAction(action: string, args: object, callback: (result: GameActionResult) => void): void;
|
||||
|
||||
/**
|
||||
* Executes a game action. In a network game, this will send a request to the server and wait
|
||||
* for the server to reply.
|
||||
* @param action The name of the action.
|
||||
* @param args The action parameters.
|
||||
* @param callback The function to be called with the result of the action.
|
||||
*/
|
||||
executeAction(action: string, args: object, callback: (result: GameActionResult) => void): void;
|
||||
|
||||
/**
|
||||
* Subscribes to the given hook.
|
||||
*/
|
||||
@@ -663,8 +681,6 @@ declare global {
|
||||
kickPlayer(index: number): void;
|
||||
sendMessage(message: string): void;
|
||||
sendMessage(message: string, players: number[]): void;
|
||||
sendQueryAction(action: string, args: object, callback: (result: GameActionResult) => void): void;
|
||||
sendExecuteAction(action: string, args: object, callback: (result: GameActionResult) => void): void;
|
||||
}
|
||||
|
||||
interface GameDate {
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
#ifdef __ENABLE_SCRIPTING__
|
||||
|
||||
# include "../actions/ParkSetNameAction.hpp"
|
||||
# include "../actions/SmallSceneryPlaceAction.hpp"
|
||||
# include "Duktape.hpp"
|
||||
# include "HookEngine.h"
|
||||
# include "ScDisposable.hpp"
|
||||
@@ -34,6 +36,7 @@ namespace OpenRCT2::Scripting
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
void registerIntent(const DukValue& desc)
|
||||
{
|
||||
}
|
||||
@@ -61,10 +64,128 @@ namespace OpenRCT2::Scripting
|
||||
return std::make_shared<ScDisposable>([this, hookType, cookie]() { _hookEngine.Unsubscribe(hookType, cookie); });
|
||||
}
|
||||
|
||||
void queryAction(const std::string& action, const DukValue& args, const DukValue& callback)
|
||||
{
|
||||
QueryOrExecuteAction(action, args, callback, false);
|
||||
}
|
||||
|
||||
void executeAction(const std::string& action, const DukValue& args, const DukValue& callback)
|
||||
{
|
||||
QueryOrExecuteAction(action, args, callback, true);
|
||||
}
|
||||
|
||||
void QueryOrExecuteAction(const std::string& actionid, const DukValue& args, const DukValue& callback, bool isExecute)
|
||||
{
|
||||
auto& scriptEngine = GetContext()->GetScriptEngine();
|
||||
auto ctx = scriptEngine.GetContext();
|
||||
if (args.type() == DukValue::Type::OBJECT)
|
||||
{
|
||||
if (callback.is_function())
|
||||
{
|
||||
try
|
||||
{
|
||||
auto action = CreateGameAction(actionid, args);
|
||||
if (action != nullptr)
|
||||
{
|
||||
auto plugin = scriptEngine.GetExecInfo().GetCurrentPlugin();
|
||||
if (isExecute)
|
||||
{
|
||||
action->SetCallback(
|
||||
[this, &plugin, &callback](const GameAction*, const GameActionResult* res) -> void {
|
||||
HandleGameActionResult(plugin, *res, callback);
|
||||
});
|
||||
GameActions::Execute(action.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
auto res = GameActions::Query(action.get());
|
||||
HandleGameActionResult(plugin, *res, callback);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
duk_error(ctx, DUK_ERR_ERROR, "Unknown action.");
|
||||
}
|
||||
}
|
||||
catch (DukException&)
|
||||
{
|
||||
duk_error(ctx, DUK_ERR_ERROR, "Invalid action parameters.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
duk_error(ctx, DUK_ERR_ERROR, "Callback was not a function.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
duk_error(ctx, DUK_ERR_ERROR, "Invalid action parameters.");
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<GameAction> CreateGameAction(const std::string& actionid, const DukValue& args)
|
||||
{
|
||||
if (actionid == "parksetname")
|
||||
{
|
||||
auto name = args["name"].as_string();
|
||||
return std::make_unique<ParkSetNameAction>(name);
|
||||
}
|
||||
else if (actionid == "smallsceneryplace")
|
||||
{
|
||||
CoordsXYZD loc;
|
||||
loc.x = args["x"].as_int();
|
||||
loc.y = args["y"].as_int();
|
||||
loc.z = args["z"].as_int();
|
||||
loc.direction = args["direction"].as_int();
|
||||
uint8_t quadrant = args["quadrant"].as_int();
|
||||
uint8_t sceneryType = args["object"].as_int();
|
||||
uint8_t primaryColour = args["primaryColour"].as_int();
|
||||
uint8_t secondaryColour = args["secondaryColour"].as_int();
|
||||
return std::make_unique<SmallSceneryPlaceAction>(loc, quadrant, sceneryType, primaryColour, secondaryColour);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void HandleGameActionResult(
|
||||
const std::shared_ptr<Plugin>& plugin, const GameActionResult& res, const DukValue& callback)
|
||||
{
|
||||
// Construct result object
|
||||
auto& scriptEngine = GetContext()->GetScriptEngine();
|
||||
auto ctx = scriptEngine.GetContext();
|
||||
auto objIdx = duk_push_object(ctx);
|
||||
duk_push_int(ctx, static_cast<duk_int_t>(res.Error));
|
||||
duk_put_prop_string(ctx, objIdx, "error");
|
||||
|
||||
if (res.Error != GA_ERROR::OK)
|
||||
{
|
||||
auto title = format_string(res.ErrorTitle, nullptr);
|
||||
duk_push_string(ctx, title.c_str());
|
||||
duk_put_prop_string(ctx, objIdx, "errorTitle");
|
||||
|
||||
auto message = format_string(res.ErrorMessage, res.ErrorMessageArgs.data());
|
||||
duk_push_string(ctx, message.c_str());
|
||||
duk_put_prop_string(ctx, objIdx, "errorMessage");
|
||||
}
|
||||
|
||||
duk_push_int(ctx, static_cast<duk_int_t>(res.Cost));
|
||||
duk_put_prop_string(ctx, objIdx, "cost");
|
||||
|
||||
duk_push_int(ctx, static_cast<duk_int_t>(res.Expenditure));
|
||||
duk_put_prop_string(ctx, objIdx, "expenditureType");
|
||||
|
||||
auto args = DukValue::take_from_stack(ctx);
|
||||
|
||||
// Call the plugin callback and pass the result object
|
||||
scriptEngine.ExecutePluginCall(plugin, callback, { args }, false);
|
||||
}
|
||||
|
||||
public:
|
||||
static void Register(duk_context* ctx)
|
||||
{
|
||||
dukglue_register_method(ctx, &ScContext::registerIntent, "registerIntent");
|
||||
dukglue_register_method(ctx, &ScContext::subscribe, "subscribe");
|
||||
dukglue_register_method(ctx, &ScContext::queryAction, "queryAction");
|
||||
dukglue_register_method(ctx, &ScContext::executeAction, "executeAction");
|
||||
}
|
||||
};
|
||||
} // namespace OpenRCT2::Scripting
|
||||
|
||||
Reference in New Issue
Block a user