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
This commit is contained in:
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
/// @}
|
||||
|
||||
Reference in New Issue
Block a user