aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent_Michael <Vincent_Michael@gmx.de>2013-02-15 14:23:21 +0100
committerVincent_Michael <Vincent_Michael@gmx.de>2013-02-15 14:23:21 +0100
commit6beda05e3d5cdf77a49fa1fcdfd5e64070d7a10c (patch)
tree6106a48422550d02d501b276024c9c8306cff84e
parent3c5bf554ffa58e46eb88aebd46af21335d581432 (diff)
parent45363b8216f03f2dd4ce21cfb5ce183560374dd8 (diff)
Merge branch 'master' of github.com:TrinityCore/TrinityCore into 4.3.4
Conflicts: src/server/game/Handlers/CharacterHandler.cpp src/server/game/World/World.h
-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/Handlers/CharacterHandler.cpp35
-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/World/World.h2
-rw-r--r--src/server/scripts/Northrend/Gundrak/boss_drakkari_colossus.cpp1
-rw-r--r--src/server/worldserver/RemoteAccess/RASocket.cpp17
-rw-r--r--src/server/worldserver/RemoteAccess/RASocket.h1
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
/// @}