diff options
Diffstat (limited to 'src')
40 files changed, 416 insertions, 431 deletions
diff --git a/src/common/Collision/Management/MMapManager.cpp b/src/common/Collision/Management/MMapManager.cpp index 486219b9f32..2a7dfd7668b 100644 --- a/src/common/Collision/Management/MMapManager.cpp +++ b/src/common/Collision/Management/MMapManager.cpp @@ -179,7 +179,7 @@ namespace MMAP dtTileRef tileRef = 0; // memory allocated for data is now managed by detour, and will be deallocated when the tile is removed - if (dtStatusSucceed(mmap->navMesh->addTile(data, fileHeader.size, DT_TILE_FREE_DATA, 0, &tileRef))) + if (dtStatusSucceed(mmap->navMesh->addTile(data, fileHeader.size, 0, 0, &tileRef))) { mmap->loadedTileRefs.insert(std::pair<uint32, dtTileRef>(packedGridPos, tileRef)); ++loadedTiles; @@ -187,7 +187,10 @@ namespace MMAP PhaseChildMapContainer::const_iterator phasedMaps = phaseMapData.find(mapId); if (phasedMaps != phaseMapData.end()) + { + mmap->AddBaseTile(packedGridPos, data, fileHeader, fileHeader.size); LoadPhaseTiles(phasedMaps, x, y); + } return true; } @@ -279,7 +282,7 @@ namespace MMAP if (dataItr != phasedTileItr->second.end()) { TC_LOG_DEBUG("phase", "MMAP:UnloadPhaseTile: Unloaded phased %04u%02i%02i.mmtile for root phase map %u", phaseMapId, x, y, phasedMapData->first); - delete dataItr->second->data; + dtFree(dataItr->second->data); delete dataItr->second; phasedTileItr->second.erase(dataItr); } @@ -311,7 +314,8 @@ namespace MMAP dtTileRef tileRef = mmap->loadedTileRefs[packedGridPos]; // unload, and mark as non loaded - if (dtStatusFailed(mmap->navMesh->removeTile(tileRef, NULL, NULL))) + unsigned char* data = NULL; + if (dtStatusFailed(mmap->navMesh->removeTile(tileRef, &data, NULL))) { // this is technically a memory leak // if the grid is later reloaded, dtNavMesh::addTile will return error but no extra memory is used @@ -327,7 +331,12 @@ namespace MMAP PhaseChildMapContainer::const_iterator phasedMaps = phaseMapData.find(mapId); if (phasedMaps != phaseMapData.end()) + { + mmap->DeleteBaseTile(packedGridPos); UnloadPhaseTile(phasedMaps, x, y); + } + else + dtFree(data); return true; } @@ -350,13 +359,19 @@ namespace MMAP { uint32 x = (i->first >> 16); uint32 y = (i->first & 0x0000FFFF); - if (dtStatusFailed(mmap->navMesh->removeTile(i->second, NULL, NULL))) + unsigned char* data = NULL; + if (dtStatusFailed(mmap->navMesh->removeTile(i->second, &data, NULL))) TC_LOG_ERROR("maps", "MMAP:unloadMap: Could not unload %04u%02i%02i.mmtile from navmesh", mapId, x, y); else { PhaseChildMapContainer::const_iterator phasedMaps = phaseMapData.find(mapId); if (phasedMaps != phaseMapData.end()) + { + mmap->DeleteBaseTile(i->first); UnloadPhaseTile(phasedMaps, x, y); + } + else + dtFree(data); --loadedTiles; TC_LOG_DEBUG("maps", "MMAP:unloadMap: Unloaded mmtile %04i[%02i, %02i] from %04i", mapId, x, y, mapId); } @@ -443,12 +458,6 @@ namespace MMAP dtFreeNavMeshQuery(i->second); dtFreeNavMesh(navMesh); - - for (PhaseTileContainer::iterator i = _baseTiles.begin(); i != _baseTiles.end(); ++i) - { - delete (*i).second->data; - delete (*i).second; - } } void MMapData::RemoveSwap(PhasedTile* ptile, uint32 swap, uint32 packedXY) @@ -472,9 +481,7 @@ namespace MMAP // restore base tile if (dtStatusSucceed(navMesh->addTile(_baseTiles[packedXY]->data, _baseTiles[packedXY]->dataSize, 0, 0, &loadedTileRefs[packedXY]))) - { TC_LOG_DEBUG("phase", "MMapData::RemoveSwap: Loaded base mmtile %04u[%02i, %02i] into %04i[%02i, %02i]", _mapId, x, y, _mapId, header->x, header->y); - } else TC_LOG_ERROR("phase", "MMapData::RemoveSwap: Could not load base %04u%02i%02i.mmtile to navmesh", _mapId, x, y); } @@ -490,7 +497,6 @@ namespace MMAP void MMapData::AddSwap(PhasedTile* ptile, uint32 swap, uint32 packedXY) { - uint32 x = (packedXY >> 16); uint32 y = (packedXY & 0x0000FFFF); @@ -505,7 +511,6 @@ namespace MMAP return; } - dtMeshHeader* header = (dtMeshHeader*)ptile->data; const dtMeshTile* oldTile = navMesh->getTileByRef(loadedTileRefs[packedXY]); @@ -520,30 +525,19 @@ namespace MMAP header->x = oldTile->header->x; header->y = oldTile->header->y; - // the removed tile's data - PhasedTile* pt = new PhasedTile(); // remove old tile - if (dtStatusFailed(navMesh->removeTile(loadedTileRefs[packedXY], &pt->data, &pt->dataSize))) - { + if (dtStatusFailed(navMesh->removeTile(loadedTileRefs[packedXY], NULL, NULL))) TC_LOG_ERROR("phase", "MMapData::AddSwap: Could not unload %04u%02i%02i.mmtile from navmesh", _mapId, x, y); - delete pt; - } else { TC_LOG_DEBUG("phase", "MMapData::AddSwap: Unloaded %04u%02i%02i.mmtile from navmesh", _mapId, x, y); - // store the removed data first time, this is the origonal, non-phased tile - if (_baseTiles.find(packedXY) == _baseTiles.end()) - _baseTiles[packedXY] = pt; - _activeSwaps.insert(swap); loadedPhasedTiles[swap].insert(packedXY); // add new swapped tile if (dtStatusSucceed(navMesh->addTile(ptile->data, ptile->fileHeader.size, 0, 0, &loadedTileRefs[packedXY]))) - { TC_LOG_DEBUG("phase", "MMapData::AddSwap: Loaded phased mmtile %04u[%02i, %02i] into %04i[%02i, %02i]", swap, x, y, _mapId, header->x, header->y); - } else TC_LOG_ERROR("phase", "MMapData::AddSwap: Could not load %04u%02i%02i.mmtile to navmesh", swap, x, y); } @@ -576,4 +570,28 @@ namespace MMAP return navMesh; } + + void MMapData::AddBaseTile(uint32 packedGridPos, unsigned char* data, MmapTileHeader const& fileHeader, int32 dataSize) + { + auto itr = _baseTiles.find(packedGridPos); + if (itr == _baseTiles.end()) + { + PhasedTile* pt = new PhasedTile(); + pt->data = data; + pt->fileHeader = fileHeader; + pt->dataSize = dataSize; + _baseTiles[packedGridPos] = pt; + } + } + + void MMapData::DeleteBaseTile(uint32 packedGridPos) + { + auto itr = _baseTiles.find(packedGridPos); + if (itr != _baseTiles.end()) + { + dtFree(itr->second->data); + delete itr->second; + _baseTiles.erase(itr); + } + } } diff --git a/src/common/Collision/Management/MMapManager.h b/src/common/Collision/Management/MMapManager.h index bcc19b92a4e..f3ea5873c9b 100644 --- a/src/common/Collision/Management/MMapManager.h +++ b/src/common/Collision/Management/MMapManager.h @@ -70,6 +70,9 @@ namespace MMAP dtNavMesh* GetNavMesh(TerrainSet swaps); + void AddBaseTile(uint32 packedGridPos, unsigned char* data, MmapTileHeader const& fileHeader, int32 dataSize); + void DeleteBaseTile(uint32 packedGridPos); + // we have to use single dtNavMeshQuery for every instance, since those are not thread safe NavMeshQuerySet navMeshQueries; // instanceId to query diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp index 85a93bd91c2..28f1308b57f 100644 --- a/src/server/game/AI/CoreAI/UnitAI.cpp +++ b/src/server/game/AI/CoreAI/UnitAI.cpp @@ -243,28 +243,64 @@ bool SpellTargetSelector::operator()(Unit const* target) const return false; // copypasta from Spell::CheckRange - uint32 range_type = _spellInfo->RangeEntry ? _spellInfo->RangeEntry->Flags : 0; - float max_range = _caster->GetSpellMaxRangeForTarget(target, _spellInfo); - float min_range = _caster->GetSpellMinRangeForTarget(target, _spellInfo); + float minRange = 0.0f; + float maxRange = 0.0f; + float rangeMod = 0.0f; + if (_spellInfo->RangeEntry) + { + if (_spellInfo->RangeEntry->Flags & SPELL_RANGE_MELEE) + { + rangeMod = _caster->GetCombatReach() + 4.0f / 3.0f; + if (target) + rangeMod += target->GetCombatReach(); + else + rangeMod += _caster->GetCombatReach(); + + rangeMod = std::max(rangeMod, NOMINAL_MELEE_RANGE); + } + else + { + float meleeRange = 0.0f; + if (_spellInfo->RangeEntry->Flags & SPELL_RANGE_RANGED) + { + meleeRange = _caster->GetCombatReach() + 4.0f / 3.0f; + if (target) + meleeRange += target->GetCombatReach(); + else + meleeRange += _caster->GetCombatReach(); + + meleeRange = std::max(meleeRange, NOMINAL_MELEE_RANGE); + } + + minRange = _caster->GetSpellMinRangeForTarget(target, _spellInfo) + meleeRange; + maxRange = _caster->GetSpellMaxRangeForTarget(target, _spellInfo); + if (target) + { + rangeMod = _caster->GetCombatReach(); + rangeMod += target->GetCombatReach(); + + if (minRange > 0.0f && !(_spellInfo->RangeEntry->Flags & SPELL_RANGE_RANGED)) + minRange += rangeMod; + } + } + + if (target && _caster->isMoving() && target->isMoving() && !_caster->IsWalking() && !target->IsWalking() && + (_spellInfo->RangeEntry->Flags & SPELL_RANGE_MELEE || target->GetTypeId() == TYPEID_PLAYER)) + rangeMod += 5.0f / 3.0f; + } + + maxRange += rangeMod; + + minRange *= minRange; + maxRange *= maxRange; if (target && target != _caster) { - if (range_type == SPELL_RANGE_MELEE) - { - // Because of lag, we can not check too strictly here. - if (!_caster->IsWithinMeleeRange(target, max_range)) - return false; - } - else if (!_caster->IsWithinCombatRange(target, max_range)) + if (_caster->GetExactDistSq(target) > maxRange) return false; - if (range_type == SPELL_RANGE_RANGED) - { - if (_caster->IsWithinMeleeRange(target)) - return false; - } - else if (min_range && _caster->IsWithinCombatRange(target, min_range)) // skip this check if min_range = 0 + if (minRange > 0.0f && _caster->GetExactDistSq(target) < minRange) return false; } diff --git a/src/server/game/Entities/Corpse/Corpse.cpp b/src/server/game/Entities/Corpse/Corpse.cpp index 6e0aa99e1c1..d09b417a0b5 100644 --- a/src/server/game/Entities/Corpse/Corpse.cpp +++ b/src/server/game/Entities/Corpse/Corpse.cpp @@ -19,7 +19,6 @@ #include "Common.h" #include "Corpse.h" #include "Player.h" -#include "UpdateMask.h" #include "ObjectAccessor.h" #include "DatabaseEnv.h" diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index d80c2eabe3b..a69f8edda04 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -21,7 +21,6 @@ #include "Common.h" #include "Unit.h" -#include "UpdateMask.h" #include "ItemTemplate.h" #include "LootMgr.h" #include "DatabaseEnv.h" diff --git a/src/server/game/Entities/DynamicObject/DynamicObject.cpp b/src/server/game/Entities/DynamicObject/DynamicObject.cpp index 25684b44db6..793bbcd656e 100644 --- a/src/server/game/Entities/DynamicObject/DynamicObject.cpp +++ b/src/server/game/Entities/DynamicObject/DynamicObject.cpp @@ -17,7 +17,6 @@ */ #include "Common.h" -#include "UpdateMask.h" #include "Opcodes.h" #include "World.h" #include "ObjectAccessor.h" diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index 6ea2dfef591..1ca20e0c4cc 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -34,6 +34,7 @@ #include "UpdateFieldFlags.h" #include "World.h" #include "Transport.h" +#include <boost/dynamic_bitset.hpp> GameObject::GameObject() : WorldObject(false), MapObject(), m_model(NULL), m_goValue(), m_AI(NULL), _animKitId(0) @@ -2302,23 +2303,24 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t bool forcedFlags = GetGoType() == GAMEOBJECT_TYPE_CHEST && GetGOInfo()->chest.usegrouplootrules && HasLootRecipient(); bool targetIsGM = target->IsGameMaster(); - ByteBuffer fieldBuffer; - - UpdateMask updateMask; - updateMask.SetCount(m_valuesCount); + boost::dynamic_bitset<uint32> updateMask(m_valuesCount); uint32* flags = GameObjectUpdateFieldFlags; uint32 visibleFlag = UF_FLAG_PUBLIC; if (GetOwnerGUID() == target->GetGUID()) visibleFlag |= UF_FLAG_OWNER; + *data << uint8(updateMask.num_blocks()); + std::size_t maskPos = data->wpos(); + data->resize(data->size() + updateMask.num_blocks() * sizeof(uint32)); + for (uint16 index = 0; index < m_valuesCount; ++index) { if (_fieldNotifyFlags & flags[index] || - ((updateType == UPDATETYPE_VALUES ? _changesMask.GetBit(index) : m_uint32Values[index]) && (flags[index] & visibleFlag)) || + ((updateType == UPDATETYPE_VALUES ? _changesMask[index] : m_uint32Values[index]) && (flags[index] & visibleFlag)) || (index == GAMEOBJECT_FLAGS && forcedFlags)) { - updateMask.SetBit(index); + updateMask.set(index); if (index == OBJECT_DYNAMIC_FLAGS) { @@ -2355,8 +2357,8 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t break; } - fieldBuffer << uint16(dynFlags); - fieldBuffer << int16(pathProgress); + *data << uint16(dynFlags); + *data << int16(pathProgress); } else if (index == GAMEOBJECT_FLAGS) { @@ -2365,14 +2367,14 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t if (GetGOInfo()->chest.usegrouplootrules && !IsLootAllowedFor(target)) goFlags |= GO_FLAG_LOCKED | GO_FLAG_NOT_SELECTABLE; - fieldBuffer << goFlags; + *data << goFlags; } else if (index == GAMEOBJECT_LEVEL) { if (isStoppableTransport) - fieldBuffer << uint32(m_goValue.Transport.PathProgress); + *data << uint32(m_goValue.Transport.PathProgress); else - fieldBuffer << m_uint32Values[index]; + *data << m_uint32Values[index]; } else if (index == GAMEOBJECT_BYTES_1) { @@ -2386,16 +2388,14 @@ void GameObject::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* t } } - fieldBuffer << bytes1; + *data << bytes1; } else - fieldBuffer << m_uint32Values[index]; // other cases + *data << m_uint32Values[index]; // other cases } } - *data << uint8(updateMask.GetBlockCount()); - updateMask.AppendToPacket(data); - data->append(fieldBuffer); + boost::to_block_range(updateMask, reinterpret_cast<uint32*>(data->contents() + maskPos)); } void GameObject::GetRespawnPosition(float &x, float &y, float &z, float* ori /* = NULL*/) const diff --git a/src/server/game/Entities/Item/Item.cpp b/src/server/game/Entities/Item/Item.cpp index 103eee0d1f0..73bdbf37a93 100644 --- a/src/server/game/Entities/Item/Item.cpp +++ b/src/server/game/Entities/Item/Item.cpp @@ -33,6 +33,7 @@ #include "TradeData.h" #include "GameTables.h" #include "CollectionMgr.h" +#include <boost/dynamic_bitset.hpp> void AddItemsSetItem(Player* player, Item* item) { @@ -283,7 +284,6 @@ Item::Item() m_paidMoney = 0; m_paidExtendedCost = 0; - memset(_modifiers, 0, sizeof(_modifiers)); memset(&_bonusData, 0, sizeof(_bonusData)); } @@ -1199,59 +1199,58 @@ void Item::BuildDynamicValuesUpdate(uint8 updateType, ByteBuffer* data, Player* if (!target) return; - ByteBuffer fieldBuffer; - UpdateMask updateMask; - updateMask.SetCount(_dynamicValuesCount); + boost::dynamic_bitset<uint32> updateMask(_dynamicValuesCount); uint32* flags = nullptr; uint32 visibleFlag = GetDynamicUpdateFieldData(target, flags); + *data << uint8(updateMask.num_blocks()); + std::size_t maskPos = data->wpos(); + data->resize(data->size() + updateMask.num_blocks() * sizeof(uint32)); + for (uint16 index = 0; index < _dynamicValuesCount; ++index) { - ByteBuffer buffer; std::vector<uint32> const& values = _dynamicValues[index]; if (_fieldNotifyFlags & flags[index] || - ((updateType == UPDATETYPE_VALUES ? _dynamicChangesMask.GetBit(index) : !values.empty()) && (flags[index] & visibleFlag)) || - (index == ITEM_DYNAMIC_FIELD_MODIFIERS && (updateType == UPDATETYPE_VALUES ? _changesMask.GetBit(ITEM_FIELD_MODIFIERS_MASK) : GetUInt32Value(ITEM_FIELD_MODIFIERS_MASK) != 0))) + ((updateType == UPDATETYPE_VALUES ? _dynamicChangesMask[index] : !values.empty()) && (flags[index] & visibleFlag))) { - updateMask.SetBit(index); + updateMask.set(index); - UpdateMask arrayMask; + boost::dynamic_bitset<uint32> arrayMask(values.size()); + *data << uint16(arrayMask.num_blocks()); + std::size_t fieldMaskPos = data->wpos(); + data->resize(data->size() + arrayMask.num_blocks() * sizeof(uint32)); if (index != ITEM_DYNAMIC_FIELD_MODIFIERS) { - arrayMask.SetCount(values.size()); for (std::size_t v = 0; v < values.size(); ++v) { - if (updateType == UPDATETYPE_VALUES ? _dynamicChangesArrayMask[index].GetBit(v) : values[v]) + if (updateType == UPDATETYPE_VALUES ? _dynamicChangesArrayMask[index][v] : values[v]) { - arrayMask.SetBit(v); - buffer << uint32(values[v]); + arrayMask.set(v); + *data << uint32(values[v]); } } + } else { - uint32 count = 0; - arrayMask.SetCount(MAX_ITEM_MODIFIERS); - for (uint32 v = 0; v < MAX_ITEM_MODIFIERS; ++v) + // in case of ITEM_DYNAMIC_FIELD_MODIFIERS it is ITEM_FIELD_MODIFIERS_MASK that controls index of each value, not updatemask + // so we just have to write this starting from 0 index + for (std::size_t v = 0, m = 0; v < values.size(); ++v) { - if (uint32 modifier = _modifiers[v]) + if (values[v] || _dynamicChangesArrayMask[index][v]) { - arrayMask.SetBit(count++); - buffer << uint32(modifier); + arrayMask.set(m++); + *data << uint32(values[v]); } } } - fieldBuffer << uint16(arrayMask.GetBlockCount()); - arrayMask.AppendToPacket(&fieldBuffer); - fieldBuffer.append(buffer); + boost::to_block_range(arrayMask, reinterpret_cast<uint32*>(data->contents() + fieldMaskPos)); } } - *data << uint8(updateMask.GetBlockCount()); - updateMask.AppendToPacket(data); - data->append(fieldBuffer); + boost::to_block_range(updateMask, reinterpret_cast<uint32*>(data->contents() + maskPos)); } void Item::AddToObjectUpdate() @@ -1954,16 +1953,15 @@ ItemModifiedAppearanceEntry const* Item::GetItemModifiedAppearance() const return sDB2Manager.GetItemModifiedAppearance(GetEntry(), _bonusData.AppearanceModID); } -void Item::SetModifier(ItemModifier modifier, uint32 value) +uint32 Item::GetModifier(ItemModifier modifier) const { - if (_modifiers[modifier] != value) - { - _dynamicChangesMask.SetBit(ITEM_DYNAMIC_FIELD_MODIFIERS); - AddToObjectUpdateIfNeeded(); - } + return GetDynamicValues(ITEM_DYNAMIC_FIELD_MODIFIERS)[modifier]; +} - _modifiers[modifier] = value; +void Item::SetModifier(ItemModifier modifier, uint32 value) +{ ApplyModFlag(ITEM_FIELD_MODIFIERS_MASK, 1 << modifier, value != 0); + SetDynamicValue(ITEM_DYNAMIC_FIELD_MODIFIERS, modifier, value); } uint32 Item::GetVisibleEntry(Player const* owner) const diff --git a/src/server/game/Entities/Item/Item.h b/src/server/game/Entities/Item/Item.h index 12a33f86a23..26acb7d8ada 100644 --- a/src/server/game/Entities/Item/Item.h +++ b/src/server/game/Entities/Item/Item.h @@ -461,7 +461,7 @@ class TC_GAME_API Item : public Object static uint32 GetSellPrice(ItemTemplate const* proto, bool& success); - uint32 GetModifier(ItemModifier modifier) const { return _modifiers[modifier]; } + uint32 GetModifier(ItemModifier modifier) const; void SetModifier(ItemModifier modifier, uint32 value); protected: @@ -479,6 +479,5 @@ class TC_GAME_API Item : public Object uint32 m_paidMoney; uint32 m_paidExtendedCost; GuidSet allowedGUIDs; - uint32 _modifiers[MAX_ITEM_MODIFIERS]; }; #endif diff --git a/src/server/game/Entities/Item/ItemTemplate.cpp b/src/server/game/Entities/Item/ItemTemplate.cpp index 3f2563345f9..77848112014 100644 --- a/src/server/game/Entities/Item/ItemTemplate.cpp +++ b/src/server/game/Entities/Item/ItemTemplate.cpp @@ -212,19 +212,20 @@ void ItemTemplate::GetDamage(uint32 itemLevel, float& minDamage, float& maxDamag maxDamage = floor(float(avgDamage * (GetStatScalingFactor() * 0.5f + 1.0f) + 0.5f)); } -bool ItemTemplate::CanWinForPlayer(Player const* player) const +bool ItemTemplate::IsUsableBySpecialization(Player const* player) const { - std::unordered_set<uint32> const& specs = Specializations[player->getLevel() > 40]; - if (specs.empty()) - return true; - uint32 spec = player->GetUInt32Value(PLAYER_FIELD_CURRENT_SPEC_ID); if (!spec) spec = player->GetDefaultSpecId(); - if (!spec) + ChrSpecializationEntry const* chrSpecialization = sChrSpecializationStore.LookupEntry(spec); + if (!chrSpecialization) return false; - auto itr = specs.find(spec); - return itr != specs.end(); + return Specializations[player->getLevel() > 40].test(CalculateItemSpecBit(chrSpecialization)); +} + +std::size_t ItemTemplate::CalculateItemSpecBit(ChrSpecializationEntry const* spec) +{ + return (spec->ClassID - 1) * MAX_SPECIALIZATIONS + spec->OrderIndex; } diff --git a/src/server/game/Entities/Item/ItemTemplate.h b/src/server/game/Entities/Item/ItemTemplate.h index cacea73bf87..a41c8d91a88 100644 --- a/src/server/game/Entities/Item/ItemTemplate.h +++ b/src/server/game/Entities/Item/ItemTemplate.h @@ -21,6 +21,7 @@ #include "DB2Structure.h" #include "SharedDefines.h" +#include <bitset> enum ItemModType { @@ -696,6 +697,7 @@ const uint32 MaxItemSubclassValues[MAX_ITEM_CLASS] = #define MAX_ITEM_LEVEL 1000 class Player; +struct ChrSpecializationEntry; struct TC_GAME_API ItemTemplate { @@ -769,7 +771,7 @@ struct TC_GAME_API ItemTemplate uint32 MaxMoneyLoot; uint32 FlagsCu; float SpellPPMRate; - std::unordered_set<uint32> Specializations[2]; // one set for 1-40 level range and another for 41-100 + std::bitset<MAX_CLASSES * MAX_SPECIALIZATIONS> Specializations[2]; // one set for 1-40 level range and another for 41-100 uint32 ItemSpecClassMask; // helpers @@ -799,7 +801,8 @@ struct TC_GAME_API ItemTemplate char const* GetDefaultLocaleName() const; uint32 GetArmor(uint32 itemLevel) const; void GetDamage(uint32 itemLevel, float& minDamage, float& maxDamage) const; - bool CanWinForPlayer(Player const* player) const; + bool IsUsableBySpecialization(Player const* player) const; + static std::size_t CalculateItemSpecBit(ChrSpecializationEntry const* spec); }; // Benchmarked: Faster than std::map (insert/find) diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 028f954744f..39538213461 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -28,7 +28,6 @@ #include "Vehicle.h" #include "ObjectMgr.h" #include "UpdateData.h" -#include "UpdateMask.h" #include "Util.h" #include "ObjectAccessor.h" #include "Transport.h" @@ -46,6 +45,7 @@ #include "BattlefieldMgr.h" #include "GameObjectPackets.h" #include "MiscPackets.h" +#include <boost/dynamic_bitset.hpp> Object::Object() { @@ -108,15 +108,14 @@ Object::~Object() void Object::_InitValues() { m_uint32Values = new uint32[m_valuesCount]; - memset(m_uint32Values, 0, m_valuesCount*sizeof(uint32)); + memset(m_uint32Values, 0, m_valuesCount * sizeof(uint32)); - _changesMask.SetCount(m_valuesCount); - - _dynamicChangesMask.SetCount(_dynamicValuesCount); + _changesMask.resize(m_valuesCount); + _dynamicChangesMask.resize(_dynamicValuesCount); if (_dynamicValuesCount) { _dynamicValues = new std::vector<uint32>[_dynamicValuesCount]; - _dynamicChangesArrayMask = new UpdateMask[_dynamicValuesCount]; + _dynamicChangesArrayMask = new std::vector<uint8>[_dynamicValuesCount]; } m_objectUpdated = false; @@ -765,27 +764,27 @@ void Object::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* targe if (!target) return; - ByteBuffer fieldBuffer; - UpdateMask updateMask; - updateMask.SetCount(m_valuesCount); + boost::dynamic_bitset<uint32> updateMask(m_valuesCount); uint32* flags = NULL; uint32 visibleFlag = GetUpdateFieldData(target, flags); ASSERT(flags); + *data << uint8(updateMask.num_blocks()); + std::size_t maskPos = data->wpos(); + data->resize(data->size() + updateMask.num_blocks() * sizeof(uint32)); + for (uint16 index = 0; index < m_valuesCount; ++index) { if (_fieldNotifyFlags & flags[index] || - ((updateType == UPDATETYPE_VALUES ? _changesMask.GetBit(index) : m_uint32Values[index]) && (flags[index] & visibleFlag))) + ((updateType == UPDATETYPE_VALUES ? _changesMask[index] : m_uint32Values[index]) && (flags[index] & visibleFlag))) { - updateMask.SetBit(index); - fieldBuffer << m_uint32Values[index]; + updateMask.set(index); + *data << m_uint32Values[index]; } } - *data << uint8(updateMask.GetBlockCount()); - updateMask.AppendToPacket(data); - data->append(fieldBuffer); + boost::to_block_range(updateMask, reinterpret_cast<uint32*>(data->contents() + maskPos)); } void Object::BuildDynamicValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) const @@ -793,42 +792,41 @@ void Object::BuildDynamicValuesUpdate(uint8 updateType, ByteBuffer* data, Player if (!target) return; - ByteBuffer fieldBuffer; - UpdateMask updateMask; - updateMask.SetCount(_dynamicValuesCount); + boost::dynamic_bitset<uint32> updateMask(_dynamicValuesCount); uint32* flags = nullptr; uint32 visibleFlag = GetDynamicUpdateFieldData(target, flags); + *data << uint8(updateMask.num_blocks()); + std::size_t maskPos = data->wpos(); + data->resize(data->size() + updateMask.num_blocks() * sizeof(uint32)); + for (uint16 index = 0; index < _dynamicValuesCount; ++index) { - ByteBuffer buffer; std::vector<uint32> const& values = _dynamicValues[index]; if (_fieldNotifyFlags & flags[index] || - ((updateType == UPDATETYPE_VALUES ? _dynamicChangesMask.GetBit(index) : !values.empty()) && (flags[index] & visibleFlag))) + ((updateType == UPDATETYPE_VALUES ? _dynamicChangesMask[index] : !values.empty()) && (flags[index] & visibleFlag))) { - updateMask.SetBit(index); + updateMask.set(index); - UpdateMask arrayMask; - arrayMask.SetCount(values.size()); + boost::dynamic_bitset<uint32> arrayMask(values.size()); + *data << uint16(arrayMask.num_blocks()); + std::size_t fieldMaskPos = data->wpos(); + data->resize(data->size() + arrayMask.num_blocks() * sizeof(uint32)); for (std::size_t v = 0; v < values.size(); ++v) { - if (updateType == UPDATETYPE_VALUES ? _dynamicChangesArrayMask[index].GetBit(v) : values[v]) + if (updateType == UPDATETYPE_VALUES ? _dynamicChangesArrayMask[index][v] : values[v]) { - arrayMask.SetBit(v); - buffer << uint32(values[v]); + arrayMask.set(v); + *data << uint32(values[v]); } } - fieldBuffer << uint16(arrayMask.GetBlockCount()); - arrayMask.AppendToPacket(&fieldBuffer); - fieldBuffer.append(buffer); + boost::to_block_range(arrayMask, reinterpret_cast<uint32*>(data->contents() + fieldMaskPos)); } } - *data << uint8(updateMask.GetBlockCount()); - updateMask.AppendToPacket(data); - data->append(fieldBuffer); + boost::to_block_range(updateMask, reinterpret_cast<uint32*>(data->contents() + maskPos)); } void Object::AddToObjectUpdateIfNeeded() @@ -842,10 +840,10 @@ void Object::AddToObjectUpdateIfNeeded() void Object::ClearUpdateMask(bool remove) { - _changesMask.Clear(); - _dynamicChangesMask.Clear(); + memset(_changesMask.data(), 0, _changesMask.size()); + memset(_dynamicChangesMask.data(), 0, _dynamicChangesMask.size()); for (uint32 i = 0; i < _dynamicValuesCount; ++i) - _dynamicChangesArrayMask[i].Clear(); + memset(_dynamicChangesArrayMask[i].data(), 0, _dynamicChangesArrayMask[i].size()); if (m_objectUpdated) { @@ -990,7 +988,7 @@ void Object::_LoadIntoDataField(std::string const& data, uint32 startOffset, uin for (uint32 index = 0; index < count; ++index) { m_uint32Values[startOffset + index] = atoul(tokens[index]); - _changesMask.SetBit(startOffset + index); + _changesMask[startOffset + index] = 1; } } @@ -1001,7 +999,7 @@ void Object::SetInt32Value(uint16 index, int32 value) if (m_int32Values[index] != value) { m_int32Values[index] = value; - _changesMask.SetBit(index); + _changesMask[index] = 1; AddToObjectUpdateIfNeeded(); } @@ -1014,7 +1012,7 @@ void Object::SetUInt32Value(uint16 index, uint32 value) if (m_uint32Values[index] != value) { m_uint32Values[index] = value; - _changesMask.SetBit(index); + _changesMask[index] = 1; AddToObjectUpdateIfNeeded(); } @@ -1025,7 +1023,7 @@ void Object::UpdateUInt32Value(uint16 index, uint32 value) ASSERT(index < m_valuesCount || PrintIndexError(index, true)); m_uint32Values[index] = value; - _changesMask.SetBit(index); + _changesMask[index] = 1; } void Object::SetUInt64Value(uint16 index, uint64 value) @@ -1035,8 +1033,8 @@ void Object::SetUInt64Value(uint16 index, uint64 value) { m_uint32Values[index] = PAIR64_LOPART(value); m_uint32Values[index + 1] = PAIR64_HIPART(value); - _changesMask.SetBit(index); - _changesMask.SetBit(index + 1); + _changesMask[index] = 1; + _changesMask[index + 1] = 1; AddToObjectUpdateIfNeeded(); } @@ -1048,10 +1046,10 @@ bool Object::AddGuidValue(uint16 index, ObjectGuid const& value) if (!value.IsEmpty() && ((ObjectGuid*)&(m_uint32Values[index]))->IsEmpty()) { *((ObjectGuid*)&(m_uint32Values[index])) = value; - _changesMask.SetBit(index); - _changesMask.SetBit(index + 1); - _changesMask.SetBit(index + 2); - _changesMask.SetBit(index + 3); + _changesMask[index] = 1; + _changesMask[index + 1] = 1; + _changesMask[index + 2] = 1; + _changesMask[index + 3] = 1; AddToObjectUpdateIfNeeded(); return true; @@ -1066,10 +1064,10 @@ bool Object::RemoveGuidValue(uint16 index, ObjectGuid const& value) if (!value.IsEmpty() && *((ObjectGuid*)&(m_uint32Values[index])) == value) { ((ObjectGuid*)&(m_uint32Values[index]))->Clear(); - _changesMask.SetBit(index); - _changesMask.SetBit(index + 1); - _changesMask.SetBit(index + 2); - _changesMask.SetBit(index + 3); + _changesMask[index] = 1; + _changesMask[index + 1] = 1; + _changesMask[index + 2] = 1; + _changesMask[index + 3] = 1; AddToObjectUpdateIfNeeded(); return true; @@ -1085,7 +1083,7 @@ void Object::SetFloatValue(uint16 index, float value) if (m_floatValues[index] != value) { m_floatValues[index] = value; - _changesMask.SetBit(index); + _changesMask[index] = 1; AddToObjectUpdateIfNeeded(); } @@ -1105,7 +1103,7 @@ void Object::SetByteValue(uint16 index, uint8 offset, uint8 value) { m_uint32Values[index] &= ~uint32(uint32(0xFF) << (offset * 8)); m_uint32Values[index] |= uint32(uint32(value) << (offset * 8)); - _changesMask.SetBit(index); + _changesMask[index] = 1; AddToObjectUpdateIfNeeded(); } @@ -1125,7 +1123,7 @@ void Object::SetUInt16Value(uint16 index, uint8 offset, uint16 value) { m_uint32Values[index] &= ~uint32(uint32(0xFFFF) << (offset * 16)); m_uint32Values[index] |= uint32(uint32(value) << (offset * 16)); - _changesMask.SetBit(index); + _changesMask[index] = 1; AddToObjectUpdateIfNeeded(); } @@ -1137,10 +1135,10 @@ void Object::SetGuidValue(uint16 index, ObjectGuid const& value) if (*((ObjectGuid*)&(m_uint32Values[index])) != value) { *((ObjectGuid*)&(m_uint32Values[index])) = value; - _changesMask.SetBit(index); - _changesMask.SetBit(index + 1); - _changesMask.SetBit(index + 2); - _changesMask.SetBit(index + 3); + _changesMask[index] = 1; + _changesMask[index + 1] = 1; + _changesMask[index + 2] = 1; + _changesMask[index + 3] = 1; AddToObjectUpdateIfNeeded(); } @@ -1219,7 +1217,7 @@ void Object::SetFlag(uint16 index, uint32 newFlag) if (oldval != newval) { m_uint32Values[index] = newval; - _changesMask.SetBit(index); + _changesMask[index] = 1; AddToObjectUpdateIfNeeded(); } @@ -1236,7 +1234,7 @@ void Object::RemoveFlag(uint16 index, uint32 oldFlag) if (oldval != newval) { m_uint32Values[index] = newval; - _changesMask.SetBit(index); + _changesMask[index] = 1; AddToObjectUpdateIfNeeded(); } @@ -1276,7 +1274,7 @@ void Object::SetByteFlag(uint16 index, uint8 offset, uint8 newFlag) if (!(uint8(m_uint32Values[index] >> (offset * 8)) & newFlag)) { m_uint32Values[index] |= uint32(uint32(newFlag) << (offset * 8)); - _changesMask.SetBit(index); + _changesMask[index] = 1; AddToObjectUpdateIfNeeded(); } @@ -1295,7 +1293,7 @@ void Object::RemoveByteFlag(uint16 index, uint8 offset, uint8 oldFlag) if (uint8(m_uint32Values[index] >> (offset * 8)) & oldFlag) { m_uint32Values[index] &= ~uint32(uint32(oldFlag) << (offset * 8)); - _changesMask.SetBit(index); + _changesMask[index] = 1; AddToObjectUpdateIfNeeded(); } @@ -1365,21 +1363,7 @@ uint32 Object::GetDynamicValue(uint16 index, uint16 offset) const void Object::AddDynamicValue(uint16 index, uint32 value) { ASSERT(index < _dynamicValuesCount || PrintIndexError(index, false)); - - std::vector<uint32>& values = _dynamicValues[index]; - UpdateMask& mask = _dynamicChangesArrayMask[index]; - - _dynamicChangesMask.SetBit(index); - if (values.size() >= values.capacity()) - values.reserve(values.capacity() + 32); - - values.push_back(value); - if (mask.GetCount() < values.size()) - mask.AddBlock(); - - mask.SetBit(values.size() - 1); - - AddToObjectUpdateIfNeeded(); + SetDynamicValue(index, _dynamicValues[index].size(), value); } void Object::RemoveDynamicValue(uint16 index, uint32 value) @@ -1393,8 +1377,8 @@ void Object::RemoveDynamicValue(uint16 index, uint32 value) if (values[i] == value) { values[i] = 0; - _dynamicChangesMask.SetBit(index); - _dynamicChangesArrayMask[index].SetBit(i); + _dynamicChangesMask[index] = 1; + _dynamicChangesArrayMask[index][i] = 1; AddToObjectUpdateIfNeeded(); } @@ -1408,8 +1392,8 @@ void Object::ClearDynamicValue(uint16 index) if (!_dynamicValues[index].empty()) { _dynamicValues[index].clear(); - _dynamicChangesMask.SetBit(index); - _dynamicChangesArrayMask[index].SetCount(0); + _dynamicChangesMask[index] = 1; + _dynamicChangesArrayMask[index].clear(); AddToObjectUpdateIfNeeded(); } @@ -1420,14 +1404,17 @@ void Object::SetDynamicValue(uint16 index, uint16 offset, uint32 value) ASSERT(index < _dynamicValuesCount || PrintIndexError(index, false)); std::vector<uint32>& values = _dynamicValues[index]; + if (values.size() <= offset) + values.resize(offset + 1); - ASSERT(offset < values.size()); + if (_dynamicChangesArrayMask[index].size() <= offset) + _dynamicChangesArrayMask[index].resize((offset / 32 + 1) * 32); if (values[offset] != value) { values[offset] = value; - _dynamicChangesMask.SetBit(index); - _dynamicChangesArrayMask[index].SetBit(offset); + _dynamicChangesMask[index] = 1; + _dynamicChangesArrayMask[index][offset] = 1; AddToObjectUpdateIfNeeded(); } @@ -2171,7 +2158,7 @@ bool WorldObject::CanDetectStealthOf(WorldObject const* obj, bool checkAlert) co void Object::ForceValuesUpdateAtIndex(uint32 i) { - _changesMask.SetBit(i); + _changesMask[i] = 1; AddToObjectUpdateIfNeeded(); } diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 07e6acdfa0b..3dc53538d23 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -21,10 +21,10 @@ #include "Common.h" #include "Position.h" -#include "UpdateMask.h" #include "GridReference.h" #include "ObjectDefines.h" #include "Map.h" +#include "UpdateFields.h" #include <set> #include <string> @@ -239,9 +239,9 @@ class TC_GAME_API Object std::vector<uint32>* _dynamicValues; - UpdateMask _changesMask; - UpdateMask _dynamicChangesMask; - UpdateMask* _dynamicChangesArrayMask; + std::vector<uint8> _changesMask; + std::vector<uint8> _dynamicChangesMask; + std::vector<uint8>* _dynamicChangesArrayMask; uint16 m_valuesCount; uint16 _dynamicValuesCount; diff --git a/src/server/game/Entities/Object/Updates/UpdateMask.h b/src/server/game/Entities/Object/Updates/UpdateMask.h deleted file mode 100644 index cadc905ffe1..00000000000 --- a/src/server/game/Entities/Object/Updates/UpdateMask.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/> - * Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef __UPDATEMASK_H -#define __UPDATEMASK_H - -#include "UpdateFields.h" -#include "Errors.h" -#include "ByteBuffer.h" - -class UpdateMask -{ - public: - /// Type representing how client reads update mask - typedef uint32 ClientUpdateMaskType; - - enum UpdateMaskCount - { - CLIENT_UPDATE_MASK_BITS = sizeof(ClientUpdateMaskType) * 8, - }; - - UpdateMask() : _fieldCount(0), _blockCount(0), _bits(NULL) { } - - UpdateMask(UpdateMask const& right) : _bits(NULL) - { - SetCount(right.GetCount()); - memcpy(_bits, right._bits, sizeof(uint8) * _blockCount * 32); - } - - ~UpdateMask() { delete[] _bits; } - - void SetBit(uint32 index) { _bits[index] = 1; } - void UnsetBit(uint32 index) { _bits[index] = 0; } - bool GetBit(uint32 index) const { return _bits[index] != 0; } - - void AppendToPacket(ByteBuffer* data) - { - for (uint32 i = 0; i < GetBlockCount(); ++i) - { - ClientUpdateMaskType maskPart = 0; - for (uint32 j = 0; j < CLIENT_UPDATE_MASK_BITS; ++j) - if (_bits[CLIENT_UPDATE_MASK_BITS * i + j]) - maskPart |= 1 << j; - - *data << maskPart; - } - } - - uint32 GetBlockCount() const { return _blockCount; } - uint32 GetCount() const { return _fieldCount; } - - void SetCount(uint32 valuesCount) - { - delete[] _bits; - - _fieldCount = valuesCount; - _blockCount = (valuesCount + CLIENT_UPDATE_MASK_BITS - 1) / CLIENT_UPDATE_MASK_BITS; - - if (!valuesCount) - { - _bits = nullptr; - return; - } - - _bits = new uint8[_blockCount * CLIENT_UPDATE_MASK_BITS]; - memset(_bits, 0, sizeof(uint8) * _blockCount * CLIENT_UPDATE_MASK_BITS); - } - - void AddBlock() - { - uint8* curr = _bits; - _fieldCount += CLIENT_UPDATE_MASK_BITS; - ++_blockCount; - - _bits = new uint8[_blockCount * CLIENT_UPDATE_MASK_BITS]; - memset(&_bits[(_blockCount - 1) * CLIENT_UPDATE_MASK_BITS], 0, CLIENT_UPDATE_MASK_BITS); - if (curr) - { - memcpy(_bits, curr, sizeof(uint8) * (_blockCount - 1) * CLIENT_UPDATE_MASK_BITS); - delete[] curr; - } - } - - void Clear() - { - if (_bits) - memset(_bits, 0, sizeof(uint8) * _blockCount * CLIENT_UPDATE_MASK_BITS); - } - - UpdateMask& operator=(UpdateMask const& right) - { - if (this == &right) - return *this; - - SetCount(right.GetCount()); - memcpy(_bits, right._bits, sizeof(uint8) * _blockCount * CLIENT_UPDATE_MASK_BITS); - return *this; - } - - UpdateMask& operator&=(UpdateMask const& right) - { - ASSERT(right.GetCount() <= GetCount()); - for (uint32 i = 0; i < _fieldCount; ++i) - _bits[i] &= right._bits[i]; - - return *this; - } - - UpdateMask& operator|=(UpdateMask const& right) - { - ASSERT(right.GetCount() <= GetCount()); - for (uint32 i = 0; i < _fieldCount; ++i) - _bits[i] |= right._bits[i]; - - return *this; - } - - UpdateMask operator|(UpdateMask const& right) - { - UpdateMask ret(*this); - ret |= right; - return ret; - } - - private: - uint32 _fieldCount; - uint32 _blockCount; - uint8* _bits; -}; - -#endif - diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 8ac7e909471..2bf30369a5c 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -93,7 +93,6 @@ #include "Transport.h" #include "UpdateData.h" #include "UpdateFieldFlags.h" -#include "UpdateMask.h" #include "Util.h" #include "VehiclePackets.h" #include "Weather.h" @@ -131,7 +130,6 @@ Player::Player(WorldSession* session) : Unit(true) m_ExtraFlags = 0; m_spellModTakingSpell = nullptr; - //m_pad = 0; // players always accept if (!GetSession()->HasPermission(rbac::RBAC_PERM_CAN_FILTER_WHISPERS)) @@ -1768,6 +1766,15 @@ void Player::RemoveFromWorld() } } +void Player::SetObjectScale(float scale) +{ + Unit::SetObjectScale(scale); + SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, scale * DEFAULT_WORLD_OBJECT_SIZE); + SetFloatValue(UNIT_FIELD_COMBATREACH, scale * DEFAULT_COMBAT_REACH); + if (IsInWorld()) + SendMovementSetCollisionHeight(scale * GetCollisionHeight(IsMounted())); +} + bool Player::IsImmunedToSpellEffect(SpellInfo const* spellInfo, uint32 index) const { SpellEffectInfo const* effect = spellInfo->GetEffect(GetMap()->GetDifficultyID(), index); @@ -14100,7 +14107,7 @@ bool Player::CanRewardQuest(Quest const* quest, uint32 reward, bool msg) if (ItemTemplate const* rewardProto = sObjectMgr->GetItemTemplate(questPackageItem->ItemID)) { - if (rewardProto->CanWinForPlayer(this)) + if (rewardProto->IsUsableBySpecialization(this)) { InventoryResult res = CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, questPackageItem->ItemID, questPackageItem->ItemCount); if (res != EQUIP_ERR_OK) @@ -14321,7 +14328,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, if (ItemTemplate const* rewardProto = sObjectMgr->GetItemTemplate(questPackageItem->ItemID)) { - if (rewardProto->CanWinForPlayer(this)) + if (rewardProto->IsUsableBySpecialization(this)) { ItemPosCountVec dest; if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, questPackageItem->ItemID, questPackageItem->ItemCount) == EQUIP_ERR_OK) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 1c4c1d57dd4..4288b9aef12 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1196,12 +1196,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void AddToWorld() override; void RemoveFromWorld() override; - void SetObjectScale(float scale) override - { - Unit::SetObjectScale(scale); - SetFloatValue(UNIT_FIELD_BOUNDINGRADIUS, scale * DEFAULT_WORLD_OBJECT_SIZE); - SetFloatValue(UNIT_FIELD_COMBATREACH, scale * DEFAULT_COMBAT_REACH); - } + void SetObjectScale(float scale) override; bool TeleportTo(uint32 mapid, float x, float y, float z, float orientation, uint32 options = 0); bool TeleportTo(WorldLocation const &loc, uint32 options = 0); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index abb2f8a9d07..b535e2225ac 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -70,7 +70,7 @@ #include "VehiclePackets.h" #include "LootPackets.h" #include "PartyPackets.h" - +#include <boost/dynamic_bitset.hpp> #include <cmath> float baseMoveSpeed[MAX_MOVE_TYPE] = @@ -500,7 +500,7 @@ bool Unit::IsWithinCombatRange(const Unit* obj, float dist2compare) const return distsq < maxdist * maxdist; } -bool Unit::IsWithinMeleeRange(const Unit* obj, float dist) const +bool Unit::IsWithinMeleeRange(Unit const* obj) const { if (!obj || !IsInMap(obj) || !IsInPhase(obj)) return false; @@ -510,10 +510,9 @@ bool Unit::IsWithinMeleeRange(const Unit* obj, float dist) const float dz = GetPositionZMinusOffset() - obj->GetPositionZMinusOffset(); float distsq = dx*dx + dy*dy + dz*dz; - float sizefactor = GetCombatReach() + obj->GetCombatReach() + 4.0f / 3.0f; - float maxdist = dist + sizefactor; + float maxdist = GetCombatReach() + obj->GetCombatReach() + 4.0f / 3.0f; - return distsq < maxdist * maxdist; + return distsq <= maxdist * maxdist; } void Unit::GetRandomContactPoint(const Unit* obj, float &x, float &y, float &z, float distance2dMin, float distance2dMax) const @@ -15670,11 +15669,7 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) if (!target) return; - ByteBuffer fieldBuffer; - UpdateMask updateMask; - uint32 valCount = m_valuesCount; - uint32* flags = UnitUpdateFieldFlags; uint32 visibleFlag = UF_FLAG_PUBLIC; @@ -15683,7 +15678,7 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) else if (GetTypeId() == TYPEID_PLAYER) valCount = PLAYER_FIELD_END_NOT_SELF; - updateMask.SetCount(valCount); + boost::dynamic_bitset<uint32> updateMask(valCount); Player* plr = GetCharmerOrOwnerPlayerOrPlayerItself(); if (GetOwnerGUID() == target->GetGUID()) @@ -15697,14 +15692,19 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) visibleFlag |= UF_FLAG_PARTY_MEMBER; Creature const* creature = ToCreature(); + + *data << uint8(updateMask.num_blocks()); + std::size_t maskPos = data->wpos(); + data->resize(data->size() + updateMask.num_blocks() * sizeof(uint32)); + for (uint16 index = 0; index < valCount; ++index) { if (_fieldNotifyFlags & flags[index] || ((flags[index] & visibleFlag) & UF_FLAG_SPECIAL_INFO) || - ((updateType == UPDATETYPE_VALUES ? _changesMask.GetBit(index) : m_uint32Values[index]) && (flags[index] & visibleFlag)) || + ((updateType == UPDATETYPE_VALUES ? _changesMask[index] : m_uint32Values[index]) && (flags[index] & visibleFlag)) || (index == UNIT_FIELD_AURASTATE && HasFlag(UNIT_FIELD_AURASTATE, PER_CASTER_AURA_STATE_MASK))) { - updateMask.SetBit(index); + updateMask.set(index); if (index == UNIT_NPC_FLAGS) { @@ -15714,18 +15714,18 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) if (!target->CanSeeSpellClickOn(creature)) appendValue &= ~UNIT_NPC_FLAG_SPELLCLICK; - fieldBuffer << uint32(appendValue); + *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 - fieldBuffer << BuildAuraStateUpdateForTarget(target); + *data << 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 - fieldBuffer << uint32(m_floatValues[index] < 0 ? 0 : m_floatValues[index]); + *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_NEGSTAT && index < UNIT_FIELD_NEGSTAT + MAX_STATS) || @@ -15733,7 +15733,7 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) (index >= UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE && index < (UNIT_FIELD_RESISTANCEBUFFMODSNEGATIVE + MAX_SPELL_SCHOOL)) || (index >= UNIT_FIELD_POSSTAT && index < UNIT_FIELD_POSSTAT + MAX_STATS)) { - fieldBuffer << uint32(m_floatValues[index]); + *data << uint32(m_floatValues[index]); } // Gamemasters should be always able to select units - remove not selectable flag else if (index == UNIT_FIELD_FLAGS) @@ -15742,7 +15742,7 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) if (target->IsGameMaster()) appendValue &= ~UNIT_FLAG_NOT_SELECTABLE; - fieldBuffer << uint32(appendValue); + *data << uint32(appendValue); } // use modelid_a if not gm, _h if gm for CREATURE_FLAG_EXTRA_TRIGGER creatures else if (index == UNIT_FIELD_DISPLAYID) @@ -15767,7 +15767,7 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) displayId = cinfo->GetFirstVisibleModel(); } - fieldBuffer << uint32(displayId); + *data << uint32(displayId); } // hide lootable animation for unallowed players else if (index == OBJECT_DYNAMIC_FLAGS) @@ -15788,7 +15788,7 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) if (!HasAuraTypeWithCaster(SPELL_AURA_MOD_STALKED, target->GetGUID())) dynamicFlags &= ~UNIT_DYNFLAG_TRACK_UNIT; - fieldBuffer << dynamicFlags; + *data << dynamicFlags; } // FG: pretend that OTHER players in own group are friendly ("blue") else if (index == UNIT_FIELD_BYTES_2 || index == UNIT_FIELD_FACTIONTEMPLATE) @@ -15801,28 +15801,26 @@ void Unit::BuildValuesUpdate(uint8 updateType, ByteBuffer* data, Player* target) { 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 !! + *data << (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()); + *data << uint32(target->getFaction()); } else - fieldBuffer << m_uint32Values[index]; + *data << m_uint32Values[index]; } else - fieldBuffer << m_uint32Values[index]; + *data << m_uint32Values[index]; } else { // send in current format (float as float, uint32 as uint32) - fieldBuffer << m_uint32Values[index]; + *data << m_uint32Values[index]; } } } - *data << uint8(updateMask.GetBlockCount()); - updateMask.AppendToPacket(data); - data->append(fieldBuffer); + boost::to_block_range(updateMask, reinterpret_cast<uint32*>(data->contents() + maskPos)); } void Unit::DestroyForPlayer(Player* target) const @@ -16019,16 +16017,15 @@ void Unit::Whisper(uint32 textId, Player* target, bool isBossWhisper /*= false*/ SpellInfo const* Unit::GetCastSpellInfo(SpellInfo const* spellInfo) const { Unit::AuraEffectList swaps = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS); - Unit::AuraEffectList const& swaps2 = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_2); + Unit::AuraEffectList const& swaps2 = GetAuraEffectsByType(SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_TRIGGERED); if (!swaps2.empty()) swaps.insert(swaps.end(), swaps2.begin(), swaps2.end()); for (AuraEffect const* auraEffect : swaps) { - if ((!auraEffect->GetSpellEffectInfo()->SpellClassMask && uint32(auraEffect->GetMiscValue()) == spellInfo->Id) || - (auraEffect->GetSpellEffectInfo()->SpellClassMask && auraEffect->IsAffectingSpell(spellInfo))) - if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo(auraEffect->GetAmount())) - return newInfo; + if (uint32(auraEffect->GetMiscValue()) == spellInfo->Id || auraEffect->IsAffectingSpell(spellInfo)) + if (SpellInfo const* newInfo = sSpellMgr->GetSpellInfo(auraEffect->GetAmount())) + return newInfo; } return spellInfo; diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 8dbe00d54c2..f991720b1eb 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1375,7 +1375,7 @@ class TC_GAME_API Unit : public WorldObject virtual void SetCanDualWield(bool value) { m_canDualWield = value; } float GetCombatReach() const { return m_floatValues[UNIT_FIELD_COMBATREACH]; } bool IsWithinCombatRange(const Unit* obj, float dist2compare) const; - bool IsWithinMeleeRange(const Unit* obj, float dist = MELEE_RANGE) const; + bool IsWithinMeleeRange(Unit const* obj) const; void GetRandomContactPoint(const Unit* target, float &x, float &y, float &z, float distance2dMin, float distance2dMax) const; uint32 m_extraAttacks; bool m_canDualWield; @@ -2131,7 +2131,7 @@ class TC_GAME_API Unit : public WorldObject void AddExtraUnitMovementFlag(uint16 f) { m_movementInfo.AddExtraMovementFlag(f); } void RemoveExtraUnitMovementFlag(uint16 f) { m_movementInfo.RemoveExtraMovementFlag(f); } - uint16 HasExtraUnitMovementFlag(uint16 f) const { return m_movementInfo.HasExtraMovementFlag(f); } + bool HasExtraUnitMovementFlag(uint16 f) const { return m_movementInfo.HasExtraMovementFlag(f); } uint16 GetExtraUnitMovementFlags() const { return m_movementInfo.GetExtraMovementFlags(); } void SetExtraUnitMovementFlags(uint16 f) { m_movementInfo.SetExtraMovementFlags(f); } bool IsSplineEnabled() const; diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 0ea0f832405..d3d33a22ad3 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -43,7 +43,6 @@ #include "SpellAuras.h" #include "SpellMgr.h" #include "SpellScript.h" -#include "UpdateMask.h" #include "Util.h" #include "Vehicle.h" #include "World.h" @@ -2671,9 +2670,10 @@ void ObjectMgr::LoadItemTemplates() if (std::vector<ItemSpecOverrideEntry const*> const* itemSpecOverrides = sDB2Manager.GetItemSpecOverrides(sparse->ID)) { for (ItemSpecOverrideEntry const* itemSpecOverride : *itemSpecOverrides) - itemTemplate.Specializations[0].insert(itemSpecOverride->SpecID); + if (ChrSpecializationEntry const* specialization = sChrSpecializationStore.LookupEntry(itemSpecOverride->SpecID)) + itemTemplate.Specializations[0].set(ItemTemplate::CalculateItemSpecBit(specialization)); - itemTemplate.Specializations[1] = itemTemplate.Specializations[0]; + itemTemplate.Specializations[1] |= itemTemplate.Specializations[0]; } else { @@ -2704,7 +2704,7 @@ void ObjectMgr::LoadItemTemplates() if ((1 << (specialization->ClassID - 1)) & sparse->AllowableClass) { itemTemplate.ItemSpecClassMask |= 1 << (specialization->ClassID - 1); - itemTemplate.Specializations[itemSpec->MaxLevel > 40].insert(itemSpec->SpecID); + itemTemplate.Specializations[itemSpec->MaxLevel > 40].set(ItemTemplate::CalculateItemSpecBit(specialization)); } } } diff --git a/src/server/game/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp index a4e9c995b4d..f25bbce20eb 100644 --- a/src/server/game/Handlers/AuctionHouseHandler.cpp +++ b/src/server/game/Handlers/AuctionHouseHandler.cpp @@ -24,7 +24,6 @@ #include "AuctionHouseMgr.h" #include "Log.h" #include "Language.h" -#include "UpdateMask.h" #include "Util.h" #include "AccountMgr.h" #include "AuctionHousePackets.h" diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index c3bea2abb34..2278e001aba 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -49,7 +49,6 @@ #include "SharedDefines.h" #include "SocialMgr.h" #include "SystemPackets.h" -#include "UpdateMask.h" #include "Util.h" #include "World.h" #include "WorldPacket.h" diff --git a/src/server/game/Handlers/NPCHandler.cpp b/src/server/game/Handlers/NPCHandler.cpp index ef1155a38b2..ae8ee2f221a 100644 --- a/src/server/game/Handlers/NPCHandler.cpp +++ b/src/server/game/Handlers/NPCHandler.cpp @@ -27,7 +27,6 @@ #include "SpellMgr.h" #include "Player.h" #include "GossipDef.h" -#include "UpdateMask.h" #include "ObjectAccessor.h" #include "Creature.h" #include "Pet.h" diff --git a/src/server/game/Handlers/QueryHandler.cpp b/src/server/game/Handlers/QueryHandler.cpp index 7749f0f4ac4..c493c58ec0c 100644 --- a/src/server/game/Handlers/QueryHandler.cpp +++ b/src/server/game/Handlers/QueryHandler.cpp @@ -24,7 +24,6 @@ #include "World.h" #include "ObjectMgr.h" #include "Player.h" -#include "UpdateMask.h" #include "NPCHandler.h" #include "MapManager.h" #include "QueryPackets.h" diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp index bfa0bc3db16..6ef966a2340 100644 --- a/src/server/game/Handlers/QuestHandler.cpp +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -285,7 +285,7 @@ void WorldSession::HandleQuestgiverChooseRewardOpcode(WorldPackets::Quest::Quest rewardProto = sObjectMgr->GetItemTemplate(questPackageItem->ItemID); if (rewardProto) { - if (rewardProto->CanWinForPlayer(_player)) + if (rewardProto->IsUsableBySpecialization(_player)) { itemValid = true; break; diff --git a/src/server/game/Instances/InstanceScript.cpp b/src/server/game/Instances/InstanceScript.cpp index a8d347a57a7..d8c99aa366d 100644 --- a/src/server/game/Instances/InstanceScript.cpp +++ b/src/server/game/Instances/InstanceScript.cpp @@ -664,6 +664,14 @@ void InstanceScript::SendEncounterEnd() instance->SendToPlayers(encounterEndMessage.Write()); } +void InstanceScript::SendBossKillCredit(uint32 encounterId) +{ + WorldPackets::Instance::BossKillCredit bossKillCreditMessage; + bossKillCreditMessage.DungeonEncounterID = encounterId; + + instance->SendToPlayers(bossKillCreditMessage.Write()); +} + void InstanceScript::UpdateEncounterState(EncounterCreditType type, uint32 creditEntry, Unit* /*source*/) { DungeonEncounterList const* encounters = sObjectMgr->GetDungeonEncounterList(instance->GetId(), instance->GetDifficultyID()); diff --git a/src/server/game/Instances/InstanceScript.h b/src/server/game/Instances/InstanceScript.h index 92c7be92752..d858bb6b9c2 100644 --- a/src/server/game/Instances/InstanceScript.h +++ b/src/server/game/Instances/InstanceScript.h @@ -250,6 +250,8 @@ class TC_GAME_API InstanceScript : public ZoneScript void SendEncounterStart(uint32 inCombatResCount = 0, uint32 maxInCombatResCount = 0, uint32 inCombatResChargeRecovery = 0, uint32 nextCombatResChargeTime = 0); void SendEncounterEnd(); + void SendBossKillCredit(uint32 encounterId); + virtual void FillInitialWorldStates(WorldPackets::WorldState::InitWorldStates& /*packet*/) { } // ReCheck PhaseTemplate related conditions diff --git a/src/server/game/Server/Packets/AuthenticationPackets.cpp b/src/server/game/Server/Packets/AuthenticationPackets.cpp index 69cb22659cd..52fb54c725a 100644 --- a/src/server/game/Server/Packets/AuthenticationPackets.cpp +++ b/src/server/game/Server/Packets/AuthenticationPackets.cpp @@ -18,6 +18,32 @@ #include "AuthenticationPackets.h" #include "HmacHash.h" +bool WorldPackets::Auth::EarlyProcessClientPacket::ReadNoThrow() +{ + try + { + Read(); + return true; + } + catch (ByteBufferPositionException const& ex) + { + } + + return false; +} + +void WorldPackets::Auth::Ping::Read() +{ + _worldPacket >> Serial; + _worldPacket >> Latency; +} + +const WorldPacket* WorldPackets::Auth::Pong::Write() +{ + _worldPacket << uint32(Serial); + return &_worldPacket; +} + WorldPacket const* WorldPackets::Auth::AuthChallenge::Write() { _worldPacket.append(DosChallenge, 8); diff --git a/src/server/game/Server/Packets/AuthenticationPackets.h b/src/server/game/Server/Packets/AuthenticationPackets.h index f17e079f0fb..ef29cfae0d1 100644 --- a/src/server/game/Server/Packets/AuthenticationPackets.h +++ b/src/server/game/Server/Packets/AuthenticationPackets.h @@ -31,6 +31,36 @@ namespace WorldPackets { namespace Auth { + class EarlyProcessClientPacket : public ClientPacket + { + public: + EarlyProcessClientPacket(OpcodeClient opcode, WorldPacket&& packet) : ClientPacket(opcode, std::move(packet)) { } + + bool ReadNoThrow(); + }; + + class Ping final : public EarlyProcessClientPacket + { + public: + Ping(WorldPacket&& packet) : EarlyProcessClientPacket(CMSG_PING, std::move(packet)) { } + + uint32 Serial = 0; + uint32 Latency = 0; + + private: + void Read(); + }; + + class Pong final : public ServerPacket + { + public: + Pong(uint32 serial) : ServerPacket(SMSG_PONG, 4), Serial(serial) { } + + WorldPacket const* Write() override; + + uint32 Serial = 0; + }; + class AuthChallenge final : public ServerPacket { public: @@ -43,19 +73,17 @@ namespace WorldPackets uint8 DosZeroBits = 0; }; - class AuthSession final : public ClientPacket + class AuthSession final : public EarlyProcessClientPacket { public: static uint32 const DigestLength = 24; - AuthSession(WorldPacket&& packet) : ClientPacket(CMSG_AUTH_SESSION, std::move(packet)) + AuthSession(WorldPacket&& packet) : EarlyProcessClientPacket(CMSG_AUTH_SESSION, std::move(packet)) { LocalChallenge.fill(0); Digest.fill(0); } - void Read() override; - uint16 Build = 0; int8 BuildType = 0; uint32 RegionID = 0; @@ -66,6 +94,9 @@ namespace WorldPackets uint64 DosResponse = 0; std::string RealmJoinTicket; bool UseIPv6 = false; + + private: + void Read() override; }; class AuthResponse final : public ServerPacket @@ -172,23 +203,24 @@ namespace WorldPackets BigNumber iqmp; }; - class AuthContinuedSession final : public ClientPacket + class AuthContinuedSession final : public EarlyProcessClientPacket { public: static uint32 const DigestLength = 24; - AuthContinuedSession(WorldPacket&& packet) : ClientPacket(CMSG_AUTH_CONTINUED_SESSION, std::move(packet)) + AuthContinuedSession(WorldPacket&& packet) : EarlyProcessClientPacket(CMSG_AUTH_CONTINUED_SESSION, std::move(packet)) { LocalChallenge.fill(0); Digest.fill(0); } - void Read() override; - uint64 DosResponse = 0; uint64 Key = 0; std::array<uint8, 16> LocalChallenge; std::array<uint8, DigestLength> Digest; + + private: + void Read() override; }; class ResumeComms final : public ServerPacket @@ -199,15 +231,16 @@ namespace WorldPackets WorldPacket const* Write() override { return &_worldPacket; } }; - class ConnectToFailed final : public ClientPacket + class ConnectToFailed final : public EarlyProcessClientPacket { public: - ConnectToFailed(WorldPacket&& packet) : ClientPacket(CMSG_CONNECT_TO_FAILED, std::move(packet)) { } - - void Read() override; + ConnectToFailed(WorldPacket&& packet) : EarlyProcessClientPacket(CMSG_CONNECT_TO_FAILED, std::move(packet)) { } ConnectToSerial Serial = ConnectToSerial::None; uint8 Con = 0; + + private: + void Read() override; }; class EnableEncryption final : public ServerPacket diff --git a/src/server/game/Server/Packets/InstancePackets.cpp b/src/server/game/Server/Packets/InstancePackets.cpp index 959f39eccbe..dfa490135b0 100644 --- a/src/server/game/Server/Packets/InstancePackets.cpp +++ b/src/server/game/Server/Packets/InstancePackets.cpp @@ -157,3 +157,10 @@ WorldPacket const* WorldPackets::Instance::InstanceEncounterGainCombatResurrecti return &_worldPacket; } + +WorldPacket const* WorldPackets::Instance::BossKillCredit::Write() +{ + _worldPacket << uint32(DungeonEncounterID); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/InstancePackets.h b/src/server/game/Server/Packets/InstancePackets.h index 8895a8aaf82..d9e957aa470 100644 --- a/src/server/game/Server/Packets/InstancePackets.h +++ b/src/server/game/Server/Packets/InstancePackets.h @@ -235,6 +235,15 @@ namespace WorldPackets int32 InCombatResCount = 0; uint32 CombatResChargeRecovery = 0; }; + + class BossKillCredit final : public ServerPacket + { + public: + BossKillCredit() : ServerPacket(SMSG_BOSS_KILL_CREDIT, 4) { } + + WorldPacket const* Write() override; + uint32 DungeonEncounterID = 0; + }; } } diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index 3dbd9a60ad9..bae5da71a9e 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -939,7 +939,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_BLACK_MARKET_REQUEST_ITEMS_RESULT, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BLACK_MARKET_WON, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BONUS_ROLL_EMPTY, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_BOSS_KILL_CREDIT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BOSS_KILL_CREDIT, STATUS_NEVER, CONNECTION_TYPE_INSTANCE); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BREAK_TARGET, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BUY_FAILED, STATUS_NEVER, CONNECTION_TYPE_REALM); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BUY_SUCCEEDED, STATUS_NEVER, CONNECTION_TYPE_REALM); diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 12a62619798..36977542e36 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -368,8 +368,18 @@ WorldSocket::ReadDataHandlerResult WorldSocket::ReadDataHandler() switch (opcode) { case CMSG_PING: + { LogOpcodeText(opcode, sessionGuard); - return HandlePing(packet) ? ReadDataHandlerResult::Ok : ReadDataHandlerResult::Error; + WorldPackets::Auth::Ping ping(std::move(packet)); + if (!ping.ReadNoThrow()) + { + TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client %s sent malformed CMSG_PING", GetRemoteIpAddress().to_string().c_str()); + return ReadDataHandlerResult::Error; + } + if (!HandlePing(ping)) + return ReadDataHandlerResult::Error; + break; + } case CMSG_AUTH_SESSION: { LogOpcodeText(opcode, sessionGuard); @@ -382,7 +392,11 @@ WorldSocket::ReadDataHandlerResult WorldSocket::ReadDataHandler() } std::shared_ptr<WorldPackets::Auth::AuthSession> authSession = std::make_shared<WorldPackets::Auth::AuthSession>(std::move(packet)); - authSession->Read(); + if (!authSession->ReadNoThrow()) + { + TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client %s sent malformed CMSG_AUTH_SESSION", GetRemoteIpAddress().to_string().c_str()); + return ReadDataHandlerResult::Error; + } HandleAuthSession(authSession); return ReadDataHandlerResult::WaitingForQuery; } @@ -398,7 +412,11 @@ WorldSocket::ReadDataHandlerResult WorldSocket::ReadDataHandler() } std::shared_ptr<WorldPackets::Auth::AuthContinuedSession> authSession = std::make_shared<WorldPackets::Auth::AuthContinuedSession>(std::move(packet)); - authSession->Read(); + if (!authSession->ReadNoThrow()) + { + TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client %s sent malformed CMSG_AUTH_CONTINUED_SESSION", GetRemoteIpAddress().to_string().c_str()); + return ReadDataHandlerResult::Error; + } HandleAuthContinuedSession(authSession); return ReadDataHandlerResult::WaitingForQuery; } @@ -419,7 +437,11 @@ WorldSocket::ReadDataHandlerResult WorldSocket::ReadDataHandler() LogOpcodeText(opcode, sessionGuard); WorldPackets::Auth::ConnectToFailed connectToFailed(std::move(packet)); - connectToFailed.Read(); + if (!connectToFailed.ReadNoThrow()) + { + TC_LOG_ERROR("network", "WorldSocket::ReadDataHandler(): client %s sent malformed CMSG_CONNECT_TO_FAILED", GetRemoteIpAddress().to_string().c_str()); + return ReadDataHandlerResult::Error; + } HandleConnectToFailed(connectToFailed); break; } @@ -924,17 +946,10 @@ void WorldSocket::SendAuthResponseError(uint32 code) SendPacketAndLogOpcode(*response.Write()); } -bool WorldSocket::HandlePing(WorldPacket& recvPacket) +bool WorldSocket::HandlePing(WorldPackets::Auth::Ping& ping) { using namespace std::chrono; - uint32 ping; - uint32 latency; - - // Get the ping packet content - recvPacket >> ping; - recvPacket >> latency; - if (_LastPingTime == steady_clock::time_point()) { _LastPingTime = steady_clock::now(); @@ -975,7 +990,7 @@ bool WorldSocket::HandlePing(WorldPacket& recvPacket) if (_worldSession) { - _worldSession->SetLatency(latency); + _worldSession->SetLatency(ping.Latency); _worldSession->ResetClientTimeDelay(); } else @@ -985,8 +1000,6 @@ bool WorldSocket::HandlePing(WorldPacket& recvPacket) } } - WorldPacket packet(SMSG_PONG, 4); - packet << ping; - SendPacketAndLogOpcode(packet); + SendPacketAndLogOpcode(*WorldPackets::Auth::Pong(ping.Serial).Write()); return true; } diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index 44f253d0864..0b78e36a3f5 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -41,6 +41,7 @@ namespace WorldPackets class AuthSession; class AuthContinuedSession; class ConnectToFailed; + class Ping; } } @@ -118,10 +119,9 @@ private: void HandleAuthContinuedSessionCallback(std::shared_ptr<WorldPackets::Auth::AuthContinuedSession> authSession, PreparedQueryResult result); void LoadSessionPermissionsCallback(PreparedQueryResult result); void HandleConnectToFailed(WorldPackets::Auth::ConnectToFailed& connectToFailed); + bool HandlePing(WorldPackets::Auth::Ping& ping); void HandleEnableEncryptionAck(); - bool HandlePing(WorldPacket& recvPacket); - ConnectionType _type; uint64 _key; diff --git a/src/server/game/Spells/Auras/SpellAuraDefines.h b/src/server/game/Spells/Auras/SpellAuraDefines.h index 34023c16d1b..8a147c88f24 100644 --- a/src/server/game/Spells/Auras/SpellAuraDefines.h +++ b/src/server/game/Spells/Auras/SpellAuraDefines.h @@ -390,7 +390,7 @@ enum AuraType SPELL_AURA_CAST_WHILE_WALKING = 330, SPELL_AURA_FORCE_WEATHER = 331, SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS = 332, - SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_2 = 333, + SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_TRIGGERED = 333, // Spells cast with this override have no cast time or power cost SPELL_AURA_MOD_BLIND = 334, // NYI SPELL_AURA_335 = 335, SPELL_AURA_MOD_FLYING_RESTRICTIONS = 336, // NYI diff --git a/src/server/game/Spells/Auras/SpellAuraEffects.cpp b/src/server/game/Spells/Auras/SpellAuraEffects.cpp index 21eb48c3fa5..da8b43f37dc 100644 --- a/src/server/game/Spells/Auras/SpellAuraEffects.cpp +++ b/src/server/game/Spells/Auras/SpellAuraEffects.cpp @@ -391,8 +391,8 @@ pAuraEffectHandler AuraEffectHandler[TOTAL_AURAS]= &AuraEffect::HandleNULL, //329 SPELL_AURA_MOD_RUNE_REGEN_SPEED &AuraEffect::HandleNoImmediateEffect, //330 SPELL_AURA_CAST_WHILE_WALKING &AuraEffect::HandleAuraForceWeather, //331 SPELL_AURA_FORCE_WEATHER - &AuraEffect::HandleNoImmediateEffect, //332 SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS implemented in WorldSession::HandleCastSpellOpcode - &AuraEffect::HandleNoImmediateEffect, //333 SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_2 implemented in WorldSession::HandleCastSpellOpcode + &AuraEffect::HandleNoImmediateEffect, //332 SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS implemented in Unit::GetCastSpellInfo + &AuraEffect::HandleNoImmediateEffect, //333 SPELL_AURA_OVERRIDE_ACTIONBAR_SPELLS_TRIGGERED implemented in Unit::GetCastSpellInfo &AuraEffect::HandleNULL, //334 SPELL_AURA_MOD_BLIND &AuraEffect::HandleNULL, //335 SPELL_AURA_335 &AuraEffect::HandleNULL, //336 SPELL_AURA_MOD_FLYING_RESTRICTIONS diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 595855370f6..e613952e015 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -24,7 +24,6 @@ #include "GridNotifiersImpl.h" #include "Opcodes.h" #include "Log.h" -#include "UpdateMask.h" #include "World.h" #include "ObjectMgr.h" #include "SpellMgr.h" diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 6a98cd525c2..22518c8fbda 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -21,7 +21,6 @@ #include "WorldPacket.h" #include "Opcodes.h" #include "Log.h" -#include "UpdateMask.h" #include "World.h" #include "ObjectMgr.h" #include "SpellMgr.h" diff --git a/src/server/game/Tools/PlayerDump.cpp b/src/server/game/Tools/PlayerDump.cpp index b3417cebc1e..877dcc3a07d 100644 --- a/src/server/game/Tools/PlayerDump.cpp +++ b/src/server/game/Tools/PlayerDump.cpp @@ -19,7 +19,6 @@ #include "Common.h" #include "PlayerDump.h" #include "DatabaseEnv.h" -#include "UpdateFields.h" #include "ObjectMgr.h" #include "Player.h" #include "AccountMgr.h" diff --git a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp index 7563a880f0a..040d8cb2a37 100644 --- a/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp +++ b/src/server/scripts/EasternKingdoms/SunwellPlateau/boss_kiljaeden.cpp @@ -1361,7 +1361,7 @@ public: DoCastVictim(SPELL_SR_SHOOT, false); uiTimer[2] = urand(4000, 6000); } - if (me->IsWithinMeleeRange(me->GetVictim(), 6)) + if (me->IsWithinMeleeRange(me->GetVictim())) { if (uiTimer[0] <= diff) { diff --git a/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp b/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp index e47392eda40..adf273e814c 100644 --- a/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp +++ b/src/server/scripts/Outland/TempestKeep/botanica/boss_warp_splinter.cpp @@ -103,7 +103,7 @@ class npc_warp_splinter_treant : public CreatureScript { if (Unit* Warp = ObjectAccessor::GetUnit(*me, WarpGuid)) { - if (me->IsWithinMeleeRange(Warp, 2.5f)) + if (me->IsWithinMeleeRange(Warp)) { int32 CurrentHP_Treant = (int32)me->GetHealth(); Warp->CastCustomSpell(Warp, SPELL_HEAL_FATHER, &CurrentHP_Treant, 0, 0, true, 0, 0, me->GetGUID()); |