Square vs Cylinder

This commit is contained in:
VG-prog 2025-09-24 10:17:16 +02:00
parent f3bd5adf8e
commit 795570ba8f
8 changed files with 129 additions and 55 deletions

View File

@ -3037,10 +3037,16 @@ float WorldObject::GetMapHeightAccurate(float x, float y, float z, bool vmap/* =
radius = 0.3f;
}
float rScale = 1.0f;
if (sWorld)
rScale = std::max(0.1f, 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, vmap, distanceToSearch);
return GetMap()->GetHeightAccurate(GetPhaseMask(), x, y, z, radius, yaw, vmap, distanceToSearch);
}
float WorldObject::GetMapWaterOrGroundLevel(float x, float y, float z, float* ground/* = nullptr*/) const

View File

@ -3,6 +3,7 @@
#include "GridTerrainData.h"
#include "Log.h"
#include "MapDefines.h"
#include "World.h"
#include <filesystem>
#include <G3D/Ray.h>
@ -616,6 +617,11 @@ LiquidData const GridTerrainData::GetLiquidData(float x, float y, float z, float
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
@ -677,6 +683,16 @@ bool GridTerrainData::SampleHeights(uint32 xInt, uint32 yInt, float& h1, float&
}
float GridTerrainData::GetHeightAccurate(float x, float y, float radius) const
{
return GetHeightAccurate(x, y, radius, GroundFootprintShape::Circle, 0.0f);
}
float GridTerrainData::GetHeightAccurate(float x, float y, float radius, GroundFootprintShape shape) const
{
return GetHeightAccurate(x, y, radius, shape, 0.0f);
}
float GridTerrainData::GetHeightAccurate(float x, float y, float radius, GroundFootprintShape shape, float yaw) const
{
if (!_loadedHeightData)
return INVALID_HEIGHT;
@ -707,56 +723,53 @@ float GridTerrainData::GetHeightAccurate(float x, float y, float radius) const
const float S2 = S * 0.5f;
G3D::Vector3 P(fx * S, fy * S, 0.0f);
G3D::Vector3 A(S2, S2, h5);
G3D::Vector3 B, C;
if (fx + fy < 1.0f)
const float eps = 1e-6f;
auto evalTri = [&](G3D::Vector3 const& B, G3D::Vector3 const& C) -> float
{
if (fx > fy)
G3D::Vector3 U = B - A;
G3D::Vector3 V = C - A;
G3D::Vector3 n = U.cross(V);
const float nzAbs = std::abs(n.z);
if (nzAbs < eps)
return -1.0e30f; // inválido
const float d = -(n.x * A.x + n.y * A.y + n.z * A.z);
const float zPlane = (-d - n.x * P.x - n.y * P.y) / n.z;
const float denom = std::max(eps, nzAbs);
if (shape == GroundFootprintShape::Square)
{
B = G3D::Vector3(S, 0.0f, h2);
C = G3D::Vector3(0.0f, 0.0f, h1);
float blend = 0.0f;
if (sWorld)
blend = std::clamp(sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_SQUARE_BLEND), 0.0f, 1.0f);
float c = std::cos(yaw), s = std::sin(yaw);
float rx = n.x * c + n.y * s;
float ry = -n.x * s + n.y * c;
const float slopeL1 = (std::abs(rx) + std::abs(ry)) / denom;
const float slopeL2 = std::sqrt(std::max(0.0f, n.x * n.x + n.y * n.y)) / denom;
const float addSq = (radius * (1.0f - blend) * INV_SQRT2) * slopeL1;
const float addCir = (radius * blend) * slopeL2;
return zPlane + addSq + addCir;
}
else
{
B = G3D::Vector3(0.0f, 0.0f, h1);
C = G3D::Vector3(0.0f, S, h3);
const float slopeL2 = std::sqrt(std::max(0.0f, n.x * n.x + n.y * n.y)) / denom;
return zPlane + radius * slopeL2;
}
}
else
{
if (fx > fy)
{
B = G3D::Vector3(S, S, h4);
C = G3D::Vector3(S, 0, h2);
}
else
{
B = G3D::Vector3(0, S, h3);
C = G3D::Vector3(S, S, h4);
}
}
};
G3D::Vector3 U = B - A;
G3D::Vector3 V = C - A;
G3D::Vector3 n = U.cross(V);
float bestZ = -1.0e30f;
bool have = false;
auto take = [&](float zc) { if (std::isfinite(zc)) { have = true; if (zc > bestZ) bestZ = zc; } };
take(evalTri(G3D::Vector3(S, 0.0f, h2), G3D::Vector3(0.0f, 0.0f, h1))); // center-h2-h1
take(evalTri(G3D::Vector3(S, S, h4), G3D::Vector3(S, 0.0f, h2))); // center-h4-h2
take(evalTri(G3D::Vector3(0.0f, S, h3), G3D::Vector3(S, S, h4))); // center-h3-h4
take(evalTri(G3D::Vector3(0.0f, 0.0f,h1), G3D::Vector3(0.0f, S, h3))); // center-h1-h3
float nz = n.z;
float const eps = 1e-6f;
if (std::abs(nz) < eps)
if (!have)
return getHeight(x, y);
if (nz < 0.0f)
n = -n;
n = n.unit();
float d = -n.dot(A);
float z = (radius - d - n.x * P.x - n.y * P.y) / n.z;
if (!std::isfinite(z))
return getHeight(x, y);
return z;
return bestZ;
}

View File

@ -245,7 +245,16 @@ public:
~GridTerrainData() { };
TerrainMapDataReadResult Load(std::string const& mapFileName);
enum class GroundFootprintShape : uint8
{
Circle = 0, // cylinder-plane
Square = 1 // upside-down pyramid
};
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;
uint16 getArea(float x, float y) const;
inline float getHeight(float x, float y) const { return (this->*_gridGetHeight)(x, y); }
float getMinHeight(float x, float y) const;

View File

@ -1176,10 +1176,15 @@ float Map::GetHeight(float x, float y, float z, bool checkVMap /*= true*/, float
}
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);
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
@ -1224,14 +1229,24 @@ float Map::GetGridHeight(float x, float y) const
return INVALID_HEIGHT;
}
float Map::GetGridHeightAccurate(float x, float y, float radius) const
float Map::GetGridHeightAccurate(float x, float y, float radius, float yaw) const
{
if (GridTerrainData* gmap = const_cast<Map*>(this)->GetGridTerrainData(x, y))
return gmap->GetHeightAccurate(x, y, radius);
{
GridTerrainData::GroundFootprintShape shape = GridTerrainData::GroundFootprintShape::Circle;
if (sWorld && sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_SHAPE) == 1)
shape = GridTerrainData::GroundFootprintShape::Square;
return gmap->GetHeightAccurate(x, y, radius, shape, yaw);
}
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
{
if (GridTerrainData const* grid = const_cast<Map*>(this)->GetGridTerrainData(x, y))
@ -1650,10 +1665,15 @@ float Map::GetHeight(uint32 phasemask, float x, float y, float z, bool vmap/*=tr
float Map::GetHeightAccurate(uint32 phasemask, float x, float y, float z, float radius,
bool vmap/*=true*/, float maxSearchDist /*= DEFAULT_HEIGHT_SEARCH*/) const
{
float h1, h2;
h1 = GetHeightAccurate(x, y, z, radius, vmap, maxSearchDist);
h2 = _dynamicTree.getHeight(x, y, z, maxSearchDist, phasemask);
return std::max<float>(h1, h2);
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);
const float 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

View File

@ -235,10 +235,12 @@ public:
// 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
[[nodiscard]] float GetHeightAccurate(float x, float y, float z, float radius, bool checkVMap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
[[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 GetGridHeight(float x, float y) const;
[[nodiscard]] float GetGridHeightAccurate(float x, float y, float radius) 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;
Transport* GetTransportForPos(uint32 phase, float x, float y, float z, WorldObject* worldobject = nullptr);
@ -381,7 +383,8 @@ public:
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 GetHeightAccurate(uint32 phasemask, float x, float y, float z, float radius, 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;
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;

View File

@ -282,6 +282,13 @@ void WorldConfig::BuildConfigCache()
SetConfigValue<bool>(CONFIG_GM_LOWER_SECURITY, "GM.LowerSecurity", false);
SetConfigValue<float>(CONFIG_CHANCE_OF_GM_SURVEY, "GM.TicketSystem.ChanceOfGMSurvey", 50.0f);
SetConfigValue<bool>(CONFIG_HEIGHT_ACCURATE_ENABLE, "Height.Accurate.Enable", true);
SetConfigValue<uint32>(CONFIG_HEIGHT_ACCURATE_SHAPE, "Height.Accurate.Shape", 1);
SetConfigValue<float>(CONFIG_HEIGHT_ACCURATE_RADIUS_SCALE, "Height.Accurate.RadiusScale", 1.0f), 0.05f, 4.0f);
float raw = sConfigMgr->GetOption<float>("Height.Accurate.SquareBlend", 0.20f);
float clamped = std::clamp(raw, 0.0f, 1.0f);
SetConfigValue<float>(CONFIG_HEIGHT_ACCURATE_SQUARE_BLEND, "Height.Accurate.SquareBlend", clamped);
SetConfigValue<uint32>(CONFIG_GROUP_VISIBILITY, "Visibility.GroupMode", 1);
SetConfigValue<bool>(CONFIG_OBJECT_SPARKLES, "Visibility.ObjectSparkles", true);

View File

@ -480,7 +480,10 @@ enum ServerConfigs
RATE_MISS_CHANCE_MULTIPLIER_TARGET_PLAYER,
CONFIG_NEW_CHAR_STRING,
CONFIG_VALIDATE_SKILL_LEARNED_BY_SPELLS,
CONFIG_HEIGHT_ACCURATE_RADIUS_SCALE,
CONFIG_HEIGHT_ACCURATE_SQUARE_BLEND,
CONFIG_HEIGHT_ACCURATE_ENABLE,
CONFIG_HEIGHT_ACCURATE_SHAPE,
MAX_NUM_SERVER_CONFIGS
};

View File

@ -629,8 +629,12 @@ public:
float groundZ = object->GetMapHeight(object->GetPositionX(), object->GetPositionY(), MAX_HEIGHT);
float floorZ = object->GetMapHeight(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ());
float GridZAccurate = map->GetGridHeightAccurate(object->GetPositionX(), object->GetPositionY(), object->GetGroundProbeRadius());
float MapZAccurate = object->GetMapHeightAccurate(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), true, DEFAULT_HEIGHT_SEARCH, object->GetGroundProbeRadius());
float probeR = object->GetGroundProbeRadius();
float GridZAccurate = map->GetGridHeightAccurate(object->GetPositionX(), object->GetPositionY(), probeR);
float MapZAccurate = object->GetMapHeightAccurate(object->GetPositionX(), object->GetPositionY(), object->GetPositionZ(), true, DEFAULT_HEIGHT_SEARCH, probeR);
const char* shapeStr = "circle";
if (sWorld && sWorld->getIntConfig(CONFIG_HEIGHT_ACCURATE_SHAPE) == 1)
shapeStr = "square";
uint32 haveMap = GridTerrainLoader::ExistMap(object->GetMapId(), cell.GridX(), cell.GridY()) ? 1 : 0;
uint32 haveVMap = GridTerrainLoader::ExistVMap(object->GetMapId(), cell.GridX(), cell.GridY()) ? 1 : 0;
@ -661,8 +665,17 @@ public:
cell.GridX(), cell.GridY(), cell.CellX(), cell.CellY(), object->GetInstanceId(),
zoneX, zoneY, groundZ, floorZ, haveMap, haveVMap, haveMMAP);
float rScale = 1.0f;
float blend = 0.0f;
if (sWorld)
{
rScale = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_RADIUS_SCALE);
blend = sWorld->getFloatConfig(CONFIG_HEIGHT_ACCURATE_SQUARE_BLEND);
}
handler->PSendSysMessage("Accurate Height Shape: %s (SquareBlend: %.2f, RadiusScale: %.2f)", shapeStr, blend, rScale);
handler->PSendSysMessage("Accurate Height Grid: %f", GridZAccurate);
handler->PSendSysMessage("Accurate Height Map: %f", MapZAccurate);
handler->PSendSysMessage("Probe radius (pre-scale): %.3f", probeR);
LiquidData const& liquidData = object->GetLiquidData();