Core/Vehicles: Add some internal checks in vehicle code to prevent crashable behaviour caused by scripts or other areas of the core.

This commit is contained in:
Machiavelli
2013-01-05 15:40:36 +01:00
parent 32fa3f6018
commit b52346522e
2 changed files with 50 additions and 24 deletions

View File

@@ -31,7 +31,8 @@
#include "MoveSplineInit.h"
#include "TemporarySummon.h"
Vehicle::Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry) : _me(unit), _vehicleInfo(vehInfo), _usableSeatNum(0), _creatureEntry(creatureEntry)
Vehicle::Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry) :
_me(unit), _vehicleInfo(vehInfo), _usableSeatNum(0), _creatureEntry(creatureEntry), _status(STATUS_NONE)
{
for (uint32 i = 0; i < MAX_VEHICLE_SEATS; ++i)
{
@@ -49,6 +50,8 @@ Vehicle::Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry)
Vehicle::~Vehicle()
{
/// @Uninstall must be called before this.
ASSERT(_status == STATUS_UNINSTALLING);
for (SeatMap::const_iterator itr = Seats.begin(); itr != Seats.end(); ++itr)
ASSERT(!itr->second.Passenger);
}
@@ -92,6 +95,7 @@ void Vehicle::Install()
}
}
_status = STATUS_INSTALLED;
if (GetBase()->GetTypeId() == TYPEID_UNIT)
sScriptMgr->OnInstall(this);
}
@@ -112,6 +116,14 @@ void Vehicle::InstallAllAccessories(bool evading)
void Vehicle::Uninstall()
{
/// @Prevent recursive uninstall call. (Bad script in OnUninstall/OnRemovePassenger/PassengerBoarded hook.)
if (_status == STATUS_UNINSTALLING)
{
sLog->outError(LOG_FILTER_VEHICLES, "Vehicle GuidLow: %u, Entry: %u attempts to uninstall, but already has STATUS_UNINSTALLING! "
"Check Uninstall/PassengerBoarded script hooks for errors.", _me->GetGUIDLow(), _me->GetEntry());
return;
}
_status = STATUS_UNINSTALLING;
sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Uninstall Entry: %u, GuidLow: %u", _creatureEntry, _me->GetGUIDLow());
RemoveAllPassengers();
@@ -250,6 +262,14 @@ int8 Vehicle::GetNextEmptySeat(int8 seatId, bool next) const
void Vehicle::InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 type, uint32 summonTime)
{
/// @Prevent adding accessories when vehicle is uninstalling. (Bad script in OnUninstall/OnRemovePassenger/PassengerBoarded hook.)
if (_status == STATUS_UNINSTALLING)
{
sLog->outError(LOG_FILTER_VEHICLES, "Vehicle GuidLow: %u, Entry: %u attempts to install accessory Entry: %u on seat %d with STATUS_UNINSTALLING! "
"Check Uninstall/PassengerBoarded script hooks for errors.", _me->GetGUIDLow(), _me->GetEntry(), entry, (int32)seatId);
return;
}
sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle: Installing accessory entry %u on vehicle entry %u (seat:%i)", entry, GetCreatureEntry(), seatId);
if (Unit* passenger = GetPassenger(seatId))
{
@@ -279,14 +299,6 @@ void Vehicle::InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 typ
return;
}
// this cannot be checked instantly like this
// spellsystem is delaying everything to next update tick
//if (!accessory->IsOnVehicle(me))
//{
// accessory->UnSummon();
// return; // Something went wrong in the spellsystem
//}
if (GetBase()->GetTypeId() == TYPEID_UNIT)
sScriptMgr->OnInstallAccessory(this, accessory);
}
@@ -294,6 +306,14 @@ void Vehicle::InstallAccessory(uint32 entry, int8 seatId, bool minion, uint8 typ
bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
{
/// @Prevent adding passengers when vehicle is uninstalling. (Bad script in OnUninstall/OnRemovePassenger/PassengerBoarded hook.)
if (_status == STATUS_UNINSTALLING)
{
sLog->outError(LOG_FILTER_VEHICLES, "Passenger GuidLow: %u, Entry: %u, attempting to board vehicle GuidLow: %u, Entry: %u during uninstall! SeatId: %i",
unit->GetGUIDLow(), unit->GetEntry(), _me->GetGUIDLow(), _me->GetEntry(), (int32)seatId);
return false;
}
if (unit->GetVehicle() != this)
return false;
@@ -353,13 +373,9 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
unit->m_movementInfo.t_seat = seat->first;
unit->m_movementInfo.t_guid = _me->GetGUID();
if (_me->GetTypeId() == TYPEID_UNIT
&& unit->GetTypeId() == TYPEID_PLAYER
&& seat->first == 0 && seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_CAN_CONTROL)
{
if (!_me->SetCharmedBy(unit, CHARM_TYPE_VEHICLE))
ASSERT(false);
}
if (_me->GetTypeId() == TYPEID_UNIT && unit->GetTypeId() == TYPEID_PLAYER &&
seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_CAN_CONTROL)
ASSERT(_me->SetCharmedBy(unit, CHARM_TYPE_VEHICLE))
if (_me->IsInWorld())
{
@@ -415,7 +431,7 @@ void Vehicle::RemovePassenger(Unit* unit)
unit->ClearUnitState(UNIT_STATE_ONVEHICLE);
if (_me->GetTypeId() == TYPEID_UNIT && unit->GetTypeId() == TYPEID_PLAYER && seat->first == 0 && seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_CAN_CONTROL)
if (_me->GetTypeId() == TYPEID_UNIT && unit->GetTypeId() == TYPEID_PLAYER && seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_CAN_CONTROL)
_me->RemoveCharmedBy(unit);
if (_me->IsInWorld())
@@ -426,13 +442,13 @@ void Vehicle::RemovePassenger(Unit* unit)
unit->m_movementInfo.t_seat = 0;
}
if (_me->GetTypeId() == TYPEID_UNIT && _me->ToCreature()->IsAIEnabled)
_me->ToCreature()->AI()->PassengerBoarded(unit, seat->first, false);
// only for flyable vehicles
if (unit->IsFlying())
_me->CastSpell(unit, VEHICLE_SPELL_PARACHUTE, true);
if (_me->GetTypeId() == TYPEID_UNIT && _me->ToCreature()->IsAIEnabled)
_me->ToCreature()->AI()->PassengerBoarded(unit, seat->first, false);
if (GetBase()->GetTypeId() == TYPEID_UNIT)
sScriptMgr->OnRemovePassenger(this, unit);
}

View File

@@ -32,9 +32,6 @@ typedef std::set<uint64> GuidSet;
class Vehicle : public TransportBase
{
public:
explicit Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry);
virtual ~Vehicle();
void Install();
void Uninstall();
void Reset(bool evading = false);
@@ -67,7 +64,20 @@ class Vehicle : public TransportBase
VehicleSeatEntry const* GetSeatForPassenger(Unit* passenger);
protected:
friend bool Unit::CreateVehicleKit(uint32 id, uint32 creatureEntry);
Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry);
friend void Unit::RemoveVehicleKit();
~Vehicle();
private:
enum Status
{
STATUS_NONE,
STATUS_INSTALLED,
STATUS_UNINSTALLING,
};
SeatMap::iterator GetSeatIteratorForPassenger(Unit* passenger);
void InitMovementInfoForBase();
@@ -82,7 +92,7 @@ class Vehicle : public TransportBase
GuidSet vehiclePlayers;
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;
Position m_lastShootPos;
};
#endif