Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce Player enter / leave Vehicle #93

Merged
merged 6 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 70 additions & 3 deletions code/client/src/core/hooks/vehicle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@
#include <utils/hooking/hook_function.h>
#include <utils/hooking/hooking.h>

#include "game/helpers/controls.h"

#include <logging/logger.h>

#include "../modules/vehicle.h"
#include "shared/modules/vehicle_sync.hpp"
#include "shared/game_rpc/vehicle/vehicle_player_enter.h"
#include "shared/game_rpc/vehicle/vehicle_player_leave.h"

#include "sdk/entities/c_actor.h"
#include "sdk/entities/c_car.h"
Expand Down Expand Up @@ -107,25 +111,82 @@ bool C_CarActionOpenCloseX__TestAction(void *pThis, SDK::C_Actor *actor) {
typedef void(__fastcall *C_Human2CarWrapper__StartDrive_t)(SDK::C_Human2CarWrapper *, SDK::C_Actor *, bool);
C_Human2CarWrapper__StartDrive_t C_Human2CarWrapper__StartDrive_original = nullptr;
void C_Human2CarWrapper__StartDrive(SDK::C_Human2CarWrapper *pThis, SDK::C_Actor *pActor, bool unk) {
const auto seatID = pThis->GetSeatID(pActor);
if (!pThis->m_pUsedCar) {
return;
}

auto seatID = pThis->GetSeatID(pActor);
if (seatID != 999) {
// Set the seat status to occupied
pThis->m_pUsedCar->SetSeatStatus(reinterpret_cast<SDK::I_Human2 *>(pActor), seatID, SDK::S_BaseSeat::E_BaseSeatStatus::OCCUPIED);

// Disable the shadows and human clothes
reinterpret_cast<SDK::C_Human2 *>(pActor)->EnableShadows(false);
reinterpret_cast<SDK::C_Human2 *>(pActor)->EnableHumanClothes();
}
}

typedef void(__fastcall *C_Human2CarWrapper__EndDrive_t)(SDK::C_Human2CarWrapper *, SDK::C_Actor *, bool, bool);
C_Human2CarWrapper__EndDrive_t C_Human2CarWrapper__EndDrive_original = nullptr;
void C_Human2CarWrapper__EndDrive(SDK::C_Human2CarWrapper *pThis, SDK::C_Actor *pActor, bool unk, bool unk2) {
if (!pThis->m_pUsedCar) {
return;
}

pThis->m_pUsedCar->GetVehicle()->SetHandbrake(1.0, true);

const auto seatID = pThis->GetSeatID(pActor);
if (seatID != 999) {
// Set the seat status to empty
pThis->m_pUsedCar->SetSeatStatus(reinterpret_cast<SDK::I_Human2 *>(pActor), seatID, SDK::S_BaseSeat::E_BaseSeatStatus::EMPTY);

// Enable the shadows and human clothes
reinterpret_cast<SDK::C_Human2 *>(pActor)->EnableShadows(true);
reinterpret_cast<SDK::C_Human2 *>(pActor)->EnableHumanClothes();
}
if (pThis->m_pUsedCar != nullptr) {
pThis->m_pUsedCar->GetVehicle()->SetHandbrake(1.0, true);
}

typedef int64_t(__fastcall *C_Human2CarWrapper__GetIn_t)(SDK::C_Human2CarWrapper *, SDK::C_Actor *, int, SDK::C_Human2CarWrapper::S_SeatInfo &);
C_Human2CarWrapper__GetIn_t C_Human2CarWrapper__GetIn_original = nullptr;

int64_t C_Human2CarWrapper__GetIn(SDK::C_Human2CarWrapper* pThis, SDK::C_Actor* pActor, int seatID, SDK::C_Human2CarWrapper::S_SeatInfo& seatInfo) {
// Notify the server
auto const pLocalPlayer = MafiaMP::Game::Helpers::Controls::GetLocalPlayer();
if (reinterpret_cast<SDK::C_Actor *>(pLocalPlayer) == pActor) {
const auto pVehicle = MafiaMP::Core::Modules::Vehicle::GetCarEntity(pThis->m_pUsedCar);
if (!pVehicle || !pVehicle.is_valid()) {
return C_Human2CarWrapper__GetIn_original(pThis, pActor, seatID, seatInfo);
}

MafiaMP::Shared::RPC::VehiclePlayerEnter rpc;
rpc.vehicleId = Framework::World::ClientEngine::GetServerID(pVehicle);
rpc.seatIndex = seatID;
FW_SEND_CLIENT_COMPONENT_GAME_RPC(MafiaMP::Shared::RPC::VehiclePlayerEnter, MafiaMP::Core::gApplication->GetLocalPlayer(), rpc);
}

// Return to game
return C_Human2CarWrapper__GetIn_original(pThis, pActor, seatID, seatInfo);
}

typedef int64_t(__fastcall *C_Human2CarWrapper__GetOut_t)(SDK::C_Human2CarWrapper *, SDK::C_Actor *);
C_Human2CarWrapper__GetOut_t C_Human2CarWrapper__GetOut_original = nullptr;

int64_t C_Human2CarWrapper__GetOut(SDK::C_Human2CarWrapper* pThis, SDK::C_Actor* pActor) {
// Notify the server
auto const pLocalPlayer = MafiaMP::Game::Helpers::Controls::GetLocalPlayer();
if (reinterpret_cast<SDK::C_Actor *>(pLocalPlayer) == pActor) {
const auto pVehicle = MafiaMP::Core::Modules::Vehicle::GetCarEntity(pThis->m_pUsedCar);
if (!pVehicle || !pVehicle.is_valid()) {
return C_Human2CarWrapper__GetOut_original(pThis, pActor);
}

MafiaMP::Shared::RPC::VehiclePlayerLeave rpc;
rpc.vehicleId = Framework::World::ClientEngine::GetServerID(pVehicle);
FW_SEND_CLIENT_COMPONENT_GAME_RPC(MafiaMP::Shared::RPC::VehiclePlayerLeave, MafiaMP::Core::gApplication->GetLocalPlayer(), rpc);
}

// Return to game
return C_Human2CarWrapper__GetOut_original(pThis, pActor);
}

static InitFunction init([]() {
Expand Down Expand Up @@ -154,4 +215,10 @@ static InitFunction init([]() {

const auto C_CarActionBailOut__TestAction_Addr = hook::get_pattern("40 53 48 83 EC 20 48 8B DA E8 ? ? ? ? 48 8B C8 4C 8B 00 41 FF 90 ? ? ? ? 48 3B D8 75 2A");
MH_CreateHook((LPVOID)C_CarActionBailOut__TestAction_Addr, (PBYTE)C_CarActionBailOut__TestAction, reinterpret_cast<void **>(&C_CarActionBailOut__TestAction_original));

const auto C_Human2CarWrapper__GetIn_Addr = hook::get_pattern("40 55 56 57 41 54 41 56 48 83 EC ? 33 ED");
MH_CreateHook((LPVOID)C_Human2CarWrapper__GetIn_Addr, (PBYTE)C_Human2CarWrapper__GetIn, reinterpret_cast<void **>(&C_Human2CarWrapper__GetIn_original));

const auto C_Human2CarWrapper__GetOut_Addr = hook::get_pattern("40 56 57 41 57 48 83 EC ? 48 8B F2 48 8B F9");
MH_CreateHook((LPVOID)C_Human2CarWrapper__GetOut_Addr, (PBYTE)C_Human2CarWrapper__GetOut, reinterpret_cast<void **>(&C_Human2CarWrapper__GetOut_original));
});
7 changes: 7 additions & 0 deletions code/client/src/core/modules/vehicle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ namespace MafiaMP::Core::Modules {
metadata.rimColor = {rimColor.r, rimColor.g, rimColor.b, rimColor.a};
metadata.rust = vehicle->GetVehicleRust();
metadata.sirenOn = vehicle->IsSiren();
metadata.engineOn = car->IsEngineOn();
metadata.steer = vehicle->GetSteer();
metadata.tireColor = {tireColor.r, tireColor.g, tireColor.b, tireColor.a};
metadata.velocity = {vehicleVelocity.x, vehicleVelocity.y, vehicleVelocity.z};
Expand Down Expand Up @@ -204,6 +205,7 @@ namespace MafiaMP::Core::Modules {
vehicle->SetVehicleColor(&colorPrimary, &colorSecondary, false);
car->SetVehicleDirty(updateData->dirt); // We have to use the car to set the dirt otherwise the value is reset
car->SetActualFuel(updateData->fuel);
vehicle->SetEngineOn(updateData->engineOn, updateData->engineOn);
vehicle->SetGear(updateData->gear);
vehicle->SetHandbrake(updateData->handbrake, false);
vehicle->SetHorn(updateData->hornOn);
Expand Down Expand Up @@ -299,6 +301,7 @@ namespace MafiaMP::Core::Modules {
const auto colorPrimary = msg->colorPrimary;
const auto colorSecondary = msg->colorSecondary;
const auto dirt = msg->dirt;
const auto engineOn = msg->engineOn;
const auto fuel = msg->fuel;
const auto licensePlate = msg->licensePlate;
const auto lockState = msg->lockState;
Expand Down Expand Up @@ -326,6 +329,10 @@ namespace MafiaMP::Core::Modules {
updateData->dirt = dirt();
}

if (engineOn.HasValue()) {
updateData->engineOn = engineOn();
}

if (fuel.HasValue()) {
updateData->fuel = fuel();
}
Expand Down
3 changes: 3 additions & 0 deletions code/client/src/sdk/wrappers/c_human_2_car_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@

namespace SDK {
class C_Human2CarWrapper {
public:
struct S_SeatInfo;

public:
char pad0[0x18]; // 0000 - 0018
C_Car *m_pUsedCar; // 0018 - 0020
Expand Down
3 changes: 3 additions & 0 deletions code/server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ set(MAFIAMP_SERVER_FILES
src/main.cpp
src/core/server.cpp

src/core/builtins/player.cpp
src/core/builtins/vehicle.cpp

src/core/modules/environment.cpp
src/core/modules/human.cpp
src/core/modules/vehicle.cpp
Expand Down
107 changes: 107 additions & 0 deletions code/server/src/core/builtins/player.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
#include "player.h"

#include "vehicle.h"

#include "shared/modules/human_sync.hpp"
#include "shared/game_rpc/add_weapon.h"
#include "shared/game_rpc/human/human_setprops.h"
#include "shared/rpc/chat_message.h"

namespace MafiaMP::Scripting {
v8::Local<v8::Object> Human::WrapHuman(Framework::Scripting::Engines::Node::Engine *engine, flecs::entity e) {
return v8pp::class_<Scripting::Human>::create_object(engine->GetIsolate(), e.id());
}

std::string Human::ToString() const {
std::ostringstream ss;
ss << "Human{ id: " << _ent.id() << " }";
return ss.str();
}

void Human::Destroy(v8::Isolate *isolate) {
isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "Human object can not be destroyed!").ToLocalChecked()));
}

void Human::AddWeapon(int weaponId, int ammo) {
FW_SEND_SERVER_COMPONENT_GAME_RPC(MafiaMP::Shared::RPC::AddWeapon, _ent, weaponId, ammo);
}

void Human::SendChat(std::string message) {
const auto str = _ent.get<Framework::World::Modules::Base::Streamer>();
FW_SEND_COMPONENT_RPC_TO(Shared::RPC::ChatMessage, SLNet::RakNetGUID(str->guid), message);
}

v8::Local<v8::Value> Human::GetVehicle() const {
const auto updateData = _ent.get<MafiaMP::Shared::Modules::HumanSync::UpdateData>();
const auto carEnt = flecs::entity(_ent.world(), updateData->carPassenger.carId);
if (carEnt.is_valid() && carEnt.is_alive()) {
return v8pp::class_<Vehicle>::create_object(v8::Isolate::GetCurrent(), carEnt.id());
}
return v8::Undefined(v8::Isolate::GetCurrent());
}

int Human::GetVehicleSeat() const {
const auto updateData = _ent.get<MafiaMP::Shared::Modules::HumanSync::UpdateData>();
const auto carEnt = flecs::entity(_ent.world(), updateData->carPassenger.carId);
if (carEnt.is_valid() && carEnt.is_alive()) {
return updateData->carPassenger.seatId;
}
return -1;
}

void Human::SendChatToAll(std::string message) {
FW_SEND_COMPONENT_RPC(Shared::RPC::ChatMessage, message);
}

void Human::SetHealth(float health) {
auto h = _ent.get_mut<MafiaMP::Shared::Modules::HumanSync::UpdateData>();
h->_healthPercent = health;
MafiaMP::Shared::RPC::HumanSetProps msg {};
msg.health = health;
FW_SEND_SERVER_COMPONENT_GAME_RPC(MafiaMP::Shared::RPC::HumanSetProps, _ent, msg);
}

float Human::GetHealth() const {
auto h = _ent.get<MafiaMP::Shared::Modules::HumanSync::UpdateData>();
return h->_healthPercent;
}

void Human::EventPlayerDied(flecs::entity e) {
const auto engine = MafiaMP::Server::GetNodeEngine();
V8_RESOURCE_LOCK(engine);
auto playerObj = WrapHuman(engine, e);
engine->InvokeEvent("playerDied", playerObj);
}

void Human::EventPlayerConnected(flecs::entity e) {
const auto engine = MafiaMP::Server::GetNodeEngine();
V8_RESOURCE_LOCK(engine);
auto playerObj = WrapHuman(engine, e);
engine->InvokeEvent("playerConnected", playerObj);
}

void Human::EventPlayerDisconnected(flecs::entity e) {
const auto engine = MafiaMP::Server::GetNodeEngine();
V8_RESOURCE_LOCK(engine);
auto playerObj = WrapHuman(engine, e);
engine->InvokeEvent("playerDisconnected", playerObj);
}

void Human::Register(v8::Isolate *isolate, v8pp::module *rootModule) {
if (!rootModule) {
return;
}

v8pp::class_<Human> cls(isolate);
cls.inherit<Framework::Integrations::Scripting::Entity>();
cls.function("destroy", &Human::Destroy);
cls.function("addWeapon", &Human::AddWeapon);
cls.function("setHealth", &Human::SetHealth);
cls.function("getHealth", &Human::GetHealth);
cls.function("getVehicle", &Human::GetVehicle);
cls.function("getVehicleSeat", &Human::GetVehicleSeat);
cls.function("sendChat", &Human::SendChat);
cls.function("sendChatToAll", &Human::SendChatToAll);
rootModule->class_("Human", cls);
}
}
Loading