mob_movement_manager.cpp 28 KB

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