Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2024-04-07 21:49:34 +08:00
45 changed files with 1497 additions and 755 deletions
@@ -113,6 +113,8 @@ void BattlegroundEY::AddPoints(TeamId teamId, uint32 points)
{
uint8 honorRewards = uint8(m_TeamScores[teamId] / _honorTics);
m_TeamScores[teamId] += points;
if (m_TeamScores[teamId] > BG_EY_MAX_TEAM_SCORE)
m_TeamScores[teamId] = BG_EY_MAX_TEAM_SCORE;
for (; honorRewards < uint8(m_TeamScores[teamId] / _honorTics); ++honorRewards)
RewardHonorToTeam(GetBonusHonorFromKill(1), teamId);
+15
View File
@@ -149,6 +149,7 @@ DBCStorage <ScalingStatValuesEntry> sScalingStatValuesStore(ScalingStatValuesfmt
DBCStorage <SkillLineEntry> sSkillLineStore(SkillLinefmt);
DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore(SkillLineAbilityfmt);
SkillLineAbilityIndexBySkillLine sSkillLineAbilityIndexBySkillLine;
DBCStorage <SkillRaceClassInfoEntry> sSkillRaceClassInfoStore(SkillRaceClassInfofmt);
SkillRaceClassInfoMap SkillRaceClassInfoBySkill;
DBCStorage <SkillTiersEntry> sSkillTiersStore(SkillTiersfmt);
@@ -473,6 +474,9 @@ void LoadDBCStores(const std::string& dataPath)
}
}
for (SkillLineAbilityEntry const* skillLine : sSkillLineAbilityStore)
sSkillLineAbilityIndexBySkillLine[skillLine->SkillLine].push_back(skillLine);
// Create Spelldifficulty searcher
for (SpellDifficultyEntry const* spellDiff : sSpellDifficultyStore)
{
@@ -945,3 +949,14 @@ EmotesTextSoundEntry const* FindTextSoundEmoteFor(uint32 emote, uint32 race, uin
auto itr = sEmotesTextSoundMap.find(EmotesTextSoundKey(emote, race, gender));
return itr != sEmotesTextSoundMap.end() ? itr->second : nullptr;
}
const std::vector<SkillLineAbilityEntry const*>& GetSkillLineAbilitiesBySkillLine(uint32 skillLine)
{
auto it = sSkillLineAbilityIndexBySkillLine.find(skillLine);
if (it == sSkillLineAbilityIndexBySkillLine.end())
{
static const std::vector<SkillLineAbilityEntry const*> emptyVector;
return emptyVector;
}
return it->second;
}
+3
View File
@@ -75,6 +75,8 @@ typedef std::pair<SkillRaceClassInfoMap::iterator, SkillRaceClassInfoMap::iterat
SkillRaceClassInfoEntry const* GetSkillRaceClassInfo(uint32 skill, uint8 race, uint8 class_);
EmotesTextSoundEntry const* FindTextSoundEmoteFor(uint32 emote, uint32 race, uint32 gender);
typedef std::unordered_map<uint32 /* SkillLine */, std::vector<SkillLineAbilityEntry const*> > SkillLineAbilityIndexBySkillLine;
const std::vector<SkillLineAbilityEntry const*>& GetSkillLineAbilitiesBySkillLine(uint32 skillLine);
extern DBCStorage <AchievementEntry> sAchievementStore;
extern DBCStorage <AchievementCriteriaEntry> sAchievementCriteriaStore;
@@ -157,6 +159,7 @@ extern DBCStorage <ScalingStatDistributionEntry> sScalingStatDistributionStore;
extern DBCStorage <ScalingStatValuesEntry> sScalingStatValuesStore;
extern DBCStorage <SkillLineEntry> sSkillLineStore;
extern DBCStorage <SkillLineAbilityEntry> sSkillLineAbilityStore;
extern SkillLineAbilityIndexBySkillLine sSkillLineAbilityIndexBySkillLine;
extern DBCStorage <SkillTiersEntry> sSkillTiersStore;
extern DBCStorage <SoundEntriesEntry> sSoundEntriesStore;
extern DBCStorage <SpellCastTimesEntry> sSpellCastTimesStore;
+1 -1
View File
@@ -198,7 +198,7 @@ void Corpse::ResetGhostTime()
m_time = GameTime::GetGameTime().count();
}
void Corpse::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const
void Corpse::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target)
{
if (!target)
return;
+1 -1
View File
@@ -54,7 +54,7 @@ public:
void AddToWorld() override;
void RemoveFromWorld() override;
void BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const override;
void BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) override;
bool Create(ObjectGuid::LowType guidlow);
bool Create(ObjectGuid::LowType guidlow, Player* owner);
@@ -2738,7 +2738,7 @@ GameObject* GameObject::GetLinkedTrap()
return ObjectAccessor::GetGameObject(*this, m_linkedTrap);
}
void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const
void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target)
{
if (!target)
return;
@@ -124,7 +124,7 @@ public:
explicit GameObject();
~GameObject() override;
void BuildValuesUpdate(uint8 updatetype, ByteBuffer* data, Player* target) const override;
void BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) override;
void AddToWorld() override;
void RemoveFromWorld() override;
@@ -166,7 +166,7 @@ void Bag::StoreItem(uint8 slot, Item* pItem, bool /*update*/)
}
}
void Bag::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const
void Bag::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target)
{
Item::BuildCreateUpdateBlockForPlayer(data, target);
@@ -55,7 +55,7 @@ public:
// overwrite virtual Item::DeleteFromDB
void DeleteFromDB(CharacterDatabaseTransaction trans) override;
void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const override;
void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) override;
std::string GetDebugInfo() const override;
+4 -4
View File
@@ -186,7 +186,7 @@ void Object::BuildMovementUpdateBlock(UpdateData* data, uint32 flags) const
data->AddUpdateBlock(buf);
}
void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const
void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target)
{
if (!target)
return;
@@ -254,7 +254,7 @@ void Object::SendUpdateToPlayer(Player* player)
player->GetSession()->SendPacket(&packet);
}
void Object::BuildValuesUpdateBlockForPlayer(UpdateData* data, Player* target) const
void Object::BuildValuesUpdateBlockForPlayer(UpdateData* data, Player* target)
{
ByteBuffer buf(500);
@@ -494,7 +494,7 @@ void Object::BuildMovementUpdate(ByteBuffer* data, uint16 flags) const
}
}
void Object::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const
void Object::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target)
{
if (!target)
return;
@@ -542,7 +542,7 @@ void Object::ClearUpdateMask(bool remove)
}
}
void Object::BuildFieldsUpdate(Player* player, UpdateDataMapType& data_map) const
void Object::BuildFieldsUpdate(Player* player, UpdateDataMapType& data_map)
{
UpdateDataMapType::iterator iter = data_map.find(player);
+4 -4
View File
@@ -121,10 +121,10 @@ public:
[[nodiscard]] TypeID GetTypeId() const { return m_objectTypeId; }
[[nodiscard]] bool isType(uint16 mask) const { return (mask & m_objectType); }
virtual void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const;
virtual void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target);
void SendUpdateToPlayer(Player* player);
void BuildValuesUpdateBlockForPlayer(UpdateData* data, Player* target) const;
void BuildValuesUpdateBlockForPlayer(UpdateData* data, Player* target);
void BuildOutOfRangeUpdateBlock(UpdateData* data) const;
void BuildMovementUpdateBlock(UpdateData* data, uint32 flags = 0) const;
@@ -183,7 +183,7 @@ public:
[[nodiscard]] virtual bool hasQuest(uint32 /* quest_id */) const { return false; }
[[nodiscard]] virtual bool hasInvolvedQuest(uint32 /* quest_id */) const { return false; }
virtual void BuildUpdate(UpdateDataMapType&, UpdatePlayerSet&) {}
void BuildFieldsUpdate(Player*, UpdateDataMapType&) const;
void BuildFieldsUpdate(Player*, UpdateDataMapType&);
void SetFieldNotifyFlag(uint16 flag) { _fieldNotifyFlags |= flag; }
void RemoveFieldNotifyFlag(uint16 flag) { _fieldNotifyFlags &= ~flag; }
@@ -223,7 +223,7 @@ protected:
uint32 GetUpdateFieldData(Player const* target, uint32*& flags) const;
void BuildMovementUpdate(ByteBuffer* data, uint16 flags) const;
virtual void BuildValuesUpdate(uint8 updatetype, ByteBuffer* data, Player* target) const;
virtual void BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target);
uint16 m_objectType;
+5 -12
View File
@@ -444,6 +444,7 @@ Player::~Player()
delete m_runes;
delete m_achievementMgr;
delete m_reputationMgr;
delete _cinematicMgr;
sWorld->DecreasePlayerCount();
@@ -3793,7 +3794,7 @@ Mail* Player::GetMail(uint32 id)
return nullptr;
}
void Player::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const
void Player::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target)
{
if (target == this)
{
@@ -5315,10 +5316,8 @@ void Player::SetSkill(uint16 id, uint16 step, uint16 newVal, uint16 maxVal)
mSkillStatus.erase(itr);
// remove all spells that related to this skill
for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j)
if (SkillLineAbilityEntry const* pAbility = sSkillLineAbilityStore.LookupEntry(j))
if (pAbility->SkillLine == id)
removeSpell(sSpellMgr->GetFirstSpellInChain(pAbility->Spell), SPEC_MASK_ALL, false);
for (SkillLineAbilityEntry const* pAbility : GetSkillLineAbilitiesBySkillLine(id))
removeSpell(sSpellMgr->GetFirstSpellInChain(pAbility->Spell), SPEC_MASK_ALL, false);
}
}
else if (newVal) //add
@@ -11937,14 +11936,8 @@ void Player::learnSkillRewardedSpells(uint32 skill_id, uint32 skill_value)
{
uint32 raceMask = getRaceMask();
uint32 classMask = getClassMask();
for (uint32 j = 0; j < sSkillLineAbilityStore.GetNumRows(); ++j)
for (SkillLineAbilityEntry const* pAbility : GetSkillLineAbilitiesBySkillLine(skill_id))
{
SkillLineAbilityEntry const* pAbility = sSkillLineAbilityStore.LookupEntry(j);
if (!pAbility || pAbility->SkillLine != skill_id)
{
continue;
}
SpellInfo const* spellInfo = sSpellMgr->GetSpellInfo(pAbility->Spell);
if (!spellInfo)
{
+1 -1
View File
@@ -1974,7 +1974,7 @@ public:
[[nodiscard]] WorldSession* GetSession() const { return m_session; }
void SetSession(WorldSession* sess) { m_session = sess; }
void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) const override;
void BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) override;
void DestroyForPlayer(Player* target, bool onDeath = false) const override;
void SendLogXPGain(uint32 GivenXP, Unit* victim, uint32 BonusXP, bool recruitAFriend = false, float group_rate = 1.0f);
+207 -133
View File
@@ -534,6 +534,8 @@ void Unit::Update(uint32 p_time)
UpdateSplineMovement(p_time);
GetMotionMaster()->UpdateMotion(p_time);
InvalidateValuesUpdateCache();
}
bool Unit::haveOffhandWeapon() const
@@ -21065,16 +21067,11 @@ void Unit::SendMovementHover(Player* sendTo)
sendTo->SendDirectMessage(&data);
}
void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const
void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target)
{
if (!target)
return;
ByteBuffer fieldBuffer;
UpdateMask updateMask;
updateMask.SetCount(m_valuesCount);
uint32* flags = UnitUpdateFieldFlags;
uint32 visibleFlag = UF_FLAG_PUBLIC;
@@ -21092,7 +21089,30 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target)
if (plr && plr->IsInSameRaidWith(target))
visibleFlag |= UF_FLAG_PARTY_MEMBER;
Creature const* creature = ToCreature();
uint64 cacheKey = static_cast<uint64>(visibleFlag) << 8 | updateType;
auto cacheIt = _valuesUpdateCache.find(cacheKey);
if (cacheIt != _valuesUpdateCache.end())
{
int32 cachePos = static_cast<int32>(data->wpos());
data->append(cacheIt->second.buffer);
BuildValuesCachePosPointers dataAdjustedPos = cacheIt->second.posPointers;
if (cachePos)
dataAdjustedPos.ApplyOffset(cachePos);
PatchValuesUpdate(*data, dataAdjustedPos, target);
return;
}
BuildValuesCachedBuffer cacheValue(500);
ByteBuffer fieldBuffer(400);
UpdateMask updateMask;
updateMask.SetCount(m_valuesCount);
for (uint16 index = 0; index < m_valuesCount; ++index)
{
if (_fieldNotifyFlags & flags[index] ||
@@ -21104,37 +21124,13 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target)
if (index == UNIT_NPC_FLAGS)
{
uint32 appendValue = m_uint32Values[UNIT_NPC_FLAGS];
if (creature)
{
if (sWorld->getIntConfig(CONFIG_INSTANT_TAXI) == 2 && appendValue & UNIT_NPC_FLAG_FLIGHTMASTER)
{
appendValue |= UNIT_NPC_FLAG_GOSSIP; // flight masters need NPC gossip flag to show instant flight toggle option
}
if (!target->CanSeeSpellClickOn(creature))
{
appendValue &= ~UNIT_NPC_FLAG_SPELLCLICK;
}
if (!target->CanSeeVendor(creature))
{
appendValue &= ~UNIT_NPC_FLAG_VENDOR_MASK;
}
if (!creature->IsValidTrainerForPlayer(target, &appendValue))
{
appendValue &= ~UNIT_NPC_FLAG_TRAINER;
}
}
fieldBuffer << uint32(appendValue);
cacheValue.posPointers.UnitNPCFlagsPos = int32(fieldBuffer.wpos());
fieldBuffer << m_uint32Values[UNIT_NPC_FLAGS];
}
else if (index == UNIT_FIELD_AURASTATE)
{
// Check per caster aura states to not enable using a spell in client if specified aura is not by target
fieldBuffer << BuildAuraStateUpdateForTarget(target);
cacheValue.posPointers.UnitFieldAuraStatePos = int32(fieldBuffer.wpos());
fieldBuffer << uint32(0); // Fill in later.
}
// FIXME: Some values at server stored in float format but must be sent to client in uint32 format
else if (index >= UNIT_FIELD_BASEATTACKTIME && index <= UNIT_FIELD_RANGEDATTACKTIME)
@@ -21153,115 +21149,35 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target)
// Gamemasters should be always able to select units - remove not selectable flag
else if (index == UNIT_FIELD_FLAGS)
{
uint32 appendValue = m_uint32Values[UNIT_FIELD_FLAGS];
if (target->IsGameMaster() && target->GetSession()->IsGMAccount())
appendValue &= ~UNIT_FLAG_NOT_SELECTABLE;
fieldBuffer << uint32(appendValue);
cacheValue.posPointers.UnitFieldFlagsPos = int32(fieldBuffer.wpos());
fieldBuffer << m_uint32Values[UNIT_FIELD_FLAGS];
}
// use modelid_a if not gm, _h if gm for CREATURE_FLAG_EXTRA_TRIGGER creatures
else if (index == UNIT_FIELD_DISPLAYID)
{
uint32 displayId = m_uint32Values[UNIT_FIELD_DISPLAYID];
if (creature)
{
CreatureTemplate const* cinfo = creature->GetCreatureTemplate();
// this also applies for transform auras
if (SpellInfo const* transform = sSpellMgr->GetSpellInfo(getTransForm()))
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if (transform->Effects[i].IsAura(SPELL_AURA_TRANSFORM))
if (CreatureTemplate const* transformInfo = sObjectMgr->GetCreatureTemplate(transform->Effects[i].MiscValue))
{
cinfo = transformInfo;
break;
}
if (cinfo->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER)
{
if (target->IsGameMaster() && target->GetSession()->IsGMAccount())
{
if (cinfo->Modelid1)
displayId = cinfo->Modelid1; // Modelid1 is a visible model for gms
else
displayId = 17519; // world visible trigger's model
}
else
{
if (cinfo->Modelid2)
displayId = cinfo->Modelid2; // Modelid2 is an invisible model for players
else
displayId = 11686; // world invisible trigger's model
}
}
}
fieldBuffer << uint32(displayId);
cacheValue.posPointers.UnitFieldDisplayPos = int32(fieldBuffer.wpos());
fieldBuffer << m_uint32Values[UNIT_FIELD_DISPLAYID];
}
// hide lootable animation for unallowed players
else if (index == UNIT_DYNAMIC_FLAGS)
{
cacheValue.posPointers.UnitDynamicFlagsPos = int32(fieldBuffer.wpos());
uint32 dynamicFlags = m_uint32Values[UNIT_DYNAMIC_FLAGS] & ~(UNIT_DYNFLAG_TAPPED | UNIT_DYNFLAG_TAPPED_BY_PLAYER);
if (creature)
{
if (creature->hasLootRecipient())
{
dynamicFlags |= UNIT_DYNFLAG_TAPPED;
if (creature->isTappedBy(target))
dynamicFlags |= UNIT_DYNFLAG_TAPPED_BY_PLAYER;
}
if (!target->isAllowedToLoot(creature))
dynamicFlags &= ~UNIT_DYNFLAG_LOOTABLE;
}
// unit UNIT_DYNFLAG_TRACK_UNIT should only be sent to caster of SPELL_AURA_MOD_STALKED auras
if (dynamicFlags & UNIT_DYNFLAG_TRACK_UNIT)
if (!HasAuraTypeWithCaster(SPELL_AURA_MOD_STALKED, target->GetGUID()))
dynamicFlags &= ~UNIT_DYNFLAG_TRACK_UNIT;
fieldBuffer << dynamicFlags;
}
// FG: pretend that OTHER players in own group are friendly ("blue")
else if (index == UNIT_FIELD_BYTES_2 || index == UNIT_FIELD_FACTIONTEMPLATE)
else if (index == UNIT_FIELD_BYTES_2)
{
if (IsControlledByPlayer() && target != this && sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && IsInRaidWith(target))
{
FactionTemplateEntry const* ft1 = GetFactionTemplateEntry();
FactionTemplateEntry const* ft2 = target->GetFactionTemplateEntry();
if (ft1 && ft2 && !ft1->IsFriendlyTo(*ft2))
{
if (index == UNIT_FIELD_BYTES_2)
// Allow targetting opposite faction in party when enabled in config
fieldBuffer << (m_uint32Values[UNIT_FIELD_BYTES_2] & ((UNIT_BYTE2_FLAG_SANCTUARY /*| UNIT_BYTE2_FLAG_AURAS | UNIT_BYTE2_FLAG_UNK5*/) << 8)); // this flag is at uint8 offset 1 !!
else
// pretend that all other HOSTILE players have own faction, to allow follow, heal, rezz (trade wont work)
fieldBuffer << uint32(target->GetFaction());
}
else
fieldBuffer << m_uint32Values[index];
}// pussywizard / Callmephil
else if (target->IsSpectator() && target->FindMap() && target->FindMap()->IsBattleArena() &&
(this->GetTypeId() == TYPEID_PLAYER || this->GetTypeId() == TYPEID_UNIT || this->GetTypeId() == TYPEID_DYNAMICOBJECT))
{
if (index == UNIT_FIELD_BYTES_2)
fieldBuffer << (m_uint32Values[index] & 0xFFFFF2FF); // clear UNIT_BYTE2_FLAG_PVP, UNIT_BYTE2_FLAG_FFA_PVP, UNIT_BYTE2_FLAG_SANCTUARY
else
fieldBuffer << (uint32)target->GetFaction();
}
else
if (!sScriptMgr->IsCustomBuildValuesUpdate(this, updateType, fieldBuffer, target, index))
{
fieldBuffer << m_uint32Values[index];
}
cacheValue.posPointers.UnitFieldBytes2Pos = int32(fieldBuffer.wpos());
fieldBuffer << m_uint32Values[index];
}
else if (index == UNIT_FIELD_FACTIONTEMPLATE)
{
cacheValue.posPointers.UnitFieldFactionTemplatePos = int32(fieldBuffer.wpos());
fieldBuffer << m_uint32Values[index];
}
else
{
if (sScriptMgr->OnBuildValuesUpdate(this, updateType, fieldBuffer, target, index))
{
continue;
}
if (sScriptMgr->ShouldTrackValuesUpdatePosByIndex(this, updateType, index))
cacheValue.posPointers.other[index] = static_cast<uint32>(fieldBuffer.wpos());
// send in current format (float as float, uint32 as uint32)
fieldBuffer << m_uint32Values[index];
@@ -21269,9 +21185,167 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target)
}
}
*data << uint8(updateMask.GetBlockCount());
updateMask.AppendToPacket(data);
data->append(fieldBuffer);
cacheValue.buffer << uint8(updateMask.GetBlockCount());
updateMask.AppendToPacket(&cacheValue.buffer);
int32 fieldBufferPos = static_cast<int32>(cacheValue.buffer.wpos());
cacheValue.buffer.append(fieldBuffer);
cacheValue.posPointers.ApplyOffset(fieldBufferPos);
int32 cachePos = static_cast<int32>(data->wpos());
data->append(cacheValue.buffer);
BuildValuesCachePosPointers dataAdjustedPos = cacheValue.posPointers;
if (cachePos)
dataAdjustedPos.ApplyOffset(cachePos);
PatchValuesUpdate(*data, dataAdjustedPos, target);
_valuesUpdateCache.insert(std::pair<uint64, BuildValuesCachedBuffer>(cacheKey, std::move(cacheValue)));
}
void Unit::PatchValuesUpdate(ByteBuffer& valuesUpdateBuf, BuildValuesCachePosPointers& posPointers, Player* target)
{
Creature const* creature = ToCreature();
// UNIT_NPC_FLAGS
if (creature && posPointers.UnitNPCFlagsPos >= 0)
{
uint32 appendValue = m_uint32Values[UNIT_NPC_FLAGS];
if (sWorld->getIntConfig(CONFIG_INSTANT_TAXI) == 2 && appendValue & UNIT_NPC_FLAG_FLIGHTMASTER)
appendValue |= UNIT_NPC_FLAG_GOSSIP; // flight masters need NPC gossip flag to show instant flight toggle option
if (!target->CanSeeSpellClickOn(creature))
appendValue &= ~UNIT_NPC_FLAG_SPELLCLICK;
if (!target->CanSeeVendor(creature))
appendValue &= ~UNIT_NPC_FLAG_VENDOR_MASK;
if (!creature->IsValidTrainerForPlayer(target, &appendValue))
appendValue &= ~UNIT_NPC_FLAG_TRAINER;
valuesUpdateBuf.put(posPointers.UnitNPCFlagsPos, appendValue);
}
// UNIT_FIELD_AURASTATE
if (posPointers.UnitFieldAuraStatePos >= 0)
valuesUpdateBuf.put(posPointers.UnitFieldAuraStatePos, uint32(BuildAuraStateUpdateForTarget(target)));
// UNIT_FIELD_FLAGS
if (posPointers.UnitFieldFlagsPos >= 0)
{
uint32 appendValue = m_uint32Values[UNIT_FIELD_FLAGS];
if (target->IsGameMaster() && target->GetSession()->IsGMAccount())
appendValue &= ~UNIT_FLAG_NOT_SELECTABLE;
valuesUpdateBuf.put(posPointers.UnitFieldFlagsPos, appendValue);
}
// UNIT_FIELD_DISPLAYID
// Use modelid_a if not gm, _h if gm for CREATURE_FLAG_EXTRA_TRIGGER creatures.
if (posPointers.UnitFieldDisplayPos >= 0)
{
uint32 displayId = m_uint32Values[UNIT_FIELD_DISPLAYID];
if (creature)
{
CreatureTemplate const* cinfo = creature->GetCreatureTemplate();
// this also applies for transform auras
if (SpellInfo const* transform = sSpellMgr->GetSpellInfo(getTransForm()))
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
if (transform->Effects[i].IsAura(SPELL_AURA_TRANSFORM))
if (CreatureTemplate const* transformInfo = sObjectMgr->GetCreatureTemplate(transform->Effects[i].MiscValue))
{
cinfo = transformInfo;
break;
}
if (cinfo->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER)
{
if (target->IsGameMaster() && target->GetSession()->IsGMAccount())
{
if (cinfo->Modelid1)
displayId = cinfo->Modelid1; // Modelid1 is a visible model for gms
else
displayId = 17519; // world visible trigger's model
}
else
{
if (cinfo->Modelid2)
displayId = cinfo->Modelid2; // Modelid2 is an invisible model for players
else
displayId = 11686; // world invisible trigger's model
}
}
}
valuesUpdateBuf.put(posPointers.UnitFieldDisplayPos, uint32(displayId));
}
// UNIT_DYNAMIC_FLAGS
// Hide lootable animation for unallowed players.
if (posPointers.UnitDynamicFlagsPos >= 0)
{
uint32 dynamicFlags = m_uint32Values[UNIT_DYNAMIC_FLAGS] & ~(UNIT_DYNFLAG_TAPPED | UNIT_DYNFLAG_TAPPED_BY_PLAYER);
if (creature)
{
if (creature->hasLootRecipient())
{
dynamicFlags |= UNIT_DYNFLAG_TAPPED;
if (creature->isTappedBy(target))
dynamicFlags |= UNIT_DYNFLAG_TAPPED_BY_PLAYER;
}
if (!target->isAllowedToLoot(creature))
dynamicFlags &= ~UNIT_DYNFLAG_LOOTABLE;
}
// unit UNIT_DYNFLAG_TRACK_UNIT should only be sent to caster of SPELL_AURA_MOD_STALKED auras
if (dynamicFlags & UNIT_DYNFLAG_TRACK_UNIT)
if (!HasAuraTypeWithCaster(SPELL_AURA_MOD_STALKED, target->GetGUID()))
dynamicFlags &= ~UNIT_DYNFLAG_TRACK_UNIT;
valuesUpdateBuf.put(posPointers.UnitDynamicFlagsPos, dynamicFlags);
}
// UNIT_FIELD_BYTES_2
if (posPointers.UnitFieldBytes2Pos >= 0)
{
if (IsControlledByPlayer() && target != this && sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && IsInRaidWith(target))
{
FactionTemplateEntry const* ft1 = GetFactionTemplateEntry();
FactionTemplateEntry const* ft2 = target->GetFactionTemplateEntry();
if (ft1 && ft2 && !ft1->IsFriendlyTo(*ft2))
// Allow targetting opposite faction in party when enabled in config
valuesUpdateBuf.put(posPointers.UnitFieldBytes2Pos, (m_uint32Values[UNIT_FIELD_BYTES_2] & ((UNIT_BYTE2_FLAG_SANCTUARY /*| UNIT_BYTE2_FLAG_AURAS | UNIT_BYTE2_FLAG_UNK5*/) << 8))); // this flag is at uint8 offset 1 !!
}// pussywizard / Callmephil
else if (target->IsSpectator() && target->FindMap() && target->FindMap()->IsBattleArena() &&
(this->GetTypeId() == TYPEID_PLAYER || this->GetTypeId() == TYPEID_UNIT || this->GetTypeId() == TYPEID_DYNAMICOBJECT))
{
valuesUpdateBuf.put(posPointers.UnitFieldBytes2Pos, (m_uint32Values[UNIT_FIELD_BYTES_2] & 0xFFFFF2FF)); // clear UNIT_BYTE2_FLAG_PVP, UNIT_BYTE2_FLAG_FFA_PVP, UNIT_BYTE2_FLAG_SANCTUARY
}
}
// UNIT_FIELD_FACTIONTEMPLATE
if (posPointers.UnitFieldFactionTemplatePos >= 0)
{
if (IsControlledByPlayer() && target != this && sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && IsInRaidWith(target))
{
FactionTemplateEntry const* ft1 = GetFactionTemplateEntry();
FactionTemplateEntry const* ft2 = target->GetFactionTemplateEntry();
if (ft1 && ft2 && !ft1->IsFriendlyTo(*ft2))
// pretend that all other HOSTILE players have own faction, to allow follow, heal, rezz (trade wont work)
valuesUpdateBuf.put(posPointers.UnitFieldFactionTemplatePos, uint32(target->GetFaction()));
}// pussywizard / Callmephil
else if (target->IsSpectator() && target->FindMap() && target->FindMap()->IsBattleArena() &&
(this->GetTypeId() == TYPEID_PLAYER || this->GetTypeId() == TYPEID_UNIT || this->GetTypeId() == TYPEID_DYNAMICOBJECT))
{
valuesUpdateBuf.put(posPointers.UnitFieldFactionTemplatePos, uint32(target->GetFaction()));
}
}
sScriptMgr->OnPatchValuesUpdate(this, valuesUpdateBuf, posPointers, target);
}
void Unit::BuildCooldownPacket(WorldPacket& data, uint8 flags, uint32 spellId, uint32 cooldown)
+63 -1
View File
@@ -1321,6 +1321,62 @@ private:
Unit* defaultValue;
};
// BuildValuesCachePosPointers is marks of the position of some data inside of BuildValue cache.
struct BuildValuesCachePosPointers
{
BuildValuesCachePosPointers() :
UnitNPCFlagsPos(-1), UnitFieldAuraStatePos(-1), UnitFieldFlagsPos(-1), UnitFieldDisplayPos(-1),
UnitDynamicFlagsPos(-1), UnitFieldBytes2Pos(-1), UnitFieldFactionTemplatePos(-1) {}
void ApplyOffset(uint32 offset)
{
if (UnitNPCFlagsPos >= 0)
UnitNPCFlagsPos += offset;
if (UnitFieldAuraStatePos >= 0)
UnitFieldAuraStatePos += offset;
if (UnitFieldFlagsPos >= 0)
UnitFieldFlagsPos += offset;
if (UnitFieldDisplayPos >= 0)
UnitFieldDisplayPos += offset;
if (UnitDynamicFlagsPos >= 0)
UnitDynamicFlagsPos += offset;
if (UnitFieldBytes2Pos >= 0)
UnitFieldBytes2Pos += offset;
if (UnitFieldFactionTemplatePos >= 0)
UnitFieldFactionTemplatePos += offset;
for (auto it = other.begin(); it != other.end(); ++it)
it->second += offset;
}
int32 UnitNPCFlagsPos;
int32 UnitFieldAuraStatePos;
int32 UnitFieldFlagsPos;
int32 UnitFieldDisplayPos;
int32 UnitDynamicFlagsPos;
int32 UnitFieldBytes2Pos;
int32 UnitFieldFactionTemplatePos;
std::unordered_map<uint16 /*index*/, uint32 /*pos*/> other;
};
// BuildValuesCachedBuffer cache for calculated BuildValue.
struct BuildValuesCachedBuffer
{
BuildValuesCachedBuffer(uint32 bufferSize) :
buffer(bufferSize), posPointers() {}
ByteBuffer buffer;
BuildValuesCachePosPointers posPointers;
};
class Unit : public WorldObject
{
public:
@@ -2511,7 +2567,7 @@ public:
protected:
explicit Unit (bool isWorldObject);
void BuildValuesUpdate(uint8 updatetype, ByteBuffer* data, Player* target) const override;
void BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) override;
UnitAI* i_AI, *i_disabledAI;
@@ -2604,6 +2660,9 @@ private:
[[nodiscard]] float GetCombatRatingReduction(CombatRating cr) const;
[[nodiscard]] uint32 GetCombatRatingDamageReduction(CombatRating cr, float rate, float cap, uint32 damage) const;
void PatchValuesUpdate(ByteBuffer& valuesUpdateBuf, BuildValuesCachePosPointers& posPointers, Player* target);
void InvalidateValuesUpdateCache() { _valuesUpdateCache.clear(); }
protected:
void SetFeared(bool apply, Unit* fearedBy = nullptr, bool isFear = false);
void SetConfused(bool apply);
@@ -2641,6 +2700,9 @@ private:
uint32 _lastExtraAttackSpell;
std::unordered_map<ObjectGuid /*guid*/, uint32 /*count*/> extraAttacksTargets;
ObjectGuid _lastDamagedTargetGuid;
typedef std::unordered_map<uint64 /*visibleFlag(uint32) + updateType(uint8)*/, BuildValuesCachedBuffer> ValuesUpdateCache;
ValuesUpdateCache _valuesUpdateCache;
};
namespace Acore
@@ -192,18 +192,24 @@ bool ScriptMgr::IsCustomBuildValuesUpdate(Unit const* unit, uint8 updateType, By
return false;
}
bool ScriptMgr::OnBuildValuesUpdate(Unit const* unit, uint8 updateType, ByteBuffer& fieldBuffer, Player* target, uint16 index)
bool ScriptMgr::ShouldTrackValuesUpdatePosByIndex(Unit const* unit, uint8 updateType, uint16 index)
{
auto ret = IsValidBoolScript<UnitScript>([&](UnitScript* script) { return script->OnBuildValuesUpdate(unit, updateType, fieldBuffer, target, index); });
auto ret = IsValidBoolScript<UnitScript>([&](UnitScript* script) { return script->ShouldTrackValuesUpdatePosByIndex(unit, updateType, index); });
if (ret && *ret)
{
return true;
}
return false;
}
void ScriptMgr::OnPatchValuesUpdate(Unit const* unit, ByteBuffer& valuesUpdateBuf, BuildValuesCachePosPointers& posPointers, Player* target)
{
ExecuteScript<UnitScript>([&](UnitScript* script)
{
script->OnPatchValuesUpdate(unit, valuesUpdateBuf, posPointers, target);
});
}
void ScriptMgr::OnUnitUpdate(Unit* unit, uint32 diff)
{
ExecuteScript<UnitScript>([&](UnitScript* script)
@@ -22,6 +22,7 @@
enum ReputationRank : uint8;
class ByteBuffer;
struct BuildValuesCachePosPointers;
class UnitScript : public ScriptObject
{
@@ -69,7 +70,9 @@ public:
[[nodiscard]] virtual bool IsCustomBuildValuesUpdate(Unit const* /*unit*/, uint8 /*updateType*/, ByteBuffer& /*fieldBuffer*/, Player const* /*target*/, uint16 /*index*/) { return false; }
[[nodiscard]] virtual bool OnBuildValuesUpdate(Unit const* /*unit*/, uint8 /*updateType*/, ByteBuffer& /*fieldBuffer*/, Player* /*target*/, uint16 /*index*/) { return false; }
[[nodiscard]] virtual bool ShouldTrackValuesUpdatePosByIndex(Unit const* /*unit*/, uint8 /*updateType*/, uint16 /*index*/) { return false; }
virtual void OnPatchValuesUpdate(Unit const* /*unit*/, ByteBuffer& /*valuesUpdateBuf*/, BuildValuesCachePosPointers& /*posPointers*/, Player* /*target*/) { }
/**
* @brief This hook runs in Unit::Update
+2 -1
View File
@@ -581,7 +581,8 @@ public: /* UnitScript */
bool IsNeedModHealPercent(Unit const* unit, AuraEffect* auraEff, float& doneTotalMod, SpellInfo const* spellProto);
bool CanSetPhaseMask(Unit const* unit, uint32 newPhaseMask, bool update);
bool IsCustomBuildValuesUpdate(Unit const* unit, uint8 updateType, ByteBuffer& fieldBuffer, Player const* target, uint16 index);
bool OnBuildValuesUpdate(Unit const* unit, uint8 updateType, ByteBuffer& fieldBuffer, Player* target, uint16 index);
bool ShouldTrackValuesUpdatePosByIndex(Unit const* unit, uint8 updateType, uint16 index);
void OnPatchValuesUpdate(Unit const* unit, ByteBuffer& valuesUpdateBuf, BuildValuesCachePosPointers& posPointers, Player* target);
void OnUnitUpdate(Unit* unit, uint32 diff);
void OnDisplayIdChange(Unit* unit, uint32 displayId);
void OnUnitEnterEvadeMode(Unit* unit, uint8 why);
+42 -32
View File
@@ -161,43 +161,53 @@ void WorldSocket::CheckIpCallback(PreparedQueryResult result)
bool WorldSocket::Update()
{
EncryptableAndCompressiblePacket* queued;
MessageBuffer buffer(_sendBufferSize);
while (_bufferQueue.Dequeue(queued))
if (_bufferQueue.Dequeue(queued))
{
queued->CompressIfNeeded();
ServerPktHeader header(queued->size() + 2, queued->GetOpcode());
if (queued->NeedsEncryption())
_authCrypt.EncryptSend(header.header, header.getHeaderLength());
if (buffer.GetRemainingSpace() < queued->size() + header.getHeaderLength())
// Allocate buffer only when it's needed but not on every Update() call.
MessageBuffer buffer(_sendBufferSize);
std::size_t currentPacketSize;
do
{
queued->CompressIfNeeded();
ServerPktHeader header(queued->size() + 2, queued->GetOpcode());
if (queued->NeedsEncryption())
_authCrypt.EncryptSend(header.header, header.getHeaderLength());
currentPacketSize = queued->size() + header.getHeaderLength();
if (buffer.GetRemainingSpace() < currentPacketSize)
{
QueuePacket(std::move(buffer));
buffer.Resize(_sendBufferSize);
}
if (buffer.GetRemainingSpace() >= currentPacketSize)
{
buffer.Write(header.header, header.getHeaderLength());
if (!queued->empty())
buffer.Write(queued->contents(), queued->size());
}
else // Single packet larger than current buffer size
{
// Resize buffer to fit current packet
buffer.Resize(currentPacketSize);
// Grow future buffers to current packet size if still below limit
if (currentPacketSize <= 65536)
_sendBufferSize = currentPacketSize;
buffer.Write(header.header, header.getHeaderLength());
if (!queued->empty())
buffer.Write(queued->contents(), queued->size());
}
delete queued;
} while (_bufferQueue.Dequeue(queued));
if (buffer.GetActiveSize() > 0)
QueuePacket(std::move(buffer));
buffer.Resize(_sendBufferSize);
}
if (buffer.GetRemainingSpace() >= queued->size() + header.getHeaderLength())
{
buffer.Write(header.header, header.getHeaderLength());
if (!queued->empty())
buffer.Write(queued->contents(), queued->size());
}
else // single packet larger than 4096 bytes
{
MessageBuffer packetBuffer(queued->size() + header.getHeaderLength());
packetBuffer.Write(header.header, header.getHeaderLength());
if (!queued->empty())
packetBuffer.Write(queued->contents(), queued->size());
QueuePacket(std::move(packetBuffer));
}
delete queued;
}
if (buffer.GetActiveSize() > 0)
QueuePacket(std::move(buffer));
if (!BaseSocket::Update())
return false;
+1 -12
View File
@@ -2323,19 +2323,8 @@ void SpellMgr::LoadPetLevelupSpellMap()
if (!creatureFamily->skillLine[j])
continue;
for (uint32 k = 0; k < sSkillLineAbilityStore.GetNumRows(); ++k)
for (SkillLineAbilityEntry const* skillLine : GetSkillLineAbilitiesBySkillLine(creatureFamily->skillLine[j]))
{
SkillLineAbilityEntry const* skillLine = sSkillLineAbilityStore.LookupEntry(k);
if (!skillLine)
continue;
//if (skillLine->skillId != creatureFamily->skillLine[0] &&
// (!creatureFamily->skillLine[1] || skillLine->skillId != creatureFamily->skillLine[1]))
// continue;
if (skillLine->SkillLine != creatureFamily->skillLine[j])
continue;
if (skillLine->AcquireMethod != SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN)
continue;