Implement PhaseFlags "ObjectsVisible "
Objects in this phase should be visible from others phases but should be interactible
This commit is contained in:
@@ -4548,7 +4548,7 @@ GuidUnorderedSet const* GameObject::GetInsidePlayers() const
|
||||
|
||||
bool GameObject::MeetsInteractCondition(Player const* user) const
|
||||
{
|
||||
return ConditionMgr::IsPlayerMeetingCondition(user, m_goInfo->GetConditionID1());
|
||||
return IsInPhaseForInteraction(user) && ConditionMgr::IsPlayerMeetingCondition(user, m_goInfo->GetConditionID1());
|
||||
}
|
||||
|
||||
std::unordered_map<ObjectGuid, GameObject::PerPlayerState>& GameObject::GetOrCreatePerPlayerStates()
|
||||
|
||||
@@ -992,6 +992,17 @@ bool WorldObject::CanNeverSee(WorldObject const* obj, bool ignorePhaseShift /*=
|
||||
return GetMap() != obj->GetMap() || (!ignorePhaseShift && !InSamePhase(obj));
|
||||
}
|
||||
|
||||
bool WorldObject::IsInPhaseForInteraction(WorldObject const* obj) const
|
||||
{
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
if (obj->IsPlayer() && obj->ToPlayer()->IsGameMaster())
|
||||
return true;
|
||||
|
||||
return InSamePhase(obj) && GetPhaseShift().CanInteractWith(obj->GetPhaseShift());
|
||||
}
|
||||
|
||||
bool WorldObject::CanDetect(WorldObject const* obj, bool implicitDetect, bool checkAlert) const
|
||||
{
|
||||
WorldObject const* seer = this;
|
||||
|
||||
@@ -341,6 +341,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation
|
||||
{
|
||||
return GetPhaseShift().CanSee(obj->GetPhaseShift());
|
||||
}
|
||||
bool IsInPhaseForInteraction(WorldObject const* obj) const;
|
||||
static bool InSamePhase(WorldObject const* a, WorldObject const* b)
|
||||
{
|
||||
return a && b && a->InSamePhase(b);
|
||||
|
||||
@@ -341,9 +341,12 @@ class ViewerDependentValue<UF::UnitData::FlagsTag>
|
||||
public:
|
||||
using value_type = UF::UnitData::FlagsTag::value_type;
|
||||
|
||||
static value_type GetValue(UF::UnitData const* unitData, Player const* receiver, Unit const* /*unit*/)
|
||||
static value_type GetValue(UF::UnitData const* unitData, Player const* receiver, Unit const* unit)
|
||||
{
|
||||
value_type flags = unitData->Flags;
|
||||
if (!unit->IsInPhaseForInteraction(receiver))
|
||||
flags |= UNIT_FLAG_UNINTERACTIBLE;
|
||||
|
||||
// Gamemasters should be always able to interact with units - remove uninteractible flag
|
||||
if (receiver->IsGameMaster())
|
||||
flags &= ~UNIT_FLAG_UNINTERACTIBLE;
|
||||
@@ -441,6 +444,9 @@ public:
|
||||
static value_type GetValue(UF::UnitData const* unitData, Player const* receiver, Unit const* unit)
|
||||
{
|
||||
value_type interactSpellId = unitData->InteractSpellID;
|
||||
if (!unit->IsInPhaseForInteraction(receiver))
|
||||
return 0;
|
||||
|
||||
if (unitData->NpcFlags & UNIT_NPC_FLAG_SPELLCLICK && !interactSpellId)
|
||||
{
|
||||
// this field is not set if there are multiple available spellclick spells
|
||||
@@ -473,7 +479,9 @@ public:
|
||||
value_type npcFlag = unitData->NpcFlags;
|
||||
if (npcFlag)
|
||||
{
|
||||
if ((!unit->IsInteractionAllowedInCombat() && unit->IsInCombat())
|
||||
if (!unit->IsInPhaseForInteraction(receiver))
|
||||
npcFlag = 0;
|
||||
else if ((!unit->IsInteractionAllowedInCombat() && unit->IsInCombat())
|
||||
|| (!unit->IsInteractionAllowedWhileHostile() && unit->IsHostileTo(receiver)))
|
||||
npcFlag = 0;
|
||||
else if (Creature const* creature = unit->ToCreature())
|
||||
@@ -500,7 +508,9 @@ public:
|
||||
value_type npcFlag = unitData->NpcFlags2;
|
||||
if (npcFlag)
|
||||
{
|
||||
if ((!unit->IsInteractionAllowedInCombat() && unit->IsInCombat())
|
||||
if (!unit->IsInPhaseForInteraction(receiver))
|
||||
npcFlag = 0;
|
||||
else if ((!unit->IsInteractionAllowedInCombat() && unit->IsInCombat())
|
||||
|| (!unit->IsInteractionAllowedWhileHostile() && unit->IsHostileTo(receiver)))
|
||||
npcFlag = 0;
|
||||
}
|
||||
|
||||
@@ -2019,6 +2019,9 @@ Creature* Player::GetNPCIfCanInteractWith(ObjectGuid const& guid, NPCFlags npcFl
|
||||
if (!creature->IsWithinDistInMap(this, creature->GetCombatReach() + 4.0f))
|
||||
return nullptr;
|
||||
|
||||
if (!creature->IsInPhaseForInteraction(this))
|
||||
return nullptr;
|
||||
|
||||
return creature;
|
||||
}
|
||||
|
||||
@@ -2058,6 +2061,9 @@ GameObject* Player::GetGameObjectIfCanInteractWith(ObjectGuid const& guid) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!go->IsInPhaseForInteraction(this))
|
||||
return nullptr;
|
||||
|
||||
return go;
|
||||
}
|
||||
|
||||
@@ -25583,6 +25589,54 @@ void Player::UpdateTriggerVisibility()
|
||||
SendDirectMessage(&packet);
|
||||
}
|
||||
|
||||
void Player::UpdateVisibleObjectPhaseInteractions()
|
||||
{
|
||||
if (m_clientGUIDs.empty() || !IsInWorld())
|
||||
return;
|
||||
|
||||
UpdateData udata(GetMapId());
|
||||
WorldPacket packet;
|
||||
for (ObjectGuid visibleObjectGuid : m_clientGUIDs)
|
||||
{
|
||||
if (visibleObjectGuid.IsCreatureOrVehicle())
|
||||
{
|
||||
Creature* creature = ObjectAccessor::GetCreatureOrPetOrVehicle(*this, visibleObjectGuid);
|
||||
if (!creature)
|
||||
continue;
|
||||
|
||||
UF::ObjectData::Base objMask;
|
||||
UF::UnitData::Base unitMask;
|
||||
unitMask.MarkChanged(&UF::UnitData::Flags);
|
||||
unitMask.MarkChanged(&UF::UnitData::Flags2);
|
||||
if (creature->m_unitData->NpcFlags)
|
||||
unitMask.MarkChanged(&UF::UnitData::NpcFlags);
|
||||
if (creature->m_unitData->NpcFlags2)
|
||||
unitMask.MarkChanged(&UF::UnitData::NpcFlags2);
|
||||
if (creature->m_unitData->InteractSpellID || creature->m_unitData->NpcFlags & UNIT_NPC_FLAG_SPELLCLICK)
|
||||
unitMask.MarkChanged(&UF::UnitData::InteractSpellID);
|
||||
|
||||
creature->BuildValuesUpdateForPlayerWithMask(&udata, objMask.GetChangesMask(), unitMask.GetChangesMask(), this, false);
|
||||
}
|
||||
else if (visibleObjectGuid.IsAnyTypeGameObject())
|
||||
{
|
||||
GameObject* go = GetMap()->GetGameObject(visibleObjectGuid);
|
||||
if (!go)
|
||||
continue;
|
||||
|
||||
UF::ObjectData::Base objMask;
|
||||
UF::GameObjectData::Base goMask;
|
||||
objMask.MarkChanged(&UF::ObjectData::DynamicFlags);
|
||||
go->BuildValuesUpdateForPlayerWithMask(&udata, objMask.GetChangesMask(), goMask.GetChangesMask(), this, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!udata.HasData())
|
||||
return;
|
||||
|
||||
udata.BuildPacket(&packet);
|
||||
SendDirectMessage(&packet);
|
||||
}
|
||||
|
||||
void Player::SendInitialVisiblePackets(WorldObject* target) const
|
||||
{
|
||||
auto sendVignette = [](Vignettes::VignetteData const& vignette, Player const* where)
|
||||
@@ -32606,6 +32660,7 @@ std::string Player::GetCharacterSelectOutfit() const
|
||||
void Player::OnPhaseChange()
|
||||
{
|
||||
Unit::OnPhaseChange();
|
||||
UpdateVisibleObjectPhaseInteractions();
|
||||
|
||||
GetMap()->UpdatePersonalPhasesForPlayer(this);
|
||||
}
|
||||
|
||||
@@ -2759,6 +2759,7 @@ class TC_GAME_API Player final : public Unit, public GridObject<Player>
|
||||
void UpdateVisibilityOf(WorldObject* target);
|
||||
void UpdateVisibilityOf(Trinity::IteratorPair<WorldObject**> targets);
|
||||
void UpdateTriggerVisibility();
|
||||
void UpdateVisibleObjectPhaseInteractions();
|
||||
|
||||
template<class T>
|
||||
void UpdateVisibilityOf(T* target, UpdateData& data, std::set<WorldObject*>& visibleNow);
|
||||
|
||||
@@ -12556,6 +12556,15 @@ float Unit::MeleeSpellMissChance(Unit const* victim, WeaponAttackType attType, S
|
||||
|
||||
void Unit::OnPhaseChange()
|
||||
{
|
||||
ForceUpdateFieldChange(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::Flags));
|
||||
ForceUpdateFieldChange(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::Flags2));
|
||||
|
||||
if (m_unitData->NpcFlags)
|
||||
ForceUpdateFieldChange(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::NpcFlags));
|
||||
if (m_unitData->NpcFlags2)
|
||||
ForceUpdateFieldChange(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::NpcFlags2));
|
||||
if (m_unitData->InteractSpellID || m_unitData->NpcFlags & UNIT_NPC_FLAG_SPELLCLICK)
|
||||
ForceUpdateFieldChange(m_values.ModifyValue(&Unit::m_unitData).ModifyValue(&UF::UnitData::InteractSpellID));
|
||||
}
|
||||
|
||||
void Unit::UpdateObjectVisibility(bool forced)
|
||||
|
||||
@@ -101,6 +101,7 @@ void PhaseShift::ClearPhases()
|
||||
NonCosmeticReferences = 0;
|
||||
CosmeticReferences = 0;
|
||||
PersonalReferences = 0;
|
||||
ObjectsVisibleReferences = 0;
|
||||
DefaultReferences = 0;
|
||||
UpdateUnphasedFlag();
|
||||
}
|
||||
@@ -114,9 +115,9 @@ bool PhaseShift::CanSee(PhaseShift const& other) const
|
||||
if (Flags.HasFlag(PhaseShiftFlags::Inverse) && other.Flags.HasFlag(PhaseShiftFlags::Inverse))
|
||||
return true;
|
||||
|
||||
PhaseFlags excludePhasesWithFlag = PhaseFlags::None;
|
||||
PhaseFlags excludePhasesWithFlag = PhaseFlags::ObjectsVisible;
|
||||
if (Flags.HasFlag(PhaseShiftFlags::NoCosmetic) && other.Flags.HasFlag(PhaseShiftFlags::NoCosmetic))
|
||||
excludePhasesWithFlag = PhaseFlags::Cosmetic;
|
||||
excludePhasesWithFlag |= PhaseFlags::Cosmetic;
|
||||
|
||||
if (!Flags.HasFlag(PhaseShiftFlags::Inverse) && !other.Flags.HasFlag(PhaseShiftFlags::Inverse))
|
||||
{
|
||||
@@ -152,6 +153,21 @@ bool PhaseShift::CanSee(PhaseShift const& other) const
|
||||
return checkInversePhaseShift(other, *this);
|
||||
}
|
||||
|
||||
bool PhaseShift::CanInteractWith(PhaseShift const& other) const
|
||||
{
|
||||
if (!HasObjectsVisiblePhase())
|
||||
return true;
|
||||
|
||||
ObjectGuid ownerGuid = PersonalGuid;
|
||||
ObjectGuid otherPersonalGuid = other.PersonalGuid;
|
||||
return Trinity::Containers::Intersects(Phases.begin(), Phases.end(), other.Phases.begin(), other.Phases.end(),
|
||||
[&ownerGuid, &otherPersonalGuid](PhaseRef const& myPhase, PhaseRef const&)
|
||||
{
|
||||
return myPhase.Flags.HasFlag(PhaseFlags::ObjectsVisible)
|
||||
&& (!myPhase.Flags.HasFlag(PhaseFlags::Personal) || ownerGuid == otherPersonalGuid);
|
||||
});
|
||||
}
|
||||
|
||||
void PhaseShift::ModifyPhasesReferences(PhaseContainer::iterator itr, int32 references)
|
||||
{
|
||||
itr->References += references;
|
||||
@@ -160,6 +176,8 @@ void PhaseShift::ModifyPhasesReferences(PhaseContainer::iterator itr, int32 refe
|
||||
{
|
||||
if (itr->Flags.HasFlag(PhaseFlags::Cosmetic))
|
||||
CosmeticReferences += references;
|
||||
if (itr->Flags.HasFlag(PhaseFlags::ObjectsVisible))
|
||||
ObjectsVisibleReferences += references;
|
||||
else if (itr->Id != DEFAULT_PHASE)
|
||||
NonCosmeticReferences += references;
|
||||
else
|
||||
|
||||
@@ -43,9 +43,10 @@ enum class PhaseShiftFlags : uint32
|
||||
|
||||
enum class PhaseFlags : uint16
|
||||
{
|
||||
None = 0x0,
|
||||
Cosmetic = 0x1,
|
||||
Personal = 0x2
|
||||
None = 0x0,
|
||||
Cosmetic = 0x1,
|
||||
Personal = 0x2,
|
||||
ObjectsVisible = 0x4
|
||||
};
|
||||
|
||||
DEFINE_ENUM_FLAG(PhaseShiftFlags);
|
||||
@@ -114,8 +115,10 @@ public:
|
||||
void ClearPhases();
|
||||
|
||||
bool CanSee(PhaseShift const& other) const;
|
||||
bool CanInteractWith(PhaseShift const& other) const;
|
||||
|
||||
bool HasPersonalPhase() const;
|
||||
bool HasObjectsVisiblePhase() const { return ObjectsVisibleReferences > 0; }
|
||||
|
||||
protected:
|
||||
friend class PhasingHandler;
|
||||
@@ -132,6 +135,7 @@ protected:
|
||||
int32 NonCosmeticReferences = 0;
|
||||
int32 CosmeticReferences = 0;
|
||||
int32 PersonalReferences = 0;
|
||||
int32 ObjectsVisibleReferences = 0;
|
||||
int32 DefaultReferences = 0;
|
||||
bool IsDbPhaseShift = false;
|
||||
};
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "Map.h"
|
||||
#include "MapUtils.h"
|
||||
#include "MiscPackets.h"
|
||||
#include "GameObject.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "ObjectMgr.h"
|
||||
#include "PartyPackets.h"
|
||||
@@ -48,16 +49,20 @@ PhaseShift const AlwaysVisible = []
|
||||
|
||||
inline PhaseFlags GetPhaseFlags(uint32 phaseId)
|
||||
{
|
||||
PhaseFlags flags = PhaseFlags::None;
|
||||
if (PhaseEntry const* phase = sPhaseStore.LookupEntry(phaseId))
|
||||
{
|
||||
if (phase->GetFlags().HasFlag(PhaseEntryFlags::Cosmetic))
|
||||
return PhaseFlags::Cosmetic;
|
||||
flags |= PhaseFlags::Cosmetic;
|
||||
|
||||
if (phase->GetFlags().HasFlag(PhaseEntryFlags::Personal))
|
||||
return PhaseFlags::Personal;
|
||||
flags |= PhaseFlags::Personal;
|
||||
|
||||
if (phase->GetFlags().HasFlag(PhaseEntryFlags::ObjectsAreVisible))
|
||||
flags |= PhaseFlags::ObjectsVisible;
|
||||
}
|
||||
|
||||
return PhaseFlags::None;
|
||||
return flags;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,7 +554,8 @@ void PhasingHandler::InitDbPhaseShift(PhaseShift& phaseShift, uint8 phaseUseFlag
|
||||
for (uint32 phaseInGroup : *phasesInGroup)
|
||||
phaseShift.AddPhase(phaseInGroup, GetPhaseFlags(phaseInGroup), nullptr);
|
||||
|
||||
if (phaseShift.Phases.empty() || phaseShift.HasPhase(DEFAULT_PHASE))
|
||||
if (phaseShift.Phases.empty() || phaseShift.HasPhase(DEFAULT_PHASE)
|
||||
|| std::ranges::all_of(phaseShift.Phases, [](PhaseShift::PhaseRef const& phase) { return phase.Flags.HasFlag(PhaseFlags::ObjectsVisible); }))
|
||||
{
|
||||
if (flags.HasFlag(PhaseShiftFlags::Inverse))
|
||||
flags |= PhaseShiftFlags::InverseUnphased;
|
||||
@@ -697,6 +703,8 @@ void PhasingHandler::UpdateVisibilityIfNeeded(WorldObject* object, bool updateVi
|
||||
{
|
||||
if (Player* player = object->ToPlayer())
|
||||
SendToPlayer(player);
|
||||
else if (GameObject* gameObject = object->ToGameObject())
|
||||
gameObject->UpdateDynamicFlagsForNearbyPlayers();
|
||||
|
||||
if (updateVisibility)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user