├── README.md ├── .gitmodules ├── src ├── Impl │ ├── Console │ │ ├── APIs.cpp │ │ └── Events.hpp │ ├── Core │ │ ├── Events.hpp │ │ └── APIs.cpp │ ├── Classes │ │ ├── Events.hpp │ │ └── APIs.cpp │ ├── Dialogs │ │ ├── Events.hpp │ │ └── APIs.cpp │ ├── Pickups │ │ ├── Events.hpp │ │ └── APIs.cpp │ ├── Menus │ │ ├── Events.hpp │ │ └── APIs.cpp │ ├── Events │ │ └── APIs.cpp │ ├── Recording │ │ └── APIs.cpp │ ├── CustomModels │ │ ├── Events.hpp │ │ └── APIs.cpp │ ├── Actors │ │ ├── Events.hpp │ │ └── APIs.cpp │ ├── Checkpoints │ │ ├── Events.hpp │ │ └── APIs.cpp │ ├── TextDraws │ │ └── Events.hpp │ ├── GangZones │ │ ├── Events.hpp │ │ └── APIs.cpp │ ├── Component │ │ └── APIs.cpp │ ├── Objects │ │ └── Events.hpp │ ├── Vehicles │ │ ├── Events.hpp │ │ └── APIs.cpp │ ├── Config │ │ └── APIs.cpp │ ├── Players │ │ └── Events.hpp │ ├── ComponentManager.hpp │ ├── ComponentManager.cpp │ └── TextLabels │ │ └── APIs.cpp ├── Utils │ ├── Singleton.hpp │ └── MacroMagic.hpp └── main.cpp ├── docker ├── docker-entrypoint.sh ├── build.sh └── Dockerfile ├── tools ├── generate_docs.js └── generate_single_header.js ├── CMakeLists.txt ├── .github └── workflows │ └── build.yml ├── .clang-format ├── .gitignore └── LICENSE.md /README.md: -------------------------------------------------------------------------------- 1 | open.mp C api component 2 | ================================== 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "sdk"] 2 | path = sdk 3 | url = https://github.com/openmultiplayer/open.mp-sdk 4 | -------------------------------------------------------------------------------- /src/Impl/Console/APIs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #include "../ComponentManager.hpp" 10 | -------------------------------------------------------------------------------- /docker/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | [ -z $CONFIG ] && config=Release || config="$CONFIG" 3 | [ -z $TARGET_BUILD_ARCH ] && target_build_arch=x64 || target_build_arch="$TARGET_BUILD_ARCH" 4 | 5 | cmake \ 6 | -S . \ 7 | -B build \ 8 | -G Ninja \ 9 | -DCMAKE_BUILD_TYPE=$config \ 10 | -DTARGET_BUILD_ARCH=${target_build_arch} \ 11 | && 12 | cmake \ 13 | --build build \ 14 | --config $config \ 15 | --parallel $(nproc) 16 | -------------------------------------------------------------------------------- /src/Impl/Core/Events.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #pragma once 10 | #include "../ComponentManager.hpp" 11 | #include "../../Utils/Singleton.hpp" 12 | #include "sdk.hpp" 13 | 14 | template 15 | struct CoreEvents : public CoreEventHandler, public Singleton> 16 | { 17 | void onTick(Microseconds elapsed, TimePoint now) override 18 | { 19 | ComponentManager::Get()->CallEvent("onTick", EventReturnHandler::None, int(elapsed.count())); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /docker/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Available configs: Debug, [RelWithDebInfo], Release 4 | [[ -z "$CONFIG" ]] \ 5 | && config=Release \ 6 | || config="$CONFIG" 7 | 8 | [[ -z "$TARGET_BUILD_ARCH" ]] \ 9 | && target_build_arch=x86 \ 10 | || target_build_arch="$TARGET_BUILD_ARCH" 11 | 12 | docker build \ 13 | -t omp-capi/build:ubuntu-18.04 ./ \ 14 | || exit 1 15 | 16 | folders=('build') 17 | for folder in "${folders[@]}"; do 18 | if [[ ! -d "./${folder}" ]]; then 19 | mkdir ${folder} 20 | fi 21 | sudo chown -R 1000:1000 ${folder} || exit 1 22 | done 23 | 24 | docker run \ 25 | --rm \ 26 | -t \ 27 | -w /code \ 28 | -v $PWD/..:/code \ 29 | -v $PWD/build:/code/build \ 30 | -e CONFIG=${config} \ 31 | -e TARGET_BUILD_ARCH=${target_build_arch} \ 32 | omp-capi/build:ubuntu-18.04 33 | -------------------------------------------------------------------------------- /src/Impl/Classes/Events.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #pragma once 10 | #include "../ComponentManager.hpp" 11 | #include "../../Utils/Singleton.hpp" 12 | #include "sdk.hpp" 13 | 14 | template 15 | struct ClassEvents : public ClassEventHandler, public Singleton> 16 | { 17 | bool onPlayerRequestClass(IPlayer& player, unsigned int classId) override 18 | { 19 | return ComponentManager::Get()->CallEvent("onPlayerRequestClass", EventReturnHandler::StopAtFalse, &player, int(classId)); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /src/Utils/Singleton.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #pragma once 10 | 11 | template 12 | class Singleton 13 | { 14 | protected: 15 | static T* m_Instance; 16 | 17 | public: 18 | Singleton() 19 | { 20 | } 21 | virtual ~Singleton() 22 | { 23 | } 24 | 25 | inline static T* Get() 26 | { 27 | if (m_Instance == nullptr) 28 | m_Instance = new T; 29 | return m_Instance; 30 | } 31 | 32 | inline static void Destroy() 33 | { 34 | if (m_Instance != nullptr) 35 | { 36 | delete m_Instance; 37 | m_Instance = nullptr; 38 | } 39 | } 40 | }; 41 | 42 | template 43 | T* Singleton::m_Instance = nullptr; 44 | -------------------------------------------------------------------------------- /src/Impl/Dialogs/Events.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #pragma once 10 | #include "../ComponentManager.hpp" 11 | #include "../../Utils/Singleton.hpp" 12 | #include "sdk.hpp" 13 | 14 | template 15 | struct DialogEvents : public PlayerDialogEventHandler, public Singleton> 16 | { 17 | void onDialogResponse(IPlayer& player, int dialogId, DialogResponse response, int listItem, StringView inputText) override 18 | { 19 | ComponentManager::Get()->CallEvent("onDialogResponse", EventReturnHandler::None, &player, dialogId, int(response), listItem, CREATE_CAPI_STRING_VIEW(inputText)); 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /src/Impl/Pickups/Events.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #pragma once 10 | #include "../ComponentManager.hpp" 11 | #include "../../Utils/Singleton.hpp" 12 | #include "sdk.hpp" 13 | 14 | template 15 | struct PickupEvents : public PickupEventHandler, public Singleton> 16 | { 17 | void onPlayerPickUpPickup(IPlayer& player, IPickup& pickup) override 18 | { 19 | if (pickup.getLegacyPlayer() == nullptr) 20 | { 21 | ComponentManager::Get()->CallEvent("onPlayerPickUpPickup", EventReturnHandler::None, &player, &pickup); 22 | } 23 | else if (auto data = queryExtension(player)) 24 | { 25 | } 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /src/Impl/Menus/Events.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #pragma once 10 | #include "../ComponentManager.hpp" 11 | #include "../../Utils/Singleton.hpp" 12 | #include "sdk.hpp" 13 | 14 | template 15 | struct MenuEvents : public MenuEventHandler, public Singleton> 16 | { 17 | void onPlayerSelectedMenuRow(IPlayer& player, MenuRow row) override 18 | { 19 | ComponentManager::Get()->CallEvent("onPlayerSelectedMenuRow", EventReturnHandler::None, &player, int(row)); 20 | } 21 | 22 | void onPlayerExitedMenu(IPlayer& player) override 23 | { 24 | ComponentManager::Get()->CallEvent("onPlayerExitedMenu", EventReturnHandler::None, &player); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /src/Impl/Events/APIs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #include "../ComponentManager.hpp" 10 | 11 | OMP_CAPI(Event_AddHandler, bool(StringCharPtr name, int priority, void* callback)) 12 | { 13 | return ComponentManager::Get()->AddEventHandler(name, EventPriorityType(priority), EventCallback_Common(callback)); 14 | } 15 | 16 | OMP_CAPI(Event_RemoveHandler, bool(StringCharPtr name, int priority, void* callback)) 17 | { 18 | return ComponentManager::Get()->RemoveEventHandler(name, EventPriorityType(priority), EventCallback_Common(callback)); 19 | } 20 | 21 | OMP_CAPI(Event_RemoveAllHandlers, bool(StringCharPtr name, int priority)) 22 | { 23 | ComponentManager::Get()->RemoveAllHandlers(name, EventPriorityType(priority)); 24 | return true; 25 | } 26 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | RUN \ 3 | dpkg --add-architecture i386 && \ 4 | apt-get update && \ 5 | apt-get install -y \ 6 | gpg \ 7 | wget \ 8 | && \ 9 | wget -O- https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | \ 10 | gpg --dearmor - | \ 11 | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null && \ 12 | echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ bionic main' | \ 13 | tee /etc/apt/sources.list.d/kitware.list >/dev/null && \ 14 | apt-get update && \ 15 | apt-get install -y \ 16 | cmake \ 17 | ninja-build \ 18 | clang-10 \ 19 | python3-pip \ 20 | gcc-8-multilib \ 21 | g++-8-multilib \ 22 | libstdc++6:i386 \ 23 | libc6:i386 \ 24 | && \ 25 | useradd -m user 26 | 27 | USER user 28 | 29 | ENV CC=/usr/bin/clang-10 \ 30 | CXX=/usr/bin/clang++-10 \ 31 | PATH=~/.local/bin:${PATH} 32 | 33 | COPY docker-entrypoint.sh / 34 | CMD /docker-entrypoint.sh 35 | -------------------------------------------------------------------------------- /src/Impl/Recording/APIs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #include "../ComponentManager.hpp" 10 | 11 | OMP_CAPI(Recording_Start, bool(objectPtr player, int type, StringCharPtr file)) 12 | { 13 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 14 | IPlayerRecordingData* recording = queryExtension(player_); 15 | if (recording) 16 | { 17 | recording->start(PlayerRecordingType(type), file); 18 | return true; 19 | } 20 | return false; 21 | } 22 | 23 | OMP_CAPI(Recording_Stop, bool(objectPtr player)) 24 | { 25 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 26 | IPlayerRecordingData* recording = queryExtension(player_); 27 | if (recording) 28 | { 29 | recording->stop(); 30 | return true; 31 | } 32 | return false; 33 | } 34 | -------------------------------------------------------------------------------- /src/Impl/CustomModels/Events.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #pragma once 10 | #include "../ComponentManager.hpp" 11 | #include "../../Utils/Singleton.hpp" 12 | #include "sdk.hpp" 13 | 14 | template 15 | struct CustomModelsEvents : public PlayerModelsEventHandler, public Singleton> 16 | { 17 | virtual void onPlayerFinishedDownloading(IPlayer& player) override 18 | { 19 | ComponentManager::Get()->CallEvent("onPlayerFinishedDownloading", EventReturnHandler::None, &player, player.getVirtualWorld()); 20 | } 21 | 22 | virtual bool onPlayerRequestDownload(IPlayer& player, ModelDownloadType type, uint32_t checksum) override 23 | { 24 | return ComponentManager::Get()->CallEvent("onPlayerRequestDownload", EventReturnHandler::StopAtFalse, &player, int(type), int(checksum)); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /src/Impl/Actors/Events.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #pragma once 10 | #include "../ComponentManager.hpp" 11 | #include "../../Utils/Singleton.hpp" 12 | #include "sdk.hpp" 13 | 14 | template 15 | struct ActorEvents : public ActorEventHandler, public Singleton> 16 | { 17 | void onPlayerGiveDamageActor(IPlayer& player, IActor& actor, float amount, unsigned weapon, BodyPart part) override 18 | { 19 | ComponentManager::Get()->CallEvent("onPlayerGiveDamageActor", EventReturnHandler::None, &player, &actor, amount, int(weapon), int(part)); 20 | } 21 | 22 | void onActorStreamIn(IActor& actor, IPlayer& forPlayer) override 23 | { 24 | ComponentManager::Get()->CallEvent("onActorStreamIn", EventReturnHandler::None, &actor, &forPlayer); 25 | } 26 | 27 | void onActorStreamOut(IActor& actor, IPlayer& forPlayer) override 28 | { 29 | ComponentManager::Get()->CallEvent("onActorStreamOut", EventReturnHandler::None, &actor, &forPlayer); 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /src/Impl/Checkpoints/Events.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #pragma once 10 | #include "../ComponentManager.hpp" 11 | #include "../../Utils/Singleton.hpp" 12 | #include "sdk.hpp" 13 | 14 | template 15 | struct CheckpointEvents : public PlayerCheckpointEventHandler, public Singleton> 16 | { 17 | void onPlayerEnterCheckpoint(IPlayer& player) override 18 | { 19 | ComponentManager::Get()->CallEvent("onPlayerEnterCheckpoint", EventReturnHandler::None, &player); 20 | } 21 | 22 | void onPlayerLeaveCheckpoint(IPlayer& player) override 23 | { 24 | ComponentManager::Get()->CallEvent("onPlayerLeaveCheckpoint", EventReturnHandler::None, &player); 25 | } 26 | 27 | void onPlayerEnterRaceCheckpoint(IPlayer& player) override 28 | { 29 | ComponentManager::Get()->CallEvent("onPlayerEnterRaceCheckpoint", EventReturnHandler::None, &player); 30 | } 31 | 32 | void onPlayerLeaveRaceCheckpoint(IPlayer& player) override 33 | { 34 | 35 | ComponentManager::Get()->CallEvent("onPlayerLeaveRaceCheckpoint", EventReturnHandler::None, &player); 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /src/Impl/Console/Events.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #pragma once 10 | #include "../ComponentManager.hpp" 11 | #include "../../Utils/Singleton.hpp" 12 | #include "sdk.hpp" 13 | 14 | template 15 | struct ConsoleEvents : public ConsoleEventHandler, public Singleton> 16 | { 17 | bool onConsoleText(StringView command, StringView parameters, const ConsoleCommandSenderData& sender) override 18 | { 19 | return ComponentManager::Get()->CallEvent("onConsoleText", EventReturnHandler::StopAtTrue, CREATE_CAPI_STRING_VIEW(command), CREATE_CAPI_STRING_VIEW(parameters)); 20 | } 21 | 22 | void onRconLoginAttempt(IPlayer& player, StringView password, bool success) override 23 | { 24 | PeerNetworkData data = player.getNetworkData(); 25 | PeerAddress::AddressString addressString; 26 | PeerAddress::ToString(data.networkID.address, addressString); 27 | StringView addressStringView = StringView(addressString.data(), addressString.length()); 28 | 29 | ComponentManager::Get()->CallEvent("onRconLoginAttempt", EventReturnHandler::StopAtTrue, CREATE_CAPI_STRING_VIEW(addressStringView), CREATE_CAPI_STRING_VIEW(password), success); 30 | } 31 | }; 32 | -------------------------------------------------------------------------------- /src/Impl/TextDraws/Events.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #pragma once 10 | #include "../ComponentManager.hpp" 11 | #include "../../Utils/Singleton.hpp" 12 | #include "sdk.hpp" 13 | 14 | template 15 | struct TextDrawEvents : public TextDrawEventHandler, public Singleton> 16 | { 17 | virtual bool onPlayerCancelTextDrawSelection(IPlayer& player) override 18 | { 19 | ComponentManager::Get()->CallEvent("onPlayerCancelTextDrawSelection", EventReturnHandler::None, &player); 20 | return true; 21 | } 22 | 23 | virtual bool onPlayerCancelPlayerTextDrawSelection(IPlayer& player) override 24 | { 25 | ComponentManager::Get()->CallEvent("onPlayerCancelPlayerTextDrawSelection", EventReturnHandler::None, &player); 26 | return true; 27 | } 28 | 29 | void onPlayerClickTextDraw(IPlayer& player, ITextDraw& td) override 30 | { 31 | ComponentManager::Get()->CallEvent("onPlayerClickTextDraw", EventReturnHandler::None, &player, &td); 32 | } 33 | 34 | void onPlayerClickPlayerTextDraw(IPlayer& player, IPlayerTextDraw& td) override 35 | { 36 | ComponentManager::Get()->CallEvent("onPlayerClickPlayerTextDraw", EventReturnHandler::None, &player, &td); 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /src/Impl/GangZones/Events.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #pragma once 10 | #include "../ComponentManager.hpp" 11 | #include "../../Utils/Singleton.hpp" 12 | #include "sdk.hpp" 13 | 14 | template 15 | struct GangZoneEvents : public GangZoneEventHandler, public Singleton> 16 | { 17 | void onPlayerEnterGangZone(IPlayer& player, IGangZone& zone) override 18 | { 19 | if (zone.getLegacyPlayer() == nullptr) 20 | { 21 | ComponentManager::Get()->CallEvent("onPlayerEnterGangZone", EventReturnHandler::None, &player, &zone); 22 | } 23 | else if (auto data = queryExtension(player)) 24 | { 25 | } 26 | } 27 | 28 | void onPlayerLeaveGangZone(IPlayer& player, IGangZone& zone) override 29 | { 30 | if (zone.getLegacyPlayer() == nullptr) 31 | { 32 | ComponentManager::Get()->CallEvent("onPlayerLeaveGangZone", EventReturnHandler::None, &player, &zone); 33 | } 34 | else if (auto data = queryExtension(player)) 35 | { 36 | } 37 | } 38 | 39 | void onPlayerClickGangZone(IPlayer& player, IGangZone& zone) override 40 | { 41 | if (zone.getLegacyPlayer() == nullptr) 42 | { 43 | ComponentManager::Get()->CallEvent("onPlayerClickGangZone", EventReturnHandler::None, &player, &zone); 44 | } 45 | else if (auto data = queryExtension(player)) 46 | { 47 | } 48 | } 49 | }; 50 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #include 10 | #include "Impl/ComponentManager.hpp" 11 | 12 | class CAPIComponent final : public IComponent 13 | { 14 | private: 15 | ICore* core_ = nullptr; 16 | 17 | public: 18 | PROVIDE_UID(0x10467DD8D4C56FC6) 19 | 20 | ~CAPIComponent() 21 | { 22 | ComponentManager::Get()->FreeEvents(); 23 | } 24 | 25 | StringView componentName() const override 26 | { 27 | return "open.mp C-API"; 28 | } 29 | 30 | SemanticVersion componentVersion() const override 31 | { 32 | return SemanticVersion(0, 1, 0, 0); 33 | } 34 | 35 | void onLoad(ICore* c) override 36 | { 37 | core_ = c; 38 | core_->printLn("open.mp C-API component loaded"); 39 | } 40 | 41 | void onInit(IComponentList* components) override 42 | { 43 | ComponentManager::Get()->Init(core_, components); 44 | 45 | ComponentManager::Get()->InitializeEvents(); 46 | } 47 | 48 | void onReady() override 49 | { 50 | } 51 | 52 | void onFree(IComponent* component) override 53 | { 54 | #define COMPONENT_UNLOADED(var) \ 55 | if (component == var) \ 56 | var = nullptr; 57 | 58 | auto mgr = ComponentManager::Get(); 59 | 60 | COMPONENT_UNLOADED(mgr->actors) 61 | COMPONENT_UNLOADED(mgr->console) 62 | COMPONENT_UNLOADED(mgr->checkpoints) 63 | COMPONENT_UNLOADED(mgr->classes) 64 | COMPONENT_UNLOADED(mgr->dialogs) 65 | COMPONENT_UNLOADED(mgr->gangzones) 66 | COMPONENT_UNLOADED(mgr->menus) 67 | COMPONENT_UNLOADED(mgr->objects) 68 | COMPONENT_UNLOADED(mgr->pickups) 69 | COMPONENT_UNLOADED(mgr->textdraws) 70 | COMPONENT_UNLOADED(mgr->textlabels) 71 | COMPONENT_UNLOADED(mgr->vehicles) 72 | COMPONENT_UNLOADED(mgr->models) 73 | } 74 | 75 | void free() override 76 | { 77 | delete this; 78 | } 79 | 80 | void reset() override 81 | { 82 | } 83 | }; 84 | 85 | COMPONENT_ENTRY_POINT() 86 | { 87 | return new CAPIComponent(); 88 | } 89 | -------------------------------------------------------------------------------- /tools/generate_docs.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const readline = require("node:readline"); 3 | 4 | const files = fs 5 | .readdirSync("../src/Impl", { recursive: true }) 6 | .filter((file) => { 7 | return file.endsWith("APIs.cpp"); 8 | }); 9 | 10 | const APIs = {}; 11 | 12 | const convertTypeNames = (type) => { 13 | if (type === "StringCharPtr") { 14 | return "const char*"; 15 | } else if (type === "objectPtr") { 16 | return "void*"; 17 | } else if (type === "voidPtr") { 18 | return "void*"; 19 | } else if (type === "OutputStringViewPtr") { 20 | return "CAPIStringView*"; 21 | } else { 22 | return type; 23 | } 24 | }; 25 | 26 | files.forEach(async (file, index) => { 27 | const data = fs.createReadStream("../src/Impl/" + file); 28 | const lines = readline.createInterface({ 29 | input: data, 30 | crlfDelay: Infinity, 31 | }); 32 | 33 | for await (const line of lines) { 34 | if (line.startsWith("OMP_CAPI(")) { 35 | const v0 = line.replace("OMP_CAPI(", ""); 36 | const name = v0.split(", ")[0]; 37 | const component = name.split("_")[0]; 38 | 39 | if (APIs[component] === undefined) { 40 | APIs[component] = []; 41 | } 42 | 43 | const v1 = v0.split(", ")[1]; 44 | const ret = v1.substring(0, v1.indexOf("(")); 45 | const v2 = v0.replace(`OMP_CAPI(${name}, ${ret}`, ""); 46 | const params = v2 47 | .substring(v2.indexOf("(") + 1, v2.indexOf(")")) 48 | .split(", ") 49 | .map((param) => { 50 | const name = param.split(" ")[1]; 51 | const type = param.split(" ")[0]; 52 | 53 | if (name === undefined) { 54 | return undefined; 55 | } 56 | 57 | return { 58 | name, 59 | type: convertTypeNames(type), 60 | }; 61 | }); 62 | 63 | APIs[component].push({ 64 | ret: convertTypeNames(ret), 65 | name, 66 | params: params.length === 1 && params[0] === undefined ? [] : params, 67 | }); 68 | } 69 | } 70 | 71 | if (index == files.length - 1) { 72 | fs.writeFileSync("../apidocs/api.json", JSON.stringify(APIs, undefined, 2)); 73 | } 74 | }); 75 | -------------------------------------------------------------------------------- /src/Impl/Dialogs/APIs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #include "../ComponentManager.hpp" 10 | 11 | OMP_CAPI(Dialog_Show, bool(objectPtr player, int dialog, int style, StringCharPtr title, StringCharPtr body, StringCharPtr button1, StringCharPtr button2)) 12 | { 13 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 14 | IPlayerDialogData* data = queryExtension(player_); 15 | if (!data) 16 | { 17 | return false; 18 | } 19 | 20 | if (dialog == INVALID_DIALOG_ID) 21 | { 22 | static bool warned = false; 23 | if (!warned) 24 | { 25 | ComponentManager::Get()->core->logLn(LogLevel::Warning, "Invalid dialog ID %d used. Use `Dialog_Hide()`.", dialog); 26 | warned = true; 27 | } 28 | 29 | data->hide(*player_); 30 | return true; 31 | } 32 | 33 | data->show(*player_, dialog & 0xFFFF, DialogStyle(style), title, body, button1, button2); 34 | return true; 35 | } 36 | 37 | OMP_CAPI(Player_GetDialog, int(objectPtr player)) 38 | { 39 | POOL_ENTITY_RET(players, IPlayer, player, player_, INVALID_DIALOG_ID); 40 | IPlayerDialogData* data = queryExtension(player_); 41 | auto dialog = data->getActiveID(); 42 | return dialog; 43 | } 44 | 45 | OMP_CAPI(Player_GetDialogData, bool(objectPtr player, int* dialogid, int* style, OutputStringViewPtr title, OutputStringViewPtr body, OutputStringViewPtr button1, OutputStringViewPtr button2)) 46 | { 47 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 48 | IPlayerDialogData* data = queryExtension(player_); 49 | DialogStyle styleVar {}; 50 | StringView titleVar {}; 51 | StringView bodyVar {}; 52 | StringView button1Var {}; 53 | StringView button2Var {}; 54 | data->get(*dialogid, styleVar, titleVar, bodyVar, button1Var, button2Var); 55 | *style = int(styleVar); 56 | SET_CAPI_STRING_VIEW(title, titleVar); 57 | SET_CAPI_STRING_VIEW(body, bodyVar); 58 | SET_CAPI_STRING_VIEW(button1, button1Var); 59 | SET_CAPI_STRING_VIEW(button2, button2Var); 60 | return true; 61 | } 62 | 63 | OMP_CAPI(Dialog_Hide, bool(objectPtr player)) 64 | { 65 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 66 | IPlayerDialogData* dialog = queryExtension(player_); 67 | if (dialog && dialog->getActiveID() != INVALID_DIALOG_ID) 68 | { 69 | dialog->hide(*player_); 70 | return true; 71 | } 72 | return true; 73 | } 74 | -------------------------------------------------------------------------------- /src/Impl/Component/APIs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #include "../ComponentManager.hpp" 10 | 11 | class Component final : public IComponent 12 | { 13 | private: 14 | Impl::String name_; 15 | uint64_t uid_; 16 | ComponentVersion version_; 17 | 18 | ComponentOnReadyCallback onReadyCB_; 19 | ComponentOnResetCallback onResetCB_; 20 | ComponentOnFreeCallback onFreeCB_; 21 | 22 | public: 23 | UID getUID() override 24 | { 25 | return uid_; 26 | } 27 | 28 | Component(UID uid, const Impl::String& name, const ComponentVersion& version) 29 | : name_(name) 30 | , uid_(uid) 31 | , version_(version) 32 | { 33 | onReadyCB_ = nullptr; 34 | onResetCB_ = nullptr; 35 | onFreeCB_ = nullptr; 36 | } 37 | 38 | ~Component() 39 | { 40 | ComponentManager::Get()->FreeEvents(); 41 | } 42 | 43 | StringView componentName() const override 44 | { 45 | return name_.c_str(); 46 | } 47 | 48 | SemanticVersion componentVersion() const override 49 | { 50 | return SemanticVersion(version_.major, version_.minor, version_.patch, version_.prerel); 51 | } 52 | 53 | void onLoad(ICore* c) override 54 | { 55 | c->logLn(LogLevel::Message, "%s component has been loaded", name_.c_str()); 56 | } 57 | 58 | void onInit(IComponentList* components) override 59 | { 60 | } 61 | 62 | void onReady() override 63 | { 64 | if (onReadyCB_) 65 | { 66 | onReadyCB_(); 67 | } 68 | } 69 | 70 | void onFree(IComponent* component) override 71 | { 72 | } 73 | 74 | void free() override 75 | { 76 | if (onFreeCB_) 77 | { 78 | onFreeCB_(); 79 | } 80 | delete this; 81 | } 82 | 83 | void reset() override 84 | { 85 | if (onResetCB_) 86 | { 87 | onResetCB_(); 88 | } 89 | } 90 | 91 | void setCallbacks(ComponentOnReadyCallback onReadyCB, ComponentOnResetCallback onResetCB, ComponentOnFreeCallback onFreeCB) 92 | { 93 | onReadyCB_ = onReadyCB; 94 | onResetCB_ = onResetCB; 95 | onFreeCB_ = onFreeCB; 96 | } 97 | }; 98 | 99 | OMP_CAPI(Component_Create, voidPtr(uint64_t uid, StringCharPtr name, ComponentVersion version, voidPtr onReadyCB, voidPtr onResetCB, voidPtr onFreeCB)) 100 | { 101 | auto component = new Component(uid, name, version); 102 | component->setCallbacks(ComponentOnReadyCallback(onReadyCB), ComponentOnResetCallback(onResetCB), ComponentOnFreeCallback(onFreeCB)); 103 | return component; 104 | } 105 | -------------------------------------------------------------------------------- /src/Impl/Objects/Events.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #pragma once 10 | #include "../ComponentManager.hpp" 11 | #include "../../Utils/Singleton.hpp" 12 | #include "sdk.hpp" 13 | 14 | template 15 | struct ObjectEvents : public ObjectEventHandler, public Singleton> 16 | { 17 | void onMoved(IObject& object) override 18 | { 19 | ComponentManager::Get()->CallEvent("onObjectMove", EventReturnHandler::None, &object); 20 | } 21 | 22 | void onPlayerObjectMoved(IPlayer& player, IPlayerObject& object) override 23 | { 24 | ComponentManager::Get()->CallEvent("onPlayerObjectMove", EventReturnHandler::None, &player, &object); 25 | } 26 | 27 | void onObjectEdited(IPlayer& player, IObject& object, ObjectEditResponse response, Vector3 offset, Vector3 rotation) override 28 | { 29 | ComponentManager::Get()->CallEvent("onPlayerEditObject", EventReturnHandler::None, &player, &object, int(response), offset.x, offset.y, offset.z, rotation.x, rotation.y, rotation.z); 30 | } 31 | 32 | void onPlayerObjectEdited(IPlayer& player, IPlayerObject& object, ObjectEditResponse response, Vector3 offset, Vector3 rotation) override 33 | { 34 | ComponentManager::Get()->CallEvent("onPlayerEditPlayerObject", EventReturnHandler::None, &player, &object, int(response), offset.x, offset.y, offset.z, rotation.x, rotation.y, rotation.z); 35 | } 36 | 37 | void onPlayerAttachedObjectEdited(IPlayer& player, int index, bool saved, const ObjectAttachmentSlotData& data) override 38 | { 39 | ComponentManager::Get()->CallEvent("onPlayerEditAttachedObject", EventReturnHandler::None, 40 | &player, saved, index, data.model, data.bone, 41 | data.offset.x, data.offset.y, data.offset.z, 42 | data.rotation.x, data.rotation.y, data.rotation.z, 43 | data.scale.x, data.scale.y, data.scale.z); 44 | } 45 | 46 | void onObjectSelected(IPlayer& player, IObject& object, int model, Vector3 position) override 47 | { 48 | ComponentManager::Get()->CallEvent("onPlayerSelectObject", EventReturnHandler::None, &player, &object, model, position.x, position.y, position.z); 49 | } 50 | 51 | void onPlayerObjectSelected(IPlayer& player, IPlayerObject& object, int model, Vector3 position) override 52 | { 53 | ComponentManager::Get()->CallEvent("onPlayerSelectPlayerObject", EventReturnHandler::None, &player, &object, model, position.x, position.y, position.z); 54 | } 55 | }; 56 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.19) 2 | project(CAPI LANGUAGES C CXX VERSION 0.0.1) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | 6 | function(GroupSourcesByFolder target) 7 | set(SOURCE_GROUP_DELIMITER "/") 8 | set(last_dir "") 9 | set(files "") 10 | 11 | get_target_property(sources ${target} SOURCES) 12 | 13 | foreach(file ${sources}) 14 | file(RELATIVE_PATH relative_file "${CMAKE_CURRENT_SOURCE_DIR}" ${file}) 15 | get_filename_component(dir "${relative_file}" PATH) 16 | if(NOT "${dir}" STREQUAL "${last_dir}") 17 | if(files) 18 | source_group("${last_dir}" FILES ${files}) 19 | endif() 20 | set(files "") 21 | endif() 22 | set(files ${files} ${file}) 23 | set(last_dir "${dir}") 24 | endforeach() 25 | 26 | if(files) 27 | source_group("${last_dir}" FILES ${files}) 28 | endif() 29 | endfunction() 30 | 31 | if (NOT TARGET_BUILD_ARCH) 32 | if (MSVC_CXX_ARCHITECTURE_ID) 33 | string(TOLOWER ${MSVC_CXX_ARCHITECTURE_ID} LOWERCASE_CMAKE_SYSTEM_PROCESSOR) 34 | if (LOWERCASE_CMAKE_SYSTEM_PROCESSOR MATCHES "(x64|x86_64|amd64)") 35 | set(TARGET_BUILD_ARCH x64) 36 | elseif (LOWERCASE_CMAKE_SYSTEM_PROCESSOR MATCHES "(i[3-6]86|x86)") 37 | set(TARGET_BUILD_ARCH x86) 38 | else () 39 | message(FATAL_ERROR "MSVC Arch ID: Unknown CPU '${LOWERCASE_CMAKE_SYSTEM_PROCESSOR}'") 40 | endif () 41 | else () 42 | if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x64|x86_64|amd64)") 43 | set(TARGET_BUILD_ARCH x64) 44 | elseif (CMAKE_SYSTEM_PROCESSOR MATCHES "(i[3-6]86|x86)") 45 | set(TARGET_BUILD_ARCH x86) 46 | set(CMAKE_C_FLAGS "-m32 ${CMAKE_C_FLAGS}") 47 | set(CMAKE_CXX_FLAGS "-m32 ${CMAKE_CXX_FLAGS}") 48 | set(CMAKE_SIZEOF_VOID_P 4) 49 | else () 50 | if (CMAKE_SYSTEM_PROCESSOR MATCHES "(arm64)") 51 | set(TARGET_BUILD_ARCH armv8) 52 | else () 53 | set(TARGET_BUILD_ARCH x86) 54 | endif () 55 | endif () 56 | endif () 57 | else() 58 | if (TARGET_BUILD_ARCH STREQUAL "x86" AND NOT MSVC_CXX_ARCHITECTURE_ID) 59 | set(CMAKE_C_FLAGS "-m32 ${CMAKE_C_FLAGS}") 60 | set(CMAKE_CXX_FLAGS "-m32 ${CMAKE_CXX_FLAGS}") 61 | set(CMAKE_SIZEOF_VOID_P 4) 62 | endif() 63 | endif() 64 | 65 | message(TARGET_BUILD_ARCH = "${TARGET_BUILD_ARCH}") 66 | 67 | add_subdirectory(sdk) 68 | 69 | file(GLOB_RECURSE CAPI_FILES 70 | "include/*.h" 71 | "src/*.hpp" 72 | "src/*.cpp" 73 | ) 74 | 75 | add_definitions(-DCAPI_COMPONENT_BUILD) 76 | add_library(${PROJECT_NAME} SHARED ${CAPI_FILES}) 77 | 78 | GroupSourcesByFolder(${PROJECT_NAME}) 79 | 80 | target_link_libraries(${PROJECT_NAME} PRIVATE 81 | OMP-SDK 82 | ) 83 | 84 | set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "$") 85 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - "*" 8 | - "*/*" 9 | - "**" 10 | pull_request: 11 | branches: 12 | - "master" 13 | 14 | jobs: 15 | build-windows-x64-release: 16 | runs-on: windows-2022 17 | steps: 18 | - uses: actions/checkout@v4 19 | with: 20 | clean: true 21 | submodules: recursive 22 | fetch-depth: 0 23 | 24 | - name: Generate build files 25 | run: | 26 | mkdir build 27 | cd build 28 | cmake -DCMAKE_BUILD_TYPE=Release .. -G "Visual Studio 17 2022" 29 | cmake --build . --config Release 30 | 31 | - name: Create a folder for release 32 | shell: bash 33 | run: | 34 | mkdir dist 35 | mv './build/Release/$CAPI.dll' './dist/$CAPI.dll' 36 | 37 | - name: Upload artifacts 38 | uses: actions/upload-artifact@v4 39 | with: 40 | name: omp-capi-win-x64 41 | path: dist/* 42 | 43 | build-windows-x86-release: 44 | runs-on: windows-2022 45 | steps: 46 | - uses: actions/checkout@v4 47 | with: 48 | clean: true 49 | submodules: recursive 50 | fetch-depth: 0 51 | 52 | - name: Generate build files 53 | run: | 54 | mkdir build 55 | cd build 56 | cmake -DCMAKE_BUILD_TYPE=Release .. -A Win32 -G "Visual Studio 17 2022" 57 | cmake --build . --config Release 58 | 59 | - name: Create a folder for release 60 | shell: bash 61 | run: | 62 | mkdir dist 63 | mv './build/Release/$CAPI.dll' './dist/$CAPI.dll' 64 | 65 | - name: Upload artifacts 66 | uses: actions/upload-artifact@v4 67 | with: 68 | name: omp-capi-win32 69 | path: dist/* 70 | 71 | build-linux-x64-release: 72 | runs-on: ubuntu-latest 73 | steps: 74 | - uses: actions/checkout@v3 75 | with: 76 | clean: true 77 | submodules: recursive 78 | fetch-depth: 0 79 | 80 | - name: Build using docker 81 | run: | 82 | cd docker 83 | chmod +x ./build.sh 84 | chmod +x ./docker-entrypoint.sh 85 | TARGET_BUILD_ARCH=x64 ./build.sh 86 | 87 | - name: Create a folder for release 88 | shell: bash 89 | run: | 90 | mkdir dist 91 | sudo mv './docker/build/$CAPI.so' './dist/$CAPI.so' 92 | 93 | - name: Upload artifacts 94 | uses: actions/upload-artifact@v4 95 | with: 96 | name: omp-capi-linux-x64 97 | path: dist/* 98 | 99 | build-linux-x86-release: 100 | runs-on: ubuntu-latest 101 | steps: 102 | - uses: actions/checkout@v3 103 | with: 104 | clean: true 105 | submodules: recursive 106 | fetch-depth: 0 107 | 108 | - name: Build using docker 109 | run: | 110 | cd docker 111 | chmod +x ./build.sh 112 | chmod +x ./docker-entrypoint.sh 113 | TARGET_BUILD_ARCH=x86 ./build.sh 114 | 115 | - name: Create a folder for release 116 | shell: bash 117 | run: | 118 | mkdir dist 119 | sudo mv './docker/build/$CAPI.so' './dist/$CAPI.so' 120 | 121 | - name: Upload artifacts 122 | uses: actions/upload-artifact@v4 123 | with: 124 | name: omp-capi-linux-x86 125 | path: dist/* 126 | -------------------------------------------------------------------------------- /src/Utils/MacroMagic.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #pragma once 10 | #include 11 | #include "../../include/ompcapi.h" 12 | 13 | #define EXPORT_OMP_API extern "C" SDK_EXPORT 14 | 15 | using OutputStringViewPtr = CAPIStringView*; 16 | using StringCharPtr = const char*; 17 | using objectPtr = void*; 18 | using voidPtr = void*; 19 | 20 | #define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__) 21 | #define PRIMITIVE_CAT(a, ...) a##__VA_ARGS__ 22 | 23 | #define EMPTY() 24 | #define DEFER(id) id EMPTY() 25 | #define OBSTRUCT(...) __VA_ARGS__ DEFER(EMPTY)() 26 | #define EXPAND(...) __VA_ARGS__ 27 | 28 | #define OMP_CAPI__WITHOUT_PARAMS_size_t(...) size_t 29 | #define OMP_CAPI__WITHOUT_PARAMS_unsigned(...) unsigned 30 | #define OMP_CAPI__WITHOUT_PARAMS_int(...) int 31 | #define OMP_CAPI__WITHOUT_PARAMS_float(...) float 32 | #define OMP_CAPI__WITHOUT_PARAMS_bool(...) bool 33 | #define OMP_CAPI__WITHOUT_PARAMS_void(...) void 34 | #define OMP_CAPI__WITHOUT_PARAMS_cell(...) cell 35 | #define OMP_CAPI__WITHOUT_PARAMS_id(...) id 36 | #define OMP_CAPI__WITHOUT_PARAMS_int8_t(...) int8_t 37 | #define OMP_CAPI__WITHOUT_PARAMS_int16_t(...) int16_t 38 | #define OMP_CAPI__WITHOUT_PARAMS_int32_t(...) int32_t 39 | #define OMP_CAPI__WITHOUT_PARAMS_int64_t(...) int64_t 40 | #define OMP_CAPI__WITHOUT_PARAMS_uint8_t(...) uint8_t 41 | #define OMP_CAPI__WITHOUT_PARAMS_uint16_t(...) uint16_t 42 | #define OMP_CAPI__WITHOUT_PARAMS_uint32_t(...) uint32_t 43 | #define OMP_CAPI__WITHOUT_PARAMS_uint64_t(...) uint64_t 44 | #define OMP_CAPI__WITHOUT_PARAMS_objectPtr(...) objectPtr 45 | #define OMP_CAPI__WITHOUT_PARAMS_voidPtr(...) voidPtr 46 | 47 | #define OMP_CAPI__WITHOUT_RETURN_size_t(...) __VA_ARGS__ 48 | #define OMP_CAPI__WITHOUT_RETURN_unsigned(...) __VA_ARGS__ 49 | #define OMP_CAPI__WITHOUT_RETURN_int(...) __VA_ARGS__ 50 | #define OMP_CAPI__WITHOUT_RETURN_float(...) __VA_ARGS__ 51 | #define OMP_CAPI__WITHOUT_RETURN_bool(...) __VA_ARGS__ 52 | #define OMP_CAPI__WITHOUT_RETURN_void(...) __VA_ARGS__ 53 | #define OMP_CAPI__WITHOUT_RETURN_cell(...) __VA_ARGS__ 54 | #define OMP_CAPI__WITHOUT_RETURN_id(...) __VA_ARGS__ 55 | #define OMP_CAPI__WITHOUT_RETURN_int8_t(...) __VA_ARGS__ 56 | #define OMP_CAPI__WITHOUT_RETURN_int16_t(...) __VA_ARGS__ 57 | #define OMP_CAPI__WITHOUT_RETURN_int32_t(...) __VA_ARGS__ 58 | #define OMP_CAPI__WITHOUT_RETURN_int64_t(...) __VA_ARGS__ 59 | #define OMP_CAPI__WITHOUT_RETURN_uint8_t(...) __VA_ARGS__ 60 | #define OMP_CAPI__WITHOUT_RETURN_uint16_t(...) __VA_ARGS__ 61 | #define OMP_CAPI__WITHOUT_RETURN_uint32_t(...) __VA_ARGS__ 62 | #define OMP_CAPI__WITHOUT_RETURN_uint64_t(...) __VA_ARGS__ 63 | #define OMP_CAPI__WITHOUT_RETURN_objectPtr(...) __VA_ARGS__ 64 | #define OMP_CAPI__WITHOUT_RETURN_voidPtr(...) __VA_ARGS__ 65 | 66 | #define OMP_CAPI__RETURN(params) OMP_CAPI__WITHOUT_PARAMS_##params 67 | #define OMP_CAPI__PARAMETERS(params) CAT(OMP_CAPI__WITHOUT_RETURN_, params) 68 | 69 | // name: name for IPC event sent from clients (other languages) 70 | // params: params in nlohmann::json object 71 | #define OMP_CAPI(name, params) \ 72 | EXPORT_OMP_API OMP_CAPI__RETURN(params) name(OMP_CAPI__PARAMETERS(params)) 73 | 74 | #define RETURN_VALUE(x) returnValue(x) 75 | #define RETURN_ERROR(x) returnError(x) 76 | #define UNDEFINED_FAILED_RETURN(x) RETURN_ERROR("undefined error") 77 | #define FUNCTION_FAIL_RETURN RETURN_ERROR(this->name_ + ": error while executing.") 78 | -------------------------------------------------------------------------------- /src/Impl/CustomModels/APIs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #include "../ComponentManager.hpp" 10 | 11 | OMP_CAPI(CustomModel_AddCharModel, bool(int baseid, int newid, StringCharPtr dff, StringCharPtr textureLibrary)) 12 | { 13 | auto models = ComponentManager::Get()->models; 14 | if (!models) 15 | { 16 | return false; 17 | } 18 | 19 | bool ret = models->addCustomModel(ModelType::Skin, newid, baseid, dff, textureLibrary); 20 | return ret; 21 | } 22 | 23 | OMP_CAPI(CustomModel_AddSimpleModel, bool(int virtualWorld, int baseid, int newid, StringCharPtr dff, StringCharPtr textureLibrary)) 24 | { 25 | auto models = ComponentManager::Get()->models; 26 | if (!models) 27 | { 28 | return false; 29 | } 30 | 31 | bool ret = models->addCustomModel(ModelType::Object, newid, baseid, dff, textureLibrary, virtualWorld); 32 | return ret; 33 | } 34 | 35 | OMP_CAPI(CustomModel_AddSimpleModelTimed, bool(int virtualWorld, int baseid, int newid, StringCharPtr dff, StringCharPtr textureLibrary, int timeOn, int timeOff)) 36 | { 37 | auto models = ComponentManager::Get()->models; 38 | if (!models) 39 | { 40 | return false; 41 | } 42 | 43 | bool ret = models->addCustomModel(ModelType::Object, newid, baseid, dff, textureLibrary, virtualWorld, uint8_t(timeOn), uint8_t(timeOff)); 44 | return ret; 45 | } 46 | 47 | OMP_CAPI(Player_GetCustomSkin, int(objectPtr player)) 48 | { 49 | POOL_ENTITY_RET(players, IPlayer, player, player_, 0); 50 | IPlayerCustomModelsData* data = queryExtension(player_); 51 | if (!data) 52 | { 53 | return 0; 54 | } 55 | auto skin = data->getCustomSkin(); 56 | return skin; 57 | } 58 | 59 | OMP_CAPI(CustomModel_RedirectDownload, bool(objectPtr player, StringCharPtr url)) 60 | { 61 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 62 | IPlayerCustomModelsData* data = queryExtension(player_); 63 | if (!data) 64 | { 65 | return false; 66 | } 67 | if (!data->sendDownloadUrl(url)) 68 | { 69 | ComponentManager::Get()->core->logLn(LogLevel::Warning, "This native can be used only within OnPlayerRequestDownload callback."); 70 | return false; 71 | } 72 | return true; 73 | } 74 | 75 | OMP_CAPI(CustomModel_FindModelFileNameFromCRC, int(int crc, OutputStringViewPtr output)) 76 | { 77 | auto models = ComponentManager::Get()->models; 78 | if (!models) 79 | { 80 | return false; 81 | } 82 | 83 | auto result = models->getModelNameFromChecksum(crc); 84 | SET_CAPI_STRING_VIEW(output, result); 85 | return true; 86 | } 87 | 88 | OMP_CAPI(CustomModel_IsValid, bool(int modelId)) 89 | { 90 | auto models = ComponentManager::Get()->models; 91 | if (!models) 92 | { 93 | return false; 94 | } 95 | 96 | auto valid = models->isValidCustomModel(modelId); 97 | return valid; 98 | } 99 | 100 | OMP_CAPI(CustomModel_GetPath, bool(int modelId, OutputStringViewPtr dffPath, OutputStringViewPtr txdPath)) 101 | { 102 | auto models = ComponentManager::Get()->models; 103 | if (!models) 104 | { 105 | return false; 106 | } 107 | 108 | StringView dffPathSV {}; 109 | StringView txdPathSV {}; 110 | 111 | auto status = models->getCustomModelPath(modelId, dffPathSV, txdPathSV); 112 | 113 | SET_CAPI_STRING_VIEW(dffPath, dffPathSV); 114 | SET_CAPI_STRING_VIEW(txdPath, txdPathSV); 115 | 116 | return status; 117 | } 118 | -------------------------------------------------------------------------------- /src/Impl/Vehicles/Events.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #pragma once 10 | #include "../ComponentManager.hpp" 11 | #include "../../Utils/Singleton.hpp" 12 | #include "sdk.hpp" 13 | 14 | template 15 | struct VehicleEvents : public VehicleEventHandler, public Singleton> 16 | { 17 | void onVehicleStreamIn(IVehicle& vehicle, IPlayer& player) override 18 | { 19 | ComponentManager::Get()->CallEvent("onVehicleStreamIn", EventReturnHandler::None, &vehicle, &player); 20 | } 21 | 22 | void onVehicleStreamOut(IVehicle& vehicle, IPlayer& player) override 23 | { 24 | ComponentManager::Get()->CallEvent("onVehicleStreamOut", EventReturnHandler::None, &vehicle, &player); 25 | } 26 | 27 | void onVehicleDeath(IVehicle& vehicle, IPlayer& player) override 28 | { 29 | ComponentManager::Get()->CallEvent("onVehicleDeath", EventReturnHandler::None, &vehicle, &player); 30 | } 31 | 32 | void onPlayerEnterVehicle(IPlayer& player, IVehicle& vehicle, bool passenger) override 33 | { 34 | ComponentManager::Get()->CallEvent("onPlayerEnterVehicle", EventReturnHandler::None, &player, &vehicle, passenger); 35 | } 36 | 37 | void onPlayerExitVehicle(IPlayer& player, IVehicle& vehicle) override 38 | { 39 | ComponentManager::Get()->CallEvent("onPlayerExitVehicle", EventReturnHandler::None, &player, &vehicle); 40 | } 41 | 42 | void onVehicleDamageStatusUpdate(IVehicle& vehicle, IPlayer& player) override 43 | { 44 | ComponentManager::Get()->CallEvent("onVehicleDamageStatusUpdate", EventReturnHandler::None, &vehicle, &player); 45 | } 46 | 47 | bool onVehiclePaintJob(IPlayer& player, IVehicle& vehicle, int paintJob) override 48 | { 49 | return ComponentManager::Get()->CallEvent("onVehiclePaintJob", EventReturnHandler::StopAtFalse, &player, &vehicle, paintJob); 50 | } 51 | 52 | bool onVehicleMod(IPlayer& player, IVehicle& vehicle, int component) override 53 | { 54 | return ComponentManager::Get()->CallEvent("onVehicleMod", EventReturnHandler::StopAtFalse, &player, &vehicle, component); 55 | } 56 | 57 | bool onVehicleRespray(IPlayer& player, IVehicle& vehicle, int colour1, int colour2) override 58 | { 59 | return ComponentManager::Get()->CallEvent("onVehicleRespray", EventReturnHandler::StopAtFalse, &player, &vehicle, colour1, colour2); 60 | } 61 | 62 | void onEnterExitModShop(IPlayer& player, bool enterexit, int interiorID) override 63 | { 64 | ComponentManager::Get()->CallEvent("onEnterExitModShop", EventReturnHandler::None, &player, enterexit, interiorID); 65 | } 66 | 67 | void onVehicleSpawn(IVehicle& vehicle) override 68 | { 69 | ComponentManager::Get()->CallEvent("onVehicleSpawn", EventReturnHandler::None, &vehicle); 70 | } 71 | 72 | bool onUnoccupiedVehicleUpdate(IVehicle& vehicle, IPlayer& player, const UnoccupiedVehicleUpdate updateData) override 73 | { 74 | return ComponentManager::Get()->CallEvent("onUnoccupiedVehicleUpdate", EventReturnHandler::StopAtFalse, &vehicle, &player, int(updateData.seat), 75 | updateData.position.x, updateData.position.y, updateData.position.z, 76 | updateData.velocity.x, updateData.velocity.y, updateData.velocity.z); 77 | } 78 | 79 | bool onTrailerUpdate(IPlayer& player, IVehicle& trailer) override 80 | { 81 | return ComponentManager::Get()->CallEvent("onTrailerUpdate", EventReturnHandler::StopAtFalse, &player, &trailer); 82 | } 83 | 84 | bool onVehicleSirenStateChange(IPlayer& player, IVehicle& vehicle, uint8_t sirenState) override 85 | { 86 | return ComponentManager::Get()->CallEvent("onVehicleSirenStateChange", EventReturnHandler::StopAtFalse, &player, &vehicle, int(sirenState)); 87 | } 88 | }; 89 | -------------------------------------------------------------------------------- /src/Impl/Classes/APIs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #include "../ComponentManager.hpp" 10 | 11 | OMP_CAPI(Class_Add, objectPtr(uint8_t team, int skin, float x, float y, float z, float angle, uint8_t weapon1, uint32_t ammo1, uint8_t weapon2, uint32_t ammo2, uint8_t weapon3, uint32_t ammo3, int* id)) 12 | { 13 | IClassesComponent* component = ComponentManager::Get()->classes; 14 | if (component) 15 | { 16 | 17 | WeaponSlots slots = { 18 | WeaponSlotData { weapon1, ammo1 }, 19 | WeaponSlotData { weapon2, ammo2 }, 20 | WeaponSlotData { weapon3, ammo3 } 21 | }; 22 | 23 | IClass* class_ = component->create(skin, team, { x, y, z }, angle, slots); 24 | 25 | if (class_) 26 | { 27 | *id = class_->getID(); 28 | return class_; 29 | } 30 | } 31 | 32 | return nullptr; 33 | } 34 | 35 | OMP_CAPI(Class_FromID, objectPtr(int classid)) 36 | { 37 | IClassesComponent* component = ComponentManager::Get()->classes; 38 | if (component) 39 | { 40 | return component->get(classid); 41 | } 42 | return nullptr; 43 | } 44 | 45 | OMP_CAPI(Class_GetID, int(objectPtr cls)) 46 | { 47 | POOL_ENTITY_RET(classes, IClass, cls, class_, 0xFFFF); 48 | return class_->getID(); 49 | } 50 | 51 | OMP_CAPI(Player_SetSpawnInfo, bool(objectPtr player, uint8_t team, int skin, float x, float y, float z, float angle, uint8_t weapon1, uint32_t ammo1, uint8_t weapon2, uint32_t ammo2, uint8_t weapon3, uint32_t ammo3)) 52 | { 53 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 54 | IPlayerClassData* classData = queryExtension(player_); 55 | if (classData) 56 | { 57 | WeaponSlots slots = { 58 | WeaponSlotData { weapon1, ammo1 }, 59 | WeaponSlotData { weapon2, ammo2 }, 60 | WeaponSlotData { weapon3, ammo3 } 61 | }; 62 | 63 | classData->setSpawnInfo(PlayerClass(skin, team, { x, y, z }, angle, slots)); 64 | return true; 65 | } 66 | return false; 67 | } 68 | 69 | OMP_CAPI(Player_GetSpawnInfo, bool(objectPtr player, uint8_t* team, int* skin, float* x, float* y, float* z, float* angle, uint8_t* weapon1, uint32_t* ammo1, uint8_t* weapon2, uint32_t* ammo2, uint8_t* weapon3, uint32_t* ammo3)) 70 | { 71 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 72 | IPlayerClassData* playerData = queryExtension(player_); 73 | if (playerData) 74 | { 75 | const PlayerClass& data = playerData->getClass(); 76 | *team = uint8_t(data.team); 77 | *skin = data.skin; 78 | *x = data.spawn.x; 79 | *y = data.spawn.y; 80 | *z = data.spawn.z; 81 | *angle = data.angle; 82 | *weapon1 = data.weapons[0].id; 83 | *ammo1 = data.weapons[0].ammo; 84 | *weapon2 = data.weapons[1].id; 85 | *ammo2 = data.weapons[1].ammo; 86 | *weapon3 = data.weapons[2].id; 87 | *ammo3 = data.weapons[2].ammo; 88 | return true; 89 | } 90 | return false; 91 | } 92 | 93 | OMP_CAPI(Class_Count, int()) 94 | { 95 | IClassesComponent* component = ComponentManager::Get()->classes; 96 | if (component) 97 | { 98 | int count = component->count(); 99 | return count; 100 | } 101 | return 0; 102 | } 103 | 104 | OMP_CAPI(Class_GetData, bool(objectPtr classptr, uint8_t* teamid, int* skin, float* x, float* y, float* z, float* angle, uint8_t* weapon1, uint32_t* weapon1_ammo, uint8_t* weapon2, uint32_t* weapon2_ammo, uint8_t* weapon3, uint32_t* weapon3_ammo)) 105 | { 106 | POOL_ENTITY_RET(classes, IClass, classptr, class_, false); 107 | const PlayerClass& data = class_->getClass(); 108 | *teamid = uint8_t(data.team); 109 | *skin = data.skin; 110 | *x = data.spawn.x; 111 | *y = data.spawn.y; 112 | *z = data.spawn.z; 113 | *angle = data.angle; 114 | *weapon1 = data.weapons[0].id; 115 | *weapon1_ammo = data.weapons[0].ammo; 116 | *weapon2 = data.weapons[1].id; 117 | *weapon2_ammo = data.weapons[1].ammo; 118 | *weapon3 = data.weapons[2].id; 119 | *weapon3_ammo = data.weapons[2].ammo; 120 | return true; 121 | } 122 | 123 | OMP_CAPI(Class_Edit, bool(objectPtr classptr, uint8_t teamid, int skin, float x, float y, float z, float angle, uint8_t weapon1, uint32_t ammo1, uint8_t weapon2, uint32_t ammo2, uint8_t weapon3, uint32_t ammo3)) 124 | { 125 | POOL_ENTITY_RET(classes, IClass, classptr, class_, false); 126 | WeaponSlots weapons; 127 | weapons[0].id = weapon1; 128 | weapons[0].ammo = ammo1; 129 | weapons[1].id = weapon2; 130 | weapons[1].ammo = ammo2; 131 | weapons[2].id = weapon3; 132 | weapons[2].ammo = ammo3; 133 | PlayerClass data = PlayerClass(skin, teamid, { x, y, z }, angle, weapons); 134 | class_->setClass(data); 135 | return true; 136 | } 137 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: WebKit 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: DontAlign 6 | AlignConsecutiveMacros: false 7 | AlignConsecutiveAssignments: false 8 | AlignConsecutiveBitFields: false 9 | AlignConsecutiveDeclarations: false 10 | AlignEscapedNewlines: Right 11 | AlignOperands: DontAlign 12 | AlignTrailingComments: false 13 | AllowAllArgumentsOnNextLine: true 14 | AllowAllConstructorInitializersOnNextLine: true 15 | AllowAllParametersOfDeclarationOnNextLine: true 16 | AllowShortEnumsOnASingleLine: true 17 | AllowShortBlocksOnASingleLine: Empty 18 | AllowShortCaseLabelsOnASingleLine: false 19 | AllowShortFunctionsOnASingleLine: All 20 | AllowShortLambdasOnASingleLine: None 21 | AllowShortIfStatementsOnASingleLine: Never 22 | AllowShortLoopsOnASingleLine: false 23 | AlwaysBreakAfterDefinitionReturnType: None 24 | AlwaysBreakAfterReturnType: None 25 | AlwaysBreakBeforeMultilineStrings: false 26 | AlwaysBreakTemplateDeclarations: MultiLine 27 | BinPackArguments: true 28 | BinPackParameters: true 29 | BraceWrapping: 30 | AfterCaseLabel: false 31 | AfterClass: false 32 | AfterControlStatement: Never 33 | AfterEnum: false 34 | AfterFunction: true 35 | AfterNamespace: false 36 | AfterObjCDeclaration: false 37 | AfterStruct: false 38 | AfterUnion: false 39 | AfterExternBlock: false 40 | BeforeCatch: false 41 | BeforeElse: false 42 | BeforeLambdaBody: false 43 | BeforeWhile: false 44 | IndentBraces: false 45 | SplitEmptyFunction: true 46 | SplitEmptyRecord: true 47 | SplitEmptyNamespace: true 48 | BreakBeforeBinaryOperators: All 49 | BreakBeforeBraces: Allman 50 | BreakBeforeInheritanceComma: false 51 | BreakInheritanceList: BeforeColon 52 | BreakBeforeTernaryOperators: true 53 | BreakConstructorInitializersBeforeComma: false 54 | BreakConstructorInitializers: BeforeComma 55 | BreakAfterJavaFieldAnnotations: false 56 | BreakStringLiterals: true 57 | ColumnLimit: 0 58 | CommentPragmas: '^ IWYU pragma:' 59 | CompactNamespaces: false 60 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 61 | ConstructorInitializerIndentWidth: 4 62 | ContinuationIndentWidth: 4 63 | Cpp11BracedListStyle: false 64 | DeriveLineEnding: true 65 | DerivePointerAlignment: false 66 | DisableFormat: false 67 | ExperimentalAutoDetectBinPacking: false 68 | FixNamespaceComments: false 69 | ForEachMacros: 70 | - foreach 71 | - Q_FOREACH 72 | - BOOST_FOREACH 73 | IncludeBlocks: Preserve 74 | IncludeCategories: 75 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 76 | Priority: 2 77 | SortPriority: 0 78 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 79 | Priority: 3 80 | SortPriority: 0 81 | - Regex: '.*' 82 | Priority: 1 83 | SortPriority: 0 84 | IncludeIsMainRegex: '(Test)?$' 85 | IncludeIsMainSourceRegex: '' 86 | IndentCaseLabels: false 87 | IndentCaseBlocks: false 88 | IndentGotoLabels: false 89 | IndentPPDirectives: None 90 | IndentExternBlock: AfterExternBlock 91 | IndentWidth: 4 92 | IndentWrappedFunctionNames: false 93 | InsertTrailingCommas: None 94 | JavaScriptQuotes: Leave 95 | JavaScriptWrapImports: true 96 | KeepEmptyLinesAtTheStartOfBlocks: true 97 | MacroBlockBegin: '' 98 | MacroBlockEnd: '' 99 | MaxEmptyLinesToKeep: 1 100 | NamespaceIndentation: Inner 101 | ObjCBinPackProtocolList: Auto 102 | ObjCBlockIndentWidth: 4 103 | ObjCBreakBeforeNestedBlockParam: true 104 | ObjCSpaceAfterProperty: true 105 | ObjCSpaceBeforeProtocolList: true 106 | PenaltyBreakAssignment: 2 107 | PenaltyBreakBeforeFirstCallParameter: 19 108 | PenaltyBreakComment: 300 109 | PenaltyBreakFirstLessLess: 120 110 | PenaltyBreakString: 1000 111 | PenaltyBreakTemplateDeclaration: 10 112 | PenaltyExcessCharacter: 1000000 113 | PenaltyReturnTypeOnItsOwnLine: 60 114 | PointerAlignment: Left 115 | ReflowComments: true 116 | SortIncludes: false 117 | SortUsingDeclarations: true 118 | SpaceAfterCStyleCast: false 119 | SpaceAfterLogicalNot: false 120 | SpaceAfterTemplateKeyword: true 121 | SpaceBeforeAssignmentOperators: true 122 | SpaceBeforeCpp11BracedList: true 123 | SpaceBeforeCtorInitializerColon: true 124 | SpaceBeforeInheritanceColon: true 125 | SpaceBeforeParens: ControlStatements 126 | SpaceBeforeRangeBasedForLoopColon: true 127 | SpaceInEmptyBlock: true 128 | SpaceInEmptyParentheses: false 129 | SpacesBeforeTrailingComments: 1 130 | SpacesInAngles: false 131 | SpacesInConditionalStatement: false 132 | SpacesInContainerLiterals: true 133 | SpacesInCStyleCastParentheses: false 134 | SpacesInParentheses: false 135 | SpacesInSquareBrackets: false 136 | SpaceBeforeSquareBrackets: false 137 | Standard: Latest 138 | StatementMacros: 139 | - Q_UNUSED 140 | - QT_REQUIRE_VERSION 141 | TabWidth: 4 142 | UseCRLF: false 143 | UseTab: true 144 | WhitespaceSensitiveMacros: 145 | - STRINGIZE 146 | - PP_STRINGIZE 147 | - BOOST_PP_STRINGIZE 148 | ... 149 | 150 | -------------------------------------------------------------------------------- /src/Impl/Config/APIs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #include "../ComponentManager.hpp" 10 | 11 | int getConfigOptionAsInt(const Impl::String& cvar) 12 | { 13 | IConfig* config = &ComponentManager::Get()->core->getConfig(); 14 | auto res = config->getNameFromAlias(cvar); 15 | bool* v0 = nullptr; 16 | int* v1 = nullptr; 17 | if (!res.second.empty()) 18 | { 19 | if (res.first) 20 | { 21 | ComponentManager::Get()->core->logLn(LogLevel::Warning, "Deprecated console variable \"%s\", use \"%.*s\" instead.", cvar.c_str(), PRINT_VIEW(res.second)); 22 | } 23 | if (!(v1 = config->getInt(res.second))) 24 | { 25 | v0 = config->getBool(res.second); 26 | } 27 | } 28 | else 29 | { 30 | if (!(v1 = config->getInt(cvar))) 31 | { 32 | v0 = config->getBool(cvar); 33 | } 34 | } 35 | if (v1) 36 | { 37 | return *v1; 38 | } 39 | else if (v0) 40 | { 41 | ComponentManager::Get()->core->logLn(LogLevel::Warning, "Boolean console variable \"%s\" retreived as integer.", cvar.c_str()); 42 | return *v0; 43 | } 44 | else 45 | { 46 | return 0; 47 | } 48 | } 49 | 50 | bool getConfigOptionAsBool(const Impl::String& cvar) 51 | { 52 | IConfig* config = &ComponentManager::Get()->core->getConfig(); 53 | auto res = config->getNameFromAlias(cvar); 54 | bool* v0 = nullptr; 55 | int* v1 = nullptr; 56 | if (!res.second.empty()) 57 | { 58 | if (res.first) 59 | { 60 | ComponentManager::Get()->core->logLn(LogLevel::Warning, "Deprecated console variable \"%s\", use \"%.*s\" instead.", cvar.c_str(), PRINT_VIEW(res.second)); 61 | } 62 | if (!(v0 = config->getBool(res.second))) 63 | { 64 | v1 = config->getInt(res.second); 65 | } 66 | } 67 | else 68 | { 69 | if (!(v0 = config->getBool(cvar))) 70 | { 71 | v1 = config->getInt(cvar); 72 | } 73 | } 74 | if (v0) 75 | { 76 | return *v0; 77 | } 78 | else if (v1) 79 | { 80 | ComponentManager::Get()->core->logLn(LogLevel::Warning, "Integer console variable \"%s\" retreived as boolean.", cvar.c_str()); 81 | return *v1 != 0; 82 | } 83 | else 84 | { 85 | return false; 86 | } 87 | } 88 | 89 | float getConfigOptionAsFloat(const Impl::String& cvar) 90 | { 91 | IConfig* config = &ComponentManager::Get()->core->getConfig(); 92 | auto res = config->getNameFromAlias(cvar); 93 | float* var = nullptr; 94 | if (!res.second.empty()) 95 | { 96 | if (res.first) 97 | { 98 | ComponentManager::Get()->core->logLn(LogLevel::Warning, "Deprecated console variable \"%s\", use \"%.*s\" instead.", cvar.c_str(), PRINT_VIEW(res.second)); 99 | } 100 | var = config->getFloat(res.second); 101 | } 102 | else 103 | { 104 | var = config->getFloat(cvar); 105 | } 106 | if (var) 107 | { 108 | return *var; 109 | } 110 | else 111 | { 112 | return 0.0f; 113 | } 114 | } 115 | 116 | int getConfigOptionAsString(const Impl::String& cvar, Impl::String& buffer) 117 | { 118 | // Special case, converting `gamemode0` to `pawn.main_scripts[0]`. It is the only string to 119 | // array change. 120 | IConfig* config = &ComponentManager::Get()->core->getConfig(); 121 | bool gm = cvar.substr(0, 8) == "gamemode"; 122 | auto res = config->getNameFromAlias(gm ? "gamemode" : cvar); 123 | if (!res.second.empty()) 124 | { 125 | if (res.first) 126 | { 127 | ComponentManager::Get()->core->logLn(LogLevel::Warning, "Deprecated console variable \"%s\", use \"%.*s\" instead.", cvar.c_str(), PRINT_VIEW(res.second)); 128 | } 129 | if (gm) 130 | { 131 | size_t i = std::stoi("0" + cvar.substr(8)); 132 | Impl::DynamicArray mainScripts(i + 1); 133 | size_t n = config->getStrings(res.second, Span(mainScripts.data(), mainScripts.size())); 134 | if (i < n) 135 | { 136 | buffer = mainScripts[i].data(); 137 | } 138 | } 139 | else 140 | { 141 | buffer = config->getString(res.second).data(); 142 | } 143 | } 144 | else 145 | { 146 | buffer = config->getString(cvar).data(); 147 | } 148 | return buffer.length(); 149 | } 150 | 151 | OMP_CAPI(Config_GetAsBool, bool(StringCharPtr cvar)) 152 | { 153 | bool value = getConfigOptionAsBool(cvar); 154 | return value; 155 | } 156 | 157 | OMP_CAPI(Config_GetAsInt, int(StringCharPtr cvar)) 158 | { 159 | int value = getConfigOptionAsInt(cvar); 160 | return value; 161 | } 162 | 163 | OMP_CAPI(Config_GetAsFloat, float(StringCharPtr cvar)) 164 | { 165 | float value = getConfigOptionAsFloat(cvar); 166 | return value; 167 | } 168 | 169 | OMP_CAPI(Config_GetAsString, int(StringCharPtr cvar, OutputStringViewPtr output)) 170 | { 171 | Impl::String value = Impl::String(); 172 | int len = getConfigOptionAsString(cvar, value); 173 | COPY_STRING_TO_CAPI_STRING_VIEW(output, value.data(), len); 174 | return len; 175 | } 176 | -------------------------------------------------------------------------------- /src/Impl/Menus/APIs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #include "../ComponentManager.hpp" 10 | 11 | OMP_CAPI(Menu_Create, objectPtr(StringCharPtr title, uint32_t columns, float x, float y, float column1Width, float column2Width, int* id)) 12 | { 13 | IMenusComponent* component = ComponentManager::Get()->menus; 14 | if (component) 15 | { 16 | IMenu* menu = component->create(title, { x, y }, uint8_t(columns), column1Width, column2Width); 17 | if (menu) 18 | { 19 | *id = menu->getID(); 20 | return menu; 21 | } 22 | } 23 | return nullptr; 24 | } 25 | 26 | OMP_CAPI(Menu_Destroy, bool(objectPtr menu)) 27 | { 28 | POOL_ENTITY_RET(menus, IMenu, menu, menu_, false); 29 | ComponentManager::Get()->menus->release(menu_->getID()); 30 | return true; 31 | } 32 | 33 | OMP_CAPI(Menu_FromID, objectPtr(int menuid)) 34 | { 35 | IMenusComponent* component = ComponentManager::Get()->menus; 36 | if (component) 37 | { 38 | return component->get(menuid); 39 | } 40 | return nullptr; 41 | } 42 | 43 | OMP_CAPI(Menu_GetID, int(objectPtr menu)) 44 | { 45 | POOL_ENTITY_RET(menus, IMenu, menu, menu_, INVALID_MENU_ID); 46 | return menu_->getID(); 47 | } 48 | 49 | OMP_CAPI(Menu_AddItem, int(objectPtr menu, uint8_t column, StringCharPtr text)) 50 | { 51 | POOL_ENTITY_RET(menus, IMenu, menu, menu_, INVALID_MENU_ID); 52 | auto index = menu_->addCell(text, column); 53 | return index; 54 | } 55 | 56 | OMP_CAPI(Menu_SetColumnHeader, bool(objectPtr menu, uint8_t column, StringCharPtr headerTitle)) 57 | { 58 | POOL_ENTITY_RET(menus, IMenu, menu, menu_, false); 59 | menu_->setColumnHeader(headerTitle, column); 60 | return true; 61 | } 62 | 63 | OMP_CAPI(Menu_ShowForPlayer, bool(objectPtr menu, objectPtr player)) 64 | { 65 | POOL_ENTITY_RET(menus, IMenu, menu, menu_, false); 66 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 67 | menu_->showForPlayer(*player_); 68 | return true; 69 | } 70 | 71 | OMP_CAPI(Menu_HideForPlayer, bool(objectPtr menu, objectPtr player)) 72 | { 73 | POOL_ENTITY_RET(menus, IMenu, menu, menu_, false); 74 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 75 | menu_->hideForPlayer(*player_); 76 | return true; 77 | } 78 | 79 | OMP_CAPI(Menu_Disable, bool(objectPtr menu)) 80 | { 81 | POOL_ENTITY_RET(menus, IMenu, menu, menu_, false); 82 | menu_->disable(); 83 | return true; 84 | } 85 | 86 | OMP_CAPI(Menu_DisableRow, bool(objectPtr menu, uint8_t row)) 87 | { 88 | POOL_ENTITY_RET(menus, IMenu, menu, menu_, false); 89 | menu_->disableRow(row); 90 | return true; 91 | } 92 | 93 | OMP_CAPI(Player_GetMenu, objectPtr(objectPtr player)) 94 | { 95 | IMenusComponent* component = ComponentManager::Get()->menus; 96 | if (component) 97 | { 98 | POOL_ENTITY_RET(players, IPlayer, player, player_, nullptr); 99 | IPlayerMenuData* menuData = queryExtension(player_); 100 | if (menuData) 101 | { 102 | return component->get(menuData->getMenuID()); 103 | } 104 | } 105 | return nullptr; 106 | } 107 | 108 | OMP_CAPI(Menu_IsValid, bool(objectPtr menu)) 109 | { 110 | POOL_ENTITY_RET(menus, IMenu, menu, menu_, false); 111 | if (!menus->get(menu_->getID())) 112 | return false; 113 | return true; 114 | } 115 | 116 | OMP_CAPI(Menu_IsDisabled, bool(objectPtr menu)) 117 | { 118 | POOL_ENTITY_RET(menus, IMenu, menu, menu_, false); 119 | auto disabled = !menu_->isEnabled(); 120 | return disabled; 121 | } 122 | 123 | OMP_CAPI(Menu_IsRowDisabled, bool(objectPtr menu, int row)) 124 | { 125 | POOL_ENTITY_RET(menus, IMenu, menu, menu_, false); 126 | auto disabled = !menu_->isRowEnabled(MenuRow(row)); 127 | return disabled; 128 | } 129 | 130 | OMP_CAPI(Menu_GetColumns, int(objectPtr menu)) 131 | { 132 | POOL_ENTITY_RET(menus, IMenu, menu, menu_, 0); 133 | auto columns = menu_->getColumnCount(); 134 | return columns; 135 | } 136 | 137 | OMP_CAPI(Menu_GetItems, int(objectPtr menu, int column)) 138 | { 139 | POOL_ENTITY_RET(menus, IMenu, menu, menu_, 0); 140 | auto rows = menu_->getRowCount(MenuColumn(column)); 141 | return rows; 142 | } 143 | 144 | OMP_CAPI(Menu_GetPos, bool(objectPtr menu, float* x, float* y)) 145 | { 146 | POOL_ENTITY_RET(menus, IMenu, menu, menu_, false); 147 | auto pos = menu_->getPosition(); 148 | *x = pos.x; 149 | *y = pos.y; 150 | return true; 151 | } 152 | 153 | OMP_CAPI(Menu_GetColumnWidth, bool(objectPtr menu, float* column1Width, float* column2Width)) 154 | { 155 | POOL_ENTITY_RET(menus, IMenu, menu, menu_, false); 156 | auto widths = menu_->getColumnWidths(); 157 | *column1Width = widths.x; 158 | *column2Width = widths.y; 159 | return true; 160 | } 161 | 162 | OMP_CAPI(Menu_GetColumnHeader, bool(objectPtr menu, int column, OutputStringViewPtr header)) 163 | { 164 | POOL_ENTITY_RET(menus, IMenu, menu, menu_, false); 165 | auto result = menu_->getColumnHeader(MenuColumn(column)); 166 | SET_CAPI_STRING_VIEW(header, result); 167 | return true; 168 | } 169 | 170 | OMP_CAPI(Menu_GetItem, bool(objectPtr menu, int column, int row, OutputStringViewPtr item)) 171 | { 172 | POOL_ENTITY_RET(menus, IMenu, menu, menu_, false); 173 | auto result = menu_->getCell(MenuColumn(column), MenuRow(row)); 174 | SET_CAPI_STRING_VIEW(item, result); 175 | return true; 176 | } 177 | -------------------------------------------------------------------------------- /src/Impl/Pickups/APIs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #include "../ComponentManager.hpp" 10 | 11 | OMP_CAPI(Pickup_Create, objectPtr(int model, int type, float x, float y, float z, int virtualWorld, int* id)) 12 | { 13 | IPickupsComponent* component = ComponentManager::Get()->pickups; 14 | if (component) 15 | { 16 | int id_ = component->reserveLegacyID(); 17 | if (id_ == INVALID_PICKUP_ID) 18 | { 19 | return nullptr; 20 | } 21 | 22 | IPickup* pickup = component->create(model, PickupType(type), { x, y, z }, virtualWorld, false); 23 | if (pickup) 24 | { 25 | component->setLegacyID(id_, pickup->getID()); 26 | *id = id_; 27 | return pickup; 28 | } 29 | else 30 | { 31 | component->releaseLegacyID(id_); 32 | } 33 | } 34 | return nullptr; 35 | } 36 | 37 | OMP_CAPI(Pickup_AddStatic, bool(int model, int type, float x, float y, float z, int virtualWorld)) 38 | { 39 | IPickupsComponent* component = ComponentManager::Get()->pickups; 40 | if (component) 41 | { 42 | int id_ = component->reserveLegacyID(); 43 | if (id_ == INVALID_PICKUP_ID) 44 | { 45 | return false; 46 | } 47 | 48 | IPickup* pickup = component->create(model, PickupType(type), { x, y, z }, virtualWorld, true); 49 | if (pickup) 50 | { 51 | component->setLegacyID(id_, pickup->getID()); 52 | return true; 53 | } 54 | else 55 | { 56 | component->releaseLegacyID(id_); 57 | } 58 | } 59 | return false; 60 | } 61 | 62 | OMP_CAPI(Pickup_Destroy, bool(objectPtr pickup)) 63 | { 64 | POOL_ENTITY_RET(pickups, IPickup, pickup, p, false); 65 | pickups->release(p->getID()); 66 | pickups->releaseLegacyID(pickups->toLegacyID(p->getID())); 67 | return true; 68 | } 69 | 70 | OMP_CAPI(Pickup_FromID, objectPtr(int pickupid)) 71 | { 72 | IPickupsComponent* component = ComponentManager::Get()->pickups; 73 | if (component) 74 | { 75 | return component->get(pickupid); 76 | } 77 | return nullptr; 78 | } 79 | 80 | OMP_CAPI(Pickup_GetID, int(objectPtr pickup)) 81 | { 82 | POOL_ENTITY_RET(pickups, IPickup, pickup, pickup_, INVALID_PICKUP_ID); 83 | return pickup_->getID(); 84 | } 85 | 86 | OMP_CAPI(Pickup_IsValid, bool(objectPtr pickup)) 87 | { 88 | POOL_ENTITY_RET(pickups, IPickup, pickup, p, false); 89 | if (!pickups->get(p->getID())) 90 | return false; 91 | return true; 92 | } 93 | 94 | OMP_CAPI(Pickup_IsStreamedIn, bool(objectPtr player, objectPtr pickup)) 95 | { 96 | POOL_ENTITY_RET(pickups, IPickup, pickup, p, false); 97 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 98 | return p->isStreamedInForPlayer(*player_); 99 | } 100 | 101 | OMP_CAPI(Pickup_GetPos, bool(objectPtr pickup, float* x, float* y, float* z)) 102 | { 103 | POOL_ENTITY_RET(pickups, IPickup, pickup, p, false); 104 | auto pos = p->getPosition(); 105 | *x = pos.x; 106 | *y = pos.y; 107 | *z = pos.z; 108 | return true; 109 | } 110 | 111 | OMP_CAPI(Pickup_GetModel, int(objectPtr pickup)) 112 | { 113 | POOL_ENTITY_RET(pickups, IPickup, pickup, p, 0); 114 | return p->getModel(); 115 | } 116 | 117 | OMP_CAPI(Pickup_GetType, int(objectPtr pickup)) 118 | { 119 | POOL_ENTITY_RET(pickups, IPickup, pickup, p, -1); 120 | return p->getType(); 121 | } 122 | 123 | OMP_CAPI(Pickup_GetVirtualWorld, int(objectPtr pickup)) 124 | { 125 | POOL_ENTITY_RET(pickups, IPickup, pickup, p, 0); 126 | return p->getVirtualWorld(); 127 | } 128 | 129 | OMP_CAPI(Pickup_SetPos, bool(objectPtr pickup, float x, float y, float z, bool update)) 130 | { 131 | POOL_ENTITY_RET(pickups, IPickup, pickup, p, false); 132 | if (update) 133 | { 134 | p->setPosition({ x, y, z }); 135 | } 136 | else 137 | { 138 | p->setPositionNoUpdate({ x, y, z }); 139 | } 140 | return true; 141 | } 142 | 143 | OMP_CAPI(Pickup_SetModel, bool(objectPtr pickup, int model, bool update)) 144 | { 145 | POOL_ENTITY_RET(pickups, IPickup, pickup, p, false); 146 | p->setModel(model, update); 147 | return true; 148 | } 149 | 150 | OMP_CAPI(Pickup_SetType, bool(objectPtr pickup, int type, bool update)) 151 | { 152 | POOL_ENTITY_RET(pickups, IPickup, pickup, p, false); 153 | p->setType(PickupType(type), update); 154 | return true; 155 | } 156 | 157 | OMP_CAPI(Pickup_SetVirtualWorld, bool(objectPtr pickup, int virtualworld)) 158 | { 159 | POOL_ENTITY_RET(pickups, IPickup, pickup, p, false); 160 | p->setVirtualWorld(virtualworld); 161 | return true; 162 | } 163 | 164 | OMP_CAPI(Pickup_ShowForPlayer, bool(objectPtr player, objectPtr pickup)) 165 | { 166 | POOL_ENTITY_RET(pickups, IPickup, pickup, p, false); 167 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 168 | p->setPickupHiddenForPlayer(*player_, false); 169 | return true; 170 | } 171 | 172 | OMP_CAPI(Pickup_HideForPlayer, bool(objectPtr player, objectPtr pickup)) 173 | { 174 | POOL_ENTITY_RET(pickups, IPickup, pickup, p, false); 175 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 176 | p->setPickupHiddenForPlayer(*player_, true); 177 | return true; 178 | } 179 | 180 | OMP_CAPI(Pickup_IsHiddenForPlayer, bool(objectPtr player, objectPtr pickup)) 181 | { 182 | POOL_ENTITY_RET(pickups, IPickup, pickup, p, false); 183 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 184 | return p->isPickupHiddenForPlayer(*player_); 185 | } 186 | -------------------------------------------------------------------------------- /src/Impl/Checkpoints/APIs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #include "../ComponentManager.hpp" 10 | 11 | OMP_CAPI(Checkpoint_Set, bool(objectPtr player, float x, float y, float z, float radius)) 12 | { 13 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 14 | IPlayerCheckpointData* playerCheckpointData = queryExtension(player_); 15 | if (playerCheckpointData) 16 | { 17 | ICheckpointData& cp = playerCheckpointData->getCheckpoint(); 18 | cp.setPosition({ x, y, z }); 19 | cp.setRadius(radius); 20 | cp.enable(); 21 | return true; 22 | } 23 | return false; 24 | } 25 | 26 | OMP_CAPI(Checkpoint_Disable, bool(objectPtr player)) 27 | { 28 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 29 | IPlayerCheckpointData* playerCheckpointData = queryExtension(player_); 30 | if (playerCheckpointData) 31 | { 32 | ICheckpointData& cp = playerCheckpointData->getCheckpoint(); 33 | cp.disable(); 34 | return true; 35 | } 36 | return false; 37 | } 38 | 39 | OMP_CAPI(Checkpoint_IsPlayerIn, bool(objectPtr player)) 40 | { 41 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 42 | IPlayerCheckpointData* playerCheckpointData = queryExtension(player_); 43 | if (playerCheckpointData) 44 | { 45 | ICheckpointData& cp = playerCheckpointData->getCheckpoint(); 46 | if (cp.isEnabled()) 47 | { 48 | bool isIn = cp.isPlayerInside(); 49 | return isIn; 50 | } 51 | } 52 | return false; 53 | } 54 | 55 | OMP_CAPI(Checkpoint_IsActive, bool(objectPtr player)) 56 | { 57 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 58 | IPlayerCheckpointData* playerData = queryExtension(player_); 59 | if (playerData) 60 | { 61 | bool active = playerData->getCheckpoint().isEnabled(); 62 | return active; 63 | } 64 | return false; 65 | } 66 | 67 | OMP_CAPI(Checkpoint_Get, bool(objectPtr player, float* x, float* y, float* z, float* radius)) 68 | { 69 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 70 | IPlayerCheckpointData* playerData = queryExtension(player_); 71 | if (playerData) 72 | { 73 | const ICheckpointData& data = playerData->getCheckpoint(); 74 | *x = data.getPosition().x; 75 | *y = data.getPosition().y; 76 | *z = data.getPosition().z; 77 | *radius = data.getRadius(); 78 | return true; 79 | } 80 | return false; 81 | } 82 | 83 | OMP_CAPI(RaceCheckpoint_Set, bool(objectPtr player, int type, float x, float y, float z, float nextX, float nextY, float nextZ, float radius)) 84 | { 85 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 86 | IPlayerCheckpointData* playerCheckpointData = queryExtension(player_); 87 | if (playerCheckpointData) 88 | { 89 | IRaceCheckpointData& cp = playerCheckpointData->getRaceCheckpoint(); 90 | if (type >= 0 && type <= 8) 91 | { 92 | cp.setType(RaceCheckpointType(type)); 93 | cp.setPosition({ x, y, z }); 94 | cp.setNextPosition({ nextX, nextY, nextZ }); 95 | cp.setRadius(radius); 96 | cp.enable(); 97 | return true; 98 | } 99 | } 100 | return false; 101 | } 102 | 103 | OMP_CAPI(RaceCheckpoint_Disable, bool(objectPtr player)) 104 | { 105 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 106 | IPlayerCheckpointData* playerCheckpointData = queryExtension(player_); 107 | if (playerCheckpointData) 108 | { 109 | IRaceCheckpointData& cp = playerCheckpointData->getRaceCheckpoint(); 110 | cp.disable(); 111 | return true; 112 | } 113 | return false; 114 | } 115 | 116 | OMP_CAPI(RaceCheckpoint_IsPlayerIn, bool(objectPtr player)) 117 | { 118 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 119 | IPlayerCheckpointData* playerCheckpointData = queryExtension(player_); 120 | if (playerCheckpointData) 121 | { 122 | IRaceCheckpointData& cp = playerCheckpointData->getRaceCheckpoint(); 123 | if (cp.getType() != RaceCheckpointType::RACE_NONE && cp.isEnabled()) 124 | { 125 | bool isIn = cp.isPlayerInside(); 126 | return isIn; 127 | } 128 | } 129 | return false; 130 | } 131 | 132 | OMP_CAPI(RaceCheckpoint_IsActive, bool(objectPtr player)) 133 | { 134 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 135 | IPlayerCheckpointData* playerData = queryExtension(player_); 136 | if (playerData) 137 | { 138 | bool active = playerData->getCheckpoint().isEnabled(); 139 | return active; 140 | } 141 | return false; 142 | } 143 | 144 | OMP_CAPI(RaceCheckpoint_Get, bool(objectPtr player, float* x, float* y, float* z, float* nextX, float* nextY, float* nextZ, float* radius)) 145 | { 146 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 147 | IPlayerCheckpointData* playerData = queryExtension(player_); 148 | if (playerData) 149 | { 150 | const IRaceCheckpointData& data = playerData->getRaceCheckpoint(); 151 | *x = data.getPosition().x; 152 | *y = data.getPosition().y; 153 | *z = data.getPosition().z; 154 | *nextX = data.getNextPosition().x; 155 | *nextY = data.getNextPosition().y; 156 | *nextZ = data.getNextPosition().z; 157 | *radius = data.getRadius(); 158 | return true; 159 | } 160 | return false; 161 | } 162 | -------------------------------------------------------------------------------- /src/Impl/Actors/APIs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #include "../ComponentManager.hpp" 10 | 11 | OMP_CAPI(Actor_Create, objectPtr(int model, float x, float y, float z, float rot, int* id)) 12 | { 13 | IActorsComponent* component = ComponentManager::Get()->actors; 14 | if (component) 15 | { 16 | IActor* actor = component->create(model, { x, y, z }, rot); 17 | if (actor) 18 | { 19 | *id = actor->getID(); 20 | return actor; 21 | } 22 | } 23 | return nullptr; 24 | } 25 | 26 | OMP_CAPI(Actor_Destroy, bool(objectPtr actor)) 27 | { 28 | POOL_ENTITY_RET(actors, IActor, actor, actor_, false); 29 | actors->release(actor_->getID()); 30 | return true; 31 | } 32 | 33 | OMP_CAPI(Actor_FromID, objectPtr(int actorid)) 34 | { 35 | IActorsComponent* component = ComponentManager::Get()->actors; 36 | if (component) 37 | { 38 | return component->get(actorid); 39 | } 40 | return nullptr; 41 | } 42 | 43 | OMP_CAPI(Actor_GetID, int(objectPtr actor)) 44 | { 45 | POOL_ENTITY_RET(actors, IActor, actor, actor_, INVALID_ACTOR_ID); 46 | return actor_->getID(); 47 | } 48 | 49 | OMP_CAPI(Actor_IsStreamedInFor, bool(objectPtr actor, objectPtr player)) 50 | { 51 | POOL_ENTITY_RET(actors, IActor, actor, actor_, false); 52 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 53 | return actor_->isStreamedInForPlayer(*player_); 54 | } 55 | 56 | OMP_CAPI(Actor_SetVirtualWorld, bool(objectPtr actor, int vw)) 57 | { 58 | POOL_ENTITY_RET(actors, IActor, actor, actor_, false); 59 | actor_->setVirtualWorld(vw); 60 | return true; 61 | } 62 | 63 | OMP_CAPI(Actor_GetVirtualWorld, int(objectPtr actor)) 64 | { 65 | POOL_ENTITY_RET(actors, IActor, actor, actor_, 0); 66 | return actor_->getVirtualWorld(); 67 | } 68 | 69 | OMP_CAPI(Actor_ApplyAnimation, bool(objectPtr actor, StringCharPtr name, StringCharPtr library, float delta, bool loop, bool lockX, bool lockY, bool freeze, int time)) 70 | { 71 | POOL_ENTITY_RET(actors, IActor, actor, actor_, false); 72 | const AnimationData animationData(delta, loop, lockX, lockY, freeze, uint32_t(time), library, name); 73 | actor_->applyAnimation(animationData); 74 | return true; 75 | } 76 | 77 | OMP_CAPI(Actor_ClearAnimations, bool(objectPtr actor)) 78 | { 79 | POOL_ENTITY_RET(actors, IActor, actor, actor_, false); 80 | actor_->clearAnimations(); 81 | return true; 82 | } 83 | 84 | OMP_CAPI(Actor_SetPos, bool(objectPtr actor, float x, float y, float z)) 85 | { 86 | POOL_ENTITY_RET(actors, IActor, actor, actor_, false); 87 | actor_->setPosition({ x, y, z }); 88 | return true; 89 | } 90 | 91 | OMP_CAPI(Actor_GetPos, bool(objectPtr actor, float* x, float* y, float* z)) 92 | { 93 | POOL_ENTITY_RET(actors, IActor, actor, actor_, false); 94 | const Vector3& pos = actor_->getPosition(); 95 | 96 | *x = pos.x; 97 | *y = pos.y; 98 | *z = pos.z; 99 | return true; 100 | } 101 | 102 | OMP_CAPI(Actor_SetFacingAngle, bool(objectPtr actor, float angle)) 103 | { 104 | POOL_ENTITY_RET(actors, IActor, actor, actor_, false); 105 | actor_->setRotation(Vector3(0.0f, 0.0f, angle)); 106 | return true; 107 | } 108 | 109 | OMP_CAPI(Actor_GetFacingAngle, float(objectPtr actor)) 110 | { 111 | POOL_ENTITY_RET(actors, IActor, actor, actor_, 0.0f); 112 | return actor_->getRotation().ToEuler().z; 113 | } 114 | 115 | OMP_CAPI(Actor_SetHealth, bool(objectPtr actor, float hp)) 116 | { 117 | POOL_ENTITY_RET(actors, IActor, actor, actor_, false); 118 | actor_->setHealth(hp); 119 | return true; 120 | } 121 | 122 | OMP_CAPI(Actor_GetHealth, float(objectPtr actor)) 123 | { 124 | POOL_ENTITY_RET(actors, IActor, actor, actor_, 0.0f); 125 | return actor_->getHealth(); 126 | } 127 | 128 | OMP_CAPI(Actor_SetInvulnerable, bool(objectPtr actor, bool toggle)) 129 | { 130 | POOL_ENTITY_RET(actors, IActor, actor, actor_, false); 131 | actor_->setInvulnerable(toggle); 132 | return true; 133 | } 134 | 135 | OMP_CAPI(Actor_IsInvulnerable, bool(objectPtr actor)) 136 | { 137 | POOL_ENTITY_RET(actors, IActor, actor, actor_, false); 138 | return actor_->isInvulnerable(); 139 | } 140 | 141 | OMP_CAPI(Actor_IsValid, bool(objectPtr actor)) 142 | { 143 | POOL_ENTITY_RET(actors, IActor, actor, actor_, false); 144 | if (!actors->get(actor_->getID())) 145 | return false; 146 | return true; 147 | } 148 | 149 | OMP_CAPI(Actor_SetSkin, bool(objectPtr actor, int skin)) 150 | { 151 | POOL_ENTITY_RET(actors, IActor, actor, actor_, false); 152 | actor_->setSkin(skin); 153 | return true; 154 | } 155 | 156 | OMP_CAPI(Actor_GetSkin, int(objectPtr actor)) 157 | { 158 | POOL_ENTITY_RET(actors, IActor, actor, actor_, 0); 159 | return actor_->getSkin(); 160 | } 161 | 162 | OMP_CAPI(Actor_GetAnimation, bool(objectPtr actor, OutputStringViewPtr library, OutputStringViewPtr name, float* delta, bool* loop, bool* lockX, bool* lockY, bool* freeze, int* time)) 163 | { 164 | POOL_ENTITY_RET(actors, IActor, actor, actor_, false); 165 | const AnimationData& anim = actor_->getAnimation(); 166 | 167 | SET_CAPI_STRING_VIEW(library, anim.lib); 168 | SET_CAPI_STRING_VIEW(name, anim.name); 169 | *delta = anim.delta; 170 | *loop = anim.loop; 171 | *lockX = anim.lockX; 172 | *lockY = anim.lockY; 173 | *freeze = anim.freeze; 174 | *time = int(anim.time); 175 | return true; 176 | } 177 | 178 | OMP_CAPI(Actor_GetSpawnInfo, bool(objectPtr actor, float* x, float* y, float* z, float* angle, int* skin)) 179 | { 180 | POOL_ENTITY_RET(actors, IActor, actor, actor_, false); 181 | const ActorSpawnData& spawnData = actor_->getSpawnData(); 182 | 183 | *x = spawnData.position.x; 184 | *y = spawnData.position.y; 185 | *z = spawnData.position.z; 186 | *angle = spawnData.facingAngle; 187 | *skin = spawnData.skin; 188 | return true; 189 | } 190 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | build/ 18 | 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | 27 | # Visual Studio 2015 cache/options directory 28 | .vs/ 29 | # Uncomment if you have tasks that create the project's static files in wwwroot 30 | #wwwroot/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | # DNX 46 | project.lock.json 47 | project.fragment.lock.json 48 | artifacts/ 49 | 50 | *_i.c 51 | *_p.c 52 | *_i.h 53 | *.ilk 54 | *.meta 55 | *.obj 56 | *.pch 57 | *.pdb 58 | *.pgc 59 | *.pgd 60 | *.rsp 61 | *.sbr 62 | *.tlb 63 | *.tli 64 | *.tlh 65 | *.tmp 66 | *.tmp_proj 67 | *.log 68 | *.vspscc 69 | *.vssscc 70 | .builds 71 | *.pidb 72 | *.svclog 73 | *.scc 74 | 75 | # Chutzpah Test files 76 | _Chutzpah* 77 | 78 | # Visual C++ cache files 79 | ipch/ 80 | *.aps 81 | *.ncb 82 | *.opendb 83 | *.opensdf 84 | *.sdf 85 | *.cachefile 86 | *.VC.db 87 | *.VC.VC.opendb 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | *.sap 94 | 95 | # TFS 2012 Local Workspace 96 | $tf/ 97 | 98 | # Guidance Automation Toolkit 99 | *.gpState 100 | 101 | # ReSharper is a .NET coding add-in 102 | _ReSharper*/ 103 | *.[Rr]e[Ss]harper 104 | *.DotSettings.user 105 | 106 | # JustCode is a .NET coding add-in 107 | .JustCode 108 | 109 | # TeamCity is a build add-in 110 | _TeamCity* 111 | 112 | # DotCover is a Code Coverage Tool 113 | *.dotCover 114 | 115 | # NCrunch 116 | _NCrunch_* 117 | .*crunch*.local.xml 118 | nCrunchTemp_* 119 | 120 | # MightyMoose 121 | *.mm.* 122 | AutoTest.Net/ 123 | 124 | # Web workbench (sass) 125 | .sass-cache/ 126 | 127 | # Installshield output folder 128 | [Ee]xpress/ 129 | 130 | # DocProject is a documentation generator add-in 131 | DocProject/buildhelp/ 132 | DocProject/Help/*.HxT 133 | DocProject/Help/*.HxC 134 | DocProject/Help/*.hhc 135 | DocProject/Help/*.hhk 136 | DocProject/Help/*.hhp 137 | DocProject/Help/Html2 138 | DocProject/Help/html 139 | 140 | # Click-Once directory 141 | publish/ 142 | 143 | # Publish Web Output 144 | *.[Pp]ublish.xml 145 | *.azurePubxml 146 | # TODO: Comment the next line if you want to checkin your web deploy settings 147 | # but database connection strings (with potential passwords) will be unencrypted 148 | #*.pubxml 149 | *.publishproj 150 | 151 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 152 | # checkin your Azure Web App publish settings, but sensitive information contained 153 | # in these scripts will be unencrypted 154 | PublishScripts/ 155 | 156 | # NuGet Packages 157 | *.nupkg 158 | # The packages folder can be ignored because of Package Restore 159 | **/packages/* 160 | # except build/, which is used as an MSBuild target. 161 | !**/packages/build/ 162 | # Uncomment if necessary however generally it will be regenerated when needed 163 | #!**/packages/repositories.config 164 | # NuGet v3's project.json files produces more ignoreable files 165 | *.nuget.props 166 | *.nuget.targets 167 | 168 | # Microsoft Azure Build Output 169 | csx/ 170 | *.build.csdef 171 | 172 | # Microsoft Azure Emulator 173 | ecf/ 174 | rcf/ 175 | 176 | # Windows Store app package directories and files 177 | AppPackages/ 178 | BundleArtifacts/ 179 | Package.StoreAssociation.xml 180 | _pkginfo.txt 181 | 182 | # Visual Studio cache files 183 | # files ending in .cache can be ignored 184 | *.[Cc]ache 185 | # but keep track of directories ending in .cache 186 | !*.[Cc]ache/ 187 | 188 | # Others 189 | ClientBin/ 190 | ~$* 191 | *~ 192 | *.dbmdl 193 | *.dbproj.schemaview 194 | *.jfm 195 | *.pfx 196 | *.publishsettings 197 | node_modules/ 198 | orleans.codegen.cs 199 | 200 | # Since there are multiple workflows, uncomment next line to ignore bower_components 201 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 202 | #bower_components/ 203 | 204 | # RIA/Silverlight projects 205 | Generated_Code/ 206 | 207 | # Backup & report files from converting an old project file 208 | # to a newer Visual Studio version. Backup files are not needed, 209 | # because we have git ;-) 210 | _UpgradeReport_Files/ 211 | Backup*/ 212 | UpgradeLog*.XML 213 | UpgradeLog*.htm 214 | 215 | # SQL Server files 216 | *.mdf 217 | *.ldf 218 | 219 | # Business Intelligence projects 220 | *.rdl.data 221 | *.bim.layout 222 | *.bim_*.settings 223 | 224 | # Microsoft Fakes 225 | FakesAssemblies/ 226 | 227 | # GhostDoc plugin setting file 228 | *.GhostDoc.xml 229 | 230 | # Node.js Tools for Visual Studio 231 | .ntvs_analysis.dat 232 | 233 | # Visual Studio 6 build log 234 | *.plg 235 | 236 | # Visual Studio 6 workspace options file 237 | *.opt 238 | 239 | # Visual Studio LightSwitch build output 240 | **/*.HTMLClient/GeneratedArtifacts 241 | **/*.DesktopClient/GeneratedArtifacts 242 | **/*.DesktopClient/ModelManifest.xml 243 | **/*.Server/GeneratedArtifacts 244 | **/*.Server/ModelManifest.xml 245 | _Pvt_Extensions 246 | 247 | # Paket dependency manager 248 | .paket/paket.exe 249 | paket-files/ 250 | 251 | # FAKE - F# Make 252 | .fake/ 253 | 254 | # JetBrains Rider 255 | .idea/ 256 | *.sln.iml 257 | 258 | # CodeRush 259 | .cr/ 260 | 261 | # Python Tools for Visual Studio (PTVS) 262 | __pycache__/ 263 | *.pyc 264 | 265 | /server/src/Networking/Legacy/CMakeFiles/*.stamp 266 | *.depend 267 | *.stamp 268 | *.list 269 | *.rule 270 | *.filters 271 | *.vcxproj 272 | *.cmake 273 | *.bin 274 | /Win32-Debug 275 | /includes/fmat 276 | /includes/gmock 277 | /includes/gtest 278 | /includes/logger 279 | /includes/pawn 280 | /includes/raknet 281 | /includes/server 282 | /includes/tinydir 283 | /includes/utils 284 | *.sln 285 | *.tlog 286 | /open.mp/Win32-Debug/temp/gtest/gtest.idb 287 | /open.mp/Win32-Debug 288 | /CMakeFiles 289 | *.pc 290 | /CMakeCache.txt 291 | *.amx 292 | *.i 293 | .vscode/ -------------------------------------------------------------------------------- /src/Impl/GangZones/APIs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #include "../ComponentManager.hpp" 10 | 11 | OMP_CAPI(GangZone_Create, objectPtr(float minx, float miny, float maxx, float maxy, int* id)) 12 | { 13 | IGangZonesComponent* component = ComponentManager::Get()->gangzones; 14 | if (component) 15 | { 16 | Vector2 min = { minx, miny }; 17 | Vector2 max = { maxx, maxy }; 18 | 19 | int id_ = component->reserveLegacyID(); 20 | if (id_ == INVALID_GANG_ZONE_ID) 21 | { 22 | return nullptr; 23 | } 24 | 25 | GangZonePos pos; 26 | pos.min.x = truncf(min.x); 27 | pos.min.y = truncf(min.y); 28 | pos.max.x = truncf(max.x); 29 | pos.max.y = truncf(max.y); 30 | 31 | IGangZone* gz = component->create(pos); 32 | if (gz) 33 | { 34 | component->setLegacyID(id_, gz->getID()); 35 | *id = id_; 36 | return gz; 37 | } 38 | else 39 | { 40 | component->releaseLegacyID(id_); 41 | } 42 | } 43 | return nullptr; 44 | } 45 | 46 | OMP_CAPI(GangZone_Destroy, bool(objectPtr gangzone)) 47 | { 48 | POOL_ENTITY_RET(gangzones, IGangZone, gangzone, gz, false); 49 | gangzones->release(gz->getID()); 50 | gangzones->releaseLegacyID(gangzones->toLegacyID(gz->getID())); 51 | return true; 52 | } 53 | 54 | OMP_CAPI(GangZone_FromID, objectPtr(int gangzoneid)) 55 | { 56 | IGangZonesComponent* component = ComponentManager::Get()->gangzones; 57 | if (component) 58 | { 59 | return component->get(gangzoneid); 60 | } 61 | return nullptr; 62 | } 63 | 64 | OMP_CAPI(GangZone_GetID, int(objectPtr gangzone)) 65 | { 66 | POOL_ENTITY_RET(gangzones, IGangZone, gangzone, gangzone_, INVALID_GANG_ZONE_ID); 67 | return gangzone_->getID(); 68 | } 69 | 70 | OMP_CAPI(GangZone_ShowForPlayer, bool(objectPtr player, objectPtr gangzone, uint32_t color)) 71 | { 72 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 73 | POOL_ENTITY_RET(gangzones, IGangZone, gangzone, gz, false); 74 | gz->showForPlayer(*player_, Colour::FromRGBA(color)); 75 | return true; 76 | } 77 | 78 | OMP_CAPI(GangZone_ShowForAll, bool(objectPtr gangzone, uint32_t color)) 79 | { 80 | POOL_ENTITY_RET(gangzones, IGangZone, gangzone, gz, false); 81 | IPlayerPool* pool = ComponentManager::Get()->players; 82 | for (IPlayer* player : pool->entries()) 83 | { 84 | gz->showForPlayer(*player, Colour::FromRGBA(color)); 85 | } 86 | return true; 87 | } 88 | 89 | OMP_CAPI(GangZone_HideForPlayer, bool(objectPtr player, objectPtr gangzone)) 90 | { 91 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 92 | POOL_ENTITY_RET(gangzones, IGangZone, gangzone, gz, false); 93 | gz->hideForPlayer(*player_); 94 | return true; 95 | } 96 | 97 | OMP_CAPI(GangZone_HideForAll, bool(objectPtr gangzone)) 98 | { 99 | POOL_ENTITY_RET(gangzones, IGangZone, gangzone, gz, false); 100 | IPlayerPool* pool = ComponentManager::Get()->players; 101 | for (IPlayer* player : pool->entries()) 102 | { 103 | gz->hideForPlayer(*player); 104 | } 105 | return true; 106 | } 107 | 108 | OMP_CAPI(GangZone_FlashForPlayer, bool(objectPtr player, objectPtr gangzone, uint32_t color)) 109 | { 110 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 111 | POOL_ENTITY_RET(gangzones, IGangZone, gangzone, gz, false); 112 | gz->flashForPlayer(*player_, Colour::FromRGBA(color)); 113 | return true; 114 | } 115 | 116 | OMP_CAPI(GangZone_FlashForAll, bool(objectPtr gangzone, uint32_t color)) 117 | { 118 | POOL_ENTITY_RET(gangzones, IGangZone, gangzone, gz, false); 119 | IPlayerPool* pool = ComponentManager::Get()->players; 120 | for (IPlayer* player : pool->entries()) 121 | { 122 | gz->flashForPlayer(*player, Colour::FromRGBA(color)); 123 | } 124 | return true; 125 | } 126 | 127 | OMP_CAPI(GangZone_StopFlashForPlayer, bool(objectPtr player, objectPtr gangzone)) 128 | { 129 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 130 | POOL_ENTITY_RET(gangzones, IGangZone, gangzone, gz, false); 131 | gz->stopFlashForPlayer(*player_); 132 | return true; 133 | } 134 | 135 | OMP_CAPI(GangZone_StopFlashForAll, bool(objectPtr gangzone)) 136 | { 137 | POOL_ENTITY_RET(gangzones, IGangZone, gangzone, gz, false); 138 | IPlayerPool* pool = ComponentManager::Get()->players; 139 | for (IPlayer* player : pool->entries()) 140 | { 141 | gz->stopFlashForPlayer(*player); 142 | } 143 | return true; 144 | } 145 | 146 | OMP_CAPI(GangZone_IsValid, bool(objectPtr gangzone)) 147 | { 148 | POOL_ENTITY_RET(gangzones, IGangZone, gangzone, gz, false); 149 | if (!gangzones->get(gz->getID())) 150 | { 151 | return false; 152 | } 153 | return true; 154 | } 155 | 156 | OMP_CAPI(GangZone_IsPlayerIn, bool(objectPtr player, objectPtr gangzone)) 157 | { 158 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 159 | POOL_ENTITY_RET(gangzones, IGangZone, gangzone, gz, false); 160 | return gz->isPlayerInside(*player_); 161 | } 162 | 163 | OMP_CAPI(GangZone_IsVisibleForPlayer, bool(objectPtr player, objectPtr gangzone)) 164 | { 165 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 166 | POOL_ENTITY_RET(gangzones, IGangZone, gangzone, gz, false); 167 | return gz->isShownForPlayer(*player_); 168 | } 169 | 170 | OMP_CAPI(GangZone_GetColorForPlayer, int(objectPtr player, objectPtr gangzone)) 171 | { 172 | POOL_ENTITY_RET(players, IPlayer, player, player_, 0); 173 | POOL_ENTITY_RET(gangzones, IGangZone, gangzone, gz, 0); 174 | if (gz->isShownForPlayer(*player_)) 175 | { 176 | return gz->getColourForPlayer(*player_).RGBA(); 177 | } 178 | return 0; 179 | } 180 | 181 | OMP_CAPI(GangZone_GetFlashColorForPlayer, int(objectPtr player, objectPtr gangzone)) 182 | { 183 | POOL_ENTITY_RET(players, IPlayer, player, player_, 0); 184 | POOL_ENTITY_RET(gangzones, IGangZone, gangzone, gz, 0); 185 | if (gz->isShownForPlayer(*player_)) 186 | { 187 | return gz->getFlashingColourForPlayer(*player_).RGBA(); 188 | } 189 | return 0; 190 | } 191 | 192 | OMP_CAPI(GangZone_IsFlashingForPlayer, bool(objectPtr player, objectPtr gangzone)) 193 | { 194 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 195 | POOL_ENTITY_RET(gangzones, IGangZone, gangzone, gz, false); 196 | return gz->isFlashingForPlayer(*player_); 197 | } 198 | 199 | OMP_CAPI(GangZone_GetPos, bool(objectPtr gangzone, float* minx, float* miny, float* maxx, float* maxy)) 200 | { 201 | POOL_ENTITY_RET(gangzones, IGangZone, gangzone, gz, false); 202 | const GangZonePos& pos = gz->getPosition(); 203 | *minx = pos.min.x; 204 | *miny = pos.min.y; 205 | *maxx = pos.max.x; 206 | *maxy = pos.max.y; 207 | return true; 208 | } 209 | 210 | OMP_CAPI(GangZone_UseCheck, bool(objectPtr gangzone, bool enable)) 211 | { 212 | POOL_ENTITY_RET(gangzones, IGangZone, gangzone, gz, false); 213 | gangzones->useGangZoneCheck(*gz, enable); 214 | return true; 215 | } 216 | 217 | /* 218 | Per-Player GangZones 219 | */ 220 | -------------------------------------------------------------------------------- /src/Impl/Players/Events.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #pragma once 10 | #include "../ComponentManager.hpp" 11 | #include "../../Utils/Singleton.hpp" 12 | #include "sdk.hpp" 13 | 14 | template 15 | class PlayerEvents : public PlayerSpawnEventHandler, public PlayerConnectEventHandler, public PlayerStreamEventHandler, public PlayerTextEventHandler, public PlayerShotEventHandler, public PlayerChangeEventHandler, public PlayerDamageEventHandler, public PlayerClickEventHandler, public PlayerCheckEventHandler, public PlayerUpdateEventHandler, public Singleton> 16 | { 17 | public: 18 | void onPlayerConnect(IPlayer& player) override 19 | { 20 | ComponentManager::Get()->CallEvent("onPlayerConnect", EventReturnHandler::None, &player); 21 | } 22 | 23 | void onPlayerSpawn(IPlayer& player) override 24 | { 25 | ComponentManager::Get()->CallEvent("onPlayerSpawn", EventReturnHandler::None, &player); 26 | } 27 | 28 | bool onPlayerCommandText(IPlayer& player, StringView cmdtext) override 29 | { 30 | return ComponentManager::Get()->CallEvent("onPlayerCommandText", EventReturnHandler::StopAtTrue, &player, CREATE_CAPI_STRING_VIEW(cmdtext)); 31 | } 32 | 33 | void onPlayerKeyStateChange(IPlayer& player, uint32_t newKeys, uint32_t oldKeys) override 34 | { 35 | ComponentManager::Get()->CallEvent("onPlayerKeyStateChange", EventReturnHandler::None, &player, int(newKeys), int(oldKeys)); 36 | } 37 | 38 | void onIncomingConnection(IPlayer& player, StringView ipAddress, unsigned short port) override 39 | { 40 | ComponentManager::Get()->CallEvent("onIncomingConnection", EventReturnHandler::None, &player, CREATE_CAPI_STRING_VIEW(ipAddress), int(port)); 41 | } 42 | 43 | void onPlayerDisconnect(IPlayer& player, PeerDisconnectReason reason) override 44 | { 45 | ComponentManager::Get()->CallEvent("onPlayerDisconnect", EventReturnHandler::None, &player, int(reason)); 46 | } 47 | 48 | bool onPlayerRequestSpawn(IPlayer& player) override 49 | { 50 | return ComponentManager::Get()->CallEvent("onPlayerRequestSpawn", EventReturnHandler::StopAtFalse, &player); 51 | } 52 | 53 | void onPlayerStreamIn(IPlayer& player, IPlayer& forPlayer) override 54 | { 55 | ComponentManager::Get()->CallEvent("onPlayerStreamIn", EventReturnHandler::None, &player, &forPlayer); 56 | } 57 | 58 | void onPlayerStreamOut(IPlayer& player, IPlayer& forPlayer) override 59 | { 60 | ComponentManager::Get()->CallEvent("onPlayerStreamOut", EventReturnHandler::None, &player, &forPlayer); 61 | } 62 | 63 | bool onPlayerText(IPlayer& player, StringView message) override 64 | { 65 | return ComponentManager::Get()->CallEvent("onPlayerText", EventReturnHandler::StopAtFalse, &player, CREATE_CAPI_STRING_VIEW(message)); 66 | } 67 | 68 | bool onPlayerShotMissed(IPlayer& player, const PlayerBulletData& bulletData) override 69 | { 70 | return ComponentManager::Get()->CallEvent("onPlayerShotMissed", EventReturnHandler::StopAtFalse, &player, 71 | int(bulletData.weapon), bulletData.offset.x, bulletData.offset.y, bulletData.offset.z); 72 | } 73 | 74 | bool onPlayerShotPlayer(IPlayer& player, IPlayer& target, const PlayerBulletData& bulletData) override 75 | { 76 | return ComponentManager::Get()->CallEvent("onPlayerShotPlayer", EventReturnHandler::StopAtFalse, &player, &target, 77 | int(bulletData.weapon), bulletData.offset.x, bulletData.offset.y, bulletData.offset.z); 78 | } 79 | 80 | bool onPlayerShotVehicle(IPlayer& player, IVehicle& target, const PlayerBulletData& bulletData) override 81 | { 82 | return ComponentManager::Get()->CallEvent("onPlayerShotVehicle", EventReturnHandler::StopAtFalse, &player, &target, 83 | int(bulletData.weapon), bulletData.offset.x, bulletData.offset.y, bulletData.offset.z); 84 | } 85 | 86 | bool onPlayerShotObject(IPlayer& player, IObject& target, const PlayerBulletData& bulletData) override 87 | { 88 | return ComponentManager::Get()->CallEvent("onPlayerShotObject", EventReturnHandler::StopAtFalse, &player, &target, 89 | int(bulletData.weapon), bulletData.offset.x, bulletData.offset.y, bulletData.offset.z); 90 | } 91 | 92 | bool onPlayerShotPlayerObject(IPlayer& player, IPlayerObject& target, const PlayerBulletData& bulletData) override 93 | { 94 | return ComponentManager::Get()->CallEvent("onPlayerShotPlayerObject", EventReturnHandler::StopAtFalse, &player, &target, 95 | int(bulletData.weapon), bulletData.offset.x, bulletData.offset.y, bulletData.offset.z); 96 | } 97 | 98 | void onPlayerDeath(IPlayer& player, IPlayer* killer, int reason) override 99 | { 100 | ComponentManager::Get()->CallEvent("onPlayerDeath", EventReturnHandler::None, &player, killer, reason); 101 | } 102 | 103 | void onPlayerTakeDamage(IPlayer& player, IPlayer* from, float amount, unsigned weapon, BodyPart part) override 104 | { 105 | ComponentManager::Get()->CallEvent("onPlayerTakeDamage", EventReturnHandler::None, &player, from, amount, int(weapon), int(part)); 106 | } 107 | 108 | void onPlayerGiveDamage(IPlayer& player, IPlayer& to, float amount, unsigned weapon, BodyPart part) override 109 | { 110 | ComponentManager::Get()->CallEvent("onPlayerGiveDamage", EventReturnHandler::None, &player, &to, amount, int(weapon), int(part)); 111 | } 112 | 113 | void onPlayerInteriorChange(IPlayer& player, unsigned newInterior, unsigned oldInterior) override 114 | { 115 | ComponentManager::Get()->CallEvent("onPlayerInteriorChange", EventReturnHandler::None, &player, int(newInterior), int(oldInterior)); 116 | } 117 | 118 | void onPlayerStateChange(IPlayer& player, PlayerState newState, PlayerState oldState) override 119 | { 120 | ComponentManager::Get()->CallEvent("onPlayerStateChange", EventReturnHandler::None, &player, int(newState), int(oldState)); 121 | } 122 | 123 | void onPlayerClickMap(IPlayer& player, Vector3 pos) override 124 | { 125 | ComponentManager::Get()->CallEvent("onPlayerClickMap", EventReturnHandler::None, &player, pos.x, pos.y, pos.z); 126 | } 127 | 128 | void onPlayerClickPlayer(IPlayer& player, IPlayer& clicked, PlayerClickSource source) override 129 | { 130 | ComponentManager::Get()->CallEvent("onPlayerClickPlayer", EventReturnHandler::None, &player, &clicked, int(source)); 131 | } 132 | 133 | void onClientCheckResponse(IPlayer& player, int actionType, int address, int results) override 134 | { 135 | ComponentManager::Get()->CallEvent("onClientCheckResponse", EventReturnHandler::None, &player, actionType, address, results); 136 | } 137 | 138 | bool onPlayerUpdate(IPlayer& player, TimePoint now) override 139 | { 140 | return ComponentManager::Get()->CallEvent("onPlayerUpdate", EventReturnHandler::StopAtFalse, &player); 141 | } 142 | }; 143 | -------------------------------------------------------------------------------- /tools/generate_single_header.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const readline = require("node:readline"); 3 | 4 | const filePath = "../include/ompcapi.h"; 5 | 6 | const events = require("../apidocs/events.json"); 7 | 8 | const files = fs 9 | .readdirSync("../src/Impl", { recursive: true }) 10 | .filter((file) => { 11 | return file.endsWith("APIs.cpp"); 12 | }); 13 | 14 | const entityTypes = [ 15 | "Player", 16 | "Vehicle", 17 | "Menu", 18 | "TextDraw", 19 | "TextLabel", 20 | "Object", 21 | "PlayerObject", 22 | "PlayerTextLabel3D", 23 | "PlayerTextDraw", 24 | "Class", 25 | "GangZone", 26 | "Pickup", 27 | ]; 28 | 29 | const predefinedTypes = `#ifndef OMPCAPI_H 30 | #define OMPCAPI_H 31 | 32 | #include 33 | #include 34 | 35 | #ifndef CAPI_COMPONENT_BUILD 36 | #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) 37 | #include 38 | #define LIBRARY_OPEN(path) LoadLibrary(path) 39 | #define LIBRARY_GET_ADDR(lib, symbol) GetProcAddress((HMODULE)lib, symbol) 40 | #else 41 | #include 42 | #define LIBRARY_OPEN(path) dlopen(path, RTLD_LAZY | RTLD_LOCAL) 43 | #define LIBRARY_GET_ADDR dlsym 44 | #endif 45 | #endif 46 | 47 | #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) 48 | #define OMP_API_EXPORT __declspec(dllexport) 49 | #else 50 | #define OMP_API_EXPORT __attribute__((visibility("default"))) 51 | #endif 52 | 53 | // Events 54 | 55 | enum EventPriorityType 56 | { 57 | EventPriorityType_Highest, 58 | EventPriorityType_FairlyHigh, 59 | EventPriorityType_Default, 60 | EventPriorityType_FairlyLow, 61 | EventPriorityType_Lowest, 62 | }; 63 | 64 | struct EventArgs_Common 65 | { 66 | int size; 67 | void** list; 68 | }; 69 | 70 | typedef bool (*EventCallback_Common)(struct EventArgs_Common* args); 71 | 72 | // Components 73 | 74 | struct ComponentVersion 75 | { 76 | uint8_t major; ///< MAJOR version when you make incompatible API changes 77 | uint8_t minor; ///< MINOR version when you add functionality in a backwards compatible manner 78 | uint8_t patch; ///< PATCH version when you make backwards compatible bug fixes 79 | uint16_t prerel; ///< PRE-RELEASE version 80 | }; 81 | 82 | typedef void (*ComponentOnReadyCallback)(); 83 | typedef void (*ComponentOnResetCallback)(); 84 | typedef void (*ComponentOnFreeCallback)(); 85 | 86 | struct CAPIStringView 87 | { 88 | unsigned int len; 89 | char* data; 90 | }; 91 | 92 | #ifndef CAPI_COMPONENT_BUILD 93 | 94 | `; 95 | 96 | fs.writeFileSync(filePath, predefinedTypes); 97 | 98 | fs.appendFileSync( 99 | filePath, 100 | entityTypes 101 | .map((type) => { 102 | return `typedef void* ${type};\n`; 103 | }) 104 | .join("") 105 | ); 106 | 107 | const APIs = {}; 108 | 109 | const convertFunctionArgTypeNames = (type) => { 110 | if (type === "StringCharPtr") { 111 | return "const char*"; 112 | } else if (type === "objectPtr") { 113 | return "void*"; 114 | } else if (type === "voidPtr") { 115 | return "void*"; 116 | } else if (type === "OutputStringViewPtr") { 117 | return "struct CAPIStringView*"; 118 | } else if (type === "ComponentVersion") { 119 | return "struct ComponentVersion"; 120 | } else { 121 | return type; 122 | } 123 | }; 124 | 125 | const convertEventArgTypeNames = (type) => { 126 | if (type === "CAPIStringView") { 127 | return "struct CAPIStringView"; 128 | } else { 129 | return type; 130 | } 131 | }; 132 | 133 | files.forEach(async (file, index) => { 134 | const data = fs.createReadStream("../src/Impl/" + file); 135 | const lines = readline.createInterface({ 136 | input: data, 137 | crlfDelay: Infinity, 138 | }); 139 | 140 | for await (const line of lines) { 141 | if (line.startsWith("OMP_CAPI(")) { 142 | const v0 = line.replace("OMP_CAPI(", ""); 143 | const name_full = v0.split(", ")[0]; 144 | const group = name_full.split("_")[0]; 145 | const name = name_full.split("_")[1]; 146 | 147 | if (APIs[group] === undefined) { 148 | APIs[group] = []; 149 | } 150 | 151 | const v1 = v0.split(", ")[1]; 152 | const ret = v1.substring(0, v1.indexOf("(")); 153 | const v2 = v0.replace(`OMP_CAPI(${name}, ${ret}`, ""); 154 | const params = v2 155 | .substring(v2.indexOf("(") + 1, v2.indexOf(")")) 156 | .split(", ") 157 | .map((param) => { 158 | const name = param.split(" ")[1]; 159 | const type = param.split(" ")[0]; 160 | 161 | if (name === undefined) { 162 | return undefined; 163 | } 164 | 165 | return { 166 | name, 167 | type: convertFunctionArgTypeNames(type), 168 | }; 169 | }); 170 | 171 | APIs[group].push({ 172 | ret: convertFunctionArgTypeNames(ret), 173 | name, 174 | params: params.length === 1 && params[0] === undefined ? [] : params, 175 | }); 176 | } 177 | } 178 | 179 | if (index == files.length - 1) { 180 | generateFunctions(APIs); 181 | 182 | fs.appendFileSync(filePath, `\n#endif\n\n#endif /* OMPCAPI_H */\n`); 183 | } 184 | }); 185 | 186 | const generateFunctions = (apis) => { 187 | const entries = Object.entries(apis); 188 | entries.forEach(([group, funcs], index) => { 189 | fs.appendFileSync(filePath, `\n\n// ${group} function type definitions\n`); 190 | funcs.forEach((func) => { 191 | fs.appendFileSync( 192 | filePath, 193 | `typedef ${func.ret} (*${group}_${func.name}_t)(${func.params 194 | .map((param) => `${param.type} ${param.name}`) 195 | .join(", ")});\n` 196 | ); 197 | }); 198 | }); 199 | 200 | generateEvents(events); 201 | 202 | entries.forEach(([group, funcs], index) => { 203 | fs.appendFileSync( 204 | filePath, 205 | `\n// ${group} functions\nstruct ${group}_t {\n` 206 | ); 207 | funcs.forEach((func) => { 208 | fs.appendFileSync( 209 | filePath, 210 | ` ${group}_${func.name}_t ${func.name};\n` 211 | ); 212 | }); 213 | fs.appendFileSync(filePath, `};\n`); 214 | }); 215 | 216 | fs.appendFileSync( 217 | filePath, 218 | `\n// All APIs 219 | struct OMPAPI_t { 220 | ` 221 | ); 222 | 223 | entries.forEach(([group, funcs], index) => { 224 | fs.appendFileSync(filePath, ` struct ${group}_t ${group};\n`); 225 | }); 226 | 227 | fs.appendFileSync(filePath, `};\n`); 228 | 229 | fs.appendFileSync( 230 | filePath, 231 | ` 232 | static void omp_initialize_capi(struct OMPAPI_t* ompapi) { 233 | #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) 234 | void* capi_lib = LIBRARY_OPEN("./components/$CAPI.dll"); 235 | #else 236 | void* capi_lib = LIBRARY_OPEN("./components/$CAPI.so"); 237 | #endif 238 | ` 239 | ); 240 | 241 | entries.forEach(([group, funcs], index) => { 242 | fs.appendFileSync(filePath, `\n // Retrieve ${group} functions\n`); 243 | funcs.forEach((func) => { 244 | fs.appendFileSync( 245 | filePath, 246 | ` ompapi->${group}.${func.name} = (${group}_${func.name}_t)LIBRARY_GET_ADDR(capi_lib, "${group}_${func.name}");\n` 247 | ); 248 | }); 249 | }); 250 | fs.appendFileSync(filePath, `\n return;\n};\n`); 251 | }; 252 | 253 | const generateEvents = (events_) => { 254 | const entries = Object.entries(events_); 255 | entries.forEach(([group, events], index) => { 256 | fs.appendFileSync( 257 | filePath, 258 | `\n\n// ${group} event type and arguments definitions` 259 | ); 260 | events.forEach((event) => { 261 | fs.appendFileSync( 262 | filePath, 263 | ` 264 | struct EventArgs_${event.name} { 265 | int size; 266 | struct { 267 | ${event.args.map((param) => ` ${convertEventArgTypeNames(param.type)}* ${param.name};`).join("\n")} 268 | } *list; 269 | }; 270 | typedef bool (*EventCallback_${event.name})(struct EventArgs_${ 271 | event.name 272 | } args);\n` 273 | ); 274 | }); 275 | }); 276 | fs.appendFileSync(filePath, `\n`); 277 | }; 278 | 279 | // generateEvents(events); 280 | 281 | /* 282 | const structBegin = `struct ${group} {\n`; 283 | fs.appendFileSync(filePath, structBegin); 284 | funcs.forEach(func => { 285 | fs.appendFileSync(filePath, structBegin); 286 | }) 287 | */ 288 | -------------------------------------------------------------------------------- /src/Impl/ComponentManager.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #pragma once 10 | #include 11 | 12 | #include "../Utils/Singleton.hpp" 13 | #include "../Utils/MacroMagic.hpp" 14 | 15 | #include "sdk.hpp" 16 | #include "Server/Components/Pickups/pickups.hpp" 17 | #include "Server/Components/Objects/objects.hpp" 18 | #include "Server/Components/TextLabels/textlabels.hpp" 19 | #include "Server/Components/Vehicles/vehicles.hpp" 20 | #include "Server/Components/Checkpoints/checkpoints.hpp" 21 | #include "Server/Components/Actors/actors.hpp" 22 | #include "Server/Components/Classes/classes.hpp" 23 | #include "Server/Components/Console/console.hpp" 24 | #include "Server/Components/CustomModels/custommodels.hpp" 25 | #include "Server/Components/Dialogs/dialogs.hpp" 26 | #include "Server/Components/Menus/menus.hpp" 27 | #include "Server/Components/TextDraws/textdraws.hpp" 28 | #include "Server/Components/Recordings/recordings.hpp" 29 | #include "Server/Components/TextDraws/textdraws.hpp" 30 | #include "Server/Components/TextLabels/textlabels.hpp" 31 | #include "Server/Components/GangZones/gangzones.hpp" 32 | 33 | enum class EventReturnHandler 34 | { 35 | None, 36 | StopAtFalse, 37 | StopAtTrue 38 | }; 39 | 40 | class ComponentManager : public Singleton 41 | { 42 | public: 43 | ICore* core = nullptr; 44 | IPlayerPool* players = nullptr; 45 | IPickupsComponent* pickups = nullptr; 46 | IObjectsComponent* objects = nullptr; 47 | ITextLabelsComponent* textlabels = nullptr; 48 | IVehiclesComponent* vehicles = nullptr; 49 | IActorsComponent* actors = nullptr; 50 | IClassesComponent* classes = nullptr; 51 | IConsoleComponent* console = nullptr; 52 | ICustomModelsComponent* models = nullptr; 53 | IMenusComponent* menus = nullptr; 54 | ITextDrawsComponent* textdraws = nullptr; 55 | IGangZonesComponent* gangzones = nullptr; 56 | ICheckpointsComponent* checkpoints = nullptr; 57 | IDialogsComponent* dialogs = nullptr; 58 | 59 | /// Store open.mp components 60 | void Init(ICore* c, IComponentList* clist); 61 | 62 | // Add event handlers to components' event dispatchers 63 | void InitializeEvents(); 64 | 65 | // Remove event handlers from components' event dispatchers 66 | void FreeEvents(); 67 | 68 | // Add an event callback of an event to omp capi handler maps 69 | bool AddEventHandler(const Impl::String& name, EventPriorityType priority, EventCallback_Common callback); 70 | 71 | // Remove an event callback of an event from omp capi handler maps 72 | bool RemoveEventHandler(const Impl::String& name, EventPriorityType priority, EventCallback_Common callback); 73 | 74 | // Remove all event callbacks of an event 75 | void RemoveAllHandlers(const Impl::String& name, EventPriorityType priority); 76 | 77 | /// Get open.mp core instance 78 | ICore* GetCore() 79 | { 80 | return core; 81 | } 82 | 83 | /// Get an open.mp component 84 | template 85 | ComponentType* GetComponent() 86 | { 87 | return componentList->queryComponent(); 88 | } 89 | 90 | // Call event 91 | template 92 | bool CallEvent(const Impl::String& name, EventReturnHandler returnHandler, Args... args) 93 | { 94 | FlatHashMap>* container = nullptr; 95 | if constexpr (PRIORITY == EventPriorityType_Highest) 96 | { 97 | container = &highestPriorityEvents; 98 | } 99 | else if constexpr (PRIORITY == EventPriorityType_FairlyHigh) 100 | { 101 | container = &fairlyHighPriorityEvents; 102 | } 103 | else if constexpr (PRIORITY == EventPriorityType_Default) 104 | { 105 | container = &defaultPriorityEvents; 106 | } 107 | else if constexpr (PRIORITY == EventPriorityType_FairlyHigh) 108 | { 109 | container = &fairlyLowPriorityEvents; 110 | } 111 | else if constexpr (PRIORITY == EventPriorityType_Lowest) 112 | { 113 | container = &lowestPriorityEvents; 114 | } 115 | 116 | bool result; 117 | 118 | if (container) 119 | { 120 | auto callbacks = container->find(name); 121 | if (callbacks != container->end()) 122 | { 123 | auto ret = CallEventOfPriority(callbacks, returnHandler, args...); 124 | if (!ret) 125 | { 126 | result = false; 127 | } 128 | } 129 | } 130 | 131 | return result; 132 | } 133 | 134 | private: 135 | IComponentList* componentList = nullptr; 136 | 137 | FlatHashMap> highestPriorityEvents; 138 | FlatHashMap> fairlyHighPriorityEvents; 139 | FlatHashMap> defaultPriorityEvents; 140 | FlatHashMap> fairlyLowPriorityEvents; 141 | FlatHashMap> lowestPriorityEvents; 142 | 143 | template 144 | bool CallEventOfPriority(Con container, EventReturnHandler returnHandler, Args... args) 145 | { 146 | EventArgs_Common eventArgs; 147 | constexpr std::size_t size = sizeof...(Args); 148 | 149 | if (size > 0) 150 | { 151 | eventArgs.list = new void*[size]; 152 | } 153 | 154 | eventArgs.size = size; 155 | bool result = true; 156 | for (auto cb : container->second) 157 | { 158 | if (cb) 159 | { 160 | int i = 0; 161 | ([&] 162 | { 163 | eventArgs.list[i] = &args; 164 | i++; 165 | }(), 166 | ...); 167 | 168 | auto ret = cb(&eventArgs); 169 | switch (returnHandler) 170 | { 171 | case EventReturnHandler::StopAtFalse: 172 | if (!ret) 173 | { 174 | delete[] eventArgs.list; 175 | return false; 176 | } 177 | break; 178 | case EventReturnHandler::StopAtTrue: 179 | if (ret) 180 | { 181 | delete[] eventArgs.list; 182 | return true; 183 | } 184 | break; 185 | } 186 | result = ret; 187 | } 188 | } 189 | 190 | delete[] eventArgs.list; 191 | return result; 192 | } 193 | }; 194 | 195 | /// Get player from players pool 196 | template 197 | inline PlayerDataType* GetPlayerData(IPlayer* player) 198 | { 199 | if (player == nullptr) 200 | { 201 | return nullptr; 202 | } 203 | return queryExtension(*player); 204 | } 205 | 206 | /// Cast object pointer to entity type, return fail_ret if not available 207 | #define ENTITY_CAST_RET(entity_type, entity, output, failret) \ 208 | if (!entity) \ 209 | return failret; \ 210 | entity_type* output = reinterpret_cast(entity) 211 | 212 | #define ENTITY_CAST(entity_type, entity, output) \ 213 | if (!entity) \ 214 | return; \ 215 | entity_type* output = reinterpret_cast(entity) 216 | 217 | #define POOL_ENTITY_RET(pool, entity_type, entity, output, failret) \ 218 | if (!ComponentManager::Get()->pool) \ 219 | return failret; \ 220 | auto pool = ComponentManager::Get()->pool; \ 221 | ENTITY_CAST_RET(entity_type, entity, output, failret) 222 | 223 | #define POOL_ENTITY(pool, entity_type, entity, output) \ 224 | if (!ComponentManager::Get()->pool) \ 225 | return; \ 226 | auto pool = ComponentManager::Get()->pool; \ 227 | ENTITY_CAST(entity_type, entity, output) 228 | 229 | #define PLAYER_POOL_ENTITY_RET(player, pool_type, entity_type, entity, entity_output, failret) \ 230 | auto playerData = GetPlayerData(player); \ 231 | if (playerData == nullptr) \ 232 | return failret; \ 233 | entity_type* entity_output = reinterpret_cast(entity); \ 234 | if (entity_output == nullptr) \ 235 | return failret; 236 | 237 | #define PLAYER_DATA_RET(player, entity_type, entity_output, failret) \ 238 | auto entity_output = GetPlayerData(player); \ 239 | if (entity_output == nullptr) \ 240 | return failret 241 | 242 | #define COPY_STRING_TO_CAPI_STRING_VIEW(output, src, len_) \ 243 | if (output) \ 244 | { \ 245 | output->len = len_; \ 246 | memcpy(output->data, src, uint32_t(len_)); \ 247 | } 248 | 249 | #define SET_CAPI_STRING_VIEW(output, str_view) \ 250 | if (output) \ 251 | { \ 252 | output->len = uint32_t(str_view.length()); \ 253 | output->data = const_cast(str_view.data()); \ 254 | } 255 | 256 | #define CREATE_CAPI_STRING_VIEW(str) \ 257 | CAPIStringView { static_cast(str.length()), const_cast(str.data()) } 258 | -------------------------------------------------------------------------------- /src/Impl/ComponentManager.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #include "Actors/Events.hpp" 10 | #include "Checkpoints/Events.hpp" 11 | #include "Classes/Events.hpp" 12 | #include "Core/Events.hpp" 13 | #include "Console/Events.hpp" 14 | #include "Dialogs/Events.hpp" 15 | #include "Menus/Events.hpp" 16 | #include "Objects/Events.hpp" 17 | #include "Pickups/Events.hpp" 18 | #include "Players/Events.hpp" 19 | #include "TextDraws/Events.hpp" 20 | #include "Vehicles/Events.hpp" 21 | #include "GangZones/Events.hpp" 22 | #include "CustomModels/Events.hpp" 23 | #include "ComponentManager.hpp" 24 | 25 | #define ADD_EVENT_HANDLER(component, event_instance) \ 26 | if (component) \ 27 | { \ 28 | component->getEventDispatcher().addEventHandler(event_instance::Get(), EventPriority_Highest); \ 29 | component->getEventDispatcher().addEventHandler(event_instance::Get(), EventPriority_FairlyHigh); \ 30 | component->getEventDispatcher().addEventHandler(event_instance::Get(), EventPriority_Default); \ 31 | component->getEventDispatcher().addEventHandler(event_instance::Get(), EventPriority_FairlyLow); \ 32 | component->getEventDispatcher().addEventHandler(event_instance::Get(), EventPriority_Lowest); \ 33 | } 34 | 35 | #define ADD_PLAYER_EVENT_HANDLER(component, event_name, event_instance) \ 36 | if (component) \ 37 | { \ 38 | component->getPlayer##event_name##Dispatcher().addEventHandler(event_instance::Get(), EventPriority_Highest); \ 39 | component->getPlayer##event_name##Dispatcher().addEventHandler(event_instance::Get(), EventPriority_FairlyHigh); \ 40 | component->getPlayer##event_name##Dispatcher().addEventHandler(event_instance::Get(), EventPriority_Default); \ 41 | component->getPlayer##event_name##Dispatcher().addEventHandler(event_instance::Get(), EventPriority_FairlyLow); \ 42 | component->getPlayer##event_name##Dispatcher().addEventHandler(event_instance::Get(), EventPriority_Lowest); \ 43 | } 44 | 45 | #define REMOVE_EVENT_HANDLER(component, event_instance) \ 46 | if (component) \ 47 | { \ 48 | component->getEventDispatcher().removeEventHandler(event_instance::Get()); \ 49 | component->getEventDispatcher().removeEventHandler(event_instance::Get()); \ 50 | component->getEventDispatcher().removeEventHandler(event_instance::Get()); \ 51 | component->getEventDispatcher().removeEventHandler(event_instance::Get()); \ 52 | component->getEventDispatcher().removeEventHandler(event_instance::Get()); \ 53 | } 54 | 55 | #define REMOVE_PLAYER_EVENT_HANDLER(component, event_name, event_instance) \ 56 | if (component) \ 57 | { \ 58 | component->getPlayer##event_name##Dispatcher().removeEventHandler(event_instance::Get()); \ 59 | component->getPlayer##event_name##Dispatcher().removeEventHandler(event_instance::Get()); \ 60 | component->getPlayer##event_name##Dispatcher().removeEventHandler(event_instance::Get()); \ 61 | component->getPlayer##event_name##Dispatcher().removeEventHandler(event_instance::Get()); \ 62 | component->getPlayer##event_name##Dispatcher().removeEventHandler(event_instance::Get()); \ 63 | } 64 | 65 | #define RETRIEVE_RELEVANT_EVENT_MAP(container, priority) \ 66 | FlatHashMap>* container = nullptr; \ 67 | switch (priority) \ 68 | { \ 69 | case EventPriorityType_Highest: \ 70 | container = &highestPriorityEvents; \ 71 | break; \ 72 | case EventPriorityType_FairlyHigh: \ 73 | container = &fairlyHighPriorityEvents; \ 74 | break; \ 75 | case EventPriorityType_Default: \ 76 | container = &defaultPriorityEvents; \ 77 | break; \ 78 | case EventPriorityType_FairlyLow: \ 79 | container = &fairlyLowPriorityEvents; \ 80 | break; \ 81 | case EventPriorityType_Lowest: \ 82 | container = &lowestPriorityEvents; \ 83 | break; \ 84 | default: \ 85 | container = &defaultPriorityEvents; \ 86 | break; \ 87 | } 88 | 89 | void ComponentManager::Init(ICore* c, IComponentList* clist) 90 | { 91 | core = c; 92 | componentList = clist; 93 | players = &core->getPlayers(); 94 | 95 | actors = GetComponent(); 96 | objects = GetComponent(); 97 | pickups = GetComponent(); 98 | textlabels = GetComponent(); 99 | vehicles = GetComponent(); 100 | classes = GetComponent(); 101 | console = GetComponent(); 102 | models = GetComponent(); 103 | menus = GetComponent(); 104 | textdraws = GetComponent(); 105 | gangzones = GetComponent(); 106 | checkpoints = GetComponent(); 107 | dialogs = GetComponent(); 108 | } 109 | 110 | void ComponentManager::InitializeEvents() 111 | { 112 | ADD_EVENT_HANDLER(core, CoreEvents); 113 | ADD_EVENT_HANDLER(actors, ActorEvents); 114 | ADD_EVENT_HANDLER(checkpoints, CheckpointEvents); 115 | ADD_EVENT_HANDLER(classes, ClassEvents); 116 | ADD_EVENT_HANDLER(dialogs, DialogEvents); 117 | ADD_EVENT_HANDLER(menus, MenuEvents); 118 | ADD_EVENT_HANDLER(textdraws, TextDrawEvents); 119 | ADD_EVENT_HANDLER(pickups, PickupEvents); 120 | ADD_EVENT_HANDLER(vehicles, VehicleEvents); 121 | ADD_EVENT_HANDLER(objects, ObjectEvents); 122 | ADD_EVENT_HANDLER(console, ConsoleEvents); 123 | ADD_EVENT_HANDLER(gangzones, GangZoneEvents); 124 | ADD_EVENT_HANDLER(models, CustomModelsEvents); 125 | 126 | ADD_PLAYER_EVENT_HANDLER(players, Spawn, PlayerEvents); 127 | ADD_PLAYER_EVENT_HANDLER(players, Connect, PlayerEvents); 128 | ADD_PLAYER_EVENT_HANDLER(players, Stream, PlayerEvents); 129 | ADD_PLAYER_EVENT_HANDLER(players, Text, PlayerEvents); 130 | ADD_PLAYER_EVENT_HANDLER(players, Shot, PlayerEvents); 131 | ADD_PLAYER_EVENT_HANDLER(players, Change, PlayerEvents); 132 | ADD_PLAYER_EVENT_HANDLER(players, Damage, PlayerEvents); 133 | ADD_PLAYER_EVENT_HANDLER(players, Click, PlayerEvents); 134 | ADD_PLAYER_EVENT_HANDLER(players, Check, PlayerEvents); 135 | ADD_PLAYER_EVENT_HANDLER(players, Update, PlayerEvents); 136 | } 137 | 138 | void ComponentManager::FreeEvents() 139 | { 140 | REMOVE_EVENT_HANDLER(core, CoreEvents); 141 | REMOVE_EVENT_HANDLER(actors, ActorEvents); 142 | REMOVE_EVENT_HANDLER(checkpoints, CheckpointEvents); 143 | REMOVE_EVENT_HANDLER(classes, ClassEvents); 144 | REMOVE_EVENT_HANDLER(dialogs, DialogEvents); 145 | REMOVE_EVENT_HANDLER(menus, MenuEvents); 146 | REMOVE_EVENT_HANDLER(textdraws, TextDrawEvents); 147 | REMOVE_EVENT_HANDLER(pickups, PickupEvents); 148 | REMOVE_EVENT_HANDLER(vehicles, VehicleEvents); 149 | REMOVE_EVENT_HANDLER(objects, ObjectEvents); 150 | REMOVE_EVENT_HANDLER(console, ConsoleEvents); 151 | REMOVE_EVENT_HANDLER(gangzones, GangZoneEvents); 152 | REMOVE_EVENT_HANDLER(models, CustomModelsEvents); 153 | 154 | REMOVE_PLAYER_EVENT_HANDLER(players, Spawn, PlayerEvents); 155 | REMOVE_PLAYER_EVENT_HANDLER(players, Connect, PlayerEvents); 156 | REMOVE_PLAYER_EVENT_HANDLER(players, Stream, PlayerEvents); 157 | REMOVE_PLAYER_EVENT_HANDLER(players, Text, PlayerEvents); 158 | REMOVE_PLAYER_EVENT_HANDLER(players, Shot, PlayerEvents); 159 | REMOVE_PLAYER_EVENT_HANDLER(players, Change, PlayerEvents); 160 | REMOVE_PLAYER_EVENT_HANDLER(players, Damage, PlayerEvents); 161 | REMOVE_PLAYER_EVENT_HANDLER(players, Click, PlayerEvents); 162 | REMOVE_PLAYER_EVENT_HANDLER(players, Check, PlayerEvents); 163 | REMOVE_PLAYER_EVENT_HANDLER(players, Update, PlayerEvents); 164 | } 165 | 166 | bool ComponentManager::AddEventHandler(const Impl::String& name, EventPriorityType priority, EventCallback_Common callback) 167 | { 168 | if (name.length()) 169 | { 170 | RETRIEVE_RELEVANT_EVENT_MAP(container, priority); 171 | if (container) 172 | { 173 | auto it = container->find(name); 174 | if (it == container->end()) 175 | { 176 | it = container->insert({ name, FlatHashSet() }).first; 177 | } 178 | 179 | it->second.insert(callback); 180 | return true; 181 | } 182 | } 183 | return false; 184 | } 185 | 186 | bool ComponentManager::RemoveEventHandler(const Impl::String& name, EventPriorityType priority, EventCallback_Common callback) 187 | { 188 | if (name.length()) 189 | { 190 | RETRIEVE_RELEVANT_EVENT_MAP(container, priority); 191 | if (container) 192 | { 193 | auto it = container->find(name); 194 | if (it != container->end()) 195 | { 196 | it->second.erase(callback); 197 | return true; 198 | } 199 | } 200 | } 201 | return false; 202 | } 203 | 204 | void ComponentManager::RemoveAllHandlers(const Impl::String& name, EventPriorityType priority) 205 | { 206 | if (name.length()) 207 | { 208 | RETRIEVE_RELEVANT_EVENT_MAP(container, priority); 209 | if (container) 210 | { 211 | container->erase(name); 212 | } 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /src/Impl/TextLabels/APIs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #include "../ComponentManager.hpp" 10 | 11 | OMP_CAPI(TextLabel_Create, objectPtr(StringCharPtr text, uint32_t color, float x, float y, float z, float drawDistance, int virtualWorld, bool los, int* id)) 12 | { 13 | ITextLabelsComponent* component = ComponentManager::Get()->textlabels; 14 | if (component) 15 | { 16 | ITextLabel* textlabel = component->create(text, Colour::FromRGBA(color), { x, y, z }, drawDistance, virtualWorld, los); 17 | if (textlabel) 18 | { 19 | *id = textlabel->getID(); 20 | return textlabel; 21 | } 22 | } 23 | return nullptr; 24 | } 25 | 26 | OMP_CAPI(TextLabel_Destroy, bool(objectPtr textlabel)) 27 | { 28 | POOL_ENTITY_RET(textlabels, ITextLabel, textlabel, textlabel_, false); 29 | ComponentManager::Get()->textlabels->release(textlabel_->getID()); 30 | return true; 31 | } 32 | 33 | OMP_CAPI(TextLabel_FromID, objectPtr(int textlabelid)) 34 | { 35 | ITextLabelsComponent* component = ComponentManager::Get()->textlabels; 36 | if (component) 37 | { 38 | return component->get(textlabelid); 39 | } 40 | return nullptr; 41 | } 42 | 43 | OMP_CAPI(TextLabel_GetID, int(objectPtr textlabel)) 44 | { 45 | POOL_ENTITY_RET(textlabels, ITextLabel, textlabel, textlabel_, false); 46 | return textlabel_->getID(); 47 | } 48 | 49 | OMP_CAPI(TextLabel_AttachToPlayer, bool(objectPtr textlabel, objectPtr player, float offsetX, float offsetY, float offsetZ)) 50 | { 51 | POOL_ENTITY_RET(textlabels, ITextLabel, textlabel, textlabel_, false); 52 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 53 | textlabel_->attachToPlayer(*player_, { offsetX, offsetY, offsetZ }); 54 | return true; 55 | } 56 | 57 | OMP_CAPI(TextLabel_AttachToVehicle, bool(objectPtr textlabel, objectPtr vehicle, float offsetX, float offsetY, float offsetZ)) 58 | { 59 | POOL_ENTITY_RET(textlabels, ITextLabel, textlabel, textlabel_, false); 60 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 61 | textlabel_->attachToVehicle(*vehicle_, { offsetX, offsetY, offsetZ }); 62 | return true; 63 | } 64 | 65 | OMP_CAPI(TextLabel_UpdateText, bool(objectPtr textlabel, uint32_t color, StringCharPtr text)) 66 | { 67 | POOL_ENTITY_RET(textlabels, ITextLabel, textlabel, textlabel_, false); 68 | textlabel_->setColourAndText(Colour::FromRGBA(color), text); 69 | return true; 70 | } 71 | 72 | OMP_CAPI(TextLabel_IsValid, bool(objectPtr textlabel)) 73 | { 74 | POOL_ENTITY_RET(textlabels, ITextLabel, textlabel, textlabel_, false); 75 | if (!textlabels->get(textlabel_->getID())) 76 | return false; 77 | return true; 78 | } 79 | 80 | OMP_CAPI(TextLabel_IsStreamedIn, bool(objectPtr player, objectPtr textlabel)) 81 | { 82 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 83 | POOL_ENTITY_RET(textlabels, ITextLabel, textlabel, textlabel_, false); 84 | auto streamed = textlabel_->isStreamedInForPlayer(*player_); 85 | return streamed; 86 | } 87 | 88 | OMP_CAPI(TextLabel_GetText, bool(objectPtr textlabel, OutputStringViewPtr output)) 89 | { 90 | POOL_ENTITY_RET(textlabels, ITextLabel, textlabel, textlabel_, false); 91 | auto result = textlabel_->getText(); 92 | SET_CAPI_STRING_VIEW(output, result); 93 | return true; 94 | } 95 | 96 | OMP_CAPI(TextLabel_GetColor, uint32_t(objectPtr textlabel)) 97 | { 98 | POOL_ENTITY_RET(textlabels, ITextLabel, textlabel, textlabel_, 0); 99 | return textlabel_->getColour().RGBA(); 100 | } 101 | 102 | OMP_CAPI(TextLabel_GetPos, bool(objectPtr textlabel, float* x, float* y, float* z)) 103 | { 104 | POOL_ENTITY_RET(textlabels, ITextLabel, textlabel, textlabel_, false); 105 | const Vector3& pos = textlabel_->getPosition(); 106 | 107 | *x = pos.x; 108 | *y = pos.y; 109 | *z = pos.z; 110 | return true; 111 | } 112 | 113 | OMP_CAPI(TextLabel_SetDrawDistance, bool(objectPtr textlabel, float distance)) 114 | { 115 | POOL_ENTITY_RET(textlabels, ITextLabel, textlabel, textlabel_, false); 116 | textlabel_->setDrawDistance(distance); 117 | return true; 118 | } 119 | 120 | OMP_CAPI(TextLabel_GetDrawDistance, float(objectPtr textlabel)) 121 | { 122 | POOL_ENTITY_RET(textlabels, ITextLabel, textlabel, textlabel_, 0.0f); 123 | auto distance = textlabel_->getDrawDistance(); 124 | return distance; 125 | } 126 | 127 | OMP_CAPI(TextLabel_GetLOS, bool(objectPtr textlabel)) 128 | { 129 | POOL_ENTITY_RET(textlabels, ITextLabel, textlabel, textlabel_, false); 130 | auto los = textlabel_->getTestLOS(); 131 | return los; 132 | } 133 | 134 | OMP_CAPI(TextLabel_SetLOS, bool(objectPtr textlabel, bool status)) 135 | { 136 | POOL_ENTITY_RET(textlabels, ITextLabel, textlabel, textlabel_, false); 137 | textlabel_->setTestLOS(status); 138 | return true; 139 | } 140 | 141 | OMP_CAPI(TextLabel_GetVirtualWorld, int(objectPtr textlabel)) 142 | { 143 | POOL_ENTITY_RET(textlabels, ITextLabel, textlabel, textlabel_, 0); 144 | auto virtualWorld = textlabel_->getVirtualWorld(); 145 | return virtualWorld; 146 | } 147 | 148 | OMP_CAPI(TextLabel_SetVirtualWorld, bool(objectPtr textlabel, int world)) 149 | { 150 | POOL_ENTITY_RET(textlabels, ITextLabel, textlabel, textlabel_, false); 151 | textlabel_->setVirtualWorld(world); 152 | return true; 153 | } 154 | 155 | OMP_CAPI(TextLabel_GetAttachedData, bool(objectPtr textlabel, int* attached_player, int* attached_vehicle)) 156 | { 157 | POOL_ENTITY_RET(textlabels, ITextLabel, textlabel, textlabel_, false); 158 | const TextLabelAttachmentData& data = textlabel_->getAttachmentData(); 159 | 160 | *attached_player = data.playerID; 161 | *attached_vehicle = data.vehicleID; 162 | 163 | return true; 164 | } 165 | 166 | /* 167 | Per-Player TextLabel 168 | */ 169 | 170 | OMP_CAPI(PlayerTextLabel_Create, objectPtr(objectPtr player, StringCharPtr text, uint32_t color, float x, float y, float z, float drawDistance, objectPtr attachedPlayer, objectPtr attachedVehicle, bool los, int* id)) 171 | { 172 | POOL_ENTITY_RET(players, IPlayer, player, player_, nullptr); 173 | IPlayerTextLabelData* labelData = queryExtension(player_); 174 | if (labelData) 175 | { 176 | IPlayerTextLabel* textlabel = nullptr; 177 | 178 | if (attachedPlayer) 179 | { 180 | textlabel = labelData->create(text, Colour::FromRGBA(color), { x, y, z }, drawDistance, los, *reinterpret_cast(attachedPlayer)); 181 | } 182 | else if (attachedVehicle) 183 | { 184 | textlabel = labelData->create(text, Colour::FromRGBA(color), { x, y, z }, drawDistance, los, *reinterpret_cast(attachedVehicle)); 185 | } 186 | else 187 | { 188 | textlabel = labelData->create(text, Colour::FromRGBA(color), { x, y, z }, drawDistance, los); 189 | } 190 | 191 | if (textlabel) 192 | { 193 | *id = textlabel->getID(); 194 | return textlabel; 195 | } 196 | } 197 | return nullptr; 198 | } 199 | 200 | OMP_CAPI(PlayerTextLabel_Destroy, bool(objectPtr player, objectPtr textlabel)) 201 | { 202 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 203 | PLAYER_POOL_ENTITY_RET(player_, IPlayerTextLabelData, IPlayerTextLabel, textlabel, textlabel_, false); 204 | auto data = queryExtension(player_); 205 | if (!data) 206 | { 207 | return false; 208 | } 209 | data->release(textlabel_->getID()); 210 | return true; 211 | } 212 | 213 | OMP_CAPI(PlayerTextLabel_FromID, objectPtr(objectPtr player, int textlabelid)) 214 | { 215 | POOL_ENTITY_RET(players, IPlayer, player, player_, nullptr); 216 | IPlayerTextLabelData* labelData = queryExtension(player_); 217 | if (labelData) 218 | { 219 | return labelData->get(textlabelid); 220 | } 221 | return nullptr; 222 | } 223 | 224 | OMP_CAPI(PlayerTextLabel_GetID, int(objectPtr player, objectPtr textlabel)) 225 | { 226 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 227 | PLAYER_POOL_ENTITY_RET(player_, IPlayerTextLabelData, IPlayerTextLabel, textlabel, textlabel_, false); 228 | return textlabel_->getID(); 229 | } 230 | 231 | OMP_CAPI(PlayerTextLabel_UpdateText, bool(objectPtr player, objectPtr textlabel, uint32_t color, StringCharPtr text)) 232 | { 233 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 234 | PLAYER_POOL_ENTITY_RET(player_, IPlayerTextLabelData, IPlayerTextLabel, textlabel, textlabel_, false); 235 | textlabel_->setColourAndText(Colour::FromRGBA(color), text); 236 | return true; 237 | } 238 | 239 | OMP_CAPI(PlayerTextLabel_IsValid, bool(objectPtr player, objectPtr textlabel, bool* valid)) 240 | { 241 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 242 | PLAYER_POOL_ENTITY_RET(player_, IPlayerTextLabelData, IPlayerTextLabel, textlabel, textlabel_, false); 243 | if (!playerData->get(textlabel_->getID())) 244 | return false; 245 | return true; 246 | } 247 | 248 | OMP_CAPI(PlayerTextLabel_GetText, bool(objectPtr player, objectPtr textlabel, OutputStringViewPtr output)) 249 | { 250 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 251 | PLAYER_POOL_ENTITY_RET(player_, IPlayerTextLabelData, IPlayerTextLabel, textlabel, textlabel_, false); 252 | auto result = textlabel_->getText(); 253 | SET_CAPI_STRING_VIEW(output, result); 254 | return true; 255 | } 256 | 257 | OMP_CAPI(PlayerTextLabel_GetColor, bool(objectPtr player, objectPtr textlabel, uint32_t* color)) 258 | { 259 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 260 | PLAYER_POOL_ENTITY_RET(player_, IPlayerTextLabelData, IPlayerTextLabel, textlabel, textlabel_, false); 261 | *color = textlabel_->getColour().RGBA(); 262 | return true; 263 | } 264 | 265 | OMP_CAPI(PlayerTextLabel_GetPos, bool(objectPtr player, objectPtr textlabel, float* x, float* y, float* z)) 266 | { 267 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 268 | PLAYER_POOL_ENTITY_RET(player_, IPlayerTextLabelData, IPlayerTextLabel, textlabel, textlabel_, false); 269 | const Vector3& pos = textlabel_->getPosition(); 270 | 271 | *x = pos.x; 272 | *y = pos.y; 273 | *z = pos.z; 274 | return true; 275 | } 276 | 277 | OMP_CAPI(PlayerTextLabel_SetDrawDistance, bool(objectPtr player, objectPtr textlabel, float distance)) 278 | { 279 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 280 | PLAYER_POOL_ENTITY_RET(player_, IPlayerTextLabelData, IPlayerTextLabel, textlabel, textlabel_, false); 281 | textlabel_->setDrawDistance(distance); 282 | return true; 283 | } 284 | 285 | OMP_CAPI(PlayerTextLabel_GetDrawDistance, float(objectPtr player, objectPtr textlabel)) 286 | { 287 | POOL_ENTITY_RET(players, IPlayer, player, player_, 0.0f); 288 | PLAYER_POOL_ENTITY_RET(player_, IPlayerTextLabelData, IPlayerTextLabel, textlabel, textlabel_, 0.0f); 289 | auto distance = textlabel_->getDrawDistance(); 290 | return distance; 291 | } 292 | 293 | OMP_CAPI(PlayerTextLabel_GetLOS, bool(objectPtr player, objectPtr textlabel)) 294 | { 295 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 296 | PLAYER_POOL_ENTITY_RET(player_, IPlayerTextLabelData, IPlayerTextLabel, textlabel, textlabel_, false); 297 | auto los = textlabel_->getTestLOS(); 298 | return los; 299 | } 300 | 301 | OMP_CAPI(PlayerTextLabel_SetLOS, bool(objectPtr player, objectPtr textlabel, bool status)) 302 | { 303 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 304 | PLAYER_POOL_ENTITY_RET(player_, IPlayerTextLabelData, IPlayerTextLabel, textlabel, textlabel_, false); 305 | textlabel_->setTestLOS(status); 306 | return true; 307 | } 308 | 309 | OMP_CAPI(PlayerTextLabel_GetVirtualWorld, int(objectPtr player)) 310 | { 311 | POOL_ENTITY_RET(players, IPlayer, player, player_, 0); 312 | return player_->getVirtualWorld(); 313 | } 314 | 315 | OMP_CAPI(PlayerTextLabel_GetAttachedData, bool(objectPtr player, objectPtr textlabel, int* attached_player, int* attached_vehicle)) 316 | { 317 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 318 | PLAYER_POOL_ENTITY_RET(player_, IPlayerTextLabelData, IPlayerTextLabel, textlabel, textlabel_, false); 319 | const TextLabelAttachmentData& data = textlabel_->getAttachmentData(); 320 | 321 | *attached_player = data.playerID; 322 | *attached_vehicle = data.vehicleID; 323 | 324 | return true; 325 | } 326 | -------------------------------------------------------------------------------- /src/Impl/Core/APIs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #include "../ComponentManager.hpp" 10 | #include 11 | #include 12 | 13 | OMP_CAPI(Core_TickCount, uint32_t()) 14 | { 15 | auto tick = ComponentManager::Get()->core->getTickCount(); 16 | return tick; 17 | } 18 | 19 | OMP_CAPI(Core_MaxPlayers, int()) 20 | { 21 | int max = *ComponentManager::Get()->core->getConfig().getInt("max_players"); 22 | return max; 23 | } 24 | 25 | OMP_CAPI(Core_Log, bool(StringCharPtr text)) 26 | { 27 | ComponentManager::Get()->core->printLn("%s", text); 28 | return true; 29 | } 30 | 31 | OMP_CAPI(Core_IsAdminTeleportAllowed, bool()) 32 | { 33 | bool allowed = *ComponentManager::Get()->core->getConfig().getBool("rcon.allow_teleport"); 34 | return allowed; 35 | } 36 | 37 | OMP_CAPI(Core_AllowAdminTeleport, bool(bool allow)) 38 | { 39 | *ComponentManager::Get()->core->getConfig().getBool("rcon.allow_teleport") = allow; 40 | return true; 41 | } 42 | 43 | OMP_CAPI(Core_AreAllAnimationsEnabled, bool()) 44 | { 45 | bool allowed = *ComponentManager::Get()->core->getConfig().getBool("game.use_all_animations"); 46 | return allowed; 47 | } 48 | 49 | OMP_CAPI(Core_EnableAllAnimations, bool(bool allow)) 50 | { 51 | *ComponentManager::Get()->core->getConfig().getBool("game.use_all_animations") = allow; 52 | return true; 53 | } 54 | 55 | OMP_CAPI(Core_IsAnimationLibraryValid, bool(StringCharPtr name)) 56 | { 57 | auto valid = animationLibraryValid(name, true); 58 | return valid; 59 | } 60 | 61 | OMP_CAPI(Core_AreInteriorWeaponsAllowed, bool()) 62 | { 63 | bool allowed = *ComponentManager::Get()->core->getConfig().getBool("game.allow_interior_weapons"); 64 | return allowed; 65 | } 66 | 67 | OMP_CAPI(Core_AllowInteriorWeapons, bool(bool allow)) 68 | { 69 | if (allow) 70 | { 71 | *ComponentManager::Get()->core->getConfig().getBool("game.allow_interior_weapons") = true; 72 | } 73 | else 74 | { 75 | IPlayerPool* players = ComponentManager::Get()->players; 76 | for (IPlayer* player : players->entries()) 77 | { 78 | if (player->getInterior() && player->areWeaponsAllowed()) 79 | { 80 | // Because they are allowed weapons currently this will send a full client reset. 81 | player->resetWeapons(); 82 | } 83 | } 84 | // By the time the player reports having no weapons, this is set and so we remember the old 85 | // ones still. 86 | *ComponentManager::Get()->core->getConfig().getBool("game.allow_interior_weapons") = false; 87 | } 88 | return true; 89 | } 90 | 91 | OMP_CAPI(Core_BlockIpAddress, bool(StringCharPtr ipAddress, int timeMS)) 92 | { 93 | if (strlen(ipAddress) < 1) 94 | { 95 | return false; 96 | } 97 | BanEntry entry(ipAddress); 98 | for (INetwork* network : ComponentManager::Get()->core->getNetworks()) 99 | { 100 | network->ban(entry, Milliseconds(timeMS)); 101 | } 102 | return true; 103 | } 104 | 105 | OMP_CAPI(Core_UnBlockIpAddress, bool(StringCharPtr ipAddress)) 106 | { 107 | BanEntry entry(ipAddress); 108 | for (INetwork* network : ComponentManager::Get()->core->getNetworks()) 109 | { 110 | network->unban(entry); 111 | } 112 | return true; 113 | } 114 | 115 | OMP_CAPI(NPC_Connect, bool(StringCharPtr name, StringCharPtr script)) 116 | { 117 | ComponentManager::Get()->core->connectBot(name, script); 118 | return true; 119 | } 120 | 121 | OMP_CAPI(Core_DisableEntryExitMarkers, bool()) 122 | { 123 | *ComponentManager::Get()->core->getConfig().getBool("game.use_entry_exit_markers") = false; 124 | return true; 125 | } 126 | 127 | OMP_CAPI(Core_DisableNameTagsLOS, bool()) 128 | { 129 | *ComponentManager::Get()->core->getConfig().getBool("game.use_nametag_los") = false; 130 | return true; 131 | } 132 | 133 | OMP_CAPI(Core_EnableZoneNames, bool(bool enable)) 134 | { 135 | *ComponentManager::Get()->core->getConfig().getBool("game.use_zone_names") = enable; 136 | return true; 137 | } 138 | 139 | OMP_CAPI(Core_ShowGameTextForAll, bool(StringCharPtr msg, int time, int style)) 140 | { 141 | if (strlen(msg) < 1) 142 | { 143 | return false; 144 | } 145 | ComponentManager::Get()->players->sendGameTextToAll(msg, Milliseconds(time), style); 146 | return true; 147 | } 148 | 149 | OMP_CAPI(Core_HideGameTextForAll, bool(int style)) 150 | { 151 | ComponentManager::Get()->players->hideGameTextForAll(style); 152 | return true; 153 | } 154 | 155 | OMP_CAPI(Core_NetworkStats, int(OutputStringViewPtr output)) 156 | { 157 | std::stringstream stream; 158 | NetworkStats stats; 159 | 160 | for (INetwork* network : ComponentManager::Get()->core->getNetworks()) 161 | { 162 | if (network->getNetworkType() == ENetworkType::ENetworkType_RakNetLegacy) 163 | { 164 | stats = network->getStatistics(); 165 | } 166 | } 167 | 168 | stream 169 | << "Server Ticks: " << ComponentManager::Get()->core->tickRate() << std::endl 170 | << "Messages in Send buffer: " << stats.messageSendBuffer << std::endl 171 | << "Messages sent: " << stats.messagesSent << std::endl 172 | << "Bytes sent: " << stats.totalBytesSent << std::endl 173 | << "Acks sent: " << stats.acknowlegementsSent << std::endl 174 | << "Acks in send buffer: " << stats.acknowlegementsPending << std::endl 175 | << "Messages waiting for ack: " << stats.messagesOnResendQueue << std::endl 176 | << "Messages resent: " << stats.messageResends << std::endl 177 | << "Bytes resent: " << stats.messagesTotalBytesResent << std::endl 178 | << "Packetloss: " << std::setprecision(1) << std::fixed << stats.packetloss << "%" << std::endl 179 | << "Messages received: " << stats.messagesReceived << std::endl 180 | << "Bytes received: " << stats.bytesReceived << std::endl 181 | << "Acks received: " << stats.acknowlegementsReceived << std::endl 182 | << "Duplicate acks received: " << stats.duplicateAcknowlegementsReceived << std::endl 183 | << "Inst. KBits per second: " << std::setprecision(1) << (stats.bitsPerSecond / 1000.0) << std::endl 184 | << "KBits per second sent: " << std::setprecision(1) << (stats.bpsSent / 1000.0) << std::endl 185 | << "KBits per second received: " << std::setprecision(1) << (stats.bpsReceived / 1000.0) << std::endl; 186 | 187 | int len = stream.str().size(); 188 | COPY_STRING_TO_CAPI_STRING_VIEW(output, stream.str().c_str(), len); 189 | return len; 190 | } 191 | 192 | OMP_CAPI(Player_GetNetworkStats, int(objectPtr player, OutputStringViewPtr output)) 193 | { 194 | POOL_ENTITY_RET(players, IPlayer, player, player_, 0); 195 | std::stringstream stream; 196 | NetworkStats stats = player_->getNetworkData().network->getStatistics(player_); 197 | 198 | stream 199 | << "Network Active: " << int(stats.isActive) << std::endl 200 | << "Network State: " << stats.connectMode << std::endl 201 | << "Messages in Send buffer: " << stats.messageSendBuffer << std::endl 202 | << "Messages sent: " << stats.messagesSent << std::endl 203 | << "Bytes sent: " << stats.totalBytesSent << std::endl 204 | << "Acks sent: " << stats.acknowlegementsSent << std::endl 205 | << "Acks in send buffer: " << stats.acknowlegementsPending << std::endl 206 | << "Messages waiting for ack: " << stats.messagesOnResendQueue << std::endl 207 | << "Messages resent: " << stats.messageResends << std::endl 208 | << "Bytes resent: " << stats.messagesTotalBytesResent << std::endl 209 | << "Packetloss: " << std::setprecision(1) << std::fixed << stats.packetloss << "%" << std::endl 210 | << "Messages received: " << stats.messagesReceived << std::endl 211 | << "Bytes received: " << stats.bytesReceived << std::endl 212 | << "Acks received: " << stats.acknowlegementsReceived << std::endl 213 | << "Duplicate acks received: " << stats.duplicateAcknowlegementsReceived << std::endl 214 | << "Inst. KBits per second: " << std::setprecision(1) << (stats.bitsPerSecond / 1000.0) << std::endl 215 | << "KBits per second sent: " << std::setprecision(1) << (stats.bpsSent / 1000.0) << std::endl 216 | << "KBits per second received: " << std::setprecision(1) << (stats.bpsReceived / 1000.0) << std::endl; 217 | 218 | int len = stream.str().size(); 219 | COPY_STRING_TO_CAPI_STRING_VIEW(output, stream.str().c_str(), len); 220 | return len; 221 | } 222 | 223 | OMP_CAPI(Core_ServerTickRate, int()) 224 | { 225 | int tick = ComponentManager::Get()->core->tickRate(); 226 | return tick; 227 | } 228 | 229 | OMP_CAPI(Core_GetWeaponName, bool(int weaponid, OutputStringViewPtr output)) 230 | { 231 | SET_CAPI_STRING_VIEW(output, ComponentManager::Get()->core->getWeaponName(PlayerWeapon(weaponid))); 232 | return true; 233 | } 234 | 235 | OMP_CAPI(Core_SetChatRadius, bool(float globalChatRadius)) 236 | { 237 | *ComponentManager::Get()->core->getConfig().getBool("game.use_chat_radius") = true; 238 | *ComponentManager::Get()->core->getConfig().getFloat("game.chat_radius") = globalChatRadius; 239 | return true; 240 | } 241 | 242 | OMP_CAPI(Core_SetMarkerRadius, bool(float playerMarkerRadius)) 243 | { 244 | *ComponentManager::Get()->core->getConfig().getBool("game.use_player_marker_draw_radius") = true; 245 | *ComponentManager::Get()->core->getConfig().getFloat("game.player_marker_draw_radius") = playerMarkerRadius; 246 | return true; 247 | } 248 | 249 | OMP_CAPI(Player_NetStatsBytesReceived, int(objectPtr player)) 250 | { 251 | POOL_ENTITY_RET(players, IPlayer, player, player_, 0); 252 | NetworkStats stats = player_->getNetworkData().network->getStatistics(player_); 253 | int bytes = stats.bytesReceived; 254 | return bytes; 255 | } 256 | 257 | OMP_CAPI(Player_NetStatsBytesSent, int(objectPtr player)) 258 | { 259 | POOL_ENTITY_RET(players, IPlayer, player, player_, 0); 260 | NetworkStats stats = player_->getNetworkData().network->getStatistics(player_); 261 | int bytes = stats.totalBytesSent; 262 | return bytes; 263 | } 264 | 265 | OMP_CAPI(Player_NetStatsConnectionStatus, int(objectPtr player)) 266 | { 267 | POOL_ENTITY_RET(players, IPlayer, player, player_, 0); 268 | NetworkStats stats = player_->getNetworkData().network->getStatistics(player_); 269 | int status = stats.connectMode; 270 | return status; 271 | } 272 | 273 | OMP_CAPI(Player_NetStatsGetConnectedTime, int(objectPtr player)) 274 | { 275 | POOL_ENTITY_RET(players, IPlayer, player, player_, 0); 276 | NetworkStats stats = player_->getNetworkData().network->getStatistics(player_); 277 | int ms = stats.connectionElapsedTime; 278 | return ms; 279 | } 280 | 281 | OMP_CAPI(Player_NetStatsGetIpPort, bool(objectPtr player, OutputStringViewPtr output)) 282 | { 283 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 284 | PeerNetworkData data = player_->getNetworkData(); 285 | PeerAddress::AddressString addressString; 286 | if (PeerAddress::ToString(data.networkID.address, addressString)) 287 | { 288 | Impl::String ip_port((StringView(addressString))); 289 | ip_port += ":"; 290 | ip_port += std::to_string(data.networkID.port); 291 | int len = ip_port.length(); 292 | COPY_STRING_TO_CAPI_STRING_VIEW(output, ip_port.c_str(), len); 293 | return len; 294 | } 295 | return 0; 296 | } 297 | 298 | OMP_CAPI(Player_NetStatsMessagesReceived, int(objectPtr player)) 299 | { 300 | POOL_ENTITY_RET(players, IPlayer, player, player_, 0); 301 | NetworkStats stats = player_->getNetworkData().network->getStatistics(player_); 302 | int received = stats.messagesReceived; 303 | return received; 304 | } 305 | 306 | OMP_CAPI(Player_NetStatsMessagesRecvPerSecond, int(objectPtr player)) 307 | { 308 | POOL_ENTITY_RET(players, IPlayer, player, player_, 0); 309 | NetworkStats stats = player_->getNetworkData().network->getStatistics(player_); 310 | int received = stats.messagesReceivedPerSecond; 311 | return received; 312 | } 313 | 314 | OMP_CAPI(Player_NetStatsMessagesSent, int(objectPtr player)) 315 | { 316 | POOL_ENTITY_RET(players, IPlayer, player, player_, 0); 317 | NetworkStats stats = player_->getNetworkData().network->getStatistics(player_); 318 | int sent = stats.messagesSent; 319 | return sent; 320 | } 321 | 322 | OMP_CAPI(Player_NetStatsPacketLossPercent, float(objectPtr player)) 323 | { 324 | POOL_ENTITY_RET(players, IPlayer, player, player_, 0.0f); 325 | NetworkStats stats = player_->getNetworkData().network->getStatistics(player_); 326 | auto packetLoss = stats.packetloss; 327 | return packetLoss; 328 | } 329 | 330 | OMP_CAPI(Core_SendRconCommand, bool(StringCharPtr command)) 331 | { 332 | IConsoleComponent* console = ComponentManager::Get()->console; 333 | if (console) 334 | { 335 | console->send(command); 336 | return true; 337 | } 338 | return false; 339 | } 340 | 341 | OMP_CAPI(Core_SetDeathDropAmount, bool(int amount)) 342 | { 343 | *ComponentManager::Get()->core->getConfig().getInt("game.death_drop_amount") = amount; 344 | return true; 345 | } 346 | 347 | OMP_CAPI(Core_GameMode_SetText, bool(StringCharPtr string)) 348 | { 349 | ComponentManager::Get()->core->setData(SettableCoreDataType::ModeText, string); 350 | return true; 351 | } 352 | 353 | OMP_CAPI(Core_SetGravity, bool(float gravity)) 354 | { 355 | ComponentManager::Get()->core->setGravity(gravity); 356 | return true; 357 | } 358 | 359 | OMP_CAPI(Core_GetGravity, float()) 360 | { 361 | float gravity = ComponentManager::Get()->core->getGravity(); 362 | return gravity; 363 | } 364 | 365 | OMP_CAPI(Core_SetNameTagsDrawDistance, bool(float distance)) 366 | { 367 | *ComponentManager::Get()->core->getConfig().getFloat("game.nametag_draw_radius") = distance; 368 | return true; 369 | } 370 | 371 | OMP_CAPI(Core_SetWeather, bool(int weatherid)) 372 | { 373 | ComponentManager::Get()->core->setWeather(weatherid); 374 | return true; 375 | } 376 | 377 | OMP_CAPI(Core_SetWorldTime, bool(int hour)) 378 | { 379 | ComponentManager::Get()->core->setWorldTime(Hours(hour)); 380 | return true; 381 | } 382 | 383 | OMP_CAPI(Core_ShowNameTags, bool(bool show)) 384 | { 385 | *ComponentManager::Get()->core->getConfig().getBool("game.use_nametags") = show; 386 | return true; 387 | } 388 | 389 | OMP_CAPI(Core_ShowPlayerMarkers, bool(int mode)) 390 | { 391 | *ComponentManager::Get()->core->getConfig().getInt("game.player_marker_mode") = mode; 392 | return true; 393 | } 394 | 395 | OMP_CAPI(Core_UsePedAnims, bool()) 396 | { 397 | *ComponentManager::Get()->core->getConfig().getBool("game.use_player_ped_anims") = true; 398 | return true; 399 | } 400 | 401 | OMP_CAPI(Core_GetWeather, int()) 402 | { 403 | int weather = *ComponentManager::Get()->core->getConfig().getInt("game.weather"); 404 | return weather; 405 | } 406 | 407 | OMP_CAPI(Core_GetWorldTime, int()) 408 | { 409 | int hour = *ComponentManager::Get()->core->getConfig().getInt("game.time"); 410 | return hour; 411 | } 412 | 413 | OMP_CAPI(Core_ToggleChatTextReplacement, bool(bool enable)) 414 | { 415 | *ComponentManager::Get()->core->getConfig().getBool("chat_input_filter") = enable; 416 | return true; 417 | } 418 | 419 | OMP_CAPI(Core_IsChatTextReplacementToggled, bool()) 420 | { 421 | bool toggled = *ComponentManager::Get()->core->getConfig().getBool("chat_input_filter"); 422 | return toggled; 423 | } 424 | 425 | OMP_CAPI(Core_IsNickNameValid, bool(StringCharPtr name)) 426 | { 427 | auto valid = ComponentManager::Get()->players->isNameValid(name); 428 | return valid; 429 | } 430 | 431 | OMP_CAPI(Core_AllowNickNameCharacter, bool(int character, bool allow)) 432 | { 433 | ComponentManager::Get()->players->allowNickNameCharacter(character, allow); 434 | return true; 435 | } 436 | 437 | OMP_CAPI(Core_IsNickNameCharacterAllowed, bool(int character)) 438 | { 439 | bool allowed = ComponentManager::Get()->players->isNickNameCharacterAllowed(character); 440 | return allowed; 441 | } 442 | 443 | OMP_CAPI(Core_ClearBanList, bool()) 444 | { 445 | ICore* core = ComponentManager::Get()->core; 446 | if (!core) 447 | { 448 | return false; 449 | } 450 | 451 | core->getConfig().clearBans(); 452 | return true; 453 | } 454 | 455 | OMP_CAPI(Core_IsIpAddressBanned, bool(StringCharPtr ip)) 456 | { 457 | ICore* core = ComponentManager::Get()->core; 458 | if (!core) 459 | { 460 | return false; 461 | } 462 | BanEntry entry(ip); 463 | bool isBanned = core->getConfig().isBanned(entry); 464 | return isBanned; 465 | } 466 | 467 | OMP_CAPI(Core_GetWeaponSlot, int(uint8_t weapon)) 468 | { 469 | int slot = WeaponSlotData { weapon }.slot(); 470 | return slot; 471 | } 472 | 473 | OMP_CAPI(Core_AddRule, bool(StringCharPtr name, StringCharPtr value)) 474 | { 475 | ICore* core = ComponentManager::Get()->core; 476 | if (!core) 477 | { 478 | return false; 479 | } 480 | 481 | for (INetwork* network : core->getNetworks()) 482 | { 483 | INetworkQueryExtension* query = queryExtension(network); 484 | 485 | if (query) 486 | { 487 | query->addRule(name, value); 488 | return true; 489 | } 490 | } 491 | return false; 492 | } 493 | 494 | OMP_CAPI(Core_IsValidRule, bool(StringCharPtr name)) 495 | { 496 | ICore* core = ComponentManager::Get()->core; 497 | if (!core) 498 | { 499 | return false; 500 | } 501 | 502 | for (INetwork* network : core->getNetworks()) 503 | { 504 | INetworkQueryExtension* query = queryExtension(network); 505 | 506 | if (query) 507 | { 508 | bool valid = query->isValidRule(name); 509 | return valid; 510 | } 511 | } 512 | return false; 513 | } 514 | 515 | OMP_CAPI(Core_RemoveRule, bool(StringCharPtr name)) 516 | { 517 | ICore* core = ComponentManager::Get()->core; 518 | if (!core) 519 | { 520 | return false; 521 | } 522 | 523 | for (INetwork* network : core->getNetworks()) 524 | { 525 | INetworkQueryExtension* query = queryExtension(network); 526 | 527 | if (query) 528 | { 529 | query->removeRule(name); 530 | return true; 531 | } 532 | } 533 | return false; 534 | } 535 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /src/Impl/Vehicles/APIs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This Source Code Form is subject to the terms of the Mozilla Public License, 3 | * v. 2.0. If a copy of the MPL was not distributed with this file, You can 4 | * obtain one at http://mozilla.org/MPL/2.0/. 5 | * 6 | * The original code is copyright (c) 2024, open.mp team and contributors. 7 | */ 8 | 9 | #include "../ComponentManager.hpp" 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | OMP_CAPI(Vehicle_Create, objectPtr(int modelid, float x, float y, float z, float rotation, int color1, int color2, int respawnDelay, bool addSiren, int* id)) 16 | { 17 | IVehiclesComponent* vehicles = ComponentManager().Get()->vehicles; 18 | if (vehicles) 19 | { 20 | IVehicle* vehicle = vehicles->create(false, modelid, { x, y, z }, rotation, color1, color2, Seconds(respawnDelay), addSiren); 21 | if (vehicle) 22 | { 23 | *id = vehicle->getID(); 24 | return vehicle; 25 | } 26 | } 27 | return nullptr; 28 | } 29 | 30 | OMP_CAPI(Vehicle_Destroy, bool(objectPtr vehicle)) 31 | { 32 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 33 | vehicles->release(vehicle_->getID()); 34 | return true; 35 | } 36 | 37 | OMP_CAPI(Vehicle_FromID, objectPtr(int vehicleid)) 38 | { 39 | IVehiclesComponent* component = ComponentManager::Get()->vehicles; 40 | if (component) 41 | { 42 | return component->get(vehicleid); 43 | } 44 | return nullptr; 45 | } 46 | 47 | OMP_CAPI(Vehicle_GetID, int(objectPtr vehicle)) 48 | { 49 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 50 | return vehicle_->getID(); 51 | } 52 | 53 | OMP_CAPI(Vehicle_GetMaxPassengerSeats, int(int modelid)) 54 | { 55 | int seats = Impl::getVehiclePassengerSeats(modelid); 56 | return seats; 57 | } 58 | 59 | OMP_CAPI(Vehicle_IsStreamedIn, bool(objectPtr vehicle, objectPtr player)) 60 | { 61 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 62 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 63 | return vehicle_->isStreamedInForPlayer(*player_); 64 | } 65 | 66 | OMP_CAPI(Vehicle_GetPos, bool(objectPtr vehicle, float* x, float* y, float* z)) 67 | { 68 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 69 | const Vector3& pos = vehicle_->getPosition(); 70 | 71 | *x = pos.x; 72 | *y = pos.y; 73 | *z = pos.z; 74 | return true; 75 | } 76 | 77 | OMP_CAPI(Vehicle_SetPos, bool(objectPtr vehicle, float x, float y, float z)) 78 | { 79 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 80 | vehicle_->setPosition({ x, y, z }); 81 | return true; 82 | } 83 | 84 | OMP_CAPI(Vehicle_GetZAngle, float(objectPtr vehicle)) 85 | { 86 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0.0f); 87 | float angle = vehicle_->getZAngle(); 88 | return angle; 89 | } 90 | 91 | OMP_CAPI(Vehicle_GetRotationQuat, bool(objectPtr vehicle, float* w, float* x, float* y, float* z)) 92 | { 93 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 94 | glm::quat rotQuat = vehicle_->getRotation().q; 95 | *w = rotQuat.w; 96 | *x = rotQuat.x; 97 | *y = rotQuat.y; 98 | *z = rotQuat.z; 99 | return true; 100 | } 101 | 102 | OMP_CAPI(Vehicle_GetDistanceFromPoint, float(objectPtr vehicle, float x, float y, float z)) 103 | { 104 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0.0f); 105 | return glm::distance(vehicle_->getPosition(), { x, y, z }); 106 | } 107 | 108 | OMP_CAPI(Vehicle_SetZAngle, bool(objectPtr vehicle, float angle)) 109 | { 110 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 111 | vehicle_->setZAngle(angle); 112 | return true; 113 | } 114 | 115 | OMP_CAPI(Vehicle_SetParamsForPlayer, bool(objectPtr vehicle, objectPtr player, int objective, int doors)) 116 | { 117 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 118 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 119 | VehicleParams params = vehicle_->getParams(); 120 | params.objective = objective; 121 | params.doors = doors; 122 | vehicle_->setParamsForPlayer(*player_, params); 123 | return true; 124 | } 125 | 126 | OMP_CAPI(Vehicle_UseManualEngineAndLights, bool()) 127 | { 128 | *ComponentManager().Get()->core->getConfig().getBool("game.use_manual_engine_and_lights") = true; 129 | return true; 130 | } 131 | 132 | OMP_CAPI(Vehicle_SetParamsEx, bool(objectPtr vehicle, int engine, int lights, int alarm, int doors, int bonnet, int boot, int objective)) 133 | { 134 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 135 | VehicleParams params = vehicle_->getParams(); 136 | params.engine = engine; 137 | params.lights = lights; 138 | params.alarm = alarm; 139 | params.doors = doors; 140 | params.bonnet = bonnet; 141 | params.boot = boot; 142 | params.objective = objective; 143 | vehicle_->setParams(params); 144 | return true; 145 | } 146 | 147 | OMP_CAPI(Vehicle_GetParamsEx, bool(objectPtr vehicle, int* engine, int* lights, int* alarm, int* doors, int* bonnet, int* boot, int* objective)) 148 | { 149 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 150 | const VehicleParams& params = vehicle_->getParams(); 151 | *engine = params.engine; 152 | *lights = params.lights; 153 | *alarm = params.alarm; 154 | *doors = params.doors; 155 | *bonnet = params.bonnet; 156 | *boot = params.boot; 157 | *objective = params.objective; 158 | return true; 159 | } 160 | 161 | OMP_CAPI(Vehicle_GetParamsSirenState, int(objectPtr vehicle)) 162 | { 163 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0); 164 | int state = vehicle_->getParams().siren; 165 | return state; 166 | } 167 | 168 | OMP_CAPI(Vehicle_SetParamsCarDoors, bool(objectPtr vehicle, int frontLeft, int frontRight, int rearLeft, int rearRight)) 169 | { 170 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 171 | VehicleParams params = vehicle_->getParams(); 172 | params.doorDriver = frontLeft; 173 | params.doorPassenger = frontRight; 174 | params.doorBackLeft = rearLeft; 175 | params.doorBackRight = rearRight; 176 | vehicle_->setParams(params); 177 | return true; 178 | } 179 | 180 | OMP_CAPI(Vehicle_GetParamsCarDoors, bool(objectPtr vehicle, int* frontLeft, int* frontRight, int* rearLeft, int* rearRight)) 181 | { 182 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 183 | const VehicleParams& params = vehicle_->getParams(); 184 | *frontLeft = params.doorDriver; 185 | *frontRight = params.doorPassenger; 186 | *rearLeft = params.doorBackLeft; 187 | *rearRight = params.doorBackRight; 188 | return true; 189 | } 190 | 191 | OMP_CAPI(Vehicle_SetParamsCarWindows, bool(objectPtr vehicle, int frontLeft, int frontRight, int rearLeft, int rearRight)) 192 | { 193 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 194 | VehicleParams params = vehicle_->getParams(); 195 | params.windowDriver = frontLeft; 196 | params.windowPassenger = frontRight; 197 | params.windowBackLeft = rearLeft; 198 | params.windowBackRight = rearRight; 199 | vehicle_->setParams(params); 200 | return true; 201 | } 202 | 203 | OMP_CAPI(Vehicle_GetParamsCarWindows, bool(objectPtr vehicle, int* frontLeft, int* frontRight, int* rearLeft, int* rearRight)) 204 | { 205 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 206 | const VehicleParams& params = vehicle_->getParams(); 207 | *frontLeft = params.windowDriver; 208 | *frontRight = params.windowPassenger; 209 | *rearLeft = params.windowBackLeft; 210 | *rearRight = params.windowBackRight; 211 | return true; 212 | } 213 | 214 | OMP_CAPI(Vehicle_SetToRespawn, bool(objectPtr vehicle)) 215 | { 216 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 217 | vehicle_->respawn(); 218 | return true; 219 | } 220 | 221 | OMP_CAPI(Vehicle_LinkToInterior, bool(objectPtr vehicle, int interiorid)) 222 | { 223 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 224 | vehicle_->setInterior(interiorid); 225 | return true; 226 | } 227 | 228 | OMP_CAPI(Vehicle_AddComponent, bool(objectPtr vehicle, int componentid)) 229 | { 230 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 231 | vehicle_->addComponent(componentid); 232 | return true; 233 | } 234 | 235 | OMP_CAPI(Vehicle_RemoveComponent, bool(objectPtr vehicle, int componentid)) 236 | { 237 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 238 | vehicle_->removeComponent(componentid); 239 | return true; 240 | } 241 | 242 | OMP_CAPI(Vehicle_ChangeColor, bool(objectPtr vehicle, int color1, int color2)) 243 | { 244 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 245 | vehicle_->setColour(color1, color2); 246 | return true; 247 | } 248 | 249 | OMP_CAPI(Vehicle_ChangePaintjob, bool(objectPtr vehicle, int paintjobid)) 250 | { 251 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 252 | vehicle_->setPaintJob(paintjobid); 253 | return true; 254 | } 255 | 256 | OMP_CAPI(Vehicle_SetHealth, bool(objectPtr vehicle, float health)) 257 | { 258 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 259 | vehicle_->setHealth(health); 260 | return true; 261 | } 262 | 263 | OMP_CAPI(Vehicle_GetHealth, float(objectPtr vehicle)) 264 | { 265 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0.0f); 266 | float health = vehicle_->getHealth(); 267 | return health; 268 | } 269 | 270 | OMP_CAPI(Vehicle_AttachTrailer, bool(objectPtr trailer, objectPtr vehicle)) 271 | { 272 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 273 | ENTITY_CAST_RET(IVehicle, trailer, trailer_, false); 274 | vehicle_->attachTrailer(*trailer_); 275 | return true; 276 | } 277 | 278 | OMP_CAPI(Vehicle_DetachTrailer, bool(objectPtr vehicle)) 279 | { 280 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 281 | vehicle_->detachTrailer(); 282 | return true; 283 | } 284 | 285 | OMP_CAPI(Vehicle_IsTrailerAttached, bool(objectPtr vehicle)) 286 | { 287 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 288 | return vehicle_->getTrailer() != nullptr; 289 | } 290 | 291 | OMP_CAPI(Vehicle_GetTrailer, objectPtr(objectPtr vehicle)) 292 | { 293 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, nullptr); 294 | IVehicle* trailer = vehicle_->getTrailer(); 295 | if (trailer) 296 | { 297 | return trailer; 298 | } 299 | return nullptr; 300 | } 301 | 302 | OMP_CAPI(Vehicle_SetNumberPlate, bool(objectPtr vehicle, StringCharPtr numberPlate)) 303 | { 304 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 305 | vehicle_->setPlate(numberPlate); 306 | return true; 307 | } 308 | 309 | OMP_CAPI(Vehicle_GetModel, int(objectPtr vehicle)) 310 | { 311 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0); 312 | return vehicle_->getModel(); 313 | } 314 | 315 | OMP_CAPI(Vehicle_GetComponentInSlot, int(objectPtr vehicle, int slot)) 316 | { 317 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0); 318 | return vehicle_->getComponentInSlot(slot); 319 | } 320 | 321 | OMP_CAPI(Vehicle_GetComponentType, int(int componentid)) 322 | { 323 | return Impl::getVehicleComponentSlot(componentid); 324 | } 325 | 326 | OMP_CAPI(Vehicle_CanHaveComponent, bool(int modelid, int componentid)) 327 | { 328 | return Impl::isValidComponentForVehicleModel(modelid, componentid); 329 | } 330 | 331 | OMP_CAPI(Vehicle_GetRandomColorPair, bool(int modelid, int* color1, int* color2, int* color3, int* color4)) 332 | { 333 | Impl::getRandomVehicleColour(modelid, *color1, *color2, *color3, *color4); 334 | return true; 335 | } 336 | 337 | OMP_CAPI(Vehicle_ColorIndexToColor, int(int colorIndex, int alpha)) 338 | { 339 | return Impl::carColourIndexToColour(colorIndex, alpha); 340 | } 341 | 342 | OMP_CAPI(Vehicle_Repair, bool(objectPtr vehicle)) 343 | { 344 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 345 | vehicle_->repair(); 346 | return true; 347 | } 348 | 349 | OMP_CAPI(Vehicle_GetVelocity, bool(objectPtr vehicle, float* x, float* y, float* z)) 350 | { 351 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 352 | const Vector3& velocity = vehicle_->getVelocity(); 353 | *x = velocity.x; 354 | *y = velocity.y; 355 | *z = velocity.z; 356 | return true; 357 | } 358 | 359 | OMP_CAPI(Vehicle_SetVelocity, bool(objectPtr vehicle, float x, float y, float z)) 360 | { 361 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 362 | vehicle_->setVelocity({ x, y, z }); 363 | return true; 364 | } 365 | 366 | OMP_CAPI(Vehicle_SetAngularVelocity, bool(objectPtr vehicle, float x, float y, float z)) 367 | { 368 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 369 | vehicle_->setAngularVelocity({ x, y, z }); 370 | return true; 371 | } 372 | 373 | OMP_CAPI(Vehicle_GetDamageStatus, bool(objectPtr vehicle, int* panels, int* doors, int* lights, int* tires)) 374 | { 375 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 376 | vehicle_->getDamageStatus(*panels, *doors, *lights, *tires); 377 | return true; 378 | } 379 | 380 | OMP_CAPI(Vehicle_UpdateDamageStatus, bool(objectPtr vehicle, int panels, int doors, int lights, int tires)) 381 | { 382 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 383 | vehicle_->setDamageStatus(panels, doors, lights, tires); 384 | return true; 385 | } 386 | 387 | OMP_CAPI(Vehicle_GetModelInfo, bool(int vehiclemodel, int infotype, float* x, float* y, float* z)) 388 | { 389 | Vector3 pos = {}; 390 | Impl::getVehicleModelInfo(vehiclemodel, VehicleModelInfoType(infotype), pos); 391 | *x = pos.x; 392 | *y = pos.y; 393 | *z = pos.z; 394 | return true; 395 | } 396 | 397 | OMP_CAPI(Vehicle_SetVirtualWorld, bool(objectPtr vehicle, int virtualWorld)) 398 | { 399 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 400 | vehicle_->setVirtualWorld(virtualWorld); 401 | return true; 402 | } 403 | 404 | OMP_CAPI(Vehicle_GetVirtualWorld, int(objectPtr vehicle)) 405 | { 406 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0); 407 | return vehicle_->getVirtualWorld(); 408 | } 409 | 410 | OMP_CAPI(Vehicle_GetLandingGearState, int(objectPtr vehicle)) 411 | { 412 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0); 413 | int state = !vehicle_->getLandingGearState(); 414 | return state; 415 | } 416 | 417 | OMP_CAPI(Vehicle_IsValid, bool(objectPtr vehicle)) 418 | { 419 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 420 | if (!vehicles->get(vehicle_->getID())) 421 | return false; 422 | return true; 423 | } 424 | 425 | OMP_CAPI(Vehicle_AddStatic, objectPtr(int modelid, float x, float y, float z, float angle, int color1, int color2, int* id)) 426 | { 427 | IVehiclesComponent* vehicles = ComponentManager().Get()->vehicles; 428 | if (vehicles) 429 | { 430 | IVehicle* vehicle = vehicles->create(true, modelid, { x, y, z }, angle, color1, color2, Seconds(120), false); 431 | if (vehicle) 432 | { 433 | *id = vehicle->getID(); 434 | return vehicle; 435 | } 436 | } 437 | return nullptr; 438 | } 439 | 440 | OMP_CAPI(Vehicle_AddStaticEx, objectPtr(int modelid, float x, float y, float z, float angle, int color1, int color2, int respawnDelay, bool addSiren, int* id)) 441 | { 442 | IVehiclesComponent* vehicles = ComponentManager().Get()->vehicles; 443 | if (vehicles) 444 | { 445 | IVehicle* vehicle = vehicles->create(true, modelid, { x, y, z }, angle, color1, color2, Seconds(respawnDelay), addSiren); 446 | if (vehicle) 447 | { 448 | *id = vehicle->getID(); 449 | return vehicle; 450 | } 451 | } 452 | return nullptr; 453 | } 454 | 455 | OMP_CAPI(Vehicle_EnableFriendlyFire, bool()) 456 | { 457 | *ComponentManager::Get()->core->getConfig().getBool("game.use_vehicle_friendly_fire") = true; 458 | return true; 459 | } 460 | 461 | OMP_CAPI(Vehicle_GetSpawnInfo, bool(objectPtr vehicle, float* x, float* y, float* z, float* rotation, int* color1, int* color2)) 462 | { 463 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 464 | const VehicleSpawnData& data = vehicle_->getSpawnData(); 465 | 466 | *x = data.position.x; 467 | *y = data.position.y; 468 | *z = data.position.z; 469 | *rotation = data.zRotation; 470 | *color1 = data.colour1; 471 | *color2 = data.colour2; 472 | return true; 473 | } 474 | 475 | OMP_CAPI(Vehicle_SetSpawnInfo, bool(objectPtr vehicle, int modelid, float x, float y, float z, float rotation, int color1, int color2, int respawn_time, int interior)) 476 | { 477 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 478 | const VehicleSpawnData& data = vehicle_->getSpawnData(); 479 | 480 | vehicle_->setSpawnData({ respawn_time >= -1 ? Seconds(respawn_time) : data.respawnDelay, modelid, { x, y, z }, rotation, color1, color2, data.siren, interior != -2 ? interior : data.interior }); 481 | return true; 482 | } 483 | 484 | OMP_CAPI(Vehicle_GetModelCount, int(int modelid)) 485 | { 486 | if (modelid < 400 || modelid > 611) 487 | return 0; 488 | 489 | auto& models = ComponentManager::Get()->vehicles->models(); 490 | int count = models[modelid - 400]; 491 | return count; 492 | } 493 | 494 | OMP_CAPI(Vehicle_GetModelsUsed, int()) 495 | { 496 | auto& vehicle_models = ComponentManager::Get()->vehicles->models(); 497 | 498 | int models = std::count_if(vehicle_models.begin(), vehicle_models.end(), [](uint8_t model_instances) 499 | { 500 | return model_instances > 0; 501 | }); 502 | return models; 503 | } 504 | 505 | OMP_CAPI(Vehicle_GetPaintjob, int(objectPtr vehicle)) 506 | { 507 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0); 508 | return vehicle_->getPaintJob(); 509 | } 510 | 511 | OMP_CAPI(Vehicle_GetColor, bool(objectPtr vehicle, int* color1, int* color2)) 512 | { 513 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 514 | Pair colors = vehicle_->getColour(); 515 | 516 | *color1 = colors.first; 517 | *color2 = colors.second; 518 | return true; 519 | } 520 | 521 | OMP_CAPI(Vehicle_GetInterior, int(objectPtr vehicle)) 522 | { 523 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0); 524 | return vehicle_->getInterior(); 525 | } 526 | 527 | OMP_CAPI(Vehicle_GetNumberPlate, bool(objectPtr vehicle, OutputStringViewPtr numberPlate)) 528 | { 529 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0); 530 | StringView plate = vehicle_->getPlate(); 531 | SET_CAPI_STRING_VIEW(numberPlate, plate); 532 | return true; 533 | } 534 | 535 | OMP_CAPI(Vehicle_SetRespawnDelay, bool(objectPtr vehicle, int respawn_delay)) 536 | { 537 | if (respawn_delay < -1) 538 | { 539 | return false; 540 | } 541 | 542 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 543 | vehicle_->setRespawnDelay(Seconds(respawn_delay)); 544 | return true; 545 | } 546 | 547 | OMP_CAPI(Vehicle_GetRespawnDelay, int(objectPtr vehicle)) 548 | { 549 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0); 550 | int delay = vehicle_->getRespawnDelay().count(); 551 | return delay; 552 | } 553 | 554 | OMP_CAPI(Vehicle_GetCab, objectPtr(objectPtr vehicle)) 555 | { 556 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, nullptr); 557 | return vehicle_->getCab(); 558 | } 559 | 560 | OMP_CAPI(Vehicle_GetTower, objectPtr(objectPtr vehicle)) 561 | { 562 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, nullptr); 563 | return vehicle_->getCab(); 564 | } 565 | 566 | OMP_CAPI(Vehicle_GetOccupiedTick, int(objectPtr vehicle)) 567 | { 568 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0); 569 | int tick = std::chrono::duration_cast(Time::now() - vehicle_->getLastOccupiedTime()).count(); 570 | return tick; 571 | } 572 | 573 | OMP_CAPI(Vehicle_GetRespawnTick, int(objectPtr vehicle)) 574 | { 575 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0); 576 | int tick = std::chrono::duration_cast(Time::now() - vehicle_->getLastSpawnTime()).count(); 577 | return tick; 578 | } 579 | 580 | OMP_CAPI(Vehicle_HasBeenOccupied, bool(objectPtr vehicle)) 581 | { 582 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 583 | bool occupied = vehicle_->hasBeenOccupied(); 584 | return occupied; 585 | } 586 | 587 | OMP_CAPI(Vehicle_IsOccupied, bool(objectPtr vehicle)) 588 | { 589 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 590 | bool occupied = vehicle_->isOccupied(); 591 | return occupied; 592 | } 593 | 594 | OMP_CAPI(Vehicle_IsDead, bool(objectPtr vehicle)) 595 | { 596 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 597 | bool dead = vehicle_->isDead(); 598 | return dead; 599 | } 600 | 601 | OMP_CAPI(Vehicle_SetParamsSirenState, bool(objectPtr vehicle, bool siren_state)) 602 | { 603 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 604 | VehicleParams params = vehicle_->getParams(); 605 | params.siren = siren_state; 606 | 607 | vehicle_->setParams(params); 608 | return true; 609 | } 610 | 611 | OMP_CAPI(Vehicle_ToggleSirenEnabled, bool(objectPtr vehicle, bool status)) 612 | { 613 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 614 | vehicle_->setSiren(status); 615 | return true; 616 | } 617 | 618 | OMP_CAPI(Vehicle_IsSirenEnabled, bool(objectPtr vehicle)) 619 | { 620 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 621 | bool enabled = vehicle_->getSpawnData().siren; 622 | return enabled; 623 | } 624 | 625 | OMP_CAPI(Vehicle_GetLastDriver, objectPtr(objectPtr vehicle)) 626 | { 627 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, nullptr); 628 | int lastDriver = vehicle_->getLastDriverPoolID(); 629 | 630 | auto players = ComponentManager::Get()->players; 631 | if (players) 632 | { 633 | return players->get(lastDriver); 634 | } 635 | 636 | return nullptr; 637 | } 638 | 639 | OMP_CAPI(Vehicle_GetDriver, objectPtr(objectPtr vehicle)) 640 | { 641 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, nullptr); 642 | return vehicle_->getDriver(); 643 | } 644 | 645 | OMP_CAPI(Player_IsInModShop, bool(objectPtr player)) 646 | { 647 | POOL_ENTITY_RET(players, IPlayer, player, player_, false); 648 | IPlayerVehicleData* data = queryExtension(player_); 649 | if (data) 650 | { 651 | return data->isInModShop(); 652 | } 653 | return false; 654 | } 655 | 656 | OMP_CAPI(Player_GetSirenState, int(objectPtr player)) 657 | { 658 | POOL_ENTITY_RET(players, IPlayer, player, player_, 0); 659 | IPlayerVehicleData* data = queryExtension(player_); 660 | IVehicle* vehicle = data->getVehicle(); 661 | if (vehicle) 662 | { 663 | return vehicle->getSirenState(); 664 | } 665 | return 0; 666 | } 667 | 668 | OMP_CAPI(Player_GetLandingGearState, int(objectPtr player)) 669 | { 670 | POOL_ENTITY_RET(players, IPlayer, player, player_, 0); 671 | IPlayerVehicleData* data = queryExtension(player_); 672 | IVehicle* vehicle = data->getVehicle(); 673 | if (vehicle) 674 | { 675 | int state = vehicle->getLandingGearState(); 676 | return state; 677 | } 678 | return 0; 679 | } 680 | 681 | OMP_CAPI(Player_GetHydraReactorAngle, uint32_t(objectPtr player)) 682 | { 683 | POOL_ENTITY_RET(players, IPlayer, player, player_, 0); 684 | IPlayerVehicleData* data = queryExtension(player_); 685 | IVehicle* vehicle = data->getVehicle(); 686 | if (vehicle) 687 | { 688 | return vehicle->getHydraThrustAngle(); 689 | } 690 | return 0; 691 | } 692 | 693 | OMP_CAPI(Player_GetTrainSpeed, float(objectPtr player)) 694 | { 695 | POOL_ENTITY_RET(players, IPlayer, player, player_, 0.0f); 696 | IPlayerVehicleData* data = queryExtension(player_); 697 | IVehicle* vehicle = data->getVehicle(); 698 | if (vehicle) 699 | { 700 | return vehicle->getTrainSpeed(); 701 | } 702 | return 0.0f; 703 | } 704 | 705 | OMP_CAPI(Vehicle_GetSirenState, int(objectPtr vehicle)) 706 | { 707 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0); 708 | return vehicle_->getSirenState(); 709 | } 710 | 711 | OMP_CAPI(Vehicle_GetHydraReactorAngle, uint32_t(objectPtr vehicle)) 712 | { 713 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0); 714 | return vehicle_->getHydraThrustAngle(); 715 | } 716 | 717 | OMP_CAPI(Vehicle_GetTrainSpeed, float(objectPtr vehicle)) 718 | { 719 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0.0f); 720 | return vehicle_->getTrainSpeed(); 721 | } 722 | 723 | OMP_CAPI(Vehicle_GetMatrix, bool(objectPtr vehicle, float* rightX, float* rightY, float* rightZ, float* upX, float* upY, float* upZ, float* atX, float* atY, float* atZ)) 724 | { 725 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, false); 726 | glm::mat3 mat = glm::transpose(glm::mat3_cast(vehicle_->getRotation().q)); 727 | 728 | *rightX = mat[0][0]; 729 | *rightY = mat[0][1]; 730 | *rightZ = mat[0][2]; 731 | *upX = mat[1][0]; 732 | *upY = mat[1][1]; 733 | *upZ = mat[1][2]; 734 | *atX = mat[2][0]; 735 | *atY = mat[2][1]; 736 | *atZ = mat[2][2]; 737 | return true; 738 | } 739 | 740 | OMP_CAPI(Vehicle_GetOccupant, objectPtr(objectPtr vehicle, int seat)) 741 | { 742 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, nullptr); 743 | IPlayer* driver = vehicle_->getDriver(); 744 | // Looking for driver 745 | if (seat == 0) 746 | { 747 | return driver; 748 | } 749 | // Looking for a passenger 750 | else 751 | { 752 | const FlatHashSet& passengers = vehicle_->getPassengers(); 753 | for (auto& passenger : passengers) 754 | { 755 | if (passenger) 756 | { 757 | IPlayerVehicleData* data = queryExtension(passenger); 758 | if (data && data->getSeat() == seat) 759 | { 760 | return passenger; 761 | } 762 | } 763 | } 764 | } 765 | return nullptr; 766 | } 767 | 768 | OMP_CAPI(Vehicle_CountOccupants, int(objectPtr vehicle)) 769 | { 770 | POOL_ENTITY_RET(vehicles, IVehicle, vehicle, vehicle_, 0); 771 | IPlayer* driver = vehicle_->getDriver(); 772 | const FlatHashSet& passengers = vehicle_->getPassengers(); 773 | int occupants = 0; 774 | 775 | if (driver) 776 | { 777 | occupants++; 778 | } 779 | occupants += passengers.size(); 780 | 781 | return occupants; 782 | } 783 | --------------------------------------------------------------------------------