├── docs
├── articles
│ ├── api-reference
│ │ ├── api.md
│ │ └── events.md
│ ├── stylesheets
│ │ └── extra.css
│ ├── vehicle.md
│ ├── colshapes.md
│ ├── vectors.md
│ ├── index.md
│ ├── intro.md
│ ├── tasks.md
│ ├── additional-information.md
│ └── events.md
├── alt
│ ├── __init__.py
│ └── events.py
├── README.md
└── mkdocs.yml
├── stubs
├── .gitignore
├── setup.py
├── setup.cfg
└── README.md
├── .editorconfig
├── src
├── bindings
│ ├── bindings.hpp
│ ├── bindings.cpp
│ ├── log.cpp
│ ├── intervals.cpp
│ ├── events.cpp
│ └── alt.cpp
├── main.hpp
├── main.cpp
├── events
│ ├── events.cpp
│ ├── events.hpp
│ ├── vehicle.cpp
│ ├── meta.cpp
│ ├── Main.cpp
│ └── player.cpp
├── utils.hpp
├── classes
│ ├── base
│ │ ├── worldobject.cpp
│ │ ├── voicechannel.cpp
│ │ ├── baseobject.cpp
│ │ ├── checkpoint.cpp
│ │ ├── colshape.cpp
│ │ ├── entity.cpp
│ │ ├── blip.cpp
│ │ ├── player.cpp
│ │ └── vehicle.cpp
│ ├── types
│ │ ├── rgba.cpp
│ │ ├── resource.cpp
│ │ ├── connectioninfo.cpp
│ │ ├── enums.cpp
│ │ ├── vehiclemodelinfo.cpp
│ │ ├── vector2.hpp
│ │ ├── resource.hpp
│ │ ├── vector3.hpp
│ │ ├── vector2.cpp
│ │ ├── vector3.cpp
│ │ └── enums.hpp
│ └── classes.hpp
├── interval.hpp
├── PythonRuntime.hpp
├── interval.cpp
├── PythonResource.hpp
├── PythonRuntime.cpp
├── utils.cpp
└── PythonResource.cpp
├── .gitmodules
├── .gitignore
├── README.md
├── cmake
└── python.cmake
├── CMakeLists.txt
├── .clang-format
└── .github
└── workflows
└── build.yml
/docs/articles/api-reference/api.md:
--------------------------------------------------------------------------------
1 | ::: alt
--------------------------------------------------------------------------------
/docs/articles/api-reference/events.md:
--------------------------------------------------------------------------------
1 | ::: alt.events
--------------------------------------------------------------------------------
/docs/alt/__init__.py:
--------------------------------------------------------------------------------
1 | ../../stubs/alt-stubs/__init__.pyi
--------------------------------------------------------------------------------
/stubs/.gitignore:
--------------------------------------------------------------------------------
1 | altv_stubs.egg-info/
2 | build/
3 | dist/
--------------------------------------------------------------------------------
/stubs/setup.py:
--------------------------------------------------------------------------------
1 | from setuptools import setup
2 |
3 |
4 | setup(
5 | name="altv-stubs",
6 | packages=["alt-stubs"],
7 | package_data={"alt-stubs": ["__init__.pyi"]},
8 | )
9 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 4
6 | end_of_line = crlf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
--------------------------------------------------------------------------------
/src/bindings/bindings.hpp:
--------------------------------------------------------------------------------
1 | #include "main.hpp"
2 |
3 | void RegisterLogFunctions(py::module_ m);
4 | void RegisterEventFunctions(py::module_ m);
5 | void RegisterMainFunctions(py::module_ m);
6 | void RegisterIntervalFunctions(py::module_ m);
7 |
--------------------------------------------------------------------------------
/stubs/setup.cfg:
--------------------------------------------------------------------------------
1 | [metadata]
2 | name = alt-stubs
3 | version = 1.0.1
4 | license = MIT
5 | author = ZackaryH8 & Marvis
6 | url = https://github.com/ZackaryH8/altv-python-stubs
7 | description = Stubs for alt:V Python Module
8 | long_description = file: README.md
9 | long_description_content_type = text/markdown
10 | keywords = mypy, altv
11 |
--------------------------------------------------------------------------------
/stubs/README.md:
--------------------------------------------------------------------------------
1 | # altv-python-stubs
2 |
3 | # What is this?
4 | This is a file to allow autocomplete for the alt:V Python Module. A manual approach was chosen for this because the autogenerated ones were not great. Based on [alt:V Types](https://github.com/altmp/altv-types).
5 |
6 | # Installation
7 | ```
8 | $ pip install altv-stubs
9 | ```
10 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "vendors/cpp-sdk"]
2 | path = vendors/cpp-sdk
3 | url = https://github.com/altmp/cpp-sdk
4 | [submodule "vendors/magic_enum"]
5 | path = vendors/magic_enum
6 | url = https://github.com/Neargye/magic_enum
7 | ignore = dirty
8 | [submodule "vendors/pybind11"]
9 | path = vendors/pybind11
10 | url = https://github.com/pybind/pybind11
11 | branch = stable
12 |
--------------------------------------------------------------------------------
/src/main.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define ALT_SERVER_API
4 |
5 | #ifdef _WIN32
6 | static char SEPARATOR = '\\';
7 | #else
8 | static char SEPARATOR = '/';
9 | #endif
10 |
11 | // Standard C++ stuff
12 | #include
13 | #include
6 |
7 | ## [Docs](https://marvisak.github.io/altv-python-module/)
8 |
9 | ## How to install
10 | 1) Download the newest version from [Releases](https://github.com/Marvisak/altv-python-module/releases)
11 | 2) Open the zip file
12 | 3) Drag & Drop files from the zip into your server's modules folder
13 | 4) Open your server's server.cfg and add the module:
14 | ```
15 | modules: [ python-module ]
16 | ```
17 |
18 | # I really appreciate any contribution
19 |
--------------------------------------------------------------------------------
/src/interval.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "main.hpp"
3 |
4 | class Interval
5 | {
6 | private:
7 | double milliseconds;
8 | py::function function;
9 | uint32_t nextTime;
10 | bool running = true;
11 | PyThreadState* interpreter;
12 |
13 | public:
14 | Interval(double milliseconds, py::function function, PyThreadState* interpreter);
15 |
16 | py::function GetFunc()
17 | {
18 | return function;
19 | }
20 |
21 | void SetRunning(bool start)
22 | {
23 | running = start;
24 | }
25 |
26 | bool IsRunning() const
27 | {
28 | return running;
29 | }
30 |
31 | void SetMilliseconds(double newMilliseconds)
32 | {
33 | milliseconds = newMilliseconds;
34 | }
35 |
36 | void TimeWarning(uint32_t time, const std::string& resourceName);
37 |
38 | bool Update(uint32_t time);
39 | };
40 |
--------------------------------------------------------------------------------
/src/PythonRuntime.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "PythonResource.hpp"
4 | #include "events/events.hpp"
5 | #include "main.hpp"
6 |
7 | class PythonRuntime : public alt::IScriptRuntime
8 | {
9 | std::vector resources{};
10 | PyThreadState* mainInterpreter;
11 | static PythonRuntime* instance;
12 | #ifdef __linux__
13 | void* python;
14 | #endif
15 | public:
16 | PythonRuntime();
17 | alt::IResource::Impl* CreateImpl(alt::IResource* resource) override;
18 | void DestroyImpl(alt::IResource::Impl* impl) override;
19 | void OnDispose() override;
20 | PythonResource* GetPythonResourceFromInterp(PyThreadState* state);
21 |
22 | PyThreadState* GetInterpreter()
23 | {
24 | return mainInterpreter;
25 | }
26 |
27 | static PythonRuntime* GetInstance()
28 | {
29 | return instance;
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/docs/articles/vehicle.md:
--------------------------------------------------------------------------------
1 | # Vehicle
2 |
3 | If you want to drive a vehicle you need to create it first. You can create them from serverside, and they will be completely synced.
4 |
5 |
6 | ```py
7 | import alt
8 |
9 | vehicle = alt.Vehicle("elegy", 10, 10, 10, 0, 0, 0) # Creates vehicle with the model elegy on 10,10,10 with 0,0,0 rotation
10 | vehicle2 = alt.Vehicle(alt.hash("panto"), alt.Vector3(40, 40, 40), alt.Vector3(20, 20, 20)) # Creates vehicle with model panto on 40,40,40 with 20,20,20 rotation
11 | ```
12 |
13 | Vehicles have a lot of properties and methods you can use to edit them
14 |
15 | ```py
16 | vehicle.primary_color_rgb = alt.RGBA(255, 0, 0) # Makes the spawned vehicle red
17 | ```
18 |
19 | You can see all the methods and properties you can use on vehicle in our stubs or inside the [API Reference](api-reference/api.md)
20 |
21 |
--------------------------------------------------------------------------------
/src/bindings/bindings.cpp:
--------------------------------------------------------------------------------
1 | #include "bindings.hpp"
2 | #include "classes/classes.hpp"
3 | #include "main.hpp"
4 |
5 | PYBIND11_EMBEDDED_MODULE(alt, m)
6 | {
7 | m.doc() = "alt:V Python Module";
8 |
9 | RegisterEnums(m);
10 | RegisterVector2Class(m);
11 | RegisterVector3Class(m);
12 | RegisterRGBAClass(m);
13 | RegisterConnectionInfoClass(m);
14 | RegisterVehicleModelInfoClass(m);
15 | RegisterResourceClass(m);
16 |
17 | RegisterBaseObjectClass(m);
18 | RegisterWorldObjectClass(m);
19 | RegisterEntityClass(m);
20 | RegisterVehicleClass(m);
21 | RegisterPlayerClass(m);
22 | RegisterColShapeClass(m);
23 | RegisterBlipClass(m);
24 | RegisterCheckpointClass(m);
25 | RegisterVoiceChannelClass(m);
26 |
27 | RegisterLogFunctions(m);
28 | RegisterEventFunctions(m);
29 | RegisterMainFunctions(m);
30 | RegisterIntervalFunctions(m);
31 | }
32 |
--------------------------------------------------------------------------------
/src/events/events.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "main.hpp"
3 |
4 | class EventHandler
5 | {
6 | static std::unordered_map& all()
7 | {
8 | static std::unordered_map _all;
9 | return _all;
10 | }
11 | using ArgsGetter = std::function;
12 | std::optional argsGetter;
13 |
14 | public:
15 | EventHandler(alt::CEvent::Type eventType, ArgsGetter argsGetter);
16 | // TODO probably remove this
17 | explicit EventHandler(alt::CEvent::Type eventType);// This is kinda useless, currently it's only used to know that the event is registered, might be removed in the future, but I'll keep it here now
18 | void GetEventArgs(const alt::CEvent* event, py::list& args);
19 |
20 | static EventHandler* Get(const alt::CEvent* event);
21 | };
22 |
--------------------------------------------------------------------------------
/src/classes/types/rgba.cpp:
--------------------------------------------------------------------------------
1 | #include "classes/classes.hpp"
2 |
3 | std::string ToString(alt::RGBA _this)
4 | {
5 | return "RGBA(" + std::to_string(_this.r) + ", " + std::to_string(_this.g) + ", " + std::to_string(_this.b) + ", " + std::to_string(_this.a) + ")";
6 | }
7 |
8 | py::list ToList(alt::RGBA _this)
9 | {
10 | py::list list;
11 | list.append(_this.r);
12 | list.append(_this.g);
13 | list.append(_this.b);
14 | list.append(_this.a);
15 | return list;
16 | }
17 |
18 | void RegisterRGBAClass(const py::module_& m)
19 | {
20 | auto pyClass = py::class_(m, "RGBA");
21 | pyClass.def(py::init(), py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a") = 255);
22 | pyClass.def_readwrite("r", &alt::RGBA::r);
23 | pyClass.def_readwrite("g", &alt::RGBA::g);
24 | pyClass.def_readwrite("b", &alt::RGBA::b);
25 | pyClass.def_readwrite("a", &alt::RGBA::a);
26 | pyClass.def("to_bgra", &alt::RGBA::toBGRA);
27 | pyClass.def("to_argb", &alt::RGBA::toARGB);
28 | pyClass.def("to_list", &ToList);
29 | pyClass.def("__str__", &ToString);
30 | }
31 |
--------------------------------------------------------------------------------
/src/classes/classes.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "main.hpp"
3 |
4 | PYBIND11_DECLARE_HOLDER_TYPE(T, alt::Ref, true)
5 |
6 | namespace pybind11::detail
7 | {
8 | template
9 | struct holder_helper> {
10 | static const T* get(const alt::Ref& p)
11 | {
12 | return p.Get();
13 | }
14 | };
15 | }// namespace pybind11::detail
16 |
17 | void RegisterEnums(const py::module_& m);
18 | void RegisterRGBAClass(const py::module_& m);
19 | void RegisterConnectionInfoClass(const py::module_& m);
20 | void RegisterVehicleModelInfoClass(const py::module_& m);
21 | void RegisterVector2Class(const py::module_& m);
22 | void RegisterVector3Class(const py::module_& m);
23 | void RegisterBaseObjectClass(const py::module_& m);
24 | void RegisterWorldObjectClass(const py::module_& m);
25 | void RegisterEntityClass(const py::module_& m);
26 | void RegisterPlayerClass(const py::module_& m);
27 | void RegisterVehicleClass(const py::module_& m);
28 | void RegisterColShapeClass(const py::module_& m);
29 | void RegisterResourceClass(const py::module_& m);
30 | void RegisterBlipClass(const py::module_& m);
31 | void RegisterCheckpointClass(const py::module_& m);
32 | void RegisterVoiceChannelClass(const py::module_& m);
33 |
--------------------------------------------------------------------------------
/src/classes/types/resource.cpp:
--------------------------------------------------------------------------------
1 | #include "resource.hpp"
2 |
3 | void RegisterResourceClass(const py::module_& m)
4 | {
5 | auto pyClass = py::class_(m, "Resource");
6 | pyClass.def_property_readonly("is_started", &Resource::IsStarted);
7 | pyClass.def_property_readonly("type", &Resource::GetType);
8 | pyClass.def_property_readonly("name", &Resource::GetName);
9 | pyClass.def_property_readonly("main", &Resource::GetMain);
10 | pyClass.def_property_readonly("path", &Resource::GetPath);
11 | pyClass.def_property_readonly("config", &Resource::GetConfig);
12 | pyClass.def_property_readonly("exports", &Resource::GetExports);
13 | pyClass.def_property_readonly("dependencies", &Resource::GetDependencies);
14 | pyClass.def_property_readonly("dependants", &Resource::GetDependants);
15 | pyClass.def_property_readonly("required_permissions", &Resource::GetRequiredPermissions);
16 | pyClass.def_property_readonly("optional_permissions", &Resource::GetOptionalPermissions);
17 |
18 | pyClass.def_static("get_by_name", &Resource::GetByName, py::arg("resource_name"));
19 | pyClass.def_property_readonly_static("all", &Resource::GetAllResources);
20 | pyClass.def_property_readonly_static("current", &Resource::GetCurrent);
21 | }
22 |
--------------------------------------------------------------------------------
/src/bindings/log.cpp:
--------------------------------------------------------------------------------
1 | #include "main.hpp"
2 |
3 | void Log(const py::args& args, const std::string& separator = " ")
4 | {
5 | std::string str;
6 | for (const py::handle& arg : args)
7 | {
8 | if (!str.empty())
9 | str += separator;
10 | str += py::str(arg).cast();
11 | }
12 | alt::ICore::Instance().LogColored(str);
13 | }
14 |
15 | void LogError(const py::args& args, const std::string& separator = " ")
16 | {
17 | std::string str;
18 | for (const py::handle& arg : args)
19 | {
20 | if (!str.empty())
21 | str += separator;
22 | str += py::str(arg).cast();
23 | }
24 | alt::ICore::Instance().LogError(str);
25 | }
26 |
27 | void LogWarning(const py::args& args, const std::string& separator = " ")
28 | {
29 | std::string str;
30 | for (const py::handle& arg : args)
31 | {
32 | if (!str.empty())
33 | str += separator;
34 | str += py::str(arg).cast();
35 | }
36 | alt::ICore::Instance().LogWarning(str);
37 | }
38 |
39 | void RegisterLogFunctions(py::module_ m)
40 | {
41 | m.def("log", &Log, py::arg("sep") = " ", "Logs text to the console");
42 | m.def("log_error", &LogError, py::arg("sep") = " ", "Logs error to the console");
43 | m.def("log_warning", &LogWarning, py::arg("sep") = " ", "Logs warning to the console");
44 | }
45 |
--------------------------------------------------------------------------------
/src/interval.cpp:
--------------------------------------------------------------------------------
1 | #include "interval.hpp"
2 | #include "PythonRuntime.hpp"
3 |
4 | Interval::Interval(double milliseconds, py::function function, PyThreadState* interpreter)
5 | : milliseconds(milliseconds), function(std::move(function)), interpreter(interpreter)
6 | {
7 | nextTime = alt::ICore::Instance().GetNetTime() + (long)milliseconds;
8 | }
9 |
10 | void Interval::TimeWarning(uint32_t time, const std::string& resourceName)
11 | {
12 | auto inspect = py::module_::import("inspect");
13 | auto path = inspect.attr("getfile")(function).cast();
14 | std::string str = std::string("Interval at ").append(resourceName).append(":").append(path.substr(path.find_last_of("/\\") + 1)).append(" at function ").append(function.attr("__name__").cast()).append(" was too long ").append(std::to_string(alt::ICore::Instance().GetNetTime() - time)).append("ms");
15 | alt::ICore::Instance().LogWarning(str);
16 | }
17 |
18 | bool Interval::Update(uint32_t time)
19 | {
20 | if (time >= nextTime && running)
21 | {
22 | try
23 | {
24 | PyThreadState_Swap(interpreter);
25 | function();
26 | PyThreadState_Swap(PythonRuntime::GetInstance()->GetInterpreter());
27 | }
28 | catch (py::error_already_set& e)
29 | {
30 | e.discard_as_unraisable(function.attr("__name__"));
31 | }
32 | nextTime = time + (long)milliseconds;
33 | return true;
34 | }
35 | return false;
36 | }
37 |
--------------------------------------------------------------------------------
/src/events/vehicle.cpp:
--------------------------------------------------------------------------------
1 | #include "events.hpp"
2 | #include "utils.hpp"
3 |
4 | EventHandler vehicleDestroy(alt::CEvent::Type::VEHICLE_DESTROY, [](const alt::CEvent* ev, py::list& args) {
5 | auto event = dynamic_cast(ev);
6 | args.append(event->GetTarget().Get());
7 | });
8 |
9 | EventHandler vehicleDamage(alt::CEvent::Type::VEHICLE_DAMAGE, [](const alt::CEvent* ev, py::list& args) {
10 | auto event = dynamic_cast(ev);
11 | args.append(event->GetTarget().Get());
12 | args.append(Utils::GetBaseObject(event->GetDamager()));
13 | args.append(event->GetBodyHealthDamage());
14 | args.append(event->GetBodyAdditionalHealthDamage());
15 | args.append(event->GetEngineHealthDamage());
16 | args.append(event->GetPetrolTankHealthDamage());
17 | args.append(event->GetDamagedWith());
18 | });
19 |
20 | EventHandler vehicleAttach(alt::CEvent::Type::VEHICLE_ATTACH, [](const alt::CEvent* ev, py::list& args) {
21 | auto event = dynamic_cast(ev);
22 | args.append(event->GetTarget().Get());
23 | args.append(event->GetAttached().Get());
24 | });
25 |
26 | EventHandler vehicleDetach(alt::CEvent::Type::VEHICLE_DETACH, [](const alt::CEvent* ev, py::list& args) {
27 | auto event = dynamic_cast(ev);
28 | args.append(event->GetTarget().Get());
29 | args.append(event->GetDetached().Get());
30 | });
31 |
--------------------------------------------------------------------------------
/src/classes/types/connectioninfo.cpp:
--------------------------------------------------------------------------------
1 | #include "classes/classes.hpp"
2 |
3 | void RegisterConnectionInfoClass(const py::module_& m)
4 | {
5 | auto pyClass = py::class_>(m, "ConnectionInfo");
6 | pyClass.def_property_readonly("name", &alt::IConnectionInfo::GetName);
7 | pyClass.def_property_readonly("social_id", &alt::IConnectionInfo::GetSocialId);
8 | pyClass.def_property_readonly("hwid_hash", &alt::IConnectionInfo::GetHwIdHash);
9 | pyClass.def_property_readonly("hwid_ex_hash", &alt::IConnectionInfo::GetHwIdExHash);
10 | pyClass.def_property_readonly("auth_token", &alt::IConnectionInfo::GetAuthToken);
11 | pyClass.def_property_readonly("is_debug", &alt::IConnectionInfo::GetIsDebug);
12 | pyClass.def_property_readonly("branch", &alt::IConnectionInfo::GetBranch);
13 | pyClass.def_property_readonly("build", &alt::IConnectionInfo::GetBuild);
14 | pyClass.def_property_readonly("cdn_url", &alt::IConnectionInfo::GetCdnUrl);
15 | pyClass.def_property_readonly("password_hash", &alt::IConnectionInfo::GetPasswordHash);
16 | pyClass.def_property_readonly("ip", &alt::IConnectionInfo::GetIp);
17 | pyClass.def_property_readonly("discord_user_id", &alt::IConnectionInfo::GetDiscordUserID);
18 | pyClass.def_property_readonly("accepted", &alt::IConnectionInfo::IsAccepted);
19 |
20 | pyClass.def("accept", &alt::IConnectionInfo::Accept);
21 | pyClass.def("decline", &alt::IConnectionInfo::Decline, py::arg("reason"));
22 | }
23 |
--------------------------------------------------------------------------------
/src/classes/base/voicechannel.cpp:
--------------------------------------------------------------------------------
1 | #include "classes/classes.hpp"
2 |
3 | void RegisterVoiceChannelClass(const py::module_& m)
4 | {
5 | auto pyClass = py::class_>(m, "VoiceChannel");
6 |
7 | pyClass.def(py::init<>([](bool spatial, float maxDistance) {
8 | auto voiceChannel = alt::ICore::Instance().CreateVoiceChannel(spatial, maxDistance);
9 | if (voiceChannel)
10 | return voiceChannel.Get();
11 | throw std::runtime_error("Failed to create VoiceChannel, make sure voice chat is enabled");
12 | }),
13 | py::arg("spatial"), py::arg("max_distance"));
14 |
15 | pyClass.def_property_readonly("player_count", &alt::IVoiceChannel::GetPlayerCount);
16 | pyClass.def_property_readonly("players", &alt::IVoiceChannel::GetPlayers);
17 | pyClass.def_property_readonly("max_distance", &alt::IVoiceChannel::GetMaxDistance);
18 | pyClass.def_property_readonly("spatial", &alt::IVoiceChannel::IsSpatial);
19 |
20 | pyClass.def("add_player", &alt::IVoiceChannel::AddPlayer, py::arg("player"));
21 | pyClass.def("has_player", &alt::IVoiceChannel::HasPlayer, py::arg("player"));
22 | pyClass.def("is_player_muted", &alt::IVoiceChannel::IsPlayerMuted, py::arg("player"));
23 | pyClass.def("mute_player", &alt::IVoiceChannel::MutePlayer, py::arg("player"));
24 | pyClass.def("remove_player", &alt::IVoiceChannel::RemovePlayer);
25 | pyClass.def("unmute_player", &alt::IVoiceChannel::UnmutePlayer);
26 | }
27 |
--------------------------------------------------------------------------------
/src/classes/types/enums.cpp:
--------------------------------------------------------------------------------
1 | #include "enums.hpp"
2 | #include "classes/classes.hpp"
3 | #include "magic_enum.hpp"
4 |
5 | template
6 | void export_enum(const py::module_& m, const char* enumName)
7 | {
8 | py::enum_ enum_type(m, enumName);
9 | for (const auto& [value, name] : magic_enum::enum_entries())
10 | {
11 | enum_type.value(name.data(), value);
12 | }
13 | }
14 |
15 | void RegisterEnums(const py::module_& m)
16 | {
17 | export_enum(m, "BaseObjectType");
18 | export_enum(m, "WeatherType");
19 | export_enum(m, "WeaponTint");
20 | export_enum(m, "VehicleModType");
21 | export_enum(m, "WindowTint");
22 | export_enum(m, "RadioStation");
23 | export_enum(m, "VehicleLockState");
24 | export_enum(m, "VehicleDoorState");
25 | export_enum(m, "VehicleDoor");
26 | export_enum(m, "VehiclePart");
27 | export_enum(m, "VehiclePartDamage");
28 | export_enum(m, "VehicleBumper");
29 | export_enum(m, "VehicleBumperDamage");
30 | export_enum(m, "NumberPlateStyle");
31 | export_enum(m, "Event");
32 | export_enum(m, "ExplosionType");
33 | export_enum(m, "BodyPart");
34 | export_enum(m, "VehicleType");
35 | export_enum(m, "ColShapeType");
36 | export_enum(m, "BlipColor");
37 | export_enum(m, "BlipSprite");
38 | export_enum(m, "CheckpointType");
39 | export_enum(m, "ConnectDeniedReason");
40 | }
41 |
--------------------------------------------------------------------------------
/cmake/python.cmake:
--------------------------------------------------------------------------------
1 | include(ProcessorCount)
2 |
3 | function(DownloadPython py_version)
4 | set(_download_link https://www.python.org/ftp/python/${py_version}/Python-${py_version}.tgz)
5 | get_filename_component(_filename ${_download_link} NAME)
6 | set(_path ${CMAKE_CURRENT_BINARY_DIR}/${_filename})
7 | if (NOT EXISTS ${_path})
8 | message("Downloading ${_download_link}")
9 | file(DOWNLOAD ${_download_link} ${_path})
10 | execute_process(COMMAND ${CMAKE_COMMAND} -E tar xfz ${_path}
11 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
12 | RESULT_VARIABLE rv)
13 | if (NOT rv EQUAL 0)
14 | message(FATAL_ERROR "extraction failed")
15 | endif()
16 | endif()
17 | endfunction()
18 |
19 | function(CompilePython py_version)
20 | set(_filename Python-${py_version})
21 | set(_path ${CMAKE_CURRENT_BINARY_DIR}/${_filename})
22 | if (UNIX)
23 | if (NOT EXISTS ${_path}/pyconfig.h)
24 | message("Configuring Python")
25 | execute_process(COMMAND ./configure --enable-optimizations --enable-shared
26 | WORKING_DIRECTORY ${_path} OUTPUT_QUIET)
27 |
28 | ProcessorCount(cores)
29 | message("Compiling Python")
30 | execute_process(COMMAND make -j${cores}
31 | WORKING_DIRECTORY ${_path} OUTPUT_QUIET)
32 | endif()
33 |
34 | else()
35 | if (NOT EXISTS ${_path}/PCbuild/amd64)
36 | message("Compiling Python")
37 | execute_process(COMMAND PCBuild\\build.bat -p x64
38 | WORKING_DIRECTORY ${_path} OUTPUT_QUIET)
39 | endif()
40 | endif()
41 | endfunction()
--------------------------------------------------------------------------------
/src/classes/types/vehiclemodelinfo.cpp:
--------------------------------------------------------------------------------
1 | #include "classes/classes.hpp"
2 | #include "enums.hpp"
3 |
4 | VehicleType GetType(const alt::VehicleModelInfo& modelInfo)
5 | {
6 | return (VehicleType)modelInfo.modelType;
7 | }
8 |
9 | py::list GetAvailableModKits(const alt::VehicleModelInfo& modelInfo)
10 | {
11 | py::list list;
12 | for (auto modkit : modelInfo.modkits)
13 | list.append(modkit != 0xFFFF);
14 | return list;
15 | }
16 |
17 | void RegisterVehicleModelInfoClass(const py::module_& m)
18 | {
19 | auto pyClass = py::class_(m, "VehicleModelInfo");
20 | pyClass.def_readonly("title", &alt::VehicleModelInfo::title);
21 | pyClass.def_readonly("wheels_count", &alt::VehicleModelInfo::wheelsCount);
22 | pyClass.def_readonly("has_armored_windows", &alt::VehicleModelInfo::hasArmoredWindows);
23 | pyClass.def_readonly("primary_color", &alt::VehicleModelInfo::primaryColor);
24 | pyClass.def_readonly("secondary_color", &alt::VehicleModelInfo::secondaryColor);
25 | pyClass.def_readonly("pearl_color", &alt::VehicleModelInfo::pearlColor);
26 | pyClass.def_readonly("wheels_color", &alt::VehicleModelInfo::wheelsColor);
27 | pyClass.def_readonly("interior_color", &alt::VehicleModelInfo::interiorColor);
28 | pyClass.def_readonly("dashboard_color", &alt::VehicleModelInfo::dashboardColor);
29 | pyClass.def_readonly("has_auto_attach_trailer", &alt::VehicleModelInfo::hasAutoAttachTrailer);
30 |
31 | pyClass.def_property_readonly("type", &GetType);
32 | pyClass.def_property_readonly("available_modkits", &GetAvailableModKits);
33 |
34 | pyClass.def("has_extra", &alt::VehicleModelInfo::DoesExtraExist, py::arg("extra_id"));
35 | pyClass.def("has_default_extra", &alt::VehicleModelInfo::DoesExtraDefault, py::arg("extra_id"));
36 | }
37 |
--------------------------------------------------------------------------------
/docs/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: alt:V Python Module
2 |
3 | theme:
4 | name: material
5 | palette:
6 | - media: "(prefers-color-scheme: light)"
7 | scheme: default
8 | toggle:
9 | icon: material/toggle-switch-off-outline
10 | name: Switch to dark mode
11 | - media: "(prefers-color-scheme: dark)"
12 | scheme: slate
13 | toggle:
14 | icon: material/toggle-switch
15 | name: Switch to light mode
16 | icon:
17 | repo: fontawesome/brands/github-alt
18 |
19 | docs_dir: articles
20 | repo_name: Marvisak/altv-python-module
21 | repo_url: https://github.com/Marvisak/altv-python-module
22 | edit_uri: edit/dev/docs/articles
23 |
24 | extra_css:
25 | - stylesheets/extra.css
26 |
27 | plugins:
28 | - mkdocstrings:
29 | handlers:
30 | python:
31 | import:
32 | - https://docs.python.org/3/objects.inv
33 | - https://mkdocstrings.github.io/objects.inv
34 | - https://mkdocstrings.github.io/griffe/objects.inv
35 | rendering:
36 | show_if_no_docstring: True
37 | show_source: False
38 | show_signature_annotations: True
39 | merge_init_into_class: True
40 | members_order: source
41 |
42 | markdown_extensions:
43 | - md_in_html
44 | - admonition
45 | - pymdownx.details
46 | - pymdownx.superfences
47 | - pymdownx.inlinehilite
48 |
49 |
50 | nav:
51 | - Home: "index.md"
52 | - Intro: "intro.md"
53 | - Events: "events.md"
54 | - Tasks and Timers: "tasks.md"
55 | - Vectors: "vectors.md"
56 | - Vehicle: "vehicle.md"
57 | - ColShapes: "colshapes.md"
58 | - Additional Information: "additional-information.md"
59 | - API Reference:
60 | Events: "api-reference/events.md"
61 | API: "api-reference/api.md"
62 |
--------------------------------------------------------------------------------
/docs/articles/colshapes.md:
--------------------------------------------------------------------------------
1 | # ColShapes
2 |
3 | ColShapes are collision zones which can detect entities entering them/leaving them
4 |
5 | There are 6 types of colShapes:
6 | - Circle
7 | - Cylinder
8 | - Sphere
9 | - Cube
10 | - Rectangle
11 | - Polygon
12 | - Checkpoint
13 |
14 | All of them work differently, we are going to take a look at Circle and later at Checkpoint
15 |
16 | ```py
17 | import alt
18 |
19 | test_colshape = alt.ColShape.circle(0, 0, 20)
20 |
21 | @alt.event(alt.Event.ColShape)
22 | def colshape_event(colshape: alt.ColShape, entity: alt.Entity, state: bool) -> None:
23 | if colshape != test_colshape: # If it isn't our ColShape we can return
24 | return
25 |
26 | if isinstance(entity, alt.Player):
27 | if state: # Entered colshape
28 | alt.log(f"Player {entity.name} just entered colshape.")
29 | else:
30 | alt.log(f"Player {entity.name} just leaved colshape.")
31 | ```
32 |
33 | This code will output text when player enters and leaves colshape.
34 |
35 | ## Checkpoints
36 |
37 | Checkpoints are little different from ColShapes. The biggest change is that the player can see the ColShape.
38 |
39 | ```py
40 | import alt
41 |
42 | checkpoint = alt.Checkpoint(alt.CheckpointType.Ring, 0, 0, 70, 2, 2, 255, 0, 0, 255)
43 |
44 | @alt.event(alt.Event.ColShape)
45 | def colshape_event(colshape: alt.ColShape, entity: alt.Entity, state: bool) -> None:
46 | if colshape != checkpoint: # If it isn't our Checkpoint we can return
47 | return
48 |
49 | if isinstance(entity, alt.Player):
50 | if state: # Entered checkpoint
51 | alt.log(f"Player {entity.name} just entered checkpoint.")
52 | else:
53 | alt.log(f"Player {entity.name} just leaved checkpoint.")
54 | ```
55 |
56 |
57 |
--------------------------------------------------------------------------------
/docs/articles/vectors.md:
--------------------------------------------------------------------------------
1 | # Vectors
2 |
3 | In order to progress forward we need to learn about vectors
4 |
5 | We have 2 types of vectors, Vector3 and Vector2
6 |
7 | ## Vector3
8 |
9 | This is the vector you are probably going to use the most
10 |
11 | You can create Vector3 like this: `alt.Vector3(0, 0, 0)` and replacing the 0 with your required number
12 |
13 | You can perform most mathematical operations on vectors
14 |
15 | ```py
16 | import alt
17 |
18 | vector = alt.Vector3(10, 10, 10)
19 | vector2 = alt.Vector3(20, 20, 20)
20 |
21 | alt.log(vector + vector2)
22 | alt.log(vector - vector2)
23 | alt.log(vector * vector2)
24 | alt.log(vector / vector2)
25 | ```
26 |
27 | This code outputs:
28 |
29 | ```
30 | Vector3(30.000000, 30.000000, 30.000000)
31 | Vector3(-10.000000, -10.000000, -10.000000)
32 | Vector3(200.000000, 200.000000, 200.000000)
33 | Vector3(0.500000, 0.500000, 0.500000)
34 | ```
35 |
36 | ## Vector2
37 |
38 | Vector2 is almost identical to Vector3, but you only get 2 numbers
39 |
40 | You can create Vector2 like this `alt.Vector2(0, 0)`
41 |
42 | You can also perform most mathematical operations
43 |
44 | ```py
45 | import alt
46 |
47 | vector = alt.Vector2(10, 10)
48 | vector2 = alt.Vector2(20, 20)
49 |
50 | alt.log(vector + vector2)
51 | alt.log(vector - vector2)
52 | alt.log(vector * vector2)
53 | alt.log(vector / vector2)
54 | ```
55 |
56 | This code outputs:
57 |
58 | ```
59 | Vector2(30.000000, 30.000000)
60 | Vector2(-10.000000, -10.000000)
61 | Vector2(200.000000, 200.000000)
62 | Vector2(0.500000, 0.500000)
63 | ```
64 |
65 | ---
66 |
67 | Now you should know basic information about Vectors
68 |
69 | Vectors have much more functions which you can find in API reference, this should be just a quick explanation of how do they work
70 |
71 | Next we are going to learn about vehicles
72 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.1)
2 |
3 | include(vendors/cpp-sdk/CMakeLists.txt)
4 | include(cmake/python.cmake)
5 |
6 | project(python-module)
7 | set(PROJECT_MODULE_NAME python-module)
8 |
9 | set(PYTHON_VERSION 3.11.0)
10 |
11 | message("Downloading and Compiling Python, this might take a while")
12 | DownloadPython(${PYTHON_VERSION})
13 | CompilePython(${PYTHON_VERSION})
14 |
15 | set(CMAKE_CXX_STANDARD 17)
16 | set(CMAKE_CXX_STANDARD_REQUIRED ON)
17 | set(CMAKE_CXX_VISIBILITY_PRESET hidden)
18 | set(CMAKE_SHARED_LIBRARY_PREFIX "")
19 |
20 | add_definitions(-DMODULE_NAME="${PROJECT_MODULE_NAME}")
21 | add_definitions(-D_CRT_SECURE_NO_WARNINGS)
22 |
23 |
24 | file(GLOB_RECURSE PROJECT_SOURCE_FILES "./src/*.h" "./src/*.hpp" "./src/*.cpp")
25 | include_directories(
26 | "${PROJECT_SOURCE_DIR}/src"
27 | "${PROJECT_SOURCE_DIR}/vendors/cpp-sdk"
28 | "${PROJECT_SOURCE_DIR}/vendors/magic_enum/include"
29 | "${CMAKE_CURRENT_BINARY_DIR}/Python-${PYTHON_VERSION}/Include"
30 | "${PROJECT_SOURCE_DIR}/vendors/pybind11/include"
31 | )
32 |
33 | if (UNIX)
34 | include_directories("${CMAKE_CURRENT_BINARY_DIR}/Python-${PYTHON_VERSION}")
35 | endif(UNIX)
36 |
37 | if (WIN32)
38 | include_directories("${CMAKE_CURRENT_BINARY_DIR}/Python-${PYTHON_VERSION}/PC")
39 | set(CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE, x64)
40 | endif(WIN32)
41 |
42 | add_library(
43 | ${PROJECT_MODULE_NAME} SHARED
44 | ${PROJECT_SOURCE_FILES}
45 | )
46 |
47 | add_dependencies(${PROJECT_MODULE_NAME} alt-sdk)
48 |
49 | if (WIN32)
50 | target_link_libraries(${PROJECT_MODULE_NAME} ${CMAKE_CURRENT_BINARY_DIR}/Python-${PYTHON_VERSION}/PCbuild/amd64/python311.lib)
51 | endif(WIN32)
52 |
53 | if (UNIX)
54 | target_link_libraries(${PROJECT_MODULE_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/Python-${PYTHON_VERSION}/libpython3.11.so)
55 | endif(UNIX)
56 |
--------------------------------------------------------------------------------
/src/classes/base/baseobject.cpp:
--------------------------------------------------------------------------------
1 | #include "classes/classes.hpp"
2 | #include "classes/types/enums.hpp"
3 | #include "utils.hpp"
4 |
5 | uint64_t GetRefCount(alt::IBaseObject* _this)
6 | {
7 | if (alt::ICore::Instance().IsDebug())
8 | return _this->GetRefCount();
9 | throw std::runtime_error("ref_count is only available in debug mode");
10 | }
11 |
12 | BaseObjectType GetBaseObjectType(alt::IBaseObject* _this)
13 | {
14 | return (BaseObjectType)_this->GetType();
15 | }
16 |
17 | bool GetValid(alt::IBaseObject* _this)
18 | {
19 | PyThreadState* interp = PyThreadState_Get();
20 | PythonResource* resource = PythonRuntime::GetInstance()->GetPythonResourceFromInterp(interp);
21 | return resource->IsObjectValid(_this);
22 | }
23 |
24 | py::object GetMeta(alt::IBaseObject* _this, const std::string& key)
25 | {
26 | return Utils::MValueToValue(_this->GetMetaData(key));
27 | }
28 |
29 | void SetMeta(alt::IBaseObject* _this, const std::string& key, const py::object& value)
30 | {
31 | _this->SetMetaData(key, Utils::ValueToMValue(value));
32 | }
33 |
34 | void Destroy(alt::IBaseObject* _this)
35 | {
36 | alt::ICore::Instance().DestroyBaseObject(_this);
37 | }
38 |
39 | void RegisterBaseObjectClass(const py::module_& m)
40 | {
41 | auto pyClass = py::class_>(m, "BaseObject");
42 |
43 | pyClass.def_property_readonly("ref_count", &GetRefCount);
44 | pyClass.def_property_readonly("valid", &GetValid);
45 | pyClass.def_property_readonly("type", &GetBaseObjectType);
46 |
47 | // Meta
48 | pyClass.def("delete_meta", &alt::IBaseObject::DeleteMetaData, py::arg("key"));
49 | pyClass.def("has_meta", &alt::IBaseObject::HasMetaData, py::arg("key"));
50 | pyClass.def("set_meta", &SetMeta, py::arg("key"), py::arg("value"));
51 | pyClass.def("get_meta", &GetMeta, py::arg("key"));
52 |
53 | pyClass.def("destroy", &Destroy);
54 | }
55 |
--------------------------------------------------------------------------------
/src/classes/base/checkpoint.cpp:
--------------------------------------------------------------------------------
1 | #include "classes/classes.hpp"
2 | #include "classes/types/enums.hpp"
3 | #include "classes/types/vector3.hpp"
4 |
5 | alt::ICheckpoint* CreateCheckpoint(uint8_t type, alt::Position pos, float radius, float height, alt::RGBA color)
6 | {
7 | auto checkpoint = alt::ICore::Instance().CreateCheckpoint(type, pos, radius, height, color);
8 | if (checkpoint)
9 | return checkpoint.Get();
10 | throw std::runtime_error("Failed to create Checkpoint");
11 | }
12 |
13 | CheckpointType GetCheckpointType(alt::ICheckpoint* _this)
14 | {
15 | return (CheckpointType)_this->GetCheckpointType();
16 | }
17 |
18 | void RegisterCheckpointClass(const py::module_& m)
19 | {
20 | auto pyClass = py::class_, alt::IColShape>(m, "Checkpoint");
21 |
22 | pyClass.def(py::init<>([](uint8_t type, double x, double y, double z, float radius, float height, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
23 | return CreateCheckpoint(type, alt::Position(x, y, z), radius, height, alt::RGBA(r, g, b, a));
24 | }),
25 | py::arg("type"), py::arg("x"), py::arg("y"), py::arg("z"), py::arg("radius"), py::arg("height"), py::arg("r"), py::arg("g"), py::arg("b"), py::arg("a"));
26 |
27 | pyClass.def(py::init<>([](uint8_t type, Vector3 pos, float radius, float height, alt::RGBA color) {
28 | return CreateCheckpoint(type, pos.ToAlt(), radius, height, color);
29 | }),
30 | py::arg("type"), py::arg("pos"), py::arg("radius"), py::arg("height"), py::arg("color"));
31 |
32 | // TODO Once setters start working change them to normal properties
33 | pyClass.def_property_readonly("checkpoint_type", &GetCheckpointType);
34 | pyClass.def_property_readonly("height", &alt::ICheckpoint::GetHeight);
35 | pyClass.def_property_readonly("radius", &alt::ICheckpoint::GetRadius);
36 | pyClass.def_property_readonly("color", &alt::ICheckpoint::GetColor);
37 | }
38 |
--------------------------------------------------------------------------------
/src/events/meta.cpp:
--------------------------------------------------------------------------------
1 | #include "events.hpp"
2 | #include "utils.hpp"
3 |
4 | EventHandler syncedMetaChange(alt::CEvent::Type::SYNCED_META_CHANGE, [](const alt::CEvent* ev, py::list& args) {
5 | auto event = dynamic_cast(ev);
6 | args.append(Utils::GetBaseObject(event->GetTarget().Get()));
7 | args.append(event->GetKey());
8 | args.append(Utils::MValueToValue(event->GetVal()));
9 | args.append(Utils::MValueToValue(event->GetOldVal()));
10 | });
11 |
12 | EventHandler streamSyncedMetaChange(alt::CEvent::Type::STREAM_SYNCED_META_CHANGE, [](const alt::CEvent* ev, py::list& args) {
13 | auto event = dynamic_cast(ev);
14 | args.append(Utils::GetBaseObject(event->GetTarget().Get()));
15 | args.append(event->GetKey());
16 | args.append(Utils::MValueToValue(event->GetVal()));
17 | args.append(Utils::MValueToValue(event->GetOldVal()));
18 | });
19 |
20 | EventHandler globalMetaChange(alt::CEvent::Type::GLOBAL_META_CHANGE, [](const alt::CEvent* ev, py::list& args) {
21 | auto event = dynamic_cast(ev);
22 | args.append(event->GetKey());
23 | args.append(Utils::MValueToValue(event->GetVal()));
24 | args.append(Utils::MValueToValue(event->GetOldVal()));
25 | });
26 |
27 | EventHandler globalSyncedMetaChange(alt::CEvent::Type::GLOBAL_SYNCED_META_CHANGE, [](const alt::CEvent* ev, py::list& args) {
28 | auto event = dynamic_cast(ev);
29 | args.append(event->GetKey());
30 | args.append(Utils::MValueToValue(event->GetVal()));
31 | args.append(Utils::MValueToValue(event->GetOldVal()));
32 | });
33 |
34 | EventHandler localMetaChange(alt::CEvent::Type::LOCAL_SYNCED_META_CHANGE, [](const alt::CEvent* ev, py::list& args) {
35 | auto event = dynamic_cast(ev);
36 | args.append(event->GetTarget().Get());
37 | args.append(event->GetKey());
38 | args.append(Utils::MValueToValue(event->GetVal()));
39 | args.append(Utils::MValueToValue(event->GetOldVal()));
40 | });
41 |
--------------------------------------------------------------------------------
/.clang-format:
--------------------------------------------------------------------------------
1 | # Generated from CLion C/C++ Code Style settings
2 | BasedOnStyle: LLVM
3 | AccessModifierOffset: -3
4 | AlignAfterOpenBracket: Align
5 | AlignConsecutiveAssignments: None
6 | AlignOperands: DontAlign
7 | AllowAllArgumentsOnNextLine: false
8 | AllowAllConstructorInitializersOnNextLine: false
9 | AllowAllParametersOfDeclarationOnNextLine: false
10 | AllowShortBlocksOnASingleLine: Always
11 | AllowShortCaseLabelsOnASingleLine: false
12 | AllowShortFunctionsOnASingleLine: None
13 | AllowShortIfStatementsOnASingleLine: Always
14 | AllowShortLambdasOnASingleLine: All
15 | AllowShortLoopsOnASingleLine: true
16 | AlwaysBreakAfterReturnType: None
17 | AlwaysBreakTemplateDeclarations: Yes
18 | BreakBeforeBraces: Custom
19 | BraceWrapping:
20 | AfterCaseLabel: false
21 | AfterClass: true
22 | AfterControlStatement: Always
23 | AfterEnum: true
24 | AfterFunction: true
25 | AfterNamespace: true
26 | AfterUnion: true
27 | BeforeCatch: true
28 | BeforeElse: true
29 | IndentBraces: false
30 | SplitEmptyFunction: true
31 | SplitEmptyRecord: true
32 | BreakBeforeBinaryOperators: NonAssignment
33 | BreakBeforeTernaryOperators: true
34 | BreakConstructorInitializers: BeforeColon
35 | BreakInheritanceList: BeforeColon
36 | ColumnLimit: 0
37 | CompactNamespaces: false
38 | ContinuationIndentWidth: 4
39 | IndentCaseLabels: false
40 | IndentPPDirectives: None
41 | IndentWidth: 4
42 | KeepEmptyLinesAtTheStartOfBlocks: true
43 | MaxEmptyLinesToKeep: 1
44 | NamespaceIndentation: All
45 | ObjCSpaceAfterProperty: false
46 | ObjCSpaceBeforeProtocolList: false
47 | PointerAlignment: Left
48 | ReflowComments: false
49 | SpaceAfterCStyleCast: false
50 | SpaceAfterLogicalNot: false
51 | SpaceAfterTemplateKeyword: false
52 | SpaceBeforeAssignmentOperators: true
53 | SpaceBeforeCpp11BracedList: false
54 | SpaceBeforeCtorInitializerColon: true
55 | SpaceBeforeInheritanceColon: true
56 | SpaceBeforeParens: ControlStatements
57 | SpaceBeforeRangeBasedForLoopColon: true
58 | SpaceInEmptyParentheses: false
59 | SpacesBeforeTrailingComments: 0
60 | SpacesInAngles: false
61 | SpacesInCStyleCastParentheses: false
62 | SpacesInContainerLiterals: false
63 | SpacesInParentheses: false
64 | SpacesInSquareBrackets: false
65 | TabWidth: 4
66 | UseTab: ForContinuationAndIndentation
67 |
--------------------------------------------------------------------------------
/src/PythonResource.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "interval.hpp"
4 | #include "main.hpp"
5 |
6 | class PythonRuntime;
7 | class PythonResource : public alt::IResource::Impl
8 | {
9 | PythonRuntime* runtime;
10 | alt::IResource* resource;
11 | PyThreadState* interpreter;
12 |
13 | std::map> localEvents;
14 | std::map> localCustomEvents;
15 | std::map> remoteEvents;
16 |
17 | int intervalId = 0;
18 | std::vector tasks;
19 | std::map timers;
20 |
21 | std::unordered_map> objects;
22 |
23 | public:
24 | PythonResource(PythonRuntime* runtime, alt::IResource* resource)
25 | : runtime(runtime), resource(resource)
26 | {
27 | }
28 |
29 | bool Start() override;
30 |
31 | bool Stop() override;
32 |
33 | bool OnEvent(const alt::CEvent* ev) override;
34 |
35 | bool IsObjectValid(const alt::Ref& object);
36 |
37 | void OnTick() override;
38 |
39 | void OnCreateBaseObject(alt::Ref object) override;
40 |
41 | void OnRemoveBaseObject(alt::Ref object) override;
42 |
43 | int AddTimer(double milliseconds, const py::function& func);
44 |
45 | void ClearTimer(int timerId);
46 |
47 | void AddTask(double milliseconds, const py::function& func);
48 |
49 | Interval* GetInterval(const py::function& func);
50 |
51 | void AddScriptEvent(const alt::CEvent::Type& type, const py::function& eventFunc);
52 |
53 | void AddServerEvent(const std::string& eventName, const py::function& eventFunc);
54 |
55 | void AddClientEvent(const std::string& eventName, const py::function& eventFunc);
56 |
57 | void HandleCustomEvent(const alt::CEvent* event);
58 |
59 | alt::IResource* GetResource()
60 | {
61 | return resource;
62 | }
63 |
64 | PyThreadState* GetInterpreter()
65 | {
66 | return interpreter;
67 | }
68 |
69 | class PythonFunction : public alt::IMValueFunction::Impl
70 | {
71 | private:
72 | py::function func;
73 |
74 | public:
75 | explicit PythonFunction(py::function func)
76 | : func(std::move(func)){};
77 |
78 | alt::MValue Call(alt::MValueArgs args) const override;
79 | };
80 |
81 | bool MakeClient(alt::IResource::CreationInfo* info, alt::Array files) override;
82 | };
83 |
--------------------------------------------------------------------------------
/src/classes/types/vector2.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "main.hpp"
3 |
4 | class Vector2
5 | {
6 | double GetAngle(const Vector2& other, const bool& degrees) const;
7 |
8 | public:
9 | double x, y;
10 |
11 | Vector2(double x, double y)
12 | : x(x), y(y)
13 | {
14 | }
15 | explicit Vector2(alt::Position position)
16 | : x{position[0]}, y{position[1]}
17 | {
18 | }
19 | explicit Vector2(alt::Rotation rotation)
20 | : x{rotation[0]}, y{rotation[1]}
21 | {
22 | }
23 | explicit Vector2(alt::Vector2f vector)
24 | : x{vector[0]}, y{vector[1]}
25 | {
26 | }
27 | explicit Vector2(const py::list& vectorList)
28 | : x{vectorList[0].cast()}, y{vectorList[1].cast()}
29 | {
30 | }
31 |
32 | py::dict ToDict();
33 | py::list ToList();
34 |
35 | alt::Position ToAlt() const;
36 | std::string ToString() const;
37 |
38 | Vector2 ToDegrees() const;
39 | Vector2 ToRadians() const;
40 |
41 | double Length() const;
42 | double Distance(Vector2& other) const;
43 | double DistanceSquared(Vector2& other) const;
44 | bool IsInRange(const Vector2& other, double range) const;
45 | Vector2 Lerp(Vector2 other, double ratio) const;
46 |
47 | Vector2 operator+(const Vector2& other) const;
48 | Vector2 operator+(double num) const;
49 | Vector2 operator+(const py::list& vectorList) const;
50 |
51 | Vector2 operator-(const Vector2& other) const;
52 | Vector2 operator-(double num) const;
53 | Vector2 operator-(const py::list& vectorList) const;
54 | Vector2 operator-() const;
55 |
56 | Vector2 operator/(const Vector2& other) const;
57 | Vector2 operator/(double num) const;
58 | Vector2 operator/(const py::list& vectorList) const;
59 |
60 | Vector2 operator*(const Vector2& other) const;
61 | Vector2 operator*(double num) const;
62 | Vector2 operator*(const py::list& vectorList) const;
63 |
64 | bool operator==(const Vector2& other) const;
65 |
66 | double Dot(const Vector2& other) const;
67 | double Dot(double num) const;
68 | double Dot(const py::list& vectorList) const;
69 |
70 | Vector2 Normalize() const;
71 |
72 | static Vector2 Zero(const py::object& _this);
73 | static Vector2 One(const py::object& _this);
74 | static Vector2 Up(const py::object& _this);
75 | static Vector2 Down(const py::object& _this);
76 | static Vector2 Left(const py::object& _this);
77 | static Vector2 Right(const py::object& _this);
78 |
79 | static Vector2 PositiveInfinity(const py::object& _this);
80 | static Vector2 NegativeInfinity(const py::object& _this);
81 |
82 | double AngleTo(const Vector2& other);
83 | double AngleToDegrees(const Vector2& other);
84 | };
85 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build & Deploy
2 | on:
3 | workflow_dispatch:
4 | push:
5 | tags:
6 | - "dev/*.*-dev*"
7 | - "rc/*.*-rc*"
8 | - "release/*.*"
9 |
10 | jobs:
11 | create-release:
12 | name: Create GitHub Release
13 | runs-on: ubuntu-latest
14 | outputs:
15 | upload_url: ${{ steps.create_release.outputs.upload_url }}
16 | steps:
17 | - name: Create Release
18 | id: create_release
19 | uses: actions/create-release@v1
20 | env:
21 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
22 | with:
23 | tag_name: ${{ github.ref }}
24 | release_name: Release ${{ github.ref }}
25 | draft: false
26 |
27 | build-windows:
28 | name: Build Windows server module
29 | runs-on: windows-2019
30 | needs: [create-release]
31 | steps:
32 | - name: Checkout repo
33 | uses: actions/checkout@v2
34 | with:
35 | submodules: recursive
36 | lfs: true
37 |
38 | - name: Build
39 | shell: cmd
40 | run: build.bat
41 |
42 | - name: Zip artifacts
43 | run: |
44 | cd dist
45 | tar -acf ..\python-module-windows.zip *
46 |
47 | - name: Upload artifacts to release
48 | uses: actions/upload-release-asset@v1
49 | env:
50 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
51 | with:
52 | upload_url: ${{ needs.create-release.outputs.upload_url }}
53 | asset_path: python-module-windows.zip
54 | asset_name: python-module-windows.zip
55 | asset_content_type: application/octet-stream
56 |
57 | build-linux:
58 | name: Build Linux server module
59 | runs-on: ubuntu-20.04
60 | needs: [create-release]
61 | steps:
62 | - name: Checkout repo
63 | uses: actions/checkout@v2
64 | with:
65 | submodules: recursive
66 | lfs: true
67 |
68 | - name: Build
69 | run: |
70 | sudo chmod +x build.sh
71 | ./build.sh
72 | - name: Zip artifacts
73 | run: |
74 | cd dist
75 | zip -r ../python-module-linux .
76 | - name: Upload artifacts to release
77 | uses: actions/upload-release-asset@v1
78 | env:
79 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
80 | with:
81 | upload_url: ${{ needs.create-release.outputs.upload_url }}
82 | asset_path: python-module-linux.zip
83 | asset_name: python-module-linux.zip
84 | asset_content_type: application/octet-stream
85 |
--------------------------------------------------------------------------------
/src/classes/types/resource.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "classes/classes.hpp"
4 | #include "utils.hpp"
5 |
6 | class Resource
7 | {
8 | private:
9 | alt::IResource* resource;
10 |
11 | public:
12 | Resource(alt::IResource* resource)
13 | : resource(resource)
14 | {
15 | }
16 |
17 | bool IsStarted()
18 | {
19 | return resource->IsStarted();
20 | }
21 |
22 | std::string GetType()
23 | {
24 | return resource->GetType();
25 | }
26 |
27 | std::string GetName()
28 | {
29 | return resource->GetName();
30 | }
31 |
32 | std::string GetMain()
33 | {
34 | return resource->GetMain();
35 | }
36 |
37 | std::string GetPath()
38 | {
39 | return resource->GetPath();
40 | }
41 |
42 | py::dict GetConfig()
43 | {
44 | Config::Value::ValuePtr config = resource->GetConfig();
45 | return Utils::ConfigNodeToValue(config);
46 | }
47 |
48 | py::dict GetExports()
49 | {
50 | return Utils::MValueToValue(resource->GetExports());
51 | }
52 |
53 | py::list GetDependencies()
54 | {
55 | return Utils::ArrayToPyList(resource->GetDependencies());
56 | }
57 |
58 | py::list GetDependants()
59 | {
60 | return Utils::ArrayToPyList(resource->GetDependants());
61 | }
62 |
63 | py::list GetRequiredPermissions()
64 | {
65 | py::list list;
66 | auto permissions = resource->GetRequiredPermissions();
67 | for (auto permission : permissions)
68 | list.append((int)permission);
69 | return list;
70 | }
71 |
72 | py::list GetOptionalPermissions()
73 | {
74 | py::list list;
75 | auto permissions = resource->GetOptionalPermissions();
76 | for (auto permission : permissions)
77 | list.append((int)permission);
78 | return list;
79 | }
80 |
81 | static py::object GetByName(const std::string& resourceName)
82 | {
83 | auto resource = alt::ICore::Instance().GetResource(resourceName);
84 | if (resource != nullptr)
85 | return py::cast(Resource(resource));
86 | return py::none();
87 | }
88 |
89 | static py::list GetAllResources(const py::object& type)
90 | {
91 | py::list list;
92 | auto resources = alt::ICore::Instance().GetAllResources();
93 | for (auto resource : resources)
94 | list.append(Resource(resource));
95 | return list;
96 | }
97 |
98 | static Resource GetCurrent(const py::object& type)
99 | {
100 | PyThreadState* interp = PyThreadState_Get();
101 | PythonResource* resource = PythonRuntime::GetInstance()->GetPythonResourceFromInterp(interp);
102 | return {resource->GetResource()};
103 | }
104 | };
105 |
--------------------------------------------------------------------------------
/src/bindings/intervals.cpp:
--------------------------------------------------------------------------------
1 | #include "PythonRuntime.hpp"
2 | #include "bindings.hpp"
3 | #include "main.hpp"
4 |
5 | void CreateAttrsForTaskFunction(PythonResource* resource, const py::function& func)
6 | {
7 | Interval* task = resource->GetInterval(func);
8 | func.attr("stop") = py::cpp_function([task, func] {
9 | task->SetRunning(false);
10 | });
11 |
12 | func.attr("start") = py::cpp_function([task, func] {
13 | task->SetRunning(true);
14 | });
15 |
16 | func.attr("is_running") = py::cpp_function([task, func] {
17 | return task->IsRunning();
18 | });
19 |
20 | func.attr("change_interval") = py::cpp_function([task, func](double milliseconds = 0, double seconds = 0, double minutes = 0, double hours = 0) {
21 | if (seconds > 0) milliseconds += seconds * 1000;
22 | if (minutes > 0) milliseconds += minutes * 60 * 1000;
23 | if (hours > 0) milliseconds += hours * 60 * 60 * 1000;
24 | task->SetMilliseconds(milliseconds);
25 | },
26 | py::arg("milliseconds") = 0, py::arg("seconds") = 0, py::arg("minutes") = 0, py::arg("hours") = 0);
27 | }
28 |
29 | py::cpp_function Task(double milliseconds = 0, double seconds = 0, double minutes = 0, double hours = 0)
30 | {
31 | if (seconds > 0) milliseconds += seconds * 1000;
32 | if (minutes > 0) milliseconds += minutes * 60 * 1000;
33 | if (hours > 0) milliseconds += hours * 60 * 60 * 1000;
34 | return [milliseconds](const py::function& func) {
35 | PyThreadState* interp = PyThreadState_Get();
36 | PythonResource* resource = PythonRuntime::GetInstance()->GetPythonResourceFromInterp(interp);
37 | resource->AddTask(milliseconds, func);
38 | CreateAttrsForTaskFunction(resource, func);
39 | return func;
40 | };
41 | }
42 |
43 | int Timer(const py::function& func, double milliseconds)
44 | {
45 | PyThreadState* interp = PyThreadState_Get();
46 | PythonResource* resource = PythonRuntime::GetInstance()->GetPythonResourceFromInterp(interp);
47 | return resource->AddTimer(milliseconds, func);
48 | }
49 |
50 | void ClearTimer(int timerId)
51 | {
52 | PyThreadState* interp = PyThreadState_Get();
53 | PythonResource* resource = PythonRuntime::GetInstance()->GetPythonResourceFromInterp(interp);
54 | resource->ClearTimer(timerId);
55 | }
56 |
57 | void RegisterIntervalFunctions(py::module_ m)
58 | {
59 | m.def("task", &Task, py::kw_only(), py::arg("milliseconds") = 0, py::arg("seconds") = 0, py::arg("minutes") = 0, py::arg("hours") = 0, "Decorator for creating task");
60 | m.def("timer", &Timer, py::arg("func"), py::arg("milliseconds"), "Creates timer and returns it's id");
61 | m.def("clear_timer", &ClearTimer, py::arg("timer_id"), "Clears the timer by it's id");
62 | }
63 |
--------------------------------------------------------------------------------
/src/PythonRuntime.cpp:
--------------------------------------------------------------------------------
1 | #include "PythonRuntime.hpp"
2 | #ifdef __linux__
3 | #include
4 | #endif
5 |
6 | PythonRuntime* PythonRuntime::instance = nullptr;
7 |
8 | PythonRuntime::PythonRuntime()
9 | {
10 | #ifdef __linux__
11 | // Without this, python doesn't recognize the shared lib, should be linux only issue
12 | std::string so = std::string("libpython") + std::to_string(PY_MAJOR_VERSION) + "." + std::to_string(PY_MINOR_VERSION) + ".so.1.0";
13 | python = dlopen(so.c_str(), RTLD_NOW | RTLD_NOLOAD | RTLD_GLOBAL);
14 | #endif
15 | // For compatibility reasons disable site packages, if user wants to use 3rd party modules they should create venv
16 | Py_IsolatedFlag = 1;
17 |
18 | #ifdef _WIN32
19 | std::string pathSeparator = ";";
20 | #else
21 | std::string pathSeparator = ":";
22 | #endif
23 | std::string basePath = alt::ICore::Instance().GetRootDirectory() + SEPARATOR + "modules" + SEPARATOR + "python-module" + SEPARATOR + "python";
24 | std::string path = basePath + pathSeparator + (basePath + SEPARATOR + "libs.zip");
25 |
26 | // Venv should get recognized automatically, but if it doesn't, here is a config option for it
27 | alt::config::Node venv = alt::ICore::Instance().GetServerConfig()["python-venv"];
28 | if (venv)
29 | path.append(pathSeparator + alt::ICore::Instance().GetRootDirectory() + SEPARATOR + venv.ToString());
30 |
31 | Py_SetPath(std::wstring(path.begin(), path.end()).c_str());
32 | py::initialize_interpreter(false);
33 | py::module_::import("alt");
34 | mainInterpreter = PyThreadState_Get();
35 | instance = this;
36 | }
37 |
38 | PythonResource* PythonRuntime::GetPythonResourceFromInterp(PyThreadState* interp)
39 | {
40 | for (PythonResource* resource : resources)
41 | if (resource->GetInterpreter() == interp)
42 | return resource;
43 | if (interp->interp == PyInterpreterState_Main())
44 | alt::ICore::Instance().LogError("Main Interpreter Passed");
45 | return nullptr;
46 | }
47 |
48 | alt::IResource::Impl* PythonRuntime::CreateImpl(alt::IResource* impl)
49 | {
50 | auto* resource = new PythonResource(this, impl);
51 | resources.push_back(resource);
52 | return resource;
53 | }
54 |
55 | void PythonRuntime::DestroyImpl(alt::IResource::Impl* impl)
56 | {
57 | auto* resource = dynamic_cast(impl);
58 | for (int i{}; i < resources.size(); i++)
59 | {
60 | if (resources[i]->GetResource()->GetName() == resource->GetResource()->GetName())
61 | {
62 | resources.erase(resources.begin() + i);
63 | break;
64 | }
65 | }
66 | delete resource;
67 | }
68 |
69 | void PythonRuntime::OnDispose()
70 | {
71 | PyThreadState_Swap(mainInterpreter);
72 | py::finalize_interpreter();
73 | #ifdef __linux__
74 | dlclose(python);
75 | #endif
76 | }
77 |
--------------------------------------------------------------------------------
/src/classes/types/vector3.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "main.hpp"
3 |
4 | class Vector3
5 | {
6 | double GetAngle(const Vector3& other, const bool& boolean) const;
7 |
8 | public:
9 | double x, y, z;
10 |
11 | Vector3(double x, double y, double z)
12 | : x(x), y(y), z(z)
13 | {
14 | }
15 | explicit Vector3(alt::Position position)
16 | : x{position[0]}, y{position[1]}, z{position[2]}
17 | {
18 | }
19 | explicit Vector3(alt::Rotation rotation)
20 | : x{rotation[0]}, y{rotation[1]}, z{rotation[2]}
21 | {
22 | }
23 | explicit Vector3(alt::Vector3f vector)
24 | : x{vector[0]}, y{vector[1]}, z{vector[2]}
25 | {
26 | }
27 | explicit Vector3(const py::list& vectorList)
28 | : x{vectorList[0].cast()}, y{vectorList[1].cast()}, z{vectorList[2].cast()}
29 | {
30 | }
31 |
32 | py::dict ToDict();
33 | py::list ToList();
34 |
35 | alt::Position ToAlt() const;
36 | std::string ToString() const;
37 |
38 | Vector3 ToDegrees() const;
39 | Vector3 ToRadians() const;
40 |
41 | double Length() const;
42 | double Distance(Vector3& other) const;
43 | double DistanceSquared(Vector3& other) const;
44 | bool IsInRange(const Vector3& other, double range) const;
45 | Vector3 Lerp(Vector3 other, double ratio) const;
46 |
47 | Vector3 operator+(const Vector3& other) const;
48 | Vector3 operator+(double num) const;
49 | Vector3 operator+(const py::list& vectorList) const;
50 |
51 | Vector3 operator-(const Vector3& other) const;
52 | Vector3 operator-(double num) const;
53 | Vector3 operator-(const py::list& vectorList) const;
54 | Vector3 operator-() const;
55 |
56 | Vector3 operator/(const Vector3& other) const;
57 | Vector3 operator/(double num) const;
58 | Vector3 operator/(const py::list& vectorList) const;
59 |
60 | Vector3 operator*(const Vector3& other) const;
61 | Vector3 operator*(double num) const;
62 | Vector3 operator*(const py::list& vectorList) const;
63 |
64 | bool operator==(const Vector3& other) const;
65 |
66 | Vector3 Cross(const Vector3& other) const;
67 | Vector3 Cross(double num) const;
68 | Vector3 Cross(const py::list& vectorList) const;
69 |
70 | double Dot(const Vector3& other) const;
71 | double Dot(double num) const;
72 | double Dot(const py::list& vectorList) const;
73 |
74 | Vector3 Normalize() const;
75 |
76 | static Vector3 Zero(const py::object& _this);
77 | static Vector3 One(const py::object& _this);
78 | static Vector3 Up(const py::object& _this);
79 | static Vector3 Down(const py::object& _this);
80 | static Vector3 Left(const py::object& _this);
81 | static Vector3 Right(const py::object& _this);
82 | static Vector3 Back(const py::object& _this);
83 | static Vector3 Forward(const py::object& _this);
84 |
85 | static Vector3 PositiveInfinity(const py::object& _this);
86 | static Vector3 NegativeInfinity(const py::object& _this);
87 |
88 | double AngleTo(const Vector3& other);
89 | double AngleToDegrees(const Vector3& other);
90 | };
91 |
--------------------------------------------------------------------------------
/docs/articles/index.md:
--------------------------------------------------------------------------------
1 | # alt:V Python Module
2 |
3 |
4 | 
5 | alt:V Python Module, fast and simple Python alt:V implementation
6 |
7 | ---
8 | alt:V Python Module adds server-side language support for Python
9 |
10 | By installing Python Module you will be able to fully use alt:V server-side API from your Python code
11 |
12 | This documentation only explains the Python module itself and assumes you are familiar with alt:V and how to use it.
13 |
14 | ---
15 |
16 | ## Let's create your first alt:V Python resource
17 |
18 | ### Requirements
19 |
20 | - Already working alt:V server
21 | - Basic Python knowledge
22 | - Basic knowledge of command prompts
23 | - An IDE or any other code editor
24 |
25 | ### Installation
26 |
27 | Installation of the Python Module is really easy
28 |
29 | - [Download](https://github.com/Marvisak/altv-python-module/releases/latest) the latest version of the module for your desired platform
30 | - Create `modules/python-module` folder in your alt:V server folder
31 | - Move all the files from the zip file you downloaded into the folder you created
32 | - Add into your `server.cfg` modules column "python-module"
33 |
34 | ```yaml
35 | modules: ['python-module']
36 | ```
37 |
38 | Now start the server, if you see this message in the console
39 |
40 | ```
41 | Python module successfully loaded
42 | ```
43 |
44 | Then Python module was installed successfully, and you are good to go
45 |
46 | ### Creating a resource
47 |
48 | Creating a resource is identical to creating JavaScript resource
49 |
50 | Let's start by creating required files of our resource
51 |
52 | For this tutorial we are going to call our resource `python`
53 |
54 | ```
55 | resources/python
56 |
57 | resources/python/resource.cfg
58 |
59 | resources/python/main.py
60 | ```
61 |
62 | ??? note
63 | Python is currently only supported on server-side, so in this documentation we are only going to create server files, your gamemode will probably have some client files in order to function
64 |
65 | There will be few places where we will need to have some client code, in that case we are going to use JavaScript
66 |
67 | ```yaml title="resource.cfg"
68 | type: py
69 | main: main.py
70 | ```
71 |
72 | ```py title="main.py"
73 | import alt
74 |
75 | alt.log("My First Python Resource Started!")
76 | ```
77 |
78 | Now only thing left to do is add the resource into your `server.cfg`
79 |
80 | ```yaml
81 | resources: ['python']
82 | ```
83 |
84 | And now when you start your server you should see this message in the console
85 |
86 | ```
87 | My First Python Resource Started!
88 | ```
89 |
90 | Congratulations, you have just created your first alt:V Python Resource
91 |
92 | ## What's next
93 |
94 | In the next few articles you are going to learn how the Python module works and how can you use it
95 |
96 | After you read through this documentation you should have solid understanding of how the module works and how to use it.
97 |
--------------------------------------------------------------------------------
/docs/articles/intro.md:
--------------------------------------------------------------------------------
1 | # Intro
2 |
3 | Let's start by breaking down the code we wrote previously
4 |
5 | ```py
6 | import alt
7 |
8 | alt.log("My First Python Resource Started!")
9 | ```
10 |
11 | This is a very simple code, but it's great for explaining how does the module work
12 |
13 | ## Import alt module
14 |
15 | ```py hl_lines="1"
16 | import alt
17 |
18 | alt.log("My First Python Resource Started!")
19 | ```
20 |
21 | The alt module is your way to communicate with alt:V API
22 |
23 | It is embedded right into the module, so you don't have to install anything.
24 |
25 | If you don't need alt:V API in your file you don't have to import it, but most of the thing module does are only usable through this import, so without it, you are going to write plain Python.
26 |
27 | Your IDE won't show you any typehints for the alt module, if you want to have them, you can find info about them and much more at [Additional Information](additional-information.md) article
28 |
29 | ## Log into the console
30 |
31 | ```py hl_lines="3"
32 | import alt
33 |
34 | alt.log("My First Python Resource Started!")
35 | ```
36 |
37 | This line calls the log function
38 |
39 | The log function behaves exactly like print function, it even has `sep` parameter which changes the way arguments passed to it are separated
40 |
41 | The difference between this function and normal `#!python print()` is that this function uses alt:V API so the output looks different
42 |
43 | ```py
44 | print("My First Python Resource Started!")
45 | ```
46 |
47 | Outputs simply: `My First Python Resource Started!`
48 |
49 | While our original code outputs: `[XX:XX:XX] My First Python Resource Started!`
50 |
51 | ??? note
52 | In the rest of articles when we will use this function, the timestamp is going to be removed
53 |
54 | ---
55 |
56 | We have 3 kinds of log functions
57 |
58 | - `alt.log()`
59 | - `alt.log_error()`
60 | - `alt.log_warning()`
61 |
62 | Each of these functions works exactly the same, only the output looks differently.
63 |
64 | ---
65 |
66 | You can pass any amount of arguments you want, all of them are going to be parsed to string and separated by space.
67 |
68 | ```py
69 | import alt
70 |
71 | alt.log("Hello", 50, [20, 30, 50])
72 | ```
73 |
74 | This code outputs: `Hello 50 [20, 30, 50]`
75 |
76 | If you want to edit the separator of the arguments you pass in, you should use the `sep` argument.
77 |
78 | ```py
79 | import alt
80 |
81 | alt.log("Hello", 50, [], sep=",")
82 | ```
83 |
84 | This code outputs: `Hello,50,[20, 30, 50]`
85 |
86 | ---
87 |
88 | You can also color the text you are outputting if you are using the `alt.log()` function
89 |
90 | ```py
91 | import alt
92 |
93 | alt.log("~r~This ~g~is ~b~colorful")
94 | ```
95 |
96 | This code outputs: This is colorful
97 |
98 | ---
99 |
100 | Now you should have basic understanding of how alt module works
101 |
102 | You should also know everything about how log functions work and how can you use them in your code
103 |
104 | In the next article we are going to learn about events and how to use them
--------------------------------------------------------------------------------
/src/bindings/events.cpp:
--------------------------------------------------------------------------------
1 | #include "classes/types/enums.hpp"
2 | #include "main.hpp"
3 | #include "utils.hpp"
4 |
5 | py::cpp_function ScriptEvent(Event event)
6 | {
7 | return [event](const py::function& func) {
8 | PyThreadState* interp = PyThreadState_Get();
9 | PythonResource* resource = PythonRuntime::GetInstance()->GetPythonResourceFromInterp(interp);
10 | auto ev = static_cast(event);
11 |
12 | if (!alt::ICore::Instance().IsEventEnabled(ev))
13 | alt::ICore::Instance().ToggleEvent(ev, true);
14 |
15 | auto castEvent = static_cast(event);
16 | resource->AddScriptEvent(castEvent, func);
17 | };
18 | }
19 |
20 | py::cpp_function ServerEvent(const std::string& eventName)
21 | {
22 | return [eventName](const py::function& func) {
23 | PyThreadState* interp = PyThreadState_Get();
24 | PythonResource* resource = PythonRuntime::GetInstance()->GetPythonResourceFromInterp(interp);
25 | resource->AddServerEvent(eventName, func);
26 | };
27 | }
28 |
29 | py::cpp_function ClientEvent(const std::string& eventName)
30 | {
31 | return [eventName](const py::function& func) {
32 | PyThreadState* interp = PyThreadState_Get();
33 | PythonResource* resource = PythonRuntime::GetInstance()->GetPythonResourceFromInterp(interp);
34 | resource->AddClientEvent(eventName, func);
35 | };
36 | }
37 |
38 | void Emit(const std::string& eventName, const py::args& args)
39 | {
40 | alt::MValueArgs eventArgs;
41 | for (const py::handle& arg : *args)
42 | eventArgs.Push(Utils::ValueToMValue(arg.cast()));
43 |
44 | alt::ICore::Instance().TriggerLocalEvent(eventName, eventArgs);
45 | }
46 |
47 | void EmitClient(alt::IPlayer* player, const std::string& eventName, const py::args& args)
48 | {
49 | alt::MValueArgs eventArgs;
50 | for (const py::handle& arg : *args)
51 | eventArgs.Push(Utils::ValueToMValue(arg.cast()));
52 | alt::ICore::Instance().TriggerClientEvent(player, eventName, eventArgs);
53 | }
54 |
55 | void EmitClient(const std::vector& players, const std::string& eventName, const py::args& args)
56 | {
57 | alt::MValueArgs eventArgs;
58 | for (const py::handle& arg : *args)
59 | eventArgs.Push(Utils::ValueToMValue(arg.cast()));
60 | for (alt::IPlayer* player : players)
61 | alt::ICore::Instance().TriggerClientEvent(player, eventName, eventArgs);
62 | }
63 |
64 | void EmitAllClients(const std::string& eventName, const py::args& args)
65 | {
66 | alt::MValueArgs eventArgs;
67 | for (const py::handle& arg : *args)
68 | eventArgs.Push(Utils::ValueToMValue(arg.cast()));
69 | alt::ICore::Instance().TriggerClientEventForAll(eventName, eventArgs);
70 | }
71 |
72 | void RegisterEventFunctions(py::module_ m)
73 | {
74 | m.def("script_event", &ScriptEvent, py::arg("event"), "Decorator for registering event listener");
75 | m.def("server_event", &ServerEvent, py::arg("event"), "Decorator for registering custom event listener");
76 | m.def("client_event", &ClientEvent, py::arg("event"), "Decorator for registering client event listener");
77 | m.def("emit", &Emit, py::arg("event_name"), "Emits event");
78 | m.def("emit_client", py::overload_cast(&EmitClient), py::arg("player"), py::arg("event_name"), "Emits client event");
79 | m.def("emit_client", py::overload_cast&, const std::string&, const py::args&>(&EmitClient), py::arg("players"), py::arg("event_name"), "Emits client event to all clients in the list");
80 | m.def("emit_all_clients", &EmitAllClients, py::arg("event_name"), "Emits event to all clients");
81 | }
82 |
--------------------------------------------------------------------------------
/docs/articles/tasks.md:
--------------------------------------------------------------------------------
1 | # Tasks and Timers
2 |
3 | Sometimes you want to call functions in loop or after certain amount of time
4 |
5 | You can't use tools provided by Python because they will freeze your whole code execution
6 |
7 | Thankfully Python module provides you with tools which can help you solve this problem
8 |
9 | ## Tasks
10 |
11 | Tasks or as some call it intervals call your code every X milliseconds
12 |
13 | ```py
14 | import alt
15 |
16 | @alt.task(seconds=1)
17 | def task() -> None:
18 | alt.log("I am called every second!")
19 | ```
20 |
21 | After you run this code you should see something like this:
22 | ```
23 | [XX:XX:01] I am called every second!
24 | [XX:XX:02] I am called every second!
25 | [XX:XX:03] I am called every second!
26 | [XX:XX:04] I am called every second!
27 | ```
28 |
29 | As you can see tasks are very similar to events, we are also using decorator
30 |
31 | The decorator `alt.task()` has 4 keyword arguments: `milliseconds`, `seconds`, `minutes`, `hours`, all of them are floats
32 |
33 | All the arguments you enter will get converted into milliseconds
34 |
35 | If you don't enter any arguments the function will get executed every server tick
36 |
37 | You can also combine the arguments to create something like this
38 |
39 | ```py
40 | import alt
41 |
42 | @alt.task(minutes=1, seconds=30)
43 | def task() -> None:
44 | alt.log("I am called every minute and a half!")
45 | ```
46 |
47 | Which outputs this:
48 | ```
49 | [XX:01:30] I am called every minute and a half!
50 | [XX:03:00] I am called every minute and a half!
51 | [XX:04:30] I am called every minute and a half!
52 | [XX:06:00] I am called every minute and a half!
53 | ```
54 |
55 | The function you used the decorator on will then get 4 new functions
56 |
57 | - `func.stop()` Stops the task from executing
58 | - `func.start()` Starts the task if it was stopped previously
59 | - `func.is_running()` Returns `True` if the interval is running, otherwise `False`
60 | - `func.set_interval()` Changes the interval, takes the exact same arguments as the `alt.task()` decorator
61 |
62 | So you can create something like this:
63 |
64 | ```py
65 | import alt
66 |
67 | @alt.task()
68 | def task() -> None:
69 | alt.log("I am called only once!")
70 | task.stop()
71 | ```
72 |
73 | Which outputs:
74 | ```
75 | I am called only once!
76 | ```
77 |
78 | ??? note
79 | You should never do something like this, if you need a code which should execute only once, use timers which are explained below
80 |
81 |
82 | ## Timers
83 |
84 | Timers call your code after X milliseconds, the difference between tasks and timers is that timers call your function only once
85 |
86 | ```py
87 | import alt
88 |
89 | def timer() -> None:
90 | alt.log("I am called after one second!")
91 |
92 | timer_id = alt.timer(timer, 1000)
93 | ```
94 |
95 | Which outputs:
96 | ```
97 | [XX:XX:01] I am called after one second!
98 | ```
99 |
100 | The `alt.timer()` function takes 2 arguments, the first one is the function you want to add to the timer, and the second one is the amount of milliseconds after which the function should get called
101 |
102 | If you need the timer to stop so that the function doesn't execute, you can use the `alt.clear_timer()` function
103 |
104 | The function takes the number you got from the `alt.timer()` as an argument.
105 |
106 | ```py
107 | import alt
108 |
109 | def timer() -> None:
110 | alt.log("I am never called :(")
111 |
112 | timer_id = alt.timer(timer, 1000)
113 |
114 | alt.clear_timer(timer_id)
115 | ```
116 |
117 | ---
118 |
119 | Now you should know everything about Tasks and Timers
120 |
121 | Next we are going to learn about vectors
122 |
--------------------------------------------------------------------------------
/docs/articles/additional-information.md:
--------------------------------------------------------------------------------
1 | # Additional Information
2 |
3 | This article will be about some additional information you might need
4 |
5 | ## Installing 3rd party packages | Using venv
6 |
7 | You'll probably want to use some 3rd party package in your code.
8 |
9 | For compatibility reasons python module doesn't allow you to use your global environment, so you need to create virtual environment
10 |
11 | There are 2 ways how to use it with the module
12 |
13 | ### The easy way
14 |
15 | The easy way is the way you would normally create virtual environment
16 |
17 | There are many ways how to achieve this but for the sake of this tutorial I am going to use the standard python way
18 |
19 | ```
20 | $ python -m venv env
21 | ```
22 |
23 | Execute this command in your server root folder, and it should create an environment in a folder called env.
24 |
25 | Now just enter it, this example is for windows
26 |
27 | ```
28 | $ env\Scripts\activate
29 | ```
30 |
31 | Now just start the server, and it should load the virtual environment into the path
32 |
33 | If it doesn't which will probably happen if you are using Windows, use the second way
34 |
35 | ### The annoying way
36 |
37 | I am going to expect that you have created your virtual environment in the previous step
38 |
39 | Here you will need to find your site-packages folder
40 |
41 | On Windows this is: `env\Lib\site-packages`
42 |
43 | Now open your `server.cfg` and enter this field:
44 | ```
45 | python-venv: env\Lib\site-packages
46 | ```
47 | Of course replace the path with your own one, this path has to be relative to the server root folder.
48 |
49 | Now start your server, and you can now import any third party packages you install into the virtual environment
50 |
51 | ### Problems
52 |
53 | There might be a bit of a problem, as the module should always be running the newest version of Python, it's APIs might not be compatible with the APIs of the Python you have installed on your system.
54 |
55 | This might create a problem with packages written in C as effectively you are installing packages for a wrong version of Python, so if you find any problems. The only way how to fix them is probably installing the newest version of Python on your system.
56 |
57 | If any package doesn't work even with the newest version of Python create issue on GitHub.
58 |
59 | ## Autocompletion and stubs
60 |
61 | If you want autocompletion for your code, you need to download our stubs
62 |
63 | You can either install it into your global environment (not recommended) or into your virtual environment you created in the previous step (recommended)
64 |
65 | ```
66 | $ pip install altv-stubs
67 | ```
68 |
69 | This should install stubs of the module and your IDE should automatically detect that the stubs were installed and add autocompletion
70 |
71 | ## Async
72 |
73 | Currently, there is no implementation of Python async in the module, meaning that any code which requires the `await` keyword won't work
74 |
75 | I (the module developer) am not experienced enough with asynchronous Python to be able to implement it
76 |
77 | If you have the necessary knowledge on how to use Python async and can help implement it, contact me on discord `Marvis#5422`
78 |
79 | ## MyPy
80 |
81 | This is just a little recommendation from me.
82 |
83 | You've probably heard of TypeScript, the static JavaScript, what if I told you there is something similar like that for Python
84 |
85 | It's called MyPy and because unlike JavaScript Python already has typehints and other required stuff for static code it's a CLI application instead of whole other language
86 |
87 | You can find all the information about MyPy [on their website](https://mypy.readthedocs.io/en/stable/)
88 |
89 | You will need the stubs installed in order for MyPy to check your code
90 |
91 | All the code in this documentation should be compatible with MyPy
92 |
--------------------------------------------------------------------------------
/src/classes/base/colshape.cpp:
--------------------------------------------------------------------------------
1 | #include "classes/classes.hpp"
2 | #include "classes/types/enums.hpp"
3 | #include "classes/types/vector2.hpp"
4 | #include "classes/types/vector3.hpp"
5 |
6 | ColShapeType GetColShapeType(alt::IColShape* _this)
7 | {
8 | return (ColShapeType)_this->GetColshapeType();
9 | }
10 |
11 | bool IsPointIn(alt::IColShape* _this, Vector3 pos)
12 | {
13 | return _this->IsPointIn(pos.ToAlt());
14 | }
15 |
16 | void RegisterColShapeClass(const py::module_& m)
17 | {
18 | auto pyClass = py::class_>(m, "ColShape", py::multiple_inheritance());
19 |
20 | pyClass.def_static(
21 | "circle", [](double x, double y, float radius) {
22 | return alt::ICore::Instance().CreateColShapeCircle({x, y, 0}, radius);
23 | },
24 | py::arg("x"), py::arg("y"), py::arg("radius"));
25 |
26 | pyClass.def_static(
27 | "circle", [](Vector2 pos, float radius) {
28 | return alt::ICore::Instance().CreateColShapeCircle(pos.ToAlt(), radius);
29 | },
30 | py::arg("pos"), py::arg("radius"));
31 |
32 | pyClass.def_static(
33 | "cylinder", [](double x, double y, double z, float radius, float height) {
34 | return alt::ICore::Instance().CreateColShapeCylinder({x, y, z}, radius, height);
35 | },
36 | py::arg("x"), py::arg("y"), py::arg("z"), py::arg("radius"), py::arg("height"));
37 |
38 | pyClass.def_static(
39 | "cylinder", [](Vector3 pos, float radius, float height) {
40 | return alt::ICore::Instance().CreateColShapeCylinder(pos.ToAlt(), radius, height);
41 | },
42 | py::arg("pos"), py::arg("radius"), py::arg("height"));
43 |
44 | pyClass.def_static(
45 | "sphere", [](double x, double y, double z, float radius) {
46 | return alt::ICore::Instance().CreateColShapeSphere({x, y, z}, radius);
47 | },
48 | py::arg("x"), py::arg("y"), py::arg("z"), py::arg("radius"));
49 |
50 | pyClass.def_static(
51 | "sphere", [](Vector3 pos, float radius) {
52 | return alt::ICore::Instance().CreateColShapeSphere(pos.ToAlt(), radius);
53 | },
54 | py::arg("pos"), py::arg("radius"));
55 |
56 | pyClass.def_static(
57 | "cube", [](double x1, double y1, double z1, double x2, double y2, double z2) {
58 | return alt::ICore::Instance().CreateColShapeCube({x1, y1, z1}, {x2, y2, z2});
59 | },
60 | py::arg("x1"), py::arg("y1"), py::arg("z1"), py::arg("x2"), py::arg("y2"), py::arg("z2"));
61 |
62 | pyClass.def_static(
63 | "cube", [](Vector3 pos1, Vector3 pos2) {
64 | return alt::ICore::Instance().CreateColShapeCube(pos1.ToAlt(), pos2.ToAlt());
65 | },
66 | py::arg("pos1"), py::arg("pos2"));
67 |
68 | pyClass.def_static(
69 | "rectangle", [](float x1, float y1, float x2, float y2) {
70 | return alt::ICore::Instance().CreateColShapeRectangle(x1, y1, x2, y2, 0);
71 | },
72 | py::arg("x1"), py::arg("y1"), py::arg("x2"), py::arg("y2"));
73 |
74 | pyClass.def_static(
75 | "rectangle", [](Vector2 pos1, Vector2 pos2) {
76 | return alt::ICore::Instance().CreateColShapeRectangle((float)pos1.x, (float)pos1.y, (float)pos2.x, (float)pos2.y, 0);
77 | },
78 | py::arg("pos1"), py::arg("pos2"));
79 |
80 | pyClass.def_static(
81 | "polygon", [](float minZ, float maxZ, const std::vector& points) {
82 | std::vector parsed_points;
83 | for (auto point : points)
84 | parsed_points.emplace_back(point.ToAlt());
85 | return alt::ICore::Instance().CreateColShapePolygon(minZ, maxZ, parsed_points);
86 | },
87 | py::arg("min_z"), py::arg("max_z"), py::arg("points"));
88 |
89 | pyClass.def_property_readonly("colshape_type", &GetColShapeType);
90 | pyClass.def_property("players_only", &alt::IColShape::IsPlayersOnly, &alt::IColShape::SetPlayersOnly);
91 |
92 | pyClass.def("is_entity_in", &alt::IColShape::IsEntityIn, py::arg("entity"));
93 | pyClass.def("is_entity_in", &alt::IColShape::IsEntityIdIn, py::arg("entity_id"));
94 | pyClass.def("is_point_in", &IsPointIn, py::arg("pos"));
95 | }
96 |
--------------------------------------------------------------------------------
/src/events/Main.cpp:
--------------------------------------------------------------------------------
1 | #include "classes/types/enums.hpp"
2 | #include "classes/types/vector3.hpp"
3 | #include "events.hpp"
4 | #include "utils.hpp"
5 |
6 | EventHandler resourceStart(alt::CEvent::Type::RESOURCE_START, [](const alt::CEvent* ev, py::list& args) {
7 | auto event = dynamic_cast(ev);
8 | args.append(event->GetResource()->GetName());
9 | });
10 |
11 | EventHandler resourceStop(alt::CEvent::Type::RESOURCE_STOP, [](const alt::CEvent* ev, py::list& args) {
12 | auto event = dynamic_cast(ev);
13 | args.append(event->GetResource()->GetName());
14 | });
15 |
16 | EventHandler resourceError(alt::CEvent::Type::RESOURCE_ERROR, [](const alt::CEvent* ev, py::list& args) {
17 | auto event = dynamic_cast(ev);
18 | args.append(event->GetResource()->GetName());
19 | });
20 |
21 | EventHandler fire(alt::CEvent::Type::FIRE_EVENT, [](const alt::CEvent* ev, py::list& args) {
22 | auto event = dynamic_cast(ev);
23 | args.append(event->GetSource().Get());
24 | py::list fireInfos;
25 | for (alt::CFireEvent::FireInfo fireInfo : event->GetFires())
26 | {
27 | py::dict fireInfoDict;
28 | fireInfoDict["pos"] = Vector3(fireInfo.position);
29 | fireInfoDict["weapon"] = fireInfo.weaponHash;
30 | fireInfos.append(fireInfoDict);
31 | }
32 | args.append(fireInfos);
33 | });
34 |
35 | EventHandler explosion(alt::CEvent::Type::EXPLOSION_EVENT, [](const alt::CEvent* ev, py::list& args) {
36 | auto event = dynamic_cast(ev);
37 | args.append(event->GetSource().Get());
38 | args.append(static_cast(event->GetExplosionType()));
39 | args.append(Vector3(event->GetPosition()));
40 | args.append(event->GetExplosionFX());
41 | args.append(Utils::GetBaseObject(event->GetTarget()));
42 | });
43 |
44 | EventHandler startProjectile(alt::CEvent::Type::START_PROJECTILE_EVENT, [](const alt::CEvent* ev, py::list& args) {
45 | auto event = dynamic_cast(ev);
46 | args.append(event->GetSource().Get());
47 | args.append(Vector3(event->GetStartPosition()));
48 | args.append(Vector3(event->GetDirection()));
49 | args.append(event->GetAmmoHash());
50 | args.append(event->GetWeaponHash());
51 | });
52 |
53 | EventHandler weaponDamage(alt::CEvent::Type::WEAPON_DAMAGE_EVENT, [](const alt::CEvent* ev, py::list& args) {
54 | auto event = dynamic_cast(ev);
55 | args.append(event->GetSource().Get());
56 | args.append(Utils::GetBaseObject(event->GetTarget()));
57 | args.append(event->GetWeaponHash());
58 | args.append(event->GetDamageValue());
59 | args.append(Vector3(event->GetShotOffset()));
60 | args.append(static_cast(event->GetBodyPart()));
61 | });
62 |
63 | EventHandler netOwnerChange(alt::CEvent::Type::NETOWNER_CHANGE, [](const alt::CEvent* ev, py::list& args) {
64 | auto event = dynamic_cast(ev);
65 | args.append(Utils::GetBaseObject(event->GetTarget()));
66 | args.append(event->GetNewOwner().Get());
67 | args.append(event->GetOldOwner().Get());
68 | });
69 |
70 | EventHandler removeEntity(alt::CEvent::Type::REMOVE_ENTITY_EVENT, [](const alt::CEvent* ev, py::list& args) {
71 | auto event = dynamic_cast(ev);
72 | args.append(Utils::GetBaseObject(event->GetEntity()));
73 | });
74 |
75 | EventHandler consoleCommand(alt::CEvent::Type::CONSOLE_COMMAND_EVENT, [](const alt::CEvent* ev, py::list& args) {
76 | auto event = dynamic_cast(ev);
77 | args.append(event->GetName());
78 | py::list commandArgs;
79 | for (const auto& arg : event->GetArgs())
80 | commandArgs.append(arg);
81 | args.append(commandArgs);
82 | });
83 |
84 | EventHandler colShapeEvent(alt::CEvent::Type::COLSHAPE_EVENT, [](const alt::CEvent* ev, py::list& args) {
85 | auto event = dynamic_cast(ev);
86 | args.append(Utils::GetBaseObject(event->GetTarget().Get()));
87 | args.append(Utils::GetBaseObject(event->GetEntity().Get()));
88 | args.append(event->GetState());
89 | });
90 |
91 | EventHandler serverStarted(alt::CEvent::Type::SERVER_STARTED);
92 |
--------------------------------------------------------------------------------
/docs/alt/events.py:
--------------------------------------------------------------------------------
1 | from . import *
2 |
3 |
4 | def ServerStarted() -> None:
5 | ...
6 |
7 |
8 | def PlayerConnect(player: Player) -> None:
9 | ...
10 |
11 |
12 | def PlayerBeforeConnect(connection_info: ConnectionInfo) -> str | bool | None:
13 | ...
14 |
15 |
16 | def PlayerDisconnect(player: Player, reason: str) -> None:
17 | ...
18 |
19 |
20 | def ConnectionQueueAdd(connection_info: ConnectionInfo) -> None:
21 | ...
22 |
23 |
24 | def ConnectionQueueRemove(connection_info: ConnectionInfo) -> None:
25 | ...
26 |
27 |
28 | def ResourceStart(resource_name: str) -> None:
29 | ...
30 |
31 |
32 | def ResourceStop(resource_name: str) -> None:
33 | ...
34 |
35 |
36 | def ResourceError(resource_name: str) -> None:
37 | ...
38 |
39 |
40 | def SyncedMetaChange(entity: Entity, key: str, value: str, old_value: str) -> None:
41 | ...
42 |
43 |
44 | def StreamSyncedMetaChange(
45 | entity: Entity, key: str, value: str, old_value: str
46 | ) -> None:
47 | ...
48 |
49 |
50 | def GlobalMetaChange(key: str, value: str, old_value: str) -> None:
51 | ...
52 |
53 |
54 | def GlobalSyncedMetaChange(key: str, value: str, old_value: str) -> None:
55 | ...
56 |
57 |
58 | def LocalMetaChange(player: Player, key: str, value: str, old_value: str) -> None:
59 | ...
60 |
61 |
62 | def PlayerDamage(
63 | victim: Player,
64 | attacker: Entity,
65 | health_damage: int,
66 | armour_damage: int,
67 | weapon_hash: int,
68 | ) -> None:
69 | ...
70 |
71 |
72 | def PlayerDeath(victim: Player, killer: Entity, weapon_hash: int) -> None:
73 | ...
74 |
75 |
76 | def Fire(player: Player, fires: FireInfo) -> bool | None:
77 | ...
78 |
79 |
80 | def Explosion(
81 | source: Player, type: ExplosionType, pos: Vector3, fx: int, target: Entity
82 | ) -> bool | None:
83 | ...
84 |
85 |
86 | def StartProjectile(
87 | player: Player, pos: Vector3, dir: Vector3, ammo_hash: int, weapon_hash: int
88 | ) -> bool | None:
89 | ...
90 |
91 |
92 | def WeaponDamage(
93 | source: Player,
94 | target: Entity,
95 | weapon_hash: int,
96 | damage: int,
97 | offset: Vector3,
98 | body_part: BodyPart,
99 | ) -> bool | None:
100 | ...
101 |
102 |
103 | def VehicleDestroy(vehicle: Vehicle) -> None:
104 | ...
105 |
106 |
107 | def VehicleDamage(
108 | vehicle: Vehicle,
109 | attacker: Entity,
110 | body_health_damage: int,
111 | additional_body_health_damage: int,
112 | engine_health_damage: int,
113 | petrol_tank_damage: int,
114 | weapon: int,
115 | ) -> None:
116 | ...
117 |
118 |
119 | def ColShape(colshape: ColShape, entity: Entity, state: bool) -> None:
120 | ...
121 |
122 |
123 | def PlayerEnterVehicle(player: Player, vehicle: Vehicle, seat: int) -> None:
124 | ...
125 |
126 |
127 | def PlayerEnteringVehicle(player: Player, vehicle: Vehicle, seat: int) -> None:
128 | ...
129 |
130 |
131 | def PlayerLeftVehicle(player: Player, vehicle: Vehicle, seat: int) -> None:
132 | ...
133 |
134 |
135 | def PlayerChangeVehicleSeat(
136 | player: Player, vehicle: Vehicle, old_seat: int, seat: int
137 | ) -> None:
138 | ...
139 |
140 |
141 | def PlayerWeaponChange(player: Player, old_weapon: int, weapon: int) -> bool | None:
142 | ...
143 |
144 |
145 | def PlayerRequestControl(player: Player, target: Entity) -> bool | None:
146 | ...
147 |
148 |
149 | def VehicleAttach(vehicle: Vehicle, attached_vehicle: Vehicle) -> None:
150 | ...
151 |
152 |
153 | def VehicleDetach(vehicle: Vehicle, detached_vehicle: Vehicle) -> None:
154 | ...
155 |
156 |
157 | def NetOwnerChange(entity: Entity, owner: Player, old_owner: Player) -> None:
158 | ...
159 |
160 |
161 | def RemoveEntity(object: Entity) -> None:
162 | ...
163 |
164 |
165 | def ConsoleCommand(name: str, args: List[str]) -> None:
166 | ...
167 |
168 |
169 | def PlayerAnimationChange(
170 | player: Player,
171 | old_anim_dict: int,
172 | new_anim_dict: int,
173 | old_anim_name: int,
174 | new_anim_name: int,
175 | ) -> None:
176 | ...
177 |
178 |
179 | def PlayerInteriorChange(player: Player, new_interior: int, old_interior: int) -> None:
180 | ...
181 |
182 |
183 | def PlayerConnectDenied(
184 | player: Player,
185 | name: str,
186 | ip: str,
187 | password_hash: int,
188 | is_debug: bool,
189 | branch: str,
190 | version: int,
191 | cdn_url: str,
192 | discord_id: int,
193 | ) -> None:
194 | ...
195 |
--------------------------------------------------------------------------------
/src/classes/base/entity.cpp:
--------------------------------------------------------------------------------
1 | #include "classes/classes.hpp"
2 | #include "classes/types/vector3.hpp"
3 | #include "utils.hpp"
4 |
5 | py::list GetAllEntities(const py::object& type)
6 | {
7 | py::list list;
8 | auto array = alt::ICore::Instance().GetEntities();
9 | for (const auto& entity : array)
10 | list.append(Utils::GetBaseObject(entity));
11 | return list;
12 | }
13 |
14 | py::object GetEntityById(uint16_t id)
15 | {
16 | return Utils::GetBaseObject(alt::ICore::Instance().GetEntityByID(id));
17 | }
18 |
19 | Vector3 GetRotation(alt::IEntity* _this)
20 | {
21 | return (Vector3)_this->GetRotation();
22 | }
23 |
24 | void SetRotation(alt::IEntity* _this, Vector3 rot)
25 | {
26 | _this->SetRotation(rot.ToAlt());
27 | }
28 |
29 | void AttachToEntity(alt::IEntity* _this, alt::IEntity* entity, int16_t entityBoneId, int16_t ownBoneId, Vector3 pos, Vector3 rot, bool enableCollisions, bool noFixedRotation)
30 | {
31 | _this->AttachToEntity(entity, entityBoneId, ownBoneId, pos.ToAlt(), rot.ToAlt(), enableCollisions, noFixedRotation);
32 | }
33 |
34 | py::object GetSyncedMeta(alt::IEntity* _this, const std::string& key)
35 | {
36 | return Utils::MValueToValue(_this->GetSyncedMetaData(key));
37 | }
38 |
39 | py::object GetStreamSyncedMeta(alt::IEntity* _this, const std::string& key)
40 | {
41 | return Utils::MValueToValue(_this->GetStreamSyncedMetaData(key));
42 | }
43 |
44 | void SetSyncedMeta(alt::IEntity* _this, const std::string& key, const py::object& value)
45 | {
46 | _this->SetSyncedMetaData(key, Utils::ValueToMValue(value));
47 | }
48 |
49 | void SetStreamSyncedMeta(alt::IEntity* _this, const std::string& key, const py::object& value)
50 | {
51 | _this->SetStreamSyncedMetaData(key, Utils::ValueToMValue(value));
52 | }
53 |
54 | void ResetNetOwner(alt::IEntity* _this, bool disable_migration)
55 | {
56 | _this->SetNetworkOwner(nullptr, disable_migration);
57 | }
58 |
59 | void SetModel(alt::IPlayer* _this, const py::object& object)
60 | {
61 | if (py::isinstance(object))
62 | _this->SetModel(alt::ICore::Instance().Hash(object.cast()));
63 | else if (py::isinstance(object))
64 | _this->SetModel(object.cast());
65 | else
66 | throw py::value_error("int or str expected");
67 | }
68 |
69 | void RegisterEntityClass(const py::module_& m)
70 | {
71 | auto pyClass = py::class_>(m, "Entity");
72 |
73 | // Static
74 | pyClass.def_property_readonly_static("all", &GetAllEntities);
75 | pyClass.def_static("get_by_id", &GetEntityById, py::arg("id"));
76 |
77 | // Entity Data
78 | pyClass.def_property_readonly("id", &alt::IEntity::GetID);
79 | pyClass.def_property("rot", &GetRotation, &SetRotation);
80 | pyClass.def_property("streamed", &alt::IEntity::GetStreamed, &alt::IEntity::SetStreamed);
81 | pyClass.def_property("visible", &alt::IEntity::GetVisible, &alt::IEntity::SetVisible);
82 | pyClass.def_property("collision", &alt::IEntity::HasCollision, &alt::IEntity::SetCollision);
83 | pyClass.def_property("frozen", &alt::IEntity::IsFrozen, &alt::IEntity::SetFrozen);
84 |
85 | // Model
86 | pyClass.def_property("model", &alt::IEntity::GetModel, &SetModel);
87 |
88 | // NetOwner
89 | pyClass.def_property_readonly("net_owner", &alt::IEntity::GetNetworkOwner);
90 | pyClass.def("set_net_owner", &alt::IEntity::SetNetworkOwner, py::arg("player"), py::arg("disable_migration") = false);
91 | pyClass.def("reset_net_owner", &ResetNetOwner, py::arg("disable_migration") = false);
92 |
93 | // Attach
94 | pyClass.def("attach_to", &AttachToEntity, py::arg("entity"), py::arg("entity_bone_id"), py::arg("own_bone_id"), py::arg("pos"), py::arg("rot"), py::arg("enable_collisions"), py::arg("no_fixed_rotation"));
95 | pyClass.def("detach", &alt::IEntity::Detach);
96 |
97 | // Synced MetaData
98 | pyClass.def("get_synced_meta", &GetSyncedMeta, py::arg("key"));
99 | pyClass.def("has_synced_meta", &alt::IEntity::HasSyncedMetaData, py::arg("key"));
100 | pyClass.def("set_synced_meta", &SetSyncedMeta, py::arg("key"), py::arg("value"));
101 | pyClass.def("delete_synced_meta", &alt::IEntity::DeleteSyncedMetaData, py::arg("key"));
102 |
103 | // Stream Synced MetaData
104 | pyClass.def("get_stream_synced_meta", &GetStreamSyncedMeta, py::arg("key"));
105 | pyClass.def("has_stream_synced_meta", &alt::IEntity::HasStreamSyncedMetaData, py::arg("key"));
106 | pyClass.def("set_stream_synced_meta", &SetStreamSyncedMeta, py::arg("key"), py::arg("value"));
107 | pyClass.def("delete_stream_synced_meta", &alt::IEntity::DeleteStreamSyncedMetaData, py::arg("key"));
108 | }
109 |
--------------------------------------------------------------------------------
/src/events/player.cpp:
--------------------------------------------------------------------------------
1 | #include "events.hpp"
2 | #include "utils.hpp"
3 | #include "../classes/types/enums.hpp"
4 |
5 | EventHandler playerConnect(alt::CEvent::Type::PLAYER_CONNECT, [](const alt::CEvent* ev, py::list& args) {
6 | auto event = dynamic_cast(ev);
7 | args.append(event->GetTarget().Get());
8 | });
9 |
10 | EventHandler playerBeforeConnect(alt::CEvent::Type::PLAYER_BEFORE_CONNECT, [](const alt::CEvent* ev, py::list& args) {
11 | auto event = dynamic_cast(ev);
12 | args.append(event->GetConnectionInfo().Get());
13 | });
14 |
15 | EventHandler playerDisconnect(alt::CEvent::Type::PLAYER_DISCONNECT, [](const alt::CEvent* ev, py::list& args) {
16 | auto event = dynamic_cast(ev);
17 | args.append(event->GetTarget().Get());
18 | args.append(event->GetReason());
19 | });
20 |
21 | EventHandler connectionQueueAdd(alt::CEvent::Type::CONNECTION_QUEUE_ADD, [](const alt::CEvent* ev, py::list& args) {
22 | auto event = dynamic_cast(ev);
23 | args.append(event->GetConnectionInfo().Get());
24 | });
25 |
26 | EventHandler connectionQueueRemove(alt::CEvent::Type::CONNECTION_QUEUE_REMOVE, [](const alt::CEvent* ev, py::list& args) {
27 | auto event = dynamic_cast(ev);
28 | args.append(event->GetConnectionInfo().Get());
29 | });
30 |
31 | EventHandler playerDamage(alt::CEvent::Type::PLAYER_DAMAGE, [](const alt::CEvent* ev, py::list& args) {
32 | auto event = dynamic_cast(ev);
33 | args.append(event->GetTarget().Get());
34 | args.append(Utils::GetBaseObject(event->GetAttacker()));
35 | args.append(event->GetHealthDamage());
36 | args.append(event->GetArmourDamage());
37 | args.append(event->GetWeapon());
38 | });
39 |
40 | EventHandler playerDeath(alt::CEvent::Type::PLAYER_DEATH, [](const alt::CEvent* ev, py::list& args) {
41 | auto event = dynamic_cast(ev);
42 | args.append(event->GetTarget().Get());
43 | args.append(Utils::GetBaseObject(event->GetKiller()));
44 | args.append(event->GetWeapon());
45 | });
46 |
47 | EventHandler playerEnterVehicle(alt::CEvent::Type::PLAYER_ENTER_VEHICLE, [](const alt::CEvent* ev, py::list& args) {
48 | auto event = dynamic_cast(ev);
49 | args.append(event->GetPlayer().Get());
50 | args.append(event->GetTarget().Get());
51 | args.append(event->GetSeat());
52 | });
53 |
54 | EventHandler playerEnteringVehicle(alt::CEvent::Type::PLAYER_ENTERING_VEHICLE, [](const alt::CEvent* ev, py::list& args) {
55 | auto event = dynamic_cast(ev);
56 | args.append(event->GetPlayer().Get());
57 | args.append(event->GetTarget().Get());
58 | args.append(event->GetSeat());
59 | });
60 |
61 | EventHandler playerLeftVehicle(alt::CEvent::Type::PLAYER_LEAVE_VEHICLE, [](const alt::CEvent* ev, py::list& args) {
62 | auto event = dynamic_cast(ev);
63 | args.append(event->GetPlayer().Get());
64 | args.append(event->GetTarget().Get());
65 | args.append(event->GetSeat());
66 | });
67 |
68 | EventHandler playerChangeVehicleSeat(alt::CEvent::Type::PLAYER_CHANGE_VEHICLE_SEAT, [](const alt::CEvent* ev, py::list& args) {
69 | auto event = dynamic_cast(ev);
70 | args.append(event->GetPlayer().Get());
71 | args.append(event->GetTarget().Get());
72 | args.append(event->GetOldSeat());
73 | args.append(event->GetNewSeat());
74 | });
75 |
76 | EventHandler playerWeaponChange(alt::CEvent::Type::PLAYER_WEAPON_CHANGE, [](const alt::CEvent* ev, py::list& args) {
77 | auto event = dynamic_cast(ev);
78 | args.append(event->GetTarget().Get());
79 | args.append(event->GetOldWeapon());
80 | args.append(event->GetNewWeapon());
81 | });
82 |
83 | EventHandler playerRequestControl(alt::CEvent::Type::PLAYER_REQUEST_CONTROL, [](const alt::CEvent* ev, py::list& args) {
84 | auto event = dynamic_cast(ev);
85 | args.append(event->GetPlayer().Get());
86 | args.append(Utils::GetBaseObject(event->GetTarget().Get()));
87 | });
88 |
89 | EventHandler playerAnimationChange(alt::CEvent::Type::PLAYER_CHANGE_ANIMATION_EVENT, [](const alt::CEvent* ev, py::list& args) {
90 | auto event = dynamic_cast(ev);
91 | args.append(event->GetTarget().Get());
92 | args.append(event->GetOldAnimationDict());
93 | args.append(event->GetNewAnimationDict());
94 | args.append(event->GetOldAnimationName());
95 | args.append(event->GetNewAnimationName());
96 | });
97 |
98 |
99 | EventHandler playerInteriorChange(alt::CEvent::Type::PLAYER_CHANGE_INTERIOR_EVENT, [](const alt::CEvent* ev, py::list& args) {
100 | auto event = dynamic_cast(ev);
101 | args.append(event->GetTarget().Get());
102 | args.append(event->GetNewInteriorLocation());
103 | args.append(event->GetOldInteriorLocation());
104 | });
105 |
106 | EventHandler playerConnectDenied(alt::CEvent::Type::PLAYER_CONNECT_DENIED, [](const alt::CEvent* ev, py::list& args) {
107 | auto event = dynamic_cast(ev);
108 | args.append(ConnectDeniedReason(event->GetReason()));
109 | args.append(event->GetName());
110 | args.append(event->GetIp());
111 | args.append(event->GetPasswordHash());
112 | args.append(event->IsDebug());
113 | args.append(event->GetBranch());
114 | args.append(event->GetMajorVersion());
115 | args.append(event->GetCdnUrl());
116 | args.append(event->GetDiscordId());
117 | });
--------------------------------------------------------------------------------
/src/bindings/alt.cpp:
--------------------------------------------------------------------------------
1 | #include "main.hpp"
2 | #include "utils.hpp"
3 | #include "version/version.h"
4 |
5 | uint32_t Hash(const std::string& str)
6 | {
7 | return alt::ICore::Instance().Hash(str);
8 | }
9 |
10 | uint32_t GetNetTime()
11 | {
12 | return alt::ICore::Instance().GetNetTime();
13 | }
14 |
15 | py::dict GetServerConfig()
16 | {
17 | Config::Value::ValuePtr config = alt::ICore::Instance().GetServerConfig();
18 | return Utils::ConfigNodeToValue(config);
19 | }
20 |
21 | alt::VehicleModelInfo GetVehicleModelInfoByHash(uint32_t vehicleHash)
22 | {
23 | return alt::ICore::Instance().GetVehicleModelByHash(vehicleHash);
24 | }
25 |
26 | py::dict GetPedModelInfoByHash(uint32_t pedHash) {
27 | py::dict dict;
28 | alt::PedModelInfo pedModelInfo = alt::ICore::Instance().GetPedModelByHash(pedHash);
29 | dict["hash"] = pedModelInfo.hash;
30 | dict["name"] = pedModelInfo.name;
31 | py::list pedBones;
32 | for (const auto& pedBone : pedModelInfo.bones) {
33 | py::dict pyPedBone;
34 | pyPedBone["id"] = pedBone.id;
35 | pyPedBone["index"] = pedBone.index;
36 | pyPedBone["name"] = pedBone.name;
37 | pedBones.append(pyPedBone);
38 | }
39 | dict["bones"] = pedBones;
40 | return dict;
41 | }
42 |
43 | uint64_t HashServerPassword(const std::string& password)
44 | {
45 | return alt::ICore::Instance().HashServerPassword(password);
46 | }
47 |
48 | void RestartResource(const std::string& resourceName)
49 | {
50 | alt::ICore::Instance().RestartResource(resourceName);
51 | }
52 |
53 | void StartResource(const std::string& resourceName)
54 | {
55 | alt::ICore::Instance().StartResource(resourceName);
56 | }
57 |
58 | void StopResource(const std::string& resourceName)
59 | {
60 | alt::ICore::Instance().StopResource(resourceName);
61 | }
62 |
63 | void SetPassword(const std::string& password)
64 | {
65 | return alt::ICore::Instance().SetPassword(password);
66 | }
67 |
68 | void StopServer()
69 | {
70 | alt::ICore::Instance().StopServer();
71 | }
72 |
73 | std::string StringToSHA256(const std::string& str)
74 | {
75 | return alt::ICore::Instance().StringToSHA256(str);
76 | }
77 |
78 | void Export(const std::string& name, const py::object& object)
79 | {
80 | PyThreadState* interp = PyThreadState_Get();
81 | PythonResource* resource = PythonRuntime::GetInstance()->GetPythonResourceFromInterp(interp);
82 | auto exports = resource->GetResource()->GetExports();
83 | exports->Set(name, Utils::ValueToMValue(object));
84 | }
85 |
86 | py::object GetMeta(const std::string& key)
87 | {
88 | return Utils::MValueToValue(alt::ICore::Instance().GetMetaData(key));
89 | }
90 |
91 | void SetMeta(const std::string& key, const py::object& value)
92 | {
93 | alt::ICore::Instance().SetMetaData(key, Utils::ValueToMValue(value));
94 | }
95 |
96 | bool HasMeta(const std::string& key)
97 | {
98 | return alt::ICore::Instance().HasMetaData(key);
99 | }
100 |
101 | void DeleteMeta(const std::string& key)
102 | {
103 | return alt::ICore::Instance().DeleteMetaData(key);
104 | }
105 |
106 | py::object GetSyncedMeta(const std::string& key)
107 | {
108 | return Utils::MValueToValue(alt::ICore::Instance().GetSyncedMetaData(key));
109 | }
110 |
111 | void SetSyncedMeta(const std::string& key, const py::object& value)
112 | {
113 | alt::ICore::Instance().SetSyncedMetaData(key, Utils::ValueToMValue(value));
114 | }
115 |
116 | bool HasSyncedMeta(const std::string& key)
117 | {
118 | return alt::ICore::Instance().HasSyncedMetaData(key);
119 | }
120 |
121 | void DeleteSyncedMeta(const std::string& key)
122 | {
123 | alt::ICore::Instance().DeleteSyncedMetaData(key);
124 | }
125 |
126 | void SetWorldProfiler(bool state)
127 | {
128 | alt::ICore::Instance().SetWorldProfiler(state);
129 | }
130 |
131 | void RegisterMainFunctions(py::module_ m)
132 | {
133 | m.attr("branch") = alt::ICore::Instance().GetBranch();
134 | m.attr("debug") = alt::ICore::Instance().IsDebug();
135 | m.attr("default_dimension") = alt::DEFAULT_DIMENSION;
136 | m.attr("global_dimension") = alt::GLOBAL_DIMENSION;
137 | m.attr("root_dir") = alt::ICore::Instance().GetRootDirectory();
138 | m.attr("sdk_version") = ALT_SDK_VERSION;
139 | m.attr("version") = alt::ICore::Instance().GetVersion();
140 |
141 | m.def("hash", &Hash, py::arg("value"));
142 | m.def("get_net_time", &GetNetTime);
143 | m.def("get_server_config", &GetServerConfig);
144 | m.def("get_vehicle_model_info_by_hash", &GetVehicleModelInfoByHash, py::arg("vehicle_hash"));
145 | m.def("get_ped_model_info_by_hash", &GetPedModelInfoByHash, py::arg("ped_hash"));
146 | m.def("hash_server_password", &HashServerPassword, py::arg("password"));
147 | m.def("set_password", &SetPassword, py::arg("password"));
148 | m.def("stop_server", &StopServer);
149 | m.def("string_to_sha256", &StringToSHA256, py::arg("value"));
150 | m.def("export", &Export, py::arg("name"), py::arg("object"));
151 | m.def("set_world_profiler", &SetWorldProfiler, py::arg("state"));
152 |
153 | m.def("restart_resource", &RestartResource, py::arg("resource_name"));
154 | m.def("start_resource", &StartResource, py::arg("resource_name"));
155 | m.def("stop_resource", &StopResource, py::arg("resource_name"));
156 |
157 | m.def("get_meta", &GetMeta, py::arg("key"));
158 | m.def("set_meta", &SetMeta, py::arg("key"), py::arg("value"));
159 | m.def("has_meta", &HasMeta, py::arg("key"));
160 | m.def("delete_meta", &DeleteMeta, py::arg("key"));
161 |
162 | m.def("get_synced_meta", &GetSyncedMeta, py::arg("key"));
163 | m.def("set_synced_meta", &SetSyncedMeta, py::arg("key"), py::arg("value"));
164 | m.def("has_synced_meta", &HasSyncedMeta, py::arg("key"));
165 | m.def("delete_synced_meta", &DeleteSyncedMeta, py::arg("key"));
166 | }
167 |
--------------------------------------------------------------------------------
/src/classes/base/blip.cpp:
--------------------------------------------------------------------------------
1 | #include "classes/classes.hpp"
2 | #include "classes/types/enums.hpp"
3 | #include "classes/types/vector2.hpp"
4 | #include "classes/types/vector3.hpp"
5 | #include "utils.hpp"
6 |
7 | BlipColor GetBlipColor(alt::IBlip* _this)
8 | {
9 | return (BlipColor)_this->GetColor();
10 | }
11 |
12 | float GetBlipScale(alt::IBlip* _this)
13 | {
14 | return _this->GetScaleXY()[0];
15 | }
16 |
17 | void SetBlipScale(alt::IBlip* _this, float scale)
18 | {
19 | _this->SetScaleXY({scale, scale});
20 | }
21 |
22 | Vector2 GetSize(alt::IBlip* _this)
23 | {
24 | return (Vector2)_this->GetScaleXY();
25 | }
26 |
27 | void SetSize(alt::IBlip* _this, Vector2 size)
28 | {
29 | _this->SetScaleXY(size.ToAlt());
30 | }
31 |
32 | BlipSprite GetBlipSprite(alt::IBlip* _this)
33 | {
34 | return (BlipSprite)_this->GetSprite();
35 | }
36 |
37 | py::list GetAllBlips(const py::object& type)
38 | {
39 | return Utils::ArrayToPyList>(alt::ICore::Instance().GetBlips());
40 | }
41 |
42 | void RegisterBlipClass(const py::module_& m)
43 | {
44 | auto pyClass = py::class_>(m, "Blip");
45 |
46 | pyClass.def_static(
47 | "area", [](double x, double y, double z, float width, float height) {
48 | auto blip = alt::ICore::Instance().CreateBlip(nullptr, alt::IBlip::BlipType::AREA, {x, y, z});
49 | blip->SetScaleXY({width, height});
50 | return blip;
51 | },
52 | py::arg("x"), py::arg("y"), py::arg("z"), py::arg("width"), py::arg("height"));
53 |
54 | pyClass.def_static(
55 | "area", [](Vector3 pos, float width, float height) {
56 | auto blip = alt::ICore::Instance().CreateBlip(nullptr, alt::IBlip::BlipType::AREA, pos.ToAlt());
57 | blip->SetScaleXY({width, height});
58 | return blip;
59 | },
60 | py::arg("pos"), py::arg("width"), py::arg("height"));
61 |
62 | pyClass.def_static(
63 | "point", [](double x, double y, double z) {
64 | return alt::ICore::Instance().CreateBlip(nullptr, alt::IBlip::BlipType::DESTINATION, {x, y, z});
65 | },
66 | py::arg("x"), py::arg("y"), py::arg("z"));
67 |
68 | pyClass.def_static(
69 | "point", [](Vector3 pos) {
70 | return alt::ICore::Instance().CreateBlip(nullptr, alt::IBlip::BlipType::DESTINATION, pos.ToAlt());
71 | },
72 | py::arg("pos"));
73 |
74 | pyClass.def_static(
75 | "point", [](alt::IEntity* entity) {
76 | return alt::ICore::Instance().CreateBlip(nullptr, alt::IBlip::BlipType::DESTINATION, entity);
77 | },
78 | py::arg("entity"));
79 |
80 | pyClass.def_static(
81 | "radius", [](double x, double y, double z, float radius) {
82 | auto blip = alt::ICore::Instance().CreateBlip(nullptr, alt::IBlip::BlipType::RADIUS, {x, y, z});
83 | blip->SetScaleXY({radius, radius});
84 | return blip;
85 | },
86 | py::arg("x"), py::arg("y"), py::arg("z"), py::arg("radius"));
87 |
88 | pyClass.def_static(
89 | "radius", [](Vector3 pos, float radius) {
90 | auto blip = alt::ICore::Instance().CreateBlip(nullptr, alt::IBlip::BlipType::RADIUS, pos.ToAlt());
91 | blip->SetScaleXY({radius, radius});
92 | return blip;
93 | },
94 | py::arg("pos"), py::arg("radius"));
95 |
96 | pyClass.def_property_readonly_static("all", &GetAllBlips);
97 |
98 | pyClass.def("fade", &alt::IBlip::Fade, py::arg("opacity"), py::arg("duration"));
99 |
100 | pyClass.def_property("alpha", &alt::IBlip::GetAlpha, &alt::IBlip::SetAlpha);
101 | pyClass.def_property("as_mission_creator", &alt::IBlip::GetAsMissionCreator, &alt::IBlip::SetAsMissionCreator);
102 | pyClass.def_property("attached_to", &alt::IBlip::AttachedTo, &alt::IBlip::AttachTo);
103 | pyClass.def_property("bright", &alt::IBlip::GetBright, &alt::IBlip::SetBright);
104 | pyClass.def_property("category", &alt::IBlip::GetCategory, &alt::IBlip::SetCategory);
105 | pyClass.def_property("color", &GetBlipColor, &alt::IBlip::SetColor);
106 | pyClass.def_property("crew_indicator_visible", &alt::IBlip::GetCrewIndicatorVisible, &alt::IBlip::SetCrewIndicatorVisible);
107 | pyClass.def_property("display", &alt::IBlip::GetDisplay, &alt::IBlip::SetDisplay);
108 | pyClass.def_property("flash_interval", &alt::IBlip::GetFlashInterval, &alt::IBlip::SetFlashInterval);
109 | pyClass.def_property("flash_timer", &alt::IBlip::GetFlashTimer, &alt::IBlip::SetFlashTimer);
110 | pyClass.def_property("flashes", &alt::IBlip::GetFlashes, &alt::IBlip::SetFlashes);
111 | pyClass.def_property("flashes_alternate", &alt::IBlip::GetFlashesAlternate, &alt::IBlip::SetFlashesAlternate);
112 | pyClass.def_property("friend_indicator_visible", &alt::IBlip::GetFriendIndicatorVisible, &alt::IBlip::SetFriendIndicatorVisible);
113 | pyClass.def_property("gxt_name", &alt::IBlip::GetGxtName, &alt::IBlip::SetGxtName);
114 | pyClass.def_property("heading", &alt::IBlip::GetRotation, &alt::IBlip::SetRotation);
115 | pyClass.def_property("heading_indicator_visible", &alt::IBlip::GetHeadingIndicatorVisible, &alt::IBlip::SetHeadingIndicatorVisible);
116 | pyClass.def_property("high_detail", &alt::IBlip::GetAsHighDetail, &alt::IBlip::SetAsHighDetail);
117 | pyClass.def_property("name", &alt::IBlip::GetName, &alt::IBlip::SetName);
118 | pyClass.def_property("number", &alt::IBlip::GetNumber, &alt::IBlip::SetNumber);
119 | pyClass.def_property("outline_indicator_visible", &alt::IBlip::GetOutlineIndicatorVisible, &alt::IBlip::SetOutlineIndicatorVisible);
120 | pyClass.def_property("priority", &alt::IBlip::GetPriority, &alt::IBlip::SetPriority);
121 | pyClass.def_property("pulse", &alt::IBlip::GetPulse, &alt::IBlip::SetPulse);
122 | pyClass.def_property("route", &alt::IBlip::GetRoute, &alt::IBlip::SetRoute);
123 | pyClass.def_property("route_color", &alt::IBlip::GetRouteColor, &alt::IBlip::SetRouteColor);
124 | pyClass.def_property("scale", &GetBlipScale, &SetBlipScale);
125 | pyClass.def_property("secondary_color", &alt::IBlip::GetSecondaryColor, &alt::IBlip::SetSecondaryColor);
126 | pyClass.def_property("short_range", &alt::IBlip::GetAsShortRange, &alt::IBlip::SetAsShortRange);
127 | pyClass.def_property("show_cone", &alt::IBlip::GetShowCone, &alt::IBlip::SetShowCone);
128 | pyClass.def_property("shrinked", &alt::IBlip::GetShrinked, &alt::IBlip::SetShrinked);
129 | pyClass.def_property("size", &GetSize, &SetSize);
130 | pyClass.def_property("sprite", &GetBlipSprite, &alt::IBlip::SetSprite);
131 | pyClass.def_property("tick_visible", &alt::IBlip::GetTickVisible, &alt::IBlip::SetTickVisible);
132 | }
133 |
--------------------------------------------------------------------------------
/src/utils.cpp:
--------------------------------------------------------------------------------
1 | #include "utils.hpp"
2 | #include "classes/types/vector2.hpp"
3 | #include "classes/types/vector3.hpp"
4 |
5 | alt::MValue Utils::ValueToMValue(const py::object& arg)
6 | {
7 | if (py::isinstance(arg))
8 | return alt::ICore::Instance().CreateMValueString(py::str(arg).cast());
9 | else if (py::isinstance(arg))
10 | return alt::ICore::Instance().CreateMValueBool(py::bool_(arg).cast());
11 | else if (py::isinstance(arg))
12 | return alt::ICore::Instance().CreateMValueInt(py::int_(arg).cast());
13 | else if (py::isinstance(arg))
14 | return alt::ICore::Instance().CreateMValueNil();
15 | else if (py::isinstance(arg))
16 | return alt::ICore::Instance().CreateMValueDouble(py::float_(arg).cast());
17 | else if (py::isinstance(arg) || py::isinstance(arg))
18 | {
19 | auto tempList = alt::ICore::Instance().CreateMValueList();
20 | for (auto element : arg)
21 | tempList->Push(ValueToMValue(element.cast()));
22 | return tempList;
23 | }
24 | else if (py::isinstance(arg))
25 | {
26 | auto tempDict = alt::ICore::Instance().CreateMValueDict();
27 | auto dict = arg.cast();
28 | for (auto item : dict)
29 | tempDict->Set(item.first.cast(), ValueToMValue(item.second.cast()));
30 | return tempDict;
31 | }
32 | else if (py::isinstance(arg))
33 | {
34 | auto func = arg.cast();
35 | return alt::ICore::Instance().CreateMValueFunction(new PythonResource::PythonFunction(func));
36 | }
37 | else if (py::isinstance(arg))
38 | return alt::ICore::Instance().CreateMValueString(arg.cast().cast());
39 | else if (py::isinstance(arg))
40 | {
41 | auto byteArray = arg.cast();
42 | return alt::ICore::Instance().CreateMValueByteArray(reinterpret_cast(byteArray.cast().c_str()), byteArray.size());
43 | }
44 | else if (py::isinstance(arg))
45 | return alt::ICore::Instance().CreateMValueVector3(arg.cast().ToAlt());
46 | else if (py::isinstance(arg))
47 | return alt::ICore::Instance().CreateMValueVector2(arg.cast().ToAlt());
48 | else if (py::isinstance(arg))
49 | return alt::ICore::Instance().CreateMValueRGBA(arg.cast());
50 | else if (py::isinstance(arg))
51 | return alt::ICore::Instance().CreateMValueBaseObject(arg.cast());
52 | else
53 | return alt::ICore::Instance().CreateMValueNone();
54 | }
55 |
56 | py::object Utils::MValueToValue(const alt::MValueConst& mValue)
57 | {
58 | switch (mValue->GetType())
59 | {
60 | case alt::IMValue::Type::NIL:
61 | case alt::IMValue::Type::NONE:
62 | return py::none();
63 | case alt::IMValue::Type::BOOL:
64 | return py::bool_(mValue.As()->Value());
65 | case alt::IMValue::Type::INT:
66 | return py::int_(static_cast(mValue.As()->Value()));
67 | case alt::IMValue::Type::UINT:
68 | return py::int_(static_cast(mValue.As()->Value()));
69 | case alt::IMValue::Type::DOUBLE:
70 | return py::float_(mValue.As()->Value());
71 | case alt::IMValue::Type::STRING:
72 | return py::str(mValue.As()->Value());
73 | case alt::IMValue::Type::LIST: {
74 | auto mList = mValue.As();
75 | py::list pyList;
76 | for (uint64_t i = 0; i < mList->GetSize(); i++)
77 | pyList.append(MValueToValue(mList->Get(i)));
78 | return pyList;
79 | }
80 |
81 | case alt::IMValue::Type::DICT: {
82 | auto mDict = mValue.As();
83 | py::dict pyDict;
84 | for (auto item = mDict->Begin(); item; item = mDict->Next())
85 | {
86 | auto dictVal = MValueToValue(item->GetValue().Get());
87 | pyDict[item->GetKey().c_str()] = dictVal;
88 | }
89 | return pyDict;
90 | }
91 |
92 | case alt::IMValue::Type::VECTOR3: {
93 | Vector3 mVector3 = Vector3(mValue.As()->Value());
94 | return py::cast(mVector3);
95 | }
96 |
97 | case alt::IMValue::Type::VECTOR2: {
98 | Vector2 mVector2 = Vector2(mValue.As()->Value());
99 | return py::cast(mVector2);
100 | }
101 |
102 | case alt::IMValue::Type::BASE_OBJECT: {
103 | auto mBaseObject = mValue.As()->Value();
104 | return Utils::GetBaseObject(mBaseObject);
105 | }
106 | case alt::IMValue::Type::FUNCTION: {
107 | auto mFunc = mValue.As();
108 | py::cpp_function pyFunc = [mFunc](const py::args& args) {
109 | alt::MValueArgs funcArgs;
110 | for (auto arg : args)
111 | funcArgs.Push(Utils::ValueToMValue(arg.cast()));
112 | auto returnValue = mFunc->Call(funcArgs);
113 | return MValueToValue(returnValue);
114 | };
115 | return pyFunc;
116 | }
117 | case alt::IMValue::Type::RGBA: {
118 | auto mRGBA = mValue.As().Get()->Value();
119 | return py::cast(mRGBA);
120 | }
121 | case alt::IMValue::Type::BYTE_ARRAY: {
122 | auto mByteArray = mValue.As();
123 | return py::bytearray(reinterpret_cast(mByteArray->GetData()), (Py_ssize_t)mByteArray->GetSize());
124 | }
125 | default:
126 | return py::none();
127 | }
128 | }
129 |
130 | py::object Utils::ConfigNodeToValue(Config::Value::ValuePtr node)
131 | {
132 | switch (node->GetType())
133 | {
134 | case Config::Value::Type::NONE:
135 | return py::none();
136 | case Config::Value::Type::BOOL:
137 | return py::bool_(node->AsBool());
138 | case Config::Value::Type::NUMBER:
139 | return py::float_(node->AsNumber());
140 | case Config::Value::Type::STRING:
141 | return py::str(node->AsString());
142 | case Config::Value::Type::LIST: {
143 | Config::Value::List list = node->AsList();
144 | py::list pyList;
145 | for (auto val : list)
146 | pyList.append(ConfigNodeToValue(val));
147 | return pyList;
148 | }
149 | case Config::Value::Type::DICT: {
150 | Config::Value::Dict dict = node->AsDict();
151 | py::dict pyDict;
152 | for (auto& pair : dict)
153 | pyDict[pair.first.c_str()] = ConfigNodeToValue(pair.second);
154 | return pyDict;
155 | }
156 | default:
157 | return py::none();
158 | }
159 | }
160 |
161 | py::object Utils::GetBaseObject(const alt::Ref& baseObject)
162 | {
163 | if (!baseObject) return py::none();
164 | switch (baseObject->GetType())
165 | {
166 | case alt::IBaseObject::Type::PLAYER:
167 | return py::cast(dynamic_cast(baseObject.Get()));
168 | case alt::IBaseObject::Type::VEHICLE:
169 | return py::cast(dynamic_cast(baseObject.Get()));
170 | case alt::IBaseObject::Type::BLIP:
171 | return py::cast(dynamic_cast(baseObject.Get()));
172 | case alt::IBaseObject::Type::COLSHAPE:
173 | return py::cast(dynamic_cast(baseObject.Get()));
174 | case alt::IBaseObject::Type::CHECKPOINT:
175 | return py::cast(dynamic_cast(baseObject.Get()));
176 | case alt::IBaseObject::Type::VOICE_CHANNEL:
177 | return py::cast(dynamic_cast(baseObject.Get()));
178 | default:
179 | return py::none();
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/src/PythonResource.cpp:
--------------------------------------------------------------------------------
1 | #include "PythonResource.hpp"
2 | #include "utils.hpp"
3 |
4 | bool PythonResource::Start()
5 | {
6 | PyThreadState_Swap(runtime->GetInterpreter());
7 | interpreter = Py_NewInterpreter();
8 |
9 | std::string path = resource->GetPath();
10 | std::string main = resource->GetMain();
11 | std::string fullPath = path + SEPARATOR + main;
12 |
13 | // Makes importing local files possible
14 | py::module_ sys = py::module_::import("sys");
15 | py::list pyPath = sys.attr("path");
16 | pyPath.append(fullPath.substr(0, fullPath.find_last_of("\\/")));
17 |
18 | py::dict modules = sys.attr("modules");
19 | py::object imp = py::module_::import("importlib.util");
20 | for (const auto& depName : resource->GetDependencies())
21 | {
22 | alt::IResource* dep = alt::ICore::Instance().GetResource(depName);
23 |
24 | py::object spec = imp.attr("spec_from_loader")(depName, py::none());
25 | py::object module = imp.attr("module_from_spec")(spec);
26 |
27 | py::dict exports = Utils::MValueToValue(dep->GetExports());
28 | for (auto exp : exports)
29 | module.attr(exp.first) = exp.second;
30 | modules[depName.c_str()] = module;
31 | }
32 |
33 | FILE* fp = fopen(fullPath.c_str(), "r");
34 | if (!fp)
35 | {
36 | alt::ICore::Instance().LogError("Main file not found");
37 | return false;
38 | }
39 | bool crashed = PyRun_SimpleFile(fp, fullPath.c_str());
40 | fclose(fp);
41 |
42 | PyThreadState_Swap(runtime->GetInterpreter());
43 | return !crashed;
44 | }
45 | bool PythonResource::Stop()
46 | {
47 | localEvents.clear();
48 | localCustomEvents.clear();
49 | remoteEvents.clear();
50 | objects.clear();
51 |
52 | for (const auto& task : tasks) delete task;
53 | for (const auto& timer : timers) delete timer.second;
54 | tasks.clear();
55 | timers.clear();
56 | PyThreadState_Swap(interpreter);
57 | Py_EndInterpreter(interpreter);
58 | PyThreadState_Swap(runtime->GetInterpreter());
59 | return true;
60 | }
61 |
62 | bool PythonResource::OnEvent(const alt::CEvent* event)
63 | {
64 | auto eventType = event->GetType();
65 | if (eventType == alt::CEvent::Type::SERVER_SCRIPT_EVENT || eventType == alt::CEvent::Type::CLIENT_SCRIPT_EVENT)
66 | HandleCustomEvent(event);
67 | else
68 | {
69 | auto eventHandler = EventHandler::Get(event);
70 | if (eventHandler)
71 | {
72 | auto callbacks = localEvents[eventType];
73 | if (callbacks.empty()) return true;
74 | py::list eventArgs;
75 | eventHandler->GetEventArgs(event, eventArgs);
76 | for (const auto& callback : callbacks)
77 | {
78 | try
79 | {
80 | PyThreadState_Swap(interpreter);
81 | py::object returnValue = callback(*eventArgs);
82 | PyThreadState_Swap(runtime->GetInterpreter());
83 | if (py::isinstance(returnValue) && !returnValue.cast())
84 | event->Cancel();
85 | else if (py::isinstance(returnValue) && eventType == alt::CEvent::Type::PLAYER_BEFORE_CONNECT)
86 | reinterpret_cast(const_cast(event))->Cancel(returnValue.cast());
87 | }
88 | catch (py::error_already_set& e)
89 | {
90 | e.discard_as_unraisable(callback.attr("__name__"));
91 | }
92 | }
93 | }
94 | }
95 | return true;
96 | }
97 |
98 | void PythonResource::OnTick()
99 | {
100 | for (auto task : tasks)
101 | {
102 | uint32_t time = alt::ICore::Instance().GetNetTime();
103 | if (task->Update(time) && (alt::ICore::Instance().GetNetTime() - time) > 10)
104 | task->TimeWarning(time, resource->GetName());
105 | }
106 | for (auto it = timers.cbegin(); it != timers.cend();)
107 | {
108 | uint32_t time = alt::ICore::Instance().GetNetTime();
109 | if (it->second->Update(time))
110 | {
111 | if ((alt::ICore::Instance().GetNetTime() - time) > 10)
112 | it->second->TimeWarning(time, resource->GetName());
113 | delete it->second;
114 | it = timers.erase(it);
115 | }
116 | else
117 | it = std::next(it);
118 | }
119 | }
120 |
121 | void PythonResource::HandleCustomEvent(const alt::CEvent* ev)
122 | {
123 | py::list eventArgs;
124 | std::vector callbacks;
125 | if (ev->GetType() == alt::CEvent::Type::SERVER_SCRIPT_EVENT)
126 | {
127 | auto event = dynamic_cast(ev);
128 | std::string name = event->GetName();
129 | callbacks = localCustomEvents[name];
130 | if (callbacks.empty()) return;
131 | for (const auto& arg : event->GetArgs())
132 | {
133 | auto value = Utils::MValueToValue(arg);
134 | eventArgs.append(value);
135 | }
136 | }
137 | else
138 | {
139 | auto event = dynamic_cast(ev);
140 | std::string name = event->GetName();
141 | callbacks = remoteEvents[name];
142 | if (callbacks.empty()) return;
143 | eventArgs.append(event->GetTarget().Get());
144 | for (const auto& arg : event->GetArgs())
145 | {
146 | auto value = Utils::MValueToValue(arg);
147 | eventArgs.append(value);
148 | }
149 | }
150 | for (const auto& callback : callbacks)
151 | {
152 | try
153 | {
154 | PyThreadState_Swap(interpreter);
155 | callback(*eventArgs);
156 | PyThreadState_Swap(runtime->GetInterpreter());
157 | }
158 | catch (py::error_already_set& e)
159 | {
160 | e.discard_as_unraisable(callback.attr("__name__"));
161 | }
162 | }
163 | }
164 |
165 | void PythonResource::OnCreateBaseObject(alt::Ref object)
166 | {
167 | object->AddRef();
168 | objects.insert({object->GetType(), object});
169 | }
170 |
171 | void PythonResource::OnRemoveBaseObject(alt::Ref object)
172 | {
173 | auto range = objects.equal_range(object->GetType());
174 | for (auto it = range.first; it != range.second; it++)
175 | if (it->second == object)
176 | {
177 | objects.erase(it);
178 | break;
179 | }
180 | }
181 |
182 | bool PythonResource::IsObjectValid(const alt::Ref& object)
183 | {
184 | auto range = objects.equal_range(object->GetType());
185 | for (auto it = range.first; it != range.second; it++)
186 | if (it->second == object) return true;
187 | return false;
188 | }
189 |
190 | int PythonResource::AddTimer(double milliseconds, const py::function& func)
191 | {
192 | auto task = new Interval(milliseconds, func, interpreter);
193 | intervalId++;
194 | timers[intervalId] = task;
195 | return intervalId;
196 | }
197 |
198 | void PythonResource::ClearTimer(int timerId)
199 | {
200 | auto interval = timers[timerId];
201 | timers.erase(timerId);
202 | delete interval;
203 | }
204 |
205 | void PythonResource::AddTask(double milliseconds, const py::function& func)
206 | {
207 | auto task = new Interval(milliseconds, func, interpreter);
208 | tasks.push_back(task);
209 | }
210 |
211 | Interval* PythonResource::GetInterval(const py::function& func)
212 | {
213 | for (int i{}; i < tasks.size(); i++)
214 | if (tasks[i]->GetFunc().is(func))
215 | return tasks[i];
216 | return nullptr;
217 | }
218 |
219 | void PythonResource::AddScriptEvent(const alt::CEvent::Type& type, const py::function& eventFunc)
220 | {
221 | localEvents[type].push_back(eventFunc);
222 | }
223 |
224 | void PythonResource::AddServerEvent(const std::string& eventName, const py::function& eventFunc)
225 | {
226 | localCustomEvents[eventName].push_back(eventFunc);
227 | }
228 |
229 | void PythonResource::AddClientEvent(const std::string& eventName, const py::function& eventFunc)
230 | {
231 | remoteEvents[eventName].push_back(eventFunc);
232 | }
233 |
234 | alt::MValue PythonResource::PythonFunction::Call(alt::MValueArgs args) const
235 | {
236 | py::list funcArgs;
237 | for (const auto& arg : args)
238 | funcArgs.append(Utils::MValueToValue(arg));
239 | auto returnValue = func(*funcArgs);
240 | return Utils::ValueToMValue(returnValue);
241 | }
242 |
243 | bool PythonResource::MakeClient(alt::IResource::CreationInfo* info, alt::Array files)
244 | {
245 | info->type = "js";
246 | return true;
247 | }
248 |
--------------------------------------------------------------------------------
/docs/articles/events.md:
--------------------------------------------------------------------------------
1 | # Events
2 |
3 | Sometimes you want to execute code when something happens
4 |
5 | This is why events exist, let's take a look at how they work
6 |
7 | ## Event's with no arguments
8 |
9 | Let's start with events without any arguments as they are easier to understand, currently there is only one so let's take a look at it.
10 |
11 | ```py
12 | import alt
13 |
14 | @alt.event(alt.Event.ServerStarted)
15 | def server_started() -> None:
16 | alt.log("Server Started!")
17 | ```
18 |
19 | This code outputs `Server Started!` when the event is triggered, in this case the ServerStarted event which triggers when the server is started
20 |
21 | Let's go through this code line by line
22 |
23 | ---
24 |
25 | ### Decorator
26 | ```py hl_lines="3"
27 | import alt
28 |
29 | @alt.event(alt.Event.ServerStarted)
30 | def server_started() -> None:
31 | alt.log("Server Started!")
32 | ```
33 |
34 | This decorator `alt.event()` decorator, is placed above a function which should get executed once the specified event is triggered
35 |
36 | The first and only argument you pass to this function is an event you want to subscribe to. This has to be `alt.Event` enum, otherwise exception will be raised
37 |
38 | ---
39 |
40 | ### Function
41 | ```py hl_lines="4 5"
42 | import alt
43 |
44 | @alt.event(alt.Event.ServerStarted)
45 | def server_started() -> None:
46 | alt.log("Server Started!")
47 | ```
48 |
49 | This is the function you want to call once the event is triggered, the name can be anything you want
50 |
51 | Because we are creating event with no arguments, there shouldn't be any arguments for this function
52 |
53 | The body of the function can of course be anything you want, most of the time it's going to do something with the arguments passed to it
54 |
55 | ## Events with arguments
56 |
57 | Most of the time you want to get some info from events, this is possible through arguments
58 |
59 | ```py
60 | import alt
61 |
62 | @alt.event(alt.Event.PlayerConnect)
63 | def player_connect(player: alt.Player) -> None:
64 | alt.log(f"Player joined: {player.name}")
65 | player.model = "mp_m_freemode_01"
66 | player.spawn(0, 0, 0)
67 | ```
68 |
69 | The only difference between these events and events without arguments, is that the function you create needs to have arguments
70 |
71 | This is a PlayerConnect event which gets executed when player joins, our first argument is the player which connected
72 |
73 | In this event we are logging into the console that player joined, spawning the player and setting its model
74 |
75 | ## Custom events
76 |
77 | Sometimes you want to trigger events yourself, like for example when you want 2 resources communicate with each other or client to communicate with server
78 |
79 | The communication can go as follows:
80 |
81 | - Client -> Server
82 | - Server -> Client
83 | - Server -> Server
84 |
85 | ### Client -> Server
86 |
87 | ```js title="client.js"
88 | import alt from "alt-client";
89 |
90 | alt.emitServer("clientEvent", "This is message from client");
91 | ```
92 |
93 | ```py title="server.py"
94 | import alt
95 |
96 | @alt.client_event("clientEvent")
97 | def client_event(player: alt.Player, msg: str) -> None:
98 | alt.log(f"Player {player.name} sent {msg}")
99 | ```
100 |
101 | Client events work almost identically to normal events, you only need to replace the decorator `alt.event()` with `alt.client_event()` and instead of `alt.Event` enum, pass name of the event as string
102 |
103 | When you receive event from client, you will get the player object as the first argument, this is the player which triggered the event
104 |
105 | Rest of the arguments are the ones sent with the event, in this example it is the string `This is message from client`
106 |
107 | ### Server -> Client
108 |
109 | ```js title="client.js"
110 | import alt from "alt-client";
111 |
112 | alt.onServer("serverEvent", (msg) => {
113 | alt.log(msg);
114 | });
115 | ```
116 |
117 | ```py title="server.py"
118 | import alt
119 |
120 | @alt.event(alt.Event.PlayerConnect)
121 | def player_connect(player: alt.Player) -> None:
122 | # These 2 do the same thing
123 | player.emit("serverEvent", "This is a server event")
124 | alt.emit_client(player, "serverEvent", "This is a server event")
125 |
126 | # You can also pass list instead of single player
127 | alt.emit_client([player], "serverEvent", "This is a server event")
128 |
129 | # This will emit an event to all players
130 | alt.emit_all_clients("serverEvent", "This is a server event")
131 | ```
132 |
133 | When we want to emit event from server to specific player, we need to have the player object
134 |
135 | All the ways to emit a client event are showed in this code
136 |
137 | The first two emit event to single player only, they both work completely the same way
138 |
139 | The third one works the same way as the second one, apart from that you can pass list instead of single player, this can be useful when you need to emit event to multiple players
140 |
141 | And the fourth and last one is the simplest, by calling the function you emit event to players
142 |
143 | ### Server -> Server
144 |
145 | ```py
146 | import alt
147 |
148 | @alt.custom_event("customEvent")
149 | def custom_event(msg: str) -> None:
150 | alt.log(f"Message received {msg}")
151 |
152 | alt.emit("customEvent", "This is a message from server")
153 | ```
154 |
155 | Subscribing to events from server works the same way as with client events, only difference is that you use `alt.custom_event()` decorator
156 |
157 | Emitting the event is also very similar to emitting client event, you just call `alt.emit()` function and pass the event name and the arguments
158 |
159 | ### Note about custom event arguments
160 |
161 | Important thing to keep in mind, is that you can't pass everything as an event argument, the structures you sent have to be cross-language, so any custom object you might try to send as an argument won't work
162 |
163 | Here is the list of types which you can send: `str`, `int`, `float`, `bool`, `NoneType`, `list`, `dict`, `function`, `bytes`, `bytearray`, `alt.Vector2`, `alt.Vector3`, `alt.RGBA`, `alt.BaseObject`
164 |
165 | Functions can be only sent on the server, trying to send function to client or vice versa will fail
166 |
167 | Keep in mind that if you send function, the return value and arguments of the function must be sendable in an event
168 |
169 | ## Cancelling Events
170 |
171 | There are some events which you are able to cancel
172 |
173 | Most of them are triggered by player doing something, and by cancelling them you disable it syncing to other players
174 |
175 | ```py
176 | import alt
177 |
178 | @alt.event(alt.Event.Explosion)
179 | def explosion(player: alt.Player, *args) -> bool:
180 | alt.log(f"{player.name} caused an explosion")
181 | return False
182 | ```
183 |
184 | This is the explosion event, which gets triggered once explosion is created
185 |
186 | We can cancel events by returning `False`, you can cancel any event this way, but not every event will be changed once you cancel them
187 |
188 | Also, here you can see that we used `*args` as an argument, this makes it so that you don't need to specify every single argument if you don't need them
189 |
190 |
191 | The only event which works differently is `alt.Event.PlayerBeforeConnect`
192 |
193 | In this event you can return `False` as with other events, but also a string, this will do the same thing as returning `False` but will also show a message
194 |
195 | ```py
196 | import alt
197 |
198 | banned_players = [
199 | "very_bad_player"
200 | ]
201 |
202 | @alt.event(alt.Event.PlayerBeforeConnect)
203 | def player_before_connect(connection_info: alt.ConnectionInfo) -> str | None:
204 | if connection_info.name in banned_players:
205 | return "You are banned"
206 | ```
207 |
208 | ---
209 |
210 | You can see all of the available events inside [API Reference](api-reference/events.md)
211 |
212 | Now you should know what events are and how to use them
213 |
214 | In the next article we are going to learn about Tasks and Timers
215 |
--------------------------------------------------------------------------------
/src/classes/types/vector2.cpp:
--------------------------------------------------------------------------------
1 | #include "vector2.hpp"
2 | #include "classes/classes.hpp"
3 |
4 | double Vector2::GetAngle(const Vector2& other, const bool& degrees) const
5 | {
6 | double xy = x * other.x + y * other.y;
7 | double posALength = sqrt(std::pow(x, 2) + std::pow(y, 2));
8 | double posBLength = sqrt(std::pow(other.x, 2) + std::pow(other.y, 2));
9 |
10 | if (posALength == 0 || posBLength == 0)
11 | {
12 | return -1;
13 | }
14 |
15 | double cos = xy / (posALength * posBLength);
16 |
17 | if (degrees)
18 | return std::acos(cos);
19 | else
20 | return std::acos(cos) * (180 / alt::PI);
21 | }
22 |
23 | py::dict Vector2::ToDict()
24 | {
25 | py::dict dict;
26 | dict["x"] = x;
27 | dict["y"] = y;
28 | return dict;
29 | }
30 |
31 | py::list Vector2::ToList()
32 | {
33 | py::list list;
34 | list.append(x);
35 | list.append(y);
36 | return list;
37 | }
38 |
39 | alt::Position Vector2::ToAlt() const
40 | {
41 | return {x, y, 0};
42 | }
43 |
44 | std::string Vector2::ToString() const
45 | {
46 | return "Vector2(" + std::to_string(x) + ", " + std::to_string(y) + ")";
47 | }
48 |
49 | Vector2 Vector2::ToDegrees() const
50 | {
51 | return {x * (180 / alt::PI), y * (180 / alt::PI)};
52 | }
53 |
54 | Vector2 Vector2::ToRadians() const
55 | {
56 | return {x * (alt::PI / 180), y * (alt::PI / 180)};
57 | }
58 |
59 | double Vector2::Length() const
60 | {
61 | return sqrt(x * x + y * y);
62 | }
63 |
64 | double Vector2::Distance(Vector2& other) const
65 | {
66 | return sqrt(DistanceSquared(other));
67 | }
68 |
69 | double Vector2::DistanceSquared(Vector2& other) const
70 | {
71 | return std::pow(x - other.x, 2) + std::pow(y - other.y, 2);
72 | }
73 |
74 | Vector2 Vector2::Lerp(Vector2 other, double ratio) const
75 | {
76 | double x1 = x + (other.x - x) * ratio;
77 | double y1 = y + (other.y - y) * ratio;
78 | return {x1, y1};
79 | }
80 |
81 | bool Vector2::IsInRange(const Vector2& other, double range) const
82 | {
83 | double dx = abs(x - other.x);
84 | double dy = abs(y - other.y);
85 |
86 | return dx <= range && dy <= range && dx * dx + dy * dy <= range * range;
87 | }
88 |
89 | Vector2 Vector2::operator+(const Vector2& other) const
90 | {
91 | return {x + other.x, y + other.y};
92 | }
93 |
94 | Vector2 Vector2::operator+(double num) const
95 | {
96 | return {x + num, y + num};
97 | }
98 |
99 | Vector2 Vector2::operator+(const py::list& vectorList) const
100 | {
101 | return {x + vectorList[0].cast(), y + vectorList[1].cast()};
102 | }
103 |
104 | Vector2 Vector2::operator-(const Vector2& other) const
105 | {
106 | return {x - other.x, y - other.y};
107 | }
108 |
109 | Vector2 Vector2::operator-(double num) const
110 | {
111 | return {x - num, y - num};
112 | }
113 |
114 | Vector2 Vector2::operator-(const py::list& vectorList) const
115 | {
116 | return {x - vectorList[0].cast(), y - vectorList[1].cast()};
117 | }
118 |
119 | Vector2 Vector2::operator-() const
120 | {
121 | return {-x, -y};
122 | }
123 |
124 | Vector2 Vector2::operator/(const Vector2& other) const
125 | {
126 | return {x / other.x, y / other.y};
127 | }
128 |
129 | Vector2 Vector2::operator/(double num) const
130 | {
131 | return {x / num, y / num};
132 | }
133 |
134 | Vector2 Vector2::operator/(const py::list& vectorList) const
135 | {
136 | return {x / vectorList[0].cast(), y / vectorList[1].cast()};
137 | }
138 |
139 | Vector2 Vector2::operator*(const Vector2& other) const
140 | {
141 | return {x * other.x, y * other.y};
142 | }
143 |
144 | Vector2 Vector2::operator*(double num) const
145 | {
146 | return {x * num, y * num};
147 | }
148 |
149 | Vector2 Vector2::operator*(const py::list& vectorList) const
150 | {
151 | return {x * vectorList[0].cast(), y * vectorList[1].cast()};
152 | }
153 |
154 | bool Vector2::operator==(const Vector2& other) const
155 | {
156 | return x == other.x && y == other.y;
157 | }
158 |
159 | double Vector2::Dot(const Vector2& other) const
160 | {
161 | return x * other.x + y * other.y;
162 | }
163 |
164 | double Vector2::Dot(double num) const
165 | {
166 | return x * num + y * num;
167 | }
168 |
169 | double Vector2::Dot(const py::list& vectorList) const
170 | {
171 | return x * vectorList[0].cast() + y * vectorList[1].cast();
172 | }
173 |
174 | Vector2 Vector2::Normalize() const
175 | {
176 | double length = sqrt(x * x + y * y);
177 | return {x / length, y / length};
178 | }
179 |
180 | Vector2 Vector2::Zero(const py::object& _this)
181 | {
182 | return {0, 0};
183 | }
184 |
185 | Vector2 Vector2::One(const py::object& _this)
186 | {
187 | return {1, 1};
188 | }
189 |
190 | Vector2 Vector2::Up(const py::object& _this)
191 | {
192 | return {0, 1};
193 | }
194 |
195 | Vector2 Vector2::Down(const py::object& _this)
196 | {
197 | return {0, -1};
198 | }
199 |
200 | Vector2 Vector2::Left(const py::object& _this)
201 | {
202 | return {-1, 0};
203 | }
204 |
205 | Vector2 Vector2::Right(const py::object& _this)
206 | {
207 | return {1, 0};
208 | }
209 |
210 | Vector2 Vector2::PositiveInfinity(const py::object& _this)
211 | {
212 | return {std::numeric_limits::infinity(), std::numeric_limits::infinity()};
213 | }
214 |
215 | Vector2 Vector2::NegativeInfinity(const py::object& _this)
216 | {
217 | return {-std::numeric_limits::infinity(), -std::numeric_limits::infinity()};
218 | }
219 |
220 | double Vector2::AngleTo(const Vector2& other)
221 | {
222 | return GetAngle(other, false);
223 | }
224 |
225 | double Vector2::AngleToDegrees(const Vector2& other)
226 | {
227 | return GetAngle(other, true);
228 | }
229 |
230 | void RegisterVector2Class(const py::module_& m)
231 | {
232 | auto pyClass = py::class_(m, "Vector2");
233 | pyClass.def(py::init([](double _x, double _y) { return Vector2(_x, _y); }), py::arg("x"), py::arg("y"));
234 | pyClass.def(py::init([](const py::list& vectorList) { return Vector2(vectorList); }), py::arg("vector_list"));
235 |
236 | pyClass.def_readwrite("x", &Vector2::x);
237 | pyClass.def_readwrite("y", &Vector2::y);
238 | pyClass.def("__str__", &Vector2::ToString);
239 |
240 | pyClass.def("to_dict", &Vector2::ToDict);
241 | pyClass.def("to_list", &Vector2::ToList);
242 | pyClass.def("length", &Vector2::Length);
243 | pyClass.def("distance", &Vector2::Distance, py::arg("vector"));
244 | pyClass.def("distance_squared", &Vector2::DistanceSquared, py::arg("vector"));
245 | pyClass.def("lerp", &Vector2::Lerp, py::arg("vector"), py::arg("ratio"));
246 |
247 | pyClass.def("to_degrees", &Vector2::ToDegrees);
248 | pyClass.def("to_radians", &Vector2::ToRadians);
249 | pyClass.def("is_in_range", &Vector2::IsInRange, py::arg("vector"), py::arg("range"));
250 |
251 | pyClass.def(py::self + py::self);
252 | pyClass.def(py::self + double());
253 | pyClass.def(py::self + py::list());
254 |
255 | pyClass.def(py::self - py::self);
256 | pyClass.def(py::self - double());
257 | pyClass.def(py::self - py::list());
258 | pyClass.def(-py::self);
259 |
260 | pyClass.def(py::self * py::self);
261 | pyClass.def(py::self * double());
262 | pyClass.def(py::self * py::list());
263 |
264 | pyClass.def(py::self / py::self);
265 | pyClass.def(py::self / double());
266 | pyClass.def(py::self / py::list());
267 |
268 | pyClass.def(py::self == py::self);
269 |
270 | pyClass.def("dot", py::overload_cast(&Vector2::Dot, py::const_), py::arg("vector"));
271 | pyClass.def("dot", py::overload_cast(&Vector2::Dot, py::const_), py::arg("vector_list"));
272 | pyClass.def("dot", py::overload_cast(&Vector2::Dot, py::const_), py::arg("num"));
273 |
274 | pyClass.def_property_readonly_static("zero", &Vector2::Zero);
275 | pyClass.def_property_readonly_static("one", &Vector2::One);
276 | pyClass.def_property_readonly_static("up", &Vector2::Up);
277 | pyClass.def_property_readonly_static("down", &Vector2::Down);
278 | pyClass.def_property_readonly_static("left", &Vector2::Left);
279 | pyClass.def_property_readonly_static("right", &Vector2::Right);
280 | pyClass.def_property_readonly_static("positive_infinity", &Vector2::PositiveInfinity);
281 | pyClass.def_property_readonly_static("negative_infinity", &Vector2::NegativeInfinity);
282 |
283 | pyClass.def("normalize", &Vector2::Normalize);
284 | pyClass.def("angle_to", &Vector2::AngleTo, py::arg("vector"));
285 | pyClass.def("angle_to_degrees", &Vector2::AngleToDegrees, py::arg("vector"));
286 | }
287 |
--------------------------------------------------------------------------------
/src/classes/types/vector3.cpp:
--------------------------------------------------------------------------------
1 | #include "vector3.hpp"
2 | #include "classes/classes.hpp"
3 |
4 | double Vector3::GetAngle(const Vector3& other, const bool& degrees) const
5 | {
6 | double xy = x * other.x + y * other.y;
7 | double posALength = sqrt(std::pow(x, 2) + std::pow(y, 2));
8 | double posBLength = sqrt(std::pow(other.x, 2) + std::pow(other.y, 2));
9 |
10 | if (posALength == 0 || posBLength == 0)
11 | {
12 | return -1;
13 | }
14 |
15 | double cos = xy / (posALength * posBLength);
16 |
17 | if (degrees)
18 | return std::acos(cos);
19 | else
20 | return std::acos(cos) * (180 / alt::PI);
21 | }
22 |
23 | py::dict Vector3::ToDict()
24 | {
25 | py::dict dict;
26 | dict["x"] = x;
27 | dict["y"] = y;
28 | dict["z"] = z;
29 | return dict;
30 | }
31 |
32 | py::list Vector3::ToList()
33 | {
34 | py::list list;
35 | list.append(x);
36 | list.append(y);
37 | list.append(z);
38 | return list;
39 | }
40 |
41 | alt::Position Vector3::ToAlt() const
42 | {
43 | return alt::Position{x, y, z};
44 | }
45 |
46 | std::string Vector3::ToString() const
47 | {
48 | return "Vector3(" + std::to_string(x) + ", " + std::to_string(y) + ", " + std::to_string(z) + ")";
49 | }
50 |
51 | Vector3 Vector3::ToDegrees() const
52 | {
53 | return {x * (180 / alt::PI), y * (180 / alt::PI), z * (180 / alt::PI)};
54 | }
55 |
56 | Vector3 Vector3::ToRadians() const
57 | {
58 | return {x * (alt::PI / 180), y * (alt::PI / 180), z * (alt::PI / 180)};
59 | }
60 |
61 | double Vector3::Length() const
62 | {
63 | return sqrt(x * x + y * y + z * z);
64 | }
65 |
66 | double Vector3::Distance(Vector3& other) const
67 | {
68 | return sqrt(DistanceSquared(other));
69 | }
70 |
71 | double Vector3::DistanceSquared(Vector3& other) const
72 | {
73 | return std::pow(x - other.x, 2) + std::pow(y - other.y, 2) + std::pow(z - other.z, 2);
74 | }
75 |
76 | bool Vector3::IsInRange(const Vector3& other, double range) const
77 | {
78 | double dx = abs(x - other.x);
79 | double dy = abs(y - other.y);
80 | double dz = abs(z - other.z);
81 |
82 | return dx <= range && dy <= range && dz <= range && dx * dx + dy * dy + dz * dz <= range * range;
83 | }
84 |
85 | Vector3 Vector3::Lerp(Vector3 other, double ratio) const
86 | {
87 | double x1 = x + (other.x - x) * ratio;
88 | double y1 = y + (other.y - y) * ratio;
89 | double z1 = z + (other.z - z) * ratio;
90 | return {x1, y1, z1};
91 | }
92 |
93 | Vector3 Vector3::operator+(const Vector3& other) const
94 | {
95 | return {x + other.x, y + other.y, z + other.z};
96 | }
97 |
98 | Vector3 Vector3::operator+(double num) const
99 | {
100 | return {x + num, y + num, z + num};
101 | }
102 |
103 | Vector3 Vector3::operator+(const py::list& vectorList) const
104 | {
105 | return {x + vectorList[0].cast(), y + vectorList[1].cast(), z + vectorList[2].cast()};
106 | }
107 |
108 | Vector3 Vector3::operator-(const Vector3& other) const
109 | {
110 | return {x - other.x, y - other.y, z - other.z};
111 | }
112 |
113 | Vector3 Vector3::operator-(double num) const
114 | {
115 | return {x - num, y - num, z - num};
116 | }
117 |
118 | Vector3 Vector3::operator-(const py::list& vectorList) const
119 | {
120 | return {x - vectorList[0].cast(), y - vectorList[1].cast(), z - vectorList[2].cast()};
121 | }
122 |
123 | Vector3 Vector3::operator-() const
124 | {
125 | return {-x, -y, -z};
126 | }
127 |
128 | Vector3 Vector3::operator/(const Vector3& other) const
129 | {
130 | return {x / other.x, y / other.y, z / other.z};
131 | }
132 |
133 | Vector3 Vector3::operator/(double num) const
134 | {
135 | return {x / num, y / num, z / num};
136 | }
137 |
138 | Vector3 Vector3::operator/(const py::list& vectorList) const
139 | {
140 | return {x / vectorList[0].cast(), y / vectorList[1].cast(), z / vectorList[2].cast()};
141 | }
142 |
143 | Vector3 Vector3::operator*(const Vector3& other) const
144 | {
145 | return {x * other.x, y * other.y, z * other.z};
146 | }
147 |
148 | Vector3 Vector3::operator*(double num) const
149 | {
150 | return {x * num, y * num, z * num};
151 | }
152 |
153 | Vector3 Vector3::operator*(const py::list& vectorList) const
154 | {
155 | return {x * vectorList[0].cast(), y * vectorList[1].cast(), z * vectorList[2].cast()};
156 | }
157 |
158 | bool Vector3::operator==(const Vector3& other) const
159 | {
160 | return x == other.x && y == other.y && z == other.z;
161 | }
162 |
163 | Vector3 Vector3::Cross(const Vector3& other) const
164 | {
165 | return {y * other.z - z * other.y, z * other.x - x * other.z, x * other.y - y * other.x};
166 | }
167 |
168 | Vector3 Vector3::Cross(double num) const
169 | {
170 | return {y * num - z * num, z * num - x * num, x * num - y * num};
171 | }
172 |
173 | Vector3 Vector3::Cross(const py::list& vectorList) const
174 | {
175 | auto _x = vectorList[0].cast();
176 | auto _y = vectorList[1].cast();
177 | auto _z = vectorList[2].cast();
178 |
179 | return {y * _z - z * _y, z * _x - x * _z, x * _y - y * _x};
180 | }
181 |
182 | double Vector3::Dot(const Vector3& other) const
183 | {
184 | return x * other.x + y * other.y + z * other.z;
185 | }
186 |
187 | double Vector3::Dot(double num) const
188 | {
189 | return x * num + y * num + z * num;
190 | }
191 |
192 | double Vector3::Dot(const py::list& vectorList) const
193 | {
194 | return x * vectorList[0].cast() + y * vectorList[1].cast() + z * vectorList[2].cast();
195 | }
196 |
197 | Vector3 Vector3::Normalize() const
198 | {
199 | double length = sqrt(x * x + y * y + z * z);
200 | return {x / length, y / length, z / length};
201 | }
202 |
203 | Vector3 Vector3::Zero(const py::object& _this)
204 | {
205 | return {0, 0, 0};
206 | }
207 |
208 | Vector3 Vector3::One(const py::object& _this)
209 | {
210 | return {1, 1, 1};
211 | }
212 |
213 | Vector3 Vector3::Up(const py::object& _this)
214 | {
215 | return {0, 1, 0};
216 | }
217 |
218 | Vector3 Vector3::Down(const py::object& _this)
219 | {
220 | return {0, -1, 0};
221 | }
222 |
223 | Vector3 Vector3::Left(const py::object& _this)
224 | {
225 | return {-1, 0, 0};
226 | }
227 |
228 | Vector3 Vector3::Right(const py::object& _this)
229 | {
230 | return {1, 0, 0};
231 | }
232 |
233 | Vector3 Vector3::Back(const py::object& _this)
234 | {
235 | return {0, 0, -1};
236 | }
237 |
238 | Vector3 Vector3::Forward(const py::object& _this)
239 | {
240 | return {0, 0, 1};
241 | }
242 |
243 | Vector3 Vector3::PositiveInfinity(const py::object& _this)
244 | {
245 | return {std::numeric_limits::infinity(), std::numeric_limits::infinity(),
246 | std::numeric_limits::infinity()};
247 | }
248 |
249 | Vector3 Vector3::NegativeInfinity(const py::object& _this)
250 | {
251 | return {-std::numeric_limits::infinity(), -std::numeric_limits::infinity(),
252 | -std::numeric_limits::infinity()};
253 | }
254 |
255 | double Vector3::AngleTo(const Vector3& other)
256 | {
257 | return GetAngle(other, false);
258 | }
259 |
260 | double Vector3::AngleToDegrees(const Vector3& other)
261 | {
262 | return GetAngle(other, true);
263 | }
264 |
265 | void RegisterVector3Class(const py::module_& m)
266 | {
267 | auto pyClass = py::class_(m, "Vector3");
268 | pyClass.def(py::init([](double _x, double _y, double _z) { return Vector3(_x, _y, _z); }), py::arg("x"), py::arg("y"), py::arg("z"));
269 | pyClass.def(py::init([](const py::list& vectorList) { return Vector3(vectorList); }), py::arg("vector_list"));
270 |
271 | pyClass.def_readwrite("x", &Vector3::x);
272 | pyClass.def_readwrite("y", &Vector3::y);
273 | pyClass.def_readwrite("z", &Vector3::z);
274 | pyClass.def("__str__", &Vector3::ToString);
275 |
276 | pyClass.def("to_dict", &Vector3::ToDict);
277 | pyClass.def("to_list", &Vector3::ToList);
278 | pyClass.def("length", &Vector3::Length);
279 | pyClass.def("distance", &Vector3::Distance, py::arg("vector"));
280 | pyClass.def("distance_squared", &Vector3::DistanceSquared, py::arg("vector"));
281 |
282 | pyClass.def("to_degrees", &Vector3::ToDegrees);
283 | pyClass.def("to_radians", &Vector3::ToRadians);
284 | pyClass.def("is_in_range", &Vector3::IsInRange, py::arg("vector"), py::arg("range"));
285 | pyClass.def("lerp", &Vector3::Lerp, py::arg("vector"), py::arg("ratio"));
286 |
287 | pyClass.def(py::self + py::self);
288 | pyClass.def(py::self + double());
289 | pyClass.def(py::self + py::list());
290 |
291 | pyClass.def(py::self - py::self);
292 | pyClass.def(py::self - double());
293 | pyClass.def(py::self - py::list());
294 | pyClass.def(-py::self);
295 |
296 | pyClass.def(py::self * py::self);
297 | pyClass.def(py::self * double());
298 | pyClass.def(py::self * py::list());
299 |
300 | pyClass.def(py::self / py::list());
301 | pyClass.def(py::self / double());
302 | pyClass.def(py::self / py::self);
303 |
304 | pyClass.def(py::self == py::self);
305 |
306 | pyClass.def("cross", py::overload_cast(&Vector3::Cross, py::const_), py::arg("vector"));
307 | pyClass.def("cross", py::overload_cast(&Vector3::Cross, py::const_), py::arg("num"));
308 | pyClass.def("cross", py::overload_cast(&Vector3::Cross, py::const_), py::arg("vector_list"));
309 |
310 | pyClass.def("dot", py::overload_cast(&Vector3::Dot, py::const_), py::arg("vector"));
311 | pyClass.def("dot", py::overload_cast(&Vector3::Dot, py::const_), py::arg("num"));
312 | pyClass.def("dot", py::overload_cast(&Vector3::Dot, py::const_), py::arg("vector_list"));
313 |
314 | pyClass.def_property_readonly_static("zero", &Vector3::Zero);
315 | pyClass.def_property_readonly_static("one", &Vector3::One);
316 | pyClass.def_property_readonly_static("up", &Vector3::Up);
317 | pyClass.def_property_readonly_static("down", &Vector3::Down);
318 | pyClass.def_property_readonly_static("left", &Vector3::Left);
319 | pyClass.def_property_readonly_static("right", &Vector3::Right);
320 | pyClass.def_property_readonly_static("back", &Vector3::Back);
321 | pyClass.def_property_readonly_static("forward", &Vector3::Forward);
322 | pyClass.def_property_readonly_static("positive_infinity", &Vector3::PositiveInfinity);
323 | pyClass.def_property_readonly_static("negative_infinity", &Vector3::NegativeInfinity);
324 |
325 | pyClass.def("normalize", &Vector3::Normalize);
326 | pyClass.def("angle_to", &Vector3::AngleTo, py::arg("vector"));
327 | pyClass.def("angle_to_degrees", &Vector3::AngleToDegrees, py::arg("vector"));
328 | }
329 |
--------------------------------------------------------------------------------
/src/classes/base/player.cpp:
--------------------------------------------------------------------------------
1 | #include "classes/classes.hpp"
2 | #include "classes/types/enums.hpp"
3 | #include "classes/types/vector3.hpp"
4 | #include "utils.hpp"
5 |
6 | py::list GetAllPlayers(const py::object& type)
7 | {
8 | return Utils::ArrayToPyList>(alt::ICore::Instance().GetPlayers());
9 | }
10 |
11 | alt::IPlayer* GetPlayerById(uint16_t id)
12 | {
13 | auto entity = alt::ICore::Instance().GetEntityByID(id);
14 | if (entity && entity->GetType() == alt::IBaseObject::Type::PLAYER)
15 | return dynamic_cast(entity.Get());
16 | return nullptr;
17 | }
18 |
19 | void Spawn(alt::IPlayer* _this, float x, float y, float z, uint32_t delay = 0)
20 | {
21 | alt::Position altPos{x, y, z};
22 | _this->Spawn(altPos, delay);
23 | }
24 |
25 | void Spawn(alt::IPlayer* _this, Vector3 pos, uint32_t delay = 0)
26 | {
27 | _this->Spawn(pos.ToAlt(), delay);
28 | }
29 |
30 | py::list GetCurrentWeaponComponents(alt::IPlayer* _this)
31 | {
32 | return Utils::ArrayToPyList(_this->GetCurrentWeaponComponents());
33 | }
34 |
35 | py::list GetWeapons(alt::IPlayer* _this)
36 | {
37 | py::list list;
38 | alt::Array weapons = _this->GetWeapons();
39 | for (const alt::Weapon& weapon : weapons)
40 | {
41 | py::dict dict;
42 | dict["hash"] = weapon.hash;
43 | dict["tint_index"] = weapon.tintIndex;
44 | dict["components"] = weapon.components;
45 | list.append(dict);
46 | }
47 | return list;
48 | }
49 |
50 | void SetDlcClothes(alt::IPlayer* _this, uint32_t dlc, uint8_t component, uint16_t drawable, uint8_t texture, uint8_t palette = 2)
51 | {
52 | if (drawable < 128)
53 | _this->SetDlcClothes(component, drawable, texture, palette, dlc);
54 | else
55 | throw py::value_error("Drawable can't be higher than 127");
56 | }
57 |
58 | bool SetDlcProps(alt::IPlayer* _this, uint32_t dlc, uint8_t component, uint8_t drawable, uint8_t texture)
59 | {
60 | return _this->SetDlcProps(component, drawable, texture, dlc);
61 | }
62 |
63 | Vector3 GetAimPos(alt::IPlayer* _this)
64 | {
65 | return (Vector3)_this->GetAimPos();
66 | }
67 |
68 | Vector3 GetHeadRot(alt::IPlayer* _this)
69 | {
70 | return (Vector3)_this->GetHeadRotation();
71 | }
72 |
73 | py::object GetEntityAimingAt(alt::IPlayer* _this)
74 | {
75 | return Utils::GetBaseObject(_this->GetEntityAimingAt());
76 | }
77 |
78 | WeaponTint GetCurrentWeaponTintIndex(alt::IPlayer* _this)
79 | {
80 | return (WeaponTint)_this->GetCurrentWeaponTintIndex();
81 | }
82 |
83 | Vector3 GetEntityAimOffset(alt::IPlayer* _this)
84 | {
85 | return (Vector3)_this->GetEntityAimOffset();
86 | }
87 |
88 | py::dict GetClothes(alt::IPlayer* _this, uint8_t component)
89 | {
90 | alt::Cloth cloth = _this->GetClothes(component);
91 | py::dict dict;
92 | dict["drawable"] = cloth.drawableId;
93 | dict["texture"] = cloth.textureId;
94 | dict["palette"] = cloth.paletteId;
95 | return dict;
96 | }
97 |
98 | py::dict GetDlcClothes(alt::IPlayer* _this, uint8_t component)
99 | {
100 | alt::DlcCloth dlcCloth = _this->GetDlcClothes(component);
101 | py::dict dict;
102 | dict["dlc"] = dlcCloth.dlc;
103 | dict["drawable"] = dlcCloth.drawableId;
104 | dict["texture"] = dlcCloth.textureId;
105 | dict["palette"] = dlcCloth.paletteId;
106 | return dict;
107 | }
108 |
109 | py::dict GetDlcProp(alt::IPlayer* _this, uint8_t component)
110 | {
111 | alt::DlcProp dlcProp = _this->GetDlcProps(component);
112 | py::dict dict;
113 | dict["dlc"] = dlcProp.dlc;
114 | dict["drawable"] = dlcProp.drawableId;
115 | dict["texture"] = dlcProp.textureId;
116 | return dict;
117 | }
118 |
119 | py::dict GetHeadBlendData(alt::IPlayer* _this)
120 | {
121 | alt::HeadBlendData headBlendData = _this->GetHeadBlendData();
122 | py::dict dict;
123 | dict["shape_first_id"] = headBlendData.shapeFirstID;
124 | dict["shape_second_id"] = headBlendData.shapeSecondID;
125 | dict["shape_third_id"] = headBlendData.shapeThirdID;
126 | dict["skin_first_id"] = headBlendData.skinFirstID;
127 | dict["skin_second_id"] = headBlendData.skinSecondID;
128 | dict["skin_third_id"] = headBlendData.skinThirdID;
129 | dict["shape_mix"] = headBlendData.shapeMix;
130 | dict["skin_mix"] = headBlendData.skinMix;
131 | dict["third_mix"] = headBlendData.thirdMix;
132 | return dict;
133 | }
134 |
135 | py::dict GetHeadOverlay(alt::IPlayer* _this, uint8_t overlayId)
136 | {
137 | alt::HeadOverlay headOverlay = _this->GetHeadOverlay(overlayId);
138 | py::dict dict;
139 | dict["index"] = headOverlay.index;
140 | dict["opacity"] = headOverlay.opacity;
141 | dict["color_type"] = headOverlay.colorType;
142 | dict["color_index"] = headOverlay.colorIndex;
143 | dict["second_color_index"] = headOverlay.secondColorIndex;
144 | return dict;
145 | }
146 |
147 | py::dict GetProps(alt::IPlayer* _this, uint8_t component)
148 | {
149 | alt::Prop prop = _this->GetProps(component);
150 | py::dict dict;
151 | dict["drawable"] = prop.drawableId;
152 | dict["texture"] = prop.textureId;
153 | return dict;
154 | }
155 |
156 | py::object GetLocalMeta(alt::IPlayer* _this, const std::string& key)
157 | {
158 | return Utils::MValueToValue(_this->GetLocalMetaData(key));
159 | }
160 |
161 | void SetLocalMeta(alt::IPlayer* _this, const std::string& key, const py::object& value)
162 | {
163 | _this->SetLocalMetaData(key, Utils::ValueToMValue(value));
164 | }
165 |
166 | void Emit(alt::IPlayer* _this, const std::string& eventName, const py::args& args)
167 | {
168 | alt::MValueArgs eventArgs;
169 | for (const py::handle& arg : *args)
170 | eventArgs.Push(Utils::ValueToMValue(arg.cast()));
171 | alt::ICore::Instance().TriggerClientEvent(_this, eventName, eventArgs);
172 | }
173 |
174 | BodyPart GetLastDamagedBodyPart(alt::IPlayer* _this) {
175 | return (BodyPart)_this->GetLastDamagedBodyPart();
176 | }
177 |
178 | void RegisterPlayerClass(const py::module_& m)
179 | {
180 | auto pyClass = py::class_>(m, "Player", py::multiple_inheritance());
181 |
182 | // Static
183 | pyClass.def_property_readonly_static("all", &GetAllPlayers);
184 | pyClass.def_static("get_by_id", &GetPlayerById, py::arg("id"));
185 |
186 | // Events
187 | pyClass.def("emit", &Emit, py::arg("event_name"));
188 |
189 | // Player Data
190 | pyClass.def_property_readonly("name", &alt::IPlayer::GetName);
191 | pyClass.def_property_readonly("ip", &alt::IPlayer::GetIP);
192 | pyClass.def_property_readonly("connected", &alt::IPlayer::IsConnected);
193 | pyClass.def_property_readonly("ping", &alt::IPlayer::GetPing);
194 | pyClass.def_property_readonly("social_id", &alt::IPlayer::GetSocialID);
195 | pyClass.def_property_readonly("hwid_hash", &alt::IPlayer::GetHwidHash);
196 | pyClass.def_property_readonly("hwid_ex_hash", &alt::IPlayer::GetHwidExHash);
197 | pyClass.def_property_readonly("auth_token", &alt::IPlayer::GetAuthToken);
198 | pyClass.def_property_readonly("discord_id", &alt::IPlayer::GetDiscordId);
199 | pyClass.def("kick", &alt::IPlayer::Kick, py::arg("reason") = "Kicked");
200 |
201 | // Game Data
202 | pyClass.def_property_readonly("move_speed", &alt::IPlayer::GetMoveSpeed);
203 | pyClass.def_property_readonly("strafe_speed", &alt::IPlayer::GetStrafeSpeed);
204 | pyClass.def_property_readonly("forward_speed", &alt::IPlayer::GetForwardSpeed);
205 | pyClass.def_property_readonly("aim_pos", &GetAimPos);
206 | pyClass.def_property_readonly("head_rot", &GetHeadRot);
207 | pyClass.def_property_readonly("entity_aiming_at", &GetEntityAimingAt);
208 | pyClass.def_property_readonly("entity_aim_offset", &GetEntityAimOffset);
209 | pyClass.def_property_readonly("interior_location", &alt::IPlayer::GetInteriorLocation);
210 | pyClass.def_property("invincible", &alt::IPlayer::GetInvincible, &alt::IPlayer::SetInvincible);
211 | pyClass.def_property("last_damaged_body_part", &GetLastDamagedBodyPart, &alt::IPlayer::SetLastDamagedBodyPart);
212 | pyClass.def("play_ambient_speech", &alt::IPlayer::PlayAmbientSpeech, py::arg("speech_name"), py::arg("speech_param"), py::arg("speech_dict_hash"));
213 |
214 | // Weather & Time
215 | pyClass.def("set_date_time", &alt::IPlayer::SetDateTime, py::arg("day"), py::arg("month"), py::arg("year"), py::arg("hour"), py::arg("minute"), py::arg("second"));
216 | pyClass.def("set_weather", &alt::IPlayer::SetWeather);
217 |
218 | // Vehicles
219 | pyClass.def_property_readonly("in_vehicle", &alt::IPlayer::IsInVehicle);
220 | pyClass.def_property_readonly("vehicle", &alt::IPlayer::GetVehicle);
221 | pyClass.def_property_readonly("seat", &alt::IPlayer::GetSeat);
222 | pyClass.def("set_into_vehicle", &alt::IPlayer::SetIntoVehicle, py::arg("vehicle"), py::arg("seat"));
223 |
224 | // Health
225 | pyClass.def_property("health", &alt::IPlayer::GetHealth, &alt::IPlayer::SetHealth);
226 | pyClass.def_property("max_health", &alt::IPlayer::GetMaxHealth, &alt::IPlayer::SetMaxHealth);
227 | pyClass.def("clear_blood_damage", &alt::IPlayer::ClearBloodDamage);
228 |
229 | // Armour
230 | pyClass.def_property("armour", &alt::IPlayer::GetArmour, &alt::IPlayer::SetArmour);
231 | pyClass.def_property("max_armour", &alt::IPlayer::GetMaxArmour, &alt::IPlayer::SetMaxArmour);
232 |
233 | // Weapons
234 | pyClass.def_property("current_weapon", &alt::IPlayer::GetCurrentWeapon, &alt::IPlayer::SetCurrentWeapon);
235 | pyClass.def("give_weapon", &alt::IPlayer::GiveWeapon, py::arg("weapon_hash"), py::arg("ammo"), py::arg("equip_now"));
236 | pyClass.def("remove_weapon", &alt::IPlayer::RemoveWeapon, py::arg("weapon_hash"));
237 | pyClass.def("remove_all_weapons", &alt::IPlayer::RemoveAllWeapons);
238 | pyClass.def("set_weapon_tint_index", &alt::IPlayer::SetWeaponTintIndex, py::arg("weapon_hash"), py::arg("tint_index"));
239 | pyClass.def_property_readonly("current_weapon_tint_index", &GetCurrentWeaponTintIndex);
240 | pyClass.def_property_readonly("current_weapon_components", &GetCurrentWeaponComponents);
241 | pyClass.def("add_weapon_component", &alt::IPlayer::AddWeaponComponent, py::arg("weapon_hash"), py::arg("component"));
242 | pyClass.def("remove_weapon_component", &alt::IPlayer::RemoveWeaponComponent, py::arg("weapon_hash"), py::arg("component"));
243 | pyClass.def_property_readonly("weapons", &GetWeapons);
244 |
245 | // Current Status
246 | pyClass.def_property_readonly("dead", &alt::IPlayer::IsDead);
247 | pyClass.def_property_readonly("jumping", &alt::IPlayer::IsJumping);
248 | pyClass.def_property_readonly("in_ragdoll", &alt::IPlayer::IsInRagdoll);
249 | pyClass.def_property_readonly("aiming", &alt::IPlayer::IsAiming);
250 | pyClass.def_property_readonly("shooting", &alt::IPlayer::IsShooting);
251 | pyClass.def_property_readonly("reloading", &alt::IPlayer::IsReloading);
252 | pyClass.def_property_readonly("super_jump", &alt::IPlayer::IsSuperJumpEnabled);
253 | pyClass.def_property_readonly("crouching", &alt::IPlayer::IsCrouching);
254 | pyClass.def_property_readonly("stealthy", &alt::IPlayer::IsStealthy);
255 | pyClass.def_property_readonly("flashlight_active", &alt::IPlayer::IsFlashlightActive);
256 |
257 | // Face Features
258 | pyClass.def("set_head_overlay", &alt::IPlayer::SetHeadOverlay, py::arg("overlay_id"), py::arg("index"), py::arg("opacity"));
259 | pyClass.def("remove_head_overlay", &alt::IPlayer::RemoveHeadOverlay, py::arg("overlay_id"));
260 | pyClass.def("set_head_overlay_color", &alt::IPlayer::SetHeadOverlayColor, py::arg("overlay_id"), py::arg("color_type"), py::arg("color_index"), py::arg("second_color_index"));
261 | pyClass.def("get_head_overlay", &GetHeadOverlay, py::arg("overlay_id"));
262 | pyClass.def("set_face_feature", &alt::IPlayer::SetFaceFeature, py::arg("index"), py::arg("scale"));
263 | pyClass.def("get_face_feature_scale", &alt::IPlayer::GetFaceFeatureScale, py::arg("index"));
264 | pyClass.def("remove_face_feature", &alt::IPlayer::RemoveFaceFeature, py::arg("index"));
265 | pyClass.def("set_head_blend_palette_color", &alt::IPlayer::SetHeadBlendPaletteColor, py::arg("id"), py::arg("red"), py::arg("green"), py::arg("blue"));
266 | pyClass.def("get_head_blend_palette_color", &alt::IPlayer::GetHeadBlendPaletteColor, py::arg("id"));
267 | pyClass.def("set_head_blend_data", &alt::IPlayer::SetHeadBlendData, py::arg("shape_first_id"), py::arg("shape_second_id"), py::arg("shape_third_id"), py::arg("skin_first_id"), py::arg("skin_second_id"), py::arg("skin_third_id"), py::arg("shape_mix"), py::arg("skin_mix"), py::arg("third_mix"));
268 | pyClass.def_property_readonly("head_blend_data", &GetHeadBlendData);
269 | pyClass.def("get_eye_color", &alt::IPlayer::GetEyeColor);
270 | pyClass.def("set_eye_color", &alt::IPlayer::SetEyeColor, py::arg("eye_color"));
271 | pyClass.def_property("hair_color", &alt::IPlayer::GetHairColor, &alt::IPlayer::SetHairColor);
272 | pyClass.def_property("hair_highlight_color", &alt::IPlayer::GetHairHighlightColor, &alt::IPlayer::SetHairHighlightColor);
273 |
274 | // Clothing & Props
275 | pyClass.def("get_clothes", &GetClothes, py::arg("component"));
276 | pyClass.def("set_clothes", &alt::IPlayer::SetClothes, py::arg("component"), py::arg("drawable"), py::arg("texture"), py::arg("palette") = 0);
277 | pyClass.def("get_dlc_clothes", &GetDlcClothes, py::arg("component"));
278 | pyClass.def("set_dlc_clothes", &SetDlcClothes, py::arg("dlc"), py::arg("component"), py::arg("drawable"), py::arg("texture"), py::arg("palette") = 2);
279 | pyClass.def("get_prop", &GetProps, py::arg("component"));
280 | pyClass.def("set_prop", &alt::IPlayer::SetProps, py::arg("component"), py::arg("drawable"), py::arg("texture"));
281 | pyClass.def("get_dlc_prop", &GetDlcProp, py::arg("component"));
282 | pyClass.def("set_dlc_prop", &SetDlcProps, py::arg("dlc"), py::arg("component"), py::arg("drawable"), py::arg("texture"));
283 | pyClass.def("clear_prop", &alt::IPlayer::ClearProps);
284 |
285 | // Streaming Range
286 | pyClass.def("is_entity_in_streaming_range", py::overload_cast>(&alt::IPlayer::IsEntityInStreamingRange), py::arg("entity"));
287 | pyClass.def("is_entity_in_streaming_range", py::overload_cast(&alt::IPlayer::IsEntityInStreamingRange), py::arg("id"));
288 |
289 | // Spawn
290 | pyClass.def_property_readonly("spawned", &alt::IPlayer::IsSpawned);
291 | pyClass.def("spawn", py::overload_cast(&Spawn), py::arg("pos"), py::arg("delay") = 0);
292 | pyClass.def("spawn", py::overload_cast(&Spawn), py::arg("x"), py::arg("y"), py::arg("z"), py::arg("delay") = 0);
293 | pyClass.def("despawn", &alt::IPlayer::Despawn);
294 |
295 | // Animations
296 | pyClass.def_property_readonly("current_animation_dict", &alt::IPlayer::GetCurrentAnimationDict);
297 | pyClass.def_property_readonly("current_animation_name", &alt::IPlayer::GetCurrentAnimationName);
298 |
299 | // Local MetaData
300 | pyClass.def("get_local_meta", &GetLocalMeta, py::arg("key"));
301 | pyClass.def("has_local_meta", &alt::IPlayer::HasLocalMetaData, py::arg("key"));
302 | pyClass.def("set_local_meta", &SetLocalMeta, py::arg("key"), py::arg("value"));
303 | pyClass.def("delete_local_meta", &alt::IPlayer::DeleteLocalMetaData, py::arg("key"));
304 | }
305 |
--------------------------------------------------------------------------------
/src/classes/base/vehicle.cpp:
--------------------------------------------------------------------------------
1 | #include "classes/classes.hpp"
2 | #include "classes/types/enums.hpp"
3 | #include "classes/types/vector3.hpp"
4 | #include "utils.hpp"
5 |
6 | py::list GetAllVehicles(const py::object& type)
7 | {
8 | return Utils::ArrayToPyList