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