fix(Core/Vehicles): Prevent accessory double-install and respawn orphans (#25499)

Co-authored-by: blinkysc <blinkysc@users.noreply.github.com>
This commit is contained in:
blinkysc 2026-04-19 10:09:51 -05:00 committed by GitHub
parent b53e1b8eac
commit 687ceeea70
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 24 additions and 8 deletions

View file

@ -1113,9 +1113,6 @@ bool Creature::AIM_Initialize(CreatureAI* ai)
IsAIEnabled = true;
i_AI->InitializeAI();
// Xinef: Initialize vehicle if it is not summoned!
if (GetVehicleKit() && m_spawnId)
GetVehicleKit()->Reset();
return true;
}
@ -2052,6 +2049,10 @@ void Creature::Respawn(bool force)
if (getDeathState() == DeathState::Dead)
{
// TempSummons (no m_spawnId) shouldn't be resurrected here; TempSummon::Update UnSummons them on the next tick once deathState is Dead.
if (!m_spawnId && !force)
return;
if (m_spawnId)
{
GetMap()->RemoveCreatureRespawnTime(m_spawnId);

View file

@ -29,7 +29,8 @@
#include <algorithm>
Vehicle::Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry) :
_me(unit), _vehicleInfo(vehInfo), _usableSeatNum(0), _creatureEntry(creatureEntry), _status(STATUS_NONE)
_me(unit), _vehicleInfo(vehInfo), _usableSeatNum(0), _creatureEntry(creatureEntry), _status(STATUS_NONE),
_accessoriesInstalled(false)
{
for (uint32 i = 0; i < MAX_VEHICLE_SEATS; ++i)
{
@ -87,8 +88,16 @@ void Vehicle::Install()
void Vehicle::InstallAllAccessories(bool evading)
{
if (GetBase()->IsPlayer() || !evading)
RemoveAllPassengers(); // We might have aura's saved in the DB with now invalid casters - remove
// Clear stale control-vehicle auras only on the first non-evade reset;
// a re-Reset would otherwise eject a just-seated passenger and, for
// accessories, fire a spurious SMART_EVENT_PASSENGER_REMOVED.
if (GetBase()->IsPlayer() || (!evading && !_accessoriesInstalled))
RemoveAllPassengers();
// Mark the initial reset as done even if this vehicle has no accessory
// list, so subsequent Resets don't eject passengers on vehicles without
// accessories (e.g. WG demolisher/catapult).
_accessoriesInstalled = true;
VehicleAccessoryList const* accessories = sObjectMgr->GetVehicleAccessoryList(this);
if (!accessories)
@ -111,6 +120,7 @@ void Vehicle::Uninstall()
_status = STATUS_UNINSTALLING;
LOG_DEBUG("vehicles", "Vehicle::Uninstall {}", _me->GetGUID().ToString());
RemoveAllPassengers();
_accessoriesInstalled = false;
if (_me && _me->IsCreature())
{

View file

@ -96,6 +96,7 @@ private:
uint32 _usableSeatNum; // Number of seats that match VehicleSeatEntry::UsableByPlayer, used for proper display flags
uint32 _creatureEntry; // Can be different than me->GetBase()->GetEntry() in case of players
Status _status;
bool _accessoriesInstalled;
};
class VehicleDespawnEvent : public BasicEvent

View file

@ -24,6 +24,7 @@
#include "GridNotifiers.h"
#include "ObjectMgr.h"
#include "Transport.h"
#include "Vehicle.h"
template <class T>
void GridObjectLoader::AddObjectHelper(Map* map, T* obj)
@ -53,6 +54,10 @@ void GridObjectLoader::LoadCreatures(CellGuidSet const& guid_set, Map* map)
AddObjectHelper<Creature>(map, obj);
// Grid load bypasses Map::AddToMap, so seat accessories here.
if (Vehicle* vehicle = obj->GetVehicleKit())
vehicle->Reset();
if (!obj->IsMoveInLineOfSightDisabled() && obj->GetDefaultMovementType() == IDLE_MOTION_TYPE && !obj->isNeedNotify(NOTIFY_VISIBILITY_CHANGED | NOTIFY_AI_RELOCATION))
{
if (obj->IsAlive() && !obj->HasUnitState(UNIT_STATE_SIGHTLESS) && obj->HasReactState(REACT_AGGRESSIVE) && !obj->IsImmuneToNPC())

View file

@ -346,8 +346,7 @@ bool Map::AddToMap(T* obj, bool checkTransport)
//also, trigger needs to cast spell, if not update, cannot see visual
obj->UpdateObjectVisibility(true);
// Xinef: little hack for vehicles, accessories have to be added after visibility update so they wont fall off the vehicle, moved from Creature::AIM_Initialize
// Initialize vehicle, this is done only for summoned npcs, DB creatures are handled by grid loaders
// Post-visibility so accessories seat after the vehicle's create packet reaches clients.
if (obj->IsCreature())
if (Vehicle* vehicle = obj->ToCreature()->GetVehicleKit())
vehicle->Reset();