mirror of
https://github.com/azerothcore/azerothcore-wotlk.git
synced 2025-11-10 20:54:15 +08:00
Merge bab53774d2d60535c4616c5dfdc86fd2c34dcea3 into 5bef92d5eaca3e2ecc317f9d599312bc23eb71aa
This commit is contained in:
commit
ed3e16896e
@ -308,6 +308,76 @@ float DynamicMapTree::getHeight(float x, float y, float z, float maxSearchDist,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool _finiteF(float v) { return std::isfinite(v); }
|
||||||
|
namespace { constexpr float INV_SQRT2 = 0.70710678118654752440f; }
|
||||||
|
|
||||||
|
float DynamicMapTree::getHeightAccurate(float x, float y, float z, float maxSearchDist, uint32 phasemask,
|
||||||
|
float radius, float yaw, float blend, float clamp, float sampleDelta) const
|
||||||
|
{
|
||||||
|
auto sample = [&](float sx, float sy) -> float
|
||||||
|
{
|
||||||
|
G3D::Vector3 v(sx, sy, z);
|
||||||
|
G3D::Ray r(v, G3D::Vector3(0, 0, -1));
|
||||||
|
float dist = maxSearchDist;
|
||||||
|
DynamicTreeIntersectionCallback cb(phasemask, VMAP::ModelIgnoreFlags::Nothing);
|
||||||
|
impl->intersectZAllignedRay(r, cb, dist);
|
||||||
|
if (cb.didHit())
|
||||||
|
return z - dist;
|
||||||
|
return std::numeric_limits<float>::quiet_NaN();
|
||||||
|
};
|
||||||
|
|
||||||
|
const float h0 = sample(x, y);
|
||||||
|
if (!_finiteF(h0))
|
||||||
|
return -G3D::finf();
|
||||||
|
|
||||||
|
if (radius <= 0.0f)
|
||||||
|
return h0;
|
||||||
|
|
||||||
|
const float d = (sampleDelta > 0.0f) ? sampleDelta
|
||||||
|
: std::max(0.05f, std::min(0.5f, radius * 0.5f));
|
||||||
|
|
||||||
|
const float hx1 = sample(x + d, y);
|
||||||
|
const float hx2 = sample(x - d, y);
|
||||||
|
const float hy1 = sample(x, y + d);
|
||||||
|
const float hy2 = sample(x, y - d);
|
||||||
|
|
||||||
|
auto diff = [&](float p, float m) -> float
|
||||||
|
{
|
||||||
|
if (_finiteF(p) && _finiteF(m)) return (p - m) / (2.0f * d);
|
||||||
|
if (_finiteF(p)) return (p - h0) / d;
|
||||||
|
if (_finiteF(m)) return (h0 - m) / d;
|
||||||
|
return 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
float gx = diff(hx1, hx2); // dz/dx
|
||||||
|
float gy = diff(hy1, hy2); // dz/dy
|
||||||
|
|
||||||
|
if (clamp > 0.0f)
|
||||||
|
{
|
||||||
|
const float g2 = gx*gx + gy*gy;
|
||||||
|
const float c2 = clamp*clamp;
|
||||||
|
if (g2 > c2)
|
||||||
|
{
|
||||||
|
const float s = clamp / std::sqrt(g2);
|
||||||
|
gx *= s; gy *= s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const float slopeL2 = std::sqrt(std::max(0.0f, gx*gx + gy*gy));
|
||||||
|
float totalSlope = slopeL2;
|
||||||
|
|
||||||
|
if (blend < 1.0f)
|
||||||
|
{
|
||||||
|
float c = std::cos(yaw), s = std::sin(yaw);
|
||||||
|
float rx = gx * c + gy * s;
|
||||||
|
float ry = -gx * s + gy * c;
|
||||||
|
float slopeL1 = std::abs(rx) + std::abs(ry);
|
||||||
|
totalSlope = blend * slopeL2 + (1.0f - blend) * (INV_SQRT2 * slopeL1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return h0 + radius * totalSlope;
|
||||||
|
}
|
||||||
|
|
||||||
bool DynamicMapTree::GetAreaInfo(float x, float y, float& z, uint32 phasemask, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const
|
bool DynamicMapTree::GetAreaInfo(float x, float y, float& z, uint32 phasemask, uint32& flags, int32& adtId, int32& rootId, int32& groupId) const
|
||||||
{
|
{
|
||||||
G3D::Vector3 v(x, y, z + 0.5f);
|
G3D::Vector3 v(x, y, z + 0.5f);
|
||||||
|
|||||||
@ -55,6 +55,8 @@ public:
|
|||||||
float pModifyDist) const;
|
float pModifyDist) const;
|
||||||
|
|
||||||
[[nodiscard]] float getHeight(float x, float y, float z, float maxSearchDist, uint32 phasemask) const;
|
[[nodiscard]] float getHeight(float x, float y, float z, float maxSearchDist, uint32 phasemask) const;
|
||||||
|
[[nodiscard]] float getHeightAccurate(float x, float y, float z, float maxSearchDist, uint32 phasemask,
|
||||||
|
float radius, float yaw, float blend, float clamp, float sampleDelta) const;
|
||||||
|
|
||||||
void insert(const GameObjectModel&);
|
void insert(const GameObjectModel&);
|
||||||
void remove(const GameObjectModel&);
|
void remove(const GameObjectModel&);
|
||||||
|
|||||||
@ -1397,6 +1397,79 @@ vmap.BlizzlikeLOSInOpenWorld = 1
|
|||||||
|
|
||||||
vmap.enableIndoorCheck = 1
|
vmap.enableIndoorCheck = 1
|
||||||
|
|
||||||
|
#
|
||||||
|
# Accurate ground settlement (cylinder–plane) settings
|
||||||
|
# 0 = cylinder-circle footprint (recommended),
|
||||||
|
# 1 = square footprint (upside-down-pyramid)
|
||||||
|
#
|
||||||
|
|
||||||
|
Height.Accurate.Shape = 0
|
||||||
|
|
||||||
|
#
|
||||||
|
# Scale factor applied to the probe radius (safety margin, do not abuse)
|
||||||
|
#
|
||||||
|
|
||||||
|
Height.Accurate.RadiusScale = 1.0
|
||||||
|
|
||||||
|
#
|
||||||
|
# Square and cylinder mix [0..1]
|
||||||
|
# 0.00 = pure square
|
||||||
|
# 1.00 = cylinder (circle) (equal to Shape=0)
|
||||||
|
# Recommended for QA: 0.15–0.25
|
||||||
|
#
|
||||||
|
|
||||||
|
Height.Accurate.SquareBlend = 0.2
|
||||||
|
|
||||||
|
#
|
||||||
|
# Optional slope clamp (rise/run). 0.0 disables clamping.
|
||||||
|
# This limits the gradient magnitude used by both circle and square footprints,
|
||||||
|
# preventing extreme lifts on near-vertical faces. Safe upper bound: ~5.0 (≈78.7°).
|
||||||
|
#
|
||||||
|
|
||||||
|
Height.Accurate.SlopeClamp = 0.0
|
||||||
|
|
||||||
|
#
|
||||||
|
# Gradient mode
|
||||||
|
# 0 = Plane (exact face-plane gradient; maximizes geometric accuracy)
|
||||||
|
# 1 = LS (least-squares gradient; smoother, slightly less exact)
|
||||||
|
#
|
||||||
|
|
||||||
|
Height.Accurate.GradientMode = 0
|
||||||
|
|
||||||
|
#
|
||||||
|
# Normal epsilon used to detect degenerate faces (|nz| < eps)
|
||||||
|
# Recommended: 1e-6 .. 1e-5
|
||||||
|
#
|
||||||
|
|
||||||
|
Height.Accurate.NormalEps = 0.000001
|
||||||
|
|
||||||
|
#
|
||||||
|
# Accurate VMAP height (apply same footprint & slope logic on VMAP)
|
||||||
|
# 1 = enable (recommended), 0 = legacy point-ray height
|
||||||
|
#
|
||||||
|
|
||||||
|
Height.Accurate.VMap.Enable = 1
|
||||||
|
|
||||||
|
#
|
||||||
|
# Lateral sample delta (meters) to estimate VMAP gradient with 4 extra rays:
|
||||||
|
# (x±delta,y) and (x,y±delta). Typical 0.15..0.35. Affects precision & cost.
|
||||||
|
#
|
||||||
|
|
||||||
|
Height.Accurate.VMap.Delta = 0.25
|
||||||
|
|
||||||
|
#
|
||||||
|
# -- Accurate DYNAMIC (MMAP) planar offset (gradient sampling) --
|
||||||
|
# 1 = enable (recommended), 0 = legacy point ray
|
||||||
|
#
|
||||||
|
|
||||||
|
Height.Accurate.Dynamic.Enable = 1
|
||||||
|
|
||||||
|
#
|
||||||
|
# Gradient sampling delta for Dynamic (meters). Typical 0.15..0.35
|
||||||
|
#
|
||||||
|
|
||||||
|
Height.Accurate.Dynamic.Delta = 0.25
|
||||||
|
|
||||||
#
|
#
|
||||||
# DetectPosCollision
|
# DetectPosCollision
|
||||||
# Description: Check final move position, summon position, etc for visible collision with
|
# Description: Check final move position, summon position, etc for visible collision with
|
||||||
|
|||||||
@ -3042,6 +3042,36 @@ float WorldObject::GetMapHeight(float x, float y, float z, bool vmap/* = true*/,
|
|||||||
return GetMap()->GetHeight(GetPhaseMask(), x, y, z, vmap, distanceToSearch);
|
return GetMap()->GetHeight(GetPhaseMask(), x, y, z, vmap, distanceToSearch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float WorldObject::GetGroundProbeRadius() const
|
||||||
|
{
|
||||||
|
if (Unit const* u = ToUnit())
|
||||||
|
return std::max(0.25f, u->GetFloatValue(UNIT_FIELD_BOUNDINGRADIUS));
|
||||||
|
return 0.3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float WorldObject::GetMapHeightAccurate(float x, float y, float z, bool vmap/* = true*/,
|
||||||
|
float distanceToSearch/* = DEFAULT_HEIGHT_SEARCH*/, float radius/* = 0.3f*/) const
|
||||||
|
{
|
||||||
|
if (radius <= 0.0f)
|
||||||
|
{
|
||||||
|
if (Unit const* u = ToUnit())
|
||||||
|
{
|
||||||
|
radius = std::max(0.25f, u->GetFloatValue(UNIT_FIELD_BOUNDINGRADIUS));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
radius = 0.3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
float rScale = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_RADIUS_SCALE);
|
||||||
|
radius *= rScale;
|
||||||
|
|
||||||
|
float yaw = GetOrientation();
|
||||||
|
if (z != MAX_HEIGHT)
|
||||||
|
z += std::max(GetCollisionHeight(), radius + 0.2f);
|
||||||
|
|
||||||
|
return GetMap()->GetHeightAccurate(GetPhaseMask(), x, y, z, radius, yaw, vmap, distanceToSearch);
|
||||||
|
}
|
||||||
|
|
||||||
float WorldObject::GetMapWaterOrGroundLevel(float x, float y, float z, float* ground/* = nullptr*/) const
|
float WorldObject::GetMapWaterOrGroundLevel(float x, float y, float z, float* ground/* = nullptr*/) const
|
||||||
{
|
{
|
||||||
return GetMap()->GetWaterOrGroundLevel(GetPhaseMask(), x, y, z, ground,
|
return GetMap()->GetWaterOrGroundLevel(GetPhaseMask(), x, y, z, ground,
|
||||||
|
|||||||
@ -703,6 +703,8 @@ public:
|
|||||||
};
|
};
|
||||||
[[nodiscard]] float GetMapWaterOrGroundLevel(float x, float y, float z, float* ground = nullptr) const;
|
[[nodiscard]] float GetMapWaterOrGroundLevel(float x, float y, float z, float* ground = nullptr) const;
|
||||||
[[nodiscard]] float GetMapHeight(float x, float y, float z, bool vmap = true, float distanceToSearch = 50.0f) const; // DEFAULT_HEIGHT_SEARCH in map.h
|
[[nodiscard]] float GetMapHeight(float x, float y, float z, bool vmap = true, float distanceToSearch = 50.0f) const; // DEFAULT_HEIGHT_SEARCH in map.h
|
||||||
|
[[nodiscard]] float GetGroundProbeRadius() const;
|
||||||
|
[[nodiscard]] float GetMapHeightAccurate(float x, float y, float z, bool vmap = true, float distanceToSearch = 50.0f, float radius = 0.3f) const;
|
||||||
|
|
||||||
[[nodiscard]] float GetFloorZ() const;
|
[[nodiscard]] float GetFloorZ() const;
|
||||||
[[nodiscard]] float GetMinHeightInWater() const;
|
[[nodiscard]] float GetMinHeightInWater() const;
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include "GridTerrainData.h"
|
#include "GridTerrainData.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "MapDefines.h"
|
#include "MapDefines.h"
|
||||||
|
#include "World.h"
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <G3D/Ray.h>
|
#include <G3D/Ray.h>
|
||||||
|
|
||||||
@ -615,3 +616,212 @@ LiquidData const GridTerrainData::GetLiquidData(float x, float y, float z, float
|
|||||||
|
|
||||||
return liquidData;
|
return liquidData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr float INV_SQRT2 = 0.70710678118654752440f; // 1/sqrt(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline float CELL_SIZE() { return SIZE_OF_GRIDS / float(MAP_RESOLUTION); } // ≈ 4.1666667f
|
||||||
|
|
||||||
|
bool GridTerrainData::SampleHeights(uint32 xInt, uint32 yInt, float& h1, float& h2, float& h3, float& h4, float& h5) const
|
||||||
|
{
|
||||||
|
if (!_loadedHeightData)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// FLOAT
|
||||||
|
if (_loadedHeightData->floatHeightData)
|
||||||
|
{
|
||||||
|
auto const& v9 = _loadedHeightData->floatHeightData->v9;
|
||||||
|
auto const& v8 = _loadedHeightData->floatHeightData->v8;
|
||||||
|
|
||||||
|
h1 = v9[xInt * 129 + yInt];
|
||||||
|
h2 = v9[(xInt + 1) * 129 + yInt];
|
||||||
|
h3 = v9[xInt * 129 + yInt + 1];
|
||||||
|
h4 = v9[(xInt + 1) * 129 + yInt + 1];
|
||||||
|
h5 = v8[xInt * 128 + yInt];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UINT8
|
||||||
|
if (_loadedHeightData->uint8HeightData)
|
||||||
|
{
|
||||||
|
auto const& d = *_loadedHeightData->uint8HeightData;
|
||||||
|
float k = d.gridIntHeightMultiplier;
|
||||||
|
float base = _loadedHeightData->gridHeight;
|
||||||
|
|
||||||
|
auto v9ptr = &d.v9[xInt * 128 + xInt + yInt]; // == xInt*129 + yInt
|
||||||
|
h1 = float(v9ptr[0]) * k + base;
|
||||||
|
h2 = float(v9ptr[129]) * k + base;
|
||||||
|
h3 = float(v9ptr[1]) * k + base;
|
||||||
|
h4 = float(v9ptr[130]) * k + base;
|
||||||
|
|
||||||
|
uint8 v8val = d.v8[xInt * 128 + yInt];
|
||||||
|
h5 = float(v8val) * k + base;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// UINT16
|
||||||
|
if (_loadedHeightData->uint16HeightData)
|
||||||
|
{
|
||||||
|
auto const& d = *_loadedHeightData->uint16HeightData;
|
||||||
|
float k = d.gridIntHeightMultiplier;
|
||||||
|
float base = _loadedHeightData->gridHeight;
|
||||||
|
|
||||||
|
auto v9ptr = &d.v9[xInt * 128 + xInt + yInt]; // == xInt*129 + yInt
|
||||||
|
h1 = float(v9ptr[0]) * k + base;
|
||||||
|
h2 = float(v9ptr[129]) * k + base;
|
||||||
|
h3 = float(v9ptr[1]) * k + base;
|
||||||
|
h4 = float(v9ptr[130]) * k + base;
|
||||||
|
|
||||||
|
uint16 v8val = d.v8[xInt * 128 + yInt];
|
||||||
|
h5 = float(v8val) * k + base;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
float GridTerrainData::GetHeightAccurate(float x, float y, float radius) const
|
||||||
|
{
|
||||||
|
return GetHeightAccurate(x, y, radius, GroundFootprintShape::Circle, 0.0f, 1.0f, 0.0f, 0u, 1.0e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float GridTerrainData::GetHeightAccurate(float x, float y, float radius, GroundFootprintShape shape) const
|
||||||
|
{
|
||||||
|
return GetHeightAccurate(x, y, radius, shape, 0.0f, (shape == GroundFootprintShape::Square ? 0.0f : 1.0f), 0.0f, 0u, 1.0e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float GridTerrainData::GetHeightAccurate(float x, float y, float radius, GroundFootprintShape shape, float yaw) const
|
||||||
|
{
|
||||||
|
// Wrapper with default blend = 1 for circle, 0 for square.
|
||||||
|
return GetHeightAccurate(x, y, radius, shape, yaw, (shape == GroundFootprintShape::Square ? 0.0f : 1.0f), 0.0f, 0u, 1.0e-6f);
|
||||||
|
}
|
||||||
|
|
||||||
|
float GridTerrainData::GetHeightAccurate(float x, float y, float radius, GroundFootprintShape shape, float yaw,
|
||||||
|
float squareBlend, float slopeClamp, uint32 gradientMode, float normalEps) const
|
||||||
|
{
|
||||||
|
if (!_loadedHeightData)
|
||||||
|
return INVALID_HEIGHT;
|
||||||
|
|
||||||
|
float xf = MAP_RESOLUTION * (32.0f - x / SIZE_OF_GRIDS);
|
||||||
|
float yf = MAP_RESOLUTION * (32.0f - y / SIZE_OF_GRIDS);
|
||||||
|
|
||||||
|
int xInt = static_cast<int>(std::floor(xf));
|
||||||
|
int yInt = static_cast<int>(std::floor(yf));
|
||||||
|
float fx = xf - static_cast<float>(xInt);
|
||||||
|
float fy = yf - static_cast<float>(yInt);
|
||||||
|
|
||||||
|
if (fx < 0.0f) { fx += 1.0f; --xInt; }
|
||||||
|
if (fy < 0.0f) { fy += 1.0f; --yInt; }
|
||||||
|
if (fx >= 1.0f) { fx -= 1.0f; ++xInt; }
|
||||||
|
if (fy >= 1.0f) { fy -= 1.0f; ++yInt; }
|
||||||
|
xInt &= (MAP_RESOLUTION - 1);
|
||||||
|
yInt &= (MAP_RESOLUTION - 1);
|
||||||
|
|
||||||
|
if (isHole(xInt, yInt))
|
||||||
|
return INVALID_HEIGHT;
|
||||||
|
|
||||||
|
float h1, h2, h3, h4, h5;
|
||||||
|
if (!SampleHeights(xInt, yInt, h1, h2, h3, h4, h5))
|
||||||
|
return INVALID_HEIGHT;
|
||||||
|
|
||||||
|
// h1 -> (0,0)
|
||||||
|
// h2 -> (S,0)
|
||||||
|
// h3 -> (0,S)
|
||||||
|
// h4 -> (S,S)
|
||||||
|
// h5 -> (S/2, S/2)
|
||||||
|
const float S = CELL_SIZE();
|
||||||
|
const float S2 = S * 0.5f;
|
||||||
|
|
||||||
|
G3D::Vector3 P(fx * S, fy * S, 0.0f);
|
||||||
|
|
||||||
|
G3D::Vector3 A(S2, S2, h5);
|
||||||
|
|
||||||
|
const float eps = 1e-6f;
|
||||||
|
const float blend = std::max(0.0f, std::min(1.0f, squareBlend));
|
||||||
|
|
||||||
|
const bool right = (P.x >= A.x);
|
||||||
|
const bool top = (P.y >= A.y);
|
||||||
|
G3D::Vector3 B, C;
|
||||||
|
if (right && !top)
|
||||||
|
{
|
||||||
|
B = G3D::Vector3(S, 0.0f, h2);
|
||||||
|
C = G3D::Vector3(0.0f, 0.0f, h1);
|
||||||
|
} // BR
|
||||||
|
else if (right && top)
|
||||||
|
{
|
||||||
|
B = G3D::Vector3(S, S, h4);
|
||||||
|
C = G3D::Vector3(S, 0.0f, h2);
|
||||||
|
} // TR
|
||||||
|
else if (!right && top)
|
||||||
|
{
|
||||||
|
B = G3D::Vector3(0.0f, S, h3);
|
||||||
|
C = G3D::Vector3(S, S, h4);
|
||||||
|
} // TL
|
||||||
|
else /* !right && !top */
|
||||||
|
{
|
||||||
|
B = G3D::Vector3(0.0f, 0.0f, h1);
|
||||||
|
C = G3D::Vector3(0.0f, S, h3);
|
||||||
|
} // BL
|
||||||
|
|
||||||
|
const G3D::Vector3 U = B - A;
|
||||||
|
const G3D::Vector3 V = C - A;
|
||||||
|
const G3D::Vector3 n = U.cross(V);
|
||||||
|
const float nzAbs = std::abs(n.z);
|
||||||
|
if (nzAbs < std::max(eps, normalEps))
|
||||||
|
return getHeight(x, y);
|
||||||
|
|
||||||
|
const float zPlane = A.z - (n.x * (P.x - A.x) + n.y * (P.y - A.y)) / n.z;
|
||||||
|
const float inv2S = 1.0f / (2.0f * S);
|
||||||
|
float gx, gy;
|
||||||
|
|
||||||
|
if (gradientMode == 0u)
|
||||||
|
{
|
||||||
|
// Plane-exact gradient: z = (-n.x*x - n.y*y - d)/n.z => ∇z = (-n.x/n.z, -n.y/n.z)
|
||||||
|
gx = -n.x / n.z;
|
||||||
|
gy = -n.y / n.z;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// LS gradient (smoother)
|
||||||
|
gx = ((h2 + h4) - (h1 + h3)) * inv2S;
|
||||||
|
gy = ((h3 + h4) - (h1 + h2)) * inv2S;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional clamp
|
||||||
|
if (slopeClamp > 0.0f)
|
||||||
|
{
|
||||||
|
const float g2 = gx*gx + gy*gy;
|
||||||
|
const float c2 = slopeClamp * slopeClamp;
|
||||||
|
if (g2 > c2)
|
||||||
|
{
|
||||||
|
const float s = slopeClamp / std::sqrt(g2);
|
||||||
|
gx *= s; gy *= s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const float slopeL2 = std::sqrt(std::max(0.0f, gx*gx + gy*gy));
|
||||||
|
|
||||||
|
// Fast‑path radius 0
|
||||||
|
if (radius <= 0.0f)
|
||||||
|
return zPlane;
|
||||||
|
|
||||||
|
float totalSlope = slopeL2; // por defecto: círculo (o blend==1)
|
||||||
|
if (shape == GroundFootprintShape::Square && blend < 1.0f)
|
||||||
|
{
|
||||||
|
float slopeL1 = 0.0f;
|
||||||
|
if (!(gx == 0.0f && gy == 0.0f))
|
||||||
|
{
|
||||||
|
const float c = std::cos(yaw);
|
||||||
|
const float s = std::sin(yaw);
|
||||||
|
const float rx = gx * c + gy * s;
|
||||||
|
const float ry = -gx * s + gy * c;
|
||||||
|
slopeL1 = std::abs(rx) + std::abs(ry);
|
||||||
|
}
|
||||||
|
totalSlope = blend * slopeL2 + (1.0f - blend) * (INV_SQRT2 * slopeL1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final height (Minkowski): base + radius * slope
|
||||||
|
return zPlane + radius * totalSlope;
|
||||||
|
}
|
||||||
|
|||||||
@ -245,11 +245,37 @@ public:
|
|||||||
~GridTerrainData() { };
|
~GridTerrainData() { };
|
||||||
TerrainMapDataReadResult Load(std::string const& mapFileName);
|
TerrainMapDataReadResult Load(std::string const& mapFileName);
|
||||||
|
|
||||||
|
enum class GroundFootprintShape : uint8
|
||||||
|
{
|
||||||
|
Circle = 0, // cylinder-plane
|
||||||
|
Square = 1 // upside-down pyramid
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline const char* ToString(GroundFootprintShape s)
|
||||||
|
{
|
||||||
|
switch (s)
|
||||||
|
{
|
||||||
|
case GroundFootprintShape::Circle: return "circle";
|
||||||
|
case GroundFootprintShape::Square: return "square";
|
||||||
|
}
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accurate height with footprint & yaw. squareBlend in [0..1]. slopeClamp in [0..10] (0 disables).
|
||||||
|
float GetHeightAccurate(float x, float y, float radius, GroundFootprintShape shape, float yaw,
|
||||||
|
float squareBlend, float slopeClamp, uint32 gradientMode, float normalEps) const;
|
||||||
|
// Convenience wrappers (kept for compatibility).
|
||||||
|
float GetHeightAccurate(float x, float y, float radius) const;
|
||||||
|
float GetHeightAccurate(float x, float y, float radius, GroundFootprintShape shape) const;
|
||||||
|
float GetHeightAccurate(float x, float y, float radius, GroundFootprintShape shape, float yaw /*rads*/) const;
|
||||||
|
inline std::string to_string(GridTerrainData::GroundFootprintShape s) { return GridTerrainData::ToString(s); }
|
||||||
uint16 getArea(float x, float y) const;
|
uint16 getArea(float x, float y) const;
|
||||||
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, uint8 ReqLiquidType) const;
|
||||||
|
private:
|
||||||
|
bool SampleHeights(uint32 xInt, uint32 yInt, float& h1, float& h2, float& h3, float& h4, float& h5) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1175,6 +1175,123 @@ float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float
|
|||||||
return mapHeight; // explicitly use map data
|
return mapHeight; // explicitly use map data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace { constexpr float INV_SQRT2 = 0.70710678118654752440f; }
|
||||||
|
|
||||||
|
float Map::GetVMapHeightAccurate(float x, float y, float z, float radius, float yaw,
|
||||||
|
GridTerrainData::GroundFootprintShape shape, float blend, float clamp, float sampleDelta) const
|
||||||
|
{
|
||||||
|
VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr();
|
||||||
|
auto sample = [&](float sx, float sy) -> float
|
||||||
|
{
|
||||||
|
float h = vmgr->getHeight(GetId(), sx, sy, z, DEFAULT_HEIGHT_SEARCH);
|
||||||
|
return (h > INVALID_HEIGHT) ? h : std::numeric_limits<float>::quiet_NaN();
|
||||||
|
};
|
||||||
|
|
||||||
|
float h0 = sample(x, y);
|
||||||
|
if (!std::isfinite(h0))
|
||||||
|
return VMAP_INVALID_HEIGHT_VALUE;
|
||||||
|
|
||||||
|
if (radius <= 0.0f)
|
||||||
|
return h0;
|
||||||
|
|
||||||
|
const float d = (sampleDelta > 0.0f) ? sampleDelta
|
||||||
|
: std::max(0.05f, std::min(0.5f, radius * 0.5f));
|
||||||
|
|
||||||
|
float hx1 = sample(x + d, y), hx2 = sample(x - d, y);
|
||||||
|
float hy1 = sample(x, y + d), hy2 = sample(x, y - d);
|
||||||
|
|
||||||
|
auto diff = [&](float p, float m) -> float
|
||||||
|
{
|
||||||
|
if (std::isfinite(p) && std::isfinite(m)) return (p - m) / (2.0f * d);
|
||||||
|
if (std::isfinite(p)) return (p - h0) / d;
|
||||||
|
if (std::isfinite(m)) return (h0 - m) / d;
|
||||||
|
return 0.0f;
|
||||||
|
};
|
||||||
|
|
||||||
|
float gx = diff(hx1, hx2); // dz/dx
|
||||||
|
float gy = diff(hy1, hy2); // dz/dy
|
||||||
|
|
||||||
|
if (clamp > 0.0f)
|
||||||
|
{
|
||||||
|
float g2 = gx*gx + gy*gy, c2 = clamp*clamp;
|
||||||
|
if (g2 > c2)
|
||||||
|
{
|
||||||
|
float s = clamp / std::sqrt(g2);
|
||||||
|
gx *= s; gy *= s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float slopeL2 = std::sqrt(std::max(0.0f, gx*gx + gy*gy));
|
||||||
|
float totalSlope = slopeL2;
|
||||||
|
|
||||||
|
if (shape == GridTerrainData::GroundFootprintShape::Square && blend < 1.0f)
|
||||||
|
{
|
||||||
|
float c = std::cos(yaw), s = std::sin(yaw);
|
||||||
|
float rx = gx * c + gy * s, ry = -gx * s + gy * c;
|
||||||
|
float slopeL1 = std::abs(rx) + std::abs(ry);
|
||||||
|
totalSlope = blend * slopeL2 + (1.0f - blend) * (INV_SQRT2 * slopeL1);
|
||||||
|
}
|
||||||
|
return h0 + radius * totalSlope;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Map::GetHeightAccurate(float x, float y, float z, float radius, bool checkVMap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const
|
||||||
|
{
|
||||||
|
return GetHeightAccurate(x, y, z, radius, 0.0f, checkVMap, maxSearchDist);
|
||||||
|
}
|
||||||
|
|
||||||
|
float Map::GetHeightAccurate(float x, float y, float z, float radius, float yaw, bool checkVMap /*= true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const
|
||||||
|
{
|
||||||
|
// find raw .map surface under Z coordinates
|
||||||
|
float mapHeight = VMAP_INVALID_HEIGHT_VALUE;
|
||||||
|
float gridHeight = GetGridHeightAccurate(x, y, radius, yaw);
|
||||||
|
if (gridHeight > INVALID_HEIGHT)
|
||||||
|
{
|
||||||
|
const float tol = std::max(0.1f, 0.5f * radius); // dynamic tolerance based on the size of the collider
|
||||||
|
if (G3D::fuzzyGe(z, gridHeight - tol))
|
||||||
|
mapHeight = gridHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
float vmapHeight = VMAP_INVALID_HEIGHT_VALUE;
|
||||||
|
if (checkVMap)
|
||||||
|
{
|
||||||
|
const bool useAccurateVMap = (sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_VMAP_ENABLE) != 0);
|
||||||
|
if (useAccurateVMap)
|
||||||
|
{
|
||||||
|
auto shape = static_cast<GridTerrainData::GroundFootprintShape>(sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_SHAPE));
|
||||||
|
float blend = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_SQUARE_BLEND);
|
||||||
|
float clamp = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_SLOPE_CLAMP);
|
||||||
|
float delta = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_VMAP_DELTA);
|
||||||
|
vmapHeight = GetVMapHeightAccurate(x, y, z, radius, yaw, shape, blend, clamp, delta);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
VMAP::IVMapMgr* vmgr = VMAP::VMapFactory::createOrGetVMapMgr();
|
||||||
|
vmapHeight = vmgr->getHeight(GetId(), x, y, z, maxSearchDist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// mapHeight set for any above raw ground Z or <= INVALID_HEIGHT
|
||||||
|
// vmapheight set for any under Z value or <= INVALID_HEIGHT
|
||||||
|
if (vmapHeight > INVALID_HEIGHT)
|
||||||
|
{
|
||||||
|
if (mapHeight > INVALID_HEIGHT)
|
||||||
|
{
|
||||||
|
// we have mapheight and vmapheight and must select more appropriate
|
||||||
|
|
||||||
|
// we are already under the surface or vmap height above map heigt
|
||||||
|
// or if the distance of the vmap height is less the land height distance
|
||||||
|
if (vmapHeight > mapHeight || std::fabs(mapHeight - z) > std::fabs(vmapHeight - z))
|
||||||
|
return vmapHeight;
|
||||||
|
else
|
||||||
|
return mapHeight; // better use .map surface height
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return vmapHeight; // we have only vmapHeight (if have)
|
||||||
|
}
|
||||||
|
|
||||||
|
return mapHeight; // explicitly use map data
|
||||||
|
}
|
||||||
|
|
||||||
float Map::GetGridHeight(float x, float y) const
|
float Map::GetGridHeight(float x, float y) const
|
||||||
{
|
{
|
||||||
if (GridTerrainData* gmap = const_cast<Map*>(this)->GetGridTerrainData(x, y))
|
if (GridTerrainData* gmap = const_cast<Map*>(this)->GetGridTerrainData(x, y))
|
||||||
@ -1183,6 +1300,26 @@ float Map::GetGridHeight(float x, float y) const
|
|||||||
return INVALID_HEIGHT;
|
return INVALID_HEIGHT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Map::GetGridHeightAccurate(float x, float y, float radius, float yaw) const
|
||||||
|
{
|
||||||
|
if (GridTerrainData* gmap = const_cast<Map*>(this)->GetGridTerrainData(x, y))
|
||||||
|
{
|
||||||
|
const auto shape = static_cast<GridTerrainData::GroundFootprintShape>(sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_SHAPE));
|
||||||
|
const float blend = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_SQUARE_BLEND);
|
||||||
|
const float clamp = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_SLOPE_CLAMP);
|
||||||
|
const uint32 mode = sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_GRADIENT_MODE);
|
||||||
|
const float eps = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_NORMAL_EPS);
|
||||||
|
return gmap->GetHeightAccurate(x, y, radius, shape, yaw, blend, clamp, mode, eps);
|
||||||
|
}
|
||||||
|
|
||||||
|
return INVALID_HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Map::GetGridHeightAccurate(float x, float y, float radius) const
|
||||||
|
{
|
||||||
|
return GetGridHeightAccurate(x, y, radius, 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
float Map::GetMinHeight(float x, float y) const
|
float Map::GetMinHeight(float x, float y) const
|
||||||
{
|
{
|
||||||
if (GridTerrainData const* grid = const_cast<Map*>(this)->GetGridTerrainData(x, y))
|
if (GridTerrainData const* grid = const_cast<Map*>(this)->GetGridTerrainData(x, y))
|
||||||
@ -1598,6 +1735,35 @@ float Map::GetHeight(uint32 phasemask, float x, float y, float z, bool vmap/*=tr
|
|||||||
return std::max<float>(h1, h2);
|
return std::max<float>(h1, h2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Map::GetHeightAccurate(uint32 phasemask, float x, float y, float z, float radius,
|
||||||
|
bool vmap/*=true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const
|
||||||
|
{
|
||||||
|
return GetHeightAccurate(phasemask, x, y, z, radius, 0.0f, vmap, maxSearchDist);
|
||||||
|
}
|
||||||
|
|
||||||
|
float Map::GetHeightAccurate(uint32 phasemask, float x, float y, float z, float radius, float yaw,
|
||||||
|
bool vmap/*=true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const
|
||||||
|
{
|
||||||
|
const float hMapMix = GetHeightAccurate(x, y, z, radius, yaw, vmap, maxSearchDist);
|
||||||
|
|
||||||
|
float hDyn;
|
||||||
|
const bool dynAcc = (sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_DYNAMIC_ENABLE) != 0);
|
||||||
|
if (dynAcc)
|
||||||
|
{
|
||||||
|
const auto shape = static_cast<GridTerrainData::GroundFootprintShape>(sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_SHAPE));
|
||||||
|
const float blend = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_SQUARE_BLEND);
|
||||||
|
const float clamp = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_SLOPE_CLAMP);
|
||||||
|
const float dlt = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_DYNAMIC_DELTA);
|
||||||
|
const float effBlend = (shape == GridTerrainData::GroundFootprintShape::Square) ? blend : 1.0f;
|
||||||
|
hDyn = _dynamicTree.getHeightAccurate(x, y, z, maxSearchDist, phasemask, radius, yaw, effBlend, clamp, dlt);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hDyn = _dynamicTree.getHeight(x, y, z, maxSearchDist, phasemask);
|
||||||
|
}
|
||||||
|
return std::max<float>(hMapMix, hDyn);
|
||||||
|
}
|
||||||
|
|
||||||
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, MAP_ALL_LIQUIDS);
|
||||||
|
|||||||
@ -238,8 +238,12 @@ public:
|
|||||||
|
|
||||||
// some calls like isInWater should not use vmaps due to processor power
|
// 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
|
// can return INVALID_HEIGHT if under z+2 z coord not found height
|
||||||
|
[[nodiscard]] float GetHeightAccurate(float x, float y, float z, float radius, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const; // wrapper yaw=0
|
||||||
|
[[nodiscard]] float GetHeightAccurate(float x, float y, float z, float radius, float yaw, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
|
||||||
[[nodiscard]] float GetHeight(float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
|
[[nodiscard]] float GetHeight(float x, float y, float z, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
|
||||||
[[nodiscard]] float GetGridHeight(float x, float y) const;
|
[[nodiscard]] float GetGridHeight(float x, float y) const;
|
||||||
|
[[nodiscard]] float GetGridHeightAccurate(float x, float y, float radius) const; // wrapper yaw=0
|
||||||
|
[[nodiscard]] float GetGridHeightAccurate(float x, float y, float radius, float yaw) const;
|
||||||
[[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);
|
||||||
|
|
||||||
@ -382,6 +386,8 @@ public:
|
|||||||
|
|
||||||
float GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, float* ground = nullptr, bool swim = false, float collisionHeight = DEFAULT_COLLISION_HEIGHT) const;
|
float GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, float* ground = nullptr, bool swim = false, float collisionHeight = DEFAULT_COLLISION_HEIGHT) const;
|
||||||
[[nodiscard]] float GetHeight(uint32 phasemask, float x, float y, float z, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
|
[[nodiscard]] float GetHeight(uint32 phasemask, float x, float y, float z, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
|
||||||
|
[[nodiscard]] float GetHeightAccurate(uint32 phasemask, float x, float y, float z, float radius, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const; // wrapper yaw=0
|
||||||
|
[[nodiscard]] float GetHeightAccurate(uint32 phasemask, float x, float y, float z, float radius, float yaw, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
|
||||||
[[nodiscard]] bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const;
|
[[nodiscard]] bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const;
|
||||||
bool CanReachPositionAndGetValidCoords(WorldObject const* source, PathGenerator *path, float &destX, float &destY, float &destZ, bool failOnCollision = true, bool failOnSlopes = true) const;
|
bool CanReachPositionAndGetValidCoords(WorldObject const* source, PathGenerator *path, float &destX, float &destY, float &destZ, bool failOnCollision = true, bool failOnSlopes = true) const;
|
||||||
bool CanReachPositionAndGetValidCoords(WorldObject const* source, float &destX, float &destY, float &destZ, bool failOnCollision = true, bool failOnSlopes = true) const;
|
bool CanReachPositionAndGetValidCoords(WorldObject const* source, float &destX, float &destY, float &destZ, bool failOnCollision = true, bool failOnSlopes = true) const;
|
||||||
@ -539,6 +545,9 @@ private:
|
|||||||
bool EnsureGridLoaded(Cell const& cell);
|
bool EnsureGridLoaded(Cell const& cell);
|
||||||
MapGridType* GetMapGrid(uint16 const x, uint16 const y);
|
MapGridType* GetMapGrid(uint16 const x, uint16 const y);
|
||||||
|
|
||||||
|
[[nodiscard]] float GetVMapHeightAccurate(float x, float y, float z, float radius, float yaw,
|
||||||
|
GridTerrainData::GroundFootprintShape shape, float blend, float clamp, float sampleDelta) const;
|
||||||
|
|
||||||
void ScriptsProcess();
|
void ScriptsProcess();
|
||||||
|
|
||||||
void SendObjectUpdates();
|
void SendObjectUpdates();
|
||||||
|
|||||||
@ -285,6 +285,17 @@ void WorldConfig::BuildConfigCache()
|
|||||||
SetConfigValue<bool>(CONFIG_GM_LOWER_SECURITY, "GM.LowerSecurity", false);
|
SetConfigValue<bool>(CONFIG_GM_LOWER_SECURITY, "GM.LowerSecurity", false);
|
||||||
SetConfigValue<float>(CONFIG_CHANCE_OF_GM_SURVEY, "GM.TicketSystem.ChanceOfGMSurvey", 50.0f);
|
SetConfigValue<float>(CONFIG_CHANCE_OF_GM_SURVEY, "GM.TicketSystem.ChanceOfGMSurvey", 50.0f);
|
||||||
|
|
||||||
|
SetConfigValue<uint32>(CONFIG_HEIGHT_ACCURATE_SHAPE, "Height.Accurate.Shape", 0, ConfigValueCache::Reloadable::Yes, [](uint32 const& value) { return value <= 1; }, "<= 1");
|
||||||
|
SetConfigValue<float>(CONFIG_HEIGHT_ACCURATE_RADIUS_SCALE, "Height.Accurate.RadiusScale", 1.0f, ConfigValueCache::Reloadable::Yes, [](float const& value) { return value >= 0.1f && value <= 4.0f; }, ">= 0.1 and <= 4.0");
|
||||||
|
SetConfigValue<float>(CONFIG_HEIGHT_ACCURATE_SQUARE_BLEND, "Height.Accurate.SquareBlend", 0.20f, ConfigValueCache::Reloadable::Yes, [](float const& value) { return value >= 0.0f && value <= 1.0f; }, ">= 0.0 and <= 1.0");
|
||||||
|
SetConfigValue<float>(CONFIG_HEIGHT_ACCURATE_SLOPE_CLAMP, "Height.Accurate.SlopeClamp", 0.0f, ConfigValueCache::Reloadable::Yes, [](float const& value) { return value >= 0.0f && value <= 10.0f; }, ">= 0.0 and <= 10.0");
|
||||||
|
SetConfigValue<uint32>(CONFIG_HEIGHT_ACCURATE_GRADIENT_MODE, "Height.Accurate.GradientMode", 0, ConfigValueCache::Reloadable::Yes, [](uint32 const& value) { return value <= 1; }, "<= 1");
|
||||||
|
SetConfigValue<float>(CONFIG_HEIGHT_ACCURATE_NORMAL_EPS, "Height.Accurate.NormalEps", 1.0e-6f, ConfigValueCache::Reloadable::Yes, [](float const& value) { return value >= 1e-8f && value <= 1e-3f; }, ">= 1e-8f and <= 1e-3f");
|
||||||
|
SetConfigValue<uint32>(CONFIG_HEIGHT_ACCURATE_VMAP_ENABLE, "Height.Accurate.VMap.Enable", 1, ConfigValueCache::Reloadable::Yes, [](uint32 const& value) { return value <= 1; }, "<= 1");
|
||||||
|
SetConfigValue<float>(CONFIG_HEIGHT_ACCURATE_VMAP_DELTA, "Height.Accurate.VMap.Delta", 0.25f, ConfigValueCache::Reloadable::Yes, [](float const& value) { return value >= 0.01f && value <= 1.0f; }, ">= 0.01f and <= 1.0f");
|
||||||
|
SetConfigValue<uint32>(CONFIG_HEIGHT_ACCURATE_DYNAMIC_ENABLE, "Height.Accurate.Dynamic.Enable", 1, ConfigValueCache::Reloadable::Yes, [](uint32 const& value) { return value <= 1; }, "<= 1");
|
||||||
|
SetConfigValue<float>(CONFIG_HEIGHT_ACCURATE_DYNAMIC_DELTA, "Height.Accurate.Dynamic.Delta", 0.25f, ConfigValueCache::Reloadable::Yes, [](float const& value) { return value >= 0.01f && value <= 1.0f; }, ">= 0.01f and <= 1.0f");
|
||||||
|
|
||||||
SetConfigValue<uint32>(CONFIG_GROUP_VISIBILITY, "Visibility.GroupMode", 1);
|
SetConfigValue<uint32>(CONFIG_GROUP_VISIBILITY, "Visibility.GroupMode", 1);
|
||||||
|
|
||||||
SetConfigValue<bool>(CONFIG_OBJECT_SPARKLES, "Visibility.ObjectSparkles", true);
|
SetConfigValue<bool>(CONFIG_OBJECT_SPARKLES, "Visibility.ObjectSparkles", true);
|
||||||
|
|||||||
@ -484,7 +484,16 @@ enum ServerConfigs
|
|||||||
RATE_MISS_CHANCE_MULTIPLIER_TARGET_PLAYER,
|
RATE_MISS_CHANCE_MULTIPLIER_TARGET_PLAYER,
|
||||||
CONFIG_NEW_CHAR_STRING,
|
CONFIG_NEW_CHAR_STRING,
|
||||||
CONFIG_VALIDATE_SKILL_LEARNED_BY_SPELLS,
|
CONFIG_VALIDATE_SKILL_LEARNED_BY_SPELLS,
|
||||||
|
CONFIG_HEIGHT_ACCURATE_RADIUS_SCALE,
|
||||||
|
CONFIG_HEIGHT_ACCURATE_SQUARE_BLEND,
|
||||||
|
CONFIG_HEIGHT_ACCURATE_SLOPE_CLAMP,
|
||||||
|
CONFIG_HEIGHT_ACCURATE_SHAPE,
|
||||||
|
CONFIG_HEIGHT_ACCURATE_NORMAL_EPS,
|
||||||
|
CONFIG_HEIGHT_ACCURATE_VMAP_DELTA,
|
||||||
|
CONFIG_HEIGHT_ACCURATE_DYNAMIC_DELTA,
|
||||||
|
CONFIG_HEIGHT_ACCURATE_GRADIENT_MODE,
|
||||||
|
CONFIG_HEIGHT_ACCURATE_VMAP_ENABLE,
|
||||||
|
CONFIG_HEIGHT_ACCURATE_DYNAMIC_ENABLE,
|
||||||
MAX_NUM_SERVER_CONFIGS
|
MAX_NUM_SERVER_CONFIGS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -619,6 +619,7 @@ public:
|
|||||||
AreaTableEntry const* zoneEntry = sAreaTableStore.LookupEntry(zoneId);
|
AreaTableEntry const* zoneEntry = sAreaTableStore.LookupEntry(zoneId);
|
||||||
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);
|
AreaTableEntry const* areaEntry = sAreaTableStore.LookupEntry(areaId);
|
||||||
|
|
||||||
|
Map* map = object->GetMap();
|
||||||
float zoneX = object->GetPositionX();
|
float zoneX = object->GetPositionX();
|
||||||
float zoneY = object->GetPositionY();
|
float zoneY = object->GetPositionY();
|
||||||
|
|
||||||
@ -626,6 +627,22 @@ public:
|
|||||||
|
|
||||||
float groundZ = object->GetMapHeight(object->GetPositionX(), object->GetPositionY(), MAX_HEIGHT);
|
float groundZ = object->GetMapHeight(object->GetPositionX(), object->GetPositionY(), MAX_HEIGHT);
|
||||||
float floorZ = object->GetMapHeight(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ());
|
float floorZ = object->GetMapHeight(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ());
|
||||||
|
const float probeR = object->GetGroundProbeRadius(); // pre-scale
|
||||||
|
const float rScale = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_RADIUS_SCALE);
|
||||||
|
const float blend = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_SQUARE_BLEND);
|
||||||
|
const float clamp = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_SLOPE_CLAMP);
|
||||||
|
const uint32 gmode = sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_GRADIENT_MODE);
|
||||||
|
const float neps = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_NORMAL_EPS);
|
||||||
|
const uint32 vmapAcc = sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_VMAP_ENABLE);
|
||||||
|
const float vdelta = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_VMAP_DELTA);
|
||||||
|
const uint32 dynAcc = sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_DYNAMIC_ENABLE);
|
||||||
|
const float dyndelta = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_DYNAMIC_DELTA);
|
||||||
|
const float yaw = object->GetOrientation();
|
||||||
|
const float probeRScaled = probeR * rScale;
|
||||||
|
|
||||||
|
const float GridZAccurate = map->GetGridHeightAccurate(object->GetPositionX(), object->GetPositionY(), probeRScaled, yaw);
|
||||||
|
const float MapZAccurate = object->GetMapHeightAccurate(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), true, DEFAULT_HEIGHT_SEARCH, probeR);
|
||||||
|
const char* shapeStr = GridTerrainData::ToString(static_cast<GridTerrainData::GroundFootprintShape>(sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_SHAPE)));
|
||||||
|
|
||||||
uint32 haveMap = GridTerrainLoader::ExistMap(object->GetMapId(), cell.GridX(), cell.GridY()) ? 1 : 0;
|
uint32 haveMap = GridTerrainLoader::ExistMap(object->GetMapId(), cell.GridX(), cell.GridY()) ? 1 : 0;
|
||||||
uint32 haveVMap = GridTerrainLoader::ExistVMap(object->GetMapId(), cell.GridX(), cell.GridY()) ? 1 : 0;
|
uint32 haveVMap = GridTerrainLoader::ExistVMap(object->GetMapId(), cell.GridX(), cell.GridY()) ? 1 : 0;
|
||||||
@ -656,6 +673,12 @@ public:
|
|||||||
cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), object->GetInstanceId(),
|
cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), object->GetInstanceId(),
|
||||||
zoneX, zoneY, groundZ, floorZ, haveMap, haveVMap, haveMMAP);
|
zoneX, zoneY, groundZ, floorZ, haveMap, haveVMap, haveMMAP);
|
||||||
|
|
||||||
|
handler->PSendSysMessage("Accurate Height Shape: {} (SquareBlend: {:0.2f}, RadiusScale: {:0.2f}, SlopeClamp: {:0.2f}, GradMode: {}, NormalEps: {:0.6f}, VMapAccurate: {}, VMapDelta: {:0.2f}, DynAccurate: {}, DynDelta: {:0.2f})",
|
||||||
|
shapeStr, blend, rScale, clamp, gmode, neps, vmapAcc, vdelta, dynAcc, dyndelta);
|
||||||
|
handler->PSendSysMessage("Accurate Height Grid: {}", GridZAccurate);
|
||||||
|
handler->PSendSysMessage("Accurate Height Map: {}", MapZAccurate);
|
||||||
|
handler->PSendSysMessage("Probe radius (pre-scale): {:0.3f}", probeR);
|
||||||
|
|
||||||
LiquidData const& liquidData = object->GetLiquidData();
|
LiquidData const& liquidData = object->GetLiquidData();
|
||||||
|
|
||||||
if (liquidData.Status)
|
if (liquidData.Status)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user