Compare commits

...

27 Commits

Author SHA1 Message Date
天鹭
89017af6ca
Merge e86727c5b96054a678088aaf0e6b7309784656fc into 3ad79541f6d0e425bed473d0bd37962d6afdb5ba 2025-11-09 19:15:54 +00:00
github-actions[bot]
3ad79541f6 chore(DB): import pending files
Referenced commit(s): be58898d061b940c13f2039695b270a242591de0
2025-11-09 18:05:21 +00:00
sogladev
be58898d06
fix(DB/SmartAI): Howling Fjord quest vehicle Iron Rune Construct (#23063)
Co-authored-by: Killyana <morphone1@gmail.com>
2025-11-09 15:04:17 -03:00
github-actions[bot]
611a85529d chore(DB): import pending files
Referenced commit(s): 040e7a0a4d690532a0bd240a515f0519173d9e4a
2025-11-09 13:15:20 +00:00
Andrew
040e7a0a4d
fix(DB/Creature): Despawn all instances of Superior Healing Ward (#23584) 2025-11-09 10:14:19 -03:00
天鹭
e86727c5b9
Merge branch 'master' into Vmaps 2025-11-08 18:15:36 +08:00
天鹭
5c9623d855
Merge branch 'master' into Vmaps 2025-11-07 15:45:34 +08:00
天鹭
4bcbe2a45a
Merge branch 'master' into Vmaps 2025-11-07 04:50:37 +08:00
天鹭
d5e766a67c
Merge branch 'master' into Vmaps 2025-11-06 04:41:49 +08:00
天鹭
5e4c8001e1
Merge branch 'master' into Vmaps 2025-11-04 22:55:32 +08:00
天鹭
a94e5bc69c
Merge branch 'master' into Vmaps 2025-11-02 14:48:21 +08:00
天鹭
b4dce52620
Merge branch 'master' into Vmaps 2025-10-31 23:31:06 +08:00
天鹭
3b585b9add
Merge branch 'master' into Vmaps 2025-10-31 08:01:22 +08:00
天鹭
2e00e00f62
Merge branch 'master' into Vmaps 2025-10-31 00:55:59 +08:00
天鹭
e3c7b0a8f9
Merge branch 'master' into Vmaps 2025-10-30 11:30:08 +08:00
天鹭
b7c9922fac
Merge branch 'master' into Vmaps 2025-10-28 08:40:52 +08:00
天鹭
297d0cd787
Merge branch 'master' into Vmaps 2025-10-27 16:25:51 +08:00
天鹭
56d4ea4685
Merge branch 'master' into Vmaps 2025-10-26 22:06:56 +08:00
天鹭
13b73f2a92
Merge branch 'master' into Vmaps 2025-10-25 08:42:32 +08:00
sudlud
c1ce87aee8
Merge branch 'master' into Vmaps 2025-10-24 12:01:26 +02:00
天鹭
35bea2f1cb
Merge branch 'master' into Vmaps 2025-10-23 09:25:36 +08:00
天鹭
defb2ff5cb
Merge branch 'master' into Vmaps 2025-10-19 05:29:47 +08:00
天鹭
c2075322f8 O.o
Co-Authored-By: Grimdhex <237474256+Grimdhex@users.noreply.github.com>
2025-10-16 23:06:43 +08:00
天鹭
300bd81aea MAP_ALL_LIQUIDS
Co-Authored-By: Grimdhex <237474256+Grimdhex@users.noreply.github.com>
2025-10-16 23:04:52 +08:00
天鹭
772eaade7c
Merge branch 'master' into Vmaps 2025-10-16 20:59:19 +08:00
天鹭
30777af88a Reset BIH::bounds on tree rebuilds
https: //github.com/TrinityCore/TrinityCore/commit/18200e1b88596dbead10d0b8ecbd10557db43323
Co-Authored-By: Shauren <shauren.trinity@gmail.com>
Co-Authored-By: Grimdhex <237474256+Grimdhex@users.noreply.github.com>
2025-10-15 01:33:59 +08:00
天鹭
be57851191 vmaps
https: //github.com/TrinityCore/TrinityCore/pull/28632
https: //github.com/TrinityCore/TrinityCore/commit/b4d6ca277aef81a49e3654a3eec131ea621da991
https: //github.com/TrinityCore/TrinityCore/commit/5eed7506a253fea65cef7dfb8560667defe4a564
https: //github.com/TrinityCore/TrinityCore/commit/c0d8dba15a1a25756f4297eaa0647797ca13e376
Co-Authored-By: ModoX <moardox@gmail.com>
Co-Authored-By: Shauren <shauren.trinity@gmail.com>
2025-10-14 18:58:07 +08:00
23 changed files with 235 additions and 335 deletions

View File

@ -0,0 +1,3 @@
-- DB update 2025_11_09_01 -> 2025_11_09_02
--
DELETE FROM `creature` WHERE `id1` = 10218;

View File

@ -0,0 +1,67 @@
-- DB update 2025_11_09_02 -> 2025_11_09_03
--
-- Fixes "Bluff", Set `allowOverride` of action list
UPDATE `smart_scripts` SET `action_param3` = 1 WHERE (`entryorguid` IN (23672, 23673, 23675, 24271)) AND (`source_type` = 0) AND (`event_type` = 8) AND (`event_param1` = 44609);
-- Removes double spawns
DELETE FROM `gameobject` WHERE `id` = 186959 AND `guid` IN (264459, 264460, 264461, 264462, 264463, 264464, 264465);
-- Add missing aura. Usage is unknown
DELETE FROM `creature_template_addon` WHERE (`entry` = 24825);
INSERT INTO `creature_template_addon` (`entry`, `path_id`, `mount`, `bytes1`, `bytes2`, `emote`, `visibilityDistanceType`, `auras`) VALUES
(24825, 0, 0, 0, 0, 0, 0, '44652');
-- Disable flying vehicle, but causes camera stuttering on rocket jump
UPDATE `creature_template_movement` SET `Flight` = 0 WHERE (`CreatureId` = 24825);
DELETE FROM `creature_text` WHERE (`CreatureID` = 24825) AND (`GroupID` = 1);
INSERT INTO `creature_text` (`CreatureID`, `GroupID`, `ID`, `Text`, `Type`, `Language`, `Probability`, `Emote`, `Duration`, `Sound`, `BroadcastTextId`, `TextRange`, `comment`) VALUES
(24825, 1, 0, 'Launching.', 12, 0, 100, 0, 0, 0, 23860, 0, 'Iron Rune Construct');
DELETE FROM `smart_scripts` WHERE (`entryorguid` = 24825) AND (`source_type` = 0) AND (`id` IN (15, 16));
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(24825, 0, 15, 0, 31, 0, 100, 512, 44609, 0, 3000, 3000, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Spellhit \'Bluff\' - Say Line 0'),
(24825, 0, 16, 0, 8, 0, 100, 512, 44626, 0, 5000, 5000, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Spellhit \'Rocket Jump\' - Say Line 1');
-- Remove unused 'Say Line 0' in actionscripts
DELETE FROM `smart_scripts` WHERE (`entryorguid` IN (2367201, 2367301, 2367501, 2427101)) AND `source_type` = 9 AND `id` = 1 AND `target_type` = 19 AND `target_param1` = 24825 AND `action_type` = 1 AND `target_param2` = 20;
DELETE FROM `conditions` WHERE (`SourceTypeOrReferenceId` = 13) AND (`SourceGroup` IN (2, 4)) AND (`SourceEntry` = 44608) AND (`SourceId` = 0) AND (`ConditionTypeOrReference` = 31);
INSERT INTO `conditions` (`SourceTypeOrReferenceId`, `SourceGroup`, `SourceEntry`, `SourceId`, `ElseGroup`, `ConditionTypeOrReference`, `ConditionTarget`, `ConditionValue1`, `ConditionValue2`, `ConditionValue3`, `NegativeCondition`, `ErrorType`, `ErrorTextId`, `ScriptName`, `Comment`) VALUES
(13, 4, 44608, 0, 0, 31, 0, 3, 24826, 0, 0, 0, 0, '', 'Rocket Jump'),
(13, 4, 44608, 0, 1, 31, 0, 3, 24827, 0, 0, 0, 0, '', 'Rocket Jump'),
(13, 4, 44608, 0, 2, 31, 0, 3, 24828, 0, 0, 0, 0, '', 'Rocket Jump'),
(13, 4, 44608, 0, 3, 31, 0, 3, 24829, 0, 0, 0, 0, '', 'Rocket Jump'),
(13, 4, 44608, 0, 4, 31, 0, 3, 24831, 0, 0, 0, 0, '', 'Rocket Jump'),
(13, 4, 44608, 0, 5, 31, 0, 3, 24832, 0, 0, 0, 0, '', 'Rocket Jump'),
(13, 2, 44608, 0, 0, 31, 0, 5, 186953, 0, 0, 0, 0, '', 'Rocket Jump'),
(13, 2, 44608, 0, 1, 31, 0, 5, 186960, 0, 0, 0, 0, '', 'Rocket Jump'),
(13, 2, 44608, 0, 2, 31, 0, 5, 186961, 0, 0, 0, 0, '', 'Rocket Jump'),
(13, 2, 44608, 0, 3, 31, 0, 5, 186963, 0, 0, 0, 0, '', 'Rocket Jump'),
(13, 2, 44608, 0, 4, 31, 0, 5, 186962, 0, 0, 0, 0, '', 'Rocket Jump'),
(13, 2, 44608, 0, 5, 31, 0, 5, 186964, 0, 0, 0, 0, '', 'Rocket Jump');
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` = 24825);
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(24825, 0, 0, 0, 54, 0, 100, 512, 0, 0, 0, 0, 0, 0, 75, 44643, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Just Summoned - Add Aura \'Reputation and Language\''),
(24825, 0, 1, 0, 28, 0, 100, 512, 0, 0, 0, 0, 0, 0, 28, 44643, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Passenger Removed - Remove Aura \'Reputation and Language\''),
(24825, 0, 2, 0, 38, 0, 100, 512, 0, 1, 0, 0, 0, 0, 53, 2, 24826, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Data Set 0 1 - Start Waypoint Path 24826'),
(24825, 0, 3, 0, 38, 0, 100, 512, 0, 2, 0, 0, 0, 0, 53, 2, 24827, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Data Set 0 2 - Start Waypoint Path 24827'),
(24825, 0, 4, 0, 38, 0, 100, 512, 0, 3, 0, 0, 0, 0, 53, 2, 24828, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Data Set 0 3 - Start Waypoint Path 24828'),
(24825, 0, 5, 0, 38, 0, 100, 512, 0, 4, 0, 0, 0, 0, 53, 2, 24831, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Data Set 0 4 - Start Waypoint Path 24831'),
(24825, 0, 6, 0, 38, 0, 100, 512, 0, 5, 0, 0, 0, 0, 53, 2, 24829, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Data Set 0 5 - Start Waypoint Path 24829'),
(24825, 0, 7, 0, 38, 0, 100, 512, 0, 6, 0, 0, 0, 0, 53, 2, 24832, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Data Set 0 6 - Start Waypoint Path 24832'),
(24825, 0, 8, 0, 58, 0, 100, 512, 0, 0, 0, 0, 0, 0, 28, 44626, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Path 0 Finished - Remove Aura \'Rocket Jump\''),
(24825, 0, 9, 0, 31, 0, 100, 512, 44609, 0, 3000, 3000, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Target Spellhit \'Bluff\' - Say Line 0'),
(24825, 0, 10, 0, 8, 0, 100, 512, 44626, 0, 5000, 5000, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 'Iron Rune Construct - On Spellhit \'Rocket Jump\' - Say Line 1');
--
UPDATE `creature_template` SET `AIName` = 'SmartAI' WHERE (`entry` IN (24826, 24827, 24828, 24829, 24831, 24832));
DELETE FROM `smart_scripts` WHERE (`source_type` = 0 AND `entryorguid` IN (24826, 24827, 24828, 24829, 24831, 24832));
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `link`, `event_type`, `event_phase_mask`, `event_chance`, `event_flags`, `event_param1`, `event_param2`, `event_param3`, `event_param4`, `event_param5`, `event_param6`, `action_type`, `action_param1`, `action_param2`, `action_param3`, `action_param4`, `action_param5`, `action_param6`, `target_type`, `target_param1`, `target_param2`, `target_param3`, `target_param4`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(24826, 0, 0, 0, 8, 0, 100, 0, 44608, 0, 0, 0, 0, 0, 45, 0, 1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'On Spellhit \'Rocket Jump\' - Set Data 0 1'),
(24827, 0, 0, 0, 8, 0, 100, 0, 44608, 0, 0, 0, 0, 0, 45, 0, 2, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'On Spellhit \'Rocket Jump\' - Set Data 0 2'),
(24828, 0, 0, 0, 8, 0, 100, 0, 44608, 0, 0, 0, 0, 0, 45, 0, 3, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'On Spellhit \'Rocket Jump\' - Set Data 0 3'),
(24831, 0, 0, 0, 8, 0, 100, 0, 44608, 0, 0, 0, 0, 0, 45, 0, 4, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'On Spellhit \'Rocket Jump\' - Set Data 0 4'),
(24829, 0, 0, 0, 8, 0, 100, 0, 44608, 0, 0, 0, 0, 0, 45, 0, 5, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'On Spellhit \'Rocket Jump\' - Set Data 0 5'),
(24832, 0, 0, 0, 8, 0, 100, 0, 44608, 0, 0, 0, 0, 0, 45, 0, 6, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 'On Spellhit \'Rocket Jump\' - Set Data 0 6');
DELETE FROM `smart_scripts` WHERE `source_type` = 9 AND `entryorguid` IN (2482600, 2482700, 2482800, 2482900, 2483100, 2483200);

View File

@ -70,6 +70,7 @@ private:
{ {
tree.clear(); tree.clear();
objects.clear(); objects.clear();
bounds = G3D::AABox::empty();
// create space for the first node // create space for the first node
tree.push_back(3u << 30u); // dummy leaf tree.push_back(3u << 30u); // dummy leaf
tree.insert(tree.end(), 2, 0); tree.insert(tree.end(), 2, 0);
@ -116,6 +117,7 @@ public:
delete[] dat.indices; delete[] dat.indices;
} }
[[nodiscard]] uint32 primCount() const { return objects.size(); } [[nodiscard]] uint32 primCount() const { return objects.size(); }
G3D::AABox const& bound() const { return bounds; }
template<typename RayCallback> template<typename RayCallback>
void intersectRay(const G3D::Ray& r, RayCallback& intersectCallback, float& maxDist, bool stopAtFirstHit) const void intersectRay(const G3D::Ray& r, RayCallback& intersectCallback, float& maxDist, bool stopAtFirstHit) const

View File

@ -170,25 +170,6 @@ private:
VMAP::ModelIgnoreFlags _ignoreFlags; VMAP::ModelIgnoreFlags _ignoreFlags;
}; };
struct DynamicTreeAreaInfoCallback
{
DynamicTreeAreaInfoCallback(uint32 phaseMask) : _phaseMask(phaseMask) { }
void operator()(G3D::Vector3 const& p, GameObjectModel const& obj)
{
obj.IntersectPoint(p, _areaInfo, _phaseMask);
}
VMAP::AreaInfo const& GetAreaInfo() const
{
return _areaInfo;
}
private:
uint32 _phaseMask;
VMAP::AreaInfo _areaInfo;
};
struct DynamicTreeLocationInfoCallback struct DynamicTreeLocationInfoCallback
{ {
DynamicTreeLocationInfoCallback(uint32 phaseMask) DynamicTreeLocationInfoCallback(uint32 phaseMask)
@ -308,24 +289,7 @@ float DynamicMapTree::getHeight(float x, float y, float z, float maxSearchDist,
} }
} }
bool DynamicMapTree::GetAreaInfo(float x, float y, float& z, uint32 phasemask, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const bool DynamicMapTree::GetAreaAndLiquidData(float x, float y, float z, uint32 phasemask, Optional<uint8> reqLiquidType, VMAP::AreaAndLiquidData& data) const
{
G3D::Vector3 v(x, y, z + 0.5f);
DynamicTreeAreaInfoCallback intersectionCallBack(phasemask);
impl->intersectPoint(v, intersectionCallBack);
if (intersectionCallBack.GetAreaInfo().result)
{
flags = intersectionCallBack.GetAreaInfo().flags;
adtId = intersectionCallBack.GetAreaInfo().adtId;
rootId = intersectionCallBack.GetAreaInfo().rootId;
groupId = intersectionCallBack.GetAreaInfo().groupId;
z = intersectionCallBack.GetAreaInfo().ground_Z;
return true;
}
return false;
}
void DynamicMapTree::GetAreaAndLiquidData(float x, float y, float z, uint32 phasemask, uint8 reqLiquidType, VMAP::AreaAndLiquidData& data) const
{ {
G3D::Vector3 v(x, y, z + 0.5f); G3D::Vector3 v(x, y, z + 0.5f);
DynamicTreeLocationInfoCallback intersectionCallBack(phasemask); DynamicTreeLocationInfoCallback intersectionCallBack(phasemask);
@ -335,13 +299,16 @@ void DynamicMapTree::GetAreaAndLiquidData(float x, float y, float z, uint32 phas
data.floorZ = intersectionCallBack.GetLocationInfo().ground_Z; data.floorZ = intersectionCallBack.GetLocationInfo().ground_Z;
uint32 liquidType = intersectionCallBack.GetLocationInfo().hitModel->GetLiquidType(); uint32 liquidType = intersectionCallBack.GetLocationInfo().hitModel->GetLiquidType();
float liquidLevel; float liquidLevel;
if (!reqLiquidType || (dynamic_cast<VMAP::VMapMgr2*>(VMAP::VMapFactory::createOrGetVMapMgr())->GetLiquidFlagsPtr(liquidType) & reqLiquidType)) if (!reqLiquidType || (dynamic_cast<VMAP::VMapMgr2*>(VMAP::VMapFactory::createOrGetVMapMgr())->GetLiquidFlagsPtr(liquidType) & *reqLiquidType))
if (intersectionCallBack.GetHitModel()->GetLiquidLevel(v, intersectionCallBack.GetLocationInfo(), liquidLevel)) if (intersectionCallBack.GetHitModel()->GetLiquidLevel(v, intersectionCallBack.GetLocationInfo(), liquidLevel))
data.liquidInfo.emplace(liquidType, liquidLevel); data.liquidInfo.emplace(liquidType, liquidLevel);
data.areaInfo.emplace(0, data.areaInfo.emplace(intersectionCallBack.GetLocationInfo().hitModel->GetWmoID(),
0,
intersectionCallBack.GetLocationInfo().rootId, intersectionCallBack.GetLocationInfo().rootId,
intersectionCallBack.GetLocationInfo().hitModel->GetWmoID(), intersectionCallBack.GetLocationInfo().hitModel->GetMogpFlags(),
intersectionCallBack.GetLocationInfo().hitModel->GetMogpFlags()); 0);
return true;
} }
return false;
} }

View File

@ -19,6 +19,7 @@
#define _DYNTREE_H #define _DYNTREE_H
#include "Define.h" #include "Define.h"
#include "Optional.h"
namespace G3D namespace G3D
{ {
@ -47,8 +48,7 @@ public:
bool GetIntersectionTime(uint32 phasemask, const G3D::Ray& ray, const G3D::Vector3& endPos, float& maxDist) const; bool GetIntersectionTime(uint32 phasemask, const G3D::Ray& ray, const G3D::Vector3& endPos, float& maxDist) const;
bool GetAreaInfo(float x, float y, float& z, uint32 phasemask, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const; bool GetAreaAndLiquidData(float x, float y, float z, uint32 phasemask, Optional<uint8> reqLiquidType, VMAP::AreaAndLiquidData& data) const;
void GetAreaAndLiquidData(float x, float y, float z, uint32 phasemask, uint8 reqLiquidType, VMAP::AreaAndLiquidData& data) const;
bool GetObjectHitPos(uint32 phasemask, const G3D::Vector3& pPos1, bool GetObjectHitPos(uint32 phasemask, const G3D::Vector3& pPos1,
const G3D::Vector3& pPos2, G3D::Vector3& pResultHitPos, const G3D::Vector3& pPos2, G3D::Vector3& pResultHitPos,

View File

@ -52,20 +52,23 @@ namespace VMAP
{ {
struct AreaInfo struct AreaInfo
{ {
AreaInfo(int32 _adtId, int32 _rootId, int32 _groupId, uint32 _flags) AreaInfo() = default;
: adtId(_adtId), rootId(_rootId), groupId(_groupId), mogpFlags(_flags) { } AreaInfo(int32 _groupId, int32 _adtId, int32 _rootId, uint32 _mogpFlags, uint32 _uniqueId)
int32 const adtId; : groupId(_groupId), adtId(_adtId), rootId(_rootId), mogpFlags(_mogpFlags), uniqueId(_uniqueId) { }
int32 const rootId; int32 groupId = 0;
int32 const groupId; int32 adtId = 0;
uint32 const mogpFlags; int32 rootId = 0;
uint32 mogpFlags = 0;
uint32 uniqueId = 0;
}; };
struct LiquidInfo struct LiquidInfo
{ {
LiquidInfo() = default;
LiquidInfo(uint32 _type, float _level) LiquidInfo(uint32 _type, float _level)
: type(_type), level(_level) {} : type(_type), level(_level) {}
uint32 const type; uint32 type = 0;
float const level; float level = 0.0f;
}; };
float floorZ = VMAP_INVALID_HEIGHT; float floorZ = VMAP_INVALID_HEIGHT;
@ -120,14 +123,12 @@ namespace VMAP
[[nodiscard]] bool isMapLoadingEnabled() const { return (iEnableLineOfSightCalc || iEnableHeightCalc ); } [[nodiscard]] bool isMapLoadingEnabled() const { return (iEnableLineOfSightCalc || iEnableHeightCalc ); }
[[nodiscard]] virtual std::string getDirFileName(unsigned int pMapId, int x, int y) const = 0; [[nodiscard]] virtual std::string getDirFileName(unsigned int pMapId, int x, int y) const = 0;
/** /**
Query world model area info. Query world model area info.
\param z gets adjusted to the ground height for which this are info is valid \param z gets adjusted to the ground height for which this are info is valid
*/ */
virtual bool GetAreaInfo(uint32 pMapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const = 0; virtual bool GetAreaAndLiquidData(uint32 mapId, float x, float y, float z, Optional<uint8> reqLiquidType, AreaAndLiquidData& data) const = 0;
virtual bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 ReqLiquidType, float& level, float& floor, uint32& type, uint32& mogpFlags) const = 0;
// get both area + liquid data in a single vmap lookup
virtual void GetAreaAndLiquidData(uint32 mapId, float x, float y, float z, uint8 reqLiquidType, AreaAndLiquidData& data) const = 0;
}; };
} }

View File

@ -253,70 +253,8 @@ namespace VMAP
return VMAP_INVALID_HEIGHT_VALUE; return VMAP_INVALID_HEIGHT_VALUE;
} }
bool VMapMgr2::GetAreaInfo(uint32 mapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const bool VMapMgr2::GetAreaAndLiquidData(uint32 mapId, float x, float y, float z, Optional<uint8> reqLiquidType, AreaAndLiquidData& data) const
{ {
#if defined(ENABLE_VMAP_CHECKS)
if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_AREAFLAG))
#endif
{
InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId);
if (instanceTree != iInstanceMapTrees.end())
{
Vector3 pos = convertPositionToInternalRep(x, y, z);
bool result = instanceTree->second->GetAreaInfo(pos, flags, adtId, rootId, groupId);
// z is not touched by convertPositionToInternalRep(), so just copy
z = pos.z;
return result;
}
}
return false;
}
bool VMapMgr2::GetLiquidLevel(uint32 mapId, float x, float y, float z, uint8 reqLiquidType, float& level, float& floor, uint32& type, uint32& mogpFlags) const
{
#if defined(ENABLE_VMAP_CHECKS)
if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LIQUIDSTATUS))
#endif
{
InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId);
if (instanceTree != iInstanceMapTrees.end())
{
LocationInfo info;
Vector3 pos = convertPositionToInternalRep(x, y, z);
if (instanceTree->second->GetLocationInfo(pos, info))
{
floor = info.ground_Z;
ASSERT(floor < std::numeric_limits<float>::max());
type = info.hitModel->GetLiquidType(); // entry from LiquidType.dbc
mogpFlags = info.hitModel->GetMogpFlags();
if (reqLiquidType && !(GetLiquidFlagsPtr(type) & reqLiquidType))
{
return false;
}
if (info.hitInstance->GetLiquidLevel(pos, info, level))
{
return true;
}
}
}
}
return false;
}
void VMapMgr2::GetAreaAndLiquidData(uint32 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.emplace(adtId, rootId, groupId, flags);
return;
}
InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId); InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId);
if (instanceTree != iInstanceMapTrees.end()) if (instanceTree != iInstanceMapTrees.end())
{ {
@ -325,16 +263,22 @@ namespace VMAP
if (instanceTree->second->GetLocationInfo(pos, info)) if (instanceTree->second->GetLocationInfo(pos, info))
{ {
data.floorZ = info.ground_Z; data.floorZ = info.ground_Z;
uint32 liquidType = info.hitModel->GetLiquidType(); if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_LIQUIDSTATUS))
float liquidLevel; {
if (!reqLiquidType || (GetLiquidFlagsPtr(liquidType) & reqLiquidType)) uint32 liquidType = info.hitModel->GetLiquidType(); // entry from LiquidType.dbc
if (info.hitInstance->GetLiquidLevel(pos, info, liquidLevel)) float liquidLevel;
data.liquidInfo.emplace(liquidType, liquidLevel); if (!reqLiquidType || (GetLiquidFlagsPtr(liquidType) & *reqLiquidType))
if (info.hitInstance->GetLiquidLevel(pos, info, liquidLevel))
data.liquidInfo.emplace(liquidType, liquidLevel);
}
if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_AREAFLAG)) if (!IsVMAPDisabledForPtr(mapId, VMAP_DISABLE_AREAFLAG))
data.areaInfo.emplace(info.hitInstance->adtId, info.rootId, info.hitModel->GetWmoID(), info.hitModel->GetMogpFlags()); data.areaInfo.emplace(info.hitModel->GetWmoID(), info.hitInstance->adtId, info.rootId, info.hitModel->GetMogpFlags(), info.hitInstance->ID);
return true;
} }
} }
return false;
} }
WorldModel* VMapMgr2::acquireModelInstance(const std::string& basepath, const std::string& filename, uint32 flags/* Only used when creating the model */) WorldModel* VMapMgr2::acquireModelInstance(const std::string& basepath, const std::string& filename, uint32 flags/* Only used when creating the model */)

View File

@ -115,9 +115,7 @@ namespace VMAP
bool processCommand(char* /*command*/) override { return false; } // for debug and extensions bool processCommand(char* /*command*/) override { return false; } // for debug and extensions
bool GetAreaInfo(uint32 pMapId, float x, float y, float& z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const override; bool GetAreaAndLiquidData(uint32 mapId, float x, float y, float z, Optional<uint8> reqLiquidType, AreaAndLiquidData& data) const override;
bool GetLiquidLevel(uint32 pMapId, float x, float y, float z, uint8 reqLiquidType, float& level, float& floor, uint32& type, uint32& mogpFlags) const override;
void GetAreaAndLiquidData(uint32 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); WorldModel* acquireModelInstance(const std::string& basepath, const std::string& filename, uint32 flags);
void releaseModelInstance(const std::string& filename); void releaseModelInstance(const std::string& filename);

View File

@ -51,22 +51,6 @@ namespace VMAP
bool hit; bool hit;
}; };
class AreaInfoCallback
{
public:
AreaInfoCallback(ModelInstance* val): prims(val) {}
void operator()(const Vector3& point, uint32 entry)
{
#if defined(VMAP_DEBUG)
LOG_DEBUG("maps", "AreaInfoCallback: trying to intersect '{}'", prims[entry].name);
#endif
prims[entry].intersectPoint(point, aInfo);
}
ModelInstance* prims;
AreaInfo aInfo;
};
class LocationInfoCallback class LocationInfoCallback
{ {
public: public:
@ -99,22 +83,6 @@ namespace VMAP
return tilefilename.str(); return tilefilename.str();
} }
bool StaticMapTree::GetAreaInfo(Vector3& pos, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const
{
AreaInfoCallback intersectionCallBack(iTreeValues);
iTree.intersectPoint(pos, intersectionCallBack);
if (intersectionCallBack.aInfo.result)
{
flags = intersectionCallBack.aInfo.flags;
adtId = intersectionCallBack.aInfo.adtId;
rootId = intersectionCallBack.aInfo.rootId;
groupId = intersectionCallBack.aInfo.groupId;
pos.z = intersectionCallBack.aInfo.ground_Z;
return true;
}
return false;
}
bool StaticMapTree::GetLocationInfo(const Vector3& pos, LocationInfo& info) const bool StaticMapTree::GetLocationInfo(const Vector3& pos, LocationInfo& info) const
{ {
LocationInfoCallback intersectionCallBack(iTreeValues, info); LocationInfoCallback intersectionCallBack(iTreeValues, info);

View File

@ -30,6 +30,12 @@ namespace VMAP
enum class ModelIgnoreFlags : uint32; enum class ModelIgnoreFlags : uint32;
enum class LoadResult : uint8; enum class LoadResult : uint8;
struct GroupLocationInfo
{
const GroupModel* hitModel = nullptr;
int32 rootId = -1;
};
struct LocationInfo struct LocationInfo
{ {
LocationInfo(): ground_Z(-G3D::inf()) { } LocationInfo(): ground_Z(-G3D::inf()) { }
@ -73,7 +79,6 @@ namespace VMAP
[[nodiscard]] bool isInLineOfSight(const G3D::Vector3& pos1, const G3D::Vector3& pos2, ModelIgnoreFlags ignoreFlags) const; [[nodiscard]] bool isInLineOfSight(const G3D::Vector3& pos1, const G3D::Vector3& pos2, ModelIgnoreFlags ignoreFlags) const;
bool GetObjectHitPos(const G3D::Vector3& pos1, const G3D::Vector3& pos2, G3D::Vector3& pResultHitPos, float pModifyDist) const; bool GetObjectHitPos(const G3D::Vector3& pos1, const G3D::Vector3& pos2, G3D::Vector3& pResultHitPos, float pModifyDist) const;
[[nodiscard]] float getHeight(const G3D::Vector3& pPos, float maxSearchDist) const; [[nodiscard]] float getHeight(const G3D::Vector3& pPos, float maxSearchDist) const;
bool GetAreaInfo(G3D::Vector3& pos, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const;
bool GetLocationInfo(const G3D::Vector3& pos, LocationInfo& info) const; bool GetLocationInfo(const G3D::Vector3& pos, LocationInfo& info) const;
bool InitMap(const std::string& fname, VMapMgr2* vm); bool InitMap(const std::string& fname, VMapMgr2* vm);

View File

@ -203,27 +203,6 @@ bool GameObjectModel::intersectRay(const G3D::Ray& ray, float& MaxDist, bool Sto
return hit; return hit;
} }
void GameObjectModel::IntersectPoint(G3D::Vector3 const& point, VMAP::AreaInfo& info, uint32 ph_mask) const
{
if (!(phasemask & ph_mask) || !owner->IsSpawned() || !IsMapObject())
return;
if (!iBound.contains(point))
return;
// child bounds are defined in object space:
Vector3 pModel = iInvRot * (point - iPos) * iInvScale;
Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
float zDist;
if (iModel->IntersectPoint(pModel, zDirModel, zDist, info))
{
Vector3 modelGround = pModel + zDist * zDirModel;
float world_Z = ((modelGround * iInvRot) * iScale + iPos).z;
if (info.ground_Z < world_Z)
info.ground_Z = world_Z;
}
}
bool GameObjectModel::GetLocationInfo(G3D::Vector3 const& point, VMAP::LocationInfo& info, uint32 ph_mask) const bool GameObjectModel::GetLocationInfo(G3D::Vector3 const& point, VMAP::LocationInfo& info, uint32 ph_mask) const
{ {
if (!(phasemask & ph_mask) || !owner->IsSpawned() || !IsMapObject()) if (!(phasemask & ph_mask) || !owner->IsSpawned() || !IsMapObject())
@ -236,7 +215,9 @@ bool GameObjectModel::GetLocationInfo(G3D::Vector3 const& point, VMAP::LocationI
Vector3 pModel = iInvRot * (point - iPos) * iInvScale; Vector3 pModel = iInvRot * (point - iPos) * iInvScale;
Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f); Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
float zDist; float zDist;
if (iModel->GetLocationInfo(pModel, zDirModel, zDist, info))
VMAP::GroupLocationInfo groupInfo;
if (iModel->GetLocationInfo(pModel, zDirModel, zDist, groupInfo))
{ {
Vector3 modelGround = pModel + zDist * zDirModel; Vector3 modelGround = pModel + zDist * zDirModel;
float world_Z = ((modelGround * iInvRot) * iScale + iPos).z; float world_Z = ((modelGround * iInvRot) * iScale + iPos).z;

View File

@ -70,7 +70,6 @@ public:
[[nodiscard]] bool IsMapObject() const { return isWmo; } [[nodiscard]] bool IsMapObject() const { return isWmo; }
bool intersectRay(const G3D::Ray& Ray, float& MaxDist, bool StopAtFirstHit, uint32 ph_mask, VMAP::ModelIgnoreFlags ignoreFlags) const; bool intersectRay(const G3D::Ray& Ray, float& MaxDist, bool StopAtFirstHit, uint32 ph_mask, VMAP::ModelIgnoreFlags ignoreFlags) const;
void IntersectPoint(G3D::Vector3 const& point, VMAP::AreaInfo& info, uint32 ph_mask) const;
bool GetLocationInfo(G3D::Vector3 const& point, VMAP::LocationInfo& info, uint32 ph_mask) const; bool GetLocationInfo(G3D::Vector3 const& point, VMAP::LocationInfo& info, uint32 ph_mask) const;
bool GetLiquidLevel(G3D::Vector3 const& point, VMAP::LocationInfo& info, float& liqHeight) const; bool GetLiquidLevel(G3D::Vector3 const& point, VMAP::LocationInfo& info, float& liqHeight) const;

View File

@ -63,44 +63,6 @@ namespace VMAP
return hit; return hit;
} }
void ModelInstance::intersectPoint(const G3D::Vector3& p, AreaInfo& info) const
{
if (!iModel)
{
#ifdef VMAP_DEBUG
std::cout << "<object not loaded>\n";
#endif
return;
}
// M2 files don't contain area info, only WMO files
if (flags & MOD_M2)
{
return;
}
if (!iBound.contains(p))
{
return;
}
// child bounds are defined in object space:
Vector3 pModel = iInvRot * (p - iPos) * iInvScale;
Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
float zDist;
if (iModel->IntersectPoint(pModel, zDirModel, zDist, info))
{
Vector3 modelGround = pModel + zDist * zDirModel;
// Transform back to world space. Note that:
// Mat * vec == vec * Mat.transpose()
// and for rotation matrices: Mat.inverse() == Mat.transpose()
float world_Z = ((modelGround * iInvRot) * iScale + iPos).z;
if (info.ground_Z < world_Z)
{
info.ground_Z = world_Z;
info.adtId = adtId;
}
}
}
bool ModelInstance::GetLocationInfo(const G3D::Vector3& p, LocationInfo& info) const bool ModelInstance::GetLocationInfo(const G3D::Vector3& p, LocationInfo& info) const
{ {
if (!iModel) if (!iModel)
@ -124,7 +86,9 @@ namespace VMAP
Vector3 pModel = iInvRot * (p - iPos) * iInvScale; Vector3 pModel = iInvRot * (p - iPos) * iInvScale;
Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f); Vector3 zDirModel = iInvRot * Vector3(0.f, 0.f, -1.f);
float zDist; float zDist;
if (iModel->GetLocationInfo(pModel, zDirModel, zDist, info))
GroupLocationInfo groupInfo;
if (iModel->GetLocationInfo(pModel, zDirModel, zDist, groupInfo))
{ {
Vector3 modelGround = pModel + zDist * zDirModel; Vector3 modelGround = pModel + zDist * zDirModel;
// Transform back to world space. Note that: // Transform back to world space. Note that:
@ -133,6 +97,8 @@ namespace VMAP
float world_Z = ((modelGround * iInvRot) * iScale + iPos).z; float world_Z = ((modelGround * iInvRot) * iScale + iPos).z;
if (info.ground_Z < world_Z) // hm...could it be handled automatically with zDist at intersection? if (info.ground_Z < world_Z) // hm...could it be handled automatically with zDist at intersection?
{ {
info.rootId = groupInfo.rootId;
info.hitModel = groupInfo.hitModel;
info.ground_Z = world_Z; info.ground_Z = world_Z;
info.hitInstance = this; info.hitInstance = this;
return true; return true;

View File

@ -66,7 +66,6 @@ namespace VMAP
ModelInstance(const ModelSpawn& spawn, WorldModel* model); ModelInstance(const ModelSpawn& spawn, WorldModel* model);
void setUnloaded() { iModel = nullptr; } void setUnloaded() { iModel = nullptr; }
bool intersectRay(const G3D::Ray& pRay, float& pMaxDist, bool StopAtFirstHit, ModelIgnoreFlags ignoreFlags) const; bool intersectRay(const G3D::Ray& pRay, float& pMaxDist, bool StopAtFirstHit, ModelIgnoreFlags ignoreFlags) const;
void intersectPoint(const G3D::Vector3& p, AreaInfo& info) const;
bool GetLocationInfo(const G3D::Vector3& p, LocationInfo& info) const; bool GetLocationInfo(const G3D::Vector3& p, LocationInfo& info) const;
bool GetLiquidLevel(const G3D::Vector3& p, LocationInfo& info, float& liqHeight) const; bool GetLiquidLevel(const G3D::Vector3& p, LocationInfo& info, float& liqHeight) const;
WorldModel* getWorldModel() { return iModel; } WorldModel* getWorldModel() { return iModel; }

View File

@ -20,9 +20,9 @@
#include "ModelIgnoreFlags.h" #include "ModelIgnoreFlags.h"
#include "ModelInstance.h" #include "ModelInstance.h"
#include "VMapDefinitions.h" #include "VMapDefinitions.h"
#include <array>
using G3D::Vector3; using G3D::Vector3;
using G3D::Ray;
template<> struct BoundsTrait<VMAP::GroupModel> template<> struct BoundsTrait<VMAP::GroupModel>
{ {
@ -451,21 +451,46 @@ namespace VMAP
return callback.hit; return callback.hit;
} }
bool GroupModel::IsInsideObject(const Vector3& pos, const Vector3& down, float& z_dist) const inline bool IsInsideOrAboveBound(G3D::AABox const& bounds, const G3D::Point3& point)
{ {
if (triangles.empty() || !iBound.contains(pos)) return point.x >= bounds.low().x
&& point.y >= bounds.low().y
&& point.z >= bounds.low().z
&& point.x <= bounds.high().x
&& point.y <= bounds.high().y;
}
GroupModel::InsideResult GroupModel::IsInsideObject(G3D::Ray const& ray, float& z_dist) const
{
if (triangles.empty() || !IsInsideOrAboveBound(iBound, ray.origin()))
return OUT_OF_BOUNDS;
if (meshTree.bound().high().z >= ray.origin().z)
{ {
return false; float dist = G3D::finf();
if (IntersectRay(ray, dist, false))
{
z_dist = dist - 0.1f;
return INSIDE;
}
if (meshTree.bound().contains(ray.origin()))
return MAYBE_INSIDE;
} }
Vector3 rPos = pos - 0.1f * down; else
float dist = G3D::inf();
G3D::Ray ray(rPos, down);
bool hit = IntersectRay(ray, dist, false);
if (hit)
{ {
z_dist = dist - 0.1f; // some group models don't have any floor to intersect with
// so we should attempt to intersect with a model part below this group
// then find back where we originated from (in WorldModel::GetLocationInfo)
float dist = G3D::finf();
float delta = ray.origin().z - meshTree.bound().high().z;
if (IntersectRay(ray.bumpedRay(delta), dist, false))
{
z_dist = dist - 0.1f + delta;
return ABOVE;
}
} }
return hit;
return OUT_OF_BOUNDS;
} }
bool GroupModel::GetLiquidLevel(const Vector3& pos, float& liqHeight) const bool GroupModel::GetLiquidLevel(const Vector3& pos, float& liqHeight) const
@ -541,76 +566,58 @@ namespace VMAP
class WModelAreaCallback class WModelAreaCallback
{ {
public: public:
WModelAreaCallback(const std::vector<GroupModel>& vals, const Vector3& down): WModelAreaCallback(std::vector<GroupModel> const& vals) :
prims(vals.begin()), hit(vals.end()), minVol(G3D::inf()), zDist(G3D::inf()), zVec(down) { } prims(vals), hit() { }
std::vector<GroupModel>::const_iterator prims; std::vector<GroupModel> const& prims;
std::vector<GroupModel>::const_iterator hit; std::array<GroupModel const*, 3> hit;
float minVol; bool operator()(G3D::Ray const& ray, uint32 entry, float& distance, bool /*stopAtFirstHit*/)
float zDist;
Vector3 zVec;
void operator()(const Vector3& point, uint32 entry)
{ {
float group_Z; float group_Z;
//float pVol = prims[entry].GetBound().volume(); if (GroupModel::InsideResult result = prims[entry].IsInsideObject(ray, group_Z); result != GroupModel::OUT_OF_BOUNDS)
//if (pVol < minVol)
//{
/* if (prims[entry].iBound.contains(point)) */
if (prims[entry].IsInsideObject(point, zVec, group_Z))
{ {
//minVol = pVol; if (result != GroupModel::MAYBE_INSIDE)
//hit = prims + entry;
if (group_Z < zDist)
{ {
zDist = group_Z; if (group_Z < distance)
hit = prims + entry; {
distance = group_Z;
hit[result] = &prims[entry];
return true;
}
} }
#ifdef VMAP_DEBUG else
const GroupModel& gm = prims[entry]; hit[result] = &prims[entry];
printf("%10u %8X %7.3f, %7.3f, %7.3f | %7.3f, %7.3f, %7.3f | z=%f, p_z=%f\n", gm.GetWmoID(), gm.GetMogpFlags(),
gm.GetBound().low().x, gm.GetBound().low().y, gm.GetBound().low().z,
gm.GetBound().high().x, gm.GetBound().high().y, gm.GetBound().high().z, group_Z, point.z);
#endif
} }
//} return false;
//std::cout << "trying to intersect '" << prims[entry].name << "'\n";
} }
}; };
bool WorldModel::IntersectPoint(const G3D::Vector3& p, const G3D::Vector3& down, float& dist, AreaInfo& info) const bool WorldModel::GetLocationInfo(const G3D::Vector3& p, const G3D::Vector3& down, float& dist, GroupLocationInfo& info) const
{ {
if (groupModels.empty()) if (groupModels.empty())
{ {
return false; return false;
} }
WModelAreaCallback callback(groupModels, down); WModelAreaCallback callback(groupModels);
groupTree.intersectPoint(p, callback); G3D::Ray r(p - down * 0.1f, down);
if (callback.hit != groupModels.end()) float zDist = groupTree.bound().extent().length();
groupTree.intersectRay(r, callback, zDist, false);
if (callback.hit[GroupModel::INSIDE])
{ {
info.rootId = RootWMOID; info.rootId = RootWMOID;
info.groupId = callback.hit->GetWmoID(); info.hitModel = callback.hit[GroupModel::INSIDE];
info.flags = callback.hit->GetMogpFlags(); dist = zDist;
info.result = true;
dist = callback.zDist;
return true; return true;
} }
return false;
}
bool WorldModel::GetLocationInfo(const G3D::Vector3& p, const G3D::Vector3& down, float& dist, LocationInfo& info) const // some group models don't have any floor to intersect with
{ // so we should attempt to intersect with a model part below the group `p` is in (stored in GroupModel::ABOVE)
if (groupModels.empty()) // then find back where we originated from (GroupModel::MAYBE_INSIDE)
{ if (callback.hit[GroupModel::MAYBE_INSIDE] && callback.hit[GroupModel::ABOVE])
return false;
}
WModelAreaCallback callback(groupModels, down);
groupTree.intersectPoint(p, callback);
if (callback.hit != groupModels.end())
{ {
info.rootId = RootWMOID; info.rootId = RootWMOID;
info.hitModel = &(*callback.hit); info.hitModel = callback.hit[GroupModel::MAYBE_INSIDE];
dist = callback.zDist; dist = zDist;
return true; return true;
} }
return false; return false;

View File

@ -29,6 +29,7 @@ namespace VMAP
class TreeNode; class TreeNode;
struct AreaInfo; struct AreaInfo;
struct LocationInfo; struct LocationInfo;
struct GroupLocationInfo;
enum class ModelIgnoreFlags : uint32; enum class ModelIgnoreFlags : uint32;
class MeshTriangle class MeshTriangle
@ -81,12 +82,14 @@ namespace VMAP
void setMeshData(std::vector<G3D::Vector3>& vert, std::vector<MeshTriangle>& tri); void setMeshData(std::vector<G3D::Vector3>& vert, std::vector<MeshTriangle>& tri);
void setLiquidData(WmoLiquid*& liquid) { iLiquid = liquid; liquid = nullptr; } void setLiquidData(WmoLiquid*& liquid) { iLiquid = liquid; liquid = nullptr; }
bool IntersectRay(const G3D::Ray& ray, float& distance, bool stopAtFirstHit) const; bool IntersectRay(const G3D::Ray& ray, float& distance, bool stopAtFirstHit) const;
bool IsInsideObject(const G3D::Vector3& pos, const G3D::Vector3& down, float& z_dist) const; enum InsideResult { INSIDE = 0, MAYBE_INSIDE = 1, ABOVE = 2, OUT_OF_BOUNDS = -1 };
InsideResult IsInsideObject(G3D::Ray const& ray, float& z_dist) const;
bool GetLiquidLevel(const G3D::Vector3& pos, float& liqHeight) const; bool GetLiquidLevel(const G3D::Vector3& pos, float& liqHeight) const;
[[nodiscard]] uint32 GetLiquidType() const; [[nodiscard]] uint32 GetLiquidType() const;
bool writeToFile(FILE* wf); bool writeToFile(FILE* wf);
bool readFromFile(FILE* rf); bool readFromFile(FILE* rf);
[[nodiscard]] const G3D::AABox& GetBound() const { return iBound; } [[nodiscard]] G3D::AABox const& GetBound() const { return iBound; }
[[nodiscard]] G3D::AABox const& GetMeshTreeBound() const { return meshTree.bound(); }
[[nodiscard]] uint32 GetMogpFlags() const { return iMogpFlags; } [[nodiscard]] uint32 GetMogpFlags() const { return iMogpFlags; }
[[nodiscard]] uint32 GetWmoID() const { return iGroupWMOID; } [[nodiscard]] uint32 GetWmoID() const { return iGroupWMOID; }
void GetMeshData(std::vector<G3D::Vector3>& outVertices, std::vector<MeshTriangle>& outTriangles, WmoLiquid*& liquid); void GetMeshData(std::vector<G3D::Vector3>& outVertices, std::vector<MeshTriangle>& outTriangles, WmoLiquid*& liquid);
@ -109,8 +112,7 @@ namespace VMAP
void setGroupModels(std::vector<GroupModel>& models); void setGroupModels(std::vector<GroupModel>& models);
void setRootWmoID(uint32 id) { RootWMOID = id; } void setRootWmoID(uint32 id) { RootWMOID = id; }
bool IntersectRay(const G3D::Ray& ray, float& distance, bool stopAtFirstHit, ModelIgnoreFlags ignoreFlags) const; bool IntersectRay(const G3D::Ray& ray, float& distance, bool stopAtFirstHit, ModelIgnoreFlags ignoreFlags) const;
bool IntersectPoint(const G3D::Vector3& p, const G3D::Vector3& down, float& dist, AreaInfo& info) const; bool GetLocationInfo(const G3D::Vector3& p, const G3D::Vector3& down, float& dist, GroupLocationInfo& info) const;
bool GetLocationInfo(const G3D::Vector3& p, const G3D::Vector3& down, float& dist, LocationInfo& info) const;
bool writeFile(const std::string& filename); bool writeFile(const std::string& filename);
bool readFile(const std::string& filename); bool readFile(const std::string& filename);
void GetGroupModels(std::vector<GroupModel>& outGroupModels); void GetGroupModels(std::vector<GroupModel>& outGroupModels);

View File

@ -527,9 +527,11 @@ float GridTerrainData::getLiquidLevel(float x, float y) const
} }
// Get water state on map // Get water state on map
LiquidData const GridTerrainData::GetLiquidData(float x, float y, float z, float collisionHeight, uint8 ReqLiquidType) const LiquidData const GridTerrainData::GetLiquidData(float x, float y, float z, float collisionHeight, Optional<uint8> ReqLiquidType) const
{ {
LiquidData liquidData; LiquidData liquidData;
liquidData.Status = LIQUID_MAP_NO_WATER;
if (!_loadedLiquidData) if (!_loadedLiquidData)
return liquidData; return liquidData;
@ -575,7 +577,7 @@ LiquidData const GridTerrainData::GetLiquidData(float x, float y, float z, float
} }
// Check req liquid type mask // Check req liquid type mask
if (type != 0 && (!ReqLiquidType || (ReqLiquidType & type) != 0)) if (type != 0 && (!ReqLiquidType || (*ReqLiquidType & type) != 0))
{ {
// Check water level: // Check water level:
// Check water height map // Check water height map

View File

@ -186,7 +186,7 @@ struct LoadedHoleData
HolesType holes; HolesType holes;
}; };
enum LiquidStatus enum LiquidStatus : uint32
{ {
LIQUID_MAP_NO_WATER = 0x00000000, LIQUID_MAP_NO_WATER = 0x00000000,
LIQUID_MAP_ABOVE_WATER = 0x00000001, LIQUID_MAP_ABOVE_WATER = 0x00000001,
@ -249,7 +249,7 @@ public:
inline float getHeight(float x, float y) const { return (this->*_gridGetHeight)(x, y); } inline float getHeight(float x, float y) const { return (this->*_gridGetHeight)(x, y); }
float getMinHeight(float x, float y) const; float getMinHeight(float x, float y) const;
float getLiquidLevel(float x, float y) const; float getLiquidLevel(float x, float y) const;
LiquidData const GetLiquidData(float x, float y, float z, float collisionHeight, uint8 ReqLiquidType) const; LiquidData const GetLiquidData(float x, float y, float z, float collisionHeight, Optional<uint8> ReqLiquidType) const;
}; };
#endif #endif

View File

@ -1097,7 +1097,7 @@ float Map::GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, fl
if (ground) if (ground)
*ground = ground_z; *ground = ground_z;
LiquidData const& liquidData = const_cast<Map*>(this)->GetLiquidData(phasemask, x, y, ground_z, collisionHeight, MAP_ALL_LIQUIDS); LiquidData const& liquidData = const_cast<Map*>(this)->GetLiquidData(phasemask, x, y, ground_z, collisionHeight, {});
switch (liquidData.Status) switch (liquidData.Status)
{ {
case LIQUID_MAP_ABOVE_WATER: case LIQUID_MAP_ABOVE_WATER:
@ -1198,27 +1198,18 @@ static inline bool IsInWMOInterior(uint32 mogpFlags)
bool Map::GetAreaInfo(uint32 phaseMask, float x, float y, float z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const bool Map::GetAreaInfo(uint32 phaseMask, float x, float y, float z, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const
{ {
float vmap_z = z;
float dynamic_z = z;
float check_z = z; float check_z = z;
VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr(); VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr();
uint32 vflags; VMAP::AreaAndLiquidData vdata;
int32 vadtId; VMAP::AreaAndLiquidData ddata;
int32 vrootId;
int32 vgroupId;
uint32 dflags;
int32 dadtId;
int32 drootId;
int32 dgroupId;
bool hasVmapAreaInfo = vmgr->GetAreaInfo(GetId(), x, y, vmap_z, vflags, vadtId, vrootId, vgroupId);
bool hasDynamicAreaInfo = _dynamicTree.GetAreaInfo(x, y, dynamic_z, phaseMask, dflags, dadtId, drootId, dgroupId);
auto useVmap = [&]() { check_z = vmap_z; flags = vflags; adtId = vadtId; rootId = vrootId; groupId = vgroupId; };
auto useDyn = [&]() { check_z = dynamic_z; flags = dflags; adtId = dadtId; rootId = drootId; groupId = dgroupId; };
bool hasVmapAreaInfo = vmgr->GetAreaAndLiquidData(GetId(), x, y, z, {}, vdata) && vdata.areaInfo.has_value();
bool hasDynamicAreaInfo = _dynamicTree.GetAreaAndLiquidData(x, y, z, phaseMask, {}, ddata) && ddata.areaInfo.has_value();
auto useVmap = [&] { check_z = vdata.floorZ; groupId = vdata.areaInfo->groupId; adtId = vdata.areaInfo->adtId; rootId = vdata.areaInfo->rootId; flags = vdata.areaInfo->mogpFlags; };
auto useDyn = [&] { check_z = ddata.floorZ; groupId = ddata.areaInfo->groupId; adtId = ddata.areaInfo->adtId; rootId = ddata.areaInfo->rootId; flags = ddata.areaInfo->mogpFlags; };
if (hasVmapAreaInfo) if (hasVmapAreaInfo)
{ {
if (hasDynamicAreaInfo && dynamic_z > vmap_z) if (hasDynamicAreaInfo && ddata.floorZ > vdata.floorZ)
useDyn(); useDyn();
else else
useVmap(); useVmap();
@ -1299,32 +1290,30 @@ void Map::GetZoneAndAreaId(uint32 phaseMask, uint32& zoneid, uint32& areaid, flo
zoneid = area->zone; zoneid = area->zone;
} }
LiquidData const Map::GetLiquidData(uint32 phaseMask, float x, float y, float z, float collisionHeight, uint8 ReqLiquidType) LiquidData const Map::GetLiquidData(uint32 phaseMask, float x, float y, float z, float collisionHeight, Optional<uint8> ReqLiquidType)
{ {
LiquidData liquidData; LiquidData liquidData;
liquidData.Status = LIQUID_MAP_NO_WATER;
VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr(); VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr();
float liquid_level = INVALID_HEIGHT; VMAP::AreaAndLiquidData vmapData;
float ground_level = INVALID_HEIGHT;
uint32 liquid_type = 0;
uint32 mogpFlags = 0;
bool useGridLiquid = true; bool useGridLiquid = true;
if (vmgr->GetLiquidLevel(GetId(), x, y, z, ReqLiquidType, liquid_level, ground_level, liquid_type, mogpFlags)) if (vmgr->GetAreaAndLiquidData(GetId(), x, y, z, ReqLiquidType, vmapData) && vmapData.liquidInfo)
{ {
useGridLiquid = !IsInWMOInterior(mogpFlags); useGridLiquid = !vmapData.areaInfo || !IsInWMOInterior(vmapData.areaInfo->mogpFlags);
LOG_DEBUG("maps", "GetLiquidStatus(): vmap liquid level: {} ground: {} type: {}", liquid_level, ground_level, liquid_type); LOG_DEBUG("maps", "GetLiquidStatus(): vmap liquid level: {} ground: {} type: {}", vmapData.liquidInfo->level, vmapData.floorZ, vmapData.liquidInfo->type);
// Check water level and ground level // Check water level and ground level
if (liquid_level > ground_level && G3D::fuzzyGe(z, ground_level - GROUND_HEIGHT_TOLERANCE)) if (vmapData.liquidInfo->level > vmapData.floorZ && G3D::fuzzyGe(z, vmapData.floorZ - GROUND_HEIGHT_TOLERANCE))
{ {
// hardcoded in client like this // hardcoded in client like this
if (GetId() == MAP_OUTLAND && liquid_type == 2) if (GetId() == MAP_OUTLAND && vmapData.liquidInfo->type == 2)
liquid_type = 15; vmapData.liquidInfo->type = 15;
uint32 liquidFlagType = 0; uint32 liquidFlagType = 0;
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(liquid_type)) if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(vmapData.liquidInfo->type))
liquidFlagType = liq->Type; liquidFlagType = liq->Type;
if (liquid_type && liquid_type < 21) if (vmapData.liquidInfo->type && vmapData.liquidInfo->type < 21)
{ {
if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(GetAreaId(phaseMask, x, y, z))) if (AreaTableEntry const* area = sAreaTableStore.LookupEntry(GetAreaId(phaseMask, x, y, z)))
{ {
@ -1338,19 +1327,19 @@ LiquidData const Map::GetLiquidData(uint32 phaseMask, float x, float y, float z,
if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid)) if (LiquidTypeEntry const* liq = sLiquidTypeStore.LookupEntry(overrideLiquid))
{ {
liquid_type = overrideLiquid; vmapData.liquidInfo->type = overrideLiquid;
liquidFlagType = liq->Type; liquidFlagType = liq->Type;
} }
} }
} }
liquidData.Level = liquid_level; liquidData.Level = vmapData.liquidInfo->level;
liquidData.DepthLevel = ground_level; liquidData.DepthLevel = vmapData.floorZ;
liquidData.Entry = liquid_type; liquidData.Entry = vmapData.liquidInfo->type;
liquidData.Flags = 1 << liquidFlagType; liquidData.Flags = 1 << liquidFlagType;
} }
float delta = liquid_level - z; float delta = vmapData.liquidInfo->level - z;
// Get position delta // Get position delta
if (delta > collisionHeight) if (delta > collisionHeight)
@ -1369,7 +1358,7 @@ LiquidData const Map::GetLiquidData(uint32 phaseMask, float x, float y, float z,
{ {
LiquidData const& map_data = gmap->GetLiquidData(x, y, z, collisionHeight, ReqLiquidType); LiquidData const& map_data = gmap->GetLiquidData(x, y, z, collisionHeight, ReqLiquidType);
// Not override LIQUID_MAP_ABOVE_WATER with LIQUID_MAP_NO_WATER: // Not override LIQUID_MAP_ABOVE_WATER with LIQUID_MAP_NO_WATER:
if (map_data.Status != LIQUID_MAP_NO_WATER && (map_data.Level > ground_level)) if (map_data.Status != LIQUID_MAP_NO_WATER && (map_data.Level > vmapData.floorZ))
{ {
// hardcoded in client like this // hardcoded in client like this
uint32 liquidEntry = map_data.Entry; uint32 liquidEntry = map_data.Entry;
@ -1385,7 +1374,7 @@ LiquidData const Map::GetLiquidData(uint32 phaseMask, float x, float y, float z,
return liquidData; return liquidData;
} }
void Map::GetFullTerrainStatusForPosition(uint32 /*phaseMask*/, float x, float y, float z, float collisionHeight, PositionFullTerrainStatus& data, uint8 reqLiquidType) void Map::GetFullTerrainStatusForPosition(uint32 /*phaseMask*/, float x, float y, float z, float collisionHeight, PositionFullTerrainStatus& data, Optional<uint8> reqLiquidType)
{ {
GridTerrainData* gmap = GetGridTerrainData(x, y); GridTerrainData* gmap = GetGridTerrainData(x, y);
@ -1600,7 +1589,7 @@ float Map::GetHeight(uint32 phasemask, float x, float y, float z, bool vmap/*=tr
bool Map::IsInWater(uint32 phaseMask, float x, float y, float pZ, float collisionHeight) const bool Map::IsInWater(uint32 phaseMask, float x, float y, float pZ, float collisionHeight) const
{ {
LiquidData const& liquidData = const_cast<Map*>(this)->GetLiquidData(phaseMask, x, y, pZ, collisionHeight, MAP_ALL_LIQUIDS); LiquidData const& liquidData = const_cast<Map*>(this)->GetLiquidData(phaseMask, x, y, pZ, collisionHeight, {});
return (liquidData.Status & MAP_LIQUID_STATUS_SWIMMING) != 0; return (liquidData.Status & MAP_LIQUID_STATUS_SWIMMING) != 0;
} }

View File

@ -243,8 +243,8 @@ public:
[[nodiscard]] float GetMinHeight(float x, float y) const; [[nodiscard]] float GetMinHeight(float x, float y) const;
Transport* GetTransportForPos(uint32 phase, float x, float y, float z, WorldObject* worldobject = nullptr); Transport* GetTransportForPos(uint32 phase, float x, float y, float z, WorldObject* worldobject = nullptr);
void GetFullTerrainStatusForPosition(uint32 phaseMask, float x, float y, float z, float collisionHeight, PositionFullTerrainStatus& data, uint8 reqLiquidType = MAP_ALL_LIQUIDS); void GetFullTerrainStatusForPosition(uint32 phaseMask, float x, float y, float z, float collisionHeight, PositionFullTerrainStatus& data, Optional<uint8> reqLiquidType = {});
LiquidData const GetLiquidData(uint32 phaseMask, float x, float y, float z, float collisionHeight, uint8 ReqLiquidType); LiquidData const GetLiquidData(uint32 phaseMask, float x, float y, float z, float collisionHeight, Optional<uint8> ReqLiquidType);
[[nodiscard]] bool GetAreaInfo(uint32 phaseMask, float x, float y, float z, uint32& mogpflags, int32& adtId, int32& rootId, int32& groupId) const; [[nodiscard]] bool GetAreaInfo(uint32 phaseMask, float x, float y, float z, uint32& mogpflags, int32& adtId, int32& rootId, int32& groupId) const;
[[nodiscard]] uint32 GetAreaId(uint32 phaseMask, float x, float y, float z) const; [[nodiscard]] uint32 GetAreaId(uint32 phaseMask, float x, float y, float z) const;

View File

@ -211,8 +211,8 @@ void PathGenerator::BuildPolyPath(G3D::Vector3 const& startPos, G3D::Vector3 con
{ {
bool buildShortcut = false; bool buildShortcut = false;
auto liquidDataStart = _source->GetMap()->GetLiquidData(_source->GetPhaseMask(), startPos.x, startPos.y, startPos.z, _source->GetCollisionHeight(), MAP_ALL_LIQUIDS); auto liquidDataStart = _source->GetMap()->GetLiquidData(_source->GetPhaseMask(), startPos.x, startPos.y, startPos.z, _source->GetCollisionHeight(), {});
auto liquidDataEnd = _source->GetMap()->GetLiquidData(_source->GetPhaseMask(), endPos.x, endPos.y, endPos.z, _source->GetCollisionHeight(), MAP_ALL_LIQUIDS); auto liquidDataEnd = _source->GetMap()->GetLiquidData(_source->GetPhaseMask(), endPos.x, endPos.y, endPos.z, _source->GetCollisionHeight(), {});
bool startUnderWaterEndInWater = liquidDataStart.Status == LIQUID_MAP_UNDER_WATER && bool startUnderWaterEndInWater = liquidDataStart.Status == LIQUID_MAP_UNDER_WATER &&
(liquidDataEnd.Status & MAP_LIQUID_STATUS_IN_CONTACT) != 0; (liquidDataEnd.Status & MAP_LIQUID_STATUS_IN_CONTACT) != 0;
@ -698,7 +698,7 @@ void PathGenerator::UpdateFilter()
NavTerrain PathGenerator::GetNavTerrain(float x, float y, float z) const NavTerrain PathGenerator::GetNavTerrain(float x, float y, float z) const
{ {
LiquidData const& liquidData = _source->GetMap()->GetLiquidData(_source->GetPhaseMask(), x, y, z, _source->GetCollisionHeight(), MAP_ALL_LIQUIDS); LiquidData const& liquidData = _source->GetMap()->GetLiquidData(_source->GetPhaseMask(), x, y, z, _source->GetCollisionHeight(), {});
if (liquidData.Status == LIQUID_MAP_NO_WATER) if (liquidData.Status == LIQUID_MAP_NO_WATER)
return NAV_GROUND; return NAV_GROUND;

View File

@ -1384,7 +1384,7 @@ void Spell::SelectImplicitCasterDestTargets(SpellEffIndex effIndex, SpellImplici
float ground = m_caster->GetMapHeight(x, y, z, true); float ground = m_caster->GetMapHeight(x, y, z, true);
float liquidLevel = VMAP_INVALID_HEIGHT_VALUE; float liquidLevel = VMAP_INVALID_HEIGHT_VALUE;
LiquidData const& liquidData = m_caster->GetMap()->GetLiquidData(m_caster->GetPhaseMask(), x, y, z, m_caster->GetCollisionHeight(), MAP_ALL_LIQUIDS); LiquidData const& liquidData = m_caster->GetMap()->GetLiquidData(m_caster->GetPhaseMask(), x, y, z, m_caster->GetCollisionHeight(), {});
if (liquidData.Status) if (liquidData.Status)
liquidLevel = liquidData.Level; liquidLevel = liquidData.Level;

View File

@ -2045,7 +2045,7 @@ class spell_spawn_blood_pool : public SpellScript
void SetDest(SpellDestination &dest) void SetDest(SpellDestination &dest)
{ {
Unit* caster = GetCaster(); Unit* caster = GetCaster();
LiquidData liquidStatus = caster->GetMap()->GetLiquidData(caster->GetPhaseMask(), caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ(), caster->GetCollisionHeight(), MAP_ALL_LIQUIDS); LiquidData liquidStatus = caster->GetMap()->GetLiquidData(caster->GetPhaseMask(), caster->GetPositionX(), caster->GetPositionY(), caster->GetPositionZ(), caster->GetCollisionHeight(), {});
float level = liquidStatus.Level > INVALID_HEIGHT ? liquidStatus.Level : caster->GetPositionZ(); float level = liquidStatus.Level > INVALID_HEIGHT ? liquidStatus.Level : caster->GetPositionZ();
Position pos = Position(caster->GetPositionX(), caster->GetPositionY(), level, caster->GetOrientation()); Position pos = Position(caster->GetPositionX(), caster->GetPositionY(), level, caster->GetOrientation());