aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/server/game/DungeonFinding/LFGScripts.cpp14
-rw-r--r--src/server/game/Entities/Creature/Creature.cpp2
-rw-r--r--src/server/game/Entities/GameObject/GameObject.cpp2
-rw-r--r--src/server/game/Entities/Player/Player.cpp3
-rw-r--r--src/server/game/Entities/Unit/Unit.cpp4
-rw-r--r--src/server/game/Entities/Unit/Unit.h2
-rwxr-xr-xsrc/server/game/Entities/Vehicle/Vehicle.cpp178
-rw-r--r--src/server/game/Entities/Vehicle/Vehicle.h27
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp37
-rw-r--r--src/server/game/Maps/MapManager.cpp9
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp4
-rw-r--r--src/server/game/Server/WorldSession.h6
-rw-r--r--src/server/game/Spells/SpellMgr.cpp11
-rw-r--r--src/server/game/World/World.h1
-rw-r--r--src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp1
-rw-r--r--src/server/scripts/Northrend/zone_storm_peaks.cpp114
-rw-r--r--src/server/worldserver/RemoteAccess/RASocket.cpp17
-rw-r--r--src/server/worldserver/RemoteAccess/RASocket.h1
18 files changed, 274 insertions, 159 deletions
diff --git a/src/server/game/DungeonFinding/LFGScripts.cpp b/src/server/game/DungeonFinding/LFGScripts.cpp
index a4716de9524..22b86a094dd 100644
--- a/src/server/game/DungeonFinding/LFGScripts.cpp
+++ b/src/server/game/DungeonFinding/LFGScripts.cpp
@@ -95,6 +95,20 @@ void LFGPlayerScript::OnMapChanged(Player* player)
if (sLFGMgr->inLfgDungeonMap(player->GetGUID(), map->GetId(), map->GetDifficulty()))
{
Group* group = player->GetGroup();
+ // This function is also called when players log in
+ // if for some reason the LFG system recognises the player as being in a LFG dungeon,
+ // but the player was loaded without a valid group, we'll teleport to homebind to prevent
+ // crashes or other undefined behaviour
+ if (!group)
+ {
+ sLFGMgr->LeaveLfg(player->GetGUID());
+ player->RemoveAurasDueToSpell(LFG_SPELL_LUCK_OF_THE_DRAW);
+ player->TeleportTo(player->m_homebindMapId, player->m_homebindX, player->m_homebindY, player->m_homebindZ, 0.0f);
+ sLog->outError(LOG_FILTER_LFG, "LFGPlayerScript::OnMapChanged, Player %s (%u) is in LFG dungeon map but does not have a valid group! "
+ "Teleporting to homebind.", player->GetName().c_str(), player->GetGUIDLow());
+ return;
+ }
+
for (GroupReference* itr = group->GetFirstMember(); itr != NULL; itr = itr->next())
if (Player* member = itr->getSource())
player->GetSession()->SendNameQueryOpcode(member->GetGUID());
diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp
index 220bc4378ae..6208bcc4727 100644
--- a/src/server/game/Entities/Creature/Creature.cpp
+++ b/src/server/game/Entities/Creature/Creature.cpp
@@ -290,7 +290,7 @@ bool Creature::InitEntry(uint32 Entry, uint32 /*team*/, const CreatureData* data
}
// Initialize loot duplicate count depending on raid difficulty
- if (GetMap()->IsRaid() && GetMap()->GetSpawnMode() & RAID_DIFFICULTY_MASK_25MAN)
+ if (GetMap()->Is25ManRaid())
loot.maxDuplicates = 3;
SetEntry(Entry); // normal entry always
diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp
index 61e7943453e..c41c8e71a44 100644
--- a/src/server/game/Entities/GameObject/GameObject.cpp
+++ b/src/server/game/Entities/GameObject/GameObject.cpp
@@ -259,7 +259,7 @@ bool GameObject::Create(uint32 guidlow, uint32 name_id, Map* map, uint32 phaseMa
AIM_Initialize();
// Initialize loot duplicate count depending on raid difficulty
- if (map->IsRaid() && map->GetSpawnMode() & RAID_DIFFICULTY_MASK_25MAN)
+ if (map->Is25ManRaid())
loot.maxDuplicates = 3;
return true;
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 37502d69456..bdf3f1780d2 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -7376,6 +7376,9 @@ uint32 Player::GetZoneIdFromDB(uint64 guid)
float posy = fields[2].GetFloat();
float posz = fields[3].GetFloat();
+ if (!sMapStore.LookupEntry(map))
+ return 0;
+
zone = sMapMgr->GetZoneId(map, posx, posy, posz);
if (zone > 0)
diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp
index e3a2430f63a..fd9eef3868b 100644
--- a/src/server/game/Entities/Unit/Unit.cpp
+++ b/src/server/game/Entities/Unit/Unit.cpp
@@ -3147,7 +3147,9 @@ void Unit::DeMorph()
Aura* Unit::_TryStackingOrRefreshingExistingAura(SpellInfo const* newAura, uint8 effMask, Unit* caster, int32* baseAmount /*= NULL*/, Item* castItem /*= NULL*/, uint64 casterGUID /*= 0*/)
{
ASSERT(casterGUID || caster);
- if (!casterGUID)
+
+ // Check if these can stack anyway
+ if (!casterGUID && (newAura->IsChanneled() || newAura->AttributesEx3 & SPELL_ATTR3_STACK_FOR_DIFF_CASTERS))
casterGUID = caster->GetGUID();
// passive and Incanter's Absorption and auras with different type can stack with themselves any number of times
diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h
index 1a41c25d97c..62facf6a69e 100644
--- a/src/server/game/Entities/Unit/Unit.h
+++ b/src/server/game/Entities/Unit/Unit.h
@@ -332,6 +332,7 @@ class UnitAI;
class Totem;
class Transport;
class Vehicle;
+class VehicleJoinEvent;
class TransportBase;
class SpellCastTargets;
@@ -2183,6 +2184,7 @@ class Unit : public WorldObject
uint32 GetRedirectThreatPercent() { return _redirectThreadInfo.GetThreatPct(); }
Unit* GetRedirectThreatTarget() { return _redirectThreadInfo.GetTargetGUID() ? GetUnit(*this, _redirectThreadInfo.GetTargetGUID()) : NULL; }
+ friend class VehicleJoinEvent;
bool IsAIEnabled, NeedChangeAI;
bool CreateVehicleKit(uint32 id, uint32 creatureEntry);
void RemoveVehicleKit();
diff --git a/src/server/game/Entities/Vehicle/Vehicle.cpp b/src/server/game/Entities/Vehicle/Vehicle.cpp
index 96f2b6d73dd..5cbed1b3a64 100755
--- a/src/server/game/Entities/Vehicle/Vehicle.cpp
+++ b/src/server/game/Entities/Vehicle/Vehicle.cpp
@@ -30,9 +30,10 @@
#include "SpellInfo.h"
#include "MoveSplineInit.h"
#include "TemporarySummon.h"
+#include "EventProcessor.h"
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)
{
for (uint32 i = 0; i < MAX_VEHICLE_SEATS; ++i)
{
@@ -41,7 +42,7 @@ _me(unit), _vehicleInfo(vehInfo), _usableSeatNum(0), _creatureEntry(creatureEntr
{
Seats.insert(std::make_pair(i, VehicleSeat(veSeat)));
if (veSeat->CanEnterOrExit())
- ++_usableSeatNum;
+ ++UsableSeatNum;
}
}
@@ -123,10 +124,12 @@ void Vehicle::Uninstall()
"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();
+
if (GetBase()->GetTypeId() == TYPEID_UNIT)
sScriptMgr->OnUninstall(this);
}
@@ -136,14 +139,14 @@ void Vehicle::Reset(bool evading /*= false*/)
sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::Reset Entry: %u, GuidLow: %u", _creatureEntry, _me->GetGUIDLow());
if (_me->GetTypeId() == TYPEID_PLAYER)
{
- if (_usableSeatNum)
+ if (UsableSeatNum)
_me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
}
else
{
ApplyAllImmunities();
InstallAllAccessories(evading);
- if (_usableSeatNum)
+ if (UsableSeatNum)
_me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
}
@@ -215,6 +218,19 @@ void Vehicle::RemoveAllPassengers()
// ASSERT(!itr->second.passenger);
}
+void Vehicle::RemovePendingPassengers()
+{
+ sLog->outDebug(LOG_FILTER_VEHICLES, "Vehicle::RemovePendingPassengers. Entry: %u, GuidLow: %u", _creatureEntry, _me->GetGUIDLow());
+
+ /// Setting to_Abort to true will cause @VehicleJoinEvent::Abort to be executed on next @Unit::UpdateEvents call
+ /// This will properly "reset" the pending join process for the passenger.
+ while (VehicleJoinEvent* e = _pendingJoinEvents.front())
+ {
+ e->to_Abort = true;
+ _pendingJoinEvents.pop_front();
+ }
+}
+
bool Vehicle::HasEmptySeat(int8 seatId) const
{
SeatMap::const_iterator seat = Seats.find(seatId);
@@ -317,7 +333,17 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
if (unit->GetVehicle() != this)
return false;
+ // The seat selection code may kick other passengers off the vehicle.
+ // While the validity of the following may be arguable, it is possible that when such a passenger
+ // exits the vehicle will dismiss. That's why the actual adding the passenger to the vehicle is scheduled
+ // asynchronously, so it can be cancelled easily in case the vehicle is uninstalled meanwhile.
SeatMap::iterator seat;
+ sLog->outDebug(LOG_FILTER_VEHICLES, "Unit %s scheduling enter vehicle entry %u id %u dbguid %u seat %d",
+ unit->GetName().c_str(), _me->GetEntry(), _vehicleInfo->m_ID, _me->GetGUIDLow(), seatId);
+ VehicleJoinEvent* e = new VehicleJoinEvent(this, unit, seat);
+ unit->m_Events.AddEvent(e, unit->m_Events.CalculateTime(0));
+ _pendingJoinEvents.push_back(e);
+
if (seatId < 0) // no specific seat requirement
{
for (seat = Seats.begin(); seat != Seats.end(); ++seat)
@@ -325,13 +351,19 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
break;
if (seat == Seats.end()) // no available seat
+ {
+ CancelJoinEvent(e);
return false;
+ }
}
else
{
seat = Seats.find(seatId);
if (seat == Seats.end())
+ {
+ CancelJoinEvent(e);
return false;
+ }
if (seat->second.Passenger)
{
@@ -344,65 +376,6 @@ bool Vehicle::AddPassenger(Unit* unit, int8 seatId)
ASSERT(!seat->second.Passenger);
}
- sLog->outDebug(LOG_FILTER_VEHICLES, "Unit %s enter vehicle entry %u id %u dbguid %u seat %d", unit->GetName().c_str(), _me->GetEntry(), _vehicleInfo->m_ID, _me->GetGUIDLow(), (int32)seat->first);
-
- seat->second.Passenger = unit->GetGUID();
- if (seat->second.SeatInfo->CanEnterOrExit())
- {
- ASSERT(_usableSeatNum);
- --_usableSeatNum;
- if (!_usableSeatNum)
- {
- if (_me->GetTypeId() == TYPEID_PLAYER)
- _me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
- else
- _me->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
- }
- }
-
- if (seat->second.SeatInfo->m_flags && !(seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_ALLOW_TURNING))
- unit->AddUnitState(UNIT_STATE_ONVEHICLE);
-
- unit->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
- VehicleSeatEntry const* veSeat = seat->second.SeatInfo;
- unit->m_movementInfo.t_pos.m_positionX = veSeat->m_attachmentOffsetX;
- unit->m_movementInfo.t_pos.m_positionY = veSeat->m_attachmentOffsetY;
- unit->m_movementInfo.t_pos.m_positionZ = veSeat->m_attachmentOffsetZ;
- unit->m_movementInfo.t_pos.SetOrientation(0);
- unit->m_movementInfo.t_time = 0; // 1 for player
- unit->m_movementInfo.t_seat = seat->first;
- unit->m_movementInfo.t_guid = _me->GetGUID();
-
- 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())
- {
- unit->SendClearTarget(); // SMSG_BREAK_TARGET
- unit->SetControlled(true, UNIT_STATE_ROOT); // SMSG_FORCE_ROOT - In some cases we send SMSG_SPLINE_MOVE_ROOT here (for creatures)
- // also adds MOVEMENTFLAG_ROOT
- Movement::MoveSplineInit init(unit);
- init.DisableTransportPathTransformations();
- init.MoveTo(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ);
- init.SetFacing(0.0f);
- init.SetTransportEnter();
- init.Launch();
-
- if (_me->GetTypeId() == TYPEID_UNIT)
- {
- if (_me->ToCreature()->IsAIEnabled)
- _me->ToCreature()->AI()->PassengerBoarded(unit, seat->first, true);
-
- // update all passenger's positions
- //Passenger's spline OR vehicle movement will update positions
- //RelocatePassengers(_me->GetPositionX(), _me->GetPositionY(), _me->GetPositionZ(), _me->GetOrientation());
- }
- }
-
- if (GetBase()->GetTypeId() == TYPEID_UNIT)
- sScriptMgr->OnAddPassenger(this, unit, seatId);
-
return true;
}
@@ -419,14 +392,14 @@ void Vehicle::RemovePassenger(Unit* unit)
seat->second.Passenger = 0;
if (seat->second.SeatInfo->CanEnterOrExit())
{
- if (!_usableSeatNum)
+ if (!UsableSeatNum)
{
if (_me->GetTypeId() == TYPEID_PLAYER)
_me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
else
_me->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
}
- ++_usableSeatNum;
+ ++UsableSeatNum;
}
unit->ClearUnitState(UNIT_STATE_ONVEHICLE);
@@ -549,3 +522,78 @@ void Vehicle::CalculatePassengerOffset(float& x, float& y, float& z, float& o)
y = (iny - inx * tan(GetBase()->GetOrientation())) / (cos(GetBase()->GetOrientation()) + std::sin(GetBase()->GetOrientation()) * tan(GetBase()->GetOrientation()));
x = (inx + iny * tan(GetBase()->GetOrientation())) / (cos(GetBase()->GetOrientation()) + std::sin(GetBase()->GetOrientation()) * tan(GetBase()->GetOrientation()));
}
+
+void Vehicle::CancelJoinEvent(VehicleJoinEvent* e)
+{
+ e->to_Abort = true;
+ _pendingJoinEvents.pop_back();
+}
+
+bool VehicleJoinEvent::Execute(uint64, uint32)
+{
+ ASSERT(Passenger->GetVehicle() == Target);
+
+ Seat->second.Passenger = Passenger->GetGUID();
+ if (Seat->second.SeatInfo->CanEnterOrExit())
+ {
+ ASSERT(Target->UsableSeatNum);
+ --(Target->UsableSeatNum);
+ if (!Target->UsableSeatNum)
+ {
+ if (Target->GetBase()->GetTypeId() == TYPEID_PLAYER)
+ Target->GetBase()->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_PLAYER_VEHICLE);
+ else
+ Target->GetBase()->RemoveFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK);
+ }
+ }
+
+ if (Seat->second.SeatInfo->m_flags && !(Seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_ALLOW_TURNING))
+ Passenger->AddUnitState(UNIT_STATE_ONVEHICLE);
+
+ Passenger->AddUnitMovementFlag(MOVEMENTFLAG_ONTRANSPORT);
+ VehicleSeatEntry const* veSeat = Seat->second.SeatInfo;
+ Passenger->m_movementInfo.t_pos.m_positionX = veSeat->m_attachmentOffsetX;
+ Passenger->m_movementInfo.t_pos.m_positionY = veSeat->m_attachmentOffsetY;
+ Passenger->m_movementInfo.t_pos.m_positionZ = veSeat->m_attachmentOffsetZ;
+ Passenger->m_movementInfo.t_pos.SetOrientation(0.0f);
+ Passenger->m_movementInfo.t_time = 0; // 1 for player
+ Passenger->m_movementInfo.t_seat = Seat->first;
+ Passenger->m_movementInfo.t_guid = Target->GetBase()->GetGUID();
+
+ if (Target->GetBase()->GetTypeId() == TYPEID_UNIT && Passenger->GetTypeId() == TYPEID_PLAYER &&
+ Seat->second.SeatInfo->m_flags & VEHICLE_SEAT_FLAG_CAN_CONTROL)
+ ASSERT(Target->GetBase()->SetCharmedBy(Passenger, CHARM_TYPE_VEHICLE))
+
+ if (Target->GetBase()->IsInWorld())
+ {
+ Passenger->SendClearTarget(); // SMSG_BREAK_TARGET
+ Passenger->SetControlled(true, UNIT_STATE_ROOT); // SMSG_FORCE_ROOT - In some cases we send SMSG_SPLINE_MOVE_ROOT here (for creatures)
+ // also adds MOVEMENTFLAG_ROOT
+ Movement::MoveSplineInit init(Passenger);
+ init.DisableTransportPathTransformations();
+ init.MoveTo(veSeat->m_attachmentOffsetX, veSeat->m_attachmentOffsetY, veSeat->m_attachmentOffsetZ);
+ init.SetFacing(0.0f);
+ init.SetTransportEnter();
+ init.Launch();
+
+ if (Target->GetBase()->GetTypeId() == TYPEID_UNIT)
+ {
+ if (Target->GetBase()->ToCreature()->IsAIEnabled)
+ Target->GetBase()->ToCreature()->AI()->PassengerBoarded(Passenger, Seat->first, true);
+
+ // update all passenger's positions
+ //Passenger's spline OR vehicle movement will update positions
+ //RelocatePassengers(_me->GetPositionX(), _me->GetPositionY(), _me->GetPositionZ(), _me->GetOrientation());
+ }
+ }
+
+ if (Target->GetBase()->GetTypeId() == TYPEID_UNIT)
+ sScriptMgr->OnAddPassenger(Target, Passenger, Seat->first);
+
+ return true;
+}
+
+void VehicleJoinEvent::Abort(uint64)
+{
+ Passenger->m_vehicle = NULL;
+}
diff --git a/src/server/game/Entities/Vehicle/Vehicle.h b/src/server/game/Entities/Vehicle/Vehicle.h
index 823fb72b8a8..f8fa7f9b64a 100644
--- a/src/server/game/Entities/Vehicle/Vehicle.h
+++ b/src/server/game/Entities/Vehicle/Vehicle.h
@@ -23,12 +23,12 @@
#include "Object.h"
#include "VehicleDefines.h"
#include "Unit.h"
+#include <deque>
struct VehicleEntry;
-
class Unit;
-
typedef std::set<uint64> GuidSet;
+class VehicleJoinEvent;
class Vehicle : public TransportBase
{
@@ -54,6 +54,7 @@ class Vehicle : public TransportBase
void RemovePassenger(Unit* passenger);
void RelocatePassengers();
void RemoveAllPassengers();
+ void RemovePendingPassengers();
void Dismiss();
void TeleportVehicle(float x, float y, float z, float ang);
bool IsVehicleInUse() { return Seats.begin() != Seats.end(); }
@@ -66,6 +67,10 @@ class Vehicle : public TransportBase
VehicleSeatEntry const* GetSeatForPassenger(Unit* passenger);
protected:
+ friend class VehicleJoinEvent;
+ uint32 UsableSeatNum; // Number of seats that match VehicleSeatEntry::UsableByPlayer, used for proper display flags
+
+ protected:
friend bool Unit::CreateVehicleKit(uint32 id, uint32 creatureEntry);
Vehicle(Unit* unit, VehicleEntry const* vehInfo, uint32 creatureEntry);
friend void Unit::RemoveVehicleKit();
@@ -91,9 +96,25 @@ class Vehicle : public TransportBase
Unit* _me;
VehicleEntry const* _vehicleInfo;
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;
+
+ std::deque<VehicleJoinEvent*> _pendingJoinEvents;
+ void CancelJoinEvent(VehicleJoinEvent* e);
+};
+
+class VehicleJoinEvent : public BasicEvent
+{
+ friend class Vehicle;
+ protected:
+ VehicleJoinEvent(Vehicle* v, Unit* u, SeatMap::iterator& itr) : Target(v), Passenger(u), Seat(itr) {}
+ bool Execute(uint64, uint32);
+ void Abort(uint64);
+
+ Vehicle* Target;
+ Unit* Passenger;
+ SeatMap::iterator& Seat;
};
#endif
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index d8e50be11f0..817a7682678 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -215,7 +215,7 @@ void WorldSession::HandleCharEnum(PreparedQueryResult result)
data << num;
- _allowedCharsToLogin.clear();
+ _legitCharacters.clear();
if (result)
{
do
@@ -224,7 +224,9 @@ void WorldSession::HandleCharEnum(PreparedQueryResult result)
sLog->outInfo(LOG_FILTER_NETWORKIO, "Loading char guid %u from account %u.", guidlow, GetAccountId());
if (Player::BuildEnumData(result, &data))
{
- _allowedCharsToLogin.insert(guidlow);
+ _legitCharacters.insert(guidlow);
+ if (!sWorld->HasCharacterNameData(guidlow)) // This can happen if characters are inserted into the database manually. Core hasn't loaded name data yet.
+ sWorld->AddCharacterNameData(guidlow, (*result)[1].GetString(), (*result)[4].GetUInt8(), (*result)[2].GetUInt8(), (*result)[3].GetUInt8(), (*result)[7].GetUInt8());
++num;
}
}
@@ -757,7 +759,7 @@ void WorldSession::HandlePlayerLoginOpcode(WorldPacket& recvData)
recvData >> playerGuid;
- if (!CharCanLogin(GUID_LOPART(playerGuid)))
+ if (!IsLegitCharacterForAccount(GUID_LOPART(playerGuid)))
{
sLog->outError(LOG_FILTER_NETWORKIO, "Account (%u) can't login with that character (%u).", GetAccountId(), GUID_LOPART(playerGuid));
KickPlayer();
@@ -1384,6 +1386,15 @@ void WorldSession::HandleCharCustomize(WorldPacket& recvData)
std::string newName;
recvData >> guid;
+ if (!IsLegitCharacterForAccount(GUID_LOPART(guid)))
+ {
+ sLog->outError(LOG_FILTER_NETWORKIO, "Account %u, IP: %s tried to customise character %u, but it does not belong to their account!",
+ GetAccountId(), GetRemoteAddress().c_str(), GUID_LOPART(guid));
+ recvData.rfinish();
+ KickPlayer();
+ return;
+ }
+
recvData >> newName;
uint8 gender, skin, face, hairStyle, hairColor, facialHair;
@@ -1392,7 +1403,7 @@ void WorldSession::HandleCharCustomize(WorldPacket& recvData)
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_AT_LOGIN);
stmt->setUInt32(0, GUID_LOPART(guid));
-
+ // TODO: Make async with callback
PreparedQueryResult result = CharacterDatabase.Query(stmt);
if (!result)
@@ -1617,6 +1628,16 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData)
std::string newname;
uint8 gender, skin, face, hairStyle, hairColor, facialHair, race;
recvData >> guid;
+
+ if (!IsLegitCharacterForAccount(GUID_LOPART(guid)))
+ {
+ sLog->outError(LOG_FILTER_NETWORKIO, "Account %u, IP: %s tried to factionchange character %u, but it does not belong to their account!",
+ GetAccountId(), GetRemoteAddress().c_str(), GUID_LOPART(guid));
+ recvData.rfinish();
+ KickPlayer();
+ return;
+ }
+
recvData >> newname;
recvData >> gender >> skin >> hairColor >> hairStyle >> facialHair >> face >> race;
@@ -1624,6 +1645,14 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData)
// get the players old (at this moment current) race
CharacterNameData const* nameData = sWorld->GetCharacterNameData(lowGuid);
+ if (!nameData)
+ {
+ WorldPacket data(SMSG_CHAR_FACTION_CHANGE, 1);
+ data << uint8(CHAR_CREATE_ERROR);
+ SendPacket(&data);
+ return;
+ }
+
uint8 oldRace = nameData->m_race;
uint8 playerClass = nameData->m_class;
uint8 level = nameData->m_level;
diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp
index 755d443091a..f44a9dd865f 100644
--- a/src/server/game/Maps/MapManager.cpp
+++ b/src/server/game/Maps/MapManager.cpp
@@ -105,16 +105,17 @@ Map* MapManager::CreateBaseMap(uint32 id)
{
TRINITY_GUARD(ACE_Thread_Mutex, Lock);
- const MapEntry* entry = sMapStore.LookupEntry(id);
- if (entry && entry->Instanceable())
- {
+ MapEntry const* entry = sMapStore.LookupEntry(id);
+ ASSERT(entry);
+
+ if (entry->Instanceable())
map = new MapInstanced(id, i_gridCleanUpDelay);
- }
else
{
map = new Map(id, i_gridCleanUpDelay, 0, REGULAR_DIFFICULTY);
map->LoadRespawnTimes();
}
+
i_maps[id] = map;
}
diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp
index 8321b88962f..32fe5d2ef33 100644
--- a/src/server/game/Scripting/ScriptMgr.cpp
+++ b/src/server/game/Scripting/ScriptMgr.cpp
@@ -489,14 +489,14 @@ void ScriptMgr::OnGroupRateCalculation(float& rate, uint32 count, bool isRaid)
}
#define SCR_MAP_BGN(M, V, I, E, C, T) \
- if (V->GetEntry()->T()) \
+ if (V->GetEntry() && V->GetEntry()->T()) \
{ \
FOR_SCRIPTS(M, I, E) \
{ \
MapEntry const* C = I->second->GetEntry(); \
if (!C) \
continue; \
- if (entry->MapID == V->GetId()) \
+ if (C->MapID == V->GetId()) \
{
#define SCR_MAP_END \
diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h
index d6877b8a18a..c1d7f0b00db 100644
--- a/src/server/game/Server/WorldSession.h
+++ b/src/server/game/Server/WorldSession.h
@@ -919,14 +919,14 @@ class WorldSession
void LogUnprocessedTail(WorldPacket* packet);
// EnumData helpers
- bool CharCanLogin(uint32 lowGUID)
+ bool IsLegitCharacterForAccount(uint32 lowGUID)
{
- return _allowedCharsToLogin.find(lowGUID) != _allowedCharsToLogin.end();
+ return _legitCharacters.find(lowGUID) != _legitCharacters.end();
}
// this stores the GUIDs of the characters who can login
// characters who failed on Player::BuildEnumData shouldn't login
- std::set<uint32> _allowedCharsToLogin;
+ std::set<uint32> _legitCharacters;
uint32 m_GUIDLow; // set loggined or recently logout player (while m_playerRecentlyLogout set)
Player* _player;
diff --git a/src/server/game/Spells/SpellMgr.cpp b/src/server/game/Spells/SpellMgr.cpp
index dbd4e3904ea..b40943ff266 100644
--- a/src/server/game/Spells/SpellMgr.cpp
+++ b/src/server/game/Spells/SpellMgr.cpp
@@ -3371,6 +3371,17 @@ void SpellMgr::LoadDbcDataCorrections()
case 64596: // Cosmic Smash (Algalon the Observer)
spellInfo->rangeIndex = 6; // 100yd
break;
+ case 64014: // Expedition Base Camp Teleport
+ case 64024: // Conservatory Teleport
+ case 64025: // Halls of Invention Teleport
+ case 64028: // Colossal Forge Teleport
+ case 64029: // Shattered Walkway Teleport
+ case 64030: // Antechamber Teleport
+ case 64031: // Scrapyard Teleport
+ case 64032: // Formation Grounds Teleport
+ case 65042: // Prison of Yogg-Saron Teleport
+ spellInfo->EffectImplicitTargetA[0] = TARGET_DEST_DB;
+ break;
// ENDOF ULDUAR SPELLS
//
// TRIAL OF THE CRUSADER SPELLS
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 95c10329690..30021338c4e 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -734,6 +734,7 @@ class World
void UpdateCharacterNameData(uint32 guid, std::string const& name, uint8 gender = GENDER_NONE, uint8 race = RACE_NONE);
void UpdateCharacterNameDataLevel(uint32 guid, uint8 level);
void DeleteCharaceterNameData(uint32 guid) { _characterNameDataMap.erase(guid); }
+ bool HasCharacterNameData(uint32 guid) { return _characterNameDataMap.find(guid) != _characterNameDataMap.end(); }
uint32 GetCleaningFlags() const { return m_CleaningFlags; }
void SetCleaningFlags(uint32 flags) { m_CleaningFlags = flags; }
diff --git a/src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp b/src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp
index 58301df4ca2..76b2e7bac7e 100644
--- a/src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp
+++ b/src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp
@@ -148,6 +148,7 @@ class boss_drakkari_colossus : public CreatureScript
DoCast(SPELL_EMERGE);
break;
case ACTION_FREEZE_COLOSSUS:
+ me->GetMotionMaster()->Clear();
me->GetMotionMaster()->MoveIdle();
me->SetReactState(REACT_PASSIVE);
diff --git a/src/server/scripts/Northrend/zone_storm_peaks.cpp b/src/server/scripts/Northrend/zone_storm_peaks.cpp
index dae2ffd36f6..d9528446bcf 100644
--- a/src/server/scripts/Northrend/zone_storm_peaks.cpp
+++ b/src/server/scripts/Northrend/zone_storm_peaks.cpp
@@ -356,34 +356,20 @@ public:
enum FreedProtoDrake
{
+ NPC_DRAKE = 29709,
+
AREA_VALLEY_OF_ANCIENT_WINTERS = 4437,
+
TEXT_EMOTE = 0,
+
SPELL_KILL_CREDIT_PRISONER = 55144,
SPELL_SUMMON_LIBERATED = 55073,
- SPELL_KILL_CREDIT_DRAKE = 55143
-};
+ SPELL_KILL_CREDIT_DRAKE = 55143,
-const Position FreedDrakeWaypoints[16] =
-{
- {7294.96f, -2418.733f, 823.869f, 0.0f},
- {7315.984f, -2331.46f, 826.3972f, 0.0f},
- {7271.826f, -2271.479f, 833.5917f, 0.0f},
- {7186.253f, -2218.475f, 847.5632f, 0.0f},
- {7113.195f, -2164.288f, 850.2301f, 0.0f},
- {7078.018f, -2063.106f, 854.7581f, 0.0f},
- {7073.221f, -1983.382f, 861.9246f, 0.0f},
- {7061.455f, -1885.899f, 865.119f, 0.0f},
- {7033.32f, -1826.775f, 876.2578f, 0.0f},
- {6999.902f, -1784.012f, 897.4521f, 0.0f},
- {6954.913f, -1747.043f, 897.4521f, 0.0f},
- {6933.856f, -1720.698f, 882.2022f, 0.0f},
- {6932.729f, -1687.306f, 866.1189f, 0.0f},
- {6952.458f, -1663.802f, 849.8133f, 0.0f},
- {7002.819f, -1651.681f, 831.397f, 0.0f},
- {7026.531f, -1649.239f, 828.8406f, 0.0f}
+ EVENT_CHECK_AREA = 1,
+ EVENT_REACHED_HOME = 2,
};
-
class npc_freed_protodrake : public CreatureScript
{
public:
@@ -393,74 +379,60 @@ public:
{
npc_freed_protodrakeAI(Creature* creature) : VehicleAI(creature) {}
- bool autoMove;
- bool wpReached;
- uint16 CheckTimer;
- uint16 countWP;
+ EventMap events;
void Reset()
{
- autoMove = false;
- wpReached = false;
- CheckTimer = 5000;
- countWP = 0;
+ events.ScheduleEvent(EVENT_CHECK_AREA, 5000);
}
void MovementInform(uint32 type, uint32 id)
{
- if (type != POINT_MOTION_TYPE)
+ if (type != WAYPOINT_MOTION_TYPE)
return;
- if (id < 15)
- {
- ++countWP;
- wpReached = true;
- }
- else
+ if (id == 15)
// drake reached village
- {
- // get player that rides drake (from seat 0)
- Unit* player = me->GetVehicleKit()->GetPassenger(0);
- if (player && player->GetTypeId() == TYPEID_PLAYER)
- {
- // for each prisoner on drake, give credit
- for (uint8 i = 1; i < 4; ++i)
- if (Unit* prisoner = me->GetVehicleKit()->GetPassenger(i))
- {
- if (prisoner->GetTypeId() != TYPEID_UNIT)
- return;
- prisoner->CastSpell(player, SPELL_KILL_CREDIT_PRISONER, true);
- prisoner->CastSpell(prisoner, SPELL_SUMMON_LIBERATED, true);
- prisoner->ExitVehicle();
- }
- me->CastSpell(me, SPELL_KILL_CREDIT_DRAKE, true);
- player->ExitVehicle();
- }
- }
+ events.ScheduleEvent(EVENT_REACHED_HOME, 2000);
}
void UpdateAI(const uint32 diff)
{
- if (!autoMove)
+ events.Update(diff);
+
+ switch (events.ExecuteEvent())
{
- if (CheckTimer < diff)
- {
- CheckTimer = 5000;
+ case EVENT_CHECK_AREA:
if (me->GetAreaId() == AREA_VALLEY_OF_ANCIENT_WINTERS)
{
- Talk(TEXT_EMOTE, me->GetVehicleKit()->GetPassenger(0)->GetGUID());
- autoMove = true;
- wpReached = true;
+ if (Vehicle* vehicle = me->GetVehicleKit())
+ if (Unit* passenger = vehicle->GetPassenger(0))
+ {
+ Talk(TEXT_EMOTE, passenger->GetGUID());
+ me->GetMotionMaster()->MovePath(NPC_DRAKE, false);
+ }
}
- }
- else
- CheckTimer -= diff;
- }
-
- if (wpReached && autoMove)
- {
- wpReached = false;
- me->GetMotionMaster()->MovePoint(countWP, FreedDrakeWaypoints[countWP]);
+ else
+ events.ScheduleEvent(EVENT_CHECK_AREA, 5000);
+ break;
+ case EVENT_REACHED_HOME:
+ Unit* player = me->GetVehicleKit()->GetPassenger(0);
+ if (player && player->GetTypeId() == TYPEID_PLAYER)
+ {
+ // for each prisoner on drake, give credit
+ for (uint8 i = 1; i < 4; ++i)
+ if (Unit* prisoner = me->GetVehicleKit()->GetPassenger(i))
+ {
+ if (prisoner->GetTypeId() != TYPEID_UNIT)
+ return;
+ prisoner->CastSpell(player, SPELL_KILL_CREDIT_PRISONER, true);
+ prisoner->CastSpell(prisoner, SPELL_SUMMON_LIBERATED, true);
+ prisoner->ExitVehicle();
+ }
+ me->CastSpell(me, SPELL_KILL_CREDIT_DRAKE, true);
+ player->ExitVehicle();
+ }
+ break;
}
}
};
diff --git a/src/server/worldserver/RemoteAccess/RASocket.cpp b/src/server/worldserver/RemoteAccess/RASocket.cpp
index ee05e83ad4d..359abd39901 100644
--- a/src/server/worldserver/RemoteAccess/RASocket.cpp
+++ b/src/server/worldserver/RemoteAccess/RASocket.cpp
@@ -33,6 +33,7 @@
RASocket::RASocket()
{
_minLevel = uint8(ConfigMgr::GetIntDefault("RA.MinLevel", 3));
+ _commandExecuting = false;
}
RASocket::~RASocket()
@@ -59,6 +60,12 @@ int RASocket::handle_close(ACE_HANDLE, ACE_Reactor_Mask)
sLog->outInfo(LOG_FILTER_REMOTECOMMAND, "Closing connection");
peer().close_reader();
wait();
+ // While the above wait() will wait for the ::svc() to finish, it will not wait for the async event
+ // RASocket::commandfinished to be completed. Calling destroy() before the latter function ends
+ // will lead to using a freed pointer -> crash.
+ while (_commandExecuting.value())
+ ACE_OS::sleep(1);
+
destroy();
return 0;
}
@@ -150,6 +157,7 @@ int RASocket::process_command(const std::string& command)
return -1;
}
+ _commandExecuting = true;
CliCommandHolder* cmd = new CliCommandHolder(this, command.c_str(), &RASocket::zprint, &RASocket::commandFinished);
sWorld->QueueCliCommand(cmd);
@@ -412,10 +420,11 @@ void RASocket::commandFinished(void* callbackArg, bool /*success*/)
// the message is 0 size control message to tell that command output is finished
// hence we don't put timeout, because it shouldn't increase queue size and shouldn't block
- if (socket->putq(mb) == -1)
- {
+ if (socket->putq(mb->duplicate()) == -1)
// getting here is bad, command can't be marked as complete
sLog->outDebug(LOG_FILTER_REMOTECOMMAND, "Failed to enqueue command end message. Error is %s", ACE_OS::strerror(errno));
- mb->release();
- }
+
+ mb->release();
+
+ socket->_commandExecuting = false;
}
diff --git a/src/server/worldserver/RemoteAccess/RASocket.h b/src/server/worldserver/RemoteAccess/RASocket.h
index d23d1f0d5fd..e92cb35eaf0 100644
--- a/src/server/worldserver/RemoteAccess/RASocket.h
+++ b/src/server/worldserver/RemoteAccess/RASocket.h
@@ -57,6 +57,7 @@ class RASocket: public ACE_Svc_Handler<ACE_SOCK_STREAM, ACE_MT_SYNCH>
private:
/// Minimum security level required to connect
uint8 _minLevel;
+ ACE_Atomic_Op<ACE_Thread_Mutex, bool> _commandExecuting;
};
#endif
/// @}