diff --git a/SDK/include/Server/Components/Pawn/pawn_impl.hpp b/SDK/include/Server/Components/Pawn/Impl/pawn_impl.hpp similarity index 99% rename from SDK/include/Server/Components/Pawn/pawn_impl.hpp rename to SDK/include/Server/Components/Pawn/Impl/pawn_impl.hpp index fcf3491f1..eec60d2f1 100644 --- a/SDK/include/Server/Components/Pawn/pawn_impl.hpp +++ b/SDK/include/Server/Components/Pawn/Impl/pawn_impl.hpp @@ -1,7 +1,7 @@ #pragma once // This file should only be included in one place. -#include "pawn.hpp" +#include #if defined PAWN_NATIVES_HAS_FUNC #include diff --git a/SDK/include/Server/Components/Pawn/Impl/pawn_natives.hpp b/SDK/include/Server/Components/Pawn/Impl/pawn_natives.hpp new file mode 100644 index 000000000..a90be2b05 --- /dev/null +++ b/SDK/include/Server/Components/Pawn/Impl/pawn_natives.hpp @@ -0,0 +1,1366 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + * + * The original code is copyright (c) 2022, open.mp team and contributors. + */ + +#pragma once + +#include +#include + +#include + +/// The bool is used because variant is initialised to index 0 by default +using OutputOnlyString = std::variant; + +/// Macro to define a script param for a pool entry +/// Example with IPlayer from the players pool: +/// Using IPlayer& in a script function throws an exception if the player with the specified ID doesn't exist +/// Using IPlayer* in a script function makes the IPlayer entry optional and is nullptr if the player with the specified ID doesn't exist +#define POOL_PARAM(type, poolPtr) \ + template <> \ + struct ParamLookup \ + { \ + static type* Val(cell ref) noexcept \ + { \ + auto pool = getAmxLookups()->poolPtr; \ + if (pool) \ + { \ + return pool->get(ref); \ + } \ + return nullptr; \ + } \ + }; \ + \ + template <> \ + class ParamCast \ + { \ + public: \ + ParamCast(AMX* amx, cell* params, int idx) noexcept \ + { \ + value_ = ParamLookup::Val(params[idx]); \ + } \ + \ + ~ParamCast() \ + { \ + } \ + \ + ParamCast(ParamCast const&) = delete; \ + ParamCast(ParamCast&&) = delete; \ + \ + operator type*() \ + { \ + return value_; \ + } \ + \ + bool Error() const \ + { \ + return false; \ + } \ + \ + static constexpr int Size = 1; \ + \ + private: \ + type* value_; \ + }; \ + \ + template <> \ + class ParamCast \ + { \ + public: \ + ParamCast(AMX* amx, cell* params, int idx) \ + { \ + value_ = ParamLookup::Val(params[idx]); \ + if (value_ == nullptr) \ + { \ + error_ = true; \ + } \ + } \ + \ + ~ParamCast() \ + { \ + } \ + \ + ParamCast(ParamCast const&) = delete; \ + ParamCast(ParamCast&&) = delete; \ + \ + operator type&() \ + { \ + return *value_; \ + } \ + \ + bool Error() const \ + { \ + return error_; \ + } \ + \ + static constexpr int Size = 1; \ + \ + private: \ + type* value_; \ + bool error_ = false; \ + }; \ + \ + template <> \ + class ParamCast \ + { \ + public: \ + ParamCast(AMX*, cell*, int) = delete; \ + ParamCast() = delete; \ + }; + +/// Macro to define a script param for a player pool entry +/// Always throws if the player ID specified in the first parameter is invalid as it's required to get the IPlayerObjectData pool +/// Example with IPlayerObject from the IPlayerObjectData pool: +/// Using IPlayerObject& in a script function throws an exception if the object with the specified ID doesn't exist +/// Using IPlayerObject* in a script function makes the IPlayerObject entry optional and is nullptr if the object with the specified ID doesn't exist +#define PLAYER_POOL_PARAM(type, dataType) \ + template <> \ + struct ParamLookup \ + { \ + static type* Val(IPlayer* player, cell ref) noexcept \ + { \ + if (player == nullptr) \ + { \ + return nullptr; \ + } \ + \ + auto data = queryExtension(player); \ + if (data) \ + { \ + return data->get(ref); \ + } \ + return nullptr; \ + } \ + }; \ + \ + template <> \ + class ParamCast \ + { \ + public: \ + ParamCast(AMX* amx, cell* params, int idx) \ + { \ + auto player = ParamLookup::Val(params[1] /* first param is always playerid */); \ + value_ = ParamLookup::Val(player, params[idx]); \ + } \ + \ + ~ParamCast() \ + { \ + } \ + \ + ParamCast(ParamCast const&) = delete; \ + ParamCast(ParamCast&&) = delete; \ + \ + operator type*() \ + { \ + return value_; \ + } \ + \ + bool Error() const \ + { \ + return false; \ + } \ + \ + static constexpr int Size = 1; \ + \ + private: \ + type* value_; \ + }; \ + \ + template <> \ + class ParamCast \ + { \ + public: \ + ParamCast(AMX* amx, cell* params, int idx) = delete; \ + ParamCast() = delete; \ + }; \ + \ + template <> \ + class ParamCast \ + { \ + public: \ + ParamCast(AMX* amx, cell* params, int idx) \ + { \ + auto player = ParamLookup::Val(params[1] /* first param is always playerid */); \ + value_ = ParamLookup::Val(player, params[idx]); \ + if (value_ == nullptr) \ + { \ + error_ = true; \ + } \ + } \ + \ + ~ParamCast() \ + { \ + } \ + \ + ParamCast(ParamCast const&) = delete; \ + ParamCast(ParamCast&&) = delete; \ + \ + operator type&() \ + { \ + return *value_; \ + } \ + \ + bool Error() const \ + { \ + return error_; \ + } \ + \ + static constexpr int Size = 1; \ + \ + private: \ + type* value_; \ + bool error_ = false; \ + }; \ + \ + template <> \ + class ParamCast \ + { \ + public: \ + ParamCast(AMX*, cell*, int) = delete; \ + ParamCast() = delete; \ + }; + +/// Macro to define a script param for a player data extension. +/// Throws an exception when playerid is invalid or player data's retrieval fails. +/// Unless it is casting to a pointer which becomes nullptr if either player id or player data is invalid. +#define PLAYER_DATA_PARAM(type) \ + template <> \ + struct ParamLookup \ + { \ + static type* Val(IPlayer* player) noexcept \ + { \ + if (player == nullptr) \ + { \ + return nullptr; \ + } \ + return queryExtension(player); \ + } \ + }; \ + \ + template <> \ + class ParamCast \ + { \ + public: \ + ParamCast(AMX* amx, cell* params, int idx) \ + { \ + value_ = ParamLookup::Val(ParamLookup::Val(params[idx])); \ + } \ + \ + ~ParamCast() \ + { \ + } \ + \ + ParamCast(ParamCast const&) = delete; \ + ParamCast(ParamCast&&) = delete; \ + \ + operator type*() \ + { \ + return value_; \ + } \ + \ + bool Error() const \ + { \ + return false; \ + } \ + \ + static constexpr int Size = 1; \ + \ + private: \ + type* value_; \ + }; \ + \ + template <> \ + class ParamCast \ + { \ + public: \ + ParamCast(AMX* amx, cell* params, int idx) = delete; \ + ParamCast() = delete; \ + }; \ + \ + template <> \ + class ParamCast \ + { \ + public: \ + ParamCast(AMX* amx, cell* params, int idx) \ + { \ + auto player = ParamLookup::Val(params[idx]); \ + value_ = ParamLookup::Val(player); \ + if (value_ == nullptr) \ + { \ + error_ = true; \ + } \ + } \ + \ + ~ParamCast() \ + { \ + } \ + \ + ParamCast(ParamCast const&) = delete; \ + ParamCast(ParamCast&&) = delete; \ + \ + operator type&() \ + { \ + return *value_; \ + } \ + \ + bool Error() const \ + { \ + return error_; \ + } \ + \ + static constexpr int Size = 1; \ + \ + private: \ + type* value_; \ + bool error_ = false; \ + }; \ + \ + template <> \ + class ParamCast \ + { \ + public: \ + ParamCast(AMX*, cell*, int) = delete; \ + ParamCast() = delete; \ + }; + +/// Macro to define a script param for a mixed pool's global entry +#define GLOBAL_MIXED_POOL_PARAM(type, poolPtr) \ + template <> \ + struct ParamLookup \ + { \ + static type* Val(cell ref) noexcept \ + { \ + auto pool = getAmxLookups()->poolPtr; \ + if (pool) \ + { \ + return pool->get(pool->fromLegacyID(ref)); \ + } \ + return nullptr; \ + } \ + }; \ + \ + template <> \ + class ParamCast \ + { \ + public: \ + ParamCast(AMX* amx, cell* params, int idx) noexcept \ + { \ + value_ = ParamLookup::Val(params[idx]); \ + } \ + \ + ~ParamCast() \ + { \ + } \ + \ + ParamCast(ParamCast const&) = delete; \ + ParamCast(ParamCast&&) = delete; \ + \ + operator type*() \ + { \ + return value_; \ + } \ + \ + bool Error() const \ + { \ + return false; \ + } \ + \ + static constexpr int Size = 1; \ + \ + private: \ + type* value_; \ + }; \ + \ + template <> \ + class ParamCast \ + { \ + public: \ + ParamCast(AMX* amx, cell* params, int idx) \ + { \ + value_ = ParamLookup::Val(params[idx]); \ + if (value_ == nullptr) \ + { \ + error_ = true; \ + } \ + } \ + \ + ~ParamCast() \ + { \ + } \ + \ + ParamCast(ParamCast const&) = delete; \ + ParamCast(ParamCast&&) = delete; \ + \ + operator type&() \ + { \ + return *value_; \ + } \ + \ + bool Error() const \ + { \ + return error_; \ + } \ + \ + static constexpr int Size = 1; \ + \ + private: \ + type* value_; \ + bool error_ = false; \ + }; \ + \ + template <> \ + class ParamCast \ + { \ + public: \ + ParamCast(AMX*, cell*, int) = delete; \ + ParamCast() = delete; \ + }; + +/// Macro to define a script param for a mixed pool's player entry +#define PLAYER_MIXED_POOL_PARAM(type, dataType, poolPtr) \ + template <> \ + struct ParamLookup \ + { \ + static type* Val(IPlayer* player, cell ref) noexcept \ + { \ + if (player == nullptr) \ + { \ + return nullptr; \ + } \ + \ + auto data = queryExtension(player); \ + auto pool = getAmxLookups()->poolPtr; \ + if (pool && data) \ + { \ + return reinterpret_cast(pool->get(data->fromLegacyID(ref))); \ + } \ + return nullptr; \ + } \ + }; \ + \ + template <> \ + class ParamCast \ + { \ + public: \ + ParamCast(AMX* amx, cell* params, int idx) \ + { \ + auto player = ParamLookup::Val(params[1] /* first param is always playerid */); \ + value_ = ParamLookup::Val(player, params[idx]); \ + } \ + \ + ~ParamCast() \ + { \ + } \ + \ + ParamCast(ParamCast const&) = delete; \ + ParamCast(ParamCast&&) = delete; \ + \ + operator type*() \ + { \ + return value_; \ + } \ + \ + bool Error() const \ + { \ + return false; \ + } \ + \ + static constexpr int Size = 1; \ + \ + private: \ + type* value_; \ + }; \ + \ + template <> \ + class ParamCast \ + { \ + public: \ + ParamCast(AMX* amx, cell* params, int idx) = delete; \ + ParamCast() = delete; \ + }; \ + \ + template <> \ + class ParamCast \ + { \ + public: \ + ParamCast(AMX* amx, cell* params, int idx) \ + { \ + auto player = ParamLookup::Val(params[1] /* first param is always playerid */); \ + value_ = ParamLookup::Val(player, params[idx]); \ + if (value_ == nullptr) \ + { \ + error_ = true; \ + } \ + } \ + \ + ~ParamCast() \ + { \ + } \ + \ + ParamCast(ParamCast const&) = delete; \ + ParamCast(ParamCast&&) = delete; \ + \ + operator type&() \ + { \ + return *value_; \ + } \ + \ + bool Error() const \ + { \ + return error_; \ + } \ + \ + static constexpr int Size = 1; \ + \ + private: \ + type* value_; \ + bool error_ = false; \ + }; \ + \ + template <> \ + class ParamCast \ + { \ + public: \ + ParamCast(AMX*, cell*, int) = delete; \ + ParamCast() = delete; \ + }; + +// custom ParamCasts here to use custom types in native declarations +namespace pawn_natives +{ + +POOL_PARAM(IPlayer, players); +POOL_PARAM(IActor, actors); +POOL_PARAM(IClass, classes); +POOL_PARAM(IMenu, menus); +POOL_PARAM(IObject, objects); +POOL_PARAM(ITextDraw, textdraws); +POOL_PARAM(ITextLabel, textlabels); +POOL_PARAM(IVehicle, vehicles); + +PLAYER_POOL_PARAM(IPlayerObject, IPlayerObjectData); +PLAYER_POOL_PARAM(IPlayerTextDraw, IPlayerTextDrawData); +PLAYER_POOL_PARAM(IPlayerTextLabel, IPlayerTextLabelData); + +PLAYER_DATA_PARAM(IPlayerVehicleData); +PLAYER_DATA_PARAM(IPlayerCheckpointData); +PLAYER_DATA_PARAM(IPlayerObjectData); +PLAYER_DATA_PARAM(IPlayerTextDrawData); +PLAYER_DATA_PARAM(IPlayerConsoleData); +PLAYER_DATA_PARAM(IPlayerDialogData); + +GLOBAL_MIXED_POOL_PARAM(IPickup, pickups); +PLAYER_MIXED_POOL_PARAM(IPlayerPickup, IPlayerPickupData, pickups); +GLOBAL_MIXED_POOL_PARAM(IGangZone, gangzones); +PLAYER_MIXED_POOL_PARAM(IPlayerGangZone, IPlayerGangZoneData, gangzones); + +/// A parameter used for only writing data to an output string +/// Greatly speeds up code as there's no need for reading the input string +/// and faster amx_SetString function is used which works well with string views +template <> +class ParamCast +{ +public: + ParamCast(AMX* amx, cell* params, int idx) + : len_((int)params[idx + 1]) + { + if (len_ < 0) + throw std::length_error("Invalid string length."); + if (len_) + { + // This is a rare case where we don't check that the address is valid and throw a + // param cast error. Instead we just don't write the string back later. + amx_GetAddr(amx, params[idx], &addr_); + } + else + { + addr_ = nullptr; + } + } + + ~ParamCast() + { + const size_t idx = value_.index(); + // Write data if there's a string written (index is 1 or 2) + if (addr_ && idx != 0 && idx != std::variant_npos) + { + StringView str = (idx == 1 ? std::get(value_) : std::get(value_)); + amx_SetStringLen(addr_, str.data(), str.length(), 0, 0, len_); + } + } + + ParamCast(ParamCast const&) = delete; + ParamCast(ParamCast&&) = delete; + + operator OutputOnlyString&() + { + return value_; + } + + bool Error() const + { + return false; + } + + static constexpr int Size = 2; + +private: + int + len_; + + cell* + addr_; + + OutputOnlyString + value_; +}; + +// Database IDatabaseConnection param lookups +template <> +struct ParamLookup +{ + static IDatabaseConnection* Val(cell ref) noexcept + { + IDatabasesComponent* databases_component = getAmxLookups()->databases; + IDatabaseConnection* connection = nullptr; + if (databases_component && databases_component->isDatabaseConnectionIDValid(static_cast(ref))) + { + connection = &databases_component->getDatabaseConnectionByID(static_cast(ref)); + } + return connection; + } +}; + +template <> +class ParamCast +{ +public: + ParamCast(AMX* amx, cell* params, int idx) + { + value_ = ParamLookup::Val(params[idx]); + if (value_ == nullptr) + { + error_ = true; + } + } + + ~ParamCast() + { + } + + ParamCast(ParamCast const&) = delete; + ParamCast(ParamCast&&) = delete; + + operator IDatabaseConnection&() + { + return *value_; + } + + bool Error() const + { + return error_; + } + + static constexpr int Size = 1; + +private: + IDatabaseConnection* value_; + bool error_ = false; +}; + +template <> +class ParamCast +{ +public: + ParamCast(AMX* amx, cell* params, int idx) noexcept + { + value_ = ParamLookup::Val(params[idx]); + } + + ~ParamCast() + { + } + + ParamCast(ParamCast const&) = delete; + ParamCast(ParamCast&&) = delete; + + operator IDatabaseConnection*() + { + return value_; + } + + bool Error() const + { + return false; + } + + static constexpr int Size = 1; + +private: + IDatabaseConnection* value_; +}; + +// Database IDatabaseResultSet param lookups +template <> +struct ParamLookup +{ + static IDatabaseResultSet* Val(cell ref) noexcept + { + IDatabasesComponent* databases_component = getAmxLookups()->databases; + IDatabaseResultSet* resultSet = nullptr; + if (databases_component && databases_component->isDatabaseResultSetIDValid(static_cast(ref))) + { + resultSet = &databases_component->getDatabaseResultSetByID(static_cast(ref)); + } + return resultSet; + } +}; + +template <> +class ParamCast +{ +public: + ParamCast(AMX* amx, cell* params, int idx) + { + value_ = ParamLookup::Val(params[idx]); + if (value_ == nullptr) + { + error_ = true; + } + } + + ~ParamCast() + { + } + + ParamCast(ParamCast const&) = delete; + ParamCast(ParamCast&&) = delete; + + operator IDatabaseResultSet&() + { + return *value_; + } + + bool Error() const + { + return error_; + } + + static constexpr int Size = 1; + +private: + IDatabaseResultSet* value_; + bool error_ = false; +}; + +template <> +class ParamCast +{ +public: + ParamCast(AMX* amx, cell* params, int idx) noexcept + { + value_ = ParamLookup::Val(params[idx]); + } + + ~ParamCast() + { + } + + ParamCast(ParamCast const&) = delete; + ParamCast(ParamCast&&) = delete; + + operator IDatabaseResultSet*() + { + return value_; + } + + bool Error() const + { + return false; + } + + static constexpr int Size = 1; + +private: + IDatabaseResultSet* value_; +}; + +// Disable the ref version. +template <> +class ParamCast +{ +public: + ParamCast(AMX*, cell*, int) = delete; + ParamCast() = delete; +}; + +template <> +class ParamCast +{ +public: + ParamCast(AMX*, cell*, int) = delete; + ParamCast() = delete; +}; + +template <> +class ParamCast +{ +public: + ParamCast(AMX*, cell*, int) = delete; + ParamCast() = delete; +}; + +template <> +class ParamCast +{ +public: + ParamCast([[maybe_unused]] AMX* amx, cell* params, int idx) + : value_ { amx_ctof(params[idx + 0]), amx_ctof(params[idx + 1]), amx_ctof(params[idx + 2]) } + { + } + + ~ParamCast() + { + } + + operator Vector3() const + { + return value_; + } + + bool Error() const + { + return false; + } + + static constexpr int Size = 3; + + using type = Vector3; + +private: + Vector3 + value_; +}; + +template <> +class ParamCast +{ +public: + ParamCast(AMX* amx, cell* params, int idx) + { + amx_GetAddr(amx, params[idx + 0], &x_); + amx_GetAddr(amx, params[idx + 1], &y_); + amx_GetAddr(amx, params[idx + 2], &z_); + if (x_ == nullptr || y_ == nullptr || z_ == nullptr) + { + error_ = true; + } + else + { + value_.x = amx_ctof(*x_); + value_.y = amx_ctof(*y_); + value_.z = amx_ctof(*z_); + } + } + + ~ParamCast() + { + // Write the value back in to memory. + *x_ = amx_ftoc(value_.x); + *y_ = amx_ftoc(value_.y); + *z_ = amx_ftoc(value_.z); + } + + operator Vector3&() + { + return value_; + } + + bool Error() const + { + return error_; + } + + static constexpr int Size = 3; + + using type = Vector3&; + +private: + Vector3 value_; + cell *x_, *y_, *z_; + bool error_ = false; +}; + +template <> +class ParamCast +{ +public: + ParamCast(AMX*, cell*, int) = delete; + ParamCast() = delete; +}; + +template <> +class ParamCast +{ +public: + ParamCast(AMX*, cell*, int) = delete; + ParamCast() = delete; +}; + +template <> +class ParamCast +{ +public: + ParamCast([[maybe_unused]] AMX* amx, cell* params, int idx) + : value_ { amx_ctof(params[idx + 0]), amx_ctof(params[idx + 1]) } + { + } + + ~ParamCast() + { + } + + operator Vector2() const + { + return value_; + } + + bool Error() const + { + return false; + } + + static constexpr int Size = 2; + + using type = Vector2; + +private: + Vector2 value_; +}; + +template <> +class ParamCast +{ +public: + ParamCast(AMX* amx, cell* params, int idx) + { + amx_GetAddr(amx, params[idx + 0], &x_); + amx_GetAddr(amx, params[idx + 1], &y_); + if (x_ == nullptr || y_ == nullptr) + { + error_ = true; + } + else + { + value_.x = amx_ctof(*x_); + value_.y = amx_ctof(*y_); + } + } + + ~ParamCast() + { + // Write the value back in to memory. + *x_ = amx_ftoc(value_.x); + *y_ = amx_ftoc(value_.y); + } + + operator Vector2&() + { + return value_; + } + + bool Error() const + { + return error_; + } + + static constexpr int Size = 2; + + using type = Vector2&; + +private: + Vector2 value_; + cell *x_, *y_; + bool error_ = false; +}; + +template <> +class ParamCast +{ +public: + ParamCast(AMX*, cell*, int) = delete; + ParamCast() = delete; +}; + +template <> +class ParamCast +{ +public: + ParamCast(AMX*, cell*, int) = delete; + ParamCast() = delete; +}; + +template <> +class ParamCast +{ +public: + ParamCast([[maybe_unused]] AMX* amx, cell* params, int idx) + : value_ { amx_ctof(params[idx + 0]), amx_ctof(params[idx + 1]), amx_ctof(params[idx + 2]), amx_ctof(params[idx + 3]) } + { + } + + ~ParamCast() + { + } + + operator Vector4() const + { + return value_; + } + + bool Error() const + { + return false; + } + + static constexpr int Size = 4; + + using type = Vector4; + +private: + Vector4 value_; +}; + +template <> +class ParamCast +{ +public: + ParamCast(AMX* amx, cell* params, int idx) + { + amx_GetAddr(amx, params[idx + 0], &x_); + amx_GetAddr(amx, params[idx + 1], &y_); + amx_GetAddr(amx, params[idx + 2], &z_); + amx_GetAddr(amx, params[idx + 3], &w_); + if (w_ == nullptr || x_ == nullptr || y_ == nullptr || z_ == nullptr) + { + error_ = true; + } + else + { + value_.x = amx_ctof(*x_); + value_.y = amx_ctof(*y_); + value_.z = amx_ctof(*z_); + value_.w = amx_ctof(*w_); + } + } + + ~ParamCast() + { + // Write the value back in to memory. + *x_ = amx_ftoc(value_.x); + *y_ = amx_ftoc(value_.y); + *z_ = amx_ftoc(value_.z); + *w_ = amx_ftoc(value_.w); + } + + operator Vector4&() + { + return value_; + } + + bool Error() const + { + return error_; + } + + static constexpr int Size = 4; + + using type = Vector4&; + +private: + Vector4 value_; + cell *x_, *y_, *z_, *w_; + bool error_ = false; +}; + +template <> +class ParamCast +{ +public: + ParamCast(AMX*, cell*, int) = delete; + ParamCast() = delete; +}; + +template <> +class ParamCast +{ +public: + ParamCast(AMX*, cell*, int) = delete; + ParamCast() = delete; +}; + +template <> +class ParamCast +{ +public: + ParamCast([[maybe_unused]] AMX* amx, cell* params, int idx) + : value_(amx_ctof(params[idx + 0]), amx_ctof(params[idx + 1]), amx_ctof(params[idx + 2]), amx_ctof(params[idx + 3])) + { + } + + ~ParamCast() + { + } + + operator GTAQuat() const + { + return value_; + } + + bool Error() const + { + return false; + } + + static constexpr int Size = 4; + + using type = GTAQuat; + +private: + GTAQuat value_; +}; + +template <> +class ParamCast +{ +public: + ParamCast(AMX* amx, cell* params, int idx) + { + amx_GetAddr(amx, params[idx + 0], &w_); + amx_GetAddr(amx, params[idx + 1], &x_); + amx_GetAddr(amx, params[idx + 2], &y_); + amx_GetAddr(amx, params[idx + 3], &z_); + if (w_ == nullptr || x_ == nullptr || y_ == nullptr || z_ == nullptr) + { + error_ = true; + } + else + { + value_.q.w = amx_ctof(*w_); + value_.q.x = amx_ctof(*x_); + value_.q.y = amx_ctof(*y_); + value_.q.z = amx_ctof(*z_); + } + } + + ~ParamCast() + { + // Write the value back in to memory. + *w_ = amx_ftoc(value_.q.w); + *x_ = amx_ftoc(value_.q.x); + *y_ = amx_ftoc(value_.q.y); + *z_ = amx_ftoc(value_.q.z); + } + + operator GTAQuat&() + { + return value_; + } + + bool Error() const + { + return error_; + } + + static constexpr int Size = 4; + + using type = GTAQuat&; + +private: + GTAQuat value_; + cell *w_, *x_, *y_, *z_; + bool error_ = false; +}; + +template +class ParamCast const&> +{ +public: + ParamCast(AMX* amx, cell* params, int idx) + : data_(nullptr) + , len_((int)params[idx + 1]) + , value_() + { + value_.resize(len_); + amx_GetAddr(amx, params[idx + 0], &data_); + if (data_ == nullptr) + { + error_ = true; + } + else + { + cell* input = data_; + // Copy the data out. + for (size_t idx = 0; idx != len_; ++idx) + { + value_[idx] = static_cast(input[idx]); + } + } + } + + ~ParamCast() + { + // No writing back for constants. + } + + ParamCast(ParamCast const&> const&) = delete; + ParamCast(ParamCast const&>&&) = delete; + + // clang-format off + // Adding this here because clang formatter (locally, even using format.bat) + // Keeps adding a space between `const` and `&` and according to our `.clang-format` + // Style guide, it's not acceptable, since `PointerAlignment` is set to `Left` + operator Impl::DynamicArray const& () + // clang-format on + { + return value_; + } + + bool Error() const + { + return error_; + } + + static constexpr int Size = 2; + +private: + cell* data_; + int len_; + Impl::DynamicArray value_; + bool error_ = false; +}; + +template +class ParamCast> +{ +public: + ParamCast(AMX* amx, cell* params, int idx) + : data_(nullptr) + , len_((int)params[idx + 1]) + , value_() + { + value_.resize(len_); + amx_GetAddr(amx, params[idx + 0], &data_); + if (data_ == nullptr) + { + error_ = true; + } + else + { + cell* input = data_; + // Copy the data out. + for (size_t idx = 0; idx != len_; ++idx) + { + value_[idx] = static_cast(input[idx]); + } + } + } + + ~ParamCast() + { + } + + ParamCast(ParamCast> const&) = delete; + ParamCast(ParamCast>&&) = delete; + + operator Impl::DynamicArray() + { + return value_; + } + + bool Error() const + { + return error_; + } + + static constexpr int Size = 2; + +private: + cell* data_; + int len_; + Impl::DynamicArray value_; + bool error_ = false; +}; + +template +class ParamCast&> +{ +public: + ParamCast(AMX* amx, cell* params, int idx) + : data_(nullptr) + , len_((int)params[idx + 1]) + , value_() + { + value_.resize(len_); + amx_GetAddr(amx, params[idx + 0], &data_); + if (data_ == nullptr) + { + error_ = true; + } + else + { + cell* input = data_; + // Copy the data out. + for (size_t idx = 0; idx != len_; ++idx) + { + value_[idx] = static_cast(input[idx]); + } + } + } + + ~ParamCast() + { + // Write the data back + cell* input = data_; + // Copy the data out. + for (size_t idx = 0; idx != len_; ++idx) + { + input[idx] = static_cast(value_[idx]); + } + } + + ParamCast(ParamCast&> const&) = delete; + ParamCast(ParamCast&>&&) = delete; + + operator Impl::DynamicArray&() + { + return value_; + } + + bool Error() const + { + return error_; + } + + static constexpr int Size = 2; + +private: + cell* data_; + int len_; + Impl::DynamicArray value_; + bool error_ = false; +}; + +class NotImplemented : public std::logic_error +{ +public: + NotImplemented() + : std::logic_error { "Pawn native not yet implemented." } + { + } +}; +} diff --git a/SDK/include/Server/Components/Pawn/pawn.hpp b/SDK/include/Server/Components/Pawn/pawn.hpp index e07e35c5b..4d96b52b0 100644 --- a/SDK/include/Server/Components/Pawn/pawn.hpp +++ b/SDK/include/Server/Components/Pawn/pawn.hpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/SDK/include/Server/Components/Pawn/pawn_natives.hpp b/SDK/include/Server/Components/Pawn/pawn_natives.hpp deleted file mode 100644 index 51bf211b8..000000000 --- a/SDK/include/Server/Components/Pawn/pawn_natives.hpp +++ /dev/null @@ -1,1280 +0,0 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public License, - * v. 2.0. If a copy of the MPL was not distributed with this file, You can - * obtain one at http://mozilla.org/MPL/2.0/. - * - * The original code is copyright (c) 2022, open.mp team and contributors. - */ - -#pragma once - -#include -#include - -#include "pawn.hpp" - -/// The bool is used because variant is initialised to index 0 by default -using OutputOnlyString = std::variant; - -/// Macro to define a script param for a pool entry -/// Example with IPlayer from the players pool: -/// Using IPlayer& in a script function throws an exception if the player with the specified ID doesn't exist -/// Using IPlayer* in a script function makes the IPlayer entry optional and is nullptr if the player with the specified ID doesn't exist -#define POOL_PARAM(type, poolPtr) \ - template <> \ - struct ParamLookup \ - { \ - static type& ValReq(cell ref) \ - { \ - auto pool = getAmxLookups()->poolPtr; \ - if (pool) \ - { \ - auto ptr = pool->get(ref); \ - if (ptr) \ - { \ - return *ptr; \ - } \ - } \ - throw pawn_natives::ParamCastFailure(); \ - } \ - \ - static type* Val(cell ref) noexcept \ - { \ - auto pool = getAmxLookups()->poolPtr; \ - if (pool) \ - { \ - return pool->get(ref); \ - } \ - return nullptr; \ - } \ - }; \ - \ - template <> \ - class ParamCast \ - { \ - public: \ - ParamCast(AMX* amx, cell* params, int idx) noexcept \ - { \ - value_ = ParamLookup::Val(params[idx]); \ - } \ - \ - ~ParamCast() \ - { \ - } \ - \ - ParamCast(ParamCast const&) = delete; \ - ParamCast(ParamCast&&) = delete; \ - \ - operator type*() \ - { \ - return value_; \ - } \ - \ - static constexpr int Size = 1; \ - \ - private: \ - type* value_; \ - }; \ - \ - template <> \ - class ParamCast \ - { \ - public: \ - ParamCast(AMX* amx, cell* params, int idx) \ - : value_(ParamLookup::ValReq(params[idx])) \ - { \ - } \ - \ - ~ParamCast() \ - { \ - } \ - \ - ParamCast(ParamCast const&) = delete; \ - ParamCast(ParamCast&&) = delete; \ - \ - operator type&() \ - { \ - return value_; \ - } \ - \ - static constexpr int Size = 1; \ - \ - private: \ - type& value_; \ - }; \ - \ - template <> \ - class ParamCast \ - { \ - public: \ - ParamCast(AMX*, cell*, int) = delete; \ - ParamCast() = delete; \ - }; - -/// Macro to define a script param for a player pool entry -/// Always throws if the player ID specified in the first parameter is invalid as it's required to get the IPlayerObjectData pool -/// Example with IPlayerObject from the IPlayerObjectData pool: -/// Using IPlayerObject& in a script function throws an exception if the object with the specified ID doesn't exist -/// Using IPlayerObject* in a script function makes the IPlayerObject entry optional and is nullptr if the object with the specified ID doesn't exist -#define PLAYER_POOL_PARAM(type, dataType) \ - template <> \ - struct ParamLookup \ - { \ - static type& ValReq(IPlayer& player, cell ref) \ - { \ - auto data = queryExtension(player); \ - if (data) \ - { \ - auto ptr = data->get(ref); \ - if (ptr) \ - { \ - return *ptr; \ - } \ - } \ - throw pawn_natives::ParamCastFailure(); \ - } \ - \ - static type* Val(IPlayer& player, cell ref) noexcept \ - { \ - auto data = queryExtension(player); \ - if (data) \ - { \ - return data->get(ref); \ - } \ - return nullptr; \ - } \ - }; \ - \ - template <> \ - class ParamCast \ - { \ - public: \ - ParamCast(AMX* amx, cell* params, int idx) \ - { \ - value_ = ParamLookup::Val(ParamLookup::ValReq(params[1] /* first param is always playerid */), params[idx]); \ - } \ - \ - ~ParamCast() \ - { \ - } \ - \ - ParamCast(ParamCast const&) = delete; \ - ParamCast(ParamCast&&) = delete; \ - \ - operator type*() \ - { \ - return value_; \ - } \ - \ - static constexpr int Size = 1; \ - \ - private: \ - type* value_; \ - }; \ - \ - template <> \ - class ParamCast \ - { \ - public: \ - ParamCast(AMX* amx, cell* params, int idx) = delete; \ - ParamCast() = delete; \ - }; \ - \ - template <> \ - class ParamCast \ - { \ - public: \ - ParamCast(AMX* amx, cell* params, int idx) \ - : value_(ParamLookup::ValReq(ParamLookup::ValReq(params[1] /* first param is always playerid */), params[idx])) \ - { \ - } \ - \ - ~ParamCast() \ - { \ - } \ - \ - ParamCast(ParamCast const&) = delete; \ - ParamCast(ParamCast&&) = delete; \ - \ - operator type&() \ - { \ - return value_; \ - } \ - \ - static constexpr int Size = 1; \ - \ - private: \ - type& value_; \ - }; \ - \ - template <> \ - class ParamCast \ - { \ - public: \ - ParamCast(AMX*, cell*, int) = delete; \ - ParamCast() = delete; \ - }; - -/// Macro to define a script param for a player data extension. -/// Throws an exception when playerid is invalid or player data's retrieval fails. -/// Unless it is casting to a pointer which becomes nullptr if either player id or player data is invalid. -#define PLAYER_DATA_PARAM(type) \ - template <> \ - struct ParamLookup \ - { \ - static type& ValReq(IPlayer& player) \ - { \ - auto data = queryExtension(player); \ - if (data) \ - { \ - return *data; \ - } \ - throw pawn_natives::ParamCastFailure(); \ - } \ - \ - static type* Val(IPlayer& player) noexcept \ - { \ - return queryExtension(player); \ - } \ - }; \ - \ - template <> \ - class ParamCast \ - { \ - public: \ - ParamCast(AMX* amx, cell* params, int idx) \ - { \ - value_ = ParamLookup::Val(ParamLookup::ValReq(params[idx])); \ - } \ - \ - ~ParamCast() \ - { \ - } \ - \ - ParamCast(ParamCast const&) = delete; \ - ParamCast(ParamCast&&) = delete; \ - \ - operator type*() \ - { \ - return value_; \ - } \ - \ - static constexpr int Size = 1; \ - \ - private: \ - type* value_; \ - }; \ - \ - template <> \ - class ParamCast \ - { \ - public: \ - ParamCast(AMX* amx, cell* params, int idx) = delete; \ - ParamCast() = delete; \ - }; \ - \ - template <> \ - class ParamCast \ - { \ - public: \ - ParamCast(AMX* amx, cell* params, int idx) \ - : value_(ParamLookup::ValReq(ParamLookup::ValReq(params[idx]))) \ - { \ - } \ - \ - ~ParamCast() \ - { \ - } \ - \ - ParamCast(ParamCast const&) = delete; \ - ParamCast(ParamCast&&) = delete; \ - \ - operator type&() \ - { \ - return value_; \ - } \ - \ - static constexpr int Size = 1; \ - \ - private: \ - type& value_; \ - }; \ - \ - template <> \ - class ParamCast \ - { \ - public: \ - ParamCast(AMX*, cell*, int) = delete; \ - ParamCast() = delete; \ - }; - -/// Macro to define a script param for a mixed pool's global entry -#define GLOBAL_MIXED_POOL_PARAM(type, poolPtr) \ - template <> \ - struct ParamLookup \ - { \ - static type& ValReq(cell ref) \ - { \ - auto pool = getAmxLookups()->poolPtr; \ - if (pool) \ - { \ - auto ptr = pool->get(pool->fromLegacyID(ref)); \ - if (ptr) \ - { \ - return *ptr; \ - } \ - } \ - throw pawn_natives::ParamCastFailure(); \ - } \ - \ - static type* Val(cell ref) noexcept \ - { \ - auto pool = getAmxLookups()->poolPtr; \ - if (pool) \ - { \ - return pool->get(pool->fromLegacyID(ref)); \ - } \ - return nullptr; \ - } \ - }; \ - \ - template <> \ - class ParamCast \ - { \ - public: \ - ParamCast(AMX* amx, cell* params, int idx) noexcept \ - { \ - value_ = ParamLookup::Val(params[idx]); \ - } \ - \ - ~ParamCast() \ - { \ - } \ - \ - ParamCast(ParamCast const&) = delete; \ - ParamCast(ParamCast&&) = delete; \ - \ - operator type*() \ - { \ - return value_; \ - } \ - \ - static constexpr int Size = 1; \ - \ - private: \ - type* value_; \ - }; \ - \ - template <> \ - class ParamCast \ - { \ - public: \ - ParamCast(AMX* amx, cell* params, int idx) \ - : value_(ParamLookup::ValReq(params[idx])) \ - { \ - } \ - \ - ~ParamCast() \ - { \ - } \ - \ - ParamCast(ParamCast const&) = delete; \ - ParamCast(ParamCast&&) = delete; \ - \ - operator type&() \ - { \ - return value_; \ - } \ - \ - static constexpr int Size = 1; \ - \ - private: \ - type& value_; \ - }; \ - \ - template <> \ - class ParamCast \ - { \ - public: \ - ParamCast(AMX*, cell*, int) = delete; \ - ParamCast() = delete; \ - }; - -/// Macro to define a script param for a mixed pool's player entry -#define PLAYER_MIXED_POOL_PARAM(type, dataType, poolPtr) \ - template <> \ - struct ParamLookup \ - { \ - static type& ValReq(IPlayer& player, cell ref) \ - { \ - auto data = queryExtension(player); \ - auto pool = getAmxLookups()->poolPtr; \ - if (pool && data) \ - { \ - auto ptr = pool->get(data->fromLegacyID(ref)); \ - if (ptr) \ - { \ - return *reinterpret_cast(ptr); \ - } \ - } \ - throw pawn_natives::ParamCastFailure(); \ - } \ - \ - static type* Val(IPlayer& player, cell ref) noexcept \ - { \ - auto data = queryExtension(player); \ - auto pool = getAmxLookups()->poolPtr; \ - if (pool && data) \ - { \ - return reinterpret_cast(pool->get(data->fromLegacyID(ref))); \ - } \ - return nullptr; \ - } \ - }; \ - \ - template <> \ - class ParamCast \ - { \ - public: \ - ParamCast(AMX* amx, cell* params, int idx) \ - { \ - value_ = ParamLookup::Val(ParamLookup::ValReq(params[1] /* first param is always playerid */), params[idx]); \ - } \ - \ - ~ParamCast() \ - { \ - } \ - \ - ParamCast(ParamCast const&) = delete; \ - ParamCast(ParamCast&&) = delete; \ - \ - operator type*() \ - { \ - return value_; \ - } \ - \ - static constexpr int Size = 1; \ - \ - private: \ - type* value_; \ - }; \ - \ - template <> \ - class ParamCast \ - { \ - public: \ - ParamCast(AMX* amx, cell* params, int idx) = delete; \ - ParamCast() = delete; \ - }; \ - \ - template <> \ - class ParamCast \ - { \ - public: \ - ParamCast(AMX* amx, cell* params, int idx) \ - : value_(ParamLookup::ValReq(ParamLookup::ValReq(params[1] /* first param is always playerid */), params[idx])) \ - { \ - } \ - \ - ~ParamCast() \ - { \ - } \ - \ - ParamCast(ParamCast const&) = delete; \ - ParamCast(ParamCast&&) = delete; \ - \ - operator type&() \ - { \ - return value_; \ - } \ - \ - static constexpr int Size = 1; \ - \ - private: \ - type& value_; \ - }; \ - \ - template <> \ - class ParamCast \ - { \ - public: \ - ParamCast(AMX*, cell*, int) = delete; \ - ParamCast() = delete; \ - }; - -// custom ParamCasts here to use custom types in native declarations -namespace pawn_natives -{ - -POOL_PARAM(IPlayer, players); -POOL_PARAM(IActor, actors); -POOL_PARAM(IClass, classes); -POOL_PARAM(IMenu, menus); -POOL_PARAM(IObject, objects); -POOL_PARAM(ITextDraw, textdraws); -POOL_PARAM(ITextLabel, textlabels); -POOL_PARAM(IVehicle, vehicles); - -PLAYER_POOL_PARAM(IPlayerObject, IPlayerObjectData); -PLAYER_POOL_PARAM(IPlayerTextDraw, IPlayerTextDrawData); -PLAYER_POOL_PARAM(IPlayerTextLabel, IPlayerTextLabelData); - -PLAYER_DATA_PARAM(IPlayerVehicleData); -PLAYER_DATA_PARAM(IPlayerCheckpointData); -PLAYER_DATA_PARAM(IPlayerObjectData); -PLAYER_DATA_PARAM(IPlayerTextDrawData); -PLAYER_DATA_PARAM(IPlayerConsoleData); -PLAYER_DATA_PARAM(IPlayerDialogData); - -GLOBAL_MIXED_POOL_PARAM(IPickup, pickups); -PLAYER_MIXED_POOL_PARAM(IPlayerPickup, IPlayerPickupData, pickups); -GLOBAL_MIXED_POOL_PARAM(IGangZone, gangzones); -PLAYER_MIXED_POOL_PARAM(IPlayerGangZone, IPlayerGangZoneData, gangzones); - -/// A parameter used for only writing data to an output string -/// Greatly speeds up code as there's no need for reading the input string -/// and faster amx_SetString function is used which works well with string views -template <> -class ParamCast -{ -public: - ParamCast(AMX* amx, cell* params, int idx) - : len_((int)params[idx + 1]) - { - if (len_ < 0) - throw std::length_error("Invalid string length."); - if (len_) - { - // This is a rare case where we don't check that the address is valid and throw a - // param cast error. Instead we just don't write the string back later. - amx_GetAddr(amx, params[idx], &addr_); - } - else - { - addr_ = nullptr; - } - } - - ~ParamCast() - { - const size_t idx = value_.index(); - // Write data if there's a string written (index is 1 or 2) - if (addr_ && idx != 0 && idx != std::variant_npos) - { - StringView str = (idx == 1 ? std::get(value_) : std::get(value_)); - amx_SetStringLen(addr_, str.data(), str.length(), 0, 0, len_); - } - } - - ParamCast(ParamCast const&) = delete; - ParamCast(ParamCast&&) = delete; - - operator OutputOnlyString&() - { - return value_; - } - - static constexpr int Size = 2; - -private: - int - len_; - - cell* - addr_; - - OutputOnlyString - value_; -}; - -// Database IDatabaseConnection param lookups -template <> -struct ParamLookup -{ - static IDatabaseConnection& ValReq(cell ref) - { - IDatabasesComponent* databases_component = getAmxLookups()->databases; - if (databases_component && databases_component->isDatabaseConnectionIDValid(static_cast(ref))) - { - return databases_component->getDatabaseConnectionByID(static_cast(ref)); - } - throw pawn_natives::ParamCastFailure(); - } - - static IDatabaseConnection* Val(cell ref) noexcept - { - IDatabasesComponent* databases_component = getAmxLookups()->databases; - IDatabaseConnection* connection = nullptr; - if (databases_component && databases_component->isDatabaseConnectionIDValid(static_cast(ref))) - { - connection = &databases_component->getDatabaseConnectionByID(static_cast(ref)); - } - return connection; - } -}; - -template <> -class ParamCast -{ -public: - ParamCast(AMX* amx, cell* params, int idx) - : value_(ParamLookup::ValReq(params[idx])) - { - } - - ~ParamCast() - { - } - - ParamCast(ParamCast const&) = delete; - ParamCast(ParamCast&&) = delete; - - operator IDatabaseConnection&() - { - return value_; - } - - static constexpr int Size = 1; - -private: - IDatabaseConnection& value_; -}; - -template <> -class ParamCast -{ -public: - ParamCast(AMX* amx, cell* params, int idx) noexcept - { - value_ = ParamLookup::Val(params[idx]); - } - - ~ParamCast() - { - } - - ParamCast(ParamCast const&) = delete; - ParamCast(ParamCast&&) = delete; - - operator IDatabaseConnection*() - { - return value_; - } - - static constexpr int Size = 1; - -private: - IDatabaseConnection* value_; -}; - -// Database IDatabaseResultSet param lookups -template <> -struct ParamLookup -{ - static IDatabaseResultSet& ValReq(cell ref) - { - IDatabasesComponent* databases_component = getAmxLookups()->databases; - if (databases_component && databases_component->isDatabaseResultSetIDValid(static_cast(ref))) - { - return databases_component->getDatabaseResultSetByID(static_cast(ref)); - } - throw pawn_natives::ParamCastFailure(); - } - - static IDatabaseResultSet* Val(cell ref) noexcept - { - IDatabasesComponent* databases_component = getAmxLookups()->databases; - IDatabaseResultSet* resultSet = nullptr; - if (databases_component && databases_component->isDatabaseResultSetIDValid(static_cast(ref))) - { - resultSet = &databases_component->getDatabaseResultSetByID(static_cast(ref)); - } - return resultSet; - } -}; - -template <> -class ParamCast -{ -public: - ParamCast(AMX* amx, cell* params, int idx) - : value_(ParamLookup::ValReq(params[idx])) - { - } - - ~ParamCast() - { - } - - ParamCast(ParamCast const&) = delete; - ParamCast(ParamCast&&) = delete; - - operator IDatabaseResultSet&() - { - return value_; - } - - static constexpr int Size = 1; - -private: - IDatabaseResultSet& value_; -}; - -template <> -class ParamCast -{ -public: - ParamCast(AMX* amx, cell* params, int idx) noexcept - { - value_ = ParamLookup::Val(params[idx]); - } - - ~ParamCast() - { - } - - ParamCast(ParamCast const&) = delete; - ParamCast(ParamCast&&) = delete; - - operator IDatabaseResultSet*() - { - return value_; - } - - static constexpr int Size = 1; - -private: - IDatabaseResultSet* value_; -}; - -// Disable the ref version. -template <> -class ParamCast -{ -public: - ParamCast(AMX*, cell*, int) = delete; - ParamCast() = delete; -}; - -template <> -class ParamCast -{ -public: - ParamCast(AMX*, cell*, int) = delete; - ParamCast() = delete; -}; - -template <> -class ParamCast -{ -public: - ParamCast(AMX*, cell*, int) = delete; - ParamCast() = delete; -}; - -template <> -class ParamCast -{ -public: - ParamCast([[maybe_unused]] AMX* amx, cell* params, int idx) - : value_ { amx_ctof(params[idx + 0]), amx_ctof(params[idx + 1]), amx_ctof(params[idx + 2]) } - { - } - - ~ParamCast() - { - } - - operator Vector3() const - { - return value_; - } - - static constexpr int Size = 3; - - using type = Vector3; - -private: - Vector3 - value_; -}; - -template <> -class ParamCast -{ -public: - ParamCast(AMX* amx, cell* params, int idx) - { - amx_GetAddr(amx, params[idx + 0], &x_); - amx_GetAddr(amx, params[idx + 1], &y_); - amx_GetAddr(amx, params[idx + 2], &z_); - if (x_ == nullptr || y_ == nullptr || z_ == nullptr) - { - throw pawn_natives::ParamCastFailure(); - } - value_.x = amx_ctof(*x_); - value_.y = amx_ctof(*y_); - value_.z = amx_ctof(*z_); - } - - ~ParamCast() - { - // Write the value back in to memory. - *x_ = amx_ftoc(value_.x); - *y_ = amx_ftoc(value_.y); - *z_ = amx_ftoc(value_.z); - } - - operator Vector3&() - { - return value_; - } - - static constexpr int Size = 3; - - using type = Vector3&; - -private: - Vector3 - value_; - - cell - *x_, - *y_, - *z_; -}; - -template <> -class ParamCast -{ -public: - ParamCast(AMX*, cell*, int) = delete; - ParamCast() = delete; -}; - -template <> -class ParamCast -{ -public: - ParamCast(AMX*, cell*, int) = delete; - ParamCast() = delete; -}; - -template <> -class ParamCast -{ -public: - ParamCast([[maybe_unused]] AMX* amx, cell* params, int idx) - : value_ { amx_ctof(params[idx + 0]), amx_ctof(params[idx + 1]) } - { - } - - ~ParamCast() - { - } - - operator Vector2() const - { - return value_; - } - - static constexpr int Size = 2; - - using type = Vector2; - -private: - Vector2 - value_; -}; - -template <> -class ParamCast -{ -public: - ParamCast(AMX* amx, cell* params, int idx) - { - amx_GetAddr(amx, params[idx + 0], &x_); - amx_GetAddr(amx, params[idx + 1], &y_); - if (x_ == nullptr || y_ == nullptr) - { - throw pawn_natives::ParamCastFailure(); - } - value_.x = amx_ctof(*x_); - value_.y = amx_ctof(*y_); - } - - ~ParamCast() - { - // Write the value back in to memory. - *x_ = amx_ftoc(value_.x); - *y_ = amx_ftoc(value_.y); - } - - operator Vector2&() - { - return value_; - } - - static constexpr int Size = 2; - - using type = Vector2&; - -private: - Vector2 - value_; - - cell - *x_, - *y_; -}; - -template <> -class ParamCast -{ -public: - ParamCast(AMX*, cell*, int) = delete; - ParamCast() = delete; -}; - -template <> -class ParamCast -{ -public: - ParamCast(AMX*, cell*, int) = delete; - ParamCast() = delete; -}; - -template <> -class ParamCast -{ -public: - ParamCast([[maybe_unused]] AMX* amx, cell* params, int idx) - : value_ { amx_ctof(params[idx + 0]), amx_ctof(params[idx + 1]), amx_ctof(params[idx + 2]), amx_ctof(params[idx + 3]) } - { - } - - ~ParamCast() - { - } - - operator Vector4() const - { - return value_; - } - - static constexpr int Size = 4; - - using type = Vector4; - -private: - Vector4 - value_; -}; - -template <> -class ParamCast -{ -public: - ParamCast(AMX* amx, cell* params, int idx) - { - amx_GetAddr(amx, params[idx + 0], &x_); - amx_GetAddr(amx, params[idx + 1], &y_); - amx_GetAddr(amx, params[idx + 2], &z_); - amx_GetAddr(amx, params[idx + 3], &w_); - if (w_ == nullptr || x_ == nullptr || y_ == nullptr || z_ == nullptr) - { - throw pawn_natives::ParamCastFailure(); - } - value_.x = amx_ctof(*x_); - value_.y = amx_ctof(*y_); - value_.z = amx_ctof(*z_); - value_.w = amx_ctof(*w_); - } - - ~ParamCast() - { - // Write the value back in to memory. - *x_ = amx_ftoc(value_.x); - *y_ = amx_ftoc(value_.y); - *z_ = amx_ftoc(value_.z); - *w_ = amx_ftoc(value_.w); - } - - operator Vector4&() - { - return value_; - } - - static constexpr int Size = 4; - - using type = Vector4&; - -private: - Vector4 - value_; - - cell - *x_, - *y_, - *z_, - *w_; -}; - -template <> -class ParamCast -{ -public: - ParamCast(AMX*, cell*, int) = delete; - ParamCast() = delete; -}; - -template <> -class ParamCast -{ -public: - ParamCast(AMX*, cell*, int) = delete; - ParamCast() = delete; -}; - -template <> -class ParamCast -{ -public: - ParamCast([[maybe_unused]] AMX* amx, cell* params, int idx) - : value_(amx_ctof(params[idx + 0]), amx_ctof(params[idx + 1]), amx_ctof(params[idx + 2]), amx_ctof(params[idx + 3])) - { - } - - ~ParamCast() - { - } - - operator GTAQuat() const - { - return value_; - } - - static constexpr int Size = 4; - - using type = GTAQuat; - -private: - GTAQuat - value_; -}; - -template <> -class ParamCast -{ -public: - ParamCast(AMX* amx, cell* params, int idx) - { - amx_GetAddr(amx, params[idx + 0], &w_); - amx_GetAddr(amx, params[idx + 1], &x_); - amx_GetAddr(amx, params[idx + 2], &y_); - amx_GetAddr(amx, params[idx + 3], &z_); - if (w_ == nullptr || x_ == nullptr || y_ == nullptr || z_ == nullptr) - { - throw pawn_natives::ParamCastFailure(); - } - value_.q.w = amx_ctof(*w_); - value_.q.x = amx_ctof(*x_); - value_.q.y = amx_ctof(*y_); - value_.q.z = amx_ctof(*z_); - } - - ~ParamCast() - { - // Write the value back in to memory. - *w_ = amx_ftoc(value_.q.w); - *x_ = amx_ftoc(value_.q.x); - *y_ = amx_ftoc(value_.q.y); - *z_ = amx_ftoc(value_.q.z); - } - - operator GTAQuat&() - { - return value_; - } - - static constexpr int Size = 4; - - using type = GTAQuat&; - -private: - GTAQuat - value_; - - cell - *w_, - *x_, - *y_, - *z_; -}; - -template -class ParamCast const&> -{ -public: - ParamCast(AMX* amx, cell* params, int idx) - : data_(nullptr) - , len_((int)params[idx + 1]) - , value_() - { - value_.resize(len_); - amx_GetAddr(amx, params[idx + 0], &data_); - if (data_ == nullptr) - { - throw pawn_natives::ParamCastFailure(); - } - cell* input = data_; - // Copy the data out. - for (size_t idx = 0; idx != len_; ++idx) - { - value_[idx] = static_cast(input[idx]); - } - } - - ~ParamCast() - { - // No writing back for constants. - } - - ParamCast(ParamCast const&> const&) = delete; - ParamCast(ParamCast const&>&&) = delete; - - // clang-format off - // Adding this here because clang formatter (locally, even using format.bat) - // Keeps adding a space between `const` and `&` and according to our `.clang-format` - // Style guide, it's not acceptable, since `PointerAlignment` is set to `Left` - operator Impl::DynamicArray const& () - // clang-format on - { - return value_; - } - - static constexpr int Size = 2; - -private: - cell* - data_; - - int - len_; - - Impl::DynamicArray - value_; -}; - -template -class ParamCast> -{ -public: - ParamCast(AMX* amx, cell* params, int idx) - : data_(nullptr) - , len_((int)params[idx + 1]) - , value_() - { - value_.resize(len_); - amx_GetAddr(amx, params[idx + 0], &data_); - if (data_ == nullptr) - { - throw pawn_natives::ParamCastFailure(); - } - cell* input = data_; - // Copy the data out. - for (size_t idx = 0; idx != len_; ++idx) - { - value_[idx] = static_cast(input[idx]); - } - } - - ~ParamCast() - { - } - - ParamCast(ParamCast> const&) = delete; - ParamCast(ParamCast>&&) = delete; - - operator Impl::DynamicArray() - { - return value_; - } - - static constexpr int Size = 2; - -private: - cell* - data_; - - int - len_; - - Impl::DynamicArray - value_; -}; - -template -class ParamCast&> -{ -public: - ParamCast(AMX* amx, cell* params, int idx) - : data_(nullptr) - , len_((int)params[idx + 1]) - , value_() - { - value_.resize(len_); - amx_GetAddr(amx, params[idx + 0], &data_); - if (data_ == nullptr) - { - throw pawn_natives::ParamCastFailure(); - } - cell* input = data_; - // Copy the data out. - for (size_t idx = 0; idx != len_; ++idx) - { - value_[idx] = static_cast(input[idx]); - } - } - - ~ParamCast() - { - // Write the data back - cell* input = data_; - // Copy the data out. - for (size_t idx = 0; idx != len_; ++idx) - { - input[idx] = static_cast(value_[idx]); - } - } - - ParamCast(ParamCast&> const&) = delete; - ParamCast(ParamCast&>&&) = delete; - - operator Impl::DynamicArray&() - { - return value_; - } - - static constexpr int Size = 2; - -private: - cell* - data_; - - int - len_; - - Impl::DynamicArray - value_; -}; - -class NotImplemented : public std::logic_error -{ -public: - NotImplemented() - : std::logic_error { "Pawn native not yet implemented." } - { - } -}; -} diff --git a/Server/Components/Pawn/Scripting/Types.hpp b/Server/Components/Pawn/Scripting/Types.hpp index 6f950072f..a45210824 100644 --- a/Server/Components/Pawn/Scripting/Types.hpp +++ b/Server/Components/Pawn/Scripting/Types.hpp @@ -15,7 +15,7 @@ #include "../Manager/Manager.hpp" #include "Impl.hpp" #include "sdk.hpp" -#include +#include namespace pawn_natives { @@ -40,6 +40,11 @@ class ParamCast return *value_; } + bool Error() const + { + return false; + } + static constexpr int Size = 0; private: diff --git a/Server/Components/Pawn/Scripting/Vehicle/Natives.cpp b/Server/Components/Pawn/Scripting/Vehicle/Natives.cpp index cf3d19d50..298fab3d1 100644 --- a/Server/Components/Pawn/Scripting/Vehicle/Natives.cpp +++ b/Server/Components/Pawn/Scripting/Vehicle/Natives.cpp @@ -281,9 +281,10 @@ SCRIPT_API(VehicleCanHaveComponent, bool(int modelid, int componentid)) return Impl::isValidComponentForVehicleModel(modelid, componentid); } -SCRIPT_API(GetRandomCarColPair, void(int modelid, int& colour1, int& colour2, int& colour3, int& colour4)) +SCRIPT_API(GetRandomCarColPair, bool(int modelid, int& colour1, int& colour2, int& colour3, int& colour4)) { getRandomVehicleColour(modelid, colour1, colour2, colour3, colour4); + return true; } SCRIPT_API(CarColIndexToColour, int(int colourIndex, int alpha)) diff --git a/lib/pawn-natives b/lib/pawn-natives index dd67433d1..68f34b4df 160000 --- a/lib/pawn-natives +++ b/lib/pawn-natives @@ -1 +1 @@ -Subproject commit dd67433d1ce5ea4c331b7c25a45ccb919defcc19 +Subproject commit 68f34b4dffdf5568e56437f8fdeec9408361373f