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:
Shauren committed 2015-09-29 18:45:01 +02:00
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,
+3 -3
View File
@@ -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);
+1 -1
View File
@@ -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
+13 -4
View File
@@ -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
+1
View File
@@ -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); }
+1 -1
View File
@@ -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)
+45 -25
View File
@@ -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)
+21 -14
View File
@@ -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);
+5 -183
View File
@@ -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;
+34 -72
View File
@@ -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
+1 -15
View File
@@ -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());
+1 -6
View File
@@ -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);
+15 -41
View File
@@ -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;
}
}
}
+10 -5
View File
@@ -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
-1
View File
@@ -741,7 +741,6 @@ void WorldSession::HandleReclaimCorpseOpcode(WorldPacket& recvData)
return;
Corpse* corpse = _player->GetCorpse();
if (!corpse)
return;
+2 -2
View File
@@ -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())
{
+6 -4
View File
@@ -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();
+12 -15
View File
@@ -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);
}
+100 -9
View File
@@ -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());
+24
View File
@@ -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;
};
+3 -4
View File
@@ -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());
+10 -1
View File
@@ -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());
}
+2
View File
@@ -761,6 +761,8 @@ class World
void ReloadRBAC();
void RemoveOldCorpses();
protected:
void _UpdateGameTime();
// callback for UpdateRealmCharacters
+2 -2
View File
@@ -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)
+5 -3
View File
@@ -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;
}
+1 -1
View File
@@ -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();
-1
View File
@@ -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