mob_movement_manager.cpp 28 KB

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