aboutsummaryrefslogtreecommitdiff
path: root/src/server/game
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/game')
-rw-r--r--src/server/game/AI/SmartScripts/SmartAI.cpp6
-rw-r--r--src/server/game/Battlefield/Battlefield.cpp2
-rw-r--r--src/server/game/Battlegrounds/Battleground.cpp9
-rw-r--r--src/server/game/Entities/Corpse/Corpse.cpp17
-rw-r--r--src/server/game/Entities/Corpse/Corpse.h1
-rw-r--r--src/server/game/Entities/Object/Object.cpp2
-rw-r--r--src/server/game/Entities/Player/Player.cpp70
-rw-r--r--src/server/game/Entities/Player/Player.h35
-rw-r--r--src/server/game/Globals/ObjectAccessor.cpp188
-rw-r--r--src/server/game/Globals/ObjectAccessor.h118
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp16
-rw-r--r--src/server/game/Globals/ObjectMgr.h7
-rw-r--r--src/server/game/Grids/ObjectGridLoader.cpp56
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp15
-rw-r--r--src/server/game/Handlers/MiscHandler.cpp1
-rw-r--r--src/server/game/Handlers/MovementHandler.cpp4
-rw-r--r--src/server/game/Handlers/NPCHandler.cpp10
-rw-r--r--src/server/game/Handlers/QueryHandler.cpp27
-rw-r--r--src/server/game/Maps/Map.cpp109
-rw-r--r--src/server/game/Maps/Map.h24
-rw-r--r--src/server/game/Maps/MapManager.cpp7
-rw-r--r--src/server/game/World/World.cpp11
-rw-r--r--src/server/game/World/World.h2
23 files changed, 322 insertions, 415 deletions
diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp
index 1a51bb2d897..7c507ad59b6 100644
--- a/src/server/game/AI/SmartScripts/SmartAI.cpp
+++ b/src/server/game/AI/SmartScripts/SmartAI.cpp
@@ -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);
diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp
index 46181011719..d22ac0ea5d5 100644
--- a/src/server/game/Battlefield/Battlefield.cpp
+++ b/src/server/game/Battlefield/Battlefield.cpp
@@ -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();
diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp
index 2b4d5a4df5e..ad8a7b9e729 100644
--- a/src/server/game/Battlegrounds/Battleground.cpp
+++ b/src/server/game/Battlegrounds/Battleground.cpp
@@ -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
diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp
index 11c0885beef..360cfdf1ae3 100644
--- a/src/server/game/Entities/Corpse/Corpse.cpp
+++ b/src/server/game/Entities/Corpse/Corpse.cpp
@@ -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
diff --git a/src/server/game/Entities/Corpse/Corpse.h b/src/server/game/Entities/Corpse/Corpse.h
index c3a693d30d3..eeb22a064ba 100644
--- a/src/server/game/Entities/Corpse/Corpse.h
+++ b/src/server/game/Entities/Corpse/Corpse.h
@@ -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); }
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp
index f5af3556332..21a65440a55 100644
--- a/src/server/game/Entities/Object/Object.cpp
+++ b/src/server/game/Entities/Object/Object.cpp
@@ -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)
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index b5d3ebaa562..e4452b84da4 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -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)
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 94d0fa5697c..e798f5d98d7 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -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);
diff --git a/src/server/game/Globals/ObjectAccessor.cpp b/src/server/game/Globals/ObjectAccessor.cpp
index f5e9b6bb5b7..ca974ba9a37 100644
--- a/src/server/game/Globals/ObjectAccessor.cpp
+++ b/src/server/game/Globals/ObjectAccessor.cpp
@@ -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;
diff --git a/src/server/game/Globals/ObjectAccessor.h b/src/server/game/Globals/ObjectAccessor.h
index 54e2a7298ef..d5fb8564b96 100644
--- a/src/server/game/Globals/ObjectAccessor.h
+++ b/src/server/game/Globals/ObjectAccessor.h
@@ -85,85 +85,47 @@ class HashMapHolder
static MapType _objectMap;
};
-class ObjectAccessor
+namespace ObjectAccessor
{
- private:
- ObjectAccessor();
- ~ObjectAccessor();
- ObjectAccessor(const ObjectAccessor&);
- ObjectAccessor& operator=(const ObjectAccessor&);
-
- public:
- /// @todo: Override these template functions for each holder type and add assertions
-
- static ObjectAccessor* instance()
- {
- static ObjectAccessor instance;
- return &instance;
- }
-
- // 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&);
-
- // 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);
-
- // 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);
-
- // 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;
+ // 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&);
+
+ // 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);
+
+ // this returns Player even if he is not in world, for example teleporting
+ Player* FindConnectedPlayer(ObjectGuid const&);
+ Player* FindConnectedPlayerByName(std::string const& name);
+
+ // when using this, you must use the hashmapholder's lock
+ HashMapHolder<Player>::MapType const& GetPlayers();
+
+ template<class T>
+ void AddObject(T* object)
+ {
+ HashMapHolder<T>::Insert(object);
+ }
+
+ template<class T>
+ void RemoveObject(T* object)
+ {
+ HashMapHolder<T>::Remove(object);
+ }
+
+ void SaveAllPlayers();
};
-#define sObjectAccessor ObjectAccessor::instance()
#endif
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 4bf86facbef..b5d8d08a6a4 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -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());
diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h
index b9d755636cd..462370001dd 100644
--- a/src/server/game/Globals/ObjectMgr.h
+++ b/src/server/game/Globals/ObjectMgr.h
@@ -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);
diff --git a/src/server/game/Grids/ObjectGridLoader.cpp b/src/server/game/Grids/ObjectGridLoader.cpp
index d0ae90d002f..de0ab490e9c 100644
--- a/src/server/game/Grids/ObjectGridLoader.cpp
+++ b/src/server/game/Grids/ObjectGridLoader.cpp
@@ -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;
}
}
}
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index 61b2837dc10..ba22ab6aa07 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -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
diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp
index 51f7e3f840a..2eebbfc1004 100644
--- a/src/server/game/Handlers/MiscHandler.cpp
+++ b/src/server/game/Handlers/MiscHandler.cpp
@@ -741,7 +741,6 @@ void WorldSession::HandleReclaimCorpseOpcode(WorldPacket& recvData)
return;
Corpse* corpse = _player->GetCorpse();
-
if (!corpse)
return;
diff --git a/src/server/game/Handlers/MovementHandler.cpp b/src/server/game/Handlers/MovementHandler.cpp
index 518baa42e97..84816bf3f33 100644
--- a/src/server/game/Handlers/MovementHandler.cpp
+++ b/src/server/game/Handlers/MovementHandler.cpp
@@ -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())
{
diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp
index 14436a864f9..f8d7f73e077 100644
--- a/src/server/game/Handlers/NPCHandler.cpp
+++ b/src/server/game/Handlers/NPCHandler.cpp
@@ -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();
diff --git a/src/server/game/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp
index 906c3017100..6d896bee26c 100644
--- a/src/server/game/Handlers/QueryHandler.cpp
+++ b/src/server/game/Handlers/QueryHandler.cpp
@@ -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);
}
diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp
index b50099b9787..7acafb3c341 100644
--- a/src/server/game/Maps/Map.cpp
+++ b/src/server/game/Maps/Map.cpp
@@ -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());
diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h
index 9b5e67cdfaf..2ba5e10c82c 100644
--- a/src/server/game/Maps/Map.h
+++ b/src/server/game/Maps/Map.h
@@ -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;
};
diff --git a/src/server/game/Maps/MapManager.cpp b/src/server/game/Maps/MapManager.cpp
index 82be6336dc6..0e7f9dbb611 100644
--- a/src/server/game/Maps/MapManager.cpp
+++ b/src/server/game/Maps/MapManager.cpp
@@ -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());
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index ce1837fbc86..2e61aecfb5f 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -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());
+}
+
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index af89adcb04e..256b856cf73 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -761,6 +761,8 @@ class World
void ReloadRBAC();
+ void RemoveOldCorpses();
+
protected:
void _UpdateGameTime();
// callback for UpdateRealmCharacters