mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-15 17:14:07 +00:00
feat(physics): movement blockers the server's movers can't walk through
Enemies are moved along navmesh paths without collision, so a wall only stops them if their path stops at it. dpWorld now keeps a list of such walls, each with the collision filter it blocks with, and cuts a path where it first walks into one (a little short of the wall; a mover inside one can walk out). Which objects block comes from data (dpMovementBlockers::BlockingFilter): - navmesh carvers (navmesh_carver in the level config, which the client reads with add_to_navmesh and carver_only) block every mover; - solid objects whose collision group touches enemies and not players (group 18, e.g. "FV - Enemy Blocking Volume", "PR - Pet Blocker") block what that group touches. dpShapeBox gains SegmentEntry, a segment test against the rotated box. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include "NiQuaternion.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
dpShapeBox::dpShapeBox(dpEntity* parentEntity, float width, float height, float depth) :
|
||||
@@ -108,6 +109,37 @@ float dpShapeBox::SquaredDistanceTo(const NiPoint3& point) const {
|
||||
return dX * dX + dY * dY + dZ * dZ;
|
||||
}
|
||||
|
||||
std::optional<float> dpShapeBox::SegmentEntry(const NiPoint3& a, const NiPoint3& b) const {
|
||||
// Into the box's frame (origin the middle of its bottom face), then clip the segment against each pair of faces
|
||||
const auto inverse = glm::conjugate(m_Orientation);
|
||||
const auto localA = (a - m_Origin).RotateByQuaternion(inverse);
|
||||
const auto localB = (b - m_Origin).RotateByQuaternion(inverse);
|
||||
|
||||
const float start[3]{ localA.x, localA.y, localA.z };
|
||||
const float delta[3]{ localB.x - localA.x, localB.y - localA.y, localB.z - localA.z };
|
||||
const float min[3]{ -m_Width, 0.0f, -m_Depth };
|
||||
const float max[3]{ m_Width, m_Height * 2.0f, m_Depth };
|
||||
|
||||
bool startsInside = true;
|
||||
float enter = 0.0f;
|
||||
float exit = 1.0f;
|
||||
for (int axis = 0; axis < 3; axis++) {
|
||||
if (start[axis] < min[axis] || start[axis] > max[axis]) startsInside = false;
|
||||
if (std::abs(delta[axis]) < 1e-6f) {
|
||||
if (start[axis] < min[axis] || start[axis] > max[axis]) return std::nullopt;
|
||||
continue;
|
||||
}
|
||||
float tNear = (min[axis] - start[axis]) / delta[axis];
|
||||
float tFar = (max[axis] - start[axis]) / delta[axis];
|
||||
if (tNear > tFar) std::swap(tNear, tFar);
|
||||
enter = std::max(enter, tNear);
|
||||
exit = std::min(exit, tFar);
|
||||
if (enter > exit) return std::nullopt;
|
||||
}
|
||||
if (startsInside) return std::nullopt;
|
||||
return enter;
|
||||
}
|
||||
|
||||
void dpShapeBox::InitVertices() {
|
||||
//The four top verts
|
||||
m_TopMinLeft = NiPoint3(GetMinWidth(), GetTop(), GetMinDepth());
|
||||
|
||||
Reference in New Issue
Block a user