mob_movement_manager.cpp 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180
  1. #include "mob_movement_manager.h"
  2. #include "../Entity.h"
  3. #include "../zoneserver.h"
  4. #include "water_map.h"
  5. #include "map.h"
  6. #include "../../common/timer.h"
  7. #include "pathfinder_interface.h"
  8. #include "position.h"
  9. #include "../../common/Log.h"
  10. #include <vector>
  11. #include <deque>
  12. #include <map>
  13. #include <stdlib.h>
  14. #ifdef WIN32
  15. #include <windows.h>
  16. #endif
  17. extern double frame_time;
  18. class IMovementCommand {
  19. public:
  20. IMovementCommand() = default;
  21. virtual ~IMovementCommand() = default;
  22. virtual bool Process(MobMovementManager* mob_movement_manager, Entity* mob) = 0;
  23. virtual bool Started() const = 0;
  24. };
  25. class RotateToCommand : public IMovementCommand {
  26. public:
  27. RotateToCommand(double rotate_to, double dir, MobMovementMode mob_movement_mode)
  28. {
  29. m_rotate_to = rotate_to;
  30. m_rotate_to_dir = dir;
  31. m_rotate_to_mode = mob_movement_mode;
  32. m_started = false;
  33. }
  34. virtual ~RotateToCommand()
  35. {
  36. }
  37. virtual bool Process(MobMovementManager* mob_movement_manager, Entity* mob)
  38. {
  39. auto rotate_to_speed = m_rotate_to_mode == MovementRunning ? 200.0 : 16.0; //todo: get this from mob
  40. auto from = mob_movement_manager->FixHeading(mob->GetHeading());
  41. auto to = mob_movement_manager->FixHeading(m_rotate_to);
  42. auto diff = to - from;
  43. while (diff < -256.0) {
  44. diff += 512.0;
  45. }
  46. while (diff > 256) {
  47. diff -= 512.0;
  48. }
  49. auto dist = std::abs(diff);
  50. if (!m_started) {
  51. m_started = true;
  52. //mob->SetMoving(true);
  53. /*if (dist > 15.0f && rotate_to_speed > 0.0 && rotate_to_speed <= 25.0) { //send basic rotation
  54. mob_movement_manager->SendCommandToClients(
  55. mob,
  56. 0.0,
  57. 0.0,
  58. 0.0,
  59. m_rotate_to_dir * rotate_to_speed,
  60. 0,
  61. ClientRangeClose
  62. );
  63. }*/
  64. }
  65. auto td = rotate_to_speed * 19.0 * frame_time;
  66. if (td >= dist) {
  67. mob->SetHeading(to);
  68. //mob->SetMoving(false);
  69. //mob_movement_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeCloseMedium);
  70. return true;
  71. }
  72. from += td * m_rotate_to_dir;
  73. mob->SetHeading(mob_movement_manager->FixHeading(from));
  74. return false;
  75. }
  76. virtual bool Started() const
  77. {
  78. return m_started;
  79. }
  80. private:
  81. double m_rotate_to;
  82. double m_rotate_to_dir;
  83. MobMovementMode m_rotate_to_mode;
  84. bool m_started;
  85. };
  86. class MoveToCommand : public IMovementCommand {
  87. public:
  88. MoveToCommand(float x, float y, float z, MobMovementMode mob_movement_mode)
  89. {
  90. m_distance_moved_since_correction = 0.0;
  91. m_move_to_x = x;
  92. m_move_to_y = y;
  93. m_move_to_z = z;
  94. m_move_to_mode = mob_movement_mode;
  95. m_last_sent_time = 0.0;
  96. m_last_sent_speed = 0;
  97. m_started = false;
  98. m_total_h_dist = 0.0;
  99. m_total_v_dist = 0.0;
  100. }
  101. virtual ~MoveToCommand()
  102. {
  103. }
  104. /**
  105. * @param mob_movement_manager
  106. * @param mob
  107. * @return
  108. */
  109. virtual bool Process(MobMovementManager* mob_movement_manager, Entity* mob)
  110. {
  111. //Send a movement packet when you start moving
  112. double current_time = static_cast<double>(Timer::GetCurrentTime2()) / 1000.0;
  113. int current_speed = 0;
  114. if (m_move_to_mode == MovementRunning) {
  115. if (mob->IsFeared()) {
  116. current_speed = mob->GetBaseSpeed();
  117. }
  118. else {
  119. current_speed = mob->GetMaxSpeed();
  120. }
  121. }
  122. else {
  123. current_speed = mob->GetBaseSpeed();
  124. }
  125. if (!m_started) {
  126. m_started = true;
  127. //rotate to the point
  128. //mob->SetMoving(true);
  129. mob->SetHeading(mob->GetFaceTarget(m_move_to_x, m_move_to_z));
  130. m_last_sent_speed = current_speed;
  131. m_last_sent_time = current_time;
  132. // Z/Y are flipped due to EverQuest 2 using Y as up/down
  133. m_total_h_dist = DistanceNoZ(glm::vec4(mob->GetX(),mob->GetZ(),mob->GetY(),mob->GetHeading()), glm::vec4(m_move_to_x, m_move_to_z, 0.0f, 0.0f));
  134. m_total_v_dist = m_move_to_y - mob->GetY();
  135. //mob_movement_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
  136. }
  137. //When speed changes
  138. if (current_speed != m_last_sent_speed) {
  139. //if (RuleB(Map, FixZWhenPathing)) {
  140. // mob->FixZ();
  141. //}
  142. m_distance_moved_since_correction = 0.0;
  143. m_last_sent_speed = current_speed;
  144. m_last_sent_time = current_time;
  145. //mob_movement_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
  146. }
  147. //If x seconds have passed without sending an update.
  148. if (current_time - m_last_sent_time >= 5.0) {
  149. //if (RuleB(Map, FixZWhenPathing)) {
  150. //mob->FixZ();
  151. //}
  152. m_distance_moved_since_correction = 0.0;
  153. m_last_sent_speed = current_speed;
  154. m_last_sent_time = current_time;
  155. //mob_movemesnt_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
  156. }
  157. auto& p = glm::vec3(mob->GetX(), mob->GetY(), mob->GetZ());
  158. // our X/Z versus the mobs X/Z
  159. glm::vec2 tar(m_move_to_x, m_move_to_z);
  160. glm::vec2 pos(p.x, p.z);
  161. double len = glm::distance(pos, tar);
  162. if (len < .01) {
  163. return true;
  164. }
  165. //mob->SetMoved(true);
  166. glm::vec2 dir = tar - pos;
  167. glm::vec2 ndir = glm::normalize(dir);
  168. double distance_moved = frame_time * current_speed * 0.4f * 1.45f;
  169. //mob->SetX(m_move_to_x);
  170. //mob->SetY(m_move_to_z);
  171. //mob->SetZ(m_move_to_y);
  172. mob->ClearRunningLocations();
  173. if (distance_moved > len) {
  174. //if (RuleB(Map, FixZWhenPathing)) {
  175. //mob->FixZ();
  176. //}
  177. // we use npos.y because higher up that is the equilvaent Z
  178. mob->AddRunningLocation(m_move_to_x, m_move_to_y, m_move_to_z, current_speed, distance_moved, true, true, "", true);
  179. return false;
  180. }
  181. else {
  182. glm::vec2 npos = pos + (ndir * static_cast<float>(distance_moved));
  183. len -= distance_moved;
  184. double total_distance_traveled = m_total_h_dist - len;
  185. double start_y = m_move_to_y - m_total_v_dist;
  186. double y_at_pos = start_y + (m_total_v_dist * (total_distance_traveled / m_total_h_dist));
  187. // we use npos.y because higher up that is the equilvaent Z
  188. mob->AddRunningLocation(m_move_to_x, m_move_to_y, m_move_to_z, current_speed, distance_moved, true, true, "", true);
  189. // mob->SetX(npos.x);
  190. // mob->SetY(z_at_pos);
  191. // mob->SetZ(npos.y);
  192. //if (RuleB(Map, FixZWhenPathing)) {
  193. // m_distance_moved_since_correction += distance_moved;
  194. // if (m_distance_moved_since_correction > 10.0f /*RuleR(Map, DistanceCanTravelBeforeAdjustment)*/) {
  195. // m_distance_moved_since_correction = 0.0;
  196. //mob->FixZ();
  197. //}
  198. // }
  199. }
  200. return false;
  201. }
  202. virtual bool Started() const
  203. {
  204. return m_started;
  205. }
  206. protected:
  207. double m_distance_moved_since_correction;
  208. double m_move_to_x;
  209. double m_move_to_y;
  210. double m_move_to_z;
  211. MobMovementMode m_move_to_mode;
  212. bool m_started;
  213. double m_last_sent_time;
  214. int m_last_sent_speed;
  215. double m_total_h_dist;
  216. double m_total_v_dist;
  217. };
  218. class SwimToCommand : public MoveToCommand {
  219. public:
  220. SwimToCommand(float x, float y, float z, MobMovementMode mob_movement_mode) : MoveToCommand(x, y, z, mob_movement_mode)
  221. {
  222. }
  223. virtual bool Process(MobMovementManager* mob_movement_manager, Entity* mob)
  224. {
  225. //Send a movement packet when you start moving
  226. double current_time = static_cast<double>(Timer::GetCurrentTime2()) / 1000.0;
  227. int current_speed = 0;
  228. if (m_move_to_mode == MovementRunning) {
  229. if (mob->IsFeared()) {
  230. current_speed = mob->GetBaseSpeed();
  231. }
  232. else {
  233. current_speed = mob->GetMaxSpeed();
  234. }
  235. }
  236. else {
  237. current_speed = mob->GetBaseSpeed();
  238. }
  239. if (!m_started) {
  240. m_started = true;
  241. //rotate to the point
  242. //mob->SetMoving(true);
  243. mob->SetHeading(mob->GetFaceTarget(m_move_to_x, m_move_to_z));
  244. m_last_sent_speed = current_speed;
  245. m_last_sent_time = current_time;
  246. m_total_h_dist = DistanceNoZ(glm::vec4(mob->GetX(),mob->GetZ(),mob->GetY(),mob->GetHeading()), glm::vec4(m_move_to_x, m_move_to_z, 0.0f, 0.0f));
  247. m_total_v_dist = m_move_to_y - mob->GetY();
  248. //mob_movement_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
  249. }
  250. //When speed changes
  251. if (current_speed != m_last_sent_speed) {
  252. m_last_sent_speed = current_speed;
  253. m_last_sent_time = current_time;
  254. //mob_movement_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
  255. }
  256. //If x seconds have passed without sending an update.
  257. if (current_time - m_last_sent_time >= 1.5) {
  258. m_last_sent_speed = current_speed;
  259. m_last_sent_time = current_time;
  260. //mob_movement_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, current_speed, ClientRangeCloseMedium);
  261. }
  262. auto& p = glm::vec4(mob->GetX(), mob->GetZ(), mob->GetY(), mob->GetHeading());
  263. glm::vec2 tar(m_move_to_x, m_move_to_y);
  264. glm::vec2 pos(p.x, p.y);
  265. double len = glm::distance(pos, tar);
  266. if (len == 0) {
  267. return true;
  268. }
  269. //mob->SetMoved(true);
  270. glm::vec2 dir = tar - pos;
  271. glm::vec2 ndir = glm::normalize(dir);
  272. double distance_moved = frame_time * current_speed * 0.4f * 1.45f;
  273. mob->SetX(m_move_to_x);
  274. mob->SetZ(m_move_to_z);
  275. mob->SetY(m_move_to_y);
  276. if (distance_moved > len) {
  277. return true;
  278. }
  279. else {
  280. glm::vec2 npos = pos + (ndir * static_cast<float>(distance_moved));
  281. len -= distance_moved;
  282. double total_distance_traveled = m_total_h_dist - len;
  283. double start_y = m_move_to_y - m_total_v_dist;
  284. double y_at_pos = start_y + (m_total_v_dist * (total_distance_traveled / m_total_h_dist));
  285. mob->SetX(npos.x);
  286. mob->SetZ(npos.y);
  287. mob->SetY(y_at_pos);
  288. }
  289. return false;
  290. }
  291. };
  292. class TeleportToCommand : public IMovementCommand {
  293. public:
  294. TeleportToCommand(float x, float y, float z, float heading)
  295. {
  296. m_teleport_to_x = x;
  297. m_teleport_to_y = y;
  298. m_teleport_to_z = z;
  299. m_teleport_to_heading = heading;
  300. }
  301. virtual ~TeleportToCommand()
  302. {
  303. }
  304. virtual bool Process(MobMovementManager* mob_movement_manager, Entity* mob)
  305. {
  306. mob->SetX(m_teleport_to_x);
  307. mob->SetZ(m_teleport_to_z);
  308. mob->SetY(m_teleport_to_y);
  309. mob->SetHeading(mob_movement_manager->FixHeading(m_teleport_to_heading));
  310. //mob_movement_manager->SendCommandToClients(mob, 0.0, 0.0, 0.0, 0.0, 0, ClientRangeAny);
  311. return true;
  312. }
  313. virtual bool Started() const
  314. {
  315. return false;
  316. }
  317. private:
  318. double m_teleport_to_x;
  319. double m_teleport_to_y;
  320. double m_teleport_to_z;
  321. double m_teleport_to_heading;
  322. };
  323. class StopMovingCommand : public IMovementCommand {
  324. public:
  325. StopMovingCommand()
  326. {
  327. }
  328. virtual ~StopMovingCommand()
  329. {
  330. }
  331. virtual bool Process(MobMovementManager* mob_movement_manager, Entity* mob)
  332. {
  333. mob->ClearRunningLocations();
  334. return true;
  335. }
  336. virtual bool Started() const
  337. {
  338. return false;
  339. }
  340. };
  341. class EvadeCombatCommand : public IMovementCommand {
  342. public:
  343. EvadeCombatCommand()
  344. {
  345. }
  346. virtual ~EvadeCombatCommand()
  347. {
  348. }
  349. virtual bool Process(MobMovementManager* mob_movement_manager, Entity* mob)
  350. {
  351. if (mob->IsRunning()) {
  352. mob->StopMoving();
  353. }
  354. return true;
  355. }
  356. virtual bool Started() const
  357. {
  358. return false;
  359. }
  360. };
  361. struct MovementStats {
  362. MovementStats()
  363. {
  364. LastResetTime = static_cast<double>(Timer::GetCurrentTime2()) / 1000.0;
  365. TotalSent = 0ULL;
  366. TotalSentMovement = 0ULL;
  367. TotalSentPosition = 0ULL;
  368. TotalSentHeading = 0ULL;
  369. }
  370. double LastResetTime;
  371. uint64_t TotalSent;
  372. uint64_t TotalSentMovement;
  373. uint64_t TotalSentPosition;
  374. uint64_t TotalSentHeading;
  375. };
  376. struct NavigateTo {
  377. NavigateTo()
  378. {
  379. navigate_to_x = 0.0;
  380. navigate_to_y = 0.0;
  381. navigate_to_z = 0.0;
  382. navigate_to_heading = 0.0;
  383. last_set_time = 0.0;
  384. }
  385. double navigate_to_x;
  386. double navigate_to_y;
  387. double navigate_to_z;
  388. double navigate_to_heading;
  389. double last_set_time;
  390. };
  391. struct MobMovementEntry {
  392. std::deque<std::unique_ptr<IMovementCommand>> Commands;
  393. NavigateTo NavTo;
  394. };
  395. void AdjustRoute(std::list<IPathfinder::IPathNode> &nodes, Entity *who)
  396. {
  397. if (who->GetZone() == nullptr || !who->GetZone()->zonemap /*|| !zone->HasWaterMap()*/) {
  398. return;
  399. }
  400. auto offset = who->GetYOffset();
  401. for (auto &node : nodes) {
  402. //if (!zone->watermap->InLiquid(node.pos)) {
  403. auto best_z = who->GetZone()->zonemap->FindBestZ(node.pos, nullptr);
  404. if (best_z != BEST_Z_INVALID) {
  405. node.pos.z = best_z + offset;
  406. }
  407. //} // todo: floating logic?
  408. }
  409. }
  410. struct MobMovementManager::Implementation {
  411. std::map<Entity *, MobMovementEntry> Entries;
  412. std::vector<Client *> Clients;
  413. MovementStats Stats;
  414. };
  415. MobMovementManager::MobMovementManager()
  416. {
  417. MobListMutex.SetName("MobMovementManager");
  418. _impl.reset(new Implementation());
  419. }
  420. MobMovementManager::~MobMovementManager()
  421. {
  422. }
  423. void MobMovementManager::Process()
  424. {
  425. MobListMutex.readlock();
  426. for (auto &iter : _impl->Entries) {
  427. auto &ent = iter.second;
  428. auto &commands = ent.Commands;
  429. while (true != commands.empty()) {
  430. auto &cmd = commands.front();
  431. auto r = cmd->Process(this, iter.first);
  432. if (true != r) {
  433. break;
  434. }
  435. commands.pop_front();
  436. }
  437. }
  438. MobListMutex.releasereadlock();
  439. }
  440. /**
  441. * @param mob
  442. */
  443. void MobMovementManager::AddMob(Entity *mob)
  444. {
  445. MobListMutex.writelock();
  446. _impl->Entries.insert(std::make_pair(mob, MobMovementEntry()));
  447. MobListMutex.releasewritelock();
  448. }
  449. /**
  450. * @param mob
  451. */
  452. void MobMovementManager::RemoveMob(Entity *mob)
  453. {
  454. MobListMutex.writelock();
  455. _impl->Entries.erase(mob);
  456. MobListMutex.releasewritelock();
  457. }
  458. /**
  459. * @param client
  460. */
  461. void MobMovementManager::AddClient(Client *client)
  462. {
  463. _impl->Clients.push_back(client);
  464. }
  465. /**
  466. * @param client
  467. */
  468. void MobMovementManager::RemoveClient(Client *client)
  469. {
  470. auto iter = _impl->Clients.begin();
  471. while (iter != _impl->Clients.end()) {
  472. if (client == *iter) {
  473. _impl->Clients.erase(iter);
  474. return;
  475. }
  476. ++iter;
  477. }
  478. }
  479. /**
  480. * @param who
  481. * @param to
  482. * @param mob_movement_mode
  483. */
  484. void MobMovementManager::RotateTo(Entity *who, float to, MobMovementMode mob_movement_mode)
  485. {
  486. MobListMutex.readlock();
  487. auto iter = _impl->Entries.find(who);
  488. auto &ent = (*iter);
  489. if (true != ent.second.Commands.empty()) {
  490. return;
  491. }
  492. PushRotateTo(ent.second, who, to, mob_movement_mode);
  493. MobListMutex.releasereadlock();
  494. }
  495. /**
  496. * @param who
  497. * @param x
  498. * @param y
  499. * @param z
  500. * @param heading
  501. */
  502. void MobMovementManager::Teleport(Entity *who, float x, float y, float z, float heading)
  503. {
  504. MobListMutex.readlock();
  505. auto iter = _impl->Entries.find(who);
  506. auto &ent = (*iter);
  507. ent.second.Commands.clear();
  508. PushTeleportTo(ent.second, x, y, z, heading);
  509. MobListMutex.releasereadlock();
  510. }
  511. /**
  512. * @param who
  513. * @param x
  514. * @param y
  515. * @param z
  516. * @param mode
  517. */
  518. void MobMovementManager::NavigateTo(Entity *who, float x, float y, float z, MobMovementMode mode, bool overrideDistance)
  519. {
  520. if (who->IsRunning())
  521. return;
  522. glm::vec3 targPos(x, z, y);
  523. glm::vec3 origPos(who->GetX(), who->GetZ(), who->GetY());
  524. if (IsPositionEqualWithinCertainZ(targPos, origPos, 6.0f)) {
  525. return;
  526. }
  527. MobListMutex.readlock();
  528. auto iter = _impl->Entries.find(who);
  529. auto &ent = (*iter);
  530. auto &nav = ent.second.NavTo;
  531. double current_time = static_cast<double>(Timer::GetCurrentTime2()) / 1000.0;
  532. if ((current_time - nav.last_set_time) > 0.5) {
  533. //Can potentially recalc
  534. auto within = IsPositionWithinSimpleCylinder(
  535. glm::vec3(who->GetX(), who->GetZ(), who->GetY()),
  536. glm::vec3(nav.navigate_to_x, nav.navigate_to_z, nav.navigate_to_y),
  537. 1.5f,
  538. 6.0f
  539. );
  540. if (within && ent.second.Commands.size() > 0 && nav.last_set_time != 0)
  541. {
  542. //who->ClearRunningLocations();
  543. //StopNavigation((Entity*)who);
  544. MobListMutex.releasereadlock();
  545. return;
  546. }
  547. else if (!within && ent.second.Commands.size() > 0 && nav.last_set_time != 0)
  548. {
  549. MobListMutex.releasereadlock();
  550. return;
  551. }
  552. LogWrite(MAP__DEBUG, 0, "Map", "%s %f %f %f: within: %i, commands: %i, lastnav: %f %f %f", who->GetName(),
  553. who->GetX(),who->GetY(),who->GetZ(),within,
  554. ent.second.Commands.size(), nav.navigate_to_x, nav.navigate_to_y, nav.navigate_to_z);
  555. //auto heading_match = IsHeadingEqual(0.0, nav.navigate_to_heading);
  556. //if (/*false == within ||*/ false == heading_match || ent.second.Commands.size() == 0) {
  557. ent.second.Commands.clear();
  558. //Path is no longer valid, calculate a new path
  559. UpdatePath(who, x, y, z, mode);
  560. nav.navigate_to_x = x;
  561. nav.navigate_to_y = y;
  562. nav.navigate_to_z = z;
  563. nav.navigate_to_heading = 0.0;
  564. nav.last_set_time = current_time;
  565. //}
  566. }
  567. MobListMutex.releasereadlock();
  568. }
  569. /**
  570. * @param who
  571. */
  572. void MobMovementManager::StopNavigation(Entity *who)
  573. {
  574. MobListMutex.readlock();
  575. auto iter = _impl->Entries.find(who);
  576. auto &ent = (*iter);
  577. auto &nav = ent.second.NavTo;
  578. nav.navigate_to_x = 0.0;
  579. nav.navigate_to_y = 0.0;
  580. nav.navigate_to_z = 0.0;
  581. nav.navigate_to_heading = 0.0;
  582. nav.last_set_time = 0.0;
  583. if (true == ent.second.Commands.empty()) {
  584. PushStopMoving(ent.second);
  585. MobListMutex.releasereadlock();
  586. return;
  587. }
  588. if (!who->IsRunning()) {
  589. ent.second.Commands.clear();
  590. MobListMutex.releasereadlock();
  591. return;
  592. }
  593. ent.second.Commands.clear();
  594. PushStopMoving(ent.second);
  595. MobListMutex.releasereadlock();
  596. }
  597. /**
  598. * @param in
  599. * @return
  600. */
  601. float MobMovementManager::FixHeading(float in)
  602. {
  603. auto h = in;
  604. while (h > 512.0) {
  605. h -= 512.0;
  606. }
  607. while (h < 0.0) {
  608. h += 512.0;
  609. }
  610. return h;
  611. }
  612. void MobMovementManager::ClearStats()
  613. {
  614. _impl->Stats.LastResetTime = static_cast<double>(Timer::GetCurrentTime2()) / 1000.0;
  615. _impl->Stats.TotalSent = 0;
  616. _impl->Stats.TotalSentHeading = 0;
  617. _impl->Stats.TotalSentMovement = 0;
  618. _impl->Stats.TotalSentPosition = 0;
  619. }
  620. /**
  621. * @param who
  622. * @param x
  623. * @param y
  624. * @param z
  625. * @param mob_movement_mode
  626. */
  627. void MobMovementManager::UpdatePath(Entity *who, float x, float y, float z, MobMovementMode mob_movement_mode)
  628. {
  629. if (!who->GetZone()->zonemap /*|| !zone->HasWaterMap()*/) {
  630. MobListMutex.readlock();
  631. auto iter = _impl->Entries.find(who);
  632. auto &ent = (*iter);
  633. PushMoveTo(ent.second, x, y, z, mob_movement_mode);
  634. PushStopMoving(ent.second);
  635. MobListMutex.releasereadlock();
  636. return;
  637. }
  638. /*
  639. if (who-?()) {
  640. UpdatePathBoat(who, x, y, z, mob_movement_mode);
  641. }
  642. else if (who->IsUnderwaterOnly()) {
  643. UpdatePathUnderwater(who, x, y, z, mob_movement_mode);
  644. }*/
  645. //else {
  646. UpdatePathGround(who, x, y, z, mob_movement_mode);
  647. //}
  648. }
  649. /**
  650. * @param who
  651. * @param x
  652. * @param y
  653. * @param z
  654. * @param mode
  655. */
  656. void MobMovementManager::UpdatePathGround(Entity *who, float x, float y, float z, MobMovementMode mode)
  657. {
  658. PathfinderOptions opts;
  659. opts.smooth_path = true;
  660. opts.step_size = 100.0f;//RuleR(Pathing, NavmeshStepSize);
  661. opts.offset = who->GetYOffset()+1.0f;
  662. opts.flags = PathingNotDisabled ^ PathingZoneLine;
  663. //This is probably pointless since the nav mesh tool currently sets zonelines to disabled anyway
  664. auto partial = false;
  665. auto stuck = false;
  666. auto route = who->GetZone()->pathing->FindPath(
  667. glm::vec3(who->GetX(), who->GetZ(), who->GetY()),
  668. glm::vec3(x, z, y),
  669. partial,
  670. stuck,
  671. opts
  672. );
  673. MobListMutex.readlock();
  674. auto eiter = _impl->Entries.find(who);
  675. auto &ent = (*eiter);
  676. if (route.size() == 0) {
  677. HandleStuckBehavior(who, x, y, z, mode);
  678. MobListMutex.releasereadlock();
  679. return;
  680. }
  681. AdjustRoute(route, who);
  682. //avoid doing any processing if the mob is stuck to allow normal stuck code to work.
  683. if (!stuck) {
  684. //there are times when the routes returned are no differen than where the mob is currently standing. What basically happens
  685. //is a mob will get 'stuck' in such a way that it should be moving but the 'moving' place is the exact same spot it is at.
  686. //this is a problem and creates an area of ground that if a mob gets to, will stay there forever. If socal this creates a
  687. //"Ball of Death" (tm). This code tries to prevent this by simply warping the mob to the requested x/y. Better to have a warp than
  688. //have stuck mobs.
  689. auto routeNode = route.begin();
  690. bool noValidPath = true;
  691. while (routeNode != route.end() && noValidPath == true) {
  692. auto &currentNode = (*routeNode);
  693. if (routeNode == route.end()) {
  694. continue;
  695. }
  696. if (!(currentNode.pos.x == who->GetX() && currentNode.pos.y == who->GetZ())) {
  697. //if one of the nodes to move to, is not our current node, pass it.
  698. noValidPath = false;
  699. break;
  700. }
  701. //move to the next node
  702. routeNode++;
  703. }
  704. if (noValidPath) {
  705. //we are 'stuck' in a path, lets just get out of this by 'teleporting' to the next position.
  706. PushTeleportTo(
  707. ent.second,
  708. x,
  709. y,
  710. z,
  711. CalculateHeadingAngleBetweenPositions(who->GetX(), who->GetZ(), x, z)
  712. );
  713. MobListMutex.releasereadlock();
  714. return;
  715. }
  716. }
  717. auto iter = route.begin();
  718. glm::vec3 previous_pos(who->GetX(), who->GetZ(), who->GetY());
  719. bool first_node = true;
  720. while (iter != route.end()) {
  721. auto &current_node = (*iter);
  722. iter++;
  723. if (iter == route.end()) {
  724. continue;
  725. }
  726. previous_pos = current_node.pos;
  727. auto &next_node = (*iter);
  728. if (first_node) {
  729. if (mode == MovementWalking) {
  730. auto h = who->GetFaceTarget(next_node.pos.x, next_node.pos.y);
  731. PushRotateTo(ent.second, who, h, mode);
  732. }
  733. first_node = false;
  734. }
  735. //move to / teleport to node + 1
  736. if (next_node.teleport && next_node.pos.x != 0.0f && next_node.pos.y != 0.0f) {
  737. float calcedHeading =
  738. CalculateHeadingAngleBetweenPositions(
  739. current_node.pos.x,
  740. current_node.pos.y,
  741. next_node.pos.x,
  742. next_node.pos.y
  743. );
  744. PushTeleportTo(
  745. ent.second,
  746. next_node.pos.x,
  747. next_node.pos.z,
  748. next_node.pos.y,
  749. calcedHeading
  750. );
  751. }
  752. else {
  753. /* if (who->GetZone()->watermap->InLiquid(previous_pos)) {
  754. PushSwimTo(ent.second, next_node.pos.x, next_node.pos.y, next_node.pos.z, mode);
  755. }
  756. else {*/
  757. PushMoveTo(ent.second, next_node.pos.x, next_node.pos.z, next_node.pos.y, mode);
  758. // }
  759. }
  760. }
  761. if (stuck) {
  762. HandleStuckBehavior(who, x, y, z, mode);
  763. }
  764. else {
  765. PushStopMoving(ent.second);
  766. }
  767. MobListMutex.releasereadlock();
  768. }
  769. /**
  770. * @param who
  771. * @param x
  772. * @param y
  773. * @param z
  774. * @param movement_mode
  775. */
  776. void MobMovementManager::UpdatePathUnderwater(Entity *who, float x, float y, float z, MobMovementMode movement_mode)
  777. {
  778. MobListMutex.readlock();
  779. auto eiter = _impl->Entries.find(who);
  780. auto &ent = (*eiter);
  781. if (/*zone->watermap->InLiquid(who->GetPosition()) && zone->watermap->InLiquid(glm::vec3(x, y, z)) &&*/
  782. who->GetZone()->zonemap->CheckLoS(glm::vec3(who->GetX(),who->GetZ(),who->GetY()), glm::vec3(x, y, z))) {
  783. PushSwimTo(ent.second, x, y, z, movement_mode);
  784. PushStopMoving(ent.second);
  785. MobListMutex.releasereadlock();
  786. return;
  787. }
  788. PathfinderOptions opts;
  789. opts.smooth_path = true;
  790. opts.step_size = 100.0f;// RuleR(Pathing, NavmeshStepSize);
  791. opts.offset = who->GetYOffset();
  792. opts.flags = PathingNotDisabled ^ PathingZoneLine;
  793. auto partial = false;
  794. auto stuck = false;
  795. auto route = who->GetZone()->pathing->FindPath(
  796. glm::vec3(who->GetX(), who->GetY(), who->GetZ()),
  797. glm::vec3(x, y, z),
  798. partial,
  799. stuck,
  800. opts
  801. );
  802. if (route.size() == 0) {
  803. HandleStuckBehavior(who, x, z, y, movement_mode);
  804. MobListMutex.releasereadlock();
  805. return;
  806. }
  807. AdjustRoute(route, who);
  808. auto iter = route.begin();
  809. glm::vec3 previous_pos(who->GetX(), who->GetY(), who->GetZ());
  810. bool first_node = true;
  811. while (iter != route.end()) {
  812. auto &current_node = (*iter);
  813. /* if (!zone->watermap->InLiquid(current_node.pos)) {
  814. stuck = true;
  815. while (iter != route.end()) {
  816. iter = route.erase(iter);
  817. }
  818. break;
  819. }
  820. else {*/
  821. iter++;
  822. // }
  823. }
  824. if (route.size() == 0) {
  825. HandleStuckBehavior(who, x, y, z, movement_mode);
  826. MobListMutex.releasereadlock();
  827. return;
  828. }
  829. iter = route.begin();
  830. while (iter != route.end()) {
  831. auto &current_node = (*iter);
  832. iter++;
  833. if (iter == route.end()) {
  834. continue;
  835. }
  836. previous_pos = current_node.pos;
  837. auto &next_node = (*iter);
  838. if (first_node) {
  839. if (movement_mode == MovementWalking) {
  840. auto h = who->GetFaceTarget(next_node.pos.x, next_node.pos.y);
  841. PushRotateTo(ent.second, who, h, movement_mode);
  842. }
  843. first_node = false;
  844. }
  845. //move to / teleport to node + 1
  846. if (next_node.teleport && next_node.pos.x != 0.0f && next_node.pos.y != 0.0f) {
  847. float calcHeading = CalculateHeadingAngleBetweenPositions(
  848. current_node.pos.x,
  849. current_node.pos.y,
  850. next_node.pos.x,
  851. next_node.pos.y
  852. );
  853. PushTeleportTo(
  854. ent.second, next_node.pos.x, next_node.pos.z, next_node.pos.y, calcHeading);
  855. }
  856. else {
  857. PushSwimTo(ent.second, next_node.pos.x, next_node.pos.z, next_node.pos.y, movement_mode);
  858. }
  859. }
  860. if (stuck) {
  861. HandleStuckBehavior(who, x, y, z, movement_mode);
  862. }
  863. else {
  864. PushStopMoving(ent.second);
  865. }
  866. MobListMutex.releasereadlock();
  867. }
  868. /**
  869. * @param who
  870. * @param x
  871. * @param y
  872. * @param z
  873. * @param mode
  874. */
  875. void MobMovementManager::UpdatePathBoat(Entity *who, float x, float y, float z, MobMovementMode mode)
  876. {
  877. MobListMutex.readlock();
  878. auto eiter = _impl->Entries.find(who);
  879. auto &ent = (*eiter);
  880. PushSwimTo(ent.second, x, y, z, mode);
  881. PushStopMoving(ent.second);
  882. MobListMutex.releasereadlock();
  883. }
  884. /**
  885. * @param ent
  886. * @param x
  887. * @param y
  888. * @param z
  889. * @param heading
  890. */
  891. void MobMovementManager::PushTeleportTo(MobMovementEntry &ent, float x, float y, float z, float heading)
  892. {
  893. ent.Commands.push_back(std::unique_ptr<IMovementCommand>(new TeleportToCommand(x, y, z, heading)));
  894. }
  895. /**
  896. * @param ent
  897. * @param x
  898. * @param y
  899. * @param z
  900. * @param mob_movement_mode
  901. */
  902. void MobMovementManager::PushMoveTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode)
  903. {
  904. ent.Commands.push_back(std::unique_ptr<IMovementCommand>(new MoveToCommand(x, y, z, mob_movement_mode)));
  905. }
  906. /**
  907. * @param ent
  908. * @param x
  909. * @param y
  910. * @param z
  911. * @param mob_movement_mode
  912. */
  913. void MobMovementManager::PushSwimTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode)
  914. {
  915. ent.Commands.push_back(std::unique_ptr<IMovementCommand>(new SwimToCommand(x, y, z, mob_movement_mode)));
  916. }
  917. /**
  918. * @param ent
  919. * @param who
  920. * @param to
  921. * @param mob_movement_mode
  922. */
  923. void MobMovementManager::PushRotateTo(MobMovementEntry &ent, Entity *who, float to, MobMovementMode mob_movement_mode)
  924. {
  925. auto from = FixHeading(who->GetHeading());
  926. to = FixHeading(to);
  927. float diff = to - from;
  928. if (std::abs(diff) < 0.001f) {
  929. return;
  930. }
  931. while (diff < -256.0) {
  932. diff += 512.0;
  933. }
  934. while (diff > 256) {
  935. diff -= 512.0;
  936. }
  937. ent.Commands.push_back(std::unique_ptr<IMovementCommand>(new RotateToCommand(to, diff > 0 ? 1.0 : -1.0, mob_movement_mode)));
  938. }
  939. /**
  940. * @param mob_movement_entry
  941. */
  942. void MobMovementManager::PushStopMoving(MobMovementEntry &mob_movement_entry)
  943. {
  944. mob_movement_entry.Commands.push_back(std::unique_ptr<IMovementCommand>(new StopMovingCommand()));
  945. }
  946. /**
  947. * @param mob_movement_entry
  948. */
  949. void MobMovementManager::PushEvadeCombat(MobMovementEntry &mob_movement_entry)
  950. {
  951. mob_movement_entry.Commands.push_back(std::unique_ptr<IMovementCommand>(new EvadeCombatCommand()));
  952. }
  953. /**
  954. * @param who
  955. * @param x
  956. * @param y
  957. * @param z
  958. * @param mob_movement_mode
  959. */
  960. void MobMovementManager::HandleStuckBehavior(Entity *who, float x, float y, float z, MobMovementMode mob_movement_mode)
  961. {
  962. //LogDebug("Handle stuck behavior for {0} at ({1}, {2}, {3}) with movement_mode {4}", who->GetName(), x, y, z, mob_movement_mode);
  963. MobListMutex.readlock();
  964. auto sb = RunToTarget;//who->GetStuckBehavior();
  965. MobStuckBehavior behavior = RunToTarget;
  966. if (sb >= 0 && sb < MaxStuckBehavior) {
  967. behavior = (MobStuckBehavior) sb;
  968. }
  969. auto eiter = _impl->Entries.find(who);
  970. auto &ent = (*eiter);
  971. switch (sb) {
  972. case RunToTarget:
  973. PushMoveTo(ent.second, x, y, z, mob_movement_mode);
  974. PushStopMoving(ent.second);
  975. break;
  976. case WarpToTarget:
  977. PushTeleportTo(ent.second, x, y, z, 0.0f);
  978. PushStopMoving(ent.second);
  979. break;
  980. case TakeNoAction:
  981. PushStopMoving(ent.second);
  982. break;
  983. case EvadeCombat:
  984. PushEvadeCombat(ent.second);
  985. break;
  986. }
  987. MobListMutex.releasereadlock();
  988. }