From 78480e24d22662943ad176729daec6f8d4fd02f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Madar=C3=A1sz?= Date: Wed, 24 Jan 2024 16:01:41 +0100 Subject: [PATCH 1/6] player.enter/exitVehicle API WIP --- code/client/src/core/modules/human.cpp | 37 ++++++++++++- code/server/src/core/builtins/player.h | 58 +++++++++++++++++++++ code/shared/game_rpc/human/human_setprops.h | 19 ++++++- code/shared/modules/human_sync.hpp | 2 + gamemode/index.js | 23 ++++++++ 5 files changed, 136 insertions(+), 3 deletions(-) diff --git a/code/client/src/core/modules/human.cpp b/code/client/src/core/modules/human.cpp index c42b8e68..02b5c044 100644 --- a/code/client/src/core/modules/human.cpp +++ b/code/client/src/core/modules/human.cpp @@ -62,6 +62,26 @@ namespace MafiaMP::Core::Modules { metadata._sprintSpeed = charController->GetSprintMoveSpeed(); metadata.weaponData.isAiming = tracking.human->GetHumanWeaponController()->IsAiming(); + // Try to enter/exit vehicle if an action is pending + if (metadata.carPassenger.pending) { + if (!metadata.carPassenger.carId) { + if (tracking.human->GetOwner()) { + Game::Helpers::Human::RemoveFromCar(tracking.charController, (SDK::C_Car *)tracking.human->GetOwner(), metadata.carPassenger.forced); + } + metadata.carPassenger.pending = false; + } + else { + const auto carEnt = gApplication->GetWorldEngine()->GetEntityByServerID(metadata.carPassenger.carId); + if (carEnt.is_valid()) { + const auto carData = carEnt.get(); + if (carData->car) { + Game::Helpers::Human::PutIntoCar(tracking.charController, carData->car, metadata.carPassenger.seatId, metadata.carPassenger.forced); + metadata.carPassenger.pending = false; + } + } + } + } + // Current state-specific sync data switch (metadata._charStateHandlerType) { case SDK::ue::game::humanai::C_CharacterStateHandler::E_SHT_MOVE: { @@ -73,6 +93,8 @@ namespace MafiaMP::Core::Modules { } break; case SDK::ue::game::humanai::C_CharacterStateHandler::E_SHT_CAR: { + if (metadata.carPassenger.pending) + break; auto human2CarWrapper = charController->GetCarHandler()->GetHuman2CarWrapper(); // printf("id: %d\n", charController->GetCarHandler()->GetCarState()); if (human2CarWrapper && charController->GetCarHandler()->GetCarState() == 2) /* entering in progress */ { @@ -88,7 +110,7 @@ namespace MafiaMP::Core::Modules { } break; } - if (metadata._charStateHandlerType != SDK::ue::game::humanai::C_CharacterStateHandler::E_SHT_CAR) { + if (!metadata.carPassenger.pending && metadata._charStateHandlerType != SDK::ue::game::humanai::C_CharacterStateHandler::E_SHT_CAR) { // not in a vehicle, so make sure data is reset metadata.carPassenger = {}; } @@ -442,7 +464,7 @@ namespace MafiaMP::Core::Modules { } auto trackingData = e.get_mut(); - if (!trackingData && trackingData->human) { + if (!trackingData || (trackingData && !trackingData->human)) { return; } @@ -451,6 +473,17 @@ namespace MafiaMP::Core::Modules { if (setHealth.HasValue()) { Game::Helpers::Human::SetHealthPercent(trackingData->human, setHealth()); } + + const auto carEnterExitAction = msg->carEnterExitAction; + + if (carEnterExitAction.HasValue()) { + const auto data = carEnterExitAction(); + auto updateData = e.get_mut(); + updateData->carPassenger.carId = data.carId; + updateData->carPassenger.seatId = data.seatId; + updateData->carPassenger.forced = data.forced; + updateData->carPassenger.pending = true; + } }); } diff --git a/code/server/src/core/builtins/player.h b/code/server/src/core/builtins/player.h index a0cc2d86..a2aed617 100644 --- a/code/server/src/core/builtins/player.h +++ b/code/server/src/core/builtins/player.h @@ -11,6 +11,7 @@ #include "scripting/module.h" +#include "core/modules/vehicle.h" #include "vehicle.h" namespace MafiaMP::Scripting { @@ -71,6 +72,61 @@ namespace MafiaMP::Scripting { FW_SEND_SERVER_COMPONENT_GAME_RPC(MafiaMP::Shared::RPC::HumanSetProps, _ent, msg); } + /* Player NEEDS to be in a stream range of the vehicle for this action to work. + * Suggestion: Teleport player to car position and then enforce entrance to ensure player always succeeds at this task. + * Local player always waits for the vehicle to enter stream range, making the process entirely async, just like + * how we handle remote human car enter/exit states. + */ + bool EnterVehicle(Vehicle vehicle, int seatId, bool forced) { + if (!vehicle.GetHandle().is_valid()) + return false; + if (!vehicle.GetHandle().is_alive()) + return false; + if (seatId < 0 || seatId > 3 /* TODO: use MAX_SEATS constexpr var */) + return false; + auto updateData = _ent.get_mut(); + + if (updateData->carPassenger.carId) + return false; + + { + const auto carData = vehicle.GetHandle().get(); + if (!carData) + return false; + + if (carData->seats[seatId]) + return false; + } + + updateData->carPassenger.carId = vehicle.GetID(); + updateData->carPassenger.seatId = seatId; + MafiaMP::Shared::RPC::HumanSetProps msg {}; + MafiaMP::Shared::RPC::HumanSetProps::CarEnterExitAction carEnterExit = {}; + + carEnterExit.carId = vehicle.GetID(); + carEnterExit.seatId = seatId; + carEnterExit.forced = forced; + msg.carEnterExitAction = carEnterExit; + FW_SEND_SERVER_COMPONENT_GAME_RPC(MafiaMP::Shared::RPC::HumanSetProps, _ent, msg); + return true; + } + + bool ExitVehicle(bool forced) { + auto updateData = _ent.get_mut(); + + if (!updateData->carPassenger.carId) + return false; + + updateData->carPassenger = {}; + MafiaMP::Shared::RPC::HumanSetProps msg {}; + MafiaMP::Shared::RPC::HumanSetProps::CarEnterExitAction carEnterExit = {}; + + carEnterExit.forced = forced; + msg.carEnterExitAction = carEnterExit; + FW_SEND_SERVER_COMPONENT_GAME_RPC(MafiaMP::Shared::RPC::HumanSetProps, _ent, msg); + return true; + } + float GetHealth() const { auto h = _ent.get(); return h->_healthPercent; @@ -109,6 +165,8 @@ namespace MafiaMP::Scripting { cls.function("setHealth", &Human::SetHealth); cls.function("getHealth", &Human::GetHealth); cls.function("getVehicle", &Human::GetVehicle); + cls.function("enterVehicle", &Human::EnterVehicle); + cls.function("exitVehicle", &Human::ExitVehicle); cls.function("getVehicleSeat", &Human::GetVehicleSeat); cls.function("sendChat", &Human::SendChat); cls.function("sendChatToAll", &Human::SendChatToAll); diff --git a/code/shared/game_rpc/human/human_setprops.h b/code/shared/game_rpc/human/human_setprops.h index 1e9a80dc..e041c808 100644 --- a/code/shared/game_rpc/human/human_setprops.h +++ b/code/shared/game_rpc/human/human_setprops.h @@ -3,21 +3,38 @@ #include "src/networking/rpc/game_rpc.h" #include "utils/optional.h" +#include "shared/modules/human_sync.hpp" + namespace MafiaMP::Shared::RPC { class HumanSetProps final: public Framework::Networking::RPC::IGameRPC { public: + struct CarEnterExitAction { + uint64_t carId {}; + int seatId {}; + bool forced {}; + }; + Framework::Utils::Optional health {}; + Framework::Utils::Optional carEnterExitAction {}; void FromParameters(HumanSetProps props) { this->health = props.health; + this->carEnterExitAction = props.carEnterExitAction; } void Serialize(SLNet::BitStream *bs, bool write) override { health.Serialize(bs, write); + carEnterExitAction.Serialize(bs, write); } bool Valid() const override { - return (health.HasValue() && health() >= 0.0f && health() <= 100.0f); + if (health.HasValue() && !(health() >= 0.0f && health() <= 100.0f)) + return false; + + if (carEnterExitAction.HasValue() && !(carEnterExitAction().seatId >= 0 && carEnterExitAction().seatId <= 3)) + return false; + + return true; } }; } // namespace MafiaMP::Shared::RPC diff --git a/code/shared/modules/human_sync.hpp b/code/shared/modules/human_sync.hpp index eebad771..680044d8 100644 --- a/code/shared/modules/human_sync.hpp +++ b/code/shared/modules/human_sync.hpp @@ -22,6 +22,8 @@ namespace MafiaMP::Shared::Modules { struct CarPassenger { uint64_t carId{}; int seatId{}; + bool pending {}; + bool forced {}; } carPassenger{}; struct WeaponData { diff --git a/gamemode/index.js b/gamemode/index.js index 4e4099fa..6401f4e5 100644 --- a/gamemode/index.js +++ b/gamemode/index.js @@ -390,6 +390,29 @@ RegisterChatCommand("tp", (player, message, command, args) => { player.sendChat(`[SERVER] Teleported to ${tpDestName}!`); }); +RegisterChatCommand("tpe", (player, message, command, args) => { + const tpDestName = args[0]; + const foundTpDest = TP_DESTINATIONS[tpDestName]; + + if (!foundTpDest) { + player.sendChat(`[SERVER] Teleportation failed. Unknown destination ${tpDestName}`); + return; + } + + const veh = player.getVehicle(); + veh.setPosition(foundTpDest.pos); + veh.setRotation(foundTpDest.rot); + player.sendChat(`[SERVER] Teleported to ${tpDestName}!`); +}); + +RegisterChatCommand("t1", (player, message, command, args) => { + player.exitVehicle(false); +}); + +RegisterChatCommand("t2", (player, message, command, args) => { + player.exitVehicle(true); +}); + RegisterChatCommand("coords", (player, message, command, args) => { let x = args[0]; let y = args[1]; From 95b3822f52dac33c58827848ab9e9860ec87c5ea Mon Sep 17 00:00:00 2001 From: Segfault <5221072+Segfaultd@users.noreply.github.com> Date: Wed, 7 Feb 2024 00:34:50 +0100 Subject: [PATCH 2/6] Reversed more methods on human script class --- .../client/src/sdk/entities/e_actor_actions.h | 75 ++++++++++++++++ .../src/sdk/entities/human/c_human_script.cpp | 9 +- .../src/sdk/entities/human/c_human_script.h | 3 + .../sdk/entities/human/e_human_move_mode.h | 18 ++++ code/client/src/sdk/patterns.cpp | 1 + code/client/src/sdk/patterns.h | 1 + .../ue/game/humainai/c_character_controller.h | 89 +------------------ 7 files changed, 107 insertions(+), 89 deletions(-) create mode 100644 code/client/src/sdk/entities/e_actor_actions.h create mode 100644 code/client/src/sdk/entities/human/e_human_move_mode.h diff --git a/code/client/src/sdk/entities/e_actor_actions.h b/code/client/src/sdk/entities/e_actor_actions.h new file mode 100644 index 00000000..d38b49ba --- /dev/null +++ b/code/client/src/sdk/entities/e_actor_actions.h @@ -0,0 +1,75 @@ +#pragma once + +namespace SDK { + enum E_ActorActions { + E_AA_DUMMY = 0x0, + E_AA_ENTER_CAR = 0x1, + E_AA_LEAVE_CAR = 0x2, + E_AA_OPEN_CAR_TRUNK = 0x3, + E_AA_CLOSE_CAR_TRUNK = 0x4, + E_AA_OPEN_CAR_HOOD = 0x5, + E_AA_CLOSE_CAR_HOOD = 0x6, + E_AA_TRAILER_MOUNT = 0x7, + E_AA_ITEM_PICK_UP = 0x8, + E_AA_USE_LADDER = 0x9, + E_AA_SCRIPT = 0xA, + E_AA_CUSTOMSCRIPT = 0xB, + E_AA_DOOR_OPEN = 0xC, + E_AA_DOOR_KICK = 0xD, + E_AA_DOOR_COMPONENT_OPEN = 0xE, + E_AA_DOOR_COMPONENT_PULL_LOCK = 0xF, + E_AA_DOOR_COMPONENT_KICK = 0x10, + E_AA_SAFEHOUSE_DOOR_ACCESS = 0x11, + E_AA_USE_LIFT = 0x12, + E_AA_ACTOR_SIT = 0x13, + E_AA_ACTOR_LEAVE = 0x14, + E_AA_RADIO = 0x15, + E_AA_JUKEBOX = 0x16, + E_AA_SLOT_MACHINE = 0x17, + E_AA_STEAL_CAR = 0x18, + E_AA_STEAL_CAR_STOP = 0x19, + E_AA_BREAK_IN_CAR = 0x1A, + E_AA_LOCK_PICK_CAR = 0x1B, + E_AA_THROW_FROM_CAR = 0x1C, + E_AA_ENTER_BOAT = 0x1D, + E_AA_LEAVE_BOAT = 0x1E, + E_AA_RESPAWN_BOAT = 0x1F, + E_AA_ENTER_TRAIN = 0x20, + E_AA_LEAVE_TRAIN = 0x21, + E_AA_GET_ON_MOTORCYCLE = 0x22, + E_AA_GET_OFF_MOTORCYCLE = 0x23, + E_AA_THROW_FROM_MOTORCYCLE = 0x24, + E_AA_GARAGE_GET_CAR = 0x25, + E_AA_GARAGE_PARK_CAR = 0x26, + E_AA_GARAGE_SWITCH_CAR = 0x27, + E_AA_ENTER_INNERSPACE = 0x28, + E_AA_LEAVE_INNERSPACE = 0x29, + E_AA_USE_TELEPHONE = 0x2A, + E_AA_USE_STATIC_WEAPON = 0x2B, + E_AA_TV = 0x2C, + E_AA_TAKE_PINUP = 0x2D, + E_AA_DRAG_DEATH_BODY = 0x2E, + E_AA_STEALABLE_WEAPON = 0x2F, + E_AA_STEALABLE_SUIT = 0x30, + E_AA_STEALABLE_FOOD = 0x31, + E_AA_STEALABLE_AMMO = 0x32, + E_AA_OPEN_SHOP = 0x33, + E_AA_USE_MOUNTED_WEAPON = 0x34, + E_AA_LEAVE_MOUNTED_WEAPON = 0x35, + E_AA_OPEN_HEADQUARTERS = 0x36, + E_AA_OPEN_CRIME_BUSINESS = 0x37, + E_AA_TELEPORT = 0x38, + E_AA_BED = 0x39, + E_AA_DEAD_GUY_THROWN_OUT_CAR = 0x3A, + E_AA_BAILOUT_CAR = 0x3B, + E_AA_BAILOUT_MOTORCYCLE = 0x3C, + E_AA_INTERROGATE_IN_CAR = 0x3D, + E_AA_PICKUP_SATCHEL = 0x3E, + E_AA_PICKUP_BODY = 0x3F, + E_AA_PUT_BODY_IN_CAR_TRUNK = 0x40, + E_AA_REMOVE_BODY_FROM_CAR_TRUNK = 0x41, + E_AA_TURRET_MOUNT = 0x42, + E_AA_CAR_TURRET_MOUNT = 0x43, + E_AA_REVIVE = 0x44, + }; +} diff --git a/code/client/src/sdk/entities/human/c_human_script.cpp b/code/client/src/sdk/entities/human/c_human_script.cpp index 6e9accba..26e78514 100644 --- a/code/client/src/sdk/entities/human/c_human_script.cpp +++ b/code/client/src/sdk/entities/human/c_human_script.cpp @@ -50,11 +50,11 @@ namespace SDK { } void C_HumanScript::GetOnVehicle(ue::C_CntPtr &outSyncObject, C_Actor *arg1, unsigned int arg2, bool arg3, bool arg4, E_HumanMoveMode moveMode, bool force) { - (*(void(__thiscall *)(C_HumanScript *, ue::C_CntPtr &, C_Actor *, unsigned int, bool, bool, E_HumanMoveMode, bool))gPatterns.C_HumanScript__GetOnVehicle)(this, outSyncObject, arg1, arg2, arg3, arg4, moveMode, force); + hook::this_call(gPatterns.C_HumanScript__GetOnVehicle, this, outSyncObject, arg1, arg2, arg3, arg4, moveMode, force); } void C_HumanScript::GetOffVehicle(ue::C_CntPtr &outSyncObject, C_Actor *arg1, bool arg2, bool arg3) { - (*(void(__thiscall *)(C_HumanScript *, ue::C_CntPtr &, C_Actor *, bool, bool))gPatterns.C_HumanScript__GetOffVehicle)(this, outSyncObject, arg1, arg2, arg3); + hook::this_call(gPatterns.C_HumanScript__GetOffVehicle, this, outSyncObject, arg1, arg2, arg3); } void C_HumanScript::ScrAim(ue::C_CntPtr &syncObject, bool aiming) { @@ -66,6 +66,11 @@ namespace SDK { void C_HumanScript::ScrAttack(C_Entity *ent) { hook::this_call(gPatterns.C_HumanScript__ScrAttack, this, ent); } + + void C_HumanScript::ScrDoAction(ue::C_CntPtr& syncObject, C_Actor* actor, E_ActorActions action, unsigned int arg3, bool arg4, bool arg5, E_HumanMoveMode moveMode, bool force) { + hook::this_call(gPatterns.C_HumanScript__ScrDoAction, this, syncObject, actor, action, arg3, arg4, arg5, moveMode, force); + } + void C_HumanScript::SetStealthMove(bool move) { hook::this_call(gPatterns.C_HumanScript__SetStealthMove, this, move); } diff --git a/code/client/src/sdk/entities/human/c_human_script.h b/code/client/src/sdk/entities/human/c_human_script.h index 9bc93953..6cc34ced 100644 --- a/code/client/src/sdk/entities/human/c_human_script.h +++ b/code/client/src/sdk/entities/human/c_human_script.h @@ -1,6 +1,7 @@ #pragma once #include "../../ue/c_cnt_ptr.h" +#include "../e_actor_actions.h" #include "../../ue/sys/math/c_vector.h" @@ -34,6 +35,8 @@ namespace SDK { void ScrAimAt(ue::C_CntPtr &, C_Entity *, ue::sys::math::C_Vector const &, bool); void ScrAttack(C_Entity *); + void ScrDoAction(ue::C_CntPtr &, C_Actor *, E_ActorActions, unsigned int, bool, bool, E_HumanMoveMode, bool); + void SetStealthMove(bool); }; } diff --git a/code/client/src/sdk/entities/human/e_human_move_mode.h b/code/client/src/sdk/entities/human/e_human_move_mode.h new file mode 100644 index 00000000..d071db4f --- /dev/null +++ b/code/client/src/sdk/entities/human/e_human_move_mode.h @@ -0,0 +1,18 @@ +#pragma once + +namespace SDK { + enum class E_HumanMoveMode { + E_HMM_NONE = -1, + E_HMM_BREATH = 0, + E_HMM_STEP, + E_HMM_WALK_SLOW, + E_HMM_WALK, + E_HMM_WALK_FAST, + E_HMM_RUN, + E_HMM_SPRINT, + E_HMM_AUTO_SLOW, + E_HMM_AUTO_NORMAL, + E_HMM_AUTO_FAST, + E_HMM_END + }; +} diff --git a/code/client/src/sdk/patterns.cpp b/code/client/src/sdk/patterns.cpp index 6a3ab676..95aa1bde 100644 --- a/code/client/src/sdk/patterns.cpp +++ b/code/client/src/sdk/patterns.cpp @@ -209,6 +209,7 @@ namespace SDK { gPatterns.C_HumanScript__ScrAim = reinterpret_cast(hook::get_pattern("48 89 5C 24 ? 55 56 57 48 8B EC 48 83 EC 20 48 8B DA 48 8B F9 48 8B 0D ? ? ? ? 48 8D 55 20 41 0F B6 F0")); gPatterns.C_HumanScript__ScrAimAt = reinterpret_cast(hook::get_pattern("48 89 5C 24 ? 48 89 74 24 ? 55 57 41 56 48 8B EC 48 83 EC 30 48 8B DA")); gPatterns.C_HumanScript__ScrAttack = reinterpret_cast(hook::get_pattern("48 85 D2 0F 84 ? ? ? ? 55 56 41 56")); + gPatterns.C_HumanScript__ScrDoAction = reinterpret_cast(hook::get_pattern("40 55 53 41 54 41 56 41 57 48 8B EC 48 81 EC")); gPatterns.C_HumanScript__SetHealth = reinterpret_cast(hook::get_pattern("48 83 EC ? 48 8B 09 0F 29 74 24 ?")); gPatterns.C_HumanScript__SetStealthMove = reinterpret_cast(hook::get_pattern("48 89 5C 24 ? 57 48 83 EC 60 48 8B F9 0F B6 DA")); diff --git a/code/client/src/sdk/patterns.h b/code/client/src/sdk/patterns.h index b730040a..f40af470 100644 --- a/code/client/src/sdk/patterns.h +++ b/code/client/src/sdk/patterns.h @@ -188,6 +188,7 @@ namespace SDK { uint64_t C_HumanScript__ScrAim = 0x0; uint64_t C_HumanScript__ScrAimAt = 0x0; uint64_t C_HumanScript__ScrAttack = 0x0; + uint64_t C_HumanScript__ScrDoAction = 0x0; uint64_t C_HumanScript__SetHealth = 0x0; uint64_t C_HumanScript__SetStealthMove = 0x0; diff --git a/code/client/src/sdk/ue/game/humainai/c_character_controller.h b/code/client/src/sdk/ue/game/humainai/c_character_controller.h index 73cb567c..7c3dfa6c 100644 --- a/code/client/src/sdk/ue/game/humainai/c_character_controller.h +++ b/code/client/src/sdk/ue/game/humainai/c_character_controller.h @@ -1,7 +1,9 @@ #pragma once #include +#include "../../../entities/e_actor_actions.h" #include "../../../entities/c_actor.h" +#include "../../../entities/human/e_human_move_mode.h" #include "c_character_state_handler.h" #include "c_character_state_handler_aim.h" @@ -12,93 +14,6 @@ namespace SDK { class C_Human2; - enum class E_HumanMoveMode { - E_HMM_NONE = -1, - E_HMM_BREATH = 0, - E_HMM_STEP, - E_HMM_WALK_SLOW, - E_HMM_WALK, - E_HMM_WALK_FAST, - E_HMM_RUN, - E_HMM_SPRINT, - E_HMM_AUTO_SLOW, - E_HMM_AUTO_NORMAL, - E_HMM_AUTO_FAST, - E_HMM_END - }; - - enum E_ActorActions { - E_AA_DUMMY = 0x0, - E_AA_ENTER_CAR = 0x1, - E_AA_LEAVE_CAR = 0x2, - E_AA_OPEN_CAR_TRUNK = 0x3, - E_AA_CLOSE_CAR_TRUNK = 0x4, - E_AA_OPEN_CAR_HOOD = 0x5, - E_AA_CLOSE_CAR_HOOD = 0x6, - E_AA_TRAILER_MOUNT = 0x7, - E_AA_ITEM_PICK_UP = 0x8, - E_AA_USE_LADDER = 0x9, - E_AA_SCRIPT = 0xA, - E_AA_CUSTOMSCRIPT = 0xB, - E_AA_DOOR_OPEN = 0xC, - E_AA_DOOR_KICK = 0xD, - E_AA_DOOR_COMPONENT_OPEN = 0xE, - E_AA_DOOR_COMPONENT_PULL_LOCK = 0xF, - E_AA_DOOR_COMPONENT_KICK = 0x10, - E_AA_SAFEHOUSE_DOOR_ACCESS = 0x11, - E_AA_USE_LIFT = 0x12, - E_AA_ACTOR_SIT = 0x13, - E_AA_ACTOR_LEAVE = 0x14, - E_AA_RADIO = 0x15, - E_AA_JUKEBOX = 0x16, - E_AA_SLOT_MACHINE = 0x17, - E_AA_STEAL_CAR = 0x18, - E_AA_STEAL_CAR_STOP = 0x19, - E_AA_BREAK_IN_CAR = 0x1A, - E_AA_LOCK_PICK_CAR = 0x1B, - E_AA_THROW_FROM_CAR = 0x1C, - E_AA_ENTER_BOAT = 0x1D, - E_AA_LEAVE_BOAT = 0x1E, - E_AA_RESPAWN_BOAT = 0x1F, - E_AA_ENTER_TRAIN = 0x20, - E_AA_LEAVE_TRAIN = 0x21, - E_AA_GET_ON_MOTORCYCLE = 0x22, - E_AA_GET_OFF_MOTORCYCLE = 0x23, - E_AA_THROW_FROM_MOTORCYCLE = 0x24, - E_AA_GARAGE_GET_CAR = 0x25, - E_AA_GARAGE_PARK_CAR = 0x26, - E_AA_GARAGE_SWITCH_CAR = 0x27, - E_AA_ENTER_INNERSPACE = 0x28, - E_AA_LEAVE_INNERSPACE = 0x29, - E_AA_USE_TELEPHONE = 0x2A, - E_AA_USE_STATIC_WEAPON = 0x2B, - E_AA_TV = 0x2C, - E_AA_TAKE_PINUP = 0x2D, - E_AA_DRAG_DEATH_BODY = 0x2E, - E_AA_STEALABLE_WEAPON = 0x2F, - E_AA_STEALABLE_SUIT = 0x30, - E_AA_STEALABLE_FOOD = 0x31, - E_AA_STEALABLE_AMMO = 0x32, - E_AA_OPEN_SHOP = 0x33, - E_AA_USE_MOUNTED_WEAPON = 0x34, - E_AA_LEAVE_MOUNTED_WEAPON = 0x35, - E_AA_OPEN_HEADQUARTERS = 0x36, - E_AA_OPEN_CRIME_BUSINESS = 0x37, - E_AA_TELEPORT = 0x38, - E_AA_BED = 0x39, - E_AA_DEAD_GUY_THROWN_OUT_CAR = 0x3A, - E_AA_BAILOUT_CAR = 0x3B, - E_AA_BAILOUT_MOTORCYCLE = 0x3C, - E_AA_INTERROGATE_IN_CAR = 0x3D, - E_AA_PICKUP_SATCHEL = 0x3E, - E_AA_PICKUP_BODY = 0x3F, - E_AA_PUT_BODY_IN_CAR_TRUNK = 0x40, - E_AA_REMOVE_BODY_FROM_CAR_TRUNK = 0x41, - E_AA_TURRET_MOUNT = 0x42, - E_AA_CAR_TURRET_MOUNT = 0x43, - E_AA_REVIVE = 0x44, - }; - namespace ue::game::humanai { class I_CharacterController { public: From 8821b184f7fc3682c767c6b99b15985016feba04 Mon Sep 17 00:00:00 2001 From: Segfault <5221072+Segfaultd@users.noreply.github.com> Date: Wed, 7 Feb 2024 00:39:23 +0100 Subject: [PATCH 3/6] Update human.cpp --- code/client/src/game/helpers/human.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/code/client/src/game/helpers/human.cpp b/code/client/src/game/helpers/human.cpp index 0ba7a855..d62c96d3 100644 --- a/code/client/src/game/helpers/human.cpp +++ b/code/client/src/game/helpers/human.cpp @@ -6,6 +6,8 @@ #include "sdk/entities/c_car.h" #include "sdk/entities/c_human_2.h" +#include "sdk/c_game.h" + namespace MafiaMP::Game::Helpers { uint8_t Human::GetHealthPercent(SDK::C_Human2 *human) { float fHealth = human->GetHumanScript()->GetHealth(); @@ -23,6 +25,18 @@ namespace MafiaMP::Game::Helpers { return false; } + const auto pLocalPlayer = SDK::GetGame()->GetActivePlayer(); + if (!pLocalPlayer) { + return false; + } + + // Specific code for local player that has no character controller bound + if (!charController || charController->GetCharacter()->GetType() == SDK::E_EntityType::E_ENTITY_PLAYER) { + SDK::ue::C_CntPtr syncObject; + reinterpret_cast(pLocalPlayer)->GetHumanScript()->GetOnVehicle(syncObject, car, seat, true, true, SDK::E_HumanMoveMode::E_HMM_WALK, force); + return true; + } + SDK::C_Actor *act = *(SDK::C_Actor **)((uintptr_t)car + 0xA8); return charController->TriggerActorAction(act, SDK::E_AA_ENTER_CAR, seat, force, false); } @@ -32,6 +46,18 @@ namespace MafiaMP::Game::Helpers { return false; } + const auto pLocalPlayer = SDK::GetGame()->GetActivePlayer(); + if (!pLocalPlayer) { + return false; + } + + // Specific code for local player that has no character controller bound + if (!charController || charController->GetCharacter()->GetType() == SDK::E_EntityType::E_ENTITY_PLAYER) { + SDK::ue::C_CntPtr syncObject; + reinterpret_cast(pLocalPlayer)->GetHumanScript()->ScrDoAction(syncObject, car, SDK::E_AA_LEAVE_CAR, 0, false, true, SDK::E_HumanMoveMode::E_HMM_WALK, true); + return true; + } + SDK::C_Actor *act = *(SDK::C_Actor **)((uintptr_t)car + 0xA8); return charController->TriggerActorAction(act, SDK::E_AA_LEAVE_CAR, 0, force, false); } From eb479fa2a2a2ad90b2041cd3dec65c80c148551b Mon Sep 17 00:00:00 2001 From: Segfault <5221072+Segfaultd@users.noreply.github.com> Date: Tue, 8 Apr 2025 18:19:37 +0200 Subject: [PATCH 4/6] Update player.cpp --- code/server/src/core/builtins/player.cpp | 68 ++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/code/server/src/core/builtins/player.cpp b/code/server/src/core/builtins/player.cpp index 30d9e54a..0e20bec6 100644 --- a/code/server/src/core/builtins/player.cpp +++ b/code/server/src/core/builtins/player.cpp @@ -31,6 +31,70 @@ namespace MafiaMP::Scripting { // Nothing should happen here, as the player entity is destroyed by the game and network systems } + int Player::GetVehicleSeat() const { + const auto updateData = _ent.get(); + const auto carEnt = flecs::entity(_ent.world(), updateData->carPassenger.carId); + if (carEnt.is_valid() && carEnt.is_alive()) { + return updateData->carPassenger.seatId; + } + return -1; + } + + /* Player NEEDS to be in a stream range of the vehicle for this action to work. + * Suggestion: Teleport player to car position and then enforce entrance to ensure player always succeeds at this task. + * Local player always waits for the vehicle to enter stream range, making the process entirely async, just like + * how we handle remote human car enter/exit states. + */ + bool Player::EnterVehicle(Vehicle vehicle, int seatId, bool forced) { + if (!vehicle.GetHandle().is_valid()) + return false; + if (!vehicle.GetHandle().is_alive()) + return false; + if (seatId < 0 || seatId > 3 /* TODO: use MAX_SEATS constexpr var */) + return false; + auto updateData = _ent.get_mut(); + + if (updateData->carPassenger.carId) + return false; + + { + const auto carData = vehicle.GetHandle().get(); + if (!carData) + return false; + + if (carData->seats[seatId]) + return false; + } + + updateData->carPassenger.carId = vehicle.GetID(); + updateData->carPassenger.seatId = seatId; + MafiaMP::Shared::RPC::HumanSetProps msg {}; + MafiaMP::Shared::RPC::HumanSetProps::CarEnterExitAction carEnterExit = {}; + + carEnterExit.carId = vehicle.GetID(); + carEnterExit.seatId = seatId; + carEnterExit.forced = forced; + msg.carEnterExitAction = carEnterExit; + FW_SEND_SERVER_COMPONENT_GAME_RPC(MafiaMP::Shared::RPC::HumanSetProps, _ent, msg); + return true; + } + + bool Player::ExitVehicle(bool forced) { + auto updateData = _ent.get_mut(); + + if (!updateData->carPassenger.carId) + return false; + + updateData->carPassenger = {}; + MafiaMP::Shared::RPC::HumanSetProps msg {}; + MafiaMP::Shared::RPC::HumanSetProps::CarEnterExitAction carEnterExit = {}; + + carEnterExit.forced = forced; + msg.carEnterExitAction = carEnterExit; + FW_SEND_SERVER_COMPONENT_GAME_RPC(MafiaMP::Shared::RPC::HumanSetProps, _ent, msg); + return true; + } + void Player::Register(sol::state *luaEngine) { if (!luaEngine) { return; @@ -38,5 +102,9 @@ namespace MafiaMP::Scripting { sol::usertype cls = luaEngine->new_usertype("Player", sol::constructors(), sol::base_classes, sol::bases()); cls["destroy"] = &Player::Destroy; + cls["getVehicle"] = &Human::GetVehicle; + cls["enterVehicle"] = &Human::EnterVehicle; + cls["exitVehicle"] = &Human::ExitVehicle; + cls["getVehicleSeat"] = &Human::GetVehicleSeat; } } // namespace MafiaMP::Scripting From 5d8d5efed66ae94036fb909ee22a09bb05b5c93f Mon Sep 17 00:00:00 2001 From: Segfault <5221072+Segfaultd@users.noreply.github.com> Date: Tue, 8 Apr 2025 18:22:47 +0200 Subject: [PATCH 5/6] Update c_character_controller.h --- code/client/src/sdk/ue/game/humanai/c_character_controller.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/client/src/sdk/ue/game/humanai/c_character_controller.h b/code/client/src/sdk/ue/game/humanai/c_character_controller.h index 3af83a4a..d6d2967b 100644 --- a/code/client/src/sdk/ue/game/humanai/c_character_controller.h +++ b/code/client/src/sdk/ue/game/humanai/c_character_controller.h @@ -2,7 +2,9 @@ #include -#include "sdk/entities/c_actor.h" +#include +#include +#include #include "c_character_state_handler.h" #include "c_character_state_handler_aim.h" From e0f0d25b071fa36820b6d915fcea2a2efc5984f2 Mon Sep 17 00:00:00 2001 From: Segfault <5221072+Segfaultd@users.noreply.github.com> Date: Tue, 8 Apr 2025 18:25:45 +0200 Subject: [PATCH 6/6] Fixed compilation --- code/server/src/core/builtins/player.cpp | 10 ++++++---- code/server/src/core/builtins/player.h | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/code/server/src/core/builtins/player.cpp b/code/server/src/core/builtins/player.cpp index 0e20bec6..2ae7e9f9 100644 --- a/code/server/src/core/builtins/player.cpp +++ b/code/server/src/core/builtins/player.cpp @@ -1,8 +1,10 @@ #include "player.h" +#include "vehicle.h" #include "core/server.h" +#include "shared/game_rpc/human/human_setprops.h" #include "shared/rpc/chat_message.h" namespace MafiaMP::Scripting { @@ -102,9 +104,9 @@ namespace MafiaMP::Scripting { sol::usertype cls = luaEngine->new_usertype("Player", sol::constructors(), sol::base_classes, sol::bases()); cls["destroy"] = &Player::Destroy; - cls["getVehicle"] = &Human::GetVehicle; - cls["enterVehicle"] = &Human::EnterVehicle; - cls["exitVehicle"] = &Human::ExitVehicle; - cls["getVehicleSeat"] = &Human::GetVehicleSeat; + cls["getVehicle"] = &Player::GetVehicle; + cls["enterVehicle"] = &Player::EnterVehicle; + cls["exitVehicle"] = &Player::ExitVehicle; + cls["getVehicleSeat"] = &Player::GetVehicleSeat; } } // namespace MafiaMP::Scripting diff --git a/code/server/src/core/builtins/player.h b/code/server/src/core/builtins/player.h index 4eddee20..d26d903f 100644 --- a/code/server/src/core/builtins/player.h +++ b/code/server/src/core/builtins/player.h @@ -5,6 +5,7 @@ #include "human.h" namespace MafiaMP::Scripting { + class Vehicle; class Player final: public MafiaMP::Scripting::Human { public: Player(flecs::entity_t ent): Human(ent) {}