Core/Objects

* Split BuildValuesUpdate into separate virtual methods for every object type that does something special with update fields
* Removed _SetCreateBits/_SetUpdateBits to halve the amount of checks if field needs to be sent
This commit is contained in:
Shauren
2013-06-15 15:16:36 +02:00
parent a8a5239aad
commit fa75fe78bd
8 changed files with 302 additions and 333 deletions
+19 -306
View File
@@ -194,7 +194,7 @@ void Object::BuildMovementUpdateBlock(UpdateData* data, uint32 flags) const
buf << uint8(UPDATETYPE_MOVEMENT);
buf.append(GetPackGUID());
_BuildMovementUpdate(&buf, flags);
BuildMovementUpdate(&buf, flags);
data->AddUpdateBlock(buf);
}
@@ -254,12 +254,8 @@ void Object::BuildCreateUpdateBlockForPlayer(UpdateData* data, Player* target) c
buf.append(GetPackGUID());
buf << uint8(m_objectTypeId);
_BuildMovementUpdate(&buf, flags);
UpdateMask updateMask;
updateMask.SetCount(m_valuesCount);
_SetCreateBits(&updateMask, target);
_BuildValuesUpdate(updateType, &buf, &updateMask, target);
BuildMovementUpdate(&buf, flags);
BuildValuesUpdate(updateType, &buf, target);
data->AddUpdateBlock(buf);
}
@@ -281,11 +277,7 @@ void Object::BuildValuesUpdateBlockForPlayer(UpdateData* data, Player* target) c
buf << uint8(UPDATETYPE_VALUES);
buf.append(GetPackGUID());
UpdateMask updateMask;
updateMask.SetCount(m_valuesCount);
_SetUpdateBits(&updateMask, target);
_BuildValuesUpdate(UPDATETYPE_VALUES, &buf, &updateMask, target);
BuildValuesUpdate(UPDATETYPE_VALUES, &buf, target);
data->AddUpdateBlock(buf);
}
@@ -358,7 +350,7 @@ uint16 Object::GetUInt16Value(uint16 index, uint8 offset) const
return *(((uint16*)&m_uint32Values[index])+offset);
}
void Object::_BuildMovementUpdate(ByteBuffer* data, uint16 flags) const
void Object::BuildMovementUpdate(ByteBuffer* data, uint16 flags) const
{
Unit const* unit = NULL;
WorldObject const* object = NULL;
@@ -510,289 +502,31 @@ void Object::_BuildMovementUpdate(ByteBuffer* data, uint16 flags) const
*data << int64(ToGameObject()->GetRotation());
}
void Object::_BuildValuesUpdate(uint8 updateType, ByteBuffer* data, UpdateMask* updateMask, Player* target) const
void Object::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const
{
if (!target)
return;
bool IsActivateToQuest = false;
ByteBuffer fieldBuffer;
UpdateMask updateMask;
updateMask.SetCount(m_valuesCount);
// Before trying to convert to each type there is a check, so safe
Unit const* unit = ToUnit();
GameObject const* go = ToGameObject();
uint32* flags = NULL;
uint32 visibleFlag = GetUpdateFieldData(target, flags);
if (unit)
for (uint16 index = 0; index < m_valuesCount; ++index)
{
if (unit->HasFlag(UNIT_FIELD_AURASTATE, PER_CASTER_AURA_STATE_MASK))
updateMask->SetBit(UNIT_FIELD_AURASTATE);
}
else if (go)
{
if (updateType == UPDATETYPE_CREATE_OBJECT || updateType == UPDATETYPE_CREATE_OBJECT2)
if (_fieldNotifyFlags & flags[index] ||
((updateType == UPDATETYPE_VALUES ? _changesMask.GetBit(index) : m_uint32Values[index]) && (flags[index] & visibleFlag)))
{
if (!go->IsDynTransport())
{
if (go->ActivateToQuest(target) || target->IsGameMaster())
IsActivateToQuest = true;
if (go->GetGoArtKit())
updateMask->SetBit(GAMEOBJECT_BYTES_1);
}
}
else
{
if (!go->IsTransport())
{
if (go->ActivateToQuest(target) || target->IsGameMaster())
IsActivateToQuest = true;
updateMask->SetBit(GAMEOBJECT_BYTES_1);
if (go->GetGoType() == GAMEOBJECT_TYPE_CHEST && go->GetGOInfo()->chest.groupLootRules &&
go->HasLootRecipient())
{
updateMask->SetBit(GAMEOBJECT_FLAGS);
}
}
updateMask.SetBit(index);
fieldBuffer << m_uint32Values[index];
}
}
ASSERT(updateMask && updateMask->GetCount() == m_valuesCount);
*data << uint8(updateMask->GetBlockCount());
updateMask->AppendToPacket(data);
// 2 specialized loops for speed optimization in non-unit case
if (unit) // unit (creature/player) case
{
Creature const* creature = ToCreature();
for (uint16 index = 0; index < m_valuesCount; ++index)
{
if (updateMask->GetBit(index))
{
if (index == UNIT_NPC_FLAGS)
{
// remove custom flag before sending
uint32 appendValue = m_uint32Values[index];
if (GetTypeId() == TYPEID_UNIT)
{
if (!target->CanSeeSpellClickOn(this->ToCreature()))
appendValue &= ~UNIT_NPC_FLAG_SPELLCLICK;
}
*data << uint32(appendValue);
}
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
*data << unit->BuildAuraStateUpdateForTarget(target);
}
// 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)
{
// convert from float to uint32 and send
*data << uint32(m_floatValues[index] < 0 ? 0 : m_floatValues[index]);
}
// there are some float values which may be negative or can't get negative due to other checks
else if ((index >= UNIT_FIELD_NEGSTAT0 && index <= UNIT_FIELD_NEGSTAT4) ||
(index >= UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE && index <= (UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE + 6)) ||
(index >= UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE && index <= (UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + 6)) ||
(index >= UNIT_FIELD_POSSTAT0 && index <= UNIT_FIELD_POSSTAT4))
{
*data << uint32(m_floatValues[index]);
}
// Gamemasters should be always able to select units - remove not selectable flag
else if (index == UNIT_FIELD_FLAGS)
{
if (target->IsGameMaster())
*data << (m_uint32Values[index] & ~UNIT_FLAG_NOT_SELECTABLE);
else
*data << m_uint32Values[index];
}
// use modelid_a if not gm, _h if gm for CREATURE_FLAG_EXTRA_TRIGGER creatures
else if (index == UNIT_FIELD_DISPLAYID)
{
if (GetTypeId() == TYPEID_UNIT)
{
CreatureTemplate const* cinfo = creature->GetCreatureTemplate();
// this also applies for transform auras
if (SpellInfo const* transform = sSpellMgr->GetSpellInfo(ToUnit()->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())
{
if (cinfo->Modelid1)
*data << cinfo->Modelid1;//Modelid1 is a visible model for gms
else
*data << 17519; // world invisible trigger's model
}
else
{
if (cinfo->Modelid2)
*data << cinfo->Modelid2;//Modelid2 is an invisible model for players
else
*data << 11686; // world invisible trigger's model
}
}
else
*data << m_uint32Values[index];
}
else
*data << m_uint32Values[index];
}
// hide lootable animation for unallowed players
else if (index == UNIT_DYNAMIC_FLAGS)
{
uint32 dynamicFlags = m_uint32Values[index];
if (creature)
{
if (creature->hasLootRecipient())
{
if (creature->isTappedBy(target))
{
dynamicFlags |= (UNIT_DYNFLAG_TAPPED | UNIT_DYNFLAG_TAPPED_BY_PLAYER);
}
else
{
dynamicFlags |= UNIT_DYNFLAG_TAPPED;
dynamicFlags &= ~UNIT_DYNFLAG_TAPPED_BY_PLAYER;
}
}
else
{
dynamicFlags &= ~UNIT_DYNFLAG_TAPPED;
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 (!unit->HasAuraTypeWithCaster(SPELL_AURA_MOD_STALKED, target->GetGUID()))
dynamicFlags &= ~UNIT_DYNFLAG_TRACK_UNIT;
*data << dynamicFlags;
}
// FG: pretend that OTHER players in own group are friendly ("blue")
else if (index == UNIT_FIELD_BYTES_2 || index == UNIT_FIELD_FACTIONTEMPLATE)
{
if (unit->IsControlledByPlayer() && target != this && sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_GROUP) && unit->IsInRaidWith(target))
{
FactionTemplateEntry const* ft1 = unit->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
*data << (m_uint32Values[index] & ((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)
uint32 faction = target->getFaction();
*data << uint32(faction);
}
}
else
*data << m_uint32Values[index];
}
else
*data << m_uint32Values[index];
}
else
{
// send in current format (float as float, uint32 as uint32)
*data << m_uint32Values[index];
}
}
}
}
else if (go) // gameobject case
{
for (uint16 index = 0; index < m_valuesCount; ++index)
{
if (updateMask->GetBit(index))
{
// send in current format (float as float, uint32 as uint32)
if (index == GAMEOBJECT_DYNAMIC)
{
if (IsActivateToQuest)
{
switch (go->GetGoType())
{
case GAMEOBJECT_TYPE_CHEST:
if (target->IsGameMaster())
*data << uint16(GO_DYNFLAG_LO_ACTIVATE);
else
*data << uint16(GO_DYNFLAG_LO_ACTIVATE | GO_DYNFLAG_LO_SPARKLE);
*data << uint16(-1);
break;
case GAMEOBJECT_TYPE_GENERIC:
if (target->IsGameMaster())
*data << uint16(0);
else
*data << uint16(GO_DYNFLAG_LO_SPARKLE);
*data << uint16(-1);
break;
case GAMEOBJECT_TYPE_GOOBER:
if (target->IsGameMaster())
*data << uint16(GO_DYNFLAG_LO_ACTIVATE);
else
*data << uint16(GO_DYNFLAG_LO_ACTIVATE | GO_DYNFLAG_LO_SPARKLE);
*data << uint16(-1);
break;
default:
// unknown, not happen.
*data << uint16(0);
*data << uint16(-1);
break;
}
}
else
{
// disable quest object
*data << uint16(0);
*data << uint16(-1);
}
}
else if (index == GAMEOBJECT_FLAGS)
{
uint32 flags = m_uint32Values[index];
if (go->GetGoType() == GAMEOBJECT_TYPE_CHEST)
if (go->GetGOInfo()->chest.groupLootRules && !go->IsLootAllowedFor(target))
flags |= GO_FLAG_LOCKED | GO_FLAG_NOT_SELECTABLE;
*data << flags;
}
else
*data << m_uint32Values[index]; // other cases
}
}
}
else // other objects case (no special index checks)
{
for (uint16 index = 0; index < m_valuesCount; ++index)
{
if (updateMask->GetBit(index))
{
// send in current format (float as float, uint32 as uint32)
*data << m_uint32Values[index];
}
}
}
*data << uint8(updateMask.GetBlockCount());
updateMask.AppendToPacket(data);
data->append(fieldBuffer);
}
void Object::ClearUpdateMask(bool remove)
@@ -891,27 +625,6 @@ void Object::_LoadIntoDataField(std::string const& data, uint32 startOffset, uin
}
}
void Object::_SetUpdateBits(UpdateMask* updateMask, Player* target) const
{
uint32* flags = NULL;
uint32 visibleFlag = GetUpdateFieldData(target, flags);
for (uint16 index = 0; index < m_valuesCount; ++index)
if (_fieldNotifyFlags & flags[index] || ((flags[index] & visibleFlag) & UF_FLAG_SPECIAL_INFO) || (_changesMask.GetBit(index) && (flags[index] & visibleFlag)))
updateMask->SetBit(index);
}
void Object::_SetCreateBits(UpdateMask* updateMask, Player* target) const
{
uint32* value = m_uint32Values;
uint32* flags = NULL;
uint32 visibleFlag = GetUpdateFieldData(target, flags);
for (uint16 index = 0; index < m_valuesCount; ++index, ++value)
if (_fieldNotifyFlags & flags[index] || ((flags[index] & visibleFlag) & UF_FLAG_SPECIAL_INFO) || (*value && (flags[index] & visibleFlag)))
updateMask->SetBit(index);
}
void Object::SetInt32Value(uint16 index, int32 value)
{
ASSERT(index < m_valuesCount || PrintIndexError(index, true));