diff --git a/Client/mods/deathmatch/logic/CClientPed.cpp b/Client/mods/deathmatch/logic/CClientPed.cpp index 5716bea120f..ccdfb79fda7 100644 --- a/Client/mods/deathmatch/logic/CClientPed.cpp +++ b/Client/mods/deathmatch/logic/CClientPed.cpp @@ -1131,7 +1131,7 @@ CClientVehicle* CClientPed::GetRealOccupiedVehicle() CClientVehicle* CClientPed::GetClosestEnterableVehicle(bool bGetPositionFromClosestDoor, bool bCheckDriverDoor, bool bCheckPassengerDoors, bool bCheckStreamedOutVehicles, unsigned int* uiClosestDoor, CVector* pClosestDoorPosition, - float fWithinRange) + float fWithinRange, bool localVehicles) { if (bGetPositionFromClosestDoor) { @@ -1164,7 +1164,7 @@ CClientVehicle* CClientPed::GetClosestEnterableVehicle(bool bGetPositionFromClos { pTempVehicle = *iter; // Skip clientside vehicles as they are not enterable - if (pTempVehicle->IsLocalEntity()) + if (pTempVehicle->IsLocalEntity() != localVehicles) continue; CVehicle* pGameVehicle = pTempVehicle->GetGameVehicle(); @@ -2679,9 +2679,6 @@ void CClientPed::WorldIgnore(bool bIgnore) void CClientPed::StreamedInPulse(bool bDoStandardPulses) { - if (!m_pPlayerPed) - return; - // ControllerState checks and fixes are done at the same same as everything else unless using alt pulse order bool bDoControllerStateFixPulse = g_pClientGame->IsUsingAlternatePulseOrder() ? !bDoStandardPulses : bDoStandardPulses; @@ -2710,6 +2707,10 @@ void CClientPed::StreamedInPulse(bool bDoStandardPulses) // Do we have a player? (streamed in) if (m_pPlayerPed) { + // If it's local entity, update in/out vehicle state + if (IsLocalEntity()) + UpdateVehicleInOut(); + // Handle waiting for the ground to load if (IsFrozenWaitingForGroundToLoad()) HandleWaitingForGroundToLoad(); @@ -6418,14 +6419,7 @@ void CClientPed::UpdateStreamPosition(const CVector& vecInPosition) bool CClientPed::EnterVehicle(CClientVehicle* pVehicle, bool bPassenger) { // Are we local player or ped we are syncing - if (!IsSyncing() && !IsLocalPlayer()) - { - return false; - } - - // Are we a clientside ped - // TODO: Add support for clientside peds - if (IsLocalEntity()) + if (!IsSyncing() && !IsLocalEntity() && !IsLocalPlayer()) { return false; } @@ -6474,7 +6468,7 @@ bool CClientPed::EnterVehicle(CClientVehicle* pVehicle, bool bPassenger) if (!pVehicle) { // Find the closest vehicle and door - CClientVehicle* pClosestVehicle = GetClosestEnterableVehicle(true, !bPassenger, bPassenger, false, &uiDoor, nullptr, 20.0f); + CClientVehicle* pClosestVehicle = GetClosestEnterableVehicle(true, !bPassenger, bPassenger, false, &uiDoor, nullptr, 20.0f, IsLocalEntity()); if (pClosestVehicle) { pVehicle = pClosestVehicle; @@ -6496,7 +6490,7 @@ bool CClientPed::EnterVehicle(CClientVehicle* pVehicle, bool bPassenger) return false; } - if (!pVehicle->IsEnterable()) + if (!pVehicle->IsEnterable(IsLocalEntity())) { // Stop if the vehicle is not enterable return false; @@ -6565,10 +6559,34 @@ bool CClientPed::EnterVehicle(CClientVehicle* pVehicle, bool bPassenger) Arguments.PushNumber(uiSeat); // seat Arguments.PushNumber(uiDoor); // door - if (!pVehicle->CallEvent("onClientVehicleStartEnter", Arguments, true)) - { - // Event has been cancelled + if (!pVehicle->CallEvent("onClientVehicleStartEnter", Arguments, true)) // Event has been cancelled return false; + + // If it's a local entity, we can just enter the vehicle + if (IsLocalEntity()) + { + // If vehicle is not local, we can't enter it + if (!pVehicle->IsLocalEntity()) + return false; + + // Set the vehicle id we're about to enter + m_VehicleInOutID = pVehicle->GetID(); + m_ucVehicleInOutSeat = uiSeat; + m_bIsJackingVehicle = false; + + // Make ped enter vehicle + GetIntoVehicle(pVehicle, uiSeat, uiDoor); + + // Remember that this ped is working on entering a vehicle + SetVehicleInOutState(VEHICLE_INOUT_GETTING_IN); + + pVehicle->CalcAndUpdateCanBeDamagedFlag(); + pVehicle->CalcAndUpdateTyresCanBurstFlag(); + + m_bIsGettingIntoVehicle = true; + m_bIsGettingOutOfVehicle = false; + + return true; } // Send an in request @@ -6620,14 +6638,7 @@ bool CClientPed::EnterVehicle(CClientVehicle* pVehicle, bool bPassenger) bool CClientPed::ExitVehicle() { // Are we local player or ped we are syncing - if (!IsSyncing() && !IsLocalPlayer()) - { - return false; - } - - // Are we a clientside ped - // TODO: Add support for clientside peds - if (IsLocalEntity()) + if (!IsSyncing() && !IsLocalEntity() && !IsLocalPlayer()) { return false; } @@ -6672,6 +6683,37 @@ bool CClientPed::ExitVehicle() return false; } + std::int8_t targetDoor = g_pGame->GetCarEnterExit()->ComputeTargetDoorToExit(m_pPlayerPed, pOccupiedVehicle->GetGameVehicle()); + + // If it's a local entity, we can just exit the vehicle + if (IsLocalEntity()) + { + // Set the vehicle id and the seat we're about to exit from + m_VehicleInOutID = pOccupiedVehicle->GetID(); + m_ucVehicleInOutSeat = GetOccupiedVehicleSeat(); + + // Call the onClientVehicleStartExit event for the ped + // Check if it is cancelled before making the ped exit the vehicle + CLuaArguments arguments; + arguments.PushElement(this); // player / ped + arguments.PushNumber(m_ucVehicleInOutSeat); // seat + arguments.PushNumber(0); // door + + if (!pOccupiedVehicle->CallEvent("onClientVehicleStartExit", arguments, true)) // Event has been cancelled + return false; + + // Make ped exit vehicle + GetOutOfVehicle(targetDoor); + + // Remember that this ped is working on leaving a vehicle + SetVehicleInOutState(VEHICLE_INOUT_GETTING_OUT); + + m_bIsGettingIntoVehicle = false; + m_bIsGettingOutOfVehicle = true; + + return true; + } + // We're about to exit a vehicle // Send an out request NetBitStreamInterface* pBitStream = g_pNet->AllocateNetBitStream(); @@ -6691,11 +6733,10 @@ bool CClientPed::ExitVehicle() unsigned char ucAction = static_cast(CClientGame::VEHICLE_REQUEST_OUT); pBitStream->WriteBits(&ucAction, 4); - unsigned char ucDoor = g_pGame->GetCarEnterExit()->ComputeTargetDoorToExit(m_pPlayerPed, pOccupiedVehicle->GetGameVehicle()); - if (ucDoor >= 2 && ucDoor <= 5) + if (targetDoor >= 2 && targetDoor <= 5) { - ucDoor -= 2; - pBitStream->WriteBits(&ucDoor, 2); + targetDoor -= 2; + pBitStream->WriteBits(&targetDoor, 2); } // Send and destroy it @@ -6737,6 +6778,57 @@ void CClientPed::ResetVehicleInOut() ////////////////////////////////////////////////////////////////// void CClientPed::UpdateVehicleInOut() { + if (IsLocalEntity()) + { + // If getting inside vehicle + if (m_bIsGettingIntoVehicle) + { + CClientVehicle* pVehicle = GetRealOccupiedVehicle(); + + if (pVehicle) + { + // Call the onClientVehicleEnter event for the ped + // Check if it is cancelled before allowing the ped to enter the vehicle + CLuaArguments arguments; + arguments.PushElement(this); // player / ped + arguments.PushNumber(m_ucVehicleInOutSeat); // seat + + if (!pVehicle->CallEvent("onClientVehicleEnter", arguments, true)) + { + m_bIsGettingIntoVehicle = false; + RemoveFromVehicle(); + return; + } + + m_bIsGettingIntoVehicle = false; + m_VehicleInOutID = INVALID_ELEMENT_ID; + WarpIntoVehicle(pVehicle, m_ucVehicleInOutSeat); + SetVehicleInOutState(VEHICLE_INOUT_NONE); + } + } + else if (m_bIsGettingOutOfVehicle) + { + // If getting out of vehicle + CClientVehicle* realVehicle = GetRealOccupiedVehicle(); + CClientVehicle* networkVehicle = GetOccupiedVehicle(); + + if (!realVehicle) + { + // Call the onClientVehicleExit event for the ped + CLuaArguments arguments; + arguments.PushElement(this); // player / ped + arguments.PushNumber(m_ucVehicleInOutSeat); // seat + networkVehicle->CallEvent("onClientVehicleExit", arguments, true); + + m_bIsGettingOutOfVehicle = false; + m_VehicleInOutID = INVALID_ELEMENT_ID; + SetVehicleInOutState(VEHICLE_INOUT_NONE); + } + } + + return; + } + // We got told by the server to animate into a certain vehicle? if (m_VehicleInOutID != INVALID_ELEMENT_ID) { diff --git a/Client/mods/deathmatch/logic/CClientPed.h b/Client/mods/deathmatch/logic/CClientPed.h index 688dba501fb..b4ff8320531 100644 --- a/Client/mods/deathmatch/logic/CClientPed.h +++ b/Client/mods/deathmatch/logic/CClientPed.h @@ -253,7 +253,7 @@ class CClientPed : public CClientStreamElement, public CAntiCheatModule CClientVehicle* GetRealOccupiedVehicle(); CClientVehicle* GetClosestEnterableVehicle(bool bGetPositionFromClosestDoor, bool bCheckDriverDoor, bool bCheckPassengerDoors, bool bCheckStreamedOutVehicles, unsigned int* uiClosestDoor = NULL, CVector* pClosestDoorPosition = NULL, - float fWithinRange = 6000.0f); + float fWithinRange = 6000.0f, bool localVehicles = false); bool GetClosestDoor(CClientVehicle* pVehicle, bool bCheckDriverDoor, bool bCheckPassengerDoors, unsigned int& uiClosestDoor, CVector* pClosestDoorPosition = NULL); diff --git a/Client/mods/deathmatch/logic/CClientVehicle.cpp b/Client/mods/deathmatch/logic/CClientVehicle.cpp index e0e27dd4173..bc3eabc656c 100644 --- a/Client/mods/deathmatch/logic/CClientVehicle.cpp +++ b/Client/mods/deathmatch/logic/CClientVehicle.cpp @@ -3859,12 +3859,12 @@ void CClientVehicle::UpdateUnderFloorFix(const CVector& vecTargetPosition, bool } } -bool CClientVehicle::IsEnterable() +bool CClientVehicle::IsEnterable(bool localEntity) { if (m_pVehicle) { // Server vehicle? - if (!IsLocalEntity()) + if (IsLocalEntity() == localEntity) { if (GetHealth() > 0.0f) { diff --git a/Client/mods/deathmatch/logic/CClientVehicle.h b/Client/mods/deathmatch/logic/CClientVehicle.h index e2c83c618ef..cad0b8fbd17 100644 --- a/Client/mods/deathmatch/logic/CClientVehicle.h +++ b/Client/mods/deathmatch/logic/CClientVehicle.h @@ -456,7 +456,7 @@ class CClientVehicle : public CClientStreamElement int GetCurrentGear(); - bool IsEnterable(); + bool IsEnterable(bool localEntity = false); bool HasRadio(); bool HasPoliceRadio();