Skip to content
Open
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
7 changes: 7 additions & 0 deletions Server/mods/deathmatch/logic/CGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2389,7 +2389,14 @@ void CGame::Packet_PlayerPuresync(CPlayerPuresyncPacket& Packet)
{
// Allow it if he's exiting
if (pPlayer->GetVehicleAction() != CPed::VEHICLEACTION_EXITING)
{
// Still acknowledge so the client's network-trouble watchdog doesn't trip while it catches up
// to the new vehicle-occupied state (e.g. just after warpPedIntoVehicle, before it starts
// sending vehicle puresync packets instead of these on-foot ones)
if ((pPlayer->GetPuresyncCount() % 4) == 0)
pPlayer->Send(CReturnSyncPacket(pPlayer));
return;
}
}

// Send a returnsync packet to the player that sent it
Expand Down
7 changes: 7 additions & 0 deletions Server/mods/deathmatch/logic/CResource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1069,6 +1069,13 @@ bool CResource::Start(std::list<CResource*>* pDependents, bool bManualStart, con
SendNoClientCacheScripts();
m_bClientSync = true;

// Run anything that got held back during onResourceStart because it depended on clients already knowing
// about elements we've just finished broadcasting above (see RunOrDeferUntilClientSynced)
std::vector<std::function<void()>> pendingCallbacks = std::move(m_PendingClientSyncCallbacks);
m_PendingClientSyncCallbacks.clear();
for (const auto& callback : pendingCallbacks)
callback();

// Add us to the running resources list
m_StartedResources.push_back(this);

Expand Down
16 changes: 16 additions & 0 deletions Server/mods/deathmatch/logic/CResource.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <unzip.h>
#include <list>
#include <vector>
#include <functional>
#include <ehs/ehs.h>
#include <time.h>

Expand Down Expand Up @@ -228,6 +229,19 @@ class CResource : public EHS

bool IsClientSynced() const noexcept { return m_bClientSync; }

// Runs the callback now if our elements have already reached the clients, otherwise holds onto it and runs it
// right after they do (see Start()). Used for things that need to tell clients about an element created moments
// earlier in onResourceStart, which wouldn't make sense to the client yet (e.g. warpPedIntoVehicle on a vehicle
// created in the same event) - dropping it outright would leave the server and clients permanently disagreeing
// about that element's state instead.
void RunOrDeferUntilClientSynced(std::function<void()> callback)
{
if (m_bClientSync)
callback();
else
m_PendingClientSyncCallbacks.push_back(std::move(callback));
}

const SString& GetName() const noexcept { return m_strResourceName; }

CLuaMain* GetVirtualMachine() { return m_pVM; }
Expand Down Expand Up @@ -372,6 +386,8 @@ class CResource : public EHS
EResourceState m_eState = EResourceState::None;
bool m_bClientSync = false;

std::vector<std::function<void()>> m_PendingClientSyncCallbacks;

unsigned short m_usNetID = -1;
uint m_uiScriptID = -1;

Expand Down
26 changes: 19 additions & 7 deletions Server/mods/deathmatch/logic/CStaticFunctionDefinitions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4293,7 +4293,7 @@ bool CStaticFunctionDefinitions::SetPedWeaponSlot(CElement* pElement, unsigned c
return false;
}

bool CStaticFunctionDefinitions::WarpPedIntoVehicle(CPed* pPed, CVehicle* pVehicle, unsigned int uiSeat)
bool CStaticFunctionDefinitions::WarpPedIntoVehicle(CPed* pPed, CVehicle* pVehicle, unsigned int uiSeat, CResource* pCallingResource)
{
assert(pPed);
assert(pVehicle);
Expand Down Expand Up @@ -4347,12 +4347,24 @@ bool CStaticFunctionDefinitions::WarpPedIntoVehicle(CPed* pPed, CVehicle* pVehic
if (uiSeat == 0 && g_pGame->IsWorldSpecialPropertyEnabled(WorldSpecialProperty::VEHICLE_ENGINE_AUTOSTART))
pVehicle->SetEngineOn(true);

// Tell all the players
CBitStream BitStream;
BitStream.pBitStream->Write(pVehicle->GetID());
BitStream.pBitStream->Write(static_cast<unsigned char>(uiSeat));
BitStream.pBitStream->Write(pPed->GenerateSyncTimeContext());
m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(pPed, WARP_PED_INTO_VEHICLE, *BitStream.pBitStream));
// Tell all the players. If the calling resource's elements haven't reached the clients yet
// (e.g. called from onResourceStart on a vehicle created in the same event), hold off until
// they have instead of just dropping it - the vehicle itself isn't synced to clients yet
// either, and an RPC referencing an unknown element there would leave the server and clients
// permanently disagreeing about whether this ped is in a vehicle.
auto sendWarpRpc = [pPed, pVehicle, uiSeat]()
{
CBitStream BitStream;
BitStream.pBitStream->Write(pVehicle->GetID());
BitStream.pBitStream->Write(static_cast<unsigned char>(uiSeat));
BitStream.pBitStream->Write(pPed->GenerateSyncTimeContext());
m_pPlayerManager->BroadcastOnlyJoined(CElementRPCPacket(pPed, WARP_PED_INTO_VEHICLE, *BitStream.pBitStream));
};

if (pCallingResource)
pCallingResource->RunOrDeferUntilClientSynced(sendWarpRpc);
else
sendWarpRpc();

// Call the player->vehicle event
CLuaArguments PlayerVehicleArguments;
Expand Down
2 changes: 1 addition & 1 deletion Server/mods/deathmatch/logic/CStaticFunctionDefinitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ class CStaticFunctionDefinitions
static bool SetPedGravity(CElement* pElement, float fGravity);
static bool SetPedChoking(CElement* pElement, bool bChoking);
static bool SetPedWeaponSlot(CElement* pElement, unsigned char ucWeaponSlot);
static bool WarpPedIntoVehicle(CPed* pPed, CVehicle* pVehicle, unsigned int uiSeat = 0);
static bool WarpPedIntoVehicle(CPed* pPed, CVehicle* pVehicle, unsigned int uiSeat = 0, CResource* pCallingResource = nullptr);
static bool RemovePedFromVehicle(CElement* pElement);
static bool SetPedDoingGangDriveby(CElement* pElement, bool bGangDriveby);
static bool SetPedAnimation(CElement* pElement, const SString& blockName, const SString& animName, int iTime, int iBlend, bool bLoop, bool bUpdatePosition,
Expand Down
10 changes: 8 additions & 2 deletions Server/mods/deathmatch/logic/luadefs/CLuaPedDefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1360,7 +1360,10 @@ int CLuaPedDefs::WarpPedIntoVehicle(lua_State* luaVM)
{
LogWarningIfPlayerHasNotJoinedYet(luaVM, pPed);

if (CStaticFunctionDefinitions::WarpPedIntoVehicle(pPed, pVehicle, uiSeat))
CLuaMain* pLuaMain = g_pGame->GetLuaManager()->GetVirtualMachine(luaVM);
CResource* pResource = pLuaMain ? pLuaMain->GetResource() : nullptr;

if (CStaticFunctionDefinitions::WarpPedIntoVehicle(pPed, pVehicle, uiSeat, pResource))
{
lua_pushboolean(luaVM, true);
return 1;
Expand Down Expand Up @@ -1394,7 +1397,10 @@ int CLuaPedDefs::OOP_WarpPedIntoVehicle(lua_State* luaVM)
{
LogWarningIfPlayerHasNotJoinedYet(luaVM, pPed);

if (CStaticFunctionDefinitions::WarpPedIntoVehicle(pPed, pVehicle, uiSeat))
CLuaMain* pLuaMain = g_pGame->GetLuaManager()->GetVirtualMachine(luaVM);
CResource* pResource = pLuaMain ? pLuaMain->GetResource() : nullptr;

if (CStaticFunctionDefinitions::WarpPedIntoVehicle(pPed, pVehicle, uiSeat, pResource))
{
lua_pushboolean(luaVM, true);
return 1;
Expand Down
Loading