diff --git a/src/common/Collision/Management/IVMapManager.h b/src/common/Collision/Management/IVMapManager.h index e9aae51a02..cfa4c19290 100644 --- a/src/common/Collision/Management/IVMapManager.h +++ b/src/common/Collision/Management/IVMapManager.h @@ -50,27 +50,6 @@ namespace VMAP #define VMAP_INVALID_HEIGHT -100000.0f // for check #define VMAP_INVALID_HEIGHT_VALUE -200000.0f // real assigned value in unknown height case - struct AreaAndLiquidData - { - struct AreaInfo - { - AreaInfo(int32 _adtId, int32 _rootId, int32 _groupId, uint32 _flags) : adtId(_adtId), rootId(_rootId), groupId(_groupId), mogpFlags(_flags) { } - int32 const adtId; - int32 const rootId; - int32 const groupId; - uint32 const mogpFlags; - }; - struct LiquidInfo - { - LiquidInfo(uint32 _type, float _level) : type(_type), level(_level) { } - uint32 const type; - float const level; - }; - - float floorZ = VMAP_INVALID_HEIGHT; - Optional areaInfo; - Optional liquidInfo; - }; //=========================================================== class TC_COMMON_API IVMapManager { @@ -124,8 +103,6 @@ namespace VMAP */ virtual bool getAreaInfo(unsigned int pMapId, float x, float y, float &z, uint32 &flags, int32 &adtId, int32 &rootId, int32 &groupId) const=0; virtual bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 ReqLiquidType, float &level, float &floor, uint32 &type) const=0; - // get both area + liquid data in a single vmap lookup - virtual void getAreaAndLiquidData(unsigned int mapId, float x, float y, float z, uint8 reqLiquidType, AreaAndLiquidData& data) const=0; }; } diff --git a/src/common/Collision/Management/VMapManager2.cpp b/src/common/Collision/Management/VMapManager2.cpp index f302d6e0f4..428c283720 100644 --- a/src/common/Collision/Management/VMapManager2.cpp +++ b/src/common/Collision/Management/VMapManager2.cpp @@ -306,39 +306,6 @@ namespace VMAP return false; } - void VMapManager2::getAreaAndLiquidData(unsigned int mapId, float x, float y, float z, uint8 reqLiquidType, AreaAndLiquidData& data) const - { - if (IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LIQUIDSTATUS)) - { - data.floorZ = z; - int32 adtId, rootId, groupId; - uint32 flags; - if (getAreaInfo(mapId, x, y, data.floorZ, flags, adtId, rootId, groupId)) - data.areaInfo = boost::in_place(adtId, rootId, groupId, flags); - return; - } - auto instanceTree = GetMapTree(mapId); - if (instanceTree != iInstanceMapTrees.end()) - { - LocationInfo info; - Vector3 pos = convertPositionToInternalRep(x, y, z); - if (instanceTree->second->GetLocationInfo(pos, info)) - { - ASSERT(info.hitModel); - ASSERT(info.hitInstance); - data.floorZ = info.ground_Z; - uint32 liquidType = info.hitModel->GetLiquidType(); - float liquidLevel; - if (!reqLiquidType || (GetLiquidFlagsPtr(liquidType) & reqLiquidType)) - if (info.hitInstance->GetLiquidLevel(pos, info, liquidLevel)) - data.liquidInfo = boost::in_place(liquidType, liquidLevel); - - if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_AREAFLAG)) - data.areaInfo = boost::in_place(info.hitInstance->adtId, info.rootId, info.hitModel->GetWmoID(), info.hitModel->GetMogpFlags()); - } - } - } - WorldModel* VMapManager2::acquireModelInstance(const std::string& basepath, const std::string& filename, uint32 flags/* Only used when creating the model */) { //! Critical section, thread safe access to iLoadedModelFiles diff --git a/src/common/Collision/Management/VMapManager2.h b/src/common/Collision/Management/VMapManager2.h index f07a8f73b2..b617e6e857 100644 --- a/src/common/Collision/Management/VMapManager2.h +++ b/src/common/Collision/Management/VMapManager2.h @@ -122,7 +122,6 @@ namespace VMAP bool getAreaInfo(unsigned int pMapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const override; bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 reqLiquidType, float& level, float& floor, uint32& type) const override; - void getAreaAndLiquidData(unsigned int mapId, float x, float y, float z, uint8 reqLiquidType, AreaAndLiquidData& data) const override; WorldModel* acquireModelInstance(const std::string& basepath, const std::string& filename, uint32 flags = 0); void releaseModelInstance(const std::string& filename); diff --git a/src/common/Collision/Maps/MapTree.h b/src/common/Collision/Maps/MapTree.h index 7cc56813d9..3d6112e7d9 100644 --- a/src/common/Collision/Maps/MapTree.h +++ b/src/common/Collision/Maps/MapTree.h @@ -34,8 +34,7 @@ namespace VMAP struct TC_COMMON_API LocationInfo { - LocationInfo(): rootId(-1), hitInstance(nullptr), hitModel(nullptr), ground_Z(-G3D::finf()) { } - int32 rootId; + LocationInfo(): hitInstance(nullptr), hitModel(nullptr), ground_Z(-G3D::finf()) { } const ModelInstance* hitInstance; const GroupModel* hitModel; float ground_Z; diff --git a/src/common/Collision/Models/WorldModel.cpp b/src/common/Collision/Models/WorldModel.cpp index e111bd8948..58c47c1d63 100644 --- a/src/common/Collision/Models/WorldModel.cpp +++ b/src/common/Collision/Models/WorldModel.cpp @@ -531,7 +531,6 @@ namespace VMAP groupTree.intersectPoint(p, callback); if (callback.hit != groupModels.end()) { - info.rootId = RootWMOID; info.hitModel = &(*callback.hit); dist = callback.zDist; return true; diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 8e0af8bb38..6331ff1886 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -2725,7 +2725,7 @@ void Creature::UpdateMovementFlags() return; // Set the movement flags if the creature is in that mode. (Only fly if actually in air, only swim if in water, etc) - float ground = GetFloorZ(); + float ground = GetMap()->GetHeight(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZMinusOffset()); bool isInAir = (G3D::fuzzyGt(GetPositionZMinusOffset(), ground + 0.05f) || G3D::fuzzyLt(GetPositionZMinusOffset(), ground - 0.05f)); // Can be underground too, prevent the falling diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 6faab3cf2d..0a90e59023 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1214,9 +1214,8 @@ void MovementInfo::OutDebug() WorldObject::WorldObject(bool isWorldObject) : WorldLocation(), LastUsedScriptID(0), m_name(""), m_isActive(false), m_isFarVisible(false), m_isWorldObject(isWorldObject), m_zoneScript(nullptr), -m_transport(nullptr), m_zoneId(0), m_areaId(0), m_staticFloorZ(VMAP_INVALID_HEIGHT), m_currMap(nullptr), m_InstanceId(0), -m_phaseMask(PHASEMASK_NORMAL), _dbPhase(0), m_notifyflags(0), m_executed_notifies(0), -m_aiAnimKitId(0), m_movementAnimKitId(0), m_meleeAnimKitId(0) +m_transport(nullptr), m_currMap(nullptr), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL), _dbPhase(0), +m_notifyflags(0), m_executed_notifies(0), m_aiAnimKitId(0), m_movementAnimKitId(0), m_meleeAnimKitId(0) { m_serverSideVisibility.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE | GHOST_VISIBILITY_GHOST); m_serverSideVisibilityDetect.SetValue(SERVERSIDE_VISIBILITY_GHOST, GHOST_VISIBILITY_ALIVE); @@ -1297,26 +1296,19 @@ void WorldObject::_Create(ObjectGuid::LowType guidlow, HighGuid guidhigh, uint32 m_phaseMask = phaseMask; } -void WorldObject::UpdatePositionData() +uint32 WorldObject::GetZoneId() const { - PositionFullTerrainStatus data; - GetMap()->GetFullTerrainStatusForPosition(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ(), data); - ProcessPositionDataChanged(data); + return GetMap()->GetZoneId(GetPhaseShift(), m_positionX, m_positionY, m_positionZ); } -void WorldObject::ProcessPositionDataChanged(PositionFullTerrainStatus const& data) +uint32 WorldObject::GetAreaId() const { - m_zoneId = m_areaId = data.areaId; - if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(m_areaId)) - if (area->zone) - m_zoneId = area->zone; - m_staticFloorZ = data.floorZ; + return GetMap()->GetAreaId(GetPhaseShift(), m_positionX, m_positionY, m_positionZ); } -void WorldObject::AddToWorld() +void WorldObject::GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const { - Object::AddToWorld(); - GetBaseMap()->GetZoneAndAreaId(GetPhaseShift(), m_zoneId, m_areaId, GetPositionX(), GetPositionY(), GetPositionZ()); + GetMap()->GetZoneAndAreaId(GetPhaseShift(), zoneid, areaid, m_positionX, m_positionY, m_positionZ); } void WorldObject::RemoveFromWorld() @@ -2741,13 +2733,6 @@ ObjectGuid WorldObject::GetTransGUID() const return ObjectGuid::Empty; } -float WorldObject::GetFloorZ() const -{ - if (!IsInWorld()) - return m_staticFloorZ; - return std::max(m_staticFloorZ, GetMap()->GetGameObjectFloor(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ())); -} - template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::list&, uint32, float) const; template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::deque&, uint32, float) const; template TC_GAME_API void WorldObject::GetGameObjectListWithEntryInGrid(std::vector&, uint32, float) const; diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 958107e5ad..53b0c8d174 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -272,8 +272,7 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation virtual void Update (uint32 /*time_diff*/) { } void _Create(ObjectGuid::LowType guidlow, HighGuid guidhigh, uint32 phaseMask); - void AddToWorld() override; - void RemoveFromWorld() override; + virtual void RemoveFromWorld(); void GetNearPoint2D(float &x, float &y, float distance, float absAngle) const; void GetNearPoint(WorldObject const* searcher, float &x, float &y, float &z, float searcher_size, float distance2d, float absAngle) const; @@ -310,9 +309,9 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation // if negative it is used as PhaseGroupId void SetDBPhase(int32 p) { _dbPhase = p; } - uint32 GetZoneId() const { return m_zoneId; } - uint32 GetAreaId() const { return m_areaId; } - void GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const { zoneid = m_zoneId, areaid = m_areaId; } + uint32 GetZoneId() const; + uint32 GetAreaId() const; + void GetZoneAndAreaId(uint32& zoneid, uint32& areaid) const; InstanceScript* GetInstanceScript() const; @@ -420,7 +419,6 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation { UpdateObjectVisibility(true); } - void UpdatePositionData(); void BuildUpdate(UpdateDataMapType&) override; @@ -464,8 +462,6 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation virtual float GetStationaryZ() const { return GetPositionZ(); } virtual float GetStationaryO() const { return GetOrientation(); } - float GetFloorZ() const; - uint16 GetAIAnimKitId() const { return m_aiAnimKitId; } void SetAIAnimKitId(uint16 animKitId); uint16 GetMovementAnimKitId() const { return m_movementAnimKitId; } @@ -483,11 +479,6 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation // transports Transport* m_transport; - virtual void ProcessPositionDataChanged(PositionFullTerrainStatus const& data); - uint32 m_zoneId; - uint32 m_areaId; - float m_staticFloorZ; - //these functions are used mostly for Relocate() and Corpse/Player specific stuff... //use them ONLY in LoadFromDB()/Create() funcs and nowhere else! //mapId/instanceId should be set in SetMap() function! diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index d17dae14c9..769297eec8 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -25142,53 +25142,77 @@ void Player::SetOriginalGroup(Group* group, int8 subgroup) } } -void Player::ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional const& liquidData) +void Player::UpdateUnderwaterState(Map* m, float x, float y, float z) { - if (IsFlying()) - return; - - // process liquid auras using generic unit code - Unit::ProcessTerrainStatusUpdate(status, liquidData); - - // player specific logic for mirror timers - if (status && liquidData) + LiquidData liquid_status; + ZLiquidStatus res = m->GetLiquidStatus(GetPhaseShift(), x, y, z, MAP_ALL_LIQUIDS, &liquid_status); + if (!res) { - // Breath bar state (under water in any liquid type) - if (liquidData->type_flags & MAP_ALL_LIQUIDS) - { - if (status & LIQUID_MAP_UNDER_WATER) - m_MirrorTimerFlags |= UNDERWATER_INWATER; - else - m_MirrorTimerFlags &= ~UNDERWATER_INWATER; - } - - // Fatigue bar state (if not on flight path or transport) - if ((liquidData->type_flags & MAP_LIQUID_TYPE_DARK_WATER) && !IsInFlight() && !GetTransport()) - m_MirrorTimerFlags |= UNDERWATER_INDARKWATER; - else - m_MirrorTimerFlags &= ~UNDERWATER_INDARKWATER; - - // Lava state (any contact) - if (liquidData->type_flags & MAP_LIQUID_TYPE_MAGMA) - { - if (status & MAP_LIQUID_STATUS_IN_CONTACT) - m_MirrorTimerFlags |= UNDERWATER_INLAVA; - else - m_MirrorTimerFlags &= ~UNDERWATER_INLAVA; - } - - // Slime state (any contact) - if (liquidData->type_flags & MAP_LIQUID_TYPE_SLIME) - { - if (status & MAP_LIQUID_STATUS_IN_CONTACT) - m_MirrorTimerFlags |= UNDERWATER_INSLIME; - else - m_MirrorTimerFlags &= ~UNDERWATER_INSLIME; - } - } - else m_MirrorTimerFlags &= ~(UNDERWATER_INWATER | UNDERWATER_INLAVA | UNDERWATER_INSLIME | UNDERWATER_INDARKWATER); + if (_lastLiquid && _lastLiquid->SpellId) + RemoveAurasDueToSpell(_lastLiquid->SpellId); + _lastLiquid = nullptr; + return; + } + + if (uint32 liqEntry = liquid_status.entry) + { + LiquidTypeEntry const* liquid = sLiquidTypeStore.LookupEntry(liqEntry); + if (_lastLiquid && _lastLiquid->SpellId && _lastLiquid != liquid) + RemoveAurasDueToSpell(_lastLiquid->SpellId); + + if (liquid && liquid->SpellId) + { + if (res & (LIQUID_MAP_UNDER_WATER | LIQUID_MAP_IN_WATER)) + { + if (!HasAura(liquid->SpellId)) + CastSpell(this, liquid->SpellId, true); + } + else + RemoveAurasDueToSpell(liquid->SpellId); + } + + _lastLiquid = liquid; + } + else if (_lastLiquid && _lastLiquid->SpellId) + { + RemoveAurasDueToSpell(_lastLiquid->SpellId); + _lastLiquid = nullptr; + } + + + // All liquids type - check under water position + if (liquid_status.type_flags & (MAP_LIQUID_TYPE_WATER | MAP_LIQUID_TYPE_OCEAN | MAP_LIQUID_TYPE_MAGMA | MAP_LIQUID_TYPE_SLIME)) + { + if (res & LIQUID_MAP_UNDER_WATER) + m_MirrorTimerFlags |= UNDERWATER_INWATER; + else + m_MirrorTimerFlags &= ~UNDERWATER_INWATER; + } + + // Allow travel in dark water on taxi or transport + if ((liquid_status.type_flags & MAP_LIQUID_TYPE_DARK_WATER) && !IsInFlight() && !GetTransport()) + m_MirrorTimerFlags |= UNDERWATER_INDARKWATER; + else + m_MirrorTimerFlags &= ~UNDERWATER_INDARKWATER; + + // in lava check, anywhere in lava level + if (liquid_status.type_flags & MAP_LIQUID_TYPE_MAGMA) + { + if (res & (LIQUID_MAP_UNDER_WATER | LIQUID_MAP_IN_WATER | LIQUID_MAP_WATER_WALK)) + m_MirrorTimerFlags |= UNDERWATER_INLAVA; + else + m_MirrorTimerFlags &= ~UNDERWATER_INLAVA; + } + // in slime check, anywhere in slime level + if (liquid_status.type_flags & MAP_LIQUID_TYPE_SLIME) + { + if (res & (LIQUID_MAP_UNDER_WATER | LIQUID_MAP_IN_WATER | LIQUID_MAP_WATER_WALK)) + m_MirrorTimerFlags |= UNDERWATER_INSLIME; + else + m_MirrorTimerFlags &= ~UNDERWATER_INSLIME; + } } void Player::SetCanParry(bool value) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index a2f4840379..84e1780de0 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1856,7 +1856,7 @@ class TC_GAME_API Player : public Unit, public GridObject bool UpdatePosition(float x, float y, float z, float orientation, bool teleport = false) override; bool UpdatePosition(Position const& pos, bool teleport = false) override { return UpdatePosition(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), pos.GetOrientation(), teleport); } - void ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional const& liquidData) override; + void UpdateUnderwaterState(Map* m, float x, float y, float z) override; void SendMessageToSet(WorldPacket* data, bool self) override { SendMessageToSetInRange(data, GetVisibilityRange(), self); } void SendMessageToSetInRange(WorldPacket* data, float dist, bool self) override; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 6b67b49e1f..b503dff888 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -484,6 +484,7 @@ void Unit::Update(uint32 p_time) UpdateSplineMovement(p_time); i_motionMaster->UpdateMotion(p_time); + UpdateUnderwaterState(GetMap(), GetPositionX(), GetPositionY(), GetPositionZ()); } bool Unit::haveOffhandWeapon() const @@ -3177,35 +3178,48 @@ bool Unit::IsUnderWater() const return GetBaseMap()->IsUnderWater(GetPhaseShift(), GetPositionX(), GetPositionY(), GetPositionZ()); } -void Unit::ProcessPositionDataChanged(PositionFullTerrainStatus const& data) +void Unit::UpdateUnderwaterState(Map* m, float x, float y, float z) { - WorldObject::ProcessPositionDataChanged(data); - ProcessTerrainStatusUpdate(data.liquidStatus, data.liquidInfo); -} - -void Unit::ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional const& liquidData) -{ - if (IsFlying() || (!IsControlledByPlayer())) + if (IsFlying() || (!IsPet() && !IsVehicle())) return; - // remove appropriate auras if we are swimming/not swimming respectively - if (status & MAP_LIQUID_STATUS_SWIMMING) - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_ABOVEWATER); - else - RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_UNDERWATER); - - // liquid aura handling - LiquidTypeEntry const* curLiquid = nullptr; - if ((status & MAP_LIQUID_STATUS_SWIMMING) && liquidData) - curLiquid = sLiquidTypeStore.LookupEntry(liquidData->entry); - if (curLiquid != _lastLiquid) + LiquidData liquid_status; + ZLiquidStatus res = m->GetLiquidStatus(GetPhaseShift(), x, y, z, MAP_ALL_LIQUIDS, &liquid_status); + if (!res) { if (_lastLiquid && _lastLiquid->SpellId) RemoveAurasDueToSpell(_lastLiquid->SpellId); - Player* player = GetCharmerOrOwnerPlayerOrPlayerItself(); - if (curLiquid && curLiquid->SpellId && (!player || !player->IsGameMaster())) - CastSpell(this, curLiquid->SpellId, true); - _lastLiquid = curLiquid; + + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_UNDERWATER); + _lastLiquid = NULL; + return; + } + + if (uint32 liqEntry = liquid_status.entry) + { + LiquidTypeEntry const* liquid = sLiquidTypeStore.LookupEntry(liqEntry); + if (_lastLiquid && _lastLiquid->SpellId && _lastLiquid->Id != liqEntry) + RemoveAurasDueToSpell(_lastLiquid->SpellId); + + if (liquid && liquid->SpellId) + { + if (res & (LIQUID_MAP_UNDER_WATER | LIQUID_MAP_IN_WATER)) + { + if (!HasAura(liquid->SpellId)) + CastSpell(this, liquid->SpellId, true); + } + else + RemoveAurasDueToSpell(liquid->SpellId); + } + + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_ABOVEWATER); + _lastLiquid = liquid; + } + else if (_lastLiquid && _lastLiquid->SpellId) + { + RemoveAurasDueToSpell(_lastLiquid->SpellId); + RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_NOT_UNDERWATER); + _lastLiquid = NULL; } } @@ -13742,7 +13756,8 @@ bool Unit::UpdatePosition(float x, float y, float z, float orientation, bool tel else if (turn) UpdateOrientation(orientation); - UpdatePositionData(); + // code block for underwater state update + UpdateUnderwaterState(GetMap(), x, y, z); return (relocated || turn); } diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 5cf383c341..63db28fd31 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1259,6 +1259,7 @@ class TC_GAME_API Unit : public WorldObject virtual bool IsInWater() const; virtual bool IsUnderWater() const; + virtual void UpdateUnderwaterState(Map* m, float x, float y, float z); bool isInAccessiblePlaceFor(Creature const* c) const; void SendHealSpellLog(HealInfo& healInfo, bool critical = false); @@ -1973,9 +1974,6 @@ class TC_GAME_API Unit : public WorldObject void DisableSpline(); - void ProcessPositionDataChanged(PositionFullTerrainStatus const& data) override; - virtual void ProcessTerrainStatusUpdate(ZLiquidStatus status, Optional const& liquidData); - private: void UpdateSplineMovement(uint32 t_diff); diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index c4f3ffd48e..a532c85fa4 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -1049,7 +1049,6 @@ void Map::PlayerRelocation(Player* player, float x, float y, float z, float orie AddToGrid(player, new_cell); } - player->UpdatePositionData(); player->UpdateObjectVisibility(false); } @@ -1084,7 +1083,6 @@ void Map::CreatureRelocation(Creature* creature, float x, float y, float z, floa if (creature->IsVehicle()) creature->GetVehicleKit()->RelocatePassengers(); creature->UpdateObjectVisibility(false); - creature->UpdatePositionData(); RemoveCreatureFromMoveList(creature); } @@ -1115,7 +1113,6 @@ void Map::GameObjectRelocation(GameObject* go, float x, float y, float z, float { go->Relocate(x, y, z, orientation); go->UpdateModelPosition(); - go->UpdatePositionData(); go->UpdateObjectVisibility(false); RemoveGameObjectFromMoveList(go); } @@ -1148,7 +1145,6 @@ void Map::DynamicObjectRelocation(DynamicObject* dynObj, float x, float y, float else { dynObj->Relocate(x, y, z, orientation); - dynObj->UpdatePositionData(); dynObj->UpdateObjectVisibility(false); RemoveDynamicObjectFromMoveList(dynObj); } @@ -1242,7 +1238,6 @@ void Map::MoveAllCreaturesInMoveList() if (c->IsVehicle()) c->GetVehicleKit()->RelocatePassengers(); //CreatureRelocationNotify(c, new_cell, new_cell.cellCoord()); - c->UpdatePositionData(); c->UpdateObjectVisibility(false); } else @@ -1297,7 +1292,6 @@ void Map::MoveAllGameObjectsInMoveList() // update pos go->Relocate(go->_newPosition); go->UpdateModelPosition(); - go->UpdatePositionData(); go->UpdateObjectVisibility(false); } else @@ -1342,7 +1336,6 @@ void Map::MoveAllDynamicObjectsInMoveList() { // update pos dynObj->Relocate(dynObj->_newPosition); - dynObj->UpdatePositionData(); dynObj->UpdateObjectVisibility(false); } else @@ -1563,7 +1556,6 @@ bool Map::CreatureRespawnRelocation(Creature* c, bool diffGridOnly) c->Relocate(resp_x, resp_y, resp_z, resp_o); c->GetMotionMaster()->Initialize(); // prevent possible problems with default move generators //CreatureRelocationNotify(c, resp_cell, resp_cell.GetCellCoord()); - c->UpdatePositionData(); c->UpdateObjectVisibility(false); return true; } @@ -1589,7 +1581,6 @@ bool Map::GameObjectRespawnRelocation(GameObject* go, bool diffGridOnly) if (GameObjectCellRelocation(go, resp_cell)) { go->Relocate(resp_x, resp_y, resp_z, resp_o); - go->UpdatePositionData(); go->UpdateObjectVisibility(false); return true; } @@ -2500,6 +2491,11 @@ uint32 Map::GetAreaId(PhaseShift const& phaseShift, float x, float y, float z, b return areaId; } +uint32 Map::GetAreaId(PhaseShift const& phaseShift, float x, float y, float z) const +{ + return GetAreaId(phaseShift, x, y, z, nullptr); +} + uint32 Map::GetZoneId(PhaseShift const& phaseShift, float x, float y, float z) const { uint32 areaId = GetAreaId(phaseShift, x, y, z); @@ -2612,108 +2608,6 @@ ZLiquidStatus Map::GetLiquidStatus(PhaseShift const& phaseShift, float x, float return result; } -void Map::GetFullTerrainStatusForPosition(PhaseShift const& phaseShift, float x, float y, float z, PositionFullTerrainStatus& data, uint8 reqLiquidType) const -{ - VMAP::IVMapManager* vmgr = VMAP::VMapFactory::createOrGetVMapManager(); - VMAP::AreaAndLiquidData vmapData; - uint32 terrainMapId = PhasingHandler::GetTerrainMapId(phaseShift, this, x, y); - vmgr->getAreaAndLiquidData(terrainMapId, x, y, z, reqLiquidType, vmapData); - if (vmapData.areaInfo) - data.areaInfo = boost::in_place(vmapData.areaInfo->adtId, vmapData.areaInfo->rootId, vmapData.areaInfo->groupId, vmapData.areaInfo->mogpFlags); - - float mapHeight = VMAP_INVALID_HEIGHT; - GridMap* gmap = const_cast(this)->GetGrid(terrainMapId, x, y); - if (gmap) - mapHeight = gmap->getHeight(x, y); - - // area lookup - AreaTableEntry const* areaEntry = nullptr; - if (vmapData.areaInfo && (z + 2.0f <= mapHeight || mapHeight <= vmapData.floorZ)) - if (WMOAreaTableEntry const* wmoEntry = GetWMOAreaTableEntryByTripple(vmapData.areaInfo->rootId, vmapData.areaInfo->adtId, vmapData.areaInfo->groupId)) - areaEntry = sAreaTableStore.LookupEntry(wmoEntry->areaId); - - data.areaId = 0; - - if (areaEntry) - { - data.floorZ = vmapData.floorZ; - data.areaId = areaEntry->ID; - } - else - { - data.floorZ = mapHeight; - if (gmap) - data.areaId = gmap->getArea(x, y); - else - data.areaId = 0; - - if (!data.areaId) - data.areaId = i_mapEntry->linked_zone; - - if (data.areaId) - areaEntry = sAreaTableStore.LookupEntry(data.areaId); - } - - // liquid processing - data.liquidStatus = LIQUID_MAP_NO_WATER; - if (vmapData.liquidInfo && vmapData.liquidInfo->level > vmapData.floorZ && z + 2.0f > vmapData.floorZ) - { - uint32 liquidType = vmapData.liquidInfo->type; - if (GetId() == 530 && liquidType == 2) // gotta love blizzard hacks - liquidType = 15; - - uint32 liquidFlagType = 0; - if (LiquidTypeEntry const* liquidData = sLiquidTypeStore.LookupEntry(liquidType)) - liquidFlagType = liquidData->Type; - - if (liquidType && liquidType < 21 && areaEntry) - { - uint32 overrideLiquid = areaEntry->LiquidTypeOverride[liquidFlagType]; - if (!overrideLiquid && areaEntry->zone) - { - AreaTableEntry const* zoneEntry = sAreaTableStore.LookupEntry(areaEntry->zone); - if (zoneEntry) - overrideLiquid = zoneEntry->LiquidTypeOverride[liquidFlagType]; - } - - if (LiquidTypeEntry const* overrideData = sLiquidTypeStore.LookupEntry(overrideLiquid)) - { - liquidType = overrideLiquid; - liquidFlagType = overrideData->Type; - } - } - - data.liquidInfo = boost::in_place(); - data.liquidInfo->level = vmapData.liquidInfo->level; - data.liquidInfo->depth_level = vmapData.floorZ; - data.liquidInfo->entry = liquidType; - data.liquidInfo->type_flags = 1 << liquidFlagType; - - float delta = vmapData.liquidInfo->level - z; - if (delta > 2.0f) - data.liquidStatus = LIQUID_MAP_UNDER_WATER; - else if (delta > 0.0f) - data.liquidStatus = LIQUID_MAP_IN_WATER; - else if (delta > -0.1f) - data.liquidStatus = LIQUID_MAP_WATER_WALK; - else - data.liquidStatus = LIQUID_MAP_ABOVE_WATER; - } - // look up liquid data from grid map - if (gmap && (data.liquidStatus == LIQUID_MAP_ABOVE_WATER || data.liquidStatus == LIQUID_MAP_NO_WATER)) - { - LiquidData gridMapLiquid; - ZLiquidStatus gridMapStatus = gmap->GetLiquidStatus(x, y, z, reqLiquidType, &gridMapLiquid); - if (gridMapStatus != LIQUID_MAP_NO_WATER && (gridMapLiquid.level > vmapData.floorZ)) - { - if (GetId() == 530 && gridMapLiquid.entry == 2) - gridMapLiquid.entry = 15; - data.liquidInfo = gridMapLiquid; - data.liquidStatus = gridMapStatus; - } - } -} - float Map::GetWaterLevel(PhaseShift const& phaseShift, float x, float y) const { if (GridMap* gmap = const_cast(this)->GetGrid(PhasingHandler::GetTerrainMapId(phaseShift, this, x, y), x, y)) @@ -2749,7 +2643,7 @@ bool Map::getObjectHitPos(PhaseShift const& phaseShift, float x1, float y1, floa float Map::GetHeight(PhaseShift const& phaseShift, float x, float y, float z, bool vmap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const { - return std::max(GetStaticHeight(phaseShift, x, y, z, vmap, maxSearchDist), GetGameObjectFloor(phaseShift, x, y, z, maxSearchDist)); + return std::max(GetStaticHeight(phaseShift, x, y, z, vmap, maxSearchDist), _dynamicTree.getHeight(x, y, z, maxSearchDist, phaseShift)); } bool Map::IsInWater(PhaseShift const& phaseShift, float x, float y, float pZ, LiquidData* data) const diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index b39209f2f4..45e9dc3253 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -141,9 +141,6 @@ enum ZLiquidStatus : uint32 LIQUID_MAP_UNDER_WATER = 0x00000008 }; -#define MAP_LIQUID_STATUS_SWIMMING (LIQUID_MAP_IN_WATER | LIQUID_MAP_UNDER_WATER) -#define MAP_LIQUID_STATUS_IN_CONTACT (MAP_LIQUID_STATUS_SWIMMING | LIQUID_MAP_WATER_WALK) - #define MAP_LIQUID_TYPE_NO_WATER 0x00 #define MAP_LIQUID_TYPE_WATER 0x01 #define MAP_LIQUID_TYPE_OCEAN 0x02 @@ -163,24 +160,6 @@ struct LiquidData float depth_level; }; -struct PositionFullTerrainStatus -{ - struct AreaInfo - { - AreaInfo(int32 _adtId, int32 _rootId, int32 _groupId, uint32 _flags) : adtId(_adtId), rootId(_rootId), groupId(_groupId), mogpFlags(_flags) { } - int32 const adtId; - int32 const rootId; - int32 const groupId; - uint32 const mogpFlags; - }; - - uint32 areaId; - float floorZ; - ZLiquidStatus liquidStatus; - Optional areaInfo; - Optional liquidInfo; -}; - class TC_GAME_API GridMap { uint32 _flags; @@ -354,12 +333,11 @@ class TC_GAME_API Map : public GridRefManager // some calls like isInWater should not use vmaps due to processor power // can return INVALID_HEIGHT if under z+2 z coord not found height float GetStaticHeight(PhaseShift const& phaseShift, float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const; - - void GetFullTerrainStatusForPosition(PhaseShift const& phaseShift, float x, float y, float z, PositionFullTerrainStatus& data, uint8 reqLiquidType = MAP_ALL_LIQUIDS) const; ZLiquidStatus GetLiquidStatus(PhaseShift const& phaseShift, float x, float y, float z, uint8 ReqLiquidType, LiquidData* data = nullptr) const; bool GetAreaInfo(PhaseShift const& phaseShift, float x, float y, float z, uint32& mogpflags, int32& adtId, int32& rootId, int32& groupId) const; - uint32 GetAreaId(PhaseShift const& phaseShift, float x, float y, float z, bool *isOutdoors = nullptr) const; + uint32 GetAreaId(PhaseShift const& phaseShift, float x, float y, float z) const; + uint32 GetAreaId(PhaseShift const& phaseShift, float x, float y, float z, bool *isOutdoors) const; uint32 GetZoneId(PhaseShift const& phaseShift, float x, float y, float z) const; void GetZoneAndAreaId(PhaseShift const& phaseShift, uint32& zoneid, uint32& areaid, float x, float y, float z) const; @@ -511,10 +489,6 @@ class TC_GAME_API Map : public GridRefManager void RemoveGameObjectModel(const GameObjectModel& model) { _dynamicTree.remove(model); } void InsertGameObjectModel(const GameObjectModel& model) { _dynamicTree.insert(model); } bool ContainsGameObjectModel(const GameObjectModel& model) const { return _dynamicTree.contains(model);} - float GetGameObjectFloor(PhaseShift const& phaseShift, float x, float y, float z, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const - { - return _dynamicTree.getHeight(x, y, z, maxSearchDist, phaseShift); - } bool getObjectHitPos(PhaseShift const& phaseShift, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float &ry, float& rz, float modifyDist); virtual uint32 GetOwnerGuildId(uint32 /*team*/ = TEAM_OTHER) const { return 0; } diff --git a/src/tools/map_extractor/System.cpp b/src/tools/map_extractor/System.cpp index 0f5d6da29a..e318a71e4e 100644 --- a/src/tools/map_extractor/System.cpp +++ b/src/tools/map_extractor/System.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -64,8 +65,26 @@ typedef struct uint32 id; } map_id; +struct LiquidMaterialEntry +{ + int8 LVF; +}; + +struct LiquidObjectEntry +{ + int16 LiquidTypeID; +}; + +struct LiquidTypeEntry +{ + uint8 SoundBank; + uint8 MaterialID; +}; + map_id *map_ids; -uint16 *LiqType; +std::unordered_map LiquidMaterials; +std::unordered_map LiquidObjects; +std::unordered_map LiquidTypes; char output_path[128] = "."; char input_path[128] = "."; @@ -309,7 +328,61 @@ uint32 ReadMapDBC() return map_count; } -void ReadLiquidTypeTableDBC() +void ReadLiquidMaterialTable() +{ + printf("Read LiquidMaterial.dbc file...\n"); + + HANDLE dbcFile; + if (!SFileOpenFileEx(LocaleMpq, "DBFilesClient\\LiquidMaterial.dbc", SFILE_OPEN_PATCHED_FILE, &dbcFile)) + { + printf("Fatal error: Cannot find LiquidMaterial.dbc in archive!\n"); + exit(1); + } + + DBCFile dbc(dbcFile); + if (!dbc.open()) + { + printf("Fatal error: Invalid LiquidMaterial.dbc file format!\n"); + exit(1); + } + + for (uint32 x = 0; x < dbc.getRecordCount(); ++x) + { + LiquidMaterialEntry& liquidType = LiquidMaterials[dbc.getRecord(x).getUInt(0)]; + liquidType.LVF = dbc.getRecord(x).getUInt(1); + } + + printf("Done! (" SZFMTD " LiquidMaterials loaded)\n", LiquidMaterials.size()); +} + +void ReadLiquidObjectTable() +{ + printf("Read LiquidObject.dbc file...\n"); + + HANDLE dbcFile; + if (!SFileOpenFileEx(LocaleMpq, "DBFilesClient\\LiquidObject.dbc", SFILE_OPEN_PATCHED_FILE, &dbcFile)) + { + printf("Fatal error: Cannot find LiquidObject.dbc in archive!\n"); + exit(1); + } + + DBCFile dbc(dbcFile); + if (!dbc.open()) + { + printf("Fatal error: Invalid LiquidObject.dbc file format!\n"); + exit(1); + } + + for (uint32 x = 0; x < dbc.getRecordCount(); ++x) + { + LiquidObjectEntry& liquidType = LiquidObjects[dbc.getRecord(x).getUInt(0)]; + liquidType.LiquidTypeID = dbc.getRecord(x).getUInt(3); + } + + printf("Done! (" SZFMTD " LiquidObjects loaded)\n", LiquidObjects.size()); +} + +void ReadLiquidTypeTable() { printf("Read LiquidType.dbc file..."); HANDLE dbcFile; @@ -326,16 +399,15 @@ void ReadLiquidTypeTableDBC() exit(1); } - size_t liqTypeCount = dbc.getRecordCount(); - size_t liqTypeMaxId = dbc.getMaxId(); - LiqType = new uint16[liqTypeMaxId + 1]; - memset(LiqType, 0xff, (liqTypeMaxId + 1) * sizeof(uint16)); - - for(uint32 x = 0; x < liqTypeCount; ++x) - LiqType[dbc.getRecord(x).getUInt(0)] = dbc.getRecord(x).getUInt(3); + for (uint32 x = 0; x < dbc.getRecordCount(); ++x) + { + LiquidTypeEntry& liquidType = LiquidTypes[dbc.getRecord(x).getUInt(0)]; + liquidType.SoundBank = dbc.getRecord(x).getUInt(3); + liquidType.MaterialID = dbc.getRecord(x).getUInt(14); + } SFileCloseFile(dbcFile); - printf("Done! (%u LiqTypes loaded)\n", (uint32)liqTypeCount); + printf("Done! (" SZFMTD " LiquidTypes loaded)\n", LiquidTypes.size()); } // @@ -434,6 +506,25 @@ uint8 liquid_flags[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; bool liquid_show[ADT_GRID_SIZE][ADT_GRID_SIZE]; float liquid_height[ADT_GRID_SIZE+1][ADT_GRID_SIZE+1]; +LiquidVertexFormatType adt_MH2O::GetLiquidVertexFormat(adt_liquid_instance const* liquidInstance) const +{ + if (liquidInstance->LiquidVertexFormat < 42) + return static_cast(liquidInstance->LiquidVertexFormat); + + if (liquidInstance->LiquidType == 2) + return LiquidVertexFormatType::Depth; + + auto liquidType = LiquidTypes.find(liquidInstance->LiquidType); + if (liquidType != LiquidTypes.end()) + { + auto liquidMaterial = LiquidMaterials.find(liquidType->second.MaterialID); + if (liquidMaterial != LiquidMaterials.end()) + return static_cast(liquidMaterial->second.LVF); + } + + return static_cast(-1); +} + bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/, uint32 build) { ADT_file adt; @@ -730,66 +821,59 @@ bool ConvertADT(char *filename, char *filename2, int /*cell_y*/, int /*cell_x*/, adt_MH2O * h2o = adt.a_grid->getMH2O(); if (h2o) { - for (int i = 0; i < ADT_CELLS_PER_GRID; i++) + for (int32 i = 0; i < ADT_CELLS_PER_GRID; i++) { - for(int j = 0; j < ADT_CELLS_PER_GRID; j++) + for(int32 j = 0; j < ADT_CELLS_PER_GRID; j++) { - adt_liquid_header *h = h2o->getLiquidData(i,j); + adt_liquid_instance const* h = h2o->GetLiquidInstance(i, j); if (!h) continue; - int count = 0; - uint64 show = h2o->getLiquidShowMap(h); - for (int y = 0; y < h->height; y++) + int32 count = 0; + uint64 existsMask = h2o->GetLiquidExistsBitmap(h); + for (int32 y = 0; y < h->Height; y++) { - int cy = i * ADT_CELL_SIZE + y + h->yOffset; - for (int x = 0; x < h->width; x++) + int32 cy = i * ADT_CELL_SIZE + y + h->OffsetY; + for (int32 x = 0; x < h->Width; x++) { - int cx = j * ADT_CELL_SIZE + x + h->xOffset; - if (show & 1) + int32 cx = j * ADT_CELL_SIZE + x + h->OffsetX; + if (existsMask & 1) { liquid_show[cy][cx] = true; ++count; } - show >>= 1; + existsMask >>= 1; } } - liquid_entry[i][j] = h->liquidType; - switch (LiqType[h->liquidType]) + liquid_entry[i][j] = h->LiquidType; + switch (LiquidTypes.at(h->LiquidType).SoundBank) { case LIQUID_TYPE_WATER: liquid_flags[i][j] |= MAP_LIQUID_TYPE_WATER; break; case LIQUID_TYPE_OCEAN: liquid_flags[i][j] |= MAP_LIQUID_TYPE_OCEAN; break; case LIQUID_TYPE_MAGMA: liquid_flags[i][j] |= MAP_LIQUID_TYPE_MAGMA; break; case LIQUID_TYPE_SLIME: liquid_flags[i][j] |= MAP_LIQUID_TYPE_SLIME; break; default: - printf("\nCan't find Liquid type %u for map %s\nchunk %d,%d\n", h->liquidType, filename, i, j); + printf("\nCan't find Liquid type %u for map %s\nchunk %d,%d\n", h->LiquidType, filename, i, j); break; } - // Dark water detect - if (LiqType[h->liquidType] == LIQUID_TYPE_OCEAN) - { - uint8* lm = h2o->getLiquidLightMap(h); - if (!lm) - liquid_flags[i][j] |= MAP_LIQUID_TYPE_DARK_WATER; - } if (!count && liquid_flags[i][j]) printf("Wrong liquid detect in MH2O chunk"); - float* height = h2o->getLiquidHeightMap(h); - int pos = 0; - for (int y = 0; y <= h->height; y++) + int32 pos = 0; + for (int32 y = 0; y <= h->Height; y++) { - int cy = i * ADT_CELL_SIZE + y + h->yOffset; - for (int x = 0; x <= h->width; x++) + int32 cy = i * ADT_CELL_SIZE + y + h->OffsetY; + for (int32 x = 0; x <= h->Width; x++) { - int cx = j * ADT_CELL_SIZE + x + h->xOffset; + int32 cx = j * ADT_CELL_SIZE + x + h->OffsetX; - if (height) - liquid_height[cy][cx] = height[pos]; - else - liquid_height[cy][cx] = h->heightLevel1; + liquid_height[cy][cx] = h2o->GetLiquidHeight(h, pos); + + // Dark water detect + if (liquid_flags[i][j] & MAP_LIQUID_TYPE_OCEAN && h2o->GetLiquidDepth(h, pos) == -1) + liquid_flags[i][j] |= MAP_LIQUID_TYPE_DARK_WATER; pos++; } @@ -978,7 +1062,9 @@ void ExtractMapsFromMpq(uint32 build) uint32 map_count = ReadMapDBC(); - ReadLiquidTypeTableDBC(); + ReadLiquidMaterialTable(); + ReadLiquidObjectTable(); + ReadLiquidTypeTable(); std::string path = output_path; path += "/maps/"; diff --git a/src/tools/map_extractor/adt.h b/src/tools/map_extractor/adt.h index 2e42d9a58d..d2d6cc7544 100644 --- a/src/tools/map_extractor/adt.h +++ b/src/tools/map_extractor/adt.h @@ -177,17 +177,28 @@ public: #define ADT_LIQUID_HEADER_FULL_LIGHT 0x01 #define ADT_LIQUID_HEADER_NO_HIGHT 0x02 -struct adt_liquid_header{ - uint16 liquidType; // Index from LiquidType.dbc - uint16 formatFlags; - float heightLevel1; - float heightLevel2; - uint8 xOffset; - uint8 yOffset; - uint8 width; - uint8 height; - uint32 offsData2a; - uint32 offsData2b; +enum class LiquidVertexFormatType : uint16 +{ + HeightDepth = 0, + HeightTextureCoord = 1, + Depth = 2, + HeightDepthTextureCoord = 3, + Unk4 = 4, + Unk5 = 5 +}; + +struct adt_liquid_instance +{ + uint16 LiquidType; // Index from LiquidType.dbc + uint16 LiquidVertexFormat; // Id from LiquidObject.dbc if >= 42 + float MinHeightLevel; + float MaxHeightLevel; + uint8 OffsetX; + uint8 OffsetY; + uint8 Width; + uint8 Height; + uint32 OffsetExistsBitmap; + uint32 OffsetVertexData; }; // @@ -203,63 +214,101 @@ public: uint32 size; struct adt_LIQUID{ - uint32 offsData1; + uint32 OffsetInstances; uint32 used; - uint32 offsData2; + uint32 OffsetAttributes; } liquid[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID]; bool prepareLoadedData(); - adt_liquid_header *getLiquidData(int x, int y) + adt_liquid_instance const* GetLiquidInstance(int32 x, int32 y) const { - if (liquid[x][y].used && liquid[x][y].offsData1) - return (adt_liquid_header *)((uint8*)this + 8 + liquid[x][y].offsData1); - return 0; + if (liquid[x][y].used && liquid[x][y].OffsetInstances) + return (adt_liquid_instance *)((uint8*)this + 8 + liquid[x][y].OffsetInstances); + return nullptr; } - float *getLiquidHeightMap(adt_liquid_header *h) + float GetLiquidHeight(adt_liquid_instance const* h, int32 pos) const { - if (h->formatFlags & ADT_LIQUID_HEADER_NO_HIGHT) - return 0; - if (h->offsData2b) - return (float *)((uint8*)this + 8 + h->offsData2b); - return 0; - } + if (!h->OffsetVertexData) + return 0.0f; + if (GetLiquidVertexFormat(h) == LiquidVertexFormatType::Depth) + return 0.0f; - uint8 *getLiquidLightMap(adt_liquid_header *h) - { - if (h->formatFlags&ADT_LIQUID_HEADER_FULL_LIGHT) - return 0; - if (h->offsData2b) + switch (GetLiquidVertexFormat(h)) { - if (h->formatFlags & ADT_LIQUID_HEADER_NO_HIGHT) - return (uint8 *)((uint8*)this + 8 + h->offsData2b); - return (uint8 *)((uint8*)this + 8 + h->offsData2b + (h->width+1)*(h->height+1)*4); + case LiquidVertexFormatType::HeightDepth: + case LiquidVertexFormatType::HeightTextureCoord: + case LiquidVertexFormatType::HeightDepthTextureCoord: + return ((float const*)((uint8*)this + 8 + h->OffsetVertexData))[pos]; + case LiquidVertexFormatType::Depth: + return 0.0f; + case LiquidVertexFormatType::Unk4: + case LiquidVertexFormatType::Unk5: + return ((float const*)((uint8*)this + 8 + h->OffsetVertexData + 4))[pos * 2]; + default: + break; + } + + return 0.0f; + } + + int8 GetLiquidDepth(adt_liquid_instance const* h, int32 pos) const + { + if (!h->OffsetVertexData) + return -1; + + switch (GetLiquidVertexFormat(h)) + { + case LiquidVertexFormatType::HeightDepth: + return ((int8 const*)((int8 const*)this + 8 + h->OffsetVertexData + (h->Width + 1) * (h->Height + 1) * 4))[pos]; + case LiquidVertexFormatType::HeightTextureCoord: + return 0; + case LiquidVertexFormatType::Depth: + return ((int8 const*)((uint8*)this + 8 + h->OffsetVertexData))[pos]; + case LiquidVertexFormatType::HeightDepthTextureCoord: + return ((int8 const*)((int8 const*)this + 8 + h->OffsetVertexData + (h->Width + 1) * (h->Height + 1) * 8))[pos]; + case LiquidVertexFormatType::Unk4: + return ((int8 const*)((uint8*)this + 8 + h->OffsetVertexData))[pos * 8]; + case LiquidVertexFormatType::Unk5: + return 0; + default: + break; } return 0; } - uint32 *getLiquidFullLightMap(adt_liquid_header *h) + uint16 const* GetLiquidTextureCoordMap(adt_liquid_instance const* h, int32 pos) const { - if (!(h->formatFlags&ADT_LIQUID_HEADER_FULL_LIGHT)) - return 0; - if (h->offsData2b) + if (!h->OffsetVertexData) + return nullptr; + + switch (GetLiquidVertexFormat(h)) { - if (h->formatFlags & ADT_LIQUID_HEADER_NO_HIGHT) - return (uint32 *)((uint8*)this + 8 + h->offsData2b); - return (uint32 *)((uint8*)this + 8 + h->offsData2b + (h->width+1)*(h->height+1)*4); + case LiquidVertexFormatType::HeightDepth: + case LiquidVertexFormatType::Depth: + case LiquidVertexFormatType::Unk4: + return nullptr; + case LiquidVertexFormatType::HeightTextureCoord: + case LiquidVertexFormatType::HeightDepthTextureCoord: + return (uint16 const*)((uint8 const*)this + 8 + h->OffsetVertexData + 4 * ((h->Width + 1) * (h->Height + 1) + pos)); + case LiquidVertexFormatType::Unk5: + return (uint16 const*)((uint8 const*)this + 8 + h->OffsetVertexData + 8 * ((h->Width + 1) * (h->Height + 1) + pos)); + default: + break; } - return 0; + return nullptr; } - uint64 getLiquidShowMap(adt_liquid_header *h) + uint64 GetLiquidExistsBitmap(adt_liquid_instance const* h) const { - if (h->offsData2a) - return *((uint64 *)((uint8*)this + 8 + h->offsData2a)); + if (h->OffsetExistsBitmap) + return *((uint64 *)((uint8*)this + 8 + h->OffsetExistsBitmap)); else return 0xFFFFFFFFFFFFFFFFuLL; } + LiquidVertexFormatType GetLiquidVertexFormat(adt_liquid_instance const* liquidInstance) const; }; // diff --git a/src/tools/vmap4_extractor/vmapexport.cpp b/src/tools/vmap4_extractor/vmapexport.cpp index 164e3110fe..68398bdc77 100644 --- a/src/tools/vmap4_extractor/vmapexport.cpp +++ b/src/tools/vmap4_extractor/vmapexport.cpp @@ -103,9 +103,27 @@ struct map_info int32 parent_id; }; +struct LiquidMaterialEntry +{ + int8 LVF; +}; + +struct LiquidObjectEntry +{ + int16 LiquidTypeID; +}; + +struct LiquidTypeEntry +{ + uint8 SoundBank; + uint8 MaterialID; +}; + std::map map_ids; std::unordered_set maps_that_are_parents; -uint16 *LiqType = 0; +std::unordered_map LiquidMaterials; +std::unordered_map LiquidObjects; +std::unordered_map LiquidTypes; char output_path[128]="."; char input_path[1024]="."; bool preciseVectorData = false; @@ -252,7 +270,47 @@ void strToLower(char* str) } // copied from contrib/extractor/System.cpp -void ReadLiquidTypeTableDBC() +void ReadLiquidMaterialTable() +{ + printf("Read LiquidMaterial.dbc file...\n"); + + DBCFile dbc(LocaleMpq, "DBFilesClient\\LiquidMaterial.dbc"); + if (!dbc.open()) + { + printf("Fatal error: Invalid LiquidMaterial.dbc file format!\n"); + exit(1); + } + + for (uint32 x = 0; x < dbc.getRecordCount(); ++x) + { + LiquidMaterialEntry& liquidType = LiquidMaterials[dbc.getRecord(x).getUInt(0)]; + liquidType.LVF = dbc.getRecord(x).getUInt(1); + } + + printf("Done! (" SZFMTD " LiquidMaterials loaded)\n", LiquidMaterials.size()); +} + +void ReadLiquidObjectTable() +{ + printf("Read LiquidObject.dbc file...\n"); + + DBCFile dbc(LocaleMpq, "DBFilesClient\\LiquidObject.dbc"); + if (!dbc.open()) + { + printf("Fatal error: Invalid LiquidObject.dbc file format!\n"); + exit(1); + } + + for (uint32 x = 0; x < dbc.getRecordCount(); ++x) + { + LiquidObjectEntry& liquidType = LiquidObjects[dbc.getRecord(x).getUInt(0)]; + liquidType.LiquidTypeID = dbc.getRecord(x).getUInt(3); + } + + printf("Done! (" SZFMTD " LiquidObjects loaded)\n", LiquidObjects.size()); +} + +void ReadLiquidTypeTable() { printf("Read LiquidType.dbc file..."); @@ -263,15 +321,14 @@ void ReadLiquidTypeTableDBC() exit(1); } - size_t LiqType_count = dbc.getRecordCount(); - size_t LiqType_maxid = dbc.getRecord(LiqType_count - 1).getUInt(0); - LiqType = new uint16[LiqType_maxid + 1]; - memset(LiqType, 0xff, (LiqType_maxid + 1) * sizeof(uint16)); + for (uint32 x = 0; x < dbc.getRecordCount(); ++x) + { + LiquidTypeEntry& liquidType = LiquidTypes[dbc.getRecord(x).getUInt(0)]; + liquidType.SoundBank = dbc.getRecord(x).getUInt(3); + liquidType.MaterialID = dbc.getRecord(x).getUInt(14); + } - for(uint32 x = 0; x < LiqType_count; ++x) - LiqType[dbc.getRecord(x).getUInt(0)] = dbc.getRecord(x).getUInt(3); - - printf("Done! (%u LiqTypes loaded)\n", (unsigned int)LiqType_count); + printf("Done! (" SZFMTD " LiquidTypes loaded)\n", LiquidTypes.size()); } bool ExtractWmo() @@ -573,7 +630,9 @@ int main(int argc, char ** argv) break; } - ReadLiquidTypeTableDBC(); + ReadLiquidMaterialTable(); + ReadLiquidObjectTable(); + ReadLiquidTypeTable(); // extract data if (success) @@ -627,6 +686,5 @@ int main(int argc, char ** argv) } printf("Extract %s. Work complete. No errors.\n", versionString); - delete [] LiqType; return 0; }