diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/DungeonFinding/LFGScripts.cpp | 14 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/Creature.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Entities/GameObject/GameObject.cpp | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 3 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 2 | ||||
-rwxr-xr-x | src/server/game/Entities/Vehicle/Vehicle.cpp | 178 | ||||
-rw-r--r-- | src/server/game/Entities/Vehicle/Vehicle.h | 27 | ||||
-rw-r--r-- | src/server/game/Handlers/CharacterHandler.cpp | 37 | ||||
-rw-r--r-- | src/server/game/Maps/MapManager.cpp | 9 | ||||
-rw-r--r-- | src/server/game/Scripting/ScriptMgr.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.h | 6 | ||||
-rw-r--r-- | src/server/game/Spells/SpellMgr.cpp | 11 | ||||
-rw-r--r-- | src/server/game/World/World.h | 1 | ||||
-rw-r--r-- | src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp | 1 | ||||
-rw-r--r-- | src/server/scripts/Northrend/zone_storm_peaks.cpp | 114 | ||||
-rw-r--r-- | src/server/worldserver/RemoteAccess/RASocket.cpp | 17 | ||||
-rw-r--r-- | src/server/worldserver/RemoteAccess/RASocket.h | 1 |
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 /// @} |