diff options
Diffstat (limited to 'src/server')
-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/Handlers/CharacterHandler.cpp | 35 | ||||
-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/World/World.h | 2 | ||||
-rw-r--r-- | src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp | 1 | ||||
-rw-r--r-- | src/server/worldserver/RemoteAccess/RASocket.cpp | 17 | ||||
-rw-r--r-- | src/server/worldserver/RemoteAccess/RASocket.h | 1 |
12 files changed, 77 insertions, 19 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 fd87054b2d8..97d414b9915 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 7f9e317c2d2..e333c8bb211 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -260,7 +260,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 a520ae67442..19de01ffd41 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -7662,6 +7662,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/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index ace5a0b68eb..5dfba797448 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -229,7 +229,7 @@ void WorldSession::HandleCharEnum(PreparedQueryResult result) bitBuffer.WriteBit(1); if (result) { - _allowedCharsToLogin.clear(); + _legitCharacters.clear(); charCount = uint32(result->GetRowCount()); bitBuffer.reserve(24 * charCount / 8); @@ -245,7 +245,9 @@ void WorldSession::HandleCharEnum(PreparedQueryResult result) Player::BuildEnumData(result, &dataBuffer, &bitBuffer); - _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()); } while (result->NextRow()); bitBuffer.FlushBits(); @@ -800,7 +802,7 @@ void WorldSession::HandlePlayerLoginOpcode(WorldPacket& recvData) sLog->outDebug(LOG_FILTER_NETWORKIO, "Character (Guid: %u) logging in", GUID_LOPART(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(); @@ -1473,6 +1475,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; @@ -1704,6 +1715,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; @@ -1711,6 +1732,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 b42a2f3c0ed..32824addff2 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 5a973395c68..dd479984178 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 419de3a466e..70a405fd808 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -974,14 +974,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/World/World.h b/src/server/game/World/World.h index 6c86057eefb..872a6c7afb3 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -753,8 +753,8 @@ class World void AddCharacterNameData(uint32 guid, std::string const& name, uint8 gender, uint8 race, uint8 playerClass, uint8 level); void UpdateCharacterNameData(uint32 guid, std::string const& name, uint8 gender = GENDER_NONE, uint8 race = RACE_NONE); void UpdateCharacterNameDataLevel(uint32 guid, uint8 level); - void DeleteCharacterNameData(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/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 /// @} |