Core/Vmaps: Fix getting area id from gameobject models

This commit is contained in:
Shauren
2026-08-08 19:27:57 +02:00
parent a8bebfd3c2
commit fcf3b8ec1c
10 changed files with 78 additions and 87 deletions
+5 -5
View File
@@ -262,19 +262,19 @@ bool DynamicMapTree::getAreaAndLiquidData(float x, float y, float z, PhaseShift
G3D::Vector3 v(x, y, z + 0.5f);
DynamicTreeLocationInfoCallback intersectionCallBack(phaseShift);
impl->intersectPoint(v, intersectionCallBack);
if (intersectionCallBack.GetLocationInfo().hitModel)
if (VMAP::GroupModel const* hitModel = intersectionCallBack.GetLocationInfo().hitModel)
{
data.floorZ = intersectionCallBack.GetLocationInfo().ground_Z;
uint32 liquidType = intersectionCallBack.GetLocationInfo().hitModel->GetLiquidType();
uint32 liquidType = hitModel->GetLiquidType();
float liquidLevel;
if (!reqLiquidType || VMAP::VMapFactory::createOrGetVMapManager()->GetLiquidFlagsPtr(liquidType) & *reqLiquidType)
if (intersectionCallBack.GetHitModel()->GetLiquidLevel(v, intersectionCallBack.GetLocationInfo(), liquidLevel))
if (intersectionCallBack.GetHitModel()->GetLiquidLevel(v, hitModel, liquidLevel))
data.liquidInfo.emplace(liquidType, liquidLevel);
data.areaInfo.emplace(intersectionCallBack.GetLocationInfo().hitModel->GetWmoID(),
data.areaInfo.emplace(hitModel->GetWmoID(),
intersectionCallBack.GetHitModel()->GetNameSetId(),
intersectionCallBack.GetLocationInfo().rootId,
intersectionCallBack.GetLocationInfo().hitModel->GetMogpFlags(),
hitModel->GetMogpFlags(),
0);
return true;
}
@@ -244,7 +244,7 @@ namespace VMAP
InstanceTreeMap::const_iterator instanceTree = GetMapTree(mapId);
if (instanceTree != iInstanceMapTrees.end())
{
LocationInfo info;
StaticMapTreeLocationInfo info;
G3D::Vector3 pos = convertPositionToInternalRep(x, y, z);
if (instanceTree->second->GetLocationInfo(pos, info))
{
@@ -254,7 +254,7 @@ namespace VMAP
uint32 liquidType = info.hitModel->GetLiquidType(); // entry from LiquidType.dbc
float liquidLevel;
if (!reqLiquidType || (GetLiquidFlagsPtr(liquidType) & *reqLiquidType))
if (info.hitInstance->GetLiquidLevel(pos, info, liquidLevel))
if (info.hitInstance->GetLiquidLevel(pos, info.hitModel, liquidLevel))
data.liquidInfo.emplace(liquidType, liquidLevel);
}
+5 -6
View File
@@ -52,28 +52,27 @@ namespace VMAP
class LocationInfoCallback
{
public:
LocationInfoCallback(ModelInstance const* val, LocationInfo& info) : prims(val), locInfo(info), result(false) { }
LocationInfoCallback(ModelInstance const* val, StaticMapTreeLocationInfo& info) : prims(val), locInfo(info) { }
void operator()(Vector3 const& point, uint32 entry)
{
#ifdef VMAP_DEBUG
TC_LOG_DEBUG("maps", "LocationInfoCallback: trying to intersect '{}'", prims[entry].name);
#endif
if (prims[entry].GetLocationInfo(point, locInfo))
result = true;
locInfo.hitInstance = &prims[entry];
}
ModelInstance const* prims;
LocationInfo& locInfo;
bool result;
StaticMapTreeLocationInfo& locInfo;
};
//=========================================================
bool StaticMapTree::GetLocationInfo(Vector3 const& pos, LocationInfo& info) const
bool StaticMapTree::GetLocationInfo(Vector3 const& pos, StaticMapTreeLocationInfo& info) const
{
LocationInfoCallback intersectionCallBack(iTreeValues.data(), info);
iTree.intersectPoint(pos, intersectionCallBack);
return intersectionCallBack.result;
return intersectionCallBack.locInfo.hitInstance != nullptr;
}
StaticMapTree::StaticMapTree(uint32 mapID, std::string const& basePath)
+6 -9
View File
@@ -31,19 +31,16 @@ namespace VMAP
enum class LoadResult : uint8;
enum class ModelIgnoreFlags : uint32;
struct GroupLocationInfo
struct LocationInfo
{
const GroupModel* hitModel = nullptr;
GroupModel const* hitModel = nullptr;
int32 rootId = -1;
float ground_Z = -G3D::finf();
};
struct TC_COMMON_API LocationInfo
struct StaticMapTreeLocationInfo : LocationInfo
{
LocationInfo(): rootId(-1), hitInstance(nullptr), hitModel(nullptr), ground_Z(-G3D::finf()) { }
int32 rootId;
ModelInstance const* hitInstance;
GroupModel const* hitModel;
float ground_Z;
ModelInstance const* hitInstance = nullptr;
};
class TC_COMMON_API StaticMapTree
@@ -74,7 +71,7 @@ namespace VMAP
bool isInLineOfSight(G3D::Vector3 const& pos1, G3D::Vector3 const& pos2, ModelIgnoreFlags ignoreFlags) const;
bool getObjectHitPos(G3D::Vector3 const& pos1, G3D::Vector3 const& pos2, G3D::Vector3& pResultHitPos, float pModifyDist) const;
float getHeight(G3D::Vector3 const& pPos, float maxSearchDist) const;
bool GetLocationInfo(G3D::Vector3 const& pos, LocationInfo& info) const;
bool GetLocationInfo(G3D::Vector3 const& pos, StaticMapTreeLocationInfo& info) const;
LoadResult InitMap(std::string const& fname);
void UnloadMap();
+11 -10
View File
@@ -15,15 +15,15 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "VMapFactory.h"
#include "VMapManager.h"
#include "VMapDefinitions.h"
#include "WorldModel.h"
#include "GameObjectModel.h"
#include "Log.h"
#include "MapTree.h"
#include "Memory.h"
#include "Timer.h"
#include "VMapDefinitions.h"
#include "VMapFactory.h"
#include "VMapManager.h"
#include "WorldModel.h"
#include <G3D/Quat.h>
using G3D::Vector3;
@@ -193,15 +193,16 @@ bool GameObjectModel::GetLocationInfo(G3D::Vector3 const& point, VMAP::LocationI
// 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;
VMAP::GroupLocationInfo groupInfo;
if (iModel->GetLocationInfo(pModel, zDirModel, zDist, groupInfo))
VMAP::WorldModelLocationInfoQueryResult locationQueryResult;
if (iModel->GetLocationInfo(pModel, zDirModel, locationQueryResult))
{
Vector3 modelGround = pModel + zDist * zDirModel;
Vector3 modelGround = pModel + locationQueryResult.distanceToModel * zDirModel;
float world_Z = ((modelGround * iInvRot) * iScale + iPos).z;
if (info.ground_Z < world_Z)
{
info.rootId = locationQueryResult.rootId;
info.hitModel = locationQueryResult.hitModel;
info.ground_Z = world_Z;
return true;
}
@@ -210,13 +211,13 @@ bool GameObjectModel::GetLocationInfo(G3D::Vector3 const& point, VMAP::LocationI
return false;
}
bool GameObjectModel::GetLiquidLevel(G3D::Vector3 const& point, VMAP::LocationInfo& info, float& liqHeight) const
bool GameObjectModel::GetLiquidLevel(G3D::Vector3 const& point, VMAP::GroupModel const* model, float& liqHeight) const
{
// 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 (info.hitModel->GetLiquidLevel(pModel, zDist))
if (model->GetLiquidLevel(pModel, zDist))
{
// calculate world height (zDist in model coords):
liqHeight = (Vector3(pModel.x, pModel.y, zDist) * iInvRot * iScale + iPos).z;
@@ -28,8 +28,8 @@
namespace VMAP
{
class GroupModel;
class WorldModel;
struct AreaInfo;
struct LocationInfo;
enum class ModelIgnoreFlags : uint32;
}
@@ -41,6 +41,11 @@ struct GameObjectDisplayInfoEntry;
class TC_COMMON_API GameObjectModelOwnerBase
{
public:
GameObjectModelOwnerBase() = default;
GameObjectModelOwnerBase(GameObjectModelOwnerBase const& other) = delete;
GameObjectModelOwnerBase(GameObjectModelOwnerBase&& other) noexcept = delete;
GameObjectModelOwnerBase& operator=(GameObjectModelOwnerBase const& other) = delete;
GameObjectModelOwnerBase& operator=(GameObjectModelOwnerBase&& other) noexcept = delete;
virtual ~GameObjectModelOwnerBase() = default;
virtual bool IsSpawned() const = 0;
@@ -81,7 +86,7 @@ public:
bool IntersectRay(G3D::Ray const& ray, float& maxDist, bool stopAtFirstHit, PhaseShift const& phaseShift, VMAP::ModelIgnoreFlags ignoreFlags) const;
bool GetLocationInfo(G3D::Vector3 const& point, VMAP::LocationInfo& info, PhaseShift const& phaseShift) const;
bool GetLiquidLevel(G3D::Vector3 const& point, VMAP::LocationInfo& info, float& liqHeight) const;
bool GetLiquidLevel(G3D::Vector3 const& point, VMAP::GroupModel const* model, float& liqHeight) const;
static std::unique_ptr<GameObjectModel> Create(std::unique_ptr<GameObjectModelOwnerBase> modelOwner, std::string const& dataPath);
+8 -10
View File
@@ -63,7 +63,7 @@ namespace VMAP
return hit;
}
bool ModelInstance::GetLocationInfo(const G3D::Vector3& p, LocationInfo& info) const
bool ModelInstance::GetLocationInfo(G3D::Vector3 const& p, LocationInfo& info) const
{
if (!iModel)
{
@@ -81,35 +81,33 @@ namespace VMAP
// 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;
GroupLocationInfo groupInfo;
if (iModel->GetLocationInfo(pModel, zDirModel, zDist, groupInfo))
WorldModelLocationInfoQueryResult locationQueryResult;
if (iModel->GetLocationInfo(pModel, zDirModel, locationQueryResult))
{
Vector3 modelGround = pModel + zDist * zDirModel;
Vector3 modelGround = pModel + locationQueryResult.distanceToModel * 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) // hm...could it be handled automatically with zDist at intersection?
{
info.rootId = groupInfo.rootId;
info.hitModel = groupInfo.hitModel;
info.rootId = locationQueryResult.rootId;
info.hitModel = locationQueryResult.hitModel;
info.ground_Z = world_Z;
info.hitInstance = this;
return true;
}
}
return false;
}
bool ModelInstance::GetLiquidLevel(const G3D::Vector3& p, LocationInfo& info, float& liqHeight) const
bool ModelInstance::GetLiquidLevel(G3D::Vector3 const& p, GroupModel const* model, float& liqHeight) const
{
// 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 (info.hitModel->GetLiquidLevel(pModel, zDist))
if (model->GetLiquidLevel(pModel, zDist))
{
// calculate world height (zDist in model coords):
liqHeight = (Vector3(pModel.x, pModel.y, zDist) * iInvRot * iScale + iPos).z;
+2 -2
View File
@@ -27,8 +27,8 @@
namespace VMAP
{
class GroupModel;
class WorldModel;
struct AreaInfo;
struct LocationInfo;
enum class ModelIgnoreFlags : uint32;
@@ -75,7 +75,7 @@ namespace VMAP
void setUnloaded() { iModel = nullptr; }
bool intersectRay(G3D::Ray const& pRay, float& pMaxDist, bool pStopAtFirstHit, ModelIgnoreFlags ignoreFlags) const;
bool GetLocationInfo(G3D::Vector3 const& p, LocationInfo& info) const;
bool GetLiquidLevel(G3D::Vector3 const& p, LocationInfo& info, float& liqHeight) const;
bool GetLiquidLevel(G3D::Vector3 const& p, GroupModel const* model, float& liqHeight) const;
G3D::Matrix3 const& GetInvRot() const { return iInvRot; }
WorldModel const* getWorldModel() const { return iModel.get(); }
void AddTileReference() { ++referencingTiles; }
+20 -30
View File
@@ -16,9 +16,8 @@
*/
#include "WorldModel.h"
#include "VMapDefinitions.h"
#include "MapTree.h"
#include "ModelIgnoreFlags.h"
#include "VMapDefinitions.h"
#include <array>
#include <cstring>
@@ -32,7 +31,7 @@ template<> struct BoundsTrait<VMAP::GroupModel>
namespace VMAP
{
bool IntersectTriangle(MeshTriangle const& tri, std::vector<Vector3>::const_iterator points, G3D::Ray const& ray, float& distance)
bool IntersectTriangle(MeshTriangle const& tri, G3D::Vector3 const* points, G3D::Ray const& ray, float& distance)
{
static const float EPS = 1e-5f;
@@ -85,19 +84,14 @@ namespace VMAP
class TriBoundFunc
{
public:
TriBoundFunc(std::vector<Vector3>& vert): vertices(vert.begin()) { }
TriBoundFunc(std::vector<G3D::Vector3> const& vert): vertices(vert.data()) { }
void operator()(MeshTriangle const& tri, G3D::AABox& out) const
{
G3D::Vector3 lo = vertices[tri.idx0];
G3D::Vector3 hi = lo;
lo = (lo.min(vertices[tri.idx1])).min(vertices[tri.idx2]);
hi = (hi.max(vertices[tri.idx1])).max(vertices[tri.idx2]);
out = G3D::AABox(lo, hi);
G3D::Vector3 const& p1 = vertices[tri.idx0], & p2 = vertices[tri.idx1], & p3 = vertices[tri.idx2];
out = { p1.min(p2).min(p3), p1.max(p2).max(p3) };
}
protected:
const std::vector<Vector3>::const_iterator vertices;
G3D::Vector3 const* vertices;
};
// ===================== WmoLiquid ==================================
@@ -395,15 +389,14 @@ namespace VMAP
struct GModelRayCallback
{
GModelRayCallback(std::vector<MeshTriangle> const& tris, const std::vector<Vector3> &vert):
vertices(vert.begin()), triangles(tris.begin()), hit(false) { }
GModelRayCallback(std::vector<MeshTriangle> const& tris, std::vector<G3D::Vector3> const& vert) :
vertices(vert.data()), triangles(tris.data()), hit(false) { }
bool operator()(G3D::Ray const& ray, uint32 entry, float& distance, bool /*pStopAtFirstHit*/)
{
hit = IntersectTriangle(triangles[entry], vertices, ray, distance) || hit;
return hit;
return hit |= IntersectTriangle(triangles[entry], vertices, ray, distance);
}
std::vector<Vector3>::const_iterator vertices;
std::vector<MeshTriangle>::const_iterator triangles;
G3D::Vector3 const* vertices;
MeshTriangle const* triangles;
bool hit;
};
@@ -417,7 +410,7 @@ namespace VMAP
return callback.hit;
}
inline bool IsInsideOrAboveBound(G3D::AABox const& bounds, const G3D::Point3& point)
inline bool IsInsideOrAboveBound(G3D::AABox const& bounds, G3D::Point3 const& point)
{
return point.x >= bounds.low().x
&& point.y >= bounds.low().y
@@ -483,15 +476,12 @@ namespace VMAP
struct WModelRayCallBack
{
WModelRayCallBack(std::vector<GroupModel> const& mod): models(mod.begin()), hit(false) { }
WModelRayCallBack(std::vector<GroupModel> const& mod) : models(mod.data()), hit(false) { }
bool operator()(G3D::Ray const& ray, uint32 entry, float& distance, bool pStopAtFirstHit)
{
bool result = models[entry].IntersectRay(ray, distance, pStopAtFirstHit);
if (result)
hit = true;
return hit;
return hit |= models[entry].IntersectRay(ray, distance, pStopAtFirstHit);
}
std::vector<GroupModel>::const_iterator models;
GroupModel const* models;
bool hit;
};
@@ -544,7 +534,7 @@ namespace VMAP
}
};
bool WorldModel::GetLocationInfo(const G3D::Vector3& p, const G3D::Vector3& down, float& dist, GroupLocationInfo& info) const
bool WorldModel::GetLocationInfo(G3D::Vector3 const& p, G3D::Vector3 const& down, WorldModelLocationInfoQueryResult& info) const
{
if (groupModels.empty())
return false;
@@ -555,9 +545,9 @@ namespace VMAP
groupTree.intersectRay(r, callback, zDist, false);
if (callback.hit[GroupModel::INSIDE])
{
info.rootId = RootWMOID;
info.hitModel = callback.hit[GroupModel::INSIDE];
dist = zDist;
info.distanceToModel = zDist;
info.rootId = RootWMOID;
return true;
}
@@ -566,9 +556,9 @@ namespace VMAP
// then find back where we originated from (GroupModel::MAYBE_INSIDE)
if (callback.hit[GroupModel::MAYBE_INSIDE] && callback.hit[GroupModel::ABOVE])
{
info.rootId = RootWMOID;
info.hitModel = callback.hit[GroupModel::MAYBE_INSIDE];
dist = zDist;
info.distanceToModel = zDist;
info.rootId = RootWMOID;
return true;
}
return false;
+12 -11
View File
@@ -18,22 +18,16 @@
#ifndef _WORLDMODEL_H
#define _WORLDMODEL_H
#include <G3D/Vector3.h>
#include <G3D/AABox.h>
#include <G3D/Ray.h>
#include "BoundingIntervalHierarchy.h"
#include "Define.h"
#include "EnumFlag.h"
#include "ModelIgnoreFlags.h"
#include <G3D/AABox.h>
#include <G3D/Ray.h>
#include <G3D/Vector3.h>
namespace VMAP
{
class TreeNode;
struct AreaInfo;
struct LocationInfo;
struct GroupLocationInfo;
enum class ModelIgnoreFlags : uint32;
enum class ModelFlags : uint32
{
None = 0x0,
@@ -113,6 +107,13 @@ namespace VMAP
WmoLiquid* iLiquid;
};
struct WorldModelLocationInfoQueryResult
{
GroupModel const* hitModel = nullptr;
float distanceToModel = 0.0f;
int32 rootId = -1;
};
/*! Holds a model (converted M2 or WMO) in its original coordinate space */
class TC_COMMON_API WorldModel
{
@@ -124,7 +125,7 @@ namespace VMAP
void setFlags(ModelFlags flags) { Flags = flags; }
void setRootWmoID(uint32 id) { RootWMOID = id; }
bool IntersectRay(const G3D::Ray &ray, float &distance, bool stopAtFirstHit, ModelIgnoreFlags ignoreFlags) const;
bool GetLocationInfo(const G3D::Vector3 &p, const G3D::Vector3 &down, float &dist, GroupLocationInfo& info) const;
bool GetLocationInfo(G3D::Vector3 const& p, G3D::Vector3 const& down, WorldModelLocationInfoQueryResult& info) const;
bool writeFile(const std::string &filename);
bool readFile(const std::string &filename);
bool IsM2() const { return Flags.HasFlag(ModelFlags::IsM2); }