mob_movement_manager.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284
  1. #include "mob_movement_manager.h"
  2. #include "../Entity.h"
  3. #include "../zoneserver.h"
  4. #include "region_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. 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, Entity* 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) {
  221. if (mob->IsFeared()) {
  222. current_speed = mob->GetBaseSpeed();
  223. }
  224. else {
  225. //runback overrides
  226. if (mob->GetSpeed() > mob->GetMaxSpeed())
  227. current_speed = mob->GetSpeed();
  228. else
  229. current_speed = 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, Entity* 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, Entity* 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, Entity* 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, Entity *who)
  392. {
  393. if (who->GetZone() == nullptr || !who->GetMap() /*|| !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->GetMap()->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<Entity *, 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. if (commands.size() < 1)
  426. continue;
  427. iter.first->MCommandMutex.writelock();
  428. while (true != commands.empty()) {
  429. auto &cmd = commands.front();
  430. auto r = cmd->Process(this, iter.first);
  431. if (true != r) {
  432. break;
  433. }
  434. commands.pop_front();
  435. }
  436. iter.first->MCommandMutex.releasewritelock();
  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. auto iter = _impl->Entries.find(mob);
  456. if(iter != _impl->Entries.end())
  457. _impl->Entries.erase(iter);
  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(Entity *who, float to, MobMovementMode mob_movement_mode)
  487. {
  488. MobListMutex.readlock();
  489. auto iter = _impl->Entries.find(who);
  490. if (iter == _impl->Entries.end())
  491. {
  492. MobListMutex.releasereadlock();
  493. return; // does not exist in navigation
  494. }
  495. auto &ent = (*iter);
  496. if (true != ent.second.Commands.empty()) {
  497. MobListMutex.releasereadlock();
  498. return;
  499. }
  500. PushRotateTo(ent.second, who, to, mob_movement_mode);
  501. MobListMutex.releasereadlock();
  502. }
  503. /**
  504. * @param who
  505. * @param x
  506. * @param y
  507. * @param z
  508. * @param heading
  509. */
  510. void MobMovementManager::Teleport(Entity *who, float x, float y, float z, float heading)
  511. {
  512. MobListMutex.readlock();
  513. auto iter = _impl->Entries.find(who);
  514. if (iter == _impl->Entries.end())
  515. {
  516. MobListMutex.releasereadlock();
  517. return; // does not exist in navigation
  518. }
  519. auto &ent = (*iter);
  520. ent.second.Commands.clear();
  521. PushTeleportTo(ent.second, x, y, z, heading);
  522. MobListMutex.releasereadlock();
  523. }
  524. /**
  525. * @param who
  526. * @param x
  527. * @param y
  528. * @param z
  529. * @param mode
  530. */
  531. void MobMovementManager::NavigateTo(Entity *who, float x, float y, float z, MobMovementMode mode, bool overrideDistance)
  532. {
  533. glm::vec3 targPos(x, z, y);
  534. glm::vec3 origPos(who->GetX(), who->GetZ(), who->GetY());
  535. if (IsPositionEqualWithinCertainZ(targPos, origPos, 6.0f)) {
  536. return;
  537. }
  538. MobListMutex.readlock();
  539. auto iter = _impl->Entries.find(who);
  540. if (iter == _impl->Entries.end())
  541. {
  542. MobListMutex.releasereadlock();
  543. return; // does not exist in navigation
  544. }
  545. auto &ent = (*iter);
  546. auto &nav = ent.second.NavTo;
  547. double current_time = static_cast<double>(Timer::GetCurrentTime2()) / 1000.0;
  548. if ((current_time - nav.last_set_time) > 0.5) {
  549. //Can potentially recalc
  550. auto within = IsPositionWithinSimpleCylinder(
  551. glm::vec3(who->GetX(), who->GetZ(), who->GetY()),
  552. glm::vec3(nav.navigate_to_x, nav.navigate_to_z, nav.navigate_to_y),
  553. 1.5f,
  554. 6.0f
  555. );
  556. who->MCommandMutex.writelock();
  557. if (within && ent.second.Commands.size() > 0 && nav.last_set_time != 0)
  558. {
  559. //who->ClearRunningLocations();
  560. //StopNavigation((Entity*)who);
  561. who->MCommandMutex.releasewritelock();
  562. MobListMutex.releasereadlock();
  563. return;
  564. }
  565. else if (!within && ent.second.Commands.size() > 0 && nav.last_set_time != 0)
  566. {
  567. who->MCommandMutex.releasewritelock();
  568. MobListMutex.releasereadlock();
  569. return;
  570. }
  571. LogWrite(MAP__DEBUG, 0, "Map", "%s %f %f %f: within: %i, commands: %i, lastnav: %f %f %f", who->GetName(),
  572. who->GetX(),who->GetY(),who->GetZ(),within,
  573. ent.second.Commands.size(), nav.navigate_to_x, nav.navigate_to_y, nav.navigate_to_z);
  574. //auto heading_match = IsHeadingEqual(0.0, nav.navigate_to_heading);
  575. //if (/*false == within ||*/ false == heading_match || ent.second.Commands.size() == 0) {
  576. ent.second.Commands.clear();
  577. //Path is no longer valid, calculate a new path
  578. UpdatePath(who, x, y, z, mode);
  579. nav.navigate_to_x = x;
  580. nav.navigate_to_y = y;
  581. nav.navigate_to_z = z;
  582. nav.navigate_to_heading = 0.0;
  583. nav.last_set_time = current_time;
  584. who->MCommandMutex.releasewritelock();
  585. //}
  586. }
  587. MobListMutex.releasereadlock();
  588. }
  589. /**
  590. * @param who
  591. */
  592. void MobMovementManager::StopNavigation(Entity *who)
  593. {
  594. MobListMutex.readlock();
  595. auto iter = _impl->Entries.find(who);
  596. if (iter == _impl->Entries.end())
  597. {
  598. MobListMutex.releasereadlock();
  599. return; // does not exist in navigation
  600. }
  601. auto &ent = (*iter);
  602. auto &nav = ent.second.NavTo;
  603. nav.navigate_to_x = 0.0;
  604. nav.navigate_to_y = 0.0;
  605. nav.navigate_to_z = 0.0;
  606. nav.navigate_to_heading = 0.0;
  607. nav.last_set_time = 0.0;
  608. who->MCommandMutex.writelock();
  609. if (true == ent.second.Commands.empty()) {
  610. PushStopMoving(ent.second);
  611. who->MCommandMutex.releasewritelock();
  612. MobListMutex.releasereadlock();
  613. return;
  614. }
  615. if (!who->IsRunning()) {
  616. ent.second.Commands.clear();
  617. who->MCommandMutex.releasewritelock();
  618. MobListMutex.releasereadlock();
  619. return;
  620. }
  621. ent.second.Commands.clear();
  622. PushStopMoving(ent.second);
  623. who->MCommandMutex.releasewritelock();
  624. MobListMutex.releasereadlock();
  625. }
  626. void MobMovementManager::DisruptNavigation(Entity* who)
  627. {
  628. MobListMutex.readlock();
  629. auto iter = _impl->Entries.find(who);
  630. if (iter == _impl->Entries.end())
  631. {
  632. MobListMutex.releasereadlock();
  633. return; // does not exist in navigation
  634. }
  635. auto& ent = (*iter);
  636. auto& nav = ent.second.NavTo;
  637. nav.navigate_to_x = 0.0;
  638. nav.navigate_to_y = 0.0;
  639. nav.navigate_to_z = 0.0;
  640. nav.navigate_to_heading = 0.0;
  641. nav.last_set_time = 0.0;
  642. if (!who->IsRunning()) {
  643. who->MCommandMutex.writelock();
  644. ent.second.Commands.clear();
  645. MobListMutex.releasereadlock();
  646. who->MCommandMutex.releasewritelock();
  647. return;
  648. }
  649. }
  650. /**
  651. * @param in
  652. * @return
  653. */
  654. float MobMovementManager::FixHeading(float in)
  655. {
  656. auto h = in;
  657. while (h > 512.0) {
  658. h -= 512.0;
  659. }
  660. while (h < 0.0) {
  661. h += 512.0;
  662. }
  663. return h;
  664. }
  665. void MobMovementManager::ClearStats()
  666. {
  667. _impl->Stats.LastResetTime = static_cast<double>(Timer::GetCurrentTime2()) / 1000.0;
  668. _impl->Stats.TotalSent = 0;
  669. _impl->Stats.TotalSentHeading = 0;
  670. _impl->Stats.TotalSentMovement = 0;
  671. _impl->Stats.TotalSentPosition = 0;
  672. }
  673. /**
  674. * @param who
  675. * @param x
  676. * @param y
  677. * @param z
  678. * @param mob_movement_mode
  679. */
  680. void MobMovementManager::UpdatePath(Entity *who, float x, float y, float z, MobMovementMode mob_movement_mode)
  681. {
  682. if (!who->GetMap() /*|| !zone->HasWaterMap()*/) {
  683. MobListMutex.readlock();
  684. auto iter = _impl->Entries.find(who);
  685. if (iter == _impl->Entries.end())
  686. {
  687. MobListMutex.releasereadlock();
  688. return; // does not exist in navigation
  689. }
  690. auto &ent = (*iter);
  691. PushMoveTo(ent.second, x, y, z, mob_movement_mode);
  692. PushStopMoving(ent.second);
  693. MobListMutex.releasereadlock();
  694. return;
  695. }
  696. /*
  697. if (who-?()) {
  698. UpdatePathBoat(who, x, y, z, mob_movement_mode);
  699. }
  700. else if (who->IsUnderwaterOnly()) {
  701. UpdatePathUnderwater(who, x, y, z, mob_movement_mode);
  702. }*/
  703. //else {
  704. UpdatePathGround(who, x, y, z, mob_movement_mode);
  705. //}
  706. }
  707. /**
  708. * @param who
  709. * @param x
  710. * @param y
  711. * @param z
  712. * @param mode
  713. */
  714. void MobMovementManager::UpdatePathGround(Entity *who, float x, float y, float z, MobMovementMode mode)
  715. {
  716. PathfinderOptions opts;
  717. opts.smooth_path = true;
  718. opts.step_size = 100.0f;//RuleR(Pathing, NavmeshStepSize);
  719. opts.offset = who->GetYOffset()+1.0f;
  720. opts.flags = PathingNotDisabled ^ PathingZoneLine;
  721. //This is probably pointless since the nav mesh tool currently sets zonelines to disabled anyway
  722. auto partial = false;
  723. auto stuck = false;
  724. auto route = who->GetZone()->pathing->FindPath(
  725. glm::vec3(who->GetX(), who->GetZ(), who->GetY()),
  726. glm::vec3(x, z, y),
  727. partial,
  728. stuck,
  729. opts
  730. );
  731. MobListMutex.readlock();
  732. auto eiter = _impl->Entries.find(who);
  733. if (eiter == _impl->Entries.end())
  734. {
  735. MobListMutex.releasereadlock();
  736. return; // does not exist in navigation
  737. }
  738. auto &ent = (*eiter);
  739. if (route.size() == 0) {
  740. HandleStuckBehavior(who, x, y, z, mode);
  741. MobListMutex.releasereadlock();
  742. return;
  743. }
  744. AdjustRoute(route, who);
  745. //avoid doing any processing if the mob is stuck to allow normal stuck code to work.
  746. if (!stuck) {
  747. //there are times when the routes returned are no differen than where the mob is currently standing. What basically happens
  748. //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.
  749. //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
  750. //"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
  751. //have stuck mobs.
  752. auto routeNode = route.begin();
  753. bool noValidPath = true;
  754. while (routeNode != route.end() && noValidPath == true) {
  755. auto &currentNode = (*routeNode);
  756. if (routeNode == route.end()) {
  757. continue;
  758. }
  759. if (!(currentNode.pos.x == who->GetX() && currentNode.pos.y == who->GetZ())) {
  760. //if one of the nodes to move to, is not our current node, pass it.
  761. noValidPath = false;
  762. break;
  763. }
  764. //move to the next node
  765. routeNode++;
  766. }
  767. if (noValidPath) {
  768. //we are 'stuck' in a path, lets just get out of this by 'teleporting' to the next position.
  769. PushTeleportTo(
  770. ent.second,
  771. x,
  772. y,
  773. z,
  774. CalculateHeadingAngleBetweenPositions(who->GetX(), who->GetZ(), x, z)
  775. );
  776. MobListMutex.releasereadlock();
  777. return;
  778. }
  779. }
  780. auto iter = route.begin();
  781. glm::vec3 previous_pos(who->GetX(), who->GetZ(), who->GetY());
  782. bool first_node = true;
  783. while (iter != route.end()) {
  784. auto &current_node = (*iter);
  785. iter++;
  786. if (iter == route.end()) {
  787. continue;
  788. }
  789. previous_pos = current_node.pos;
  790. auto &next_node = (*iter);
  791. if (first_node) {
  792. if (mode == MovementWalking) {
  793. auto h = who->GetFaceTarget(next_node.pos.x, next_node.pos.y);
  794. PushRotateTo(ent.second, who, h, mode);
  795. }
  796. first_node = false;
  797. }
  798. //move to / teleport to node + 1
  799. if (next_node.teleport && next_node.pos.x != 0.0f && next_node.pos.y != 0.0f) {
  800. float calcedHeading =
  801. CalculateHeadingAngleBetweenPositions(
  802. current_node.pos.x,
  803. current_node.pos.y,
  804. next_node.pos.x,
  805. next_node.pos.y
  806. );
  807. PushTeleportTo(
  808. ent.second,
  809. next_node.pos.x,
  810. next_node.pos.z,
  811. next_node.pos.y,
  812. calcedHeading
  813. );
  814. }
  815. else {
  816. /* if (who->GetZone()->watermap->InLiquid(previous_pos)) {
  817. PushSwimTo(ent.second, next_node.pos.x, next_node.pos.y, next_node.pos.z, mode);
  818. }
  819. else {*/
  820. PushMoveTo(ent.second, next_node.pos.x, next_node.pos.z, next_node.pos.y, mode);
  821. // }
  822. }
  823. }
  824. if (stuck) {
  825. HandleStuckBehavior(who, x, y, z, mode);
  826. }
  827. else {
  828. PushStopMoving(ent.second);
  829. }
  830. MobListMutex.releasereadlock();
  831. }
  832. /**
  833. * @param who
  834. * @param x
  835. * @param y
  836. * @param z
  837. * @param movement_mode
  838. */
  839. void MobMovementManager::UpdatePathUnderwater(Entity *who, float x, float y, float z, MobMovementMode movement_mode)
  840. {
  841. MobListMutex.readlock();
  842. auto eiter = _impl->Entries.find(who);
  843. if (eiter == _impl->Entries.end())
  844. {
  845. MobListMutex.releasereadlock();
  846. return; // does not exist in navigation
  847. }
  848. auto &ent = (*eiter);
  849. if (/*zone->watermap->InLiquid(who->GetPosition()) && zone->watermap->InLiquid(glm::vec3(x, y, z)) &&*/
  850. who->GetMap()->CheckLoS(glm::vec3(who->GetX(),who->GetZ(),who->GetY()), glm::vec3(x, y, z))) {
  851. PushSwimTo(ent.second, x, y, z, movement_mode);
  852. PushStopMoving(ent.second);
  853. MobListMutex.releasereadlock();
  854. return;
  855. }
  856. PathfinderOptions opts;
  857. opts.smooth_path = true;
  858. opts.step_size = 100.0f;// RuleR(Pathing, NavmeshStepSize);
  859. opts.offset = who->GetYOffset();
  860. opts.flags = PathingNotDisabled ^ PathingZoneLine;
  861. auto partial = false;
  862. auto stuck = false;
  863. auto route = who->GetZone()->pathing->FindPath(
  864. glm::vec3(who->GetX(), who->GetY(), who->GetZ()),
  865. glm::vec3(x, y, z),
  866. partial,
  867. stuck,
  868. opts
  869. );
  870. if (route.size() == 0) {
  871. HandleStuckBehavior(who, x, z, y, movement_mode);
  872. MobListMutex.releasereadlock();
  873. return;
  874. }
  875. AdjustRoute(route, who);
  876. auto iter = route.begin();
  877. glm::vec3 previous_pos(who->GetX(), who->GetY(), who->GetZ());
  878. bool first_node = true;
  879. while (iter != route.end()) {
  880. auto &current_node = (*iter);
  881. /* if (!zone->watermap->InLiquid(current_node.pos)) {
  882. stuck = true;
  883. while (iter != route.end()) {
  884. iter = route.erase(iter);
  885. }
  886. break;
  887. }
  888. else {*/
  889. iter++;
  890. // }
  891. }
  892. if (route.size() == 0) {
  893. HandleStuckBehavior(who, x, y, z, movement_mode);
  894. MobListMutex.releasereadlock();
  895. return;
  896. }
  897. iter = route.begin();
  898. while (iter != route.end()) {
  899. auto &current_node = (*iter);
  900. iter++;
  901. if (iter == route.end()) {
  902. continue;
  903. }
  904. previous_pos = current_node.pos;
  905. auto &next_node = (*iter);
  906. if (first_node) {
  907. if (movement_mode == MovementWalking) {
  908. auto h = who->GetFaceTarget(next_node.pos.x, next_node.pos.y);
  909. PushRotateTo(ent.second, who, h, movement_mode);
  910. }
  911. first_node = false;
  912. }
  913. //move to / teleport to node + 1
  914. if (next_node.teleport && next_node.pos.x != 0.0f && next_node.pos.y != 0.0f) {
  915. float calcHeading = CalculateHeadingAngleBetweenPositions(
  916. current_node.pos.x,
  917. current_node.pos.y,
  918. next_node.pos.x,
  919. next_node.pos.y
  920. );
  921. PushTeleportTo(
  922. ent.second, next_node.pos.x, next_node.pos.z, next_node.pos.y, calcHeading);
  923. }
  924. else {
  925. PushSwimTo(ent.second, next_node.pos.x, next_node.pos.z, next_node.pos.y, movement_mode);
  926. }
  927. }
  928. if (stuck) {
  929. HandleStuckBehavior(who, x, y, z, movement_mode);
  930. }
  931. else {
  932. PushStopMoving(ent.second);
  933. }
  934. MobListMutex.releasereadlock();
  935. }
  936. /**
  937. * @param who
  938. * @param x
  939. * @param y
  940. * @param z
  941. * @param mode
  942. */
  943. void MobMovementManager::UpdatePathBoat(Entity *who, float x, float y, float z, MobMovementMode mode)
  944. {
  945. MobListMutex.readlock();
  946. auto eiter = _impl->Entries.find(who);
  947. if (eiter == _impl->Entries.end())
  948. {
  949. MobListMutex.releasereadlock();
  950. return; // does not exist in navigation
  951. }
  952. auto &ent = (*eiter);
  953. PushSwimTo(ent.second, x, y, z, mode);
  954. PushStopMoving(ent.second);
  955. MobListMutex.releasereadlock();
  956. }
  957. /**
  958. * @param ent
  959. * @param x
  960. * @param y
  961. * @param z
  962. * @param heading
  963. */
  964. void MobMovementManager::PushTeleportTo(MobMovementEntry &ent, float x, float y, float z, float heading)
  965. {
  966. ent.Commands.push_back(std::unique_ptr<IMovementCommand>(new TeleportToCommand(x, y, z, heading)));
  967. }
  968. /**
  969. * @param ent
  970. * @param x
  971. * @param y
  972. * @param z
  973. * @param mob_movement_mode
  974. */
  975. void MobMovementManager::PushMoveTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode)
  976. {
  977. ent.Commands.push_back(std::unique_ptr<IMovementCommand>(new MoveToCommand(x, y, z, mob_movement_mode)));
  978. }
  979. /**
  980. * @param ent
  981. * @param x
  982. * @param y
  983. * @param z
  984. * @param mob_movement_mode
  985. */
  986. void MobMovementManager::PushSwimTo(MobMovementEntry &ent, float x, float y, float z, MobMovementMode mob_movement_mode)
  987. {
  988. ent.Commands.push_back(std::unique_ptr<IMovementCommand>(new SwimToCommand(x, y, z, mob_movement_mode)));
  989. }
  990. /**
  991. * @param ent
  992. * @param who
  993. * @param to
  994. * @param mob_movement_mode
  995. */
  996. void MobMovementManager::PushRotateTo(MobMovementEntry &ent, Entity *who, float to, MobMovementMode mob_movement_mode)
  997. {
  998. auto from = FixHeading(who->GetHeading());
  999. to = FixHeading(to);
  1000. float diff = to - from;
  1001. if (std::abs(diff) < 0.001f) {
  1002. return;
  1003. }
  1004. while (diff < -256.0) {
  1005. diff += 512.0;
  1006. }
  1007. while (diff > 256) {
  1008. diff -= 512.0;
  1009. }
  1010. ent.Commands.push_back(std::unique_ptr<IMovementCommand>(new RotateToCommand(to, diff > 0 ? 1.0 : -1.0, mob_movement_mode)));
  1011. }
  1012. /**
  1013. * @param mob_movement_entry
  1014. */
  1015. void MobMovementManager::PushStopMoving(MobMovementEntry &mob_movement_entry)
  1016. {
  1017. mob_movement_entry.Commands.push_back(std::unique_ptr<IMovementCommand>(new StopMovingCommand()));
  1018. }
  1019. /**
  1020. * @param mob_movement_entry
  1021. */
  1022. void MobMovementManager::PushEvadeCombat(MobMovementEntry &mob_movement_entry)
  1023. {
  1024. mob_movement_entry.Commands.push_back(std::unique_ptr<IMovementCommand>(new EvadeCombatCommand()));
  1025. }
  1026. /**
  1027. * @param who
  1028. * @param x
  1029. * @param y
  1030. * @param z
  1031. * @param mob_movement_mode
  1032. */
  1033. void MobMovementManager::HandleStuckBehavior(Entity *who, float x, float y, float z, MobMovementMode mob_movement_mode)
  1034. {
  1035. //LogDebug("Handle stuck behavior for {0} at ({1}, {2}, {3}) with movement_mode {4}", who->GetName(), x, y, z, mob_movement_mode);
  1036. MobListMutex.readlock();
  1037. auto sb = RunToTarget;//who->GetStuckBehavior();
  1038. MobStuckBehavior behavior = RunToTarget;
  1039. if (sb >= 0 && sb < MaxStuckBehavior) {
  1040. behavior = (MobStuckBehavior) sb;
  1041. }
  1042. auto eiter = _impl->Entries.find(who);
  1043. if (eiter == _impl->Entries.end())
  1044. {
  1045. MobListMutex.releasereadlock();
  1046. return; // does not exist in navigation
  1047. }
  1048. auto &ent = (*eiter);
  1049. switch (sb) {
  1050. case RunToTarget:
  1051. PushMoveTo(ent.second, x, y, z, mob_movement_mode);
  1052. PushStopMoving(ent.second);
  1053. break;
  1054. case WarpToTarget:
  1055. PushTeleportTo(ent.second, x, y, z, 0.0f);
  1056. PushStopMoving(ent.second);
  1057. break;
  1058. case TakeNoAction:
  1059. PushStopMoving(ent.second);
  1060. break;
  1061. case EvadeCombat:
  1062. PushEvadeCombat(ent.second);
  1063. break;
  1064. }
  1065. MobListMutex.releasereadlock();
  1066. }