diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp index 6517f8157..d32d951a1 100644 --- a/src/game/AchievementMgr.cpp +++ b/src/game/AchievementMgr.cpp @@ -639,7 +639,7 @@ void AchievementMgr::SendAchievementEarned(AchievementEntry const* achievement) { MaNGOS::AchievementChatBuilder say_builder(*GetPlayer(), CHAT_MSG_ACHIEVEMENT, LANG_ACHIEVEMENT_EARNED,achievement->ID); MaNGOS::LocalizedPacketDo say_do(say_builder); - MaNGOS::PlayerDistWorker > say_worker(GetPlayer(),sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY),say_do); + MaNGOS::CameraDistWorker > say_worker(GetPlayer(),sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY),say_do); Cell::VisitWorldObjects(GetPlayer(), say_worker, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY)); } diff --git a/src/game/Camera.cpp b/src/game/Camera.cpp new file mode 100644 index 000000000..b151ec556 --- /dev/null +++ b/src/game/Camera.cpp @@ -0,0 +1,134 @@ +#include "Camera.h" +#include "GridNotifiersImpl.h" +#include "CellImpl.h" +#include "Log.h" +#include "Errors.h" +#include "Player.h" + +Camera::Camera(Player* pl) : m_owner(*pl), m_source(pl) +{ + m_source->GetViewPoint().Attach(this); +} + +Camera::~Camera() +{ + // view of camera should be already reseted to owner (RemoveFromWorld -> Event_RemovedFromWorld -> ResetView) + ASSERT(m_source == &m_owner); + + // for symmetry with constructor and way to make viewpoint's list empty + m_source->GetViewPoint().Detach(this); +} + +void Camera::ReceivePacket(WorldPacket *data) +{ + m_owner.SendDirectMessage(data); +} + +void Camera::UpdateForCurrentViewPoint() +{ + m_gridRef.unlink(); + + if (GridType* grid = m_source->GetViewPoint().m_grid) + grid->AddWorldObject(this); + + m_owner.SetUInt64Value(PLAYER_FARSIGHT, (m_source == &m_owner ? 0 : m_source->GetGUID())); + UpdateVisibilityForOwner(); +} + +void Camera::SetView(WorldObject *obj) +{ + ASSERT(obj); + + if (!m_owner.IsInMap(obj)) + { + sLog.outError("Camera::SetView, viewpoint is not in map with camera's owner"); + return; + } + + if (!obj->isType(TYPEMASK_DYNAMICOBJECT | TYPEMASK_UNIT)) + { + sLog.outError("Camera::SetView, viewpoint type is not available for client"); + return; + } + + m_source->GetViewPoint().Detach(this); + m_source = obj; + m_source->GetViewPoint().Attach(this); + + UpdateForCurrentViewPoint(); +} + +void Camera::Event_ViewPointVisibilityChanged() +{ + if (!m_owner.HaveAtClient(m_source)) + ResetView(); +} + +void Camera::ResetView() +{ + m_source->GetViewPoint().Detach(this); + m_source = &m_owner; + m_source->GetViewPoint().Attach(this); + + UpdateForCurrentViewPoint(); +} + +void Camera::Event_AddedToWorld() +{ + GridType* grid = m_source->GetViewPoint().m_grid; + ASSERT(grid); + grid->AddWorldObject(this); + + UpdateVisibilityForOwner(); +} + +void Camera::Event_RemovedFromWorld() +{ + if (m_source == &m_owner) + { + m_gridRef.unlink(); + return; + } + + ResetView(); +} + +void Camera::Event_Moved() +{ + m_gridRef.unlink(); + m_source->GetViewPoint().m_grid->AddWorldObject(this); +} + +void Camera::UpdateVisibilityOf(WorldObject* target) +{ + m_owner.UpdateVisibilityOf(m_source, target); +} + +template +void Camera::UpdateVisibilityOf(T * target, UpdateData &data, std::set& vis) +{ + m_owner.template UpdateVisibilityOf(m_source, target,data,vis); +} + +template void Camera::UpdateVisibilityOf(Player* , UpdateData& , std::set& ); +template void Camera::UpdateVisibilityOf(Creature* , UpdateData& , std::set& ); +template void Camera::UpdateVisibilityOf(Corpse* , UpdateData& , std::set& ); +template void Camera::UpdateVisibilityOf(GameObject* , UpdateData& , std::set& ); +template void Camera::UpdateVisibilityOf(DynamicObject* , UpdateData& , std::set& ); + +void Camera::UpdateVisibilityForOwner() +{ + MaNGOS::VisibleNotifier notifier(*this); + Cell::VisitAllObjects(m_source, notifier, m_source->GetMap()->GetVisibilityDistance(), false); + notifier.Notify(); +} + +////////////////// + +ViewPoint::~ViewPoint() +{ + if (!m_cameras.empty()) + { + sLog.outError("ViewPoint destructor called, but some cameras referenced to it"); + } +} diff --git a/src/game/Camera.h b/src/game/Camera.h new file mode 100644 index 000000000..65bd6b88c --- /dev/null +++ b/src/game/Camera.h @@ -0,0 +1,122 @@ + +#ifndef MANGOSSERVER_CAMERA_H +#define MANGOSSERVER_CAMERA_H + +#include "GridDefines.h" + +class ViewPoint; +class WorldObject; +class UpdateData; +class WorldPacket; +class Player; + +/// Camera - object-receiver. Receives broadcast packets from nearby worldobjects, object visibility changes and sends them to client +class MANGOS_DLL_SPEC Camera +{ + friend class ViewPoint; + public: + + explicit Camera(Player* pl); + ~Camera(); + + WorldObject* GetBody() { return m_source;} + Player* GetOwner() { return &m_owner;} + + // set camera's view to any worldobject + // Note: this worldobject must be in same map, in same phase with camera's owner(player) + // client supports only unit and dynamic objects as farsight objects + void SetView(WorldObject *obj); + + // set view to camera's owner + void ResetView(); + + template + void UpdateVisibilityOf(T * obj, UpdateData &d, std::set& vis); + void UpdateVisibilityOf(WorldObject* obj); + + void ReceivePacket(WorldPacket *data); + + // updates visibility of worldobjects around viewpoint for camera's owner + void UpdateVisibilityForOwner(); + + private: + // called when viewpoint changes visibility state + void Event_AddedToWorld(); + void Event_RemovedFromWorld(); + void Event_Moved(); + void Event_ViewPointVisibilityChanged(); + + Player& m_owner; + WorldObject* m_source; + + void UpdateForCurrentViewPoint(); + + public: + GridReference& GetGridRef() { return m_gridRef; } + bool isActiveObject() const { return false; } + private: + GridReference m_gridRef; +}; + +/// Object-observer, notifies farsight object state to cameras that attached to it +class MANGOS_DLL_SPEC ViewPoint +{ + friend class Camera; + + std::list m_cameras; + std::list::iterator m_camera_iter; + GridType * m_grid; + + void Attach(Camera* c) { m_cameras.push_back(c); } + + void Detach(Camera* c) + { + if (m_camera_iter != m_cameras.end() && *m_camera_iter == c) // detach called during the loop + m_camera_iter = m_cameras.erase(m_camera_iter); + else + m_cameras.remove(c); + } + + void CameraCall(void (Camera::*handler)()) + { + if (!m_cameras.empty()) + for(m_camera_iter = m_cameras.begin(); m_camera_iter!=m_cameras.end(); ++m_camera_iter) + ((*m_camera_iter)->*handler)(); + } + +public: + + ViewPoint() : m_grid(0), m_camera_iter(m_cameras.end()) {} + ~ViewPoint(); + + // these events are called when viewpoint changes visibility state + void Event_AddedToWorld(GridType *grid) + { + m_grid = grid; + CameraCall(&Camera::Event_AddedToWorld); + } + + void Event_RemovedFromWorld() + { + m_grid = NULL; + CameraCall(&Camera::Event_RemovedFromWorld); + } + + void Event_GridChanged(GridType *grid) + { + m_grid = grid; + CameraCall(&Camera::Event_Moved); + } + + void Event_ViewPointVisibilityChanged() + { + CameraCall(&Camera::Event_ViewPointVisibilityChanged); + } + + void Call_UpdateVisibilityForOwner() + { + CameraCall(&Camera::UpdateVisibilityForOwner); + } +}; + +#endif diff --git a/src/game/ChatHandler.cpp b/src/game/ChatHandler.cpp index 3e575bb49..405118641 100644 --- a/src/game/ChatHandler.cpp +++ b/src/game/ChatHandler.cpp @@ -574,7 +574,7 @@ void WorldSession::HandleTextEmoteOpcode( WorldPacket & recv_data ) MaNGOS::EmoteChatBuilder emote_builder(*GetPlayer(), text_emote, emoteNum, unit); MaNGOS::LocalizedPacketDo emote_do(emote_builder); - MaNGOS::PlayerDistWorker > emote_worker(GetPlayer(), sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE), emote_do); + MaNGOS::CameraDistWorker > emote_worker(GetPlayer(), sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE), emote_do); Cell::VisitWorldObjects(GetPlayer(), emote_worker, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_TEXTEMOTE)); GetPlayer()->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE, text_emote, 0, unit); diff --git a/src/game/DynamicObject.cpp b/src/game/DynamicObject.cpp index 6a36f6dda..cde2529af 100644 --- a/src/game/DynamicObject.cpp +++ b/src/game/DynamicObject.cpp @@ -50,7 +50,10 @@ void DynamicObject::RemoveFromWorld() { ///- Remove the dynamicObject from the accessor if(IsInWorld()) + { GetMap()->GetObjectsStore().erase(GetGUID(), (DynamicObject*)NULL); + GetViewPoint().Event_RemovedFromWorld(); + } Object::RemoveFromWorld(); } diff --git a/src/game/GridDefines.h b/src/game/GridDefines.h index 0f737decc..da5abba03 100644 --- a/src/game/GridDefines.h +++ b/src/game/GridDefines.h @@ -31,6 +31,7 @@ class DynamicObject; class GameObject; class Pet; class Player; +class Camera; #define MAX_NUMBER_OF_GRIDS 64 @@ -56,10 +57,12 @@ class Player; #define MAP_HALFSIZE (MAP_SIZE/2) // Creature used instead pet to simplify *::Visit templates (not required duplicate code for Creature->Pet case) -typedef TYPELIST_3(Player, Creature/*pets*/, Corpse/*resurrectable*/) AllWorldObjectTypes; +// Cameras in world list just because linked with Player objects +typedef TYPELIST_4(Player, Creature/*pets*/, Corpse/*resurrectable*/, Camera) AllWorldObjectTypes; typedef TYPELIST_4(GameObject, Creature/*except pets*/, DynamicObject, Corpse/*Bones*/) AllGridObjectTypes; typedef TYPELIST_5(Creature, Pet, Vehicle, GameObject, DynamicObject) AllMapStoredObjectTypes; +typedef GridRefManager CameraMapType; typedef GridRefManager CorpseMapType; typedef GridRefManager CreatureMapType; typedef GridRefManager DynamicObjectMapType; diff --git a/src/game/GridNotifiers.cpp b/src/game/GridNotifiers.cpp index 30d977c40..da6aa90ea 100644 --- a/src/game/GridNotifiers.cpp +++ b/src/game/GridNotifiers.cpp @@ -28,32 +28,29 @@ using namespace MaNGOS; void -VisibleChangesNotifier::Visit(PlayerMapType &m) +VisibleChangesNotifier::Visit(CameraMapType &m) { - for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) + for(CameraMapType::iterator iter=m.begin(); iter != m.end(); ++iter) { - Player* player = iter->getSource(); - if(player == &i_object) - continue; - - player->UpdateVisibilityOf(player->GetViewPoint(),&i_object); + iter->getSource()->UpdateVisibilityOf(&i_object); } } void VisibleNotifier::Notify() { + Player& player = *i_camera.GetOwner(); // at this moment i_clientGUIDs have guids that not iterate at grid level checks // but exist one case when this possible and object not out of range: transports - if(Transport* transport = i_player.GetTransport()) + if(Transport* transport = player.GetTransport()) { for(Transport::PlayerSet::const_iterator itr = transport->GetPassengers().begin();itr!=transport->GetPassengers().end();++itr) { - if(i_clientGUIDs.find((*itr)->GetGUID())!=i_clientGUIDs.end()) + if (i_clientGUIDs.find((*itr)->GetGUID()) != i_clientGUIDs.end()) { // ignore far sight case - (*itr)->UpdateVisibilityOf((*itr),&i_player); - i_player.UpdateVisibilityOf(&i_player,(*itr),i_data,i_visibleNow); + (*itr)->UpdateVisibilityOf(*itr, &player); + player.UpdateVisibilityOf(&player, *itr, i_data, i_visibleNow); i_clientGUIDs.erase((*itr)->GetGUID()); } } @@ -63,27 +60,28 @@ VisibleNotifier::Notify() i_data.AddOutOfRangeGUID(i_clientGUIDs); for(ObjectGuidSet::iterator itr = i_clientGUIDs.begin();itr!=i_clientGUIDs.end();++itr) { - i_player.m_clientGUIDs.erase(*itr); + player.m_clientGUIDs.erase(*itr); - DEBUG_FILTER_LOG(LOG_FILTER_VISIBILITY_CHANGES, "%s is out of range (no in active cells set) now for player %u",itr->GetString().c_str(),i_player.GetGUIDLow()); + DEBUG_FILTER_LOG(LOG_FILTER_VISIBILITY_CHANGES, "%s is out of range (no in active cells set) now for %s", + itr->GetString().c_str(), player.GetObjectGuid().GetString().c_str()); } - if( i_data.HasData() ) + if (i_data.HasData()) { // send create/outofrange packet to player (except player create updates that already sent using SendUpdateToPlayer) WorldPacket packet; i_data.BuildPacket(&packet); - i_player.GetSession()->SendPacket(&packet); + player.GetSession()->SendPacket(&packet); // send out of range to other players if need ObjectGuidSet const& oor = i_data.GetOutOfRangeGUIDs(); for(ObjectGuidSet::const_iterator iter = oor.begin(); iter != oor.end(); ++iter) { - if(!iter->IsPlayer()) + if (!iter->IsPlayer()) continue; if (Player* plr = ObjectAccessor::FindPlayer(*iter)) - plr->UpdateVisibilityOf(plr->GetViewPoint(),&i_player); + plr->UpdateVisibilityOf(plr->GetCamera().GetBody(), &player); } } @@ -93,87 +91,92 @@ VisibleNotifier::Notify() for(std::set::const_iterator vItr = i_visibleNow.begin(); vItr != i_visibleNow.end(); ++vItr) { // target aura duration for caster show only if target exist at caster client - if((*vItr)!=&i_player && (*vItr)->isType(TYPEMASK_UNIT)) - i_player.SendAurasForTarget((Unit*)(*vItr)); + if ((*vItr) != &player && (*vItr)->isType(TYPEMASK_UNIT)) + player.SendAurasForTarget((Unit*)(*vItr)); // non finished movements show to player - if((*vItr)->GetTypeId()==TYPEID_UNIT && ((Creature*)(*vItr))->isAlive()) - ((Creature*)(*vItr))->SendMonsterMoveWithSpeedToCurrentDestination(&i_player); + if ((*vItr)->GetTypeId()==TYPEID_UNIT && ((Creature*)(*vItr))->isAlive()) + ((Creature*)(*vItr))->SendMonsterMoveWithSpeedToCurrentDestination(&player); } } void -MessageDeliverer::Visit(PlayerMapType &m) +MessageDeliverer::Visit(CameraMapType &m) { - for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) + for(CameraMapType::iterator iter = m.begin(); iter != m.end(); ++iter) { - if (i_toSelf || iter->getSource() != &i_player) + Player* owner = iter->getSource()->GetOwner(); + + if (i_toSelf || owner != &i_player) { - if (!i_player.InSamePhase(iter->getSource())) + if (!i_player.InSamePhase(iter->getSource()->GetBody())) continue; - if(WorldSession* session = iter->getSource()->GetSession()) + if (WorldSession* session = owner->GetSession()) session->SendPacket(i_message); } } } -void MessageDelivererExcept::Visit(PlayerMapType &m) +void MessageDelivererExcept::Visit(CameraMapType &m) { - for(PlayerMapType::iterator it = m.begin(); it!= m.end(); ++it) + for(CameraMapType::iterator iter = m.begin(); iter != m.end(); ++iter) { - Player* player = it->getSource(); - if(!player->InSamePhase(i_phaseMask) || player == i_skipped_receiver) + Player* owner = iter->getSource()->GetOwner(); + + if (!owner->InSamePhase(i_phaseMask) || owner == i_skipped_receiver) continue; - if (WorldSession* session = player->GetSession()) + if (WorldSession* session = owner->GetSession()) session->SendPacket(i_message); } } void -ObjectMessageDeliverer::Visit(PlayerMapType &m) +ObjectMessageDeliverer::Visit(CameraMapType &m) { - for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) + for(CameraMapType::iterator iter = m.begin(); iter != m.end(); ++iter) { - if(!iter->getSource()->InSamePhase(i_phaseMask)) + if(!iter->getSource()->GetBody()->InSamePhase(i_phaseMask)) continue; - if(WorldSession* session = iter->getSource()->GetSession()) + if(WorldSession* session = iter->getSource()->GetOwner()->GetSession()) session->SendPacket(i_message); } } void -MessageDistDeliverer::Visit(PlayerMapType &m) +MessageDistDeliverer::Visit(CameraMapType &m) { - for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) + for(CameraMapType::iterator iter=m.begin(); iter != m.end(); ++iter) { - if ((i_toSelf || iter->getSource() != &i_player ) && - (!i_ownTeamOnly || iter->getSource()->GetTeam() == i_player.GetTeam() ) && - (!i_dist || iter->getSource()->IsWithinDist(&i_player,i_dist))) + Player * owner = iter->getSource()->GetOwner(); + + if ((i_toSelf || owner != &i_player) && + (!i_ownTeamOnly || owner->GetTeam() == i_player.GetTeam()) && + (!i_dist || iter->getSource()->GetBody()->IsWithinDist(&i_player,i_dist))) { - if (!i_player.InSamePhase(iter->getSource())) + if (!i_player.InSamePhase(iter->getSource()->GetBody())) continue; - if (WorldSession* session = iter->getSource()->GetSession()) + if (WorldSession* session = owner->GetSession()) session->SendPacket(i_message); } } } void -ObjectMessageDistDeliverer::Visit(PlayerMapType &m) +ObjectMessageDistDeliverer::Visit(CameraMapType &m) { - for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) + for(CameraMapType::iterator iter=m.begin(); iter != m.end(); ++iter) { - if (!i_dist || iter->getSource()->IsWithinDist(&i_object,i_dist)) + if (!i_dist || iter->getSource()->GetBody()->IsWithinDist(&i_object,i_dist)) { - if (!i_object.InSamePhase(iter->getSource())) + if (!i_object.InSamePhase(iter->getSource()->GetBody())) continue; - if (WorldSession* session = iter->getSource()->GetSession()) + if (WorldSession* session = iter->getSource()->GetOwner()->GetSession()) session->SendPacket(i_message); } } diff --git a/src/game/GridNotifiers.h b/src/game/GridNotifiers.h index cd7614352..d2449085f 100644 --- a/src/game/GridNotifiers.h +++ b/src/game/GridNotifiers.h @@ -38,13 +38,14 @@ namespace MaNGOS { struct MANGOS_DLL_DECL VisibleNotifier { - Player &i_player; + Camera& i_camera; UpdateData i_data; ObjectGuidSet i_clientGUIDs; std::set i_visibleNow; - explicit VisibleNotifier(Player &player) : i_player(player),i_clientGUIDs(player.m_clientGUIDs) {} + explicit VisibleNotifier(Camera &c) : i_camera(c), i_clientGUIDs(c.GetOwner()->m_clientGUIDs) {} template void Visit(GridRefManager &m); + void Visit(CameraMapType &m) {} void Notify(void); }; @@ -54,7 +55,7 @@ namespace MaNGOS explicit VisibleChangesNotifier(WorldObject &object) : i_object(object) {} template void Visit(GridRefManager &) {} - void Visit(PlayerMapType &); + void Visit(CameraMapType &); }; struct MANGOS_DLL_DECL GridUpdater @@ -82,7 +83,7 @@ namespace MaNGOS WorldPacket *i_message; bool i_toSelf; MessageDeliverer(Player &pl, WorldPacket *msg, bool to_self) : i_player(pl), i_message(msg), i_toSelf(to_self) {} - void Visit(PlayerMapType &m); + void Visit(CameraMapType &m); template void Visit(GridRefManager &) {} }; @@ -95,7 +96,7 @@ namespace MaNGOS MessageDelivererExcept(WorldObject const* obj, WorldPacket *msg, Player const* skipped) : i_phaseMask(obj->GetPhaseMask()), i_message(msg), i_skipped_receiver(skipped) {} - void Visit(PlayerMapType &m); + void Visit(CameraMapType &m); template void Visit(GridRefManager &) {} }; @@ -105,7 +106,7 @@ namespace MaNGOS WorldPacket *i_message; explicit ObjectMessageDeliverer(WorldObject& obj, WorldPacket *msg) : i_phaseMask(obj.GetPhaseMask()), i_message(msg) {} - void Visit(PlayerMapType &m); + void Visit(CameraMapType &m); template void Visit(GridRefManager &) {} }; @@ -119,7 +120,7 @@ namespace MaNGOS MessageDistDeliverer(Player &pl, WorldPacket *msg, float dist, bool to_self, bool ownTeamOnly) : i_player(pl), i_message(msg), i_toSelf(to_self), i_ownTeamOnly(ownTeamOnly), i_dist(dist) {} - void Visit(PlayerMapType &m); + void Visit(CameraMapType &m); template void Visit(GridRefManager &) {} }; @@ -129,7 +130,7 @@ namespace MaNGOS WorldPacket *i_message; float i_dist; ObjectMessageDistDeliverer(WorldObject &obj, WorldPacket *msg, float dist) : i_object(obj), i_message(msg), i_dist(dist) {} - void Visit(PlayerMapType &m); + void Visit(CameraMapType &m); template void Visit(GridRefManager &) {} }; @@ -140,6 +141,7 @@ namespace MaNGOS template void Visit(GridRefManager &m); void Visit(PlayerMapType &) {} void Visit(CorpseMapType &) {} + void Visit(CameraMapType &) {} void Visit(CreatureMapType &); }; @@ -476,22 +478,21 @@ namespace MaNGOS }; template - struct MANGOS_DLL_DECL PlayerDistWorker + struct MANGOS_DLL_DECL CameraDistWorker { WorldObject const* i_searcher; float i_dist; Do& i_do; - PlayerDistWorker(WorldObject const* searcher, float _dist, Do& _do) + CameraDistWorker(WorldObject const* searcher, float _dist, Do& _do) : i_searcher(searcher), i_dist(_dist), i_do(_do) {} - void Visit(PlayerMapType &m) + void Visit(CameraMapType &m) { - for(PlayerMapType::iterator itr=m.begin(); itr != m.end(); ++itr) - if (itr->getSource()->InSamePhase(i_searcher) && itr->getSource()->IsWithinDist(i_searcher,i_dist)) - i_do(itr->getSource()); + for(CameraMapType::iterator itr=m.begin(); itr != m.end(); ++itr) + if (itr->getSource()->GetBody()->InSamePhase(i_searcher) && itr->getSource()->GetBody()->IsWithinDist(i_searcher,i_dist)) + i_do(itr->getSource()->GetOwner()); } - template void Visit(GridRefManager &) {} }; diff --git a/src/game/GridNotifiersImpl.h b/src/game/GridNotifiersImpl.h index 192d52f5d..c32073011 100644 --- a/src/game/GridNotifiersImpl.h +++ b/src/game/GridNotifiersImpl.h @@ -31,11 +31,9 @@ template inline void MaNGOS::VisibleNotifier::Visit(GridRefManager &m) { - WorldObject const* viewPoint = i_player.GetViewPoint(); - for(typename GridRefManager::iterator iter = m.begin(); iter != m.end(); ++iter) { - i_player.UpdateVisibilityOf(viewPoint,iter->getSource(), i_data, i_visibleNow); + i_camera.UpdateVisibilityOf(iter->getSource(), i_data, i_visibleNow); i_clientGUIDs.erase(iter->getSource()->GetGUID()); } } @@ -96,7 +94,7 @@ inline void MaNGOS::PlayerRelocationNotifier::Visit(CreatureMapType &m) if (!i_player.isAlive() || i_player.isInFlight()) return; - WorldObject const* viewPoint = i_player.GetViewPoint(); + WorldObject const* viewPoint = i_player.GetCamera().GetBody(); for(CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter) if (iter->getSource()->isAlive()) @@ -106,13 +104,13 @@ inline void MaNGOS::PlayerRelocationNotifier::Visit(CreatureMapType &m) template<> inline void MaNGOS::CreatureRelocationNotifier::Visit(PlayerMapType &m) { - if(!i_creature.isAlive()) + if (!i_creature.isAlive()) return; for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) if (Player* player = iter->getSource()) if (player->isAlive() && !player->isInFlight()) - PlayerCreatureRelocationWorker(player, player->GetViewPoint(), &i_creature); + PlayerCreatureRelocationWorker(player, player->GetCamera().GetBody(), &i_creature); } template<> diff --git a/src/game/Makefile.am b/src/game/Makefile.am index f4ef7892f..575b4c04b 100644 --- a/src/game/Makefile.am +++ b/src/game/Makefile.am @@ -76,6 +76,8 @@ libmangosgame_a_SOURCES = \ Calendar.cpp \ Calendar.h \ CalendarHandler.cpp \ + Camera.cpp \ + Camera.h \ Cell.h \ CellImpl.h \ Channel.cpp \ diff --git a/src/game/Map.cpp b/src/game/Map.cpp index bca4cca36..83718c71b 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -367,8 +367,9 @@ bool Map::Add(Player *player) SendInitSelf(player); SendInitTransports(player); + NGridType* grid = getNGrid(cell.GridX(), cell.GridY()); + player->GetViewPoint().Event_AddedToWorld(&(*grid)(cell.CellX(), cell.CellY())); UpdateObjectVisibility(player,cell,p); - UpdateObjectsVisibilityFor(player,cell,p); AddNotifier(player,cell,p); return true; @@ -406,6 +407,7 @@ Map::Add(T *obj) DEBUG_LOG("Object %u enters grid[%u,%u]", GUID_LOPART(obj->GetGUID()), cell.GridX(), cell.GridY()); + obj->GetViewPoint().Event_AddedToWorld(&(*grid)(cell.CellX(), cell.CellY())); UpdateObjectVisibility(obj,cell,p); AddNotifier(obj,cell,p); @@ -682,7 +684,6 @@ void Map::Remove(Player *player, bool remove) SendRemoveTransports(player); UpdateObjectVisibility(player,cell,p); - UpdateObjectsVisibilityFor(player,cell,p); player->ResetMap(); if( remove ) @@ -716,10 +717,9 @@ Map::Remove(T *obj, bool remove) else obj->RemoveFromWorld(); + UpdateObjectVisibility(obj,cell,p); // i think will be better to call this function while object still in grid, this changes nothing but logically is better(as for me) RemoveFromGrid(obj,grid,cell); - UpdateObjectVisibility(obj,cell,p); - obj->ResetMap(); if( remove ) { @@ -759,10 +759,13 @@ Map::PlayerRelocation(Player *player, float x, float y, float z, float orientati AddToGrid(player, oldGrid,new_cell); else EnsureGridLoadedAtEnter(new_cell, player); + + NGridType* newGrid = getNGrid(new_cell.GridX(), new_cell.GridY()); + player->GetViewPoint().Event_GridChanged(&(*newGrid)(new_cell.CellX(),new_cell.CellY())); } + player->GetViewPoint().Call_UpdateVisibilityForOwner(); // if move then update what player see and who seen - UpdateObjectsVisibilityFor(player,new_cell,new_val); UpdateObjectVisibility(player, new_cell, new_val); PlayerRelocationNotify(player,new_cell,new_val); @@ -816,6 +819,7 @@ Map::CreatureRelocation(Creature *creature, float x, float y, float z, float ang creature->SetNeedNotify(); } + creature->GetViewPoint().Call_UpdateVisibilityForOwner(); ASSERT(CheckGridIntegrity(creature,true)); } @@ -829,12 +833,12 @@ bool Map::CreatureCellRelocation(Creature *c, Cell new_cell) { DEBUG_FILTER_LOG(LOG_FILTER_CREATURE_MOVES, "Creature (GUID: %u Entry: %u) moved in grid[%u,%u] from cell[%u,%u] to cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.CellX(), new_cell.CellY()); - if( !old_cell.DiffGrid(new_cell) ) - { - RemoveFromGrid(c,getNGrid(old_cell.GridX(), old_cell.GridY()),old_cell); - AddToGrid(c,getNGrid(new_cell.GridX(), new_cell.GridY()),new_cell); - c->SetCurrentCell(new_cell); - } + RemoveFromGrid(c,getNGrid(old_cell.GridX(), old_cell.GridY()),old_cell); + + NGridType* new_grid = getNGrid(new_cell.GridX(), new_cell.GridY()); + AddToGrid(c,new_grid,new_cell); + + c->GetViewPoint().Event_GridChanged( &(*new_grid)(new_cell.CellX(),new_cell.CellY()) ); } else { @@ -852,7 +856,10 @@ bool Map::CreatureCellRelocation(Creature *c, Cell new_cell) DEBUG_FILTER_LOG(LOG_FILTER_CREATURE_MOVES, "Active creature (GUID: %u Entry: %u) moved from grid[%u,%u]cell[%u,%u] to grid[%u,%u]cell[%u,%u].", c->GetGUIDLow(), c->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY()); RemoveFromGrid(c,getNGrid(old_cell.GridX(), old_cell.GridY()),old_cell); - AddToGrid(c,getNGrid(new_cell.GridX(), new_cell.GridY()),new_cell); + + NGridType* new_grid = getNGrid(new_cell.GridX(), new_cell.GridY()); + AddToGrid(c,new_grid,new_cell); + c->GetViewPoint().Event_GridChanged( &(*new_grid)(new_cell.CellX(),new_cell.CellY()) ); return true; } @@ -865,7 +872,9 @@ bool Map::CreatureCellRelocation(Creature *c, Cell new_cell) RemoveFromGrid(c,getNGrid(old_cell.GridX(), old_cell.GridY()),old_cell); { EnsureGridCreated(GridPair(new_cell.GridX(), new_cell.GridY())); - AddToGrid(c,getNGrid(new_cell.GridX(), new_cell.GridY()),new_cell); + NGridType* new_grid = getNGrid(new_cell.GridX(), new_cell.GridY()); + AddToGrid(c,new_grid,new_cell); + c->GetViewPoint().Event_GridChanged( &(*new_grid)(new_cell.CellX(),new_cell.CellY()) ); } return true; @@ -1420,21 +1429,6 @@ void Map::UpdateObjectVisibility( WorldObject* obj, Cell cell, CellPair cellpair cell.Visit(cellpair, player_notifier, *this, *obj, GetVisibilityDistance()); } -void Map::UpdateObjectsVisibilityFor( Player* player, Cell cell, CellPair cellpair ) -{ - MaNGOS::VisibleNotifier notifier(*player); - - cell.data.Part.reserved = ALL_DISTRICT; - //cell.SetNoCreate(); need trigger cell loading around the player - TypeContainerVisitor world_notifier(notifier); - TypeContainerVisitor grid_notifier(notifier); - cell.Visit(cellpair, world_notifier, *this, *player, GetVisibilityDistance()); - cell.Visit(cellpair, grid_notifier, *this, *player, GetVisibilityDistance()); - - // send data - notifier.Notify(); -} - void Map::PlayerRelocationNotify( Player* player, Cell cell, CellPair cellpair ) { MaNGOS::PlayerRelocationNotifier relocationNotifier(*player); diff --git a/src/game/Map.h b/src/game/Map.h index 5193d2c7b..8ba96e803 100644 --- a/src/game/Map.h +++ b/src/game/Map.h @@ -84,6 +84,8 @@ enum LevelRequirementVsMode class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::ObjectLevelLockable { friend class MapReference; + friend class ObjectGridLoader; + friend class ObjectWorldLoader; public: Map(uint32 id, time_t, uint32 InstanceId, uint8 SpawnMode, Map* _parent = NULL); virtual ~Map(); @@ -211,7 +213,6 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj void AddObjectToRemoveList(WorldObject *obj); void UpdateObjectVisibility(WorldObject* obj, Cell cell, CellPair cellpair); - void UpdateObjectsVisibilityFor(Player* player, Cell cell, CellPair cellpair); void resetMarkedCells() { marked_cells.reset(); } bool isCellMarked(uint32 pCellId) { return marked_cells.test(pCellId); } diff --git a/src/game/NPCHandler.cpp b/src/game/NPCHandler.cpp index 95a869d88..749b5161b 100644 --- a/src/game/NPCHandler.cpp +++ b/src/game/NPCHandler.cpp @@ -397,11 +397,17 @@ void WorldSession::SendSpiritResurrect() _player->TeleportTo(corpseGrave->map_id, corpseGrave->x, corpseGrave->y, corpseGrave->z, _player->GetOrientation()); // or update at original position else - _player->UpdateVisibilityForPlayer(); + { + _player->GetCamera().UpdateVisibilityForOwner(); + _player->UpdateObjectVisibility(); + } } // or update at original position else - _player->UpdateVisibilityForPlayer(); + { + _player->GetCamera().UpdateVisibilityForOwner(); + _player->UpdateObjectVisibility(); + } } void WorldSession::HandleBinderActivateOpcode( WorldPacket & recv_data ) diff --git a/src/game/Object.cpp b/src/game/Object.cpp index 55fc2d08a..c78a2e397 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -1496,7 +1496,7 @@ void WorldObject::MonsterSay(int32 textId, uint32 language, uint64 TargetGuid) { MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_SAY, textId,language,TargetGuid); MaNGOS::LocalizedPacketDo say_do(say_build); - MaNGOS::PlayerDistWorker > say_worker(this,sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY),say_do); + MaNGOS::CameraDistWorker > say_worker(this,sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY),say_do); Cell::VisitWorldObjects(this, say_worker, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_SAY)); } @@ -1507,7 +1507,7 @@ void WorldObject::MonsterYell(int32 textId, uint32 language, uint64 TargetGuid) MaNGOS::MonsterChatBuilder say_build(*this, CHAT_MSG_MONSTER_YELL, textId,language,TargetGuid); MaNGOS::LocalizedPacketDo say_do(say_build); - MaNGOS::PlayerDistWorker > say_worker(this,range,say_do); + MaNGOS::CameraDistWorker > say_worker(this,range,say_do); Cell::VisitWorldObjects(this, say_worker, sWorld.getConfig(CONFIG_FLOAT_LISTEN_RANGE_YELL)); } @@ -1530,7 +1530,7 @@ void WorldObject::MonsterTextEmote(int32 textId, uint64 TargetGuid, bool IsBossE MaNGOS::MonsterChatBuilder say_build(*this, IsBossEmote ? CHAT_MSG_RAID_BOSS_EMOTE : CHAT_MSG_MONSTER_EMOTE, textId,LANG_UNIVERSAL,TargetGuid); MaNGOS::LocalizedPacketDo say_do(say_build); - MaNGOS::PlayerDistWorker > say_worker(this,range,say_do); + MaNGOS::CameraDistWorker > say_worker(this,range,say_do); Cell::VisitWorldObjects(this, say_worker, range); } @@ -1864,7 +1864,10 @@ void WorldObject::SetPhaseMask(uint32 newPhaseMask, bool update) m_phaseMask = newPhaseMask; if(update && IsInWorld()) + { UpdateObjectVisibility(); + GetViewPoint().Event_ViewPointVisibilityChanged(); + } } void WorldObject::PlayDistanceSound( uint32 sound_id, Player* target /*= NULL*/ ) @@ -1910,12 +1913,22 @@ struct WorldObjectChangeAccumulator { UpdateDataMapType &i_updateDatas; WorldObject &i_object; - WorldObjectChangeAccumulator(WorldObject &obj, UpdateDataMapType &d) : i_updateDatas(d), i_object(obj) {} - void Visit(PlayerMapType &m) + WorldObjectChangeAccumulator(WorldObject &obj, UpdateDataMapType &d) : i_updateDatas(d), i_object(obj) { - for(PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter) - if(iter->getSource()->HaveAtClient(&i_object)) - i_object.BuildUpdateDataForPlayer(iter->getSource(), i_updateDatas); + // send self fields changes in another way, otherwise + // with new camera system when player's camera too far from player, camera wouldn't receive packets and changes from player + if(i_object.isType(TYPEMASK_PLAYER)) + i_object.BuildUpdateDataForPlayer((Player*)&i_object, i_updateDatas); + } + + void Visit(CameraMapType &m) + { + for(CameraMapType::iterator iter = m.begin(); iter != m.end(); ++iter) + { + Player* owner = iter->getSource()->GetOwner(); + if(owner != &i_object && owner->HaveAtClient(&i_object)) + i_object.BuildUpdateDataForPlayer(owner, i_updateDatas); + } } template void Visit(GridRefManager &) {} diff --git a/src/game/Object.h b/src/game/Object.h index 04c31f0f5..c214a9dd4 100644 --- a/src/game/Object.h +++ b/src/game/Object.h @@ -23,8 +23,8 @@ #include "ByteBuffer.h" #include "UpdateFields.h" #include "UpdateData.h" -#include "GameSystem/GridReference.h" #include "ObjectGuid.h" +#include "Camera.h" #include #include @@ -476,6 +476,8 @@ class MANGOS_DLL_SPEC WorldObject : public Object void BuildUpdateData(UpdateDataMapType &); Creature* SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime); + + ViewPoint& GetViewPoint() { return m_viewPoint; } protected: explicit WorldObject(); @@ -498,6 +500,8 @@ class MANGOS_DLL_SPEC WorldObject : public Object float m_positionY; float m_positionZ; float m_orientation; + + ViewPoint m_viewPoint; }; #endif diff --git a/src/game/ObjectGridLoader.cpp b/src/game/ObjectGridLoader.cpp index 415c7ac6f..8df5d4632 100644 --- a/src/game/ObjectGridLoader.cpp +++ b/src/game/ObjectGridLoader.cpp @@ -25,6 +25,7 @@ #include "Corpse.h" #include "World.h" #include "CellImpl.h" +#include "GridDefines.h" class MANGOS_DLL_DECL ObjectGridRespawnMover { @@ -105,7 +106,7 @@ template<> void addUnitState(Creature *obj, CellPair const& cell_pair) } template -void LoadHelper(CellGuidSet const& guid_set, CellPair &cell, GridRefManager &m, uint32 &count, Map* map) +void LoadHelper(CellGuidSet const& guid_set, CellPair &cell, GridRefManager &m, uint32 &count, Map* map, GridType& grid) { BattleGround* bg = map->IsBattleGroundOrArena() ? ((BattleGroundMap*)map)->GetBG() : NULL; @@ -121,13 +122,16 @@ void LoadHelper(CellGuidSet const& guid_set, CellPair &cell, GridRefManager & continue; } - obj->GetGridRef().link(&m, obj); + grid.AddGridObject(obj); addUnitState(obj,cell); obj->SetMap(map); obj->AddToWorld(); if(obj->isActiveObject()) map->AddToActive(obj); + + obj->GetViewPoint().Event_AddedToWorld(&grid); + if (bg) bg->OnObjectDBLoad(obj); @@ -135,7 +139,7 @@ void LoadHelper(CellGuidSet const& guid_set, CellPair &cell, GridRefManager & } } -void LoadHelper(CellCorpseSet const& cell_corpses, CellPair &cell, CorpseMapType &m, uint32 &count, Map* map) +void LoadHelper(CellCorpseSet const& cell_corpses, CellPair &cell, CorpseMapType &m, uint32 &count, Map* map, GridType& grid) { if(cell_corpses.empty()) return; @@ -151,7 +155,7 @@ void LoadHelper(CellCorpseSet const& cell_corpses, CellPair &cell, CorpseMapType if(!obj) continue; - obj->GetGridRef().link(&m, obj); + grid.AddWorldObject(obj); addUnitState(obj,cell); obj->SetMap(map); @@ -173,7 +177,8 @@ ObjectGridLoader::Visit(GameObjectMapType &m) CellObjectGuids const& cell_guids = sObjectMgr.GetCellObjectGuids(i_map->GetId(), i_map->GetSpawnMode(), cell_id); - LoadHelper(cell_guids.gameobjects, cell_pair, m, i_gameObjects, i_map); + GridType& grid = (*i_map->getNGrid(i_cell.GridX(),i_cell.GridY())) (i_cell.CellX(),i_cell.CellY()); + LoadHelper(cell_guids.gameobjects, cell_pair, m, i_gameObjects, i_map, grid); } void @@ -186,7 +191,8 @@ ObjectGridLoader::Visit(CreatureMapType &m) CellObjectGuids const& cell_guids = sObjectMgr.GetCellObjectGuids(i_map->GetId(), i_map->GetSpawnMode(), cell_id); - LoadHelper(cell_guids.creatures, cell_pair, m, i_creatures, i_map); + GridType& grid = (*i_map->getNGrid(i_cell.GridX(),i_cell.GridY())) (i_cell.CellX(),i_cell.CellY()); + LoadHelper(cell_guids.creatures, cell_pair, m, i_creatures, i_map, grid); } void @@ -199,7 +205,8 @@ ObjectWorldLoader::Visit(CorpseMapType &m) // 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, cell_id); - LoadHelper(cell_guids.corpses, cell_pair, m, i_corpses, i_map); + GridType& grid = (*i_map->getNGrid(i_cell.GridX(),i_cell.GridY())) (i_cell.CellX(),i_cell.CellY()); + LoadHelper(cell_guids.corpses, cell_pair, m, i_corpses, i_map, grid); } void diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 53706be37..39827a33a 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -405,7 +405,7 @@ void TradeData::SetAccepted(bool state, bool crosssend /*= false*/) UpdateMask Player::updateVisualBits; -Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputationMgr(this) +Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputationMgr(this), m_camera(this) { m_transport = 0; @@ -2409,7 +2409,8 @@ void Player::SetGameMaster(bool on) getHostileRefManager().setOnlineOfflineState(true); } - UpdateVisibilityForPlayer(); + m_camera.UpdateVisibilityForOwner(); + UpdateObjectVisibility(); } void Player::SetGMVisible(bool on) @@ -4490,8 +4491,10 @@ void Player::ResurrectPlayer(float restore_percent, bool applySickness) GetZoneAndAreaId(newzone,newarea); UpdateZone(newzone,newarea); - // update visibility - UpdateVisibilityForPlayer(); + // update visibility of world around viewpoint + m_camera.UpdateVisibilityForOwner(); + // update visibility of player for nearby cameras + UpdateObjectVisibility(); if(!applySickness) return; @@ -6073,42 +6076,30 @@ void Player::SaveRecallPosition() void Player::SendMessageToSet(WorldPacket *data, bool self) { - Map * _map = IsInWorld() ? GetMap() : sMapMgr.FindMap(GetMapId(), GetInstanceId()); - if(_map) - { - _map->MessageBroadcast(this, data, self); - return; - } + if (Map * _map = IsInWorld() ? GetMap() : sMapMgr.FindMap(GetMapId(), GetInstanceId())) + _map->MessageBroadcast(this, data, false); //if player is not in world and map in not created/already destroyed //no need to create one, just send packet for itself! - if(self) + if (self) GetSession()->SendPacket(data); } void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self) { - Map * _map = IsInWorld() ? GetMap() : sMapMgr.FindMap(GetMapId(), GetInstanceId()); - if(_map) - { - _map->MessageDistBroadcast(this, data, dist, self); - return; - } + if (Map * _map = IsInWorld() ? GetMap() : sMapMgr.FindMap(GetMapId(), GetInstanceId())) + _map->MessageDistBroadcast(this, data, dist, false); - if(self) + if (self) GetSession()->SendPacket(data); } void Player::SendMessageToSetInRange(WorldPacket *data, float dist, bool self, bool own_team_only) { - Map * _map = IsInWorld() ? GetMap() : sMapMgr.FindMap(GetMapId(), GetInstanceId()); - if(_map) - { - _map->MessageDistBroadcast(this, data, dist, self, own_team_only); - return; - } + if (Map * _map = IsInWorld() ? GetMap() : sMapMgr.FindMap(GetMapId(), GetInstanceId())) + _map->MessageDistBroadcast(this, data, dist, false, own_team_only); - if(self) + if (self) GetSession()->SendPacket(data); } @@ -15322,7 +15313,8 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder ) SetCreatorGUID(0); // reset some aura modifiers before aura apply - SetFarSightGUID(0); + + SetUInt64Value(PLAYER_FARSIGHT, 0); SetUInt32Value(PLAYER_TRACK_CREATURES, 0 ); SetUInt32Value(PLAYER_TRACK_RESOURCES, 0 ); @@ -18058,7 +18050,7 @@ void Player::HandleStealthedUnitsDetection() MaNGOS::UnitListSearcher searcher(this,stealthedUnits, u_check); Cell::VisitAllObjects(this, searcher, MAX_PLAYER_STEALTH_DETECT_RANGE); - WorldObject const* viewPoint = GetViewPoint(); + WorldObject const* viewPoint = GetCamera().GetBody(); for (std::list::const_iterator i = stealthedUnits.begin(); i != stealthedUnits.end(); ++i) { @@ -19154,17 +19146,6 @@ void Player::ReportedAfkBy(Player* reporter) } } -WorldObject const* Player::GetViewPoint() const -{ - if(uint64 far_sight = GetFarSight()) - { - WorldObject const* viewPoint = GetMap()->GetWorldObject(far_sight); - return viewPoint ? viewPoint : this; // always expected not NULL - } - else - return this; -} - bool Player::IsVisibleInGridForPlayer( Player* pl ) const { // gamemaster in GM mode see all, including ghosts @@ -20736,7 +20717,7 @@ void Player::EnterVehicle(Vehicle *vehicle) vehicle->setFaction(getFaction()); SetCharm(vehicle); // charm - SetFarSightGUID(vehicle->GetGUID()); // set view + m_camera.SetView(vehicle); // set view SetClientControl(vehicle, 1); // redirect controls to vehicle SetMover(vehicle); @@ -20788,7 +20769,7 @@ void Player::ExitVehicle(Vehicle *vehicle) vehicle->setFaction((GetTeam() == ALLIANCE) ? vehicle->GetCreatureInfo()->faction_A : vehicle->GetCreatureInfo()->faction_H); SetCharm(NULL); - SetFarSightGUID(0); + m_camera.ResetView(); SetClientControl(vehicle, 0); SetMover(NULL); @@ -22022,38 +22003,6 @@ bool Player::HasMovementFlag( MovementFlags f ) const return m_movementInfo.HasMovementFlag(f); } -void Player::SetFarSightGUID( uint64 guid ) -{ - if(GetFarSight() == guid) - return; - - SetUInt64Value(PLAYER_FARSIGHT, guid); - - // need triggering load grids around new view point - UpdateVisibilityForPlayer(); -} - -void Player::UpdateVisibilityForPlayer() -{ - WorldObject const* viewPoint = GetViewPoint(); - Map* m = GetMap(); - - CellPair p(MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY())); - Cell cell(p); - - m->UpdateObjectVisibility(this, cell, p); - - if (this != viewPoint) - { - CellPair pView(MaNGOS::ComputeCellPair(viewPoint->GetPositionX(), viewPoint->GetPositionY())); - Cell cellView(pView); - - m->UpdateObjectsVisibilityFor(this, cellView, pView); - } - else - m->UpdateObjectsVisibilityFor(this, cell, p); -} - void Player::ResetTimeSync() { m_timeSyncCounter = 0; diff --git a/src/game/Player.h b/src/game/Player.h index bdaa39991..544e7e18a 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1128,8 +1128,6 @@ class MANGOS_DLL_SPEC Player : public Unit Creature* GetNPCIfCanInteractWith(ObjectGuid guid, uint32 npcflagmask); GameObject* GetGameObjectIfCanInteractWith(ObjectGuid guid, uint32 gameobject_type = MAX_GAMEOBJECT_TYPE) const; - void UpdateVisibilityForPlayer(); - bool ToggleAFK(); bool ToggleDND(); bool isAFK() const { return HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK); } @@ -2250,7 +2248,6 @@ class MANGOS_DLL_SPEC Player : public Unit bool HaveAtClient(WorldObject const* u) { return u==this || m_clientGUIDs.find(u->GetGUID())!=m_clientGUIDs.end(); } - WorldObject const* GetViewPoint() const; bool IsVisibleInGridForPlayer(Player* pl) const; bool IsVisibleGloballyFor(Player* pl) const; @@ -2262,6 +2259,8 @@ class MANGOS_DLL_SPEC Player : public Unit // Stealth detection system void HandleStealthedUnitsDetection(); + Camera& GetCamera() { return m_camera; } + uint8 m_forced_speed_changes[MAX_MOVE_TYPE]; bool HasAtLoginFlag(AtLoginFlags f) const { return m_atLoginFlags & f; } @@ -2603,6 +2602,8 @@ class MANGOS_DLL_SPEC Player : public Unit m_DelayedOperations |= operation; } + Camera m_camera; + GridReference m_gridRef; MapReference m_mapRef; diff --git a/src/game/Spell.h b/src/game/Spell.h index cea75be8b..1ec5d7c14 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -808,6 +808,7 @@ namespace MaNGOS template<> inline void Visit(CorpseMapType & ) {} template<> inline void Visit(GameObjectMapType & ) {} template<> inline void Visit(DynamicObjectMapType & ) {} + template<> inline void Visit(CameraMapType & ) {} #endif }; @@ -815,6 +816,7 @@ namespace MaNGOS template<> inline void SpellNotifierCreatureAndPlayer::Visit(CorpseMapType& ) {} template<> inline void SpellNotifierCreatureAndPlayer::Visit(GameObjectMapType& ) {} template<> inline void SpellNotifierCreatureAndPlayer::Visit(DynamicObjectMapType& ) {} + template<> inline void SpellNotifierCreatureAndPlayer::Visit(CameraMapType& ) {} #endif } diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index f6badb486..c199196b9 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -2380,7 +2380,7 @@ void Aura::HandleAuraDummy(bool apply, bool Real) (GetSpellProto()->EffectApplyAuraName[EFFECT_INDEX_0] == 1 || GetSpellProto()->EffectApplyAuraName[EFFECT_INDEX_0] == 128))) { // spells with SpellEffect=72 and aura=4: 6196, 6197, 21171, 21425 - ((Player*)target)->SetFarSightGUID(0); + ((Player*)target)->GetCamera().ResetView(); WorldPacket data(SMSG_CLEAR_FAR_SIGHT_IMMEDIATE, 0); ((Player*)target)->GetSession()->SendPacket(&data); return; @@ -3543,7 +3543,11 @@ void Aura::HandleBindSight(bool apply, bool /*Real*/) if(!caster || caster->GetTypeId() != TYPEID_PLAYER) return; - ((Player*)caster)->SetFarSightGUID(apply ? GetTarget()->GetGUID() : 0); + Camera& camera = ((Player*)caster)->GetCamera(); + if (apply) + camera.SetView(m_target); + else + camera.ResetView(); } void Aura::HandleFarSight(bool apply, bool /*Real*/) @@ -3552,7 +3556,11 @@ void Aura::HandleFarSight(bool apply, bool /*Real*/) if(!caster || caster->GetTypeId() != TYPEID_PLAYER) return; - ((Player*)caster)->SetFarSightGUID(apply ? GetTarget()->GetGUID() : 0); + Camera& camera = ((Player*)caster)->GetCamera(); + if (apply) + camera.SetView(GetTarget()); + else + camera.ResetView(); } void Aura::HandleAuraTrackCreatures(bool apply, bool /*Real*/) @@ -3607,7 +3615,7 @@ void Aura::HandleModPossess(bool apply, bool Real) return; Player* p_caster = (Player*)caster; - + Camera& camera = p_caster->GetCamera(); if( apply ) { @@ -3618,7 +3626,7 @@ void Aura::HandleModPossess(bool apply, bool Real) p_caster->SetCharm(target); - p_caster->SetFarSightGUID(target->GetGUID()); + camera.SetView(target); p_caster->SetClientControl(target, 1); p_caster->SetMover(target); @@ -3646,7 +3654,7 @@ void Aura::HandleModPossess(bool apply, bool Real) p_caster->InterruptSpell(CURRENT_CHANNELED_SPELL); // the spell is not automatically canceled when interrupted, do it now p_caster->SetCharm(NULL); - p_caster->SetFarSightGUID(0); + camera.ResetView(); p_caster->SetClientControl(target, 0); p_caster->SetMover(NULL); @@ -3695,13 +3703,19 @@ void Aura::HandleModPossessPet(bool apply, bool Real) return; Player* p_caster = (Player*)caster; + Camera& camera = p_caster->GetCamera(); if(apply) + { pet->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED); + camera.SetView(pet); + } else + { pet->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED); + camera.ResetView(); + } - p_caster->SetFarSightGUID(apply ? pet->GetGUID() : 0); p_caster->SetCharm(apply ? pet : NULL); p_caster->SetClientControl(pet, apply ? 1 : 0); ((Player*)caster)->SetMover(apply ? pet : NULL); @@ -4182,7 +4196,7 @@ void Aura::HandleInvisibilityDetect(bool apply, bool Real) target->m_detectInvisibilityMask |= (1 << m_modifier.m_miscvalue); } if(Real && target->GetTypeId()==TYPEID_PLAYER) - ((Player*)target)->UpdateVisibilityForPlayer(); + ((Player*)target)->GetCamera().UpdateVisibilityForOwner(); } void Aura::HandleAuraModRoot(bool apply, bool Real) diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index f0c6fcf44..d8f6aac3a 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -4244,7 +4244,8 @@ void Spell::EffectAddFarsight(SpellEffectIndex eff_idx) dynObj->SetUInt32Value(DYNAMICOBJECT_BYTES, 0x80000002); m_caster->AddDynObject(dynObj); m_caster->GetMap()->Add(dynObj); - ((Player*)m_caster)->SetFarSightGUID(dynObj->GetGUID()); + + ((Player*)m_caster)->GetCamera().SetView(dynObj); } void Spell::DoSummonWild(SpellEffectIndex eff_idx, uint32 forceFaction) diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index ae03a34e5..f6a2c5a03 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -10579,10 +10579,6 @@ bool Unit::isVisibleForOrDetect(Unit const* u, WorldObject const* viewPoint, boo return false; } - // always seen by far sight caster - if (u->GetTypeId()==TYPEID_PLAYER && ((Player*)u)->GetFarSight()==GetGUID()) - return true; - // different visible distance checks if (u->isInFlight()) // what see player in flight { @@ -10781,12 +10777,41 @@ void Unit::SetVisibility(UnitVisibility x) if(IsInWorld()) { + // some auras requires visible target + if(m_Visibility == VISIBILITY_GROUP_NO_DETECT || m_Visibility == VISIBILITY_OFF) + { + static const AuraType auratypes[] = {SPELL_AURA_BIND_SIGHT, SPELL_AURA_FAR_SIGHT, SPELL_AURA_NONE}; + for (AuraType const* type = &auratypes[0]; *type != SPELL_AURA_NONE; ++type) + { + AuraList& alist = m_modAuras[*type]; + if(alist.empty()) + continue; + + for (AuraList::iterator it = alist.begin(); it != alist.end();) + { + Aura* aura = (*it); + Unit* owner = aura->GetCaster(); + + if (!owner || !isVisibleForOrDetect(owner,this,false)) + { + alist.erase(it); + RemoveAura(aura); + it = alist.begin(); + } + else + ++it; + } + } + } + Map *m = GetMap(); if(GetTypeId()==TYPEID_PLAYER) m->PlayerRelocation((Player*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); else m->CreatureRelocation((Creature*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); + + GetViewPoint().Event_ViewPointVisibilityChanged(); } } @@ -12039,6 +12064,7 @@ void Unit::RemoveFromWorld() RemoveAllGameObjects(); RemoveAllDynObjects(); CleanupDeletedAuras(); + GetViewPoint().Event_RemovedFromWorld(); } Object::RemoveFromWorld(); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index 5c22b2fa3..926d2dd1d 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "10051" + #define REVISION_NR "10052" #endif // __REVISION_NR_H__ diff --git a/win/VC100/game.vcxproj b/win/VC100/game.vcxproj index 575fef41e..44858d500 100644 --- a/win/VC100/game.vcxproj +++ b/win/VC100/game.vcxproj @@ -370,6 +370,7 @@ + @@ -517,6 +518,7 @@ + diff --git a/win/VC100/game.vcxproj.filters b/win/VC100/game.vcxproj.filters index 44940f527..804e66778 100644 --- a/win/VC100/game.vcxproj.filters +++ b/win/VC100/game.vcxproj.filters @@ -442,6 +442,9 @@ Tool + + Object + @@ -832,5 +835,8 @@ Tool + + Object + \ No newline at end of file diff --git a/win/VC80/game.vcproj b/win/VC80/game.vcproj index 409c26ffa..8f1c431a6 100644 --- a/win/VC80/game.vcproj +++ b/win/VC80/game.vcproj @@ -669,6 +669,14 @@ RelativePath="..\..\src\game\CalendarHandler.cpp" > + + + + diff --git a/win/VC90/game.vcproj b/win/VC90/game.vcproj index b8d61586e..1eb6872bc 100644 --- a/win/VC90/game.vcproj +++ b/win/VC90/game.vcproj @@ -1162,6 +1162,14 @@ RelativePath="..\..\src\game\Calendar.h" > + + + +