Core/Maps: Moved corpse management to map level
(cherry picked from commit cd27fd38b93884797c094a82dc7beb0498e2f124) # Conflicts: # src/server/database/Database/Implementation/CharacterDatabase.cpp # src/server/database/Database/Implementation/CharacterDatabase.h # src/server/game/Entities/Corpse/Corpse.cpp # src/server/game/Entities/Creature/GossipDef.cpp # src/server/game/Entities/Player/Player.cpp # src/server/game/Entities/Player/Player.h # src/server/game/Globals/ObjectAccessor.cpp # src/server/game/Globals/ObjectAccessor.h # src/server/game/Globals/ObjectMgr.cpp # src/server/game/Globals/ObjectMgr.h # src/server/game/Grids/ObjectGridLoader.cpp # src/server/game/Handlers/AuctionHouseHandler.cpp # src/server/game/Handlers/CharacterHandler.cpp # src/server/game/Handlers/ChatHandler.cpp # src/server/game/Handlers/QueryHandler.cpp # src/server/game/Maps/Map.cpp # src/server/game/Server/Packets/CharacterPackets.cpp # src/server/game/World/World.cpp # src/server/scripts/Commands/cs_reload.cpp
This commit is contained in:
1 parent
70a5cdfc04
commit
402a3c45ff
30 files changed
+328
-418
No files matched your search
@@ -320,6 +320,7 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
||||
PrepareStatement(CHAR_INS_CORPSE, "INSERT INTO corpse (guid, posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, guildId, flags, dynFlags, time, corpseType, instanceId, phaseMask) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_CORPSE, "DELETE FROM corpse WHERE guid = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_DEL_CORPSES_FROM_MAP, "DELETE FROM corpse WHERE mapId = ? AND instanceId = ?", CONNECTION_ASYNC);
|
||||
PrepareStatement(CHAR_SEL_CORPSE_LOCATION, "SELECT mapId, posX, posY, posZ, orientation FROM corpse WHERE guid = ?", CONNECTION_ASYNC);
|
||||
|
||||
// Creature respawn
|
||||
PrepareStatement(CHAR_SEL_CREATURE_RESPAWNS, "SELECT guid, respawnTime FROM creature_respawn WHERE mapId = ? AND instanceId = ?", CONNECTION_SYNCH);
|
||||
|
||||
@@ -269,6 +269,7 @@ enum CharacterDatabaseStatements
|
||||
CHAR_INS_CORPSE,
|
||||
CHAR_DEL_CORPSE,
|
||||
CHAR_DEL_CORPSES_FROM_MAP,
|
||||
CHAR_SEL_CORPSE_LOCATION,
|
||||
|
||||
CHAR_SEL_CREATURE_RESPAWNS,
|
||||
CHAR_REP_CREATURE_RESPAWN,
|
||||
|
||||
@@ -208,7 +208,7 @@ void SmartAI::EndPath(bool fail)
|
||||
if (targets->size() == 1 && GetScript()->IsPlayer((*targets->begin())))
|
||||
{
|
||||
Player* player = (*targets->begin())->ToPlayer();
|
||||
if (!fail && player->IsAtGroupRewardDistance(me) && !player->GetCorpse())
|
||||
if (!fail && player->IsAtGroupRewardDistance(me) && !player->HasCorpse())
|
||||
player->GroupEventHappens(mEscortQuestID, me);
|
||||
|
||||
if (fail && player->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE)
|
||||
@@ -220,7 +220,7 @@ void SmartAI::EndPath(bool fail)
|
||||
{
|
||||
Player* groupGuy = groupRef->GetSource();
|
||||
|
||||
if (!fail && groupGuy->IsAtGroupRewardDistance(me) && !groupGuy->GetCorpse())
|
||||
if (!fail && groupGuy->IsAtGroupRewardDistance(me) && !groupGuy->HasCorpse())
|
||||
groupGuy->AreaExploredOrEventHappens(mEscortQuestID);
|
||||
if (fail && groupGuy->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE)
|
||||
groupGuy->FailQuest(mEscortQuestID);
|
||||
@@ -233,7 +233,7 @@ void SmartAI::EndPath(bool fail)
|
||||
if (GetScript()->IsPlayer((*iter)))
|
||||
{
|
||||
Player* player = (*iter)->ToPlayer();
|
||||
if (!fail && player->IsAtGroupRewardDistance(me) && !player->GetCorpse())
|
||||
if (!fail && player->IsAtGroupRewardDistance(me) && !player->HasCorpse())
|
||||
player->AreaExploredOrEventHappens(mEscortQuestID);
|
||||
if (fail && player->GetQuestStatus(mEscortQuestID) == QUEST_STATUS_INCOMPLETE)
|
||||
player->FailQuest(mEscortQuestID);
|
||||
|
||||
@@ -695,7 +695,7 @@ void BfGraveyard::Resurrect()
|
||||
player->CastSpell(player, 6962, true);
|
||||
player->CastSpell(player, SPELL_SPIRIT_HEAL_MANA, true);
|
||||
|
||||
sObjectAccessor->ConvertCorpseForPlayer(player->GetGUID());
|
||||
player->SpawnCorpseBones(false);
|
||||
}
|
||||
|
||||
m_ResurrectQueue.clear();
|
||||
|
||||
@@ -367,7 +367,7 @@ inline void Battleground::_ProcessResurrect(uint32 diff)
|
||||
player->ResurrectPlayer(1.0f);
|
||||
player->CastSpell(player, 6962, true);
|
||||
player->CastSpell(player, SPELL_SPIRIT_HEAL_MANA, true);
|
||||
sObjectAccessor->ConvertCorpseForPlayer(*itr);
|
||||
player->SpawnCorpseBones(false);
|
||||
}
|
||||
m_ResurrectQueue.clear();
|
||||
}
|
||||
@@ -889,8 +889,11 @@ void Battleground::RemovePlayerAtLeave(ObjectGuid guid, bool Transport, bool Sen
|
||||
player->SpawnCorpseBones();
|
||||
}
|
||||
}
|
||||
else // try to resurrect the offline player. If he is alive nothing will happen
|
||||
sObjectAccessor->ConvertCorpseForPlayer(guid);
|
||||
else
|
||||
{
|
||||
SQLTransaction trans(nullptr);
|
||||
Player::OfflineResurrect(guid, trans);
|
||||
}
|
||||
|
||||
RemovePlayer(player, guid, team); // BG subclass specific code
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "UpdateMask.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "World.h"
|
||||
|
||||
Corpse::Corpse(CorpseType type) : WorldObject(type != CORPSE_BONES), m_type(type)
|
||||
{
|
||||
@@ -138,10 +139,14 @@ void Corpse::DeleteBonesFromWorld()
|
||||
|
||||
void Corpse::DeleteFromDB(SQLTransaction& trans)
|
||||
{
|
||||
PreparedStatement* stmt = NULL;
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CORPSE);
|
||||
stmt->setUInt32(0, GetOwnerGUID().GetCounter());
|
||||
trans->Append(stmt);
|
||||
DeleteFromDB(GetOwnerGUID(), trans);
|
||||
}
|
||||
|
||||
void Corpse::DeleteFromDB(ObjectGuid const& ownerGuid, SQLTransaction& trans)
|
||||
{
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CORPSE);
|
||||
stmt->setUInt32(0, ownerGuid.GetCounter());
|
||||
CharacterDatabase.ExecuteOrAppend(trans, stmt);
|
||||
}
|
||||
|
||||
bool Corpse::LoadCorpseFromDB(uint32 guid, Field* fields)
|
||||
@@ -193,6 +198,10 @@ bool Corpse::LoadCorpseFromDB(uint32 guid, Field* fields)
|
||||
|
||||
bool Corpse::IsExpired(time_t t) const
|
||||
{
|
||||
// Deleted character
|
||||
if (!sWorld->GetCharacterNameData(GetOwnerGUID()))
|
||||
return true;
|
||||
|
||||
if (m_type == CORPSE_BONES)
|
||||
return m_time < t - 60 * MINUTE;
|
||||
else
|
||||
|
||||
@@ -63,6 +63,7 @@ class Corpse : public WorldObject, public GridObject<Corpse>
|
||||
|
||||
void DeleteBonesFromWorld();
|
||||
void DeleteFromDB(SQLTransaction& trans);
|
||||
static void DeleteFromDB(ObjectGuid const& ownerGuid, SQLTransaction& trans);
|
||||
|
||||
ObjectGuid GetOwnerGUID() const { return GetGuidValue(CORPSE_FIELD_OWNER); }
|
||||
|
||||
|
||||
@@ -1743,7 +1743,7 @@ void WorldObject::SendObjectDeSpawnAnim(ObjectGuid guid)
|
||||
void WorldObject::SetMap(Map* map)
|
||||
{
|
||||
ASSERT(map);
|
||||
ASSERT(!IsInWorld() || GetTypeId() == TYPEID_CORPSE);
|
||||
ASSERT(!IsInWorld());
|
||||
if (m_currMap == map) // command add npc: first create, than loadfromdb
|
||||
return;
|
||||
if (m_currMap)
|
||||
|
||||
@@ -2022,6 +2022,8 @@ bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data)
|
||||
|
||||
uint32 charFlags = 0;
|
||||
uint32 playerFlags = fields[14].GetUInt32();
|
||||
if (atLoginFlags & AT_LOGIN_RESURRECT)
|
||||
playerFlags &= ~PLAYER_FLAGS_GHOST;
|
||||
if (playerFlags & PLAYER_FLAGS_HIDE_HELM)
|
||||
charFlags |= CHARACTER_FLAG_HIDE_HELM;
|
||||
if (playerFlags & PLAYER_FLAGS_HIDE_CLOAK)
|
||||
@@ -4537,10 +4539,6 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
|
||||
charDelete_method = CHAR_DELETE_REMOVE;
|
||||
}
|
||||
|
||||
// convert corpse to bones if exist (to prevent exiting Corpse in World without DB entry)
|
||||
// bones will be deleted by corpse/bones deleting thread shortly
|
||||
sObjectAccessor->ConvertCorpseForPlayer(playerguid);
|
||||
|
||||
if (uint32 guildId = GetGuildIdFromDB(playerguid))
|
||||
if (Guild* guild = sGuildMgr->GetGuildById(guildId))
|
||||
guild->DeleteMember(playerguid, false, false, true);
|
||||
@@ -4841,6 +4839,8 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe
|
||||
stmt->setUInt32(0, guid);
|
||||
trans->Append(stmt);
|
||||
|
||||
Corpse::DeleteFromDB(playerguid, trans);
|
||||
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
break;
|
||||
}
|
||||
@@ -4940,18 +4940,17 @@ void Player::BuildPlayerRepop()
|
||||
|
||||
// there must be SMSG.FORCE_RUN_SPEED_CHANGE, SMSG.FORCE_SWIM_SPEED_CHANGE, SMSG.MOVE_WATER_WALK
|
||||
// there must be SMSG.STOP_MIRROR_TIMER
|
||||
// there we must send 888 opcode
|
||||
|
||||
// the player cannot have a corpse already, only bones which are not returned by GetCorpse
|
||||
if (GetCorpse())
|
||||
// the player cannot have a corpse already on current map, only bones which are not returned by GetCorpse
|
||||
WorldLocation corpseLocation = GetCorpseLocation();
|
||||
if (corpseLocation.GetMapId() == GetMapId())
|
||||
{
|
||||
TC_LOG_ERROR("entities.player", "BuildPlayerRepop: player %s(%d) already has a corpse", GetName().c_str(), GetGUID().GetCounter());
|
||||
return;
|
||||
}
|
||||
|
||||
// create a corpse and place it at the player's location
|
||||
CreateCorpse();
|
||||
Corpse* corpse = GetCorpse();
|
||||
Corpse* corpse = CreateCorpse();
|
||||
if (!corpse)
|
||||
{
|
||||
TC_LOG_ERROR("entities.player", "Error creating corpse for Player %s [%u]", GetName().c_str(), GetGUID().GetCounter());
|
||||
@@ -5093,7 +5092,16 @@ void Player::KillPlayer()
|
||||
UpdateObjectVisibility();
|
||||
}
|
||||
|
||||
void Player::CreateCorpse()
|
||||
void Player::OfflineResurrect(ObjectGuid const& guid, SQLTransaction& trans)
|
||||
{
|
||||
Corpse::DeleteFromDB(guid, trans);
|
||||
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG);
|
||||
stmt->setUInt16(0, uint16(AT_LOGIN_RESURRECT));
|
||||
stmt->setUInt64(1, guid.GetCounter());
|
||||
CharacterDatabase.ExecuteOrAppend(trans, stmt);
|
||||
}
|
||||
|
||||
Corpse* Player::CreateCorpse()
|
||||
{
|
||||
// prevent existence 2 corpse for player
|
||||
SpawnCorpseBones();
|
||||
@@ -5106,9 +5114,11 @@ void Player::CreateCorpse()
|
||||
if (!corpse->Create(GetMap()->GenerateLowGuid<HighGuid::Corpse>(), this))
|
||||
{
|
||||
delete corpse;
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
_corpseLocation.WorldRelocate(*this);
|
||||
|
||||
_uf = GetUInt32Value(UNIT_FIELD_BYTES_0);
|
||||
_pb = GetUInt32Value(PLAYER_BYTES);
|
||||
_pb2 = GetUInt32Value(PLAYER_BYTES_2);
|
||||
@@ -5159,19 +5169,21 @@ void Player::CreateCorpse()
|
||||
corpse->SaveToDB();
|
||||
|
||||
// register for player, but not show
|
||||
sObjectAccessor->AddCorpse(corpse);
|
||||
GetMap()->AddCorpse(corpse);
|
||||
return corpse;
|
||||
}
|
||||
|
||||
void Player::SpawnCorpseBones()
|
||||
void Player::SpawnCorpseBones(bool triggerSave /*= true*/)
|
||||
{
|
||||
if (sObjectAccessor->ConvertCorpseForPlayer(GetGUID()))
|
||||
if (!GetSession()->PlayerLogoutWithSave()) // at logout we will already store the player
|
||||
SaveToDB(); // prevent loading as ghost without corpse
|
||||
_corpseLocation.WorldRelocate();
|
||||
if (GetMap()->ConvertCorpseToBones(GetGUID()))
|
||||
if (triggerSave && !GetSession()->PlayerLogoutWithSave()) // at logout we will already store the player
|
||||
SaveToDB(); // prevent loading as ghost without corpse
|
||||
}
|
||||
|
||||
Corpse* Player::GetCorpse() const
|
||||
{
|
||||
return sObjectAccessor->GetCorpseForPlayerGUID(GetGUID());
|
||||
return GetMap()->GetCorpseByPlayer(GetGUID());
|
||||
}
|
||||
|
||||
void Player::DurabilityLossAll(double percent, bool inventory)
|
||||
@@ -8580,9 +8592,11 @@ void Player::RemovedInsignia(Player* looterPlr)
|
||||
RepopAtGraveyard();
|
||||
}
|
||||
|
||||
_corpseLocation.WorldRelocate();
|
||||
|
||||
// We have to convert player corpse to bones, not to be able to resurrect there
|
||||
// SpawnCorpseBones isn't handy, 'cos it saves player while he in BG
|
||||
Corpse* bones = sObjectAccessor->ConvertCorpseForPlayer(GetGUID(), true);
|
||||
Corpse* bones = GetMap()->ConvertCorpseToBones(GetGUID(), true);
|
||||
if (!bones)
|
||||
return;
|
||||
|
||||
@@ -17910,18 +17924,24 @@ void Player::_LoadGlyphAuras()
|
||||
}
|
||||
}
|
||||
|
||||
void Player::LoadCorpse()
|
||||
void Player::LoadCorpse(PreparedQueryResult result)
|
||||
{
|
||||
if (IsAlive())
|
||||
sObjectAccessor->ConvertCorpseForPlayer(GetGUID());
|
||||
else
|
||||
if (IsAlive() || HasAtLoginFlag(AT_LOGIN_RESURRECT))
|
||||
SpawnCorpseBones(false);
|
||||
|
||||
if (!IsAlive())
|
||||
{
|
||||
if (Corpse* corpse = GetCorpse())
|
||||
ApplyModFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTE_RELEASE_TIMER, corpse && !sMapStore.LookupEntry(corpse->GetMapId())->Instanceable());
|
||||
if (result && !HasAtLoginFlag(AT_LOGIN_RESURRECT))
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
_corpseLocation.WorldRelocate(fields[0].GetUInt16(), fields[1].GetFloat(), fields[2].GetFloat(), fields[3].GetFloat(), fields[4].GetFloat());
|
||||
ApplyModFlag(PLAYER_FIELD_BYTES, PLAYER_FIELD_BYTE_RELEASE_TIMER, !sMapStore.LookupEntry(_corpseLocation.GetMapId())->Instanceable());
|
||||
}
|
||||
else
|
||||
//Prevent Dead Player login without corpse
|
||||
ResurrectPlayer(0.5f);
|
||||
}
|
||||
|
||||
RemoveAtLoginFlag(AT_LOGIN_RESURRECT);
|
||||
}
|
||||
|
||||
void Player::_LoadInventory(PreparedQueryResult result, uint32 timeDiff)
|
||||
|
||||
@@ -503,15 +503,16 @@ enum PlayerExtraFlags
|
||||
// 2^n values
|
||||
enum AtLoginFlags
|
||||
{
|
||||
AT_LOGIN_NONE = 0x00,
|
||||
AT_LOGIN_RENAME = 0x01,
|
||||
AT_LOGIN_RESET_SPELLS = 0x02,
|
||||
AT_LOGIN_RESET_TALENTS = 0x04,
|
||||
AT_LOGIN_CUSTOMIZE = 0x08,
|
||||
AT_LOGIN_RESET_PET_TALENTS = 0x10,
|
||||
AT_LOGIN_FIRST = 0x20,
|
||||
AT_LOGIN_CHANGE_FACTION = 0x40,
|
||||
AT_LOGIN_CHANGE_RACE = 0x80
|
||||
AT_LOGIN_NONE = 0x000,
|
||||
AT_LOGIN_RENAME = 0x001,
|
||||
AT_LOGIN_RESET_SPELLS = 0x002,
|
||||
AT_LOGIN_RESET_TALENTS = 0x004,
|
||||
AT_LOGIN_CUSTOMIZE = 0x008,
|
||||
AT_LOGIN_RESET_PET_TALENTS = 0x010,
|
||||
AT_LOGIN_FIRST = 0x020,
|
||||
AT_LOGIN_CHANGE_FACTION = 0x040,
|
||||
AT_LOGIN_CHANGE_RACE = 0x080,
|
||||
AT_LOGIN_RESURRECT = 0x100,
|
||||
};
|
||||
|
||||
typedef std::map<uint32, QuestStatusData> QuestStatusMap;
|
||||
@@ -819,6 +820,7 @@ enum PlayerLoginQueryIndex
|
||||
PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES = 30,
|
||||
PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS = 31,
|
||||
PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS = 32,
|
||||
PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION = 33,
|
||||
MAX_PLAYER_LOGIN_QUERY
|
||||
};
|
||||
|
||||
@@ -1343,7 +1345,7 @@ class Player : public Unit, public GridObject<Player>
|
||||
void AddItemDurations(Item* item);
|
||||
void RemoveItemDurations(Item* item);
|
||||
void SendItemDurations();
|
||||
void LoadCorpse();
|
||||
void LoadCorpse(PreparedQueryResult result);
|
||||
void LoadPet();
|
||||
|
||||
bool AddItem(uint32 itemId, uint32 count);
|
||||
@@ -1835,17 +1837,20 @@ class Player : public Unit, public GridObject<Player>
|
||||
bool UpdatePosition(const Position &pos, bool teleport = false) { return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport); }
|
||||
void UpdateUnderwaterState(Map* m, float x, float y, float z) override;
|
||||
|
||||
void SendMessageToSet(WorldPacket* data, bool self) override {SendMessageToSetInRange(data, GetVisibilityRange(), self); }// overwrite Object::SendMessageToSet
|
||||
void SendMessageToSetInRange(WorldPacket* data, float fist, bool self) override;// overwrite Object::SendMessageToSetInRange
|
||||
void SendMessageToSet(WorldPacket* data, bool self) override { SendMessageToSetInRange(data, GetVisibilityRange(), self); }
|
||||
void SendMessageToSetInRange(WorldPacket* data, float dist, bool self) override;
|
||||
void SendMessageToSetInRange(WorldPacket* data, float dist, bool self, bool own_team_only);
|
||||
void SendMessageToSet(WorldPacket* data, Player const* skipped_rcvr) override;
|
||||
|
||||
void SendTeleportAckPacket();
|
||||
|
||||
Corpse* GetCorpse() const;
|
||||
void SpawnCorpseBones();
|
||||
void CreateCorpse();
|
||||
void SpawnCorpseBones(bool triggerSave = true);
|
||||
Corpse* CreateCorpse();
|
||||
void KillPlayer();
|
||||
static void OfflineResurrect(ObjectGuid const& guid, SQLTransaction& trans);
|
||||
bool HasCorpse() const { return _corpseLocation.GetMapId() != MAPID_INVALID; }
|
||||
WorldLocation GetCorpseLocation() const { return _corpseLocation; }
|
||||
uint32 GetResurrectionSpellId();
|
||||
void ResurrectPlayer(float restore_percent, bool applySickness = false);
|
||||
void BuildPlayerRepop();
|
||||
@@ -2624,6 +2629,8 @@ class Player : public Unit, public GridObject<Player>
|
||||
uint32 _pendingBindTimer;
|
||||
|
||||
uint32 _activeCheats;
|
||||
|
||||
WorldLocation _corpseLocation;
|
||||
};
|
||||
|
||||
void AddItemsSetItem(Player* player, Item* item);
|
||||
|
||||
@@ -34,10 +34,6 @@
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
ObjectAccessor::ObjectAccessor() { }
|
||||
|
||||
ObjectAccessor::~ObjectAccessor() { }
|
||||
|
||||
WorldObject* ObjectAccessor::GetWorldObject(WorldObject const& p, ObjectGuid const& guid)
|
||||
{
|
||||
switch (guid.GetHigh())
|
||||
@@ -210,6 +206,11 @@ Player* ObjectAccessor::FindConnectedPlayerByName(std::string const& name)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HashMapHolder<Player>::MapType const& ObjectAccessor::GetPlayers()
|
||||
{
|
||||
return HashMapHolder<Player>::GetContainer();
|
||||
}
|
||||
|
||||
void ObjectAccessor::SaveAllPlayers()
|
||||
{
|
||||
boost::shared_lock<boost::shared_mutex> lock(*HashMapHolder<Player>::GetLock());
|
||||
@@ -219,185 +220,6 @@ void ObjectAccessor::SaveAllPlayers()
|
||||
itr->second->SaveToDB();
|
||||
}
|
||||
|
||||
Corpse* ObjectAccessor::GetCorpseForPlayerGUID(ObjectGuid const& guid)
|
||||
{
|
||||
boost::shared_lock<boost::shared_mutex> lock(_corpseLock);
|
||||
|
||||
Player2CorpsesMapType::iterator iter = i_player2corpse.find(guid);
|
||||
if (iter == i_player2corpse.end())
|
||||
return NULL;
|
||||
|
||||
ASSERT(iter->second->GetType() != CORPSE_BONES);
|
||||
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
void ObjectAccessor::RemoveCorpse(Corpse* corpse)
|
||||
{
|
||||
ASSERT(corpse && corpse->GetType() != CORPSE_BONES);
|
||||
|
||||
boost::upgrade_lock<boost::shared_mutex> lock(_corpseLock);
|
||||
|
||||
/// @todo more works need to be done for corpse and other world object
|
||||
if (Map* map = corpse->FindMap())
|
||||
{
|
||||
corpse->DestroyForNearbyPlayers();
|
||||
if (corpse->IsInGrid())
|
||||
map->RemoveFromMap(corpse, false);
|
||||
else
|
||||
{
|
||||
corpse->RemoveFromWorld();
|
||||
corpse->ResetMap();
|
||||
}
|
||||
}
|
||||
else
|
||||
corpse->RemoveFromWorld();
|
||||
|
||||
// Critical section
|
||||
{
|
||||
boost::upgrade_to_unique_lock<boost::shared_mutex> uniqueLock(lock);
|
||||
|
||||
Player2CorpsesMapType::iterator iter = i_player2corpse.find(corpse->GetOwnerGUID());
|
||||
if (iter == i_player2corpse.end()) /// @todo Fix this
|
||||
return;
|
||||
|
||||
// build mapid*cellid -> guid_set map
|
||||
CellCoord cellCoord = Trinity::ComputeCellCoord(corpse->GetPositionX(), corpse->GetPositionY());
|
||||
sObjectMgr->DeleteCorpseCellData(corpse->GetMapId(), cellCoord.GetId(), corpse->GetOwnerGUID().GetCounter());
|
||||
|
||||
i_player2corpse.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectAccessor::AddCorpse(Corpse* corpse)
|
||||
{
|
||||
ASSERT(corpse && corpse->GetType() != CORPSE_BONES);
|
||||
|
||||
// Critical section
|
||||
{
|
||||
boost::unique_lock<boost::shared_mutex> lock(_corpseLock);
|
||||
|
||||
ASSERT(i_player2corpse.find(corpse->GetOwnerGUID()) == i_player2corpse.end());
|
||||
i_player2corpse[corpse->GetOwnerGUID()] = corpse;
|
||||
|
||||
// build mapid*cellid -> guid_set map
|
||||
CellCoord cellCoord = Trinity::ComputeCellCoord(corpse->GetPositionX(), corpse->GetPositionY());
|
||||
sObjectMgr->AddCorpseCellData(corpse->GetMapId(), cellCoord.GetId(), corpse->GetOwnerGUID().GetCounter(), corpse->GetInstanceId());
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectAccessor::AddCorpsesToGrid(GridCoord const& gridpair, GridType& grid, Map* map)
|
||||
{
|
||||
boost::shared_lock<boost::shared_mutex> lock(_corpseLock);
|
||||
|
||||
for (Player2CorpsesMapType::iterator iter = i_player2corpse.begin(); iter != i_player2corpse.end(); ++iter)
|
||||
{
|
||||
// We need this check otherwise a corpose may be added to a grid twice
|
||||
if (iter->second->IsInGrid())
|
||||
continue;
|
||||
|
||||
if (iter->second->GetGridCoord() == gridpair)
|
||||
{
|
||||
// verify, if the corpse in our instance (add only corpses which are)
|
||||
if (map->Instanceable())
|
||||
{
|
||||
if (iter->second->GetInstanceId() == map->GetInstanceId())
|
||||
grid.AddWorldObject(iter->second);
|
||||
}
|
||||
else
|
||||
grid.AddWorldObject(iter->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Corpse* ObjectAccessor::ConvertCorpseForPlayer(ObjectGuid const& player_guid, bool insignia /*=false*/)
|
||||
{
|
||||
Corpse* corpse = GetCorpseForPlayerGUID(player_guid);
|
||||
if (!corpse)
|
||||
{
|
||||
//in fact this function is called from several places
|
||||
//even when player doesn't have a corpse, not an error
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TC_LOG_DEBUG("misc", "Deleting Corpse and spawned bones.");
|
||||
|
||||
// Map can be NULL
|
||||
Map* map = corpse->FindMap();
|
||||
|
||||
// remove corpse from player_guid -> corpse map and from current map
|
||||
RemoveCorpse(corpse);
|
||||
|
||||
// remove corpse from DB
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
corpse->DeleteFromDB(trans);
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
Corpse* bones = NULL;
|
||||
// create the bones only if the map and the grid is loaded at the corpse's location
|
||||
// ignore bones creating option in case insignia
|
||||
|
||||
if (map && (insignia ||
|
||||
(map->IsBattlegroundOrArena() ? sWorld->getBoolConfig(CONFIG_DEATH_BONES_BG_OR_ARENA) : sWorld->getBoolConfig(CONFIG_DEATH_BONES_WORLD))) &&
|
||||
!map->IsRemovalGrid(corpse->GetPositionX(), corpse->GetPositionY()))
|
||||
{
|
||||
// Create bones, don't change Corpse
|
||||
bones = new Corpse;
|
||||
bones->Create(corpse->GetGUID().GetCounter(), map);
|
||||
|
||||
for (uint8 i = OBJECT_FIELD_TYPE + 1; i < CORPSE_END; ++i) // don't overwrite guid and object type
|
||||
bones->SetUInt32Value(i, corpse->GetUInt32Value(i));
|
||||
|
||||
bones->SetGridCoord(corpse->GetGridCoord());
|
||||
// bones->m_time = m_time; // don't overwrite time
|
||||
// bones->m_type = m_type; // don't overwrite type
|
||||
bones->Relocate(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetOrientation());
|
||||
bones->SetPhaseMask(corpse->GetPhaseMask(), false);
|
||||
|
||||
bones->SetUInt32Value(CORPSE_FIELD_FLAGS, CORPSE_FLAG_UNK2 | CORPSE_FLAG_BONES);
|
||||
bones->SetGuidValue(CORPSE_FIELD_OWNER, ObjectGuid::Empty);
|
||||
|
||||
for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i)
|
||||
{
|
||||
if (corpse->GetUInt32Value(CORPSE_FIELD_ITEM + i))
|
||||
bones->SetUInt32Value(CORPSE_FIELD_ITEM + i, 0);
|
||||
}
|
||||
|
||||
// add bones in grid store if grid loaded where corpse placed
|
||||
map->AddToMap(bones);
|
||||
}
|
||||
|
||||
// all references to the corpse should be removed at this point
|
||||
delete corpse;
|
||||
|
||||
return bones;
|
||||
}
|
||||
|
||||
void ObjectAccessor::RemoveOldCorpses()
|
||||
{
|
||||
time_t now = time(NULL);
|
||||
Player2CorpsesMapType::iterator next;
|
||||
for (Player2CorpsesMapType::iterator itr = i_player2corpse.begin(); itr != i_player2corpse.end(); itr = next)
|
||||
{
|
||||
next = itr;
|
||||
++next;
|
||||
|
||||
if (!itr->second->IsExpired(now))
|
||||
continue;
|
||||
|
||||
ConvertCorpseForPlayer(itr->first);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectAccessor::UnloadAll()
|
||||
{
|
||||
for (Player2CorpsesMapType::const_iterator itr = i_player2corpse.begin(); itr != i_player2corpse.end(); ++itr)
|
||||
{
|
||||
itr->second->RemoveFromWorld();
|
||||
delete itr->second;
|
||||
}
|
||||
}
|
||||
|
||||
/// Define the static members of HashMapHolder
|
||||
|
||||
template <class T> typename HashMapHolder<T>::MapType HashMapHolder<T>::_objectMap;
|
||||
|
||||
@@ -85,85 +85,47 @@ class HashMapHolder
|
||||
static MapType _objectMap;
|
||||
};
|
||||
|
||||
class ObjectAccessor
|
||||
namespace ObjectAccessor
|
||||
{
|
||||
private:
|
||||
ObjectAccessor();
|
||||
~ObjectAccessor();
|
||||
ObjectAccessor(const ObjectAccessor&);
|
||||
ObjectAccessor& operator=(const ObjectAccessor&);
|
||||
// these functions return objects only if in map of specified object
|
||||
WorldObject* GetWorldObject(WorldObject const&, ObjectGuid const&);
|
||||
Object* GetObjectByTypeMask(WorldObject const&, ObjectGuid const&, uint32 typemask);
|
||||
Corpse* GetCorpse(WorldObject const& u, ObjectGuid const& guid);
|
||||
GameObject* GetGameObject(WorldObject const& u, ObjectGuid const& guid);
|
||||
Transport* GetTransport(WorldObject const& u, ObjectGuid const& guid);
|
||||
DynamicObject* GetDynamicObject(WorldObject const& u, ObjectGuid const& guid);
|
||||
Unit* GetUnit(WorldObject const&, ObjectGuid const& guid);
|
||||
Creature* GetCreature(WorldObject const& u, ObjectGuid const& guid);
|
||||
Pet* GetPet(WorldObject const&, ObjectGuid const& guid);
|
||||
Player* GetPlayer(Map const*, ObjectGuid const& guid);
|
||||
Player* GetPlayer(WorldObject const&, ObjectGuid const& guid);
|
||||
Creature* GetCreatureOrPetOrVehicle(WorldObject const&, ObjectGuid const&);
|
||||
|
||||
public:
|
||||
/// @todo: Override these template functions for each holder type and add assertions
|
||||
// these functions return objects if found in whole world
|
||||
// ACCESS LIKE THAT IS NOT THREAD SAFE
|
||||
Player* FindPlayer(ObjectGuid const&);
|
||||
Player* FindPlayerByName(std::string const& name);
|
||||
|
||||
static ObjectAccessor* instance()
|
||||
{
|
||||
static ObjectAccessor instance;
|
||||
return &instance;
|
||||
}
|
||||
// this returns Player even if he is not in world, for example teleporting
|
||||
Player* FindConnectedPlayer(ObjectGuid const&);
|
||||
Player* FindConnectedPlayerByName(std::string const& name);
|
||||
|
||||
// these functions return objects only if in map of specified object
|
||||
static WorldObject* GetWorldObject(WorldObject const&, ObjectGuid const&);
|
||||
static Object* GetObjectByTypeMask(WorldObject const&, ObjectGuid const&, uint32 typemask);
|
||||
static Corpse* GetCorpse(WorldObject const& u, ObjectGuid const& guid);
|
||||
static GameObject* GetGameObject(WorldObject const& u, ObjectGuid const& guid);
|
||||
static Transport* GetTransport(WorldObject const& u, ObjectGuid const& guid);
|
||||
static DynamicObject* GetDynamicObject(WorldObject const& u, ObjectGuid const& guid);
|
||||
static Unit* GetUnit(WorldObject const&, ObjectGuid const& guid);
|
||||
static Creature* GetCreature(WorldObject const& u, ObjectGuid const& guid);
|
||||
static Pet* GetPet(WorldObject const&, ObjectGuid const& guid);
|
||||
static Player* GetPlayer(Map const*, ObjectGuid const& guid);
|
||||
static Player* GetPlayer(WorldObject const&, ObjectGuid const& guid);
|
||||
static Creature* GetCreatureOrPetOrVehicle(WorldObject const&, ObjectGuid const&);
|
||||
// when using this, you must use the hashmapholder's lock
|
||||
HashMapHolder<Player>::MapType const& GetPlayers();
|
||||
|
||||
// these functions return objects if found in whole world
|
||||
// ACCESS LIKE THAT IS NOT THREAD SAFE
|
||||
static Player* FindPlayer(ObjectGuid const&);
|
||||
static Player* FindPlayerByName(std::string const& name);
|
||||
template<class T>
|
||||
void AddObject(T* object)
|
||||
{
|
||||
HashMapHolder<T>::Insert(object);
|
||||
}
|
||||
|
||||
// this returns Player even if he is not in world, for example teleporting
|
||||
static Player* FindConnectedPlayer(ObjectGuid const&);
|
||||
static Player* FindConnectedPlayerByName(std::string const& name);
|
||||
template<class T>
|
||||
void RemoveObject(T* object)
|
||||
{
|
||||
HashMapHolder<T>::Remove(object);
|
||||
}
|
||||
|
||||
// when using this, you must use the hashmapholder's lock
|
||||
static HashMapHolder<Player>::MapType const& GetPlayers()
|
||||
{
|
||||
return HashMapHolder<Player>::GetContainer();
|
||||
}
|
||||
|
||||
template<class T> static void AddObject(T* object)
|
||||
{
|
||||
HashMapHolder<T>::Insert(object);
|
||||
}
|
||||
|
||||
template<class T> static void RemoveObject(T* object)
|
||||
{
|
||||
HashMapHolder<T>::Remove(object);
|
||||
}
|
||||
|
||||
static void SaveAllPlayers();
|
||||
|
||||
//non-static functions
|
||||
|
||||
//Thread safe
|
||||
Corpse* GetCorpseForPlayerGUID(ObjectGuid const& guid);
|
||||
void RemoveCorpse(Corpse* corpse);
|
||||
void AddCorpse(Corpse* corpse);
|
||||
void AddCorpsesToGrid(GridCoord const& gridpair, GridType& grid, Map* map);
|
||||
Corpse* ConvertCorpseForPlayer(ObjectGuid const& player_guid, bool insignia = false);
|
||||
|
||||
//Thread unsafe
|
||||
void RemoveOldCorpses();
|
||||
void UnloadAll();
|
||||
|
||||
private:
|
||||
typedef std::unordered_map<ObjectGuid, Corpse*> Player2CorpsesMapType;
|
||||
typedef std::unordered_map<Player*, UpdateData>::value_type UpdateDataValueType;
|
||||
|
||||
Player2CorpsesMapType i_player2corpse;
|
||||
|
||||
boost::shared_mutex _corpseLock;
|
||||
void SaveAllPlayers();
|
||||
};
|
||||
|
||||
#define sObjectAccessor ObjectAccessor::instance()
|
||||
#endif
|
||||
@@ -7358,20 +7358,6 @@ void ObjectMgr::DeleteGOData(uint32 guid)
|
||||
_gameObjectDataStore.erase(guid);
|
||||
}
|
||||
|
||||
void ObjectMgr::AddCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid, uint32 instance)
|
||||
{
|
||||
// corpses are always added to spawn mode 0 and they are spawned by their instance id
|
||||
CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(mapid, 0)][cellid];
|
||||
cell_guids.corpses[player_guid] = instance;
|
||||
}
|
||||
|
||||
void ObjectMgr::DeleteCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid)
|
||||
{
|
||||
// corpses are always added to spawn mode 0 and they are spawned by their instance id
|
||||
CellObjectGuids& cell_guids = _mapObjectGuidsStore[MAKE_PAIR32(mapid, 0)][cellid];
|
||||
cell_guids.corpses.erase(player_guid);
|
||||
}
|
||||
|
||||
void ObjectMgr::LoadQuestRelationsHelper(QuestRelations& map, QuestRelationsReverse* reverseMap, std::string const& table, bool starter, bool go)
|
||||
{
|
||||
uint32 oldMSTime = getMSTime();
|
||||
@@ -8590,7 +8576,7 @@ void ObjectMgr::LoadScriptNames()
|
||||
|
||||
do
|
||||
{
|
||||
_scriptNamesStore.emplace_back((*result)[0].GetCString());
|
||||
_scriptNamesStore.push_back((*result)[0].GetString());
|
||||
}
|
||||
while (result->NextRow());
|
||||
|
||||
|
||||
@@ -445,13 +445,11 @@ struct BroadcastText
|
||||
|
||||
typedef std::unordered_map<uint32, BroadcastText> BroadcastTextContainer;
|
||||
|
||||
typedef std::set<uint32> CellGuidSet;
|
||||
typedef std::map<uint32/*player guid*/, uint32/*instance*/> CellCorpseSet;
|
||||
typedef std::set<ObjectGuid::LowType> CellGuidSet;
|
||||
struct CellObjectGuids
|
||||
{
|
||||
CellGuidSet creatures;
|
||||
CellGuidSet gameobjects;
|
||||
CellCorpseSet corpses;
|
||||
};
|
||||
typedef std::unordered_map<uint32/*cell_id*/, CellObjectGuids> CellObjectGuidsMap;
|
||||
typedef std::unordered_map<uint32/*(mapid, spawnMode) pair*/, CellObjectGuidsMap> MapObjectGuids;
|
||||
@@ -1219,9 +1217,6 @@ class ObjectMgr
|
||||
LocaleConstant GetDBCLocaleIndex() const { return DBCLocaleIndex; }
|
||||
void SetDBCLocaleIndex(LocaleConstant locale) { DBCLocaleIndex = locale; }
|
||||
|
||||
void AddCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid, uint32 instance);
|
||||
void DeleteCorpseCellData(uint32 mapid, uint32 cellid, uint32 player_guid);
|
||||
|
||||
// grid objects
|
||||
void AddCreatureToGrid(uint32 guid, CreatureData const* data);
|
||||
void RemoveCreatureFromGrid(uint32 guid, CreatureData const* data);
|
||||
|
||||
@@ -62,7 +62,7 @@ class ObjectWorldLoader
|
||||
{
|
||||
public:
|
||||
explicit ObjectWorldLoader(ObjectGridLoader& gloader)
|
||||
: i_cell(gloader.i_cell), i_map(gloader.i_map), i_corpses (0)
|
||||
: i_cell(gloader.i_cell), i_map(gloader.i_map), i_grid(gloader.i_grid), i_corpses(gloader.i_corpses)
|
||||
{ }
|
||||
|
||||
void Visit(CorpseMapType &m);
|
||||
@@ -72,8 +72,9 @@ class ObjectWorldLoader
|
||||
private:
|
||||
Cell i_cell;
|
||||
Map* i_map;
|
||||
NGridType& i_grid;
|
||||
public:
|
||||
uint32 i_corpses;
|
||||
uint32& i_corpses;
|
||||
};
|
||||
|
||||
template<class T> void ObjectGridLoader::SetObjectCell(T* /*obj*/, CellCoord const& /*cellCoord*/) { }
|
||||
@@ -129,38 +130,6 @@ void LoadHelper(CellGuidSet const& guid_set, CellCoord &cell, GridRefManager<T>
|
||||
}
|
||||
}
|
||||
|
||||
void LoadHelper(CellCorpseSet const& cell_corpses, CellCoord &cell, CorpseMapType &m, uint32 &count, Map* map)
|
||||
{
|
||||
if (cell_corpses.empty())
|
||||
return;
|
||||
|
||||
for (CellCorpseSet::const_iterator itr = cell_corpses.begin(); itr != cell_corpses.end(); ++itr)
|
||||
{
|
||||
if (itr->second != map->GetInstanceId())
|
||||
continue;
|
||||
|
||||
ObjectGuid player_guid(HighGuid::Player, itr->first);
|
||||
|
||||
Corpse* obj = sObjectAccessor->GetCorpseForPlayerGUID(player_guid);
|
||||
if (!obj)
|
||||
continue;
|
||||
|
||||
/// @todo this is a hack
|
||||
// corpse's map should be reset when the map is unloaded
|
||||
// but it may still exist when the grid is unloaded but map is not
|
||||
// in that case map == currMap
|
||||
obj->SetMap(map);
|
||||
|
||||
if (obj->IsInGrid())
|
||||
{
|
||||
obj->AddToWorld();
|
||||
continue;
|
||||
}
|
||||
|
||||
AddObjectHelper(cell, m, count, map, obj);
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectGridLoader::Visit(GameObjectMapType &m)
|
||||
{
|
||||
CellCoord cellCoord = i_cell.GetCellCoord();
|
||||
@@ -175,22 +144,28 @@ void ObjectGridLoader::Visit(CreatureMapType &m)
|
||||
LoadHelper(cell_guids.creatures, cellCoord, m, i_creatures, i_map);
|
||||
}
|
||||
|
||||
void ObjectWorldLoader::Visit(CorpseMapType &m)
|
||||
void ObjectWorldLoader::Visit(CorpseMapType& /*m*/)
|
||||
{
|
||||
CellCoord cellCoord = i_cell.GetCellCoord();
|
||||
// corpses are always added to spawn mode 0 and they are spawned by their instance id
|
||||
CellObjectGuids const& cell_guids = sObjectMgr->GetCellObjectGuids(i_map->GetId(), 0, cellCoord.GetId());
|
||||
LoadHelper(cell_guids.corpses, cellCoord, m, i_corpses, i_map);
|
||||
if (std::unordered_set<Corpse*> const* corpses = i_map->GetCorpsesInCell(cellCoord.GetId()))
|
||||
{
|
||||
for (Corpse* corpse : *corpses)
|
||||
{
|
||||
corpse->AddToWorld();
|
||||
i_grid.GetGridType(i_cell.CellX(), i_cell.CellY()).AddWorldObject(corpse);
|
||||
++i_corpses;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectGridLoader::LoadN(void)
|
||||
{
|
||||
i_gameObjects = 0; i_creatures = 0; i_corpses = 0;
|
||||
i_cell.data.Part.cell_y = 0;
|
||||
for (unsigned int x=0; x < MAX_NUMBER_OF_CELLS; ++x)
|
||||
for (uint32 x = 0; x < MAX_NUMBER_OF_CELLS; ++x)
|
||||
{
|
||||
i_cell.data.Part.cell_x = x;
|
||||
for (unsigned int y=0; y < MAX_NUMBER_OF_CELLS; ++y)
|
||||
for (uint32 y = 0; y < MAX_NUMBER_OF_CELLS; ++y)
|
||||
{
|
||||
i_cell.data.Part.cell_y = y;
|
||||
|
||||
@@ -205,7 +180,6 @@ void ObjectGridLoader::LoadN(void)
|
||||
ObjectWorldLoader worker(*this);
|
||||
TypeContainerVisitor<ObjectWorldLoader, WorldTypeMapContainer> visitor(worker);
|
||||
i_grid.VisitGrid(x, y, visitor);
|
||||
i_corpses += worker.i_corpses;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,6 +203,10 @@ bool LoginQueryHolder::Initialize()
|
||||
stmt->setUInt32(0, m_accountId);
|
||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES, stmt);
|
||||
|
||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CORPSE_LOCATION);
|
||||
stmt->setUInt64(0, lowGuid);
|
||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION, stmt);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -892,7 +896,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)
|
||||
pCurrChar->TeleportTo(pCurrChar->m_homebindMapId, pCurrChar->m_homebindX, pCurrChar->m_homebindY, pCurrChar->m_homebindZ, pCurrChar->GetOrientation());
|
||||
}
|
||||
|
||||
sObjectAccessor->AddObject(pCurrChar);
|
||||
ObjectAccessor::AddObject(pCurrChar);
|
||||
//TC_LOG_DEBUG("Player %s added to Map.", pCurrChar->GetName().c_str());
|
||||
|
||||
pCurrChar->SendInitialPacketsAfterAddToMap();
|
||||
@@ -923,7 +927,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)
|
||||
sSocialMgr->SendFriendStatus(pCurrChar, FRIEND_ONLINE, pCurrChar->GetGUID().GetCounter(), true);
|
||||
|
||||
// Place character in world (and load zone) before some object loading
|
||||
pCurrChar->LoadCorpse();
|
||||
pCurrChar->LoadCorpse(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION));
|
||||
|
||||
// setting Ghost+speed if dead
|
||||
if (pCurrChar->m_deathState != ALIVE)
|
||||
@@ -1672,11 +1676,11 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData)
|
||||
}
|
||||
}
|
||||
|
||||
// resurrect the character in case he's dead
|
||||
sObjectAccessor->ConvertCorpseForPlayer(factionChangeInfo.Guid);
|
||||
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
|
||||
// resurrect the character in case he's dead
|
||||
Player::OfflineResurrect(factionChangeInfo.Guid, trans);
|
||||
|
||||
CharacterDatabase.EscapeString(factionChangeInfo.Name);
|
||||
Player::Customize(&factionChangeInfo, trans);
|
||||
|
||||
@@ -1820,6 +1824,7 @@ void WorldSession::HandleCharFactionOrRaceChange(WorldPacket& recvData)
|
||||
trans->Append(stmt);
|
||||
}
|
||||
|
||||
/// @todo: make this part async
|
||||
if (!sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GUILD))
|
||||
{
|
||||
// Reset guild
|
||||
|
||||
@@ -741,7 +741,6 @@ void WorldSession::HandleReclaimCorpseOpcode(WorldPacket& recvData)
|
||||
return;
|
||||
|
||||
Corpse* corpse = _player->GetCorpse();
|
||||
|
||||
if (!corpse)
|
||||
return;
|
||||
|
||||
|
||||
@@ -142,8 +142,8 @@ void WorldSession::HandleMoveWorldportAckOpcode()
|
||||
}
|
||||
|
||||
// resurrect character at enter into instance where his corpse exist after add to map
|
||||
Corpse* corpse = GetPlayer()->GetCorpse();
|
||||
if (corpse && corpse->GetType() != CORPSE_BONES && corpse->GetMapId() == GetPlayer()->GetMapId())
|
||||
Corpse* corpse = GetPlayer()->GetMap()->GetCorpseByPlayer(GetPlayer()->GetGUID());
|
||||
if (corpse && corpse->GetType() != CORPSE_BONES)
|
||||
{
|
||||
if (mEntry->IsDungeon())
|
||||
{
|
||||
|
||||
@@ -403,10 +403,12 @@ void WorldSession::SendSpiritResurrect()
|
||||
|
||||
// get corpse nearest graveyard
|
||||
WorldSafeLocsEntry const* corpseGrave = NULL;
|
||||
Corpse* corpse = _player->GetCorpse();
|
||||
if (corpse)
|
||||
corpseGrave = sObjectMgr->GetClosestGraveYard(
|
||||
corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetMapId(), _player->GetTeam());
|
||||
WorldLocation corpseLocation = _player->GetCorpseLocation();
|
||||
if (_player->HasCorpse())
|
||||
{
|
||||
corpseGrave = sObjectMgr->GetClosestGraveYard(corpseLocation.GetPositionX(), corpseLocation.GetPositionY(),
|
||||
corpseLocation.GetPositionZ(), corpseLocation.GetMapId(), _player->GetTeam());
|
||||
}
|
||||
|
||||
// now can spawn bones
|
||||
_player->SpawnCorpseBones();
|
||||
|
||||
@@ -218,11 +218,7 @@ void WorldSession::HandleGameObjectQueryOpcode(WorldPacket& recvData)
|
||||
|
||||
void WorldSession::HandleCorpseQueryOpcode(WorldPacket & /*recvData*/)
|
||||
{
|
||||
TC_LOG_DEBUG("network", "WORLD: Received MSG_CORPSE_QUERY");
|
||||
|
||||
Corpse* corpse = GetPlayer()->GetCorpse();
|
||||
|
||||
if (!corpse)
|
||||
if (!_player->HasCorpse())
|
||||
{
|
||||
WorldPacket data(MSG_CORPSE_QUERY, 1);
|
||||
data << uint8(0); // corpse not found
|
||||
@@ -230,24 +226,25 @@ void WorldSession::HandleCorpseQueryOpcode(WorldPacket & /*recvData*/)
|
||||
return;
|
||||
}
|
||||
|
||||
uint32 mapid = corpse->GetMapId();
|
||||
float x = corpse->GetPositionX();
|
||||
float y = corpse->GetPositionY();
|
||||
float z = corpse->GetPositionZ();
|
||||
uint32 corpsemapid = mapid;
|
||||
WorldLocation corpseLocation = _player->GetCorpseLocation();
|
||||
uint32 corpseMapID = corpseLocation.GetMapId();
|
||||
uint32 mapID = corpseLocation.GetMapId();
|
||||
float x = corpseLocation.GetPositionX();
|
||||
float y = corpseLocation.GetPositionY();
|
||||
float z = corpseLocation.GetPositionZ();
|
||||
|
||||
// if corpse at different map
|
||||
if (mapid != _player->GetMapId())
|
||||
if (mapID != _player->GetMapId())
|
||||
{
|
||||
// search entrance map for proper show entrance
|
||||
if (MapEntry const* corpseMapEntry = sMapStore.LookupEntry(mapid))
|
||||
if (MapEntry const* corpseMapEntry = sMapStore.LookupEntry(mapID))
|
||||
{
|
||||
if (corpseMapEntry->IsDungeon() && corpseMapEntry->entrance_map >= 0)
|
||||
{
|
||||
// if corpse map have entrance
|
||||
if (Map const* entranceMap = sMapMgr->CreateBaseMap(corpseMapEntry->entrance_map))
|
||||
{
|
||||
mapid = corpseMapEntry->entrance_map;
|
||||
mapID = corpseMapEntry->entrance_map;
|
||||
x = corpseMapEntry->entrance_x;
|
||||
y = corpseMapEntry->entrance_y;
|
||||
z = entranceMap->GetHeight(GetPlayer()->GetPhaseMask(), x, y, MAX_HEIGHT);
|
||||
@@ -258,11 +255,11 @@ void WorldSession::HandleCorpseQueryOpcode(WorldPacket & /*recvData*/)
|
||||
|
||||
WorldPacket data(MSG_CORPSE_QUERY, 1+(6*4));
|
||||
data << uint8(1); // corpse found
|
||||
data << int32(mapid);
|
||||
data << int32(mapID);
|
||||
data << float(x);
|
||||
data << float(y);
|
||||
data << float(z);
|
||||
data << int32(corpsemapid);
|
||||
data << int32(corpseMapID);
|
||||
data << uint32(0); // unknown
|
||||
SendPacket(&data);
|
||||
}
|
||||
|
||||
@@ -50,9 +50,9 @@ GridState* si_GridStates[MAX_GRID_STATE];
|
||||
|
||||
Map::~Map()
|
||||
{
|
||||
sScriptMgr->OnDestroyMap(this);
|
||||
// UnloadAll must be called before deleting the map
|
||||
|
||||
UnloadAll();
|
||||
sScriptMgr->OnDestroyMap(this);
|
||||
|
||||
while (!i_worldObjects.empty())
|
||||
{
|
||||
@@ -400,7 +400,7 @@ void Map::DeleteFromWorld(T* obj)
|
||||
template<>
|
||||
void Map::DeleteFromWorld(Player* player)
|
||||
{
|
||||
sObjectAccessor->RemoveObject(player);
|
||||
ObjectAccessor::RemoveObject(player);
|
||||
RemoveUpdateObject(player); /// @todo I do not know why we need this, it should be removed in ~Object anyway
|
||||
delete player;
|
||||
}
|
||||
@@ -468,8 +468,6 @@ bool Map::EnsureGridLoaded(const Cell &cell)
|
||||
ObjectGridLoader loader(*grid, this, cell);
|
||||
loader.LoadN();
|
||||
|
||||
// Add resurrectable corpses to world object list in grid
|
||||
sObjectAccessor->AddCorpsesToGrid(GridCoord(cell.GridX(), cell.GridY()), grid->GetGridType(cell.CellX(), cell.CellY()), this);
|
||||
Balance();
|
||||
return true;
|
||||
}
|
||||
@@ -507,6 +505,9 @@ bool Map::AddPlayerToMap(Player* player)
|
||||
player->m_clientGUIDs.clear();
|
||||
player->UpdateObjectVisibility(false);
|
||||
|
||||
if (player->IsAlive())
|
||||
ConvertCorpseToBones(player->GetGUID());
|
||||
|
||||
sScriptMgr->OnPlayerEnterMap(this, player);
|
||||
return true;
|
||||
}
|
||||
@@ -2610,7 +2611,7 @@ void Map::SendObjectUpdates()
|
||||
_updateObjects.erase(_updateObjects.begin());
|
||||
obj->BuildUpdate(update_players);
|
||||
}
|
||||
|
||||
|
||||
WorldPacket packet; // here we allocate a std::vector with a size of 0x10000
|
||||
for (UpdateDataMapType::iterator iter = update_players.begin(); iter != update_players.end(); ++iter)
|
||||
{
|
||||
@@ -3530,7 +3531,6 @@ void Map::LoadCorpseData()
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
uint32 count = 0;
|
||||
do
|
||||
{
|
||||
Field* fields = result->Fetch();
|
||||
@@ -3550,8 +3550,8 @@ void Map::LoadCorpseData()
|
||||
continue;
|
||||
}
|
||||
|
||||
sObjectAccessor->AddCorpse(corpse);
|
||||
++count;
|
||||
AddCorpse(corpse);
|
||||
|
||||
} while (result->NextRow());
|
||||
}
|
||||
|
||||
@@ -3564,6 +3564,97 @@ void Map::DeleteCorpseData()
|
||||
CharacterDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
void Map::AddCorpse(Corpse* corpse)
|
||||
{
|
||||
corpse->SetMap(this);
|
||||
|
||||
CellCoord cellCoord = Trinity::ComputeCellCoord(corpse->GetPositionX(), corpse->GetPositionY());
|
||||
_corpsesByCell[cellCoord.GetId()].insert(corpse);
|
||||
_corpsesByPlayer[corpse->GetOwnerGUID()] = corpse;
|
||||
}
|
||||
|
||||
void Map::RemoveCorpse(Corpse* corpse)
|
||||
{
|
||||
ASSERT(corpse && corpse->GetType() != CORPSE_BONES);
|
||||
|
||||
corpse->DestroyForNearbyPlayers();
|
||||
if (corpse->IsInGrid())
|
||||
RemoveFromMap(corpse, false);
|
||||
else
|
||||
{
|
||||
corpse->RemoveFromWorld();
|
||||
corpse->ResetMap();
|
||||
}
|
||||
|
||||
CellCoord cellCoord = Trinity::ComputeCellCoord(corpse->GetPositionX(), corpse->GetPositionY());
|
||||
_corpsesByCell[cellCoord.GetId()].erase(corpse);
|
||||
_corpsesByPlayer.erase(corpse->GetOwnerGUID());
|
||||
}
|
||||
|
||||
Corpse* Map::ConvertCorpseToBones(ObjectGuid const& ownerGuid, bool insignia /*= false*/)
|
||||
{
|
||||
Corpse* corpse = GetCorpseByPlayer(ownerGuid);
|
||||
if (!corpse)
|
||||
return nullptr;
|
||||
|
||||
RemoveCorpse(corpse);
|
||||
|
||||
// remove corpse from DB
|
||||
SQLTransaction trans = CharacterDatabase.BeginTransaction();
|
||||
corpse->DeleteFromDB(trans);
|
||||
CharacterDatabase.CommitTransaction(trans);
|
||||
|
||||
Corpse* bones = NULL;
|
||||
|
||||
// create the bones only if the map and the grid is loaded at the corpse's location
|
||||
// ignore bones creating option in case insignia
|
||||
if ((insignia ||
|
||||
(IsBattlegroundOrArena() ? sWorld->getBoolConfig(CONFIG_DEATH_BONES_BG_OR_ARENA) : sWorld->getBoolConfig(CONFIG_DEATH_BONES_WORLD))) &&
|
||||
!IsRemovalGrid(corpse->GetPositionX(), corpse->GetPositionY()))
|
||||
{
|
||||
// Create bones, don't change Corpse
|
||||
bones = new Corpse();
|
||||
bones->Create(corpse->GetGUID().GetCounter(), this);
|
||||
|
||||
for (uint8 i = OBJECT_FIELD_TYPE + 1; i < CORPSE_END; ++i) // don't overwrite guid and object type
|
||||
bones->SetUInt32Value(i, corpse->GetUInt32Value(i));
|
||||
|
||||
bones->SetGridCoord(corpse->GetGridCoord());
|
||||
bones->Relocate(corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ(), corpse->GetOrientation());
|
||||
bones->SetPhaseMask(corpse->GetPhaseMask(), false);
|
||||
|
||||
bones->SetUInt32Value(CORPSE_FIELD_FLAGS, CORPSE_FLAG_UNK2 | CORPSE_FLAG_BONES);
|
||||
bones->SetGuidValue(CORPSE_FIELD_OWNER, ObjectGuid::Empty);
|
||||
|
||||
for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i)
|
||||
if (corpse->GetUInt32Value(CORPSE_FIELD_ITEM + i))
|
||||
bones->SetUInt32Value(CORPSE_FIELD_ITEM + i, 0);
|
||||
|
||||
// add bones in grid store if grid loaded where corpse placed
|
||||
AddToMap(bones);
|
||||
}
|
||||
|
||||
// all references to the corpse should be removed at this point
|
||||
delete corpse;
|
||||
|
||||
return bones;
|
||||
}
|
||||
|
||||
void Map::RemoveOldCorpses()
|
||||
{
|
||||
time_t now = time(nullptr);
|
||||
|
||||
std::vector<ObjectGuid> corpses;
|
||||
corpses.reserve(_corpsesByPlayer.size());
|
||||
|
||||
for (auto const& p : _corpsesByPlayer)
|
||||
if (p.second->IsExpired(now))
|
||||
corpses.push_back(p.first);
|
||||
|
||||
for (ObjectGuid const& ownerGuid : corpses)
|
||||
ConvertCorpseToBones(ownerGuid);
|
||||
}
|
||||
|
||||
void Map::SendZoneDynamicInfo(Player* player)
|
||||
{
|
||||
uint32 zoneId = GetZoneId(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ());
|
||||
|
||||
@@ -459,6 +459,24 @@ class Map : public GridRefManager<NGridType>
|
||||
typedef std::unordered_multimap<ObjectGuid::LowType, GameObject*> GameObjectBySpawnIdContainer;
|
||||
GameObjectBySpawnIdContainer& GetGameObjectBySpawnIdStore() { return _gameobjectBySpawnIdStore; }
|
||||
|
||||
std::unordered_set<Corpse*> const* GetCorpsesInCell(uint32 cellId) const
|
||||
{
|
||||
auto itr = _corpsesByCell.find(cellId);
|
||||
if (itr != _corpsesByCell.end())
|
||||
return &itr->second;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Corpse* GetCorpseByPlayer(ObjectGuid const& ownerGuid) const
|
||||
{
|
||||
auto itr = _corpsesByPlayer.find(ownerGuid);
|
||||
if (itr != _corpsesByPlayer.end())
|
||||
return itr->second;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MapInstanced* ToMapInstanced() { if (Instanceable()) return reinterpret_cast<MapInstanced*>(this); return NULL; }
|
||||
MapInstanced const* ToMapInstanced() const { if (Instanceable()) return reinterpret_cast<MapInstanced const*>(this); return NULL; }
|
||||
|
||||
@@ -508,6 +526,10 @@ class Map : public GridRefManager<NGridType>
|
||||
|
||||
void LoadCorpseData();
|
||||
void DeleteCorpseData();
|
||||
void AddCorpse(Corpse* corpse);
|
||||
void RemoveCorpse(Corpse* corpse);
|
||||
Corpse* ConvertCorpseToBones(ObjectGuid const& ownerGuid, bool insignia = false);
|
||||
void RemoveOldCorpses();
|
||||
|
||||
static void DeleteRespawnTimesInDB(uint16 mapId, uint32 instanceId);
|
||||
|
||||
@@ -709,6 +731,8 @@ class Map : public GridRefManager<NGridType>
|
||||
MapStoredObjectTypesContainer _objectsStore;
|
||||
CreatureBySpawnIdContainer _creatureBySpawnIdStore;
|
||||
GameObjectBySpawnIdContainer _gameobjectBySpawnIdStore;
|
||||
std::unordered_map<uint32/*cellId*/, std::unordered_set<Corpse*>> _corpsesByCell;
|
||||
std::unordered_map<ObjectGuid, Corpse*> _corpsesByPlayer;
|
||||
|
||||
std::unordered_set<Object*> _updateObjects;
|
||||
};
|
||||
|
||||
@@ -164,10 +164,10 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
|
||||
|
||||
if (!player->IsAlive())
|
||||
{
|
||||
if (Corpse* corpse = player->GetCorpse())
|
||||
if (player->HasCorpse())
|
||||
{
|
||||
// let enter in ghost mode in instance that connected to inner instance with corpse
|
||||
uint32 corpseMap = corpse->GetMapId();
|
||||
uint32 corpseMap = player->GetCorpseLocation().GetMapId();
|
||||
do
|
||||
{
|
||||
if (corpseMap == mapid)
|
||||
@@ -184,9 +184,8 @@ bool MapManager::CanPlayerEnter(uint32 mapid, Player* player, bool loginCheck)
|
||||
TC_LOG_DEBUG("maps", "MAP: Player '%s' does not have a corpse in instance '%s' and cannot enter.", player->GetName().c_str(), mapName);
|
||||
return false;
|
||||
}
|
||||
|
||||
TC_LOG_DEBUG("maps", "MAP: Player '%s' has corpse in instance '%s' and can enter.", player->GetName().c_str(), mapName);
|
||||
player->ResurrectPlayer(0.5f, false);
|
||||
player->SpawnCorpseBones();
|
||||
}
|
||||
else
|
||||
TC_LOG_DEBUG("maps", "Map::CanPlayerEnter - player '%s' is dead but does not have a corpse!", player->GetName().c_str());
|
||||
|
||||
@@ -2150,7 +2150,10 @@ void World::Update(uint32 diff)
|
||||
if (m_timers[WUPDATE_CORPSES].Passed())
|
||||
{
|
||||
m_timers[WUPDATE_CORPSES].Reset();
|
||||
sObjectAccessor->RemoveOldCorpses();
|
||||
sMapMgr->DoForAllMaps([](Map* map)
|
||||
{
|
||||
map->RemoveOldCorpses();
|
||||
});
|
||||
}
|
||||
|
||||
///- Process Game events when necessary
|
||||
@@ -3264,3 +3267,9 @@ void World::ReloadRBAC()
|
||||
if (WorldSession* session = itr->second)
|
||||
session->InvalidateRBACData();
|
||||
}
|
||||
|
||||
void World::RemoveOldCorpses()
|
||||
{
|
||||
m_timers[WUPDATE_CORPSES].SetCurrent(m_timers[WUPDATE_CORPSES].GetInterval());
|
||||
}
|
||||
|
||||
@@ -761,6 +761,8 @@ class World
|
||||
|
||||
void ReloadRBAC();
|
||||
|
||||
void RemoveOldCorpses();
|
||||
|
||||
protected:
|
||||
void _UpdateGameTime();
|
||||
// callback for UpdateRealmCharacters
|
||||
|
||||
@@ -217,7 +217,7 @@ public:
|
||||
{
|
||||
playerName = param3;
|
||||
if (normalizePlayerName(playerName))
|
||||
player = sObjectAccessor->FindPlayerByName(playerName);
|
||||
player = ObjectAccessor::FindPlayerByName(playerName);
|
||||
}
|
||||
|
||||
if (!player)
|
||||
@@ -283,7 +283,7 @@ public:
|
||||
{
|
||||
playerName = param2;
|
||||
if (normalizePlayerName(playerName))
|
||||
player = sObjectAccessor->FindPlayerByName(playerName);
|
||||
player = ObjectAccessor::FindPlayerByName(playerName);
|
||||
}
|
||||
|
||||
if (!player)
|
||||
|
||||
@@ -600,8 +600,10 @@ public:
|
||||
target->SaveToDB();
|
||||
}
|
||||
else
|
||||
// will resurrected at login without corpse
|
||||
sObjectAccessor->ConvertCorpseForPlayer(targetGuid);
|
||||
{
|
||||
SQLTransaction trans(nullptr);
|
||||
Player::OfflineResurrect(targetGuid, trans);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -820,7 +822,7 @@ public:
|
||||
// Save all players in the world
|
||||
static bool HandleSaveAllCommand(ChatHandler* handler, char const* /*args*/)
|
||||
{
|
||||
sObjectAccessor->SaveAllPlayers();
|
||||
ObjectAccessor::SaveAllPlayers();
|
||||
handler->SendSysMessage(LANG_PLAYERS_SAVED);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ public:
|
||||
// Triggering corpses expire check in world
|
||||
static bool HandleServerCorpsesCommand(ChatHandler* /*handler*/, char const* /*args*/)
|
||||
{
|
||||
sObjectAccessor->RemoveOldCorpses();
|
||||
sWorld->RemoveOldCorpses();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -541,7 +541,7 @@ public:
|
||||
case PHASE_PLANT_FIRST_DETONATE: // first explosives detonate finish
|
||||
for (GuidList::iterator itr = _explosivesGuids.begin(); itr != _explosivesGuids.end(); ++itr)
|
||||
{
|
||||
if (GameObject* explosive = sObjectAccessor->GetGameObject(*me, *itr))
|
||||
if (GameObject* explosive = ObjectAccessor::GetGameObject(*me, *itr))
|
||||
me->RemoveGameObject(explosive, true);
|
||||
}
|
||||
_explosivesGuids.clear();
|
||||
@@ -638,7 +638,7 @@ public:
|
||||
case PHASE_PLANT_SECOND_DETONATE: // second explosives detonate finish
|
||||
for (GuidList::iterator itr = _explosivesGuids.begin(); itr != _explosivesGuids.end(); ++itr)
|
||||
{
|
||||
if (GameObject* explosive = sObjectAccessor->GetGameObject(*me, *itr))
|
||||
if (GameObject* explosive = ObjectAccessor::GetGameObject(*me, *itr))
|
||||
me->RemoveGameObject(explosive, true);
|
||||
}
|
||||
_explosivesGuids.clear();
|
||||
|
||||
@@ -256,7 +256,6 @@ extern int main(int argc, char** argv)
|
||||
sInstanceSaveMgr->Unload();
|
||||
sOutdoorPvPMgr->Die();
|
||||
sMapMgr->UnloadAll(); // unload all grids (including locked in memory)
|
||||
sObjectAccessor->UnloadAll(); // unload 'i_player2corpse' storage and remove from world
|
||||
sScriptMgr->Unload();
|
||||
|
||||
// set server offline
|
||||
|
||||
Reference in new issue
Block a user