From 43da07fb55231eb520113a5745c36aab91e5d2bf Mon Sep 17 00:00:00 2001 From: hg <4683435+hgtw@users.noreply.github.com> Date: Tue, 28 Jan 2020 19:04:47 -0500 Subject: [PATCH 1/8] Fix zone crash when a group member raid invites own group leader --- zone/client_packet.cpp | 5 +++++ zone/string_ids.h | 1 + 2 files changed, 6 insertions(+) diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index ebc6bd38a..dfb7ab673 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -11130,6 +11130,11 @@ void Client::Handle_OP_RaidCommand(const EQApplicationPacket *app) break; } + if (player_to_invite_group && player_to_invite_group->IsGroupMember(this)) { + MessageString(Chat::Red, ALREADY_IN_PARTY); + break; + } + if (player_to_invite_group && !player_to_invite_group->IsLeader(player_to_invite)) { Message(Chat::Red, "You can only invite an ungrouped player or group leader to join your raid."); break; diff --git a/zone/string_ids.h b/zone/string_ids.h index 0948d13a8..25321b3c9 100644 --- a/zone/string_ids.h +++ b/zone/string_ids.h @@ -417,6 +417,7 @@ #define TARGET_PLAYER_FOR_GUILD_STATUS 12260 #define GROUP_INVITEE_NOT_FOUND 12268 //You must target a player or use /invite to invite someone to your group. #define GROUP_INVITEE_SELF 12270 //12270 You cannot invite yourself. +#define ALREADY_IN_PARTY 12272 //That person is already in your party. #define NO_LONGER_HIDDEN 12337 //You are no longer hidden. #define STOP_SNEAKING 12338 //You stop sneaking #define NOT_IN_CONTROL 12368 //You do not have control of yourself right now. From 50a39057e4bfd36141d69aa16539b60bdbfa1dca Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 1 Feb 2020 19:27:15 -0500 Subject: [PATCH 2/8] Update QuestReward_Struct --- common/eq_packet_structs.h | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/common/eq_packet_structs.h b/common/eq_packet_structs.h index 53d7021ba..3fe2430db 100644 --- a/common/eq_packet_structs.h +++ b/common/eq_packet_structs.h @@ -35,6 +35,7 @@ static const uint32 MAX_MERC = 100; static const uint32 MAX_MERC_GRADES = 10; static const uint32 MAX_MERC_STANCES = 10; static const uint32 BLOCKED_BUFF_COUNT = 20; +static const uint32 QUESTREWARD_COUNT = 8; /* @@ -2180,14 +2181,7 @@ struct QuestReward_Struct /*024*/ uint32 silver; // Gives silver to the client /*028*/ uint32 gold; // Gives gold to the client /*032*/ uint32 platinum; // Gives platinum to the client - /*036*/ uint32 item_id; - /*040*/ uint32 unknown040; - /*044*/ uint32 unknown044; - /*048*/ uint32 unknown048; - /*052*/ uint32 unknown052; - /*056*/ uint32 unknown056; - /*060*/ uint32 unknown060; - /*064*/ uint32 unknown064; + /*036*/ int32 item_id[QUESTREWARD_COUNT]; // -1 for nothing /*068*/ }; From b02e87cce72a9a413de3213aeaa91883e2ce26bc Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 1 Feb 2020 19:54:26 -0500 Subject: [PATCH 3/8] Fix Client::QuestReward for struct adjustment --- zone/client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/client.cpp b/zone/client.cpp index 9ea27869a..eb157dc2f 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -8539,7 +8539,7 @@ void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold, qr->silver = silver; qr->gold = gold; qr->platinum = platinum; - qr->item_id = itemid; + qr->item_id[0] = itemid; qr->exp_reward = exp; if (copper > 0 || silver > 0 || gold > 0 || platinum > 0) From ab3d65b2ea344fed0f6bf1fdcc5b92ce0ec2989c Mon Sep 17 00:00:00 2001 From: Paul Coene Date: Sat, 1 Feb 2020 20:29:48 -0500 Subject: [PATCH 4/8] Fix FixZ regarding the use of model in npc_types This fix only impacts those that use the model field in npc_types to override race on the client. GetModel() returns model if set, otherwise race. As a refresher, the model field is there so the server can still see a mob as its base race for things like bane, while the client can use a new model. FixZ needs to know about this. --- zone/waypoints.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zone/waypoints.cpp b/zone/waypoints.cpp index 0bd18edbf..65f4fd099 100644 --- a/zone/waypoints.cpp +++ b/zone/waypoints.cpp @@ -771,7 +771,7 @@ void Mob::FixZ(int32 z_find_offset /*= 5*/, bool fix_client_z /*= false*/) { float Mob::GetZOffset() const { float offset = 3.125f; - switch (race) { + switch (GetModel()) { case RACE_BASILISK_436: offset = 0.577f; break; From 59903313e4c46ff8b7cae6b8c7eb7b6d46a35f82 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sat, 1 Feb 2020 22:20:19 -0500 Subject: [PATCH 5/8] Expand Lua's Client QuestReward function You can now use it to summon up to 8 items ex: `e.other:QuestReward(e.self, {items = {28745, 28092}, exp = 250})` This expands the version that takes a table. The new item is a table (in the main table) called items, which needs to be auto keyed like the example above. If you also provide the old itemid key, it will be ignored if the items is there. --- zone/client.cpp | 36 ++++++++++++++++++++++++++++++ zone/client.h | 1 + zone/lua_client.cpp | 54 ++++++++++++++++++++++++++++++++++----------- 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index eb157dc2f..acbb7cc74 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -8566,6 +8566,42 @@ void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold, safe_delete(outapp); } +void Client::QuestReward(Mob* target, const QuestReward_Struct &reward, bool faction) +{ + auto outapp = new EQApplicationPacket(OP_Sound, sizeof(QuestReward_Struct)); + memset(outapp->pBuffer, 0, sizeof(QuestReward_Struct)); + QuestReward_Struct* qr = (QuestReward_Struct*)outapp->pBuffer; + + memcpy(qr, &reward, sizeof(QuestReward_Struct)); + + // not set in caller because reasons + qr->mob_id = target->GetID(); // Entity ID for the from mob name + + if (reward.copper > 0 || reward.silver > 0 || reward.gold > 0 || reward.platinum > 0) + AddMoneyToPP(reward.copper, reward.silver, reward.gold, reward.platinum, false); + + for (int i = 0; i < QUESTREWARD_COUNT; ++i) + if (reward.item_id[i] > 0) + SummonItem(reward.item_id[i], 0, 0, 0, 0, 0, 0, false, EQEmu::invslot::slotCursor); + + if (faction) + { + if (target->IsNPC()) + { + int32 nfl_id = target->CastToNPC()->GetNPCFactionID(); + SetFactionLevel(CharacterID(), nfl_id, GetBaseClass(), GetBaseRace(), GetDeity(), true); + qr->faction = target->CastToNPC()->GetPrimaryFaction(); + qr->faction_mod = 1; // Too lazy to get real value, not sure if this is even used by client anyhow. + } + } + + if (reward.exp_reward> 0) + AddEXP(reward.exp_reward); + + QueuePacket(outapp, true, Client::CLIENT_CONNECTED); + safe_delete(outapp); +} + void Client::SendHPUpdateMarquee(){ if (!this || !this->IsClient() || !this->current_hp || !this->max_hp) return; diff --git a/zone/client.h b/zone/client.h index 4ff431520..300073bb5 100644 --- a/zone/client.h +++ b/zone/client.h @@ -1282,6 +1282,7 @@ public: int32 GetMeleeDamage(Mob* other, bool GetMinDamage = false); void QuestReward(Mob* target, uint32 copper = 0, uint32 silver = 0, uint32 gold = 0, uint32 platinum = 0, uint32 itemid = 0, uint32 exp = 0, bool faction = false); + void QuestReward(Mob* target, const QuestReward_Struct &reward, bool faction); // TODO: Fix faction processing void ResetHPUpdateTimer() { hpupdate_timer.Start(); } diff --git a/zone/lua_client.cpp b/zone/lua_client.cpp index 14c009b12..9d0873360 100644 --- a/zone/lua_client.cpp +++ b/zone/lua_client.cpp @@ -1385,18 +1385,23 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { return; } - uint32 copper = 0; - uint32 silver = 0; - uint32 gold = 0; - uint32 platinum = 0; - uint32 itemid = 0; - uint32 exp = 0; + QuestReward_Struct quest_reward; + quest_reward.mob_id = 0; + quest_reward.target_id = self->GetID(); + quest_reward.copper = 0; + quest_reward.silver = 0; + quest_reward.gold = 0; + quest_reward.platinum = 0; + quest_reward.exp_reward = 0; + quest_reward.faction = 0; + quest_reward.faction_mod = 0; bool faction = false; + std::fill(std::begin(quest_reward.item_id), std::end(quest_reward.item_id), -1); auto cur = reward["copper"]; if (luabind::type(cur) != LUA_TNIL) { try { - copper = luabind::object_cast(cur); + quest_reward.copper = luabind::object_cast(cur); } catch (luabind::cast_failed &) { } } @@ -1404,7 +1409,7 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { cur = reward["silver"]; if (luabind::type(cur) != LUA_TNIL) { try { - silver = luabind::object_cast(cur); + quest_reward.silver = luabind::object_cast(cur); } catch (luabind::cast_failed &) { } } @@ -1412,7 +1417,7 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { cur = reward["gold"]; if (luabind::type(cur) != LUA_TNIL) { try { - gold = luabind::object_cast(cur); + quest_reward.gold = luabind::object_cast(cur); } catch (luabind::cast_failed &) { } } @@ -1420,7 +1425,7 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { cur = reward["platinum"]; if (luabind::type(cur) != LUA_TNIL) { try { - platinum = luabind::object_cast(cur); + quest_reward.platinum = luabind::object_cast(cur); } catch (luabind::cast_failed &) { } } @@ -1428,7 +1433,30 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { cur = reward["itemid"]; if (luabind::type(cur) != LUA_TNIL) { try { - itemid = luabind::object_cast(cur); + quest_reward.item_id[0] = luabind::object_cast(cur); + } catch (luabind::cast_failed &) { + } + } + + // if you define both an itemid and items table, the itemid is thrown away + // should we error? + cur = reward["items"]; + if (luabind::type(cur) == LUA_TTABLE) { + try { + // assume they defined a compatible table + for (int i = 1; i <= QUESTREWARD_COUNT; ++i) { + auto item = cur[i]; + int cur_value = -1; + if (luabind::type(item) != LUA_TNIL) { + try { + cur_value = luabind::object_cast(item); + } catch (luabind::cast_failed &) { + } + } else { + break; + } + quest_reward.item_id[i - 1] = cur_value; + } } catch (luabind::cast_failed &) { } } @@ -1436,7 +1464,7 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { cur = reward["exp"]; if (luabind::type(cur) != LUA_TNIL) { try { - exp = luabind::object_cast(cur); + quest_reward.exp_reward = luabind::object_cast(cur); } catch (luabind::cast_failed &) { } } @@ -1449,7 +1477,7 @@ void Lua_Client::QuestReward(Lua_Mob target, luabind::adl::object reward) { } } - self->QuestReward(target, copper, silver, gold, platinum, itemid, exp, faction); + self->QuestReward(target, quest_reward, faction); } bool Lua_Client::IsDead() { From c2300d514cecc32547679b4fdcebac5d26d3d662 Mon Sep 17 00:00:00 2001 From: KimLS Date: Sat, 1 Feb 2020 20:49:04 -0800 Subject: [PATCH 6/8] Packet warnings --- common/net/packet.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/net/packet.h b/common/net/packet.h index 1ce173a10..4ff5f8510 100644 --- a/common/net/packet.h +++ b/common/net/packet.h @@ -89,9 +89,9 @@ namespace EQ { public: StaticPacket(void *data, size_t size) { m_data = data; m_data_length = size; m_max_data_length = size; } virtual ~StaticPacket() { } - StaticPacket(const StaticPacket &o) { m_data = o.m_data; m_data_length = o.m_data_length; } + StaticPacket(const StaticPacket &o) { m_data = o.m_data; m_data_length = o.m_data_length; m_max_data_length = o.m_max_data_length; } StaticPacket& operator=(const StaticPacket &o) { m_data = o.m_data; m_data_length = o.m_data_length; return *this; } - StaticPacket(StaticPacket &&o) { m_data = o.m_data; m_data_length = o.m_data_length; } + StaticPacket(StaticPacket &&o) noexcept { m_data = o.m_data; m_data_length = o.m_data_length; } virtual const void *Data() const { return m_data; } virtual void *Data() { return m_data; } @@ -112,7 +112,7 @@ namespace EQ { public: DynamicPacket() { } virtual ~DynamicPacket() { } - DynamicPacket(DynamicPacket &&o) { m_data = std::move(o.m_data); } + DynamicPacket(DynamicPacket &&o) noexcept { m_data = std::move(o.m_data); } DynamicPacket(const DynamicPacket &o) { m_data = o.m_data; } DynamicPacket& operator=(const DynamicPacket &o) { m_data = o.m_data; return *this; } @@ -127,4 +127,4 @@ namespace EQ { std::vector m_data; }; } -} \ No newline at end of file +} From 424b669cbbe574764d121d65f97722e01a92c906 Mon Sep 17 00:00:00 2001 From: "Michael Cook (mackal)" Date: Sun, 2 Feb 2020 16:39:46 -0500 Subject: [PATCH 7/8] Target not required for newer clients in QuestReward --- zone/client.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zone/client.cpp b/zone/client.cpp index acbb7cc74..6b366afba 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -8533,7 +8533,7 @@ void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold, memset(outapp->pBuffer, 0, sizeof(QuestReward_Struct)); QuestReward_Struct* qr = (QuestReward_Struct*)outapp->pBuffer; - qr->mob_id = target->GetID(); // Entity ID for the from mob name + qr->mob_id = target ? target->GetID() : 0; // Entity ID for the from mob name qr->target_id = GetID(); // The Client ID (this) qr->copper = copper; qr->silver = silver; @@ -8550,7 +8550,7 @@ void Client::QuestReward(Mob* target, uint32 copper, uint32 silver, uint32 gold, if (faction) { - if (target->IsNPC()) + if (target && target->IsNPC()) { int32 nfl_id = target->CastToNPC()->GetNPCFactionID(); SetFactionLevel(CharacterID(), nfl_id, GetBaseClass(), GetBaseRace(), GetDeity(), true); @@ -8575,7 +8575,7 @@ void Client::QuestReward(Mob* target, const QuestReward_Struct &reward, bool fac memcpy(qr, &reward, sizeof(QuestReward_Struct)); // not set in caller because reasons - qr->mob_id = target->GetID(); // Entity ID for the from mob name + qr->mob_id = target ? target->GetID() : 0; // Entity ID for the from mob name if (reward.copper > 0 || reward.silver > 0 || reward.gold > 0 || reward.platinum > 0) AddMoneyToPP(reward.copper, reward.silver, reward.gold, reward.platinum, false); @@ -8586,7 +8586,7 @@ void Client::QuestReward(Mob* target, const QuestReward_Struct &reward, bool fac if (faction) { - if (target->IsNPC()) + if (target && target->IsNPC()) { int32 nfl_id = target->CastToNPC()->GetNPCFactionID(); SetFactionLevel(CharacterID(), nfl_id, GetBaseClass(), GetBaseRace(), GetDeity(), true); From d65a97e556a39e4edb0f4734773311961b3c754c Mon Sep 17 00:00:00 2001 From: KimLS Date: Sun, 2 Feb 2020 20:19:37 -0800 Subject: [PATCH 8/8] Rule for setting max navmesh nodes, default set higher than current to improve accuracy --- common/ruletypes.h | 1 + zone/mob_movement_manager.cpp | 9 +-- zone/pathfinder_nav_mesh.cpp | 109 ++++++++++++++++------------------ 3 files changed, 57 insertions(+), 62 deletions(-) diff --git a/common/ruletypes.h b/common/ruletypes.h index c6e99e5f4..8acbb2c14 100644 --- a/common/ruletypes.h +++ b/common/ruletypes.h @@ -293,6 +293,7 @@ RULE_BOOL(Pathing, Find, true, "Enable pathing for FindPerson requests from the RULE_BOOL(Pathing, Fear, true, "Enable pathing for fear") RULE_REAL(Pathing, NavmeshStepSize, 100.0f, "") RULE_REAL(Pathing, ShortMovementUpdateRange, 130.0f, "") +RULE_INT(Pathing, MaxNavmeshNodes, 4092) RULE_CATEGORY_END() RULE_CATEGORY(Watermap) diff --git a/zone/mob_movement_manager.cpp b/zone/mob_movement_manager.cpp index 5e40dfeee..4ac0c7f23 100644 --- a/zone/mob_movement_manager.cpp +++ b/zone/mob_movement_manager.cpp @@ -1300,7 +1300,9 @@ void MobMovementManager::PushEvadeCombat(MobMovementEntry &mob_movement_entry) */ void MobMovementManager::HandleStuckBehavior(Mob *who, float x, float y, float z, MobMovementMode mob_movement_mode) { - auto sb = who->GetStuckBehavior(); + LogDebug("Handle stuck behavior for {0} at ({1}, {2}, {3}) with movement_mode {4}", who->GetName(), x, y, z, mob_movement_mode); + + auto sb = who->GetStuckBehavior(); MobStuckBehavior behavior = RunToTarget; if (sb >= 0 && sb < MaxStuckBehavior) { @@ -1308,7 +1310,7 @@ void MobMovementManager::HandleStuckBehavior(Mob *who, float x, float y, float z } auto eiter = _impl->Entries.find(who); - auto &ent = (*eiter); + auto &ent = (*eiter); switch (sb) { case RunToTarget: @@ -1323,8 +1325,7 @@ void MobMovementManager::HandleStuckBehavior(Mob *who, float x, float y, float z PushStopMoving(ent.second); break; case EvadeCombat: - //PushEvadeCombat(ent.second); - PushStopMoving(ent.second); + PushEvadeCombat(ent.second); break; } } diff --git a/zone/pathfinder_nav_mesh.cpp b/zone/pathfinder_nav_mesh.cpp index 5be10b64f..63e76f486 100644 --- a/zone/pathfinder_nav_mesh.cpp +++ b/zone/pathfinder_nav_mesh.cpp @@ -12,8 +12,6 @@ extern Zone *zone; -const int MaxNavmeshNodes = 1024; - struct PathfinderNavmesh::Implementation { dtNavMesh *nav_mesh; @@ -36,19 +34,19 @@ PathfinderNavmesh::~PathfinderNavmesh() IPathfinder::IPath PathfinderNavmesh::FindRoute(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, int flags) { partial = false; - + if (!m_impl->nav_mesh) { return IPath(); } - + if (!m_impl->query) { m_impl->query = dtAllocNavMeshQuery(); } - - m_impl->query->init(m_impl->nav_mesh, MaxNavmeshNodes); + + m_impl->query->init(m_impl->nav_mesh, RuleI(Pathing, MaxNavmeshNodes)); glm::vec3 current_location(start.x, start.z, start.y); glm::vec3 dest_location(end.x, end.z, end.y); - + dtQueryFilter filter; filter.setIncludeFlags(flags); filter.setAreaCost(0, 1.0f); //Normal @@ -61,48 +59,48 @@ IPathfinder::IPath PathfinderNavmesh::FindRoute(const glm::vec3 &start, const gl filter.setAreaCost(8, 1.0f); //General Area filter.setAreaCost(9, 0.1f); //Portal filter.setAreaCost(10, 0.1f); //Prefer - + dtPolyRef start_ref; dtPolyRef end_ref; glm::vec3 ext(5.0f, 100.0f, 5.0f); - + m_impl->query->findNearestPoly(¤t_location[0], &ext[0], &filter, &start_ref, 0); m_impl->query->findNearestPoly(&dest_location[0], &ext[0], &filter, &end_ref, 0); - + if (!start_ref || !end_ref) { return IPath(); } - + int npoly = 0; dtPolyRef path[1024] = { 0 }; auto status = m_impl->query->findPath(start_ref, end_ref, ¤t_location[0], &dest_location[0], &filter, path, &npoly, 1024); - + if (npoly) { glm::vec3 epos = dest_location; if (path[npoly - 1] != end_ref) { m_impl->query->closestPointOnPoly(path[npoly - 1], &dest_location[0], &epos[0], 0); partial = true; - + auto dist = DistanceSquared(epos, current_location); if (dist < 10000.0f) { stuck = true; } } - + float straight_path[2048 * 3]; unsigned char straight_path_flags[2048]; - + int n_straight_polys; dtPolyRef straight_path_polys[2048]; - + status = m_impl->query->findStraightPath(¤t_location[0], &epos[0], path, npoly, straight_path, straight_path_flags, straight_path_polys, &n_straight_polys, 2048, DT_STRAIGHTPATH_AREA_CROSSINGS); - + if (dtStatusFailed(status)) { return IPath(); } - + if (n_straight_polys) { IPath Route; for (int i = 0; i < n_straight_polys; ++i) @@ -111,9 +109,9 @@ IPathfinder::IPath PathfinderNavmesh::FindRoute(const glm::vec3 &start, const gl node.x = straight_path[i * 3]; node.z = straight_path[i * 3 + 1]; node.y = straight_path[i * 3 + 2]; - + Route.push_back(node); - + unsigned short flag = 0; if (dtStatusSucceed(m_impl->nav_mesh->getPolyFlags(straight_path_polys[i], &flag))) { if (flag & 512) { @@ -121,11 +119,11 @@ IPathfinder::IPath PathfinderNavmesh::FindRoute(const glm::vec3 &start, const gl } } } - + return Route; } } - + IPath Route; Route.push_back(end); return Route; @@ -134,19 +132,19 @@ IPathfinder::IPath PathfinderNavmesh::FindRoute(const glm::vec3 &start, const gl IPathfinder::IPath PathfinderNavmesh::FindPath(const glm::vec3 &start, const glm::vec3 &end, bool &partial, bool &stuck, const PathfinderOptions &opts) { partial = false; - + if (!m_impl->nav_mesh) { return IPath(); } - + if (!m_impl->query) { m_impl->query = dtAllocNavMeshQuery(); } - - m_impl->query->init(m_impl->nav_mesh, MaxNavmeshNodes); + + m_impl->query->init(m_impl->nav_mesh, RuleI(Pathing, MaxNavmeshNodes)); glm::vec3 current_location(start.x, start.z, start.y); glm::vec3 dest_location(end.x, end.z, end.y); - + dtQueryFilter filter; filter.setIncludeFlags(opts.flags); filter.setAreaCost(0, opts.flag_cost[0]); //Normal @@ -159,83 +157,78 @@ IPathfinder::IPath PathfinderNavmesh::FindPath(const glm::vec3 &start, const glm filter.setAreaCost(8, opts.flag_cost[7]); //General Area filter.setAreaCost(9, opts.flag_cost[8]); //Portal filter.setAreaCost(10, opts.flag_cost[9]); //Prefer - + static const int max_polys = 256; dtPolyRef start_ref; dtPolyRef end_ref; glm::vec3 ext(10.0f, 200.0f, 10.0f); - + m_impl->query->findNearestPoly(¤t_location[0], &ext[0], &filter, &start_ref, 0); m_impl->query->findNearestPoly(&dest_location[0], &ext[0], &filter, &end_ref, 0); - + if (!start_ref || !end_ref) { return IPath(); } - + int npoly = 0; dtPolyRef path[max_polys] = { 0 }; - m_impl->query->findPath(start_ref, end_ref, ¤t_location[0], &dest_location[0], &filter, path, &npoly, max_polys); - + auto status = m_impl->query->findPath(start_ref, end_ref, ¤t_location[0], &dest_location[0], &filter, path, &npoly, max_polys); + if (npoly) { glm::vec3 epos = dest_location; if (path[npoly - 1] != end_ref) { m_impl->query->closestPointOnPoly(path[npoly - 1], &dest_location[0], &epos[0], 0); partial = true; - - auto dist = DistanceSquared(epos, current_location); - if (dist < 10000.0f) { - stuck = true; - } } - + int n_straight_polys; glm::vec3 straight_path[max_polys]; unsigned char straight_path_flags[max_polys]; dtPolyRef straight_path_polys[max_polys]; - + auto status = m_impl->query->findStraightPath(¤t_location[0], &epos[0], path, npoly, (float*)&straight_path[0], straight_path_flags, straight_path_polys, &n_straight_polys, 2048, DT_STRAIGHTPATH_AREA_CROSSINGS | DT_STRAIGHTPATH_ALL_CROSSINGS); - + if (dtStatusFailed(status)) { return IPath(); } - + if (n_straight_polys) { if (opts.smooth_path) { IPath Route; - + //Add the first point { auto &flag = straight_path_flags[0]; if (flag & DT_STRAIGHTPATH_OFFMESH_CONNECTION) { auto &p = straight_path[0]; - + Route.push_back(glm::vec3(p.x, p.z, p.y)); } else { auto &p = straight_path[0]; - + float h = 0.0f; if (dtStatusSucceed(GetPolyHeightOnPath(path, npoly, p, &h))) { p.y = h + opts.offset; } - + Route.push_back(glm::vec3(p.x, p.z, p.y)); } } - + for (int i = 0; i < n_straight_polys - 1; ++i) { auto &flag = straight_path_flags[i]; - + if (flag & DT_STRAIGHTPATH_OFFMESH_CONNECTION) { auto &poly = straight_path_polys[i]; - + auto &p2 = straight_path[i + 1]; glm::vec3 node(p2.x, p2.z, p2.y); Route.push_back(node); - + unsigned short pflag = 0; if (dtStatusSucceed(m_impl->nav_mesh->getPolyFlags(straight_path_polys[i], &pflag))) { if (pflag & 512) { @@ -250,12 +243,12 @@ IPathfinder::IPath PathfinderNavmesh::FindPath(const glm::vec3 &start, const glm auto dir = glm::normalize(p2 - p1); float total = 0.0f; glm::vec3 previous_pt = p1; - + while (total < dist) { glm::vec3 current_pt; float dist_to_move = opts.step_size; float ff = opts.step_size / 2.0f; - + if (total + dist_to_move + ff >= dist) { current_pt = p2; total = dist; @@ -264,18 +257,18 @@ IPathfinder::IPath PathfinderNavmesh::FindPath(const glm::vec3 &start, const glm total += dist_to_move; current_pt = p1 + dir * total; } - + float h = 0.0f; if (dtStatusSucceed(GetPolyHeightOnPath(path, npoly, current_pt, &h))) { current_pt.y = h + opts.offset; } - + Route.push_back(glm::vec3(current_pt.x, current_pt.z, current_pt.y)); previous_pt = current_pt; } } } - + return Route; } else { @@ -285,7 +278,7 @@ IPathfinder::IPath PathfinderNavmesh::FindPath(const glm::vec3 &start, const glm auto ¤t = straight_path[i]; glm::vec3 node(current.x, current.z, current.y); Route.push_back(node); - + unsigned short flag = 0; if (dtStatusSucceed(m_impl->nav_mesh->getPolyFlags(straight_path_polys[i], &flag))) { if (flag & 512) { @@ -293,7 +286,7 @@ IPathfinder::IPath PathfinderNavmesh::FindPath(const glm::vec3 &start, const glm } } } - + return Route; } } @@ -313,7 +306,7 @@ glm::vec3 PathfinderNavmesh::GetRandomLocation(const glm::vec3 &start) if (!m_impl->query) { m_impl->query = dtAllocNavMeshQuery(); - m_impl->query->init(m_impl->nav_mesh, MaxNavmeshNodes); + m_impl->query->init(m_impl->nav_mesh, RuleI(Pathing, MaxNavmeshNodes)); } dtQueryFilter filter;