diff options
author | Rat <gmstreetrat@gmail.com> | 2015-03-16 07:28:49 +0100 |
---|---|---|
committer | Rat <gmstreetrat@gmail.com> | 2015-03-16 07:28:49 +0100 |
commit | 8f3a80c1cf39978056979a0bcbcb7321e510c101 (patch) | |
tree | fb935f44c86ea9ae84a232f499757b97728e86c4 /src | |
parent | 8366ed5a720047102fc44a7ae89adc8ed83f9076 (diff) |
Core/Phases: Ported new phasing system from 4.3.4 branch and fixed some map swap logic
Diffstat (limited to 'src')
38 files changed, 643 insertions, 297 deletions
diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 6fce1b9f97f..e34b7df0c54 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -416,6 +416,11 @@ bool Condition::Meets(ConditionSourceInfo& sourceInfo) condMeets = creature->GetCreatureTemplate()->type == ConditionValue1; break; } + case CONDITION_TERRAIN_SWAP: + { + condMeets = object->IsInTerrainSwap(ConditionValue1); + break; + } default: condMeets = false; break; @@ -585,6 +590,9 @@ uint32 Condition::GetSearcherTypeMaskForCondition() case CONDITION_CREATURE_TYPE: mask |= GRID_MAP_TYPE_MASK_CREATURE; break; + case CONDITION_TERRAIN_SWAP: + mask |= GRID_MAP_TYPE_MASK_ALL; + break; default: ASSERT(false && "Condition::GetSearcherTypeMaskForCondition - missing condition handling!"); break; @@ -784,7 +792,6 @@ bool ConditionMgr::CanHaveSourceGroupSet(ConditionSourceType sourceType) sourceType == CONDITION_SOURCE_TYPE_SPELL_IMPLICIT_TARGET || sourceType == CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT || sourceType == CONDITION_SOURCE_TYPE_SMART_EVENT || - sourceType == CONDITION_SOURCE_TYPE_PHASE_DEFINITION || sourceType == CONDITION_SOURCE_TYPE_NPC_VENDOR); } @@ -860,22 +867,6 @@ ConditionList ConditionMgr::GetConditionsForSmartEvent(int64 entryOrGuid, uint32 return cond; } -ConditionList const* ConditionMgr::GetConditionsForPhaseDefinition(uint32 zone, uint32 entry) -{ - PhaseDefinitionConditionContainer::const_iterator itr = PhaseDefinitionsConditionStore.find(zone); - if (itr != PhaseDefinitionsConditionStore.end()) - { - ConditionTypeContainer::const_iterator i = itr->second.find(entry); - if (i != itr->second.end()) - { - TC_LOG_DEBUG("condition", "GetConditionsForPhaseDefinition: found conditions for zone %u entry %u", zone, entry); - return &i->second; - } - } - - return NULL; -} - ConditionList ConditionMgr::GetConditionsForNpcVendorEvent(uint32 creatureId, uint32 itemId) { ConditionList cond; @@ -1115,13 +1106,6 @@ void ConditionMgr::LoadConditions(bool isReload) ++count; continue; } - case CONDITION_SOURCE_TYPE_PHASE_DEFINITION: - { - PhaseDefinitionsConditionStore[cond->SourceGroup][cond->SourceEntry].push_back(cond); - valid = true; - ++count; - continue; - } case CONDITION_SOURCE_TYPE_NPC_VENDOR: { NpcVendorConditionContainerStore[cond->SourceGroup][cond->SourceEntry].push_back(cond); @@ -1650,13 +1634,6 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) return false; } break; - case CONDITION_SOURCE_TYPE_PHASE_DEFINITION: - /*if (!PhaseMgr::IsConditionTypeSupported(cond->ConditionType)) - { - TC_LOG_ERROR("sql.sql", "Condition source type `CONDITION_SOURCE_TYPE_PHASE_DEFINITION` does not support condition type %u, ignoring.", cond->ConditionType); - return false; - }*/ - break; case CONDITION_SOURCE_TYPE_NPC_VENDOR: { if (!sObjectMgr->GetCreatureTemplate(cond->SourceGroup)) @@ -1676,6 +1653,8 @@ bool ConditionMgr::isSourceTypeValid(Condition* cond) case CONDITION_SOURCE_TYPE_GOSSIP_MENU_OPTION: case CONDITION_SOURCE_TYPE_SMART_EVENT: case CONDITION_SOURCE_TYPE_NONE: + case CONDITION_SOURCE_TYPE_TERRAIN_SWAP: + case CONDITION_SOURCE_TYPE_PHASE: default: break; } @@ -2075,6 +2054,14 @@ bool ConditionMgr::isConditionTypeValid(Condition* cond) } break; } + case CONDITION_TERRAIN_SWAP: + { + if (cond->ConditionValue2) + TC_LOG_ERROR("sql.sql", "Terrain swap condition has useless data in value2 (%u)!", cond->ConditionValue2); + if (cond->ConditionValue3) + TC_LOG_ERROR("sql.sql", "Terrain swap condition has useless data in value3 (%u)!", cond->ConditionValue3); + break; + } case CONDITION_TITLE: { CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(cond->ConditionValue1); @@ -2198,19 +2185,6 @@ void ConditionMgr::Clean() SpellClickEventConditionStore.clear(); - for (PhaseDefinitionConditionContainer::iterator itr = PhaseDefinitionsConditionStore.begin(); itr != PhaseDefinitionsConditionStore.end(); ++itr) - { - for (ConditionTypeContainer::iterator it = itr->second.begin(); it != itr->second.end(); ++it) - { - for (ConditionList::const_iterator i = it->second.begin(); i != it->second.end(); ++i) - delete *i; - it->second.clear(); - } - itr->second.clear(); - } - - PhaseDefinitionsConditionStore.clear(); - for (NpcVendorConditionContainer::iterator itr = NpcVendorConditionContainerStore.begin(); itr != NpcVendorConditionContainerStore.end(); ++itr) { for (ConditionTypeContainer::iterator it = itr->second.begin(); it != itr->second.end(); ++it) diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index aa9ad9963d9..71da857fd29 100644 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -72,7 +72,8 @@ enum ConditionTypes CONDITION_ALIVE = 36, // 0 0 0 true if unit is alive CONDITION_HP_VAL = 37, // hpVal ComparisonType 0 true if unit's hp matches given value CONDITION_HP_PCT = 38, // hpPct ComparisonType 0 true if unit's hp matches given pct - CONDITION_MAX = 39 // MAX + CONDITION_TERRAIN_SWAP = 39, // terrainSwap 0 0 true if object is in terrainswap + CONDITION_MAX = 40 // MAX }; /*! Documentation on implementing a new ConditionSourceType: @@ -129,8 +130,9 @@ enum ConditionSourceType CONDITION_SOURCE_TYPE_SMART_EVENT = 22, CONDITION_SOURCE_TYPE_NPC_VENDOR = 23, CONDITION_SOURCE_TYPE_SPELL_PROC = 24, - CONDITION_SOURCE_TYPE_PHASE_DEFINITION = 25, // only 4.3.4 - CONDITION_SOURCE_TYPE_MAX = 26 // MAX + CONDITION_SOURCE_TYPE_TERRAIN_SWAP = 25, + CONDITION_SOURCE_TYPE_PHASE = 26, + CONDITION_SOURCE_TYPE_MAX = 27 // MAX }; enum RelationType @@ -221,7 +223,6 @@ typedef std::map<ConditionSourceType, ConditionTypeContainer> ConditionContainer typedef std::map<uint32, ConditionTypeContainer> CreatureSpellConditionContainer; typedef std::map<uint32, ConditionTypeContainer> NpcVendorConditionContainer; typedef std::map<std::pair<int32, uint32 /*SAI source_type*/>, ConditionTypeContainer> SmartEventConditionContainer; -typedef std::map<int32 /*zoneId*/, ConditionTypeContainer> PhaseDefinitionConditionContainer; typedef std::map<uint32, ConditionList> ConditionReferenceContainer;//only used for references @@ -252,7 +253,6 @@ class ConditionMgr ConditionList GetConditionsForSpellClickEvent(uint32 creatureId, uint32 spellId); ConditionList GetConditionsForSmartEvent(int64 entryOrGuid, uint32 eventId, uint32 sourceType); ConditionList GetConditionsForVehicleSpell(uint32 creatureId, uint32 spellId); - ConditionList const* GetConditionsForPhaseDefinition(uint32 zone, uint32 entry); ConditionList GetConditionsForNpcVendorEvent(uint32 creatureId, uint32 itemId); struct ConditionTypeInfo @@ -284,7 +284,6 @@ class ConditionMgr CreatureSpellConditionContainer SpellClickEventConditionStore; NpcVendorConditionContainer NpcVendorConditionContainerStore; SmartEventConditionContainer SmartEventConditionStore; - PhaseDefinitionConditionContainer PhaseDefinitionsConditionStore; }; #define sConditionMgr ConditionMgr::instance() diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp index 67c245ac04b..8850392a13e 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp +++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp @@ -78,8 +78,7 @@ bool AreaTrigger::CreateAreaTrigger(ObjectGuid::LowType guidlow, uint32 triggerE SetUInt32Value(AREATRIGGER_SPELLVISUALID, spell->SpellVisual[0]); SetUInt32Value(AREATRIGGER_DURATION, spell->GetDuration()); - for (auto phase : caster->GetPhases()) - SetInPhase(phase, false, true); + CopyPhaseFrom(caster); if (!GetMap()->AddToMap(this)) return false; diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp index 99cbd75cb29..6be200b8887 100644 --- a/src/server/game/Entities/Corpse/Corpse.cpp +++ b/src/server/game/Entities/Corpse/Corpse.cpp @@ -94,6 +94,8 @@ bool Corpse::Create(ObjectGuid::LowType guidlow, Player* owner) _gridCoord = Trinity::ComputeGridCoord(GetPositionX(), GetPositionY()); + CopyPhaseFrom(owner); + return true; } @@ -121,9 +123,20 @@ void Corpse::SaveToDB() stmt->setUInt32(index++, uint32(m_time)); // time stmt->setUInt8 (index++, GetType()); // corpseType stmt->setUInt32(index++, GetInstanceId()); // instanceId - stmt->setUInt32(index++, GetPhaseMask()); // phaseMask trans->Append(stmt); + for (uint32 phaseId : GetPhases()) + { + index = 0; + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CORPSE_PHASES); + stmt->setUInt32(index++, GetGUID().GetCounter()); // Guid (corpse's) + stmt->setUInt32(index++, phaseId); // PhaseId + stmt->setUInt32(index++, GetOwnerGUID().GetCounter()); // OwnerGuid + stmt->setUInt32(index++, uint32(m_time)); // Time + stmt->setUInt8(index++, GetType()); // CorpseType + trans->Append(stmt); + } + CharacterDatabase.CommitTransaction(trans); } @@ -148,21 +161,31 @@ void Corpse::DeleteFromDB(SQLTransaction& trans) { // Only specific bones stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CORPSE); - stmt->setUInt64(0, GetGUID().GetCounter()); + stmt->setUInt32(0, GetGUID().GetCounter()); + trans->Append(stmt); + + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CORPSE_PHASES); + stmt->setUInt32(0, GetGUID().GetCounter()); + trans->Append(stmt); } else { // all corpses (not bones) stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_CORPSES); - stmt->setUInt64(0, GetOwnerGUID().GetCounter()); + stmt->setUInt32(0, GetOwnerGUID().GetCounter()); + trans->Append(stmt); + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_CORPSES_PHASES); + stmt->setUInt32(0, GetOwnerGUID().GetCounter()); + trans->Append(stmt); } - trans->Append(stmt); } bool Corpse::LoadCorpseFromDB(ObjectGuid::LowType guid, Field* fields) { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - // SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId, phaseMask, corpseGuid, guid FROM corpse WHERE corpseType <> 0 + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + // SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId, corpseGuid, guid FROM corpse WHERE corpseType <> 0 float posX = fields[0].GetFloat(); float posY = fields[1].GetFloat(); @@ -178,12 +201,11 @@ bool Corpse::LoadCorpseFromDB(ObjectGuid::LowType guid, Field* fields) SetUInt32Value(CORPSE_FIELD_BYTES_2, fields[8].GetUInt32()); SetUInt32Value(CORPSE_FIELD_FLAGS, fields[9].GetUInt8()); SetUInt32Value(CORPSE_FIELD_DYNAMIC_FLAGS, fields[10].GetUInt8()); - SetGuidValue(CORPSE_FIELD_OWNER, ObjectGuid::Create<HighGuid::Player>(fields[16].GetUInt64())); + SetGuidValue(CORPSE_FIELD_OWNER, ObjectGuid::Create<HighGuid::Player>(fields[15].GetUInt64())); m_time = time_t(fields[11].GetUInt32()); uint32 instanceId = fields[13].GetUInt32(); - //uint32 phaseMask = fields[14].GetUInt32(); // place SetLocationInstanceId(instanceId); diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index f5c7b42292e..dd5ab7fe9d1 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -1011,6 +1011,9 @@ void Creature::SaveToDB(uint32 mapid, uint32 spawnMask, uint32 phaseMask) data.npcflag = npcflag; data.unit_flags = unit_flags; data.dynamicflags = dynamicflags; + + data.phaseid = GetDBPhase() > 0 ? GetDBPhase() : 0; + data.phaseGroup = GetDBPhase() < 0 ? abs(GetDBPhase()) : 0; // update in DB SQLTransaction trans = WorldDatabase.BeginTransaction(); @@ -1027,6 +1030,8 @@ void Creature::SaveToDB(uint32 mapid, uint32 spawnMask, uint32 phaseMask) stmt->setUInt16(index++, uint16(mapid)); stmt->setUInt32(index++, spawnMask); stmt->setUInt32(index++, GetPhaseMask()); + stmt->setUInt32(index++, data.phaseid); + stmt->setUInt32(index++, data.phaseGroup); stmt->setUInt32(index++, displayId); stmt->setUInt8(index++, GetCurrentEquipmentId()); stmt->setFloat(index++, GetPositionX()); diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index bb4bed9f79a..2a6f5ae7df8 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -2163,11 +2163,13 @@ void GameObject::SetDisplayId(uint32 displayid) UpdateModel(); } -void GameObject::SetInPhase(uint32 id, bool update, bool apply) +bool GameObject::SetInPhase(uint32 id, bool update, bool apply) { - WorldObject::SetInPhase(id, update, apply); + bool res = WorldObject::SetInPhase(id, update, apply); if (m_model && m_model->isEnabled()) EnableCollision(true); + + return res; } void GameObject::EnableCollision(bool enable) diff --git a/src/server/game/Entities/GameObject/GameObject.h b/src/server/game/Entities/GameObject/GameObject.h index d5d53df48c1..63a4ece8aef 100644 --- a/src/server/game/Entities/GameObject/GameObject.h +++ b/src/server/game/Entities/GameObject/GameObject.h @@ -949,7 +949,7 @@ class GameObject : public WorldObject, public GridObject<GameObject>, public Map void SetGoAnimProgress(uint8 animprogress) { SetByteValue(GAMEOBJECT_BYTES_1, 3, animprogress); } static void SetGoArtKit(uint8 artkit, GameObject* go, ObjectGuid::LowType lowguid = UI64LIT(0)); - void SetInPhase(uint32 id, bool update, bool apply); + bool SetInPhase(uint32 id, bool update, bool apply); void EnableCollision(bool enable); void Use(Unit* user); diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index cb504f6cb19..953d3b9d596 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1557,7 +1557,7 @@ void MovementInfo::OutDebug() WorldObject::WorldObject(bool isWorldObject) : WorldLocation(), LastUsedScriptID(0), m_name(""), m_isActive(false), m_isWorldObject(isWorldObject), m_zoneScript(NULL), m_transport(NULL), m_currMap(NULL), m_InstanceId(0), -m_phaseMask(PHASEMASK_NORMAL), m_notifyflags(0), m_executed_notifies(0) +m_phaseMask(PHASEMASK_NORMAL), _dbPhase(0), m_notifyflags(0), m_executed_notifies(0) { m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE | GHOST_VISIBILITY_GHOST); m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); @@ -2463,10 +2463,6 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert } } - std::set<uint32> phases; - if (summoner) - phases = summoner->GetPhases(); - TempSummon* summon = NULL; switch (mask) { @@ -2494,8 +2490,7 @@ TempSummon* Map::SummonCreature(uint32 entry, Position const& pos, SummonPropert } // Set the summon to the summoner's phase - for (auto phaseId : phases) - summon->SetInPhase(phaseId, false, true); + summon->CopyPhaseFrom(summoner); summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, spellId); @@ -2591,8 +2586,7 @@ GameObject* WorldObject::SummonGameObject(uint32 entry, float x, float y, float return NULL; } - for (auto phase : GetPhases()) - go->SetInPhase(phase, false, true); + go->CopyPhaseFrom(this); go->SetRespawnTime(respawnTime); if (GetTypeId() == TYPEID_PLAYER || GetTypeId() == TYPEID_UNIT) //not sure how to handle this @@ -3003,12 +2997,138 @@ void WorldObject::SetPhaseMask(uint32 newPhaseMask, bool update) UpdateObjectVisibility(); } -void WorldObject::SetInPhase(uint32 id, bool update, bool apply) +bool WorldObject::HasInPhaseList(uint32 phase) { - if (apply) - _phases.insert(id); - else - _phases.erase(id); + return _phases.find(phase) != _phases.end(); +} + +// Updates Area based phases, does not remove phases from auras +// Phases from gm commands are not taken into calculations, they can be lost!! +void WorldObject::UpdateAreaPhase() +{ + bool updateNeeded = false; + PhaseInfo phases = sObjectMgr->GetAreaPhases(); + for (PhaseInfo::const_iterator itr = phases.begin(); itr != phases.end(); ++itr) + { + uint32 areaId = itr->first; + for (uint32 phaseId : itr->second) + { + if (areaId == GetAreaId()) + { + ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_PHASE, phaseId); + if (sConditionMgr->IsObjectMeetToConditions(this, conditions)) + { + // add new phase if condition passed, true if it wasnt added before + bool up = SetInPhase(phaseId, false, true); + if (!updateNeeded && up) + updateNeeded = true; + } + else + { + // condition failed, remove phase, true if there was something removed + bool up = SetInPhase(phaseId, false, false); + if (!updateNeeded && up) + updateNeeded = true; + } + } + else + { + // not in area, remove phase, true if there was something removed + bool up = SetInPhase(phaseId, false, false); + if (!updateNeeded && up) + updateNeeded = true; + } + } + } + + // do not remove a phase if it would be removed by an area but we have the same phase from an aura + if (Unit* unit = ToUnit()) + { + Unit::AuraEffectList const& auraPhaseList = unit->GetAuraEffectsByType(SPELL_AURA_PHASE); + for (Unit::AuraEffectList::const_iterator itr = auraPhaseList.begin(); itr != auraPhaseList.end(); ++itr) + { + uint32 phase = uint32((*itr)->GetMiscValueB()); + bool up = SetInPhase(phase, false, true); + if (!updateNeeded && up) + updateNeeded = true; + } + Unit::AuraEffectList const& auraPhaseGroupList = unit->GetAuraEffectsByType(SPELL_AURA_PHASE_GROUP); + for (Unit::AuraEffectList::const_iterator itr = auraPhaseGroupList.begin(); itr != auraPhaseGroupList.end(); ++itr) + { + bool up = false; + uint32 phaseGroup = uint32((*itr)->GetMiscValueB()); + std::set<uint32> const& phases = sDB2Manager.GetPhasesForGroup(phaseGroup); + for (uint32 phase : phases) + up = SetInPhase(phase, false, true); + if (!updateNeeded && up) + updateNeeded = true; + } + } + + // only update visibility and send packets if there was a change in the phase list + + if (updateNeeded && GetTypeId() == TYPEID_PLAYER && IsInWorld()) + ToPlayer()->GetSession()->SendSetPhaseShift(GetPhases(), GetTerrainSwaps(), GetWorldMapAreaSwaps()); + + // only update visibilty once, to prevent objects appearing for a moment while adding in multiple phases + if (updateNeeded && IsInWorld()) + UpdateObjectVisibility(); +} + +bool WorldObject::SetInPhase(uint32 id, bool update, bool apply) +{ + if (id) + { + if (apply) + { + if (HasInPhaseList(id)) // do not run the updates if we are already in this phase + return false; + _phases.insert(id); + } + else + { + for (uint32 phaseId : sObjectMgr->GetPhasesForArea(GetAreaId())) + { + if (id == phaseId) + { + ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_PHASE, phaseId); + if (sConditionMgr->IsObjectMeetToConditions(this, conditions)) + { + // if area phase passes the condition we should not remove it (ie: if remove called from aura remove) + // this however breaks the .mod phase command, you wont be able to remove any area based phases with it + return false; + } + } + } + if (!HasInPhaseList(id)) // do not run the updates if we are not in this phase + return false; + _phases.erase(id); + } + } + RebuildTerrainSwaps(); + + if (update && IsInWorld()) + UpdateObjectVisibility(); + return true; +} + +void WorldObject::CopyPhaseFrom(WorldObject* obj, bool update) +{ + if (!obj) + return; + + for (uint32 phase : obj->GetPhases()) + SetInPhase(phase, false, true); + + if (update && IsInWorld()) + UpdateObjectVisibility(); +} + +void WorldObject::ClearPhases(bool update) +{ + _phases.clear(); + + RebuildTerrainSwaps(); if (update && IsInWorld()) UpdateObjectVisibility(); @@ -3026,13 +3146,10 @@ bool WorldObject::IsInPhase(WorldObject const* obj) const if (obj->GetPhases().empty() && IsInPhase(169)) return true; - return Trinity::Containers::Intersects(_phases.begin(), _phases.end(), obj->GetPhases().begin(), obj->GetPhases().end()); -} + if (GetTypeId() == TYPEID_PLAYER && ToPlayer()->IsGameMaster()) + return true; -bool WorldObject::InSamePhase(WorldObject const* obj) const -{ - return IsInPhase(obj); - // return InSamePhase(obj->GetPhaseMask()); + return Trinity::Containers::Intersects(_phases.begin(), _phases.end(), obj->GetPhases().begin(), obj->GetPhases().end()); } void WorldObject::PlayDistanceSound(uint32 sound_id, Player* target /*= NULL*/) @@ -3181,3 +3298,86 @@ ObjectGuid WorldObject::GetTransGUID() const return GetTransport()->GetGUID(); return ObjectGuid::Empty; } + +void WorldObject::RebuildTerrainSwaps() +{ + // Clear all terrain swaps, will be rebuilt below + // Reason for this is, multiple phases can have the same terrain swap, we should not remove the swap if another phase still use it + _terrainSwaps.clear(); + ConditionList conditions; + + // Check all applied phases for terrain swap and add it only once + for (uint32 phaseId : _phases) + { + std::list<uint32>& swaps = sObjectMgr->GetPhaseTerrainSwaps(phaseId); + + for (uint32 swap : swaps) + { + // only add terrain swaps for current map + MapEntry const* mapEntry = sMapStore.LookupEntry(swap); + if (!mapEntry || mapEntry->ParentMapID != GetMapId()) + continue; + + conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, swap); + + if (sConditionMgr->IsObjectMeetToConditions(this, conditions)) + _terrainSwaps.insert(swap); + } + } + + // get default terrain swaps, only for current map always + std::list<uint32>& mapSwaps = sObjectMgr->GetDefaultTerrainSwaps(GetMapId()); + + for (uint32 swap : mapSwaps) + { + conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, swap); + + if (sConditionMgr->IsObjectMeetToConditions(this, conditions)) + _terrainSwaps.insert(swap); + } + + // online players have a game client with world map display + if (GetTypeId() == TYPEID_PLAYER) + RebuildWorldMapAreaSwaps(); +} + +void WorldObject::RebuildWorldMapAreaSwaps() +{ + // Clear all world map area swaps, will be rebuilt below + _worldMapAreaSwaps.clear(); + + // get ALL default terrain swaps, if we are using it (condition is true) + // send the worldmaparea for it, to see swapped worldmaparea in client from other maps too, not just from our current + TerrainPhaseInfo defaults = sObjectMgr->GetDefaultTerrainSwapStore(); + for (TerrainPhaseInfo::const_iterator itr = defaults.begin(); itr != defaults.end(); ++itr) + { + for (uint32 swap : itr->second) + { + ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, swap); + if (sConditionMgr->IsObjectMeetToConditions(this, conditions)) + { + for (uint32 map : sObjectMgr->GetTerrainWorldMaps(swap)) + _worldMapAreaSwaps.insert(map); + } + } + } + + // Check all applied phases for world map area swaps + for (uint32 phaseId : _phases) + { + std::list<uint32>& swaps = sObjectMgr->GetPhaseTerrainSwaps(phaseId); + + for (uint32 swap : swaps) + { + // add world map swaps for ANY map + + ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_TERRAIN_SWAP, swap); + + if (sConditionMgr->IsObjectMeetToConditions(this, conditions)) + { + for (uint32 map : sObjectMgr->GetTerrainWorldMaps(swap)) + _worldMapAreaSwaps.insert(map); + } + } + } +}
\ No newline at end of file diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index e8022df5462..54fd48fa4b9 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -612,13 +612,24 @@ class WorldObject : public Object, public WorldLocation uint32 GetInstanceId() const { return m_InstanceId; } virtual void SetPhaseMask(uint32 newPhaseMask, bool update); - virtual void SetInPhase(uint32 id, bool update, bool apply); + virtual bool SetInPhase(uint32 id, bool update, bool apply); + void CopyPhaseFrom(WorldObject* obj, bool update = false); + void UpdateAreaPhase(); + void ClearPhases(bool update = false); + void RebuildTerrainSwaps(); + void RebuildWorldMapAreaSwaps(); + bool HasInPhaseList(uint32 phase); uint32 GetPhaseMask() const { return m_phaseMask; } - bool InSamePhase(WorldObject const* obj) const; - bool InSamePhase(uint32 phasemask) const { return (GetPhaseMask() & phasemask) != 0; } bool IsInPhase(uint32 phase) const { return _phases.find(phase) != _phases.end(); } bool IsInPhase(WorldObject const* obj) const; + bool IsInTerrainSwap(uint32 terrainSwap) const { return _terrainSwaps.find(terrainSwap) != _terrainSwaps.end(); } std::set<uint32> const& GetPhases() const { return _phases; } + std::set<uint32> const& GetTerrainSwaps() const { return _terrainSwaps; } + std::set<uint32> const& GetWorldMapAreaSwaps() const { return _worldMapAreaSwaps; } + int32 GetDBPhase() { return _dbPhase; } + + // if negative it is used as PhaseGroupId + void SetDBPhase(int32 p) { _dbPhase = p; } uint32 GetZoneId() const; uint32 GetAreaId() const; @@ -791,6 +802,9 @@ class WorldObject : public Object, public WorldLocation uint32 m_InstanceId; // in map copy with instance id uint32 m_phaseMask; // in area phase state std::set<uint32> _phases; + std::set<uint32> _terrainSwaps; + std::set<uint32> _worldMapAreaSwaps; + int32 _dbPhase; uint16 m_notifyflags; uint16 m_executed_notifies; diff --git a/src/server/game/Entities/Pet/Pet.cpp b/src/server/game/Entities/Pet/Pet.cpp index a59866c402f..6a07a56d0af 100644 --- a/src/server/game/Entities/Pet/Pet.cpp +++ b/src/server/game/Entities/Pet/Pet.cpp @@ -176,11 +176,10 @@ bool Pet::LoadPetFromDB(Player* owner, uint32 petEntry, uint32 petnumber, bool c } Map* map = owner->GetMap(); - if (!Create(sObjectMgr->GetGenerator<HighGuid::Pet>()->Generate(), map, owner->GetPhaseMask(), petEntry)) + if (!Create(sObjectMgr->GetGenerator<HighGuid::Pet>()->Generate(), map, petEntry)) return false; - for (auto itr : owner->GetPhases()) - SetInPhase(itr, false, true); + CopyPhaseFrom(owner); setPetType(petType); setFaction(owner->getFaction()); @@ -732,7 +731,7 @@ bool Pet::CreateBaseAtCreature(Creature* creature) { ASSERT(creature); - if (!CreateBaseAtTamed(creature->GetCreatureTemplate(), creature->GetMap(), creature->GetPhaseMask())) + if (!CreateBaseAtTamed(creature->GetCreatureTemplate(), creature->GetMap())) return false; Relocate(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), creature->GetOrientation()); @@ -763,7 +762,7 @@ bool Pet::CreateBaseAtCreature(Creature* creature) bool Pet::CreateBaseAtCreatureInfo(CreatureTemplate const* cinfo, Unit* owner) { - if (!CreateBaseAtTamed(cinfo, owner->GetMap(), owner->GetPhaseMask())) + if (!CreateBaseAtTamed(cinfo, owner->GetMap())) return false; if (CreatureFamilyEntry const* cFamily = sCreatureFamilyStore.LookupEntry(cinfo->family)) @@ -774,10 +773,10 @@ bool Pet::CreateBaseAtCreatureInfo(CreatureTemplate const* cinfo, Unit* owner) return true; } -bool Pet::CreateBaseAtTamed(CreatureTemplate const* cinfo, Map* map, uint32 phaseMask) +bool Pet::CreateBaseAtTamed(CreatureTemplate const* cinfo, Map* map) { TC_LOG_DEBUG("entities.pet", "Pet::CreateBaseForTamed"); - if (!Create(sObjectMgr->GetGenerator<HighGuid::Pet>()->Generate(), map, phaseMask, cinfo->Entry)) + if (!Create(sObjectMgr->GetGenerator<HighGuid::Pet>()->Generate(), map, cinfo->Entry)) return false; setPowerType(POWER_FOCUS); @@ -1800,12 +1799,11 @@ bool Pet::IsPermanentPetFor(Player* owner) const } } -bool Pet::Create(ObjectGuid::LowType guidlow, Map* map, uint32 phaseMask, uint32 Entry) +bool Pet::Create(ObjectGuid::LowType guidlow, Map* map, uint32 Entry) { ASSERT(map); SetMap(map); - SetPhaseMask(phaseMask, false); Object::_Create(ObjectGuid::Create<HighGuid::Pet>(map->GetId(), Entry, guidlow)); m_DBTableGuid = guidlow; diff --git a/src/server/game/Entities/Pet/Pet.h b/src/server/game/Entities/Pet/Pet.h index b349b79a6bd..494db54208d 100644 --- a/src/server/game/Entities/Pet/Pet.h +++ b/src/server/game/Entities/Pet/Pet.h @@ -55,10 +55,10 @@ class Pet : public Guardian bool IsPermanentPetFor(Player* owner) const; // pet have tab in character windows and set UNIT_FIELD_PETNUMBER - bool Create(ObjectGuid::LowType guidlow, Map* map, uint32 phaseMask, uint32 Entry); + bool Create(ObjectGuid::LowType guidlow, Map* map, uint32 Entry); bool CreateBaseAtCreature(Creature* creature); bool CreateBaseAtCreatureInfo(CreatureTemplate const* cinfo, Unit* owner); - bool CreateBaseAtTamed(CreatureTemplate const* cinfo, Map* map, uint32 phaseMask); + bool CreateBaseAtTamed(CreatureTemplate const* cinfo, Map* map); bool LoadPetFromDB(Player* owner, uint32 petentry = 0, uint32 petnumber = 0, bool current = false); bool IsLoading() const override { return m_loading;} void SavePetToDB(PetSaveMode mode); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 47b46f05752..7e945a0c0b6 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -7431,6 +7431,8 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) UpdateLocalChannels(newZone); UpdateZoneDependentAuras(newZone); + + UpdateAreaPhase(); } //If players are too far away from the duel flag... they lose the duel @@ -15423,6 +15425,7 @@ void Player::SendQuestUpdate(uint32 questId) } UpdateForQuestWorldObjects(); + SendUpdatePhasing(); } QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver) @@ -26207,15 +26210,15 @@ Pet* Player::SummonPet(uint32 entry, float x, float y, float z, float ang, PetTy Map* map = GetMap(); uint32 pet_number = sObjectMgr->GeneratePetNumber(); - if (!pet->Create(sObjectMgr->GetGenerator<HighGuid::Pet>()->Generate(), map, GetPhaseMask(), entry)) + + if (!pet->Create(sObjectMgr->GetGenerator<HighGuid::Pet>()->Generate(), map, entry)) { TC_LOG_ERROR("misc", "no such creature entry %u", entry); delete pet; return NULL; } - for (auto itr : GetPhases()) - pet->SetInPhase(itr, false, true); + pet->CopyPhaseFrom(this); pet->SetCreatorGUID(GetGUID()); pet->SetUInt32Value(UNIT_FIELD_FACTIONTEMPLATE, getFaction()); @@ -26585,25 +26588,14 @@ void Player::ReadMovementInfo(WorldPacket& data, MovementInfo* mi, Movement::Ext #undef REMOVE_VIOLATING_FLAGS } -void Player::UpdatePhasing() +void Player::SendUpdatePhasing() { if (!IsInWorld()) return; - std::set<uint32> phaseIds; - std::set<uint32> terrainswaps; - std::set<uint32> worldAreaSwaps; - - for (auto phase : GetPhases()) - { - PhaseInfo const* info = sObjectMgr->GetPhaseInfo(phase); - if (!info) - continue; - terrainswaps.insert(info->terrainSwapMap); - worldAreaSwaps.insert(info->worldMapAreaSwap); - } + RebuildTerrainSwaps(); // to set default map swaps - GetSession()->SendSetPhaseShift(GetPhases(), terrainswaps, worldAreaSwaps); + GetSession()->SendSetPhaseShift(GetPhases(), GetTerrainSwaps(), GetWorldMapAreaSwaps()); } void Player::SendSupercededSpell(uint32 oldSpell, uint32 newSpell) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index d0cf22ca24b..6e174995ebd 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2449,7 +2449,7 @@ class Player : public Unit, public GridObject<Player> void UpdateVisibilityOf(WorldObject* target); void UpdateTriggerVisibility(); - void UpdatePhasing(); + void SendUpdatePhasing(); template<class T> void UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& visibleNow); diff --git a/src/server/game/Entities/Transport/Transport.cpp b/src/server/game/Entities/Transport/Transport.cpp index 68d50b1861a..6ad2bd52130 100644 --- a/src/server/game/Entities/Transport/Transport.cpp +++ b/src/server/game/Entities/Transport/Transport.cpp @@ -318,8 +318,7 @@ Creature* Transport::CreateNPCPassenger(ObjectGuid::LowType guid, CreatureData c for (auto phase : sDB2Manager.GetPhasesForGroup(data->phaseGroup)) creature->SetInPhase(phase, false, true); else - for (auto phase : GetPhases()) // Set the creature to the transport's phases - creature->SetInPhase(phase, false, true); + creature->CopyPhaseFrom(this); if (!map->AddToMap(creature)) { @@ -463,8 +462,8 @@ TempSummon* Transport::SummonPassenger(uint32 entry, Position const& pos, TempSu return NULL; } - for (auto itr : phases) - summon->SetInPhase(itr, false, true); + for (uint32 phase : phases) + summon->SetInPhase(phase, false, true); summon->SetUInt32Value(UNIT_CREATED_BY_SPELL, spellId); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index b26211a4b5d..a1a08ad15e0 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -3660,7 +3660,7 @@ void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase, bool phaseid) else { Unit* caster = aura->GetCaster(); - if (!caster || (newPhase && !caster->InSamePhase(newPhase)) || (!newPhase && !caster->IsInPhase(this))) + if (!caster || (newPhase && !caster->IsInPhase(newPhase)) || (!newPhase && !caster->IsInPhase(this))) RemoveAura(iter); else ++iter; @@ -3675,7 +3675,7 @@ void Unit::RemoveNotOwnSingleTargetAuras(uint32 newPhase, bool phaseid) for (AuraList::iterator iter = scAuras.begin(); iter != scAuras.end();) { Aura* aura = *iter; - if (aura->GetUnitOwner() != this && !aura->GetUnitOwner()->InSamePhase(newPhase)) + if (aura->GetUnitOwner() != this && !aura->GetUnitOwner()->IsInPhase(newPhase)) { aura->Remove(); iter = scAuras.begin(); @@ -11563,6 +11563,7 @@ void Unit::AddToWorld() { WorldObject::AddToWorld(); } + RebuildTerrainSwaps(); } void Unit::RemoveFromWorld() @@ -13091,6 +13092,8 @@ bool Unit::InitTamedPet(Pet* pet, uint8 level, uint32 spell_id) return false; } + pet->CopyPhaseFrom(this); + pet->GetCharmInfo()->SetPetNumber(sObjectMgr->GeneratePetNumber(), true); // this enables pet details window (Shift+P) pet->InitPetCreateSpells(); @@ -14421,12 +14424,12 @@ float Unit::MeleeSpellMissChance(const Unit* victim, WeaponAttackType attType, u return missChance; } -void Unit::SetInPhase(uint32 id, bool update, bool apply) +bool Unit::SetInPhase(uint32 id, bool update, bool apply) { - WorldObject::SetInPhase(id, update, apply); + bool res = WorldObject::SetInPhase(id, update, apply); if (!IsInWorld()) - return; + return res; if (GetTypeId() == TYPEID_UNIT || (!ToPlayer()->IsGameMaster() && !ToPlayer()->GetSession()->PlayerLogout())) { @@ -14469,6 +14472,8 @@ void Unit::SetInPhase(uint32 id, bool update, bool apply) summon->SetInPhase(id, true, apply); RemoveNotOwnSingleTargetAuras(0, true); + + return res; } void Unit::UpdateObjectVisibility(bool forced) diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 595e2839264..1704164f592 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1958,7 +1958,7 @@ class Unit : public WorldObject void SetVisible(bool x); // common function for visibility checks for player/creatures with detection code - void SetInPhase(uint32 id, bool update, bool apply); + bool SetInPhase(uint32 id, bool update, bool apply); void UpdateObjectVisibility(bool forced = true) override; SpellImmuneList m_spellImmune[MAX_SPELL_IMMUNITY]; diff --git a/src/server/game/Globals/ObjectAccessor.cpp b/src/server/game/Globals/ObjectAccessor.cpp index e38c14046c4..44e7271ca70 100644 --- a/src/server/game/Globals/ObjectAccessor.cpp +++ b/src/server/game/Globals/ObjectAccessor.cpp @@ -411,6 +411,8 @@ Corpse* ObjectAccessor::ConvertCorpseForPlayer(ObjectGuid player_guid, bool insi bones->SetUInt32Value(CORPSE_FIELD_ITEM + i, 0); } + bones->CopyPhaseFrom(corpse); + // add bones in grid store if grid loaded where corpse placed map->AddToMap(bones); } diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 2523f316cec..acadc036fb3 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -6448,11 +6448,28 @@ uint64 ObjectMgr::GenerateVoidStorageItemId() void ObjectMgr::LoadCorpses() { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - // SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId, phaseMask, corpseGuid, guid FROM corpse WHERE corpseType <> 0 - uint32 oldMSTime = getMSTime(); + std::unordered_map<uint32, std::list<uint32>> phases; + + // 0 1 + // SELECT Guid, PhaseId FROM corpse_phases + PreparedQueryResult phaseResult = CharacterDatabase.Query(CharacterDatabase.GetPreparedStatement(CHAR_SEL_CORPSE_PHASES)); + if (phaseResult) + { + do + { + Field* fields = phaseResult->Fetch(); + uint32 guid = fields[0].GetUInt32(); + uint32 phaseId = fields[1].GetUInt32(); + + phases[guid].push_back(phaseId); + + } while (phaseResult->NextRow()); + } + + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + // SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId, corpseGuid, guid FROM corpse WHERE corpseType <> 0 PreparedQueryResult result = CharacterDatabase.Query(CharacterDatabase.GetPreparedStatement(CHAR_SEL_CORPSES)); if (!result) { @@ -6464,11 +6481,11 @@ void ObjectMgr::LoadCorpses() do { Field* fields = result->Fetch(); - ObjectGuid::LowType guid = fields[15].GetUInt64(); + uint32 guid = fields[14].GetUInt32(); CorpseType type = CorpseType(fields[12].GetUInt8()); if (type >= MAX_CORPSE_TYPE) { - TC_LOG_ERROR("misc", "Corpse (guid: " UI64FMTD ") have wrong corpse type (%u), not loading.", guid, type); + TC_LOG_ERROR("misc", "Corpse (guid: %u) have wrong corpse type (%u), not loading.", guid, type); continue; } @@ -6479,6 +6496,9 @@ void ObjectMgr::LoadCorpses() continue; } + for (auto phaseId : phases[guid]) + corpse->SetInPhase(phaseId, false, true); + sObjectAccessor->AddCorpse(corpse); ++count; } @@ -8527,60 +8547,64 @@ void ObjectMgr::LoadFactionChangeTitles() TC_LOG_INFO("server.loading", ">> Loaded %u faction change title pairs in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } -void ObjectMgr::LoadPhaseDefinitions() +void ObjectMgr::LoadTerrainSwapDefaults() { - _PhaseDefinitionStore.clear(); + _terrainMapDefaultStore.clear(); uint32 oldMSTime = getMSTime(); - // 0 1 2 3 - QueryResult result = WorldDatabase.Query("SELECT zoneId, entry, phaseId, phaseGroup FROM `phase_definitions` ORDER BY `entry` ASC"); + // 0 1 + QueryResult result = WorldDatabase.Query("SELECT MapId, TerrainSwapMap FROM `terrain_swap_defaults`"); if (!result) { - TC_LOG_INFO("server.loading", ">> Loaded 0 phasing definitions. DB table `phase_definitions` is empty."); + TC_LOG_INFO("server.loading", ">> Loaded 0 terrain swap defaults. DB table `terrain_swap_defaults` is empty."); return; } uint32 count = 0; - do { Field* fields = result->Fetch(); - PhaseDefinition PhaseDefinition; + uint32 mapId = fields[0].GetUInt32(); - PhaseDefinition.zoneId = fields[0].GetUInt32(); - PhaseDefinition.entry = fields[1].GetUInt32(); - PhaseDefinition.phaseId = fields[2].GetUInt32(); - PhaseDefinition.phaseGroup = fields[3].GetUInt32(); + MapEntry const* map = sMapStore.LookupEntry(mapId); + if (!map) + { + TC_LOG_ERROR("sql.sql", "Map %u defined in `terrain_swap_defaults` does not exist, skipped.", mapId); + continue; + } - if (PhaseDefinition.phaseGroup && PhaseDefinition.phaseId) + uint32 terrainSwap = fields[1].GetUInt32(); + + map = sMapStore.LookupEntry(terrainSwap); + if (!map) { - TC_LOG_ERROR("sql.sql", "Phase definition for zone %u (Entry: %u) has phaseGroup and phaseId set, phaseGroup set to 0", PhaseDefinition.zoneId, PhaseDefinition.entry); - PhaseDefinition.phaseGroup = 0; + TC_LOG_ERROR("sql.sql", "TerrainSwapMap %u defined in `terrain_swap_defaults` does not exist, skipped.", terrainSwap); + continue; } - _PhaseDefinitionStore[PhaseDefinition.zoneId].push_back(PhaseDefinition); + + _terrainMapDefaultStore[mapId].push_back(terrainSwap); ++count; - } - while (result->NextRow()); + } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u phasing definitions in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded %u terrain swap defaults in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } -void ObjectMgr::LoadPhaseInfo() +void ObjectMgr::LoadTerrainPhaseInfo() { - _PhaseInfoStore.clear(); + _terrainPhaseInfoStore.clear(); uint32 oldMSTime = getMSTime(); - // 0 1 2 - QueryResult result = WorldDatabase.Query("SELECT id, worldmapareaswap, terrainswapmap FROM `phase_info`"); + // 0 1 + QueryResult result = WorldDatabase.Query("SELECT Id, TerrainSwapMap FROM `terrain_phase_info`"); if (!result) { - TC_LOG_INFO("server.loading", ">> Loaded 0 phase infos. DB table `phase_info` is empty."); + TC_LOG_INFO("server.loading", ">> Loaded 0 terrain phase infos. DB table `terrain_phase_info` is empty."); return; } @@ -8589,25 +8613,93 @@ void ObjectMgr::LoadPhaseInfo() { Field* fields = result->Fetch(); - PhaseInfo phaseInfo; - phaseInfo.phaseId = fields[0].GetUInt32(); + uint32 phaseId = fields[0].GetUInt32(); - PhaseEntry const* phase = sPhaseStore.LookupEntry(phaseInfo.phaseId); + PhaseEntry const* phase = sPhaseStore.LookupEntry(phaseId); if (!phase) { - TC_LOG_ERROR("sql.sql", "Phase %u defined in `phase_info` does not exists, skipped.", phaseInfo.phaseId); + TC_LOG_ERROR("sql.sql", "Phase %u defined in `terrain_phase_info` does not exist, skipped.", phaseId); continue; } - phaseInfo.worldMapAreaSwap = fields[1].GetUInt32(); - phaseInfo.terrainSwapMap = fields[2].GetUInt32(); + uint32 terrainSwap = fields[1].GetUInt32(); - _PhaseInfoStore[phaseInfo.phaseId] = phaseInfo; + _terrainPhaseInfoStore[phaseId].push_back(terrainSwap); ++count; } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded %u phase infos in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); + + TC_LOG_INFO("server.loading", ">> Loaded %u terrain phase infos in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); +} + +void ObjectMgr::LoadTerrainWorldMaps() +{ + _terrainWorldMapStore.clear(); + + uint32 oldMSTime = getMSTime(); + + // 0 1 + QueryResult result = WorldDatabase.Query("SELECT TerrainSwapMap, WorldMapArea FROM `terrain_worldmap`"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 terrain world maps. DB table `terrain_worldmap` is empty."); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + uint32 mapId = fields[0].GetUInt32(); + + if (!sMapStore.LookupEntry(mapId)) + { + TC_LOG_ERROR("sql.sql", "TerrainSwapMap %u defined in `terrain_worldmap` does not exist, skipped.", mapId); + continue; + } + + uint32 worldMapArea = fields[1].GetUInt32(); + + _terrainWorldMapStore[mapId].push_back(worldMapArea); + + ++count; + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u terrain world maps in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); +} + +void ObjectMgr::LoadAreaPhases() +{ + _phases.clear(); + + uint32 oldMSTime = getMSTime(); + + // 0 1 + QueryResult result = WorldDatabase.Query("SELECT AreaId, PhaseId FROM `phase_area`"); + + if (!result) + { + TC_LOG_INFO("server.loading", ">> Loaded 0 phase areas. DB table `phase_area` is empty."); + return; + } + + uint32 count = 0; + do + { + Field* fields = result->Fetch(); + + uint32 area = fields[0].GetUInt32(); + uint32 phase = fields[1].GetUInt32(); + + _phases[area].push_back(phase); + + ++count; + } while (result->NextRow()); + + TC_LOG_INFO("server.loading", ">> Loaded %u phase areas in %u ms.", count, GetMSTimeDiffToNow(oldMSTime)); } GameObjectTemplate const* ObjectMgr::GetGameObjectTemplate(uint32 entry) diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index e9ec98f3e98..dca58857f9c 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -129,34 +129,6 @@ typedef std::map<uint32, PageText> PageTextContainer; // Benchmarked: Faster than std::map (insert/find) typedef std::unordered_map<uint16, InstanceTemplate> InstanceTemplateContainer; -// Phasing (visibility) -enum PhasingFlags -{ - PHASE_FLAG_OVERWRITE_EXISTING = 0x01, // don't stack with existing phases, overwrites existing phases - PHASE_FLAG_NO_MORE_PHASES = 0x02, // stop calculating phases after this phase was applied (no more phases will be applied) - PHASE_FLAG_NEGATE_PHASE = 0x04 // negate instead to add the phasemask -}; - -struct PhaseInfo -{ - uint32 phaseId; - uint32 worldMapAreaSwap; - uint32 terrainSwapMap; -}; - -typedef std::unordered_map<uint32, PhaseInfo> PhaseInfoContainer; - -struct PhaseDefinition -{ - uint32 zoneId; - uint32 entry; - uint32 phaseId; - uint32 phaseGroup; -}; - -typedef std::list<PhaseDefinition> PhaseDefinitionContainer; -typedef std::unordered_map<uint32 /*zoneId*/, PhaseDefinitionContainer> PhaseDefinitionStore; - struct GameTele { float position_x; @@ -672,6 +644,9 @@ struct DungeonEncounter typedef std::list<DungeonEncounter const*> DungeonEncounterList; typedef std::unordered_map<uint64, DungeonEncounterList> DungeonEncounterContainer; +typedef std::unordered_map<uint32, std::list<uint32>> TerrainPhaseInfo; +typedef std::unordered_map<uint32, std::list<uint32>> PhaseInfo; + class PlayerDumpReader; class ObjectMgr @@ -1008,8 +983,10 @@ class ObjectMgr void LoadTrainerSpell(); void AddSpellToTrainer(uint32 entry, uint32 spell, uint32 spellCost, uint32 reqSkill, uint32 reqSkillValue, uint32 reqLevel); - void LoadPhaseDefinitions(); - void LoadPhaseInfo(); + void LoadTerrainPhaseInfo(); + void LoadTerrainSwapDefaults(); + void LoadTerrainWorldMaps(); + void LoadAreaPhases(); std::string GeneratePetName(uint32 entry); uint32 GetBaseXP(uint8 level); @@ -1243,7 +1220,12 @@ class ObjectMgr return _gossipMenuItemsStore.equal_range(uiMenuId); } - PhaseInfo const* GetPhaseInfo(uint32 phase) { return _PhaseInfoStore.find(phase) != _PhaseInfoStore.end() ? &_PhaseInfoStore[phase] : nullptr; } + std::list<uint32>& GetPhaseTerrainSwaps(uint32 phaseid) { return _terrainPhaseInfoStore[phaseid]; } + std::list<uint32>& GetDefaultTerrainSwaps(uint32 mapid) { return _terrainMapDefaultStore[mapid]; } + std::list<uint32>& GetTerrainWorldMaps(uint32 terrainId) { return _terrainWorldMapStore[terrainId]; } + TerrainPhaseInfo& GetDefaultTerrainSwapStore() { return _terrainMapDefaultStore; } + std::list<uint32>& GetPhasesForArea(uint32 area) { return _phases[area]; } + PhaseInfo& GetAreaPhases() { return _phases; } // for wintergrasp only GraveYardContainer GraveYardStore; @@ -1369,8 +1351,10 @@ class ObjectMgr PageTextContainer _pageTextStore; InstanceTemplateContainer _instanceTemplateStore; - PhaseDefinitionStore _PhaseDefinitionStore; - PhaseInfoContainer _PhaseInfoStore; + TerrainPhaseInfo _terrainPhaseInfoStore; + TerrainPhaseInfo _terrainMapDefaultStore; + TerrainPhaseInfo _terrainWorldMapStore; + PhaseInfo _phases; private: void LoadScripts(ScriptsType type); diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 13b60d571d3..33b9d8fe461 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -1423,48 +1423,30 @@ void WorldSession::HandleUITimeRequest(WorldPackets::Misc::UITimeRequest& /*requ void WorldSession::SendSetPhaseShift(std::set<uint32> const& phaseIds, std::set<uint32> const& terrainswaps, std::set<uint32> const& worldMapAreaSwaps) { - ObjectGuid guid = _player->GetGUID(); - WorldPacket data(SMSG_SET_PHASE_SHIFT_CHANGE, 1 + 8 + 4 + 4 + 4 + 4 + 2 * phaseIds.size() + 4 + terrainswaps.size() * 2); - data.WriteBit(guid[2]); - data.WriteBit(guid[3]); - data.WriteBit(guid[1]); - data.WriteBit(guid[6]); - data.WriteBit(guid[4]); - data.WriteBit(guid[5]); - data.WriteBit(guid[0]); - data.WriteBit(guid[7]); - - data.WriteByteSeq(guid[7]); - data.WriteByteSeq(guid[4]); - - data << uint32(worldMapAreaSwaps.size()); - for (auto mapSwap : worldMapAreaSwaps) - data << uint16(mapSwap); // WorldMapArea.dbc id (controls map display) - - data.WriteByteSeq(guid[1]); - - data << uint32(phaseIds.size() ? 0 : 8); // flags (not phasemask) - - data.WriteByteSeq(guid[2]); - data.WriteByteSeq(guid[6]); - - data << uint32(0); // Inactive terrain swaps - //for (uint8 i = 0; i < inactiveSwapsCount; ++i) - // data << uint16(0); - - data << uint32(phaseIds.size()) * 2; // Phase.dbc ids + + data << _player->GetGUID(); // Client + data << uint32(phaseIds.size() ? 0 : 8); // PhaseShiftFlags + + data << uint32(phaseIds.size()); // PhaseShiftCount + data << _player->GetGUID(); // PersonalGUID for (std::set<uint32>::const_iterator itr = phaseIds.begin(); itr != phaseIds.end(); ++itr) - data << uint16(*itr); - - data.WriteByteSeq(guid[3]); - data.WriteByteSeq(guid[0]); + { + data << uint16(1); // PhaseFlags + data << uint16(*itr); // Id + } data << uint32(terrainswaps.size()) * 2; // Active terrain swaps for (std::set<uint32>::const_iterator itr = terrainswaps.begin(); itr != terrainswaps.end(); ++itr) data << uint16(*itr); - data.WriteByteSeq(guid[5]); + data << uint32(0); // Inactive terrain swaps + //for (uint8 i = 0; i < inactiveSwapsCount; ++i) + // data << uint16(0); + + data << uint32(worldMapAreaSwaps.size()) * 2; + for (auto mapSwap : worldMapAreaSwaps) + data << uint16(mapSwap); // WorldMapArea.dbc id (controls map display) SendPacket(&data); } diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index b8f95b9407c..904da4c0d3c 100644 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -631,5 +631,5 @@ void InstanceScript::UpdatePhasing() Map::PlayerList const& players = instance->GetPlayers(); for (Map::PlayerList::const_iterator itr = players.begin(); itr != players.end(); ++itr) if (Player* player = itr->GetSource()) - player->UpdatePhasing(); + player->SendUpdatePhasing(); } diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 71d05031483..0b106c0b391 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -498,6 +498,8 @@ bool Map::AddPlayerToMap(Player* player) player->m_clientGUIDs.clear(); player->UpdateObjectVisibility(false); + player->SendUpdatePhasing(); + sScriptMgr->OnPlayerEnterMap(this, player); return true; } @@ -556,6 +558,8 @@ bool Map::AddToMap(T* obj) if (obj->isActiveObject()) AddToActive(obj); + obj->RebuildTerrainSwaps(); + //something, such as vehicle, needs to be update immediately //also, trigger needs to cast spell, if not update, cannot see visual obj->UpdateObjectVisibility(true); diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index ed7af046428..5328d1a21c9 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -1743,7 +1743,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_MAX_WEEKLY_QUANTITY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_MELEE_ANIM_KIT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PCT_SPELL_MODIFIER, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PHASE_SHIFT_CHANGE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PHASE_SHIFT_CHANGE, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PLAYER_DECLINED_NAMES_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PLAY_HOVER_ANIM, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SET_PROFICIENCY, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index dd90e10f7bb..2766109fafc 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -1733,7 +1733,7 @@ void AuraEffect::HandlePhase(AuraApplication const* aurApp, uint8 mode, bool app { if (player->IsInWorld()) player->GetMap()->SendUpdateTransportVisibility(player, oldPhases); - player->UpdatePhasing(); + player->SendUpdatePhasing(); } // need triggering visibility update base at phase update of not GM invisible (other GMs anyway see in any phases) @@ -1765,7 +1765,7 @@ void AuraEffect::HandlePhaseGroup(AuraApplication const* aurApp, uint8 mode, boo { if (player->IsInWorld()) player->GetMap()->SendUpdateTransportVisibility(player, oldPhases); - player->UpdatePhasing(); + player->SendUpdatePhasing(); } // need triggering visibility update base at phase update of not GM invisible (other GMs anyway see in any phases) diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 06cf95c77d2..fe86b623893 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -3212,8 +3212,7 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex) return; } - for (auto phase : m_caster->GetPhases()) - pGameObj->SetInPhase(phase, false, true); + pGameObj->CopyPhaseFrom(m_caster); int32 duration = m_spellInfo->GetDuration(); @@ -3236,8 +3235,7 @@ void Spell::EffectSummonObjectWild(SpellEffIndex effIndex) if (linkedGO->Create(sObjectMgr->GetGenerator<HighGuid::GameObject>()->Generate(), linkedEntry, map, m_caster->GetPhaseMask(), x, y, z, target->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) { - for (auto phase : m_caster->GetPhases()) - linkedGO->SetInPhase(phase, false, true); + linkedGO->CopyPhaseFrom(m_caster); linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); linkedGO->SetSpellId(m_spellInfo->Id); @@ -3871,8 +3869,7 @@ void Spell::EffectDuel(SpellEffIndex effIndex) return; } - for (auto phase : m_caster->GetPhases()) - pGameObj->SetInPhase(phase, false, true); + pGameObj->CopyPhaseFrom(m_caster); pGameObj->SetUInt32Value(GAMEOBJECT_FACTION, m_caster->getFaction()); pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()+1); @@ -4244,8 +4241,7 @@ void Spell::EffectSummonObject(SpellEffIndex effIndex) return; } - for (auto phase : m_caster->GetPhases()) - go->SetInPhase(phase, false, true); + go->CopyPhaseFrom(m_caster); //pGameObj->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()); int32 duration = m_spellInfo->GetDuration(); @@ -4882,8 +4878,7 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex) return; } - for (auto phase : m_caster->GetPhases()) - pGameObj->SetInPhase(phase, false, true); + pGameObj->CopyPhaseFrom(m_caster); int32 duration = m_spellInfo->GetDuration(); @@ -4947,8 +4942,7 @@ void Spell::EffectTransmitted(SpellEffIndex effIndex) if (linkedGO->Create(sObjectMgr->GetGenerator<HighGuid::GameObject>()->Generate(), linkedEntry, cMap, 0, fx, fy, fz, m_caster->GetOrientation(), 0.0f, 0.0f, 0.0f, 0.0f, 100, GO_STATE_READY)) { - for (auto phase : m_caster->GetPhases()) - linkedGO->SetInPhase(phase, false, true); + linkedGO->CopyPhaseFrom(m_caster); linkedGO->SetRespawnTime(duration > 0 ? duration/IN_MILLISECONDS : 0); //linkedGO->SetUInt32Value(GAMEOBJECT_LEVEL, m_caster->getLevel()); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 561cd5bb3a0..5e3fcd1fd0e 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1460,6 +1460,10 @@ void World::SetInitialWorldSettings() stmt->setUInt32(0, 3 * DAY); CharacterDatabase.Execute(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_OLD_CORPSE_PHASES); + stmt->setUInt32(0, 3 * DAY); + CharacterDatabase.Execute(stmt); + ///- Load the DBC files TC_LOG_INFO("server.loading", "Initialize data stores..."); LoadDBCStores(m_dataPath); @@ -1550,9 +1554,6 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading Spell Group Stack Rules..."); sSpellMgr->LoadSpellGroupStackRules(); - TC_LOG_INFO("server.loading", "Loading Spell Phase Dbc Info..."); - sObjectMgr->LoadPhaseInfo(); - TC_LOG_INFO("server.loading", "Loading NPC Texts..."); sObjectMgr->LoadGossipText(); @@ -1801,8 +1802,17 @@ void World::SetInitialWorldSettings() TC_LOG_INFO("server.loading", "Loading World States..."); // must be loaded before battleground, outdoor PvP and conditions LoadWorldStates(); - TC_LOG_INFO("server.loading", "Loading Phase definitions..."); - sObjectMgr->LoadPhaseDefinitions(); + TC_LOG_INFO("server.loading", "Loading Terrain Phase definitions..."); + sObjectMgr->LoadTerrainPhaseInfo(); + + TC_LOG_INFO("server.loading", "Loading Terrain Swap Default definitions..."); + sObjectMgr->LoadTerrainSwapDefaults(); + + TC_LOG_INFO("server.loading", "Loading Terrain World Map definitions..."); + sObjectMgr->LoadTerrainWorldMaps(); + + TC_LOG_INFO("server.loading", "Loading Phase Area definitions..."); + sObjectMgr->LoadAreaPhases(); TC_LOG_INFO("server.loading", "Loading Conditions..."); sConditionMgr->LoadConditions(); diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index 5b60fc81229..e08557dd357 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -934,8 +934,7 @@ public: return false; } - for (auto phase : handler->GetSession()->GetPlayer()->GetPhases()) - v->SetInPhase(phase, false, true); + v->CopyPhaseFrom(handler->GetSession()->GetPlayer()); map->AddToMap(v->ToCreature()); @@ -959,6 +958,7 @@ public: char* t = strtok((char*)args, " "); char* p = strtok(NULL, " "); + char* m = strtok(NULL, " "); if (!t) return false; @@ -967,10 +967,16 @@ public: std::set<uint32> phaseId; std::set<uint32> worldMapSwap; - terrainswap.insert((uint32)atoi(t)); + if (uint32 ut = (uint32)atoi(t)) + terrainswap.insert(ut); if (p) - phaseId.insert((uint32)atoi(p)); + if (uint32 up = (uint32)atoi(p)) + phaseId.insert(up); + + if (m) + if (uint32 um = (uint32)atoi(m)) + worldMapSwap.insert(um); handler->GetSession()->SendSetPhaseShift(phaseId, terrainswap, worldMapSwap); return true; @@ -1390,14 +1396,28 @@ public: return true; } - static bool HandleDebugPhaseCommand(ChatHandler* /*handler*/, char const* /*args*/) + static bool HandleDebugPhaseCommand(ChatHandler* handler, char const* /*args*/) { - /*/ - Unit* unit = handler->getSelectedUnit(); - Player* player = handler->GetSession()->GetPlayer(); - if (unit && unit->GetTypeId() == TYPEID_PLAYER) - player = unit->ToPlayer(); - */ + Unit* target = handler->getSelectedUnit(); + + if (!target) + { + handler->SendSysMessage(LANG_SELECT_CREATURE); + handler->SetSentErrorMessage(true); + return false; + } + + std::stringstream phases; + + for (uint32 phase : target->GetPhases()) + { + phases << phase << " "; + } + + if (!phases.str().empty()) + handler->PSendSysMessage("Target's current phases: %s", phases.str().c_str()); + else + handler->SendSysMessage("Target is not phased"); return true; } }; diff --git a/src/server/scripts/Commands/cs_gobject.cpp b/src/server/scripts/Commands/cs_gobject.cpp index 59d32f9e418..36876a9be34 100644 --- a/src/server/scripts/Commands/cs_gobject.cpp +++ b/src/server/scripts/Commands/cs_gobject.cpp @@ -158,8 +158,7 @@ public: return false; } - for (auto phase : player->GetPhases()) - object->SetInPhase(phase, false, true); + object->CopyPhaseFrom(player); if (spawntimeSecs) { diff --git a/src/server/scripts/Commands/cs_misc.cpp b/src/server/scripts/Commands/cs_misc.cpp index bc8f7bad5fb..466c24eba5d 100644 --- a/src/server/scripts/Commands/cs_misc.cpp +++ b/src/server/scripts/Commands/cs_misc.cpp @@ -247,6 +247,21 @@ public: if (status) handler->PSendSysMessage(LANG_LIQUID_STATUS, liquidStatus.level, liquidStatus.depth_level, liquidStatus.entry, liquidStatus.type_flags, status); + + if (!object->GetTerrainSwaps().empty()) + { + std::stringstream ss; + for (uint32 swap : object->GetTerrainSwaps()) + ss << swap << " "; + handler->PSendSysMessage("Target's active terrain swaps: %s", ss.str().c_str()); + } + if (!object->GetWorldMapAreaSwaps().empty()) + { + std::stringstream ss; + for (uint32 swap : object->GetWorldMapAreaSwaps()) + ss << swap << " "; + handler->PSendSysMessage("Target's active world map area swaps: %s", ss.str().c_str()); + } return true; } @@ -407,8 +422,7 @@ public: target->GetContactPoint(_player, x, y, z); _player->TeleportTo(target->GetMapId(), x, y, z, _player->GetAngle(target), TELE_TO_GM_MODE); - for (auto phase : target->GetPhases()) - _player->SetInPhase(phase, true, true); + _player->CopyPhaseFrom(target, true); } else { @@ -532,8 +546,7 @@ public: float x, y, z; handler->GetSession()->GetPlayer()->GetClosePoint(x, y, z, target->GetObjectSize()); target->TeleportTo(handler->GetSession()->GetPlayer()->GetMapId(), x, y, z, target->GetOrientation()); - for (auto phase : handler->GetSession()->GetPlayer()->GetPhases()) - target->SetInPhase(phase, true, true); + target->CopyPhaseFrom(handler->GetSession()->GetPlayer(), true); } else { diff --git a/src/server/scripts/Commands/cs_modify.cpp b/src/server/scripts/Commands/cs_modify.cpp index c22edf52dd3..5af9b150572 100644 --- a/src/server/scripts/Commands/cs_modify.cpp +++ b/src/server/scripts/Commands/cs_modify.cpp @@ -1279,10 +1279,13 @@ public: uint32 phase = (uint32)atoi((char*)args); Unit* target = handler->getSelectedUnit(); - if (target) - target->SetInPhase(phase, true, !target->IsInPhase(phase)); - else - handler->GetSession()->GetPlayer()->SetInPhase(phase, true, !handler->GetSession()->GetPlayer()->IsInPhase(phase)); + if (!target) + target = handler->GetSession()->GetPlayer(); + + target->SetInPhase(phase, true, !target->IsInPhase(phase)); + + if (target->GetTypeId() == TYPEID_PLAYER) + target->ToPlayer()->SendUpdatePhasing(); return true; } diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index 70086c94988..9ee32d0c6e5 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -206,6 +206,7 @@ public: { "model", rbac::RBAC_PERM_COMMAND_NPC_SET_MODEL, false, &HandleNpcSetModelCommand, "", NULL }, { "movetype", rbac::RBAC_PERM_COMMAND_NPC_SET_MOVETYPE, false, &HandleNpcSetMoveTypeCommand, "", NULL }, { "phase", rbac::RBAC_PERM_COMMAND_NPC_SET_PHASE, false, &HandleNpcSetPhaseCommand, "", NULL }, + { "phasegroup", rbac::RBAC_PERM_COMMAND_NPC_SET_PHASE, false, &HandleNpcSetPhaseGroup, "", NULL }, { "spawndist", rbac::RBAC_PERM_COMMAND_NPC_SET_SPAWNDIST, false, &HandleNpcSetSpawnDistCommand, "", NULL }, { "spawntime", rbac::RBAC_PERM_COMMAND_NPC_SET_SPAWNTIME, false, &HandleNpcSetSpawnTimeCommand, "", NULL }, { "data", rbac::RBAC_PERM_COMMAND_NPC_SET_DATA, false, &HandleNpcSetDataCommand, "", NULL }, @@ -285,9 +286,6 @@ public: return false; } - for (auto phase : chr->GetPhases()) - creature->SetInPhase(phase, false, true); - creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMask()); ObjectGuid::LowType db_guid = creature->GetDBTableGUIDLow(); @@ -1100,7 +1098,37 @@ public: } //npc phase handling - //change phase of creature or pet + //change phase of creature + static bool HandleNpcSetPhaseGroup(ChatHandler* handler, char const* args) + { + if (!*args) + return false; + + uint32 phaseGroupId = (uint32)atoi((char*)args); + + Creature* creature = handler->getSelectedCreature(); + if (!creature || creature->IsPet()) + { + handler->SendSysMessage(LANG_SELECT_CREATURE); + handler->SetSentErrorMessage(true); + return false; + } + + creature->ClearPhases(); + + for (uint32 id : sDB2Manager.GetPhasesForGroup(phaseGroupId)) + creature->SetInPhase(id, false, true); // don't send update here for multiple phases, only send it once after adding all phases + + creature->UpdateObjectVisibility(); + creature->SetDBPhase(-int(phaseGroupId)); + + creature->SaveToDB(); + + return true; + } + + //npc phase handling + //change phase of creature static bool HandleNpcSetPhaseCommand(ChatHandler* handler, char const* args) { if (!*args) @@ -1109,17 +1137,18 @@ public: uint32 phase = (uint32) atoi((char*)args); Creature* creature = handler->getSelectedCreature(); - if (!creature) + if (!creature || creature->IsPet()) { handler->SendSysMessage(LANG_SELECT_CREATURE); handler->SetSentErrorMessage(true); return false; } - creature->SetInPhase(phase, true, !creature->IsInPhase(phase)); + creature->ClearPhases(); + creature->SetInPhase(phase, true, true); + creature->SetDBPhase(phase); - if (!creature->IsPet()) - creature->SaveToDB(); + creature->SaveToDB(); return true; } diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index 99cec7bed95..78f23ceab25 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -1104,10 +1104,10 @@ public: static bool HandleReloadPhaseDefinitionsCommand(ChatHandler* handler, const char* /*args*/) { - TC_LOG_INFO("misc", "Reloading phase_definitions table..."); - sObjectMgr->LoadPhaseDefinitions(); + TC_LOG_INFO("misc", "Reloading terrain_phase_info table..."); + sObjectMgr->LoadTerrainPhaseInfo(); sWorld->UpdatePhaseDefinitions(); - handler->SendGlobalGMSysMessage("Phase Definitions reloaded."); + handler->SendGlobalGMSysMessage("Terrain phase infos reloaded."); return true; } diff --git a/src/server/scripts/Commands/cs_wp.cpp b/src/server/scripts/Commands/cs_wp.cpp index 35b142e9e5e..a4e0ce3af61 100644 --- a/src/server/scripts/Commands/cs_wp.cpp +++ b/src/server/scripts/Commands/cs_wp.cpp @@ -682,8 +682,7 @@ public: return false; } - for (auto phase : chr->GetPhases()) - wpCreature2->SetInPhase(phase, false, true); + wpCreature2->CopyPhaseFrom(chr); wpCreature2->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMask()); // To call _LoadGoods(); _LoadQuests(); CreateTrainerSpells(); @@ -902,8 +901,7 @@ public: return false; } - for (auto phase : chr->GetPhases()) - wpCreature->SetInPhase(phase, false, true); + wpCreature->CopyPhaseFrom(chr); // Set "wpguid" column to the visual waypoint stmt = WorldDatabase.GetPreparedStatement(WORLD_UPD_WAYPOINT_DATA_WPGUID); @@ -967,8 +965,7 @@ public: return false; } - for (auto phase : chr->GetPhases()) - creature->SetInPhase(phase, false, true); + creature->CopyPhaseFrom(chr); creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMask()); if (!creature->LoadCreatureFromDB(creature->GetDBTableGUIDLow(), map)) @@ -1019,8 +1016,7 @@ public: return false; } - for (auto phase : chr->GetPhases()) - creature->SetInPhase(phase, false, true); + creature->CopyPhaseFrom(chr); creature->SaveToDB(map->GetId(), (1 << map->GetSpawnMode()), chr->GetPhaseMask()); if (!creature->LoadCreatureFromDB(creature->GetDBTableGUIDLow(), map)) diff --git a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp index dd261d4014c..a8da4ff7438 100644 --- a/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp +++ b/src/server/scripts/OutdoorPvP/OutdoorPvPSI.cpp @@ -172,8 +172,7 @@ bool OutdoorPvPSI::HandleDropFlag(Player* player, uint32 spellId) return true; } - for (auto phase : player->GetPhases()) - go->SetInPhase(phase, false, true); + go->CopyPhaseFrom(player); go->SetRespawnTime(0); @@ -209,8 +208,7 @@ bool OutdoorPvPSI::HandleDropFlag(Player* player, uint32 spellId) return true; } - for (auto phase : player->GetPhases()) - go->SetInPhase(phase, false, true); + go->CopyPhaseFrom(player); go->SetRespawnTime(0); diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp index 6369429236f..352854636dc 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp @@ -336,11 +336,16 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_PLAYER_HOMEBIND, "DELETE FROM character_homebind WHERE guid = ?", CONNECTION_ASYNC); // Corpse - PrepareStatement(CHAR_SEL_CORPSES, "SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId, phaseMask, corpseGuid, guid FROM corpse WHERE corpseType <> 0", CONNECTION_SYNCH); - PrepareStatement(CHAR_INS_CORPSE, "INSERT INTO corpse (corpseGuid, guid, posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId, phaseMask) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CORPSES, "SELECT posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId, corpseGuid, guid FROM corpse WHERE corpseType <> 0", CONNECTION_SYNCH); + PrepareStatement(CHAR_INS_CORPSE, "INSERT INTO corpse (corpseGuid, guid, posX, posY, posZ, orientation, mapId, displayId, itemCache, bytes1, bytes2, flags, dynFlags, time, corpseType, instanceId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_CORPSE, "DELETE FROM corpse WHERE corpseGuid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_PLAYER_CORPSES, "DELETE FROM corpse WHERE guid = ? AND corpseType <> 0", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_OLD_CORPSES, "DELETE FROM corpse WHERE corpseType = 0 OR time < (UNIX_TIMESTAMP(NOW()) - ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CORPSE_PHASES, "SELECT Guid, PhaseId FROM corpse_phases", CONNECTION_SYNCH); + PrepareStatement(CHAR_DEL_CORPSE_PHASES, "DELETE FROM corpse_phases WHERE Guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_PLAYER_CORPSES_PHASES, "DELETE FROM corpse_phases WHERE OwnerGuid = ? AND CorpseType <> 0", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_OLD_CORPSE_PHASES, "DELETE FROM corpse_phases WHERE CorpseType = 0 OR Time < (UNIX_TIMESTAMP(NOW()) - ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CORPSE_PHASES, "INSERT INTO corpse_phases (Guid, PhaseId, OwnerGuid, Time, CorpseType) VALUES (?, ?, ?, ?, ?)", CONNECTION_ASYNC); // Creature respawn PrepareStatement(CHAR_SEL_CREATURE_RESPAWNS, "SELECT guid, respawnTime FROM creature_respawn WHERE mapId = ? AND instanceId = ?", CONNECTION_SYNCH); diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h index b10591f0e5f..e6c0a0db48c 100644 --- a/src/server/shared/Database/Implementation/CharacterDatabase.h +++ b/src/server/shared/Database/Implementation/CharacterDatabase.h @@ -294,6 +294,11 @@ enum CharacterDatabaseStatements CHAR_DEL_CORPSE, CHAR_DEL_PLAYER_CORPSES, CHAR_DEL_OLD_CORPSES, + CHAR_SEL_CORPSE_PHASES, + CHAR_DEL_CORPSE_PHASES, + CHAR_DEL_PLAYER_CORPSES_PHASES, + CHAR_DEL_OLD_CORPSE_PHASES, + CHAR_INS_CORPSE_PHASES, CHAR_SEL_CREATURE_RESPAWNS, CHAR_REP_CREATURE_RESPAWN, diff --git a/src/server/shared/Database/Implementation/WorldDatabase.cpp b/src/server/shared/Database/Implementation/WorldDatabase.cpp index 4c2f6fb9333..98a4db35242 100644 --- a/src/server/shared/Database/Implementation/WorldDatabase.cpp +++ b/src/server/shared/Database/Implementation/WorldDatabase.cpp @@ -81,7 +81,7 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_SEL_CREATURE_BY_ID, "SELECT guid FROM creature WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_GAMEOBJECT_NEAREST, "SELECT guid, id, position_x, position_y, position_z, map, (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) AS order_ FROM gameobject WHERE map = ? AND (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) <= ? ORDER BY order_", CONNECTION_SYNCH); PrepareStatement(WORLD_SEL_CREATURE_NEAREST, "SELECT guid, id, position_x, position_y, position_z, map, (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) AS order_ FROM creature WHERE map = ? AND (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) <= ? ORDER BY order_", CONNECTION_SYNCH); - PrepareStatement(WORLD_INS_CREATURE, "INSERT INTO creature (guid, id , map, spawnMask, phaseMask, modelid, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(WORLD_INS_CREATURE, "INSERT INTO creature (guid, id , map, spawnMask, phaseMask, PhaseId, PhaseGroup, modelid, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(WORLD_DEL_GAME_EVENT_CREATURE, "DELETE FROM game_event_creature WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_DEL_GAME_EVENT_MODEL_EQUIP, "DELETE FROM game_event_model_equip WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_INS_GAMEOBJECT, "INSERT INTO gameobject (guid, id, map, spawnMask, phaseMask, position_x, position_y, position_z, orientation, rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 86d9dac2946..f0f9adc32ed 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -3258,6 +3258,7 @@ Logger.sql.sql=5,Console DBErrors #Logger.network.opcode=3,Console Server #Logger.network.soap=3,Console Server #Logger.outdoorpvp=3,Console Server +#Logger.phase=3,Console Server #Logger.pool=3,Console Server #Logger.rbac=3,Console Server #Logger.scripts=3,Console Server |