mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-12 22:01:30 +00:00
[Pathing] Improvements to handling tight corridors pathing, clipping detection and recovery (#2826)
This commit is contained in:
parent
823e73336d
commit
404f7cada8
@ -317,6 +317,7 @@ RULE_BOOL(Map, FixPathingZOnSendTo, false, "Try to repair Z coordinates in the S
|
|||||||
RULE_BOOL(Map, FixZWhenPathing, true, "Automatically fix NPC Z coordinates when moving/pathing/engaged (Far less CPU intensive than its predecessor)")
|
RULE_BOOL(Map, FixZWhenPathing, true, "Automatically fix NPC Z coordinates when moving/pathing/engaged (Far less CPU intensive than its predecessor)")
|
||||||
RULE_REAL(Map, DistanceCanTravelBeforeAdjustment, 10.0, "Distance a mob can path before FixZ is called, depends on FixZWhenPathing")
|
RULE_REAL(Map, DistanceCanTravelBeforeAdjustment, 10.0, "Distance a mob can path before FixZ is called, depends on FixZWhenPathing")
|
||||||
RULE_BOOL(Map, MobZVisualDebug, false, "Displays spell effects determining whether or not NPC is hitting Best Z calcs (blue for hit, red for miss)")
|
RULE_BOOL(Map, MobZVisualDebug, false, "Displays spell effects determining whether or not NPC is hitting Best Z calcs (blue for hit, red for miss)")
|
||||||
|
RULE_BOOL(Map, MobPathingVisualDebug, false, "Displays nodes in pathing points in realtime to help with visual debugging")
|
||||||
RULE_REAL(Map, FixPathingZMaxDeltaSendTo, 20, "At runtime in SendTo: maximum change in Z to allow the BestZ code to apply")
|
RULE_REAL(Map, FixPathingZMaxDeltaSendTo, 20, "At runtime in SendTo: maximum change in Z to allow the BestZ code to apply")
|
||||||
RULE_INT(Map, FindBestZHeightAdjust, 1, "Adds this to the current Z before seeking the best Z position")
|
RULE_INT(Map, FindBestZHeightAdjust, 1, "Adds this to the current Z before seeking the best Z position")
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|||||||
@ -29,6 +29,7 @@ void command_loc(Client *c, const Seperator *sep)
|
|||||||
glm::vec3 hit;
|
glm::vec3 hit;
|
||||||
|
|
||||||
auto best_z = zone->zonemap->FindBestZ(tarloc, &hit);
|
auto best_z = zone->zonemap->FindBestZ(tarloc, &hit);
|
||||||
|
auto fixed_z = c->GetFixedZ(c->GetPosition());
|
||||||
|
|
||||||
if (best_z != BEST_Z_INVALID) {
|
if (best_z != BEST_Z_INVALID) {
|
||||||
c->Message(
|
c->Message(
|
||||||
@ -39,6 +40,14 @@ void command_loc(Client *c, const Seperator *sep)
|
|||||||
best_z
|
best_z
|
||||||
).c_str()
|
).c_str()
|
||||||
);
|
);
|
||||||
|
c->Message(
|
||||||
|
Chat::White,
|
||||||
|
fmt::format(
|
||||||
|
"Fixed Z for {} | {:.2f}",
|
||||||
|
c->GetTargetDescription(target, TargetDescriptionType::UCSelf),
|
||||||
|
fixed_z
|
||||||
|
).c_str()
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
c->Message(Chat::White, "Could not find Best Z.");
|
c->Message(Chat::White, "Could not find Best Z.");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1451,6 +1451,8 @@ public:
|
|||||||
void SetManualFollow(bool flag) { m_manual_follow = flag; }
|
void SetManualFollow(bool flag) { m_manual_follow = flag; }
|
||||||
bool GetManualFollow() const { return m_manual_follow; }
|
bool GetManualFollow() const { return m_manual_follow; }
|
||||||
|
|
||||||
|
void DrawDebugCoordinateNode(std::string node_name, const glm::vec4 vec);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void CommonDamage(Mob* other, int64 &damage, const uint16 spell_id, const EQ::skills::SkillType attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic, eSpecialAttacks specal = eSpecialAttacks::None);
|
void CommonDamage(Mob* other, int64 &damage, const uint16 spell_id, const EQ::skills::SkillType attack_skill, bool &avoidable, const int8 buffslot, const bool iBuffTic, eSpecialAttacks specal = eSpecialAttacks::None);
|
||||||
static uint16 GetProcID(uint16 spell_id, uint8 effect_index);
|
static uint16 GetProcID(uint16 spell_id, uint8 effect_index);
|
||||||
|
|||||||
@ -138,7 +138,7 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Send a movement packet when you start moving
|
//Send a movement packet when you start moving
|
||||||
double current_time = static_cast<double>(Timer::GetCurrentTime()) / 1000.0;
|
double current_time = static_cast<double>(Timer::GetCurrentTime()) / 1000.0;
|
||||||
int current_speed = 0;
|
int current_speed = 0;
|
||||||
|
|
||||||
@ -1053,6 +1053,13 @@ void MobMovementManager::FillCommandStruct(
|
|||||||
position_update->delta_z = FloatToEQ13(delta_z);
|
position_update->delta_z = FloatToEQ13(delta_z);
|
||||||
position_update->delta_heading = FloatToEQ10(delta_heading);
|
position_update->delta_heading = FloatToEQ10(delta_heading);
|
||||||
position_update->animation = (mob->IsBot() ? (int) ((float) anim / 1.785714f) : anim);
|
position_update->animation = (mob->IsBot() ? (int) ((float) anim / 1.785714f) : anim);
|
||||||
|
|
||||||
|
if (RuleB(Map, MobPathingVisualDebug)) {
|
||||||
|
mob->DrawDebugCoordinateNode(
|
||||||
|
fmt::format("{} position update", mob->GetCleanName()),
|
||||||
|
mob->GetPosition()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1093,7 +1100,7 @@ void MobMovementManager::UpdatePath(Mob *who, float x, float y, float z, MobMove
|
|||||||
}
|
}
|
||||||
// Below for npcs that can traverse land or water so they don't sink
|
// Below for npcs that can traverse land or water so they don't sink
|
||||||
else if (who->GetFlyMode() == GravityBehavior::Water &&
|
else if (who->GetFlyMode() == GravityBehavior::Water &&
|
||||||
zone->watermap->InLiquid(who->GetPosition()) &&
|
zone->watermap->InLiquid(who->GetPosition()) &&
|
||||||
zone->watermap->InLiquid(glm::vec3(x, y, z)) &&
|
zone->watermap->InLiquid(glm::vec3(x, y, z)) &&
|
||||||
zone->zonemap->CheckLoS(who->GetPosition(), glm::vec3(x, y, z))) {
|
zone->zonemap->CheckLoS(who->GetPosition(), glm::vec3(x, y, z))) {
|
||||||
auto iter = _impl->Entries.find(who);
|
auto iter = _impl->Entries.find(who);
|
||||||
|
|||||||
@ -6415,7 +6415,7 @@ void Client::SetItemRecastTimer(int32 spell_id, uint32 inventory_slot)
|
|||||||
recast_delay = std::max(recast_delay, 0);
|
recast_delay = std::max(recast_delay, 0);
|
||||||
|
|
||||||
if (recast_delay > 0) {
|
if (recast_delay > 0) {
|
||||||
|
|
||||||
if (recast_type != RECAST_TYPE_UNLINKED_ITEM) {
|
if (recast_type != RECAST_TYPE_UNLINKED_ITEM) {
|
||||||
GetPTimers().Start((pTimerItemStart + recast_type), static_cast<uint32>(recast_delay));
|
GetPTimers().Start((pTimerItemStart + recast_type), static_cast<uint32>(recast_delay));
|
||||||
database.UpdateItemRecast(
|
database.UpdateItemRecast(
|
||||||
@ -6441,14 +6441,14 @@ void Client::SetItemRecastTimer(int32 spell_id, uint32 inventory_slot)
|
|||||||
void Client::DeleteItemRecastTimer(uint32 item_id)
|
void Client::DeleteItemRecastTimer(uint32 item_id)
|
||||||
{
|
{
|
||||||
const auto* d = database.GetItem(item_id);
|
const auto* d = database.GetItem(item_id);
|
||||||
|
|
||||||
if (!d) {
|
if (!d) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto recast_type = d->RecastType != RECAST_TYPE_UNLINKED_ITEM ? d->RecastType : item_id;
|
const auto recast_type = d->RecastType != RECAST_TYPE_UNLINKED_ITEM ? d->RecastType : item_id;
|
||||||
const int timer_id = d->RecastType != RECAST_TYPE_UNLINKED_ITEM ? (pTimerItemStart + recast_type) : (pTimerNegativeItemReuse * item_id);
|
const int timer_id = d->RecastType != RECAST_TYPE_UNLINKED_ITEM ? (pTimerItemStart + recast_type) : (pTimerNegativeItemReuse * item_id);
|
||||||
|
|
||||||
database.DeleteItemRecast(CharacterID(), recast_type);
|
database.DeleteItemRecast(CharacterID(), recast_type);
|
||||||
GetPTimers().Clear(&database, timer_id);
|
GetPTimers().Clear(&database, timer_id);
|
||||||
|
|
||||||
@ -7002,3 +7002,17 @@ void Mob::SetHP(int64 hp)
|
|||||||
|
|
||||||
current_hp = hp;
|
current_hp = hp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Mob::DrawDebugCoordinateNode(std::string node_name, const glm::vec4 vec)
|
||||||
|
{
|
||||||
|
NPC* node = nullptr;
|
||||||
|
for (const auto& n : entity_list.GetNPCList()) {
|
||||||
|
if (n.second->GetCleanName() == node_name) {
|
||||||
|
node = n.second;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!node) {
|
||||||
|
node = NPC::SpawnNodeNPC(node_name, "", GetPosition());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -771,17 +771,15 @@ float Mob::GetFixedZ(const glm::vec3 &destination, int32 z_find_offset) {
|
|||||||
float new_z = destination.z;
|
float new_z = destination.z;
|
||||||
|
|
||||||
if (zone->HasMap()) {
|
if (zone->HasMap()) {
|
||||||
|
if (flymode == GravityBehavior::Flying) {
|
||||||
if (flymode == GravityBehavior::Flying)
|
|
||||||
return new_z;
|
return new_z;
|
||||||
|
}
|
||||||
|
|
||||||
if (zone->HasWaterMap() && zone->watermap->InLiquid(glm::vec3(m_Position)))
|
if (zone->HasWaterMap() && zone->watermap->InLiquid(glm::vec3(m_Position))) {
|
||||||
return new_z;
|
return new_z;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
new_z = FindDestGroundZ(destination, (-GetZOffset() / 2));
|
||||||
* Any more than 5 in the offset makes NPC's hop/snap to ceiling in small corridors
|
|
||||||
*/
|
|
||||||
new_z = FindDestGroundZ(destination, z_find_offset);
|
|
||||||
if (new_z != BEST_Z_INVALID) {
|
if (new_z != BEST_Z_INVALID) {
|
||||||
new_z += GetZOffset();
|
new_z += GetZOffset();
|
||||||
|
|
||||||
@ -790,6 +788,20 @@ float Mob::GetFixedZ(const glm::vec3 &destination, int32 z_find_offset) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prevent ceiling clipping
|
||||||
|
// if client is close in distance (not counting Z) and we clipped up into a ceiling
|
||||||
|
// this helps us snap back down (or up) if it were to happen
|
||||||
|
// other fixes were put in place to prevent clipping into the ceiling to begin with
|
||||||
|
if (std::abs(new_z - m_Position.z) > 15) {
|
||||||
|
LogFixZ("TRIGGER clipping detection");
|
||||||
|
auto t = GetTarget();
|
||||||
|
if (t && DistanceNoZ(GetPosition(), t->GetPosition()) < 20) {
|
||||||
|
new_z = FindDestGroundZ(t->GetPosition(), -t->GetZOffset());
|
||||||
|
new_z += GetZOffset();
|
||||||
|
GMMove(t->GetPosition().x, t->GetPosition().y, new_z, t->GetPosition().w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto duration = timer.elapsed();
|
auto duration = timer.elapsed();
|
||||||
|
|
||||||
LogFixZ("[{}] returned [{}] at [{}] [{}] [{}] - Took [{}]",
|
LogFixZ("[{}] returned [{}] at [{}] [{}] [{}] - Took [{}]",
|
||||||
@ -833,6 +845,10 @@ void Mob::FixZ(int32 z_find_offset /*= 5*/, bool fix_client_z /*= false*/) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_Position.z = new_z;
|
m_Position.z = new_z;
|
||||||
|
|
||||||
|
if (RuleB(Map, MobPathingVisualDebug)) {
|
||||||
|
DrawDebugCoordinateNode(fmt::format("{} new fixed z node", GetCleanName()), GetPosition());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (RuleB(Map, MobZVisualDebug)) {
|
if (RuleB(Map, MobZVisualDebug)) {
|
||||||
@ -928,6 +944,7 @@ float Mob::GetZOffset() const {
|
|||||||
case RACE_RABBIT_668:
|
case RACE_RABBIT_668:
|
||||||
offset = 5.0f;
|
offset = 5.0f;
|
||||||
break;
|
break;
|
||||||
|
case RACE_WURM_158:
|
||||||
case RACE_BLIND_DREAMER_669:
|
case RACE_BLIND_DREAMER_669:
|
||||||
offset = 7.0f;
|
offset = 7.0f;
|
||||||
break;
|
break;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user