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
10 changes: 8 additions & 2 deletions Server/Components/LegacyNetwork/legacy_network_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -828,8 +828,6 @@ void RakNetLegacyNetwork::start()
{
SAMPRakNet::Init(core);
SAMPRakNet::SeedToken();
lastCookieSeed = Time::now();
SAMPRakNet::SeedCookie();

playerFromRakIndex.fill(nullptr);

Expand Down Expand Up @@ -915,6 +913,14 @@ void RakNetLegacyNetwork::start()
{
rakNetServer.ReserveSlots(npcComponent->count());
}

// SeedCookie must be called after rakNetServer.Start() because Start() internally calls
// RakPeer::Disconnect() which resets RakNet's internal state. Seeding the cookie before
// Start() means the seeded value is discarded, leaving the cookie in an invalid state
// until the next onTick() re-seed. Clients connecting in that window fail the cookie
// check and their packets are silently ignored (issue #1211).
lastCookieSeed = Time::now();
SAMPRakNet::SeedCookie();
}

void RakNetLegacyNetwork::onTick(Microseconds elapsed, TimePoint now)
Expand Down
2 changes: 2 additions & 0 deletions Server/Components/Vehicles/vehicle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,8 @@ void Vehicle::_respawn()
lastOccupiedChange = TimePoint();
timeOfSpawn = Time::now();
mods.fill(0);
// paintJob was not reset here unlike mods and colours, causing it to persist after vehicle respawn (issue #1212)
paintJob = 0;
doorDamage = 0;
tyreDamage = 0;
lightDamage = 0;
Expand Down
7 changes: 6 additions & 1 deletion Server/Components/Vehicles/vehicles_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -590,7 +590,12 @@ class VehiclesComponent final : public IVehiclesComponent, public CoreEventHandl
Vehicle* vehicle = static_cast<Vehicle*>(v);
const Seconds delay = vehicle->getRespawnDelay();

if (!vehicle->isOccupied())
// A dead vehicle driven solely by an NPC has no client to send exit/death RPCs,
// so it stays "occupied" indefinitely. Treat it as unoccupied for death/respawn handling.
IPlayer* vehicleDriver = vehicle->getDriver();
bool deadNPCOnly = vehicle->isDead() && vehicleDriver != nullptr && vehicleDriver->isBot() && vehicle->getPassengers().empty();

if (!vehicle->isOccupied() || deadNPCOnly)
{
TimePoint lastOccupied = vehicle->getLastOccupiedTime();
if (vehicle->isDead())
Expand Down
Loading