llpathfindinglinkset.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. /**
  2. * @file llpathfindinglinkset.cpp
  3. * @brief Definition of a pathfinding linkset that contains various properties required for havok pathfinding.
  4. *
  5. * $LicenseInfo:firstyear=2012&license=viewergpl$
  6. *
  7. * Copyright (c) 2012, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llpathfindinglinkset.h"
  34. #include "llsd.h"
  35. #define LINKSET_LAND_IMPACT_FIELD "landimpact"
  36. #define LINKSET_MODIFIABLE_FIELD "modifiable"
  37. #define LINKSET_CATEGORY_FIELD "navmesh_category"
  38. #define LINKSET_CAN_BE_VOLUME "can_be_volume"
  39. #define LINKSET_IS_SCRIPTED_FIELD "is_scripted"
  40. #define LINKSET_PHANTOM_FIELD "phantom"
  41. #define LINKSET_WALKABILITY_A_FIELD "A"
  42. #define LINKSET_WALKABILITY_B_FIELD "B"
  43. #define LINKSET_WALKABILITY_C_FIELD "C"
  44. #define LINKSET_WALKABILITY_D_FIELD "D"
  45. #define LINKSET_CATEGORY_VALUE_INCLUDE 0
  46. #define LINKSET_CATEGORY_VALUE_EXCLUDE 1
  47. #define LINKSET_CATEGORY_VALUE_IGNORE 2
  48. LLPathfindingLinkset::LLPathfindingLinkset(const LLSD& terrain_data)
  49. : LLPathfindingObject(),
  50. mIsTerrain(true),
  51. mLandImpact(0U),
  52. mIsModifiable(false),
  53. mCanBeVolume(false),
  54. mIsScripted(false),
  55. mHasIsScripted(true),
  56. mLinksetUse(kUnknown),
  57. mWalkabilityCoefficientA(MIN_WALKABILITY_VALUE),
  58. mWalkabilityCoefficientB(MIN_WALKABILITY_VALUE),
  59. mWalkabilityCoefficientC(MIN_WALKABILITY_VALUE),
  60. mWalkabilityCoefficientD(MIN_WALKABILITY_VALUE)
  61. {
  62. parsePathfindingData(terrain_data);
  63. }
  64. LLPathfindingLinkset::LLPathfindingLinkset(const LLUUID& id, const LLSD& data)
  65. : LLPathfindingObject(id, data),
  66. mIsTerrain(false),
  67. mLandImpact(0U),
  68. mIsModifiable(true),
  69. mCanBeVolume(true),
  70. mIsScripted(false),
  71. mHasIsScripted(false),
  72. mLinksetUse(kUnknown),
  73. mWalkabilityCoefficientA(MIN_WALKABILITY_VALUE),
  74. mWalkabilityCoefficientB(MIN_WALKABILITY_VALUE),
  75. mWalkabilityCoefficientC(MIN_WALKABILITY_VALUE),
  76. mWalkabilityCoefficientD(MIN_WALKABILITY_VALUE)
  77. {
  78. parseLinksetData(data);
  79. parsePathfindingData(data);
  80. }
  81. LLPathfindingLinkset::LLPathfindingLinkset(const LLPathfindingLinkset& obj)
  82. : LLPathfindingObject(obj),
  83. mIsTerrain(obj.mIsTerrain),
  84. mLandImpact(obj.mLandImpact),
  85. mIsModifiable(obj.mIsModifiable),
  86. mCanBeVolume(obj.mCanBeVolume),
  87. mIsScripted(obj.mIsScripted),
  88. mHasIsScripted(obj.mHasIsScripted),
  89. mLinksetUse(obj.mLinksetUse),
  90. mWalkabilityCoefficientA(obj.mWalkabilityCoefficientA),
  91. mWalkabilityCoefficientB(obj.mWalkabilityCoefficientB),
  92. mWalkabilityCoefficientC(obj.mWalkabilityCoefficientC),
  93. mWalkabilityCoefficientD(obj.mWalkabilityCoefficientD)
  94. {
  95. }
  96. LLPathfindingLinkset& LLPathfindingLinkset::operator=(const LLPathfindingLinkset& obj)
  97. {
  98. dynamic_cast<LLPathfindingObject&>(*this) = obj;
  99. mIsTerrain = obj.mIsTerrain;
  100. mLandImpact = obj.mLandImpact;
  101. mIsModifiable = obj.mIsModifiable;
  102. mCanBeVolume = obj.mCanBeVolume;
  103. mIsScripted = obj.mIsScripted;
  104. mHasIsScripted = obj.mHasIsScripted;
  105. mLinksetUse = obj.mLinksetUse;
  106. mWalkabilityCoefficientA = obj.mWalkabilityCoefficientA;
  107. mWalkabilityCoefficientB = obj.mWalkabilityCoefficientB;
  108. mWalkabilityCoefficientC = obj.mWalkabilityCoefficientC;
  109. mWalkabilityCoefficientD = obj.mWalkabilityCoefficientD;
  110. return *this;
  111. }
  112. bool LLPathfindingLinkset::isPhantom() const
  113. {
  114. return isPhantom(getLinksetUse());
  115. }
  116. LLPathfindingLinkset::ELinksetUse LLPathfindingLinkset::getLinksetUseWithToggledPhantom(ELinksetUse use)
  117. {
  118. bool phantom = isPhantom(use);
  119. ENavMeshGenerationCategory category = getNavMeshGenerationCategory(use);
  120. return getLinksetUse(!phantom, category);
  121. }
  122. bool LLPathfindingLinkset::showUnmodifiablePhantomWarning(ELinksetUse use) const
  123. {
  124. return !isModifiable() && isPhantom() != isPhantom(use);
  125. }
  126. bool LLPathfindingLinkset::showPhantomToggleWarning(ELinksetUse use) const
  127. {
  128. return isModifiable() && isPhantom() != isPhantom(use);
  129. }
  130. bool LLPathfindingLinkset::showCannotBeVolumeWarning(ELinksetUse use) const
  131. {
  132. return !canBeVolume() &&
  133. (use == kMaterialVolume || use == kExclusionVolume);
  134. }
  135. LLSD LLPathfindingLinkset::encodeAlteredFields(ELinksetUse use, S32 a, S32 b,
  136. S32 c, S32 d) const
  137. {
  138. LLSD data;
  139. if (!isTerrain() && use != kUnknown && getLinksetUse() != use &&
  140. (canBeVolume() || (use != kMaterialVolume && use != kExclusionVolume)))
  141. {
  142. if (isModifiable())
  143. {
  144. data[LINKSET_PHANTOM_FIELD] = isPhantom(use);
  145. }
  146. data[LINKSET_CATEGORY_FIELD] =
  147. convertCategoryToLLSD(getNavMeshGenerationCategory(use));
  148. }
  149. if (mWalkabilityCoefficientA != a)
  150. {
  151. data[LINKSET_WALKABILITY_A_FIELD] = llclamp(a, MIN_WALKABILITY_VALUE,
  152. MAX_WALKABILITY_VALUE);
  153. }
  154. if (mWalkabilityCoefficientB != b)
  155. {
  156. data[LINKSET_WALKABILITY_B_FIELD] = llclamp(b, MIN_WALKABILITY_VALUE,
  157. MAX_WALKABILITY_VALUE);
  158. }
  159. if (mWalkabilityCoefficientC != c)
  160. {
  161. data[LINKSET_WALKABILITY_C_FIELD] = llclamp(c, MIN_WALKABILITY_VALUE,
  162. MAX_WALKABILITY_VALUE);
  163. }
  164. if (mWalkabilityCoefficientD != d)
  165. {
  166. data[LINKSET_WALKABILITY_D_FIELD] = llclamp(d, MIN_WALKABILITY_VALUE,
  167. MAX_WALKABILITY_VALUE);
  168. }
  169. return data;
  170. }
  171. void LLPathfindingLinkset::parseLinksetData(const LLSD& data)
  172. {
  173. if (data.has(LINKSET_LAND_IMPACT_FIELD) &&
  174. data.get(LINKSET_LAND_IMPACT_FIELD).isInteger() &&
  175. data.get(LINKSET_LAND_IMPACT_FIELD).asInteger() >= 0)
  176. {
  177. mLandImpact = data.get(LINKSET_LAND_IMPACT_FIELD).asInteger();
  178. }
  179. else
  180. {
  181. llwarns << "Malformed pathfinding linkset data: no land impact"
  182. << llendl;
  183. }
  184. if (data.has(LINKSET_MODIFIABLE_FIELD) &&
  185. data.get(LINKSET_MODIFIABLE_FIELD).isBoolean())
  186. {
  187. mIsModifiable = data.get(LINKSET_MODIFIABLE_FIELD).asBoolean();
  188. }
  189. else
  190. {
  191. llwarns << "Malformed pathfinding linkset data: missing modify flag"
  192. << llendl;
  193. }
  194. mHasIsScripted = data.has(LINKSET_IS_SCRIPTED_FIELD);
  195. if (mHasIsScripted)
  196. {
  197. if (data.get(LINKSET_IS_SCRIPTED_FIELD).isBoolean())
  198. {
  199. mIsScripted = data.get(LINKSET_IS_SCRIPTED_FIELD).asBoolean();
  200. }
  201. else
  202. {
  203. llwarns << "Malformed pathfinding linkset data: bad scripted flag"
  204. << llendl;
  205. }
  206. }
  207. }
  208. void LLPathfindingLinkset::parsePathfindingData(const LLSD& data)
  209. {
  210. bool phantom = false;
  211. if (data.has(LINKSET_PHANTOM_FIELD))
  212. {
  213. if (data.get(LINKSET_PHANTOM_FIELD).isBoolean())
  214. {
  215. phantom = data.get(LINKSET_PHANTOM_FIELD).asBoolean();
  216. }
  217. else
  218. {
  219. llwarns << "Malformed pathfinding terrain data: invalid phantom flag"
  220. << llendl;
  221. }
  222. }
  223. if (data.has(LINKSET_CATEGORY_FIELD))
  224. {
  225. mLinksetUse =
  226. getLinksetUse(phantom,
  227. convertCategoryFromLLSD(data.get(LINKSET_CATEGORY_FIELD)));
  228. }
  229. else
  230. {
  231. llwarns << "Malformed pathfinding terrain data: missing category"
  232. << llendl;
  233. }
  234. if (data.has(LINKSET_CAN_BE_VOLUME))
  235. {
  236. if (data.get(LINKSET_CAN_BE_VOLUME).isBoolean())
  237. {
  238. mCanBeVolume = data.get(LINKSET_CAN_BE_VOLUME).asBoolean();
  239. }
  240. else
  241. {
  242. llwarns << "Malformed pathfinding terrain data: invalid volume flag"
  243. << llendl;
  244. }
  245. }
  246. if (data.has(LINKSET_WALKABILITY_A_FIELD) &&
  247. data.get(LINKSET_WALKABILITY_A_FIELD).isInteger())
  248. {
  249. mWalkabilityCoefficientA =
  250. data.get(LINKSET_WALKABILITY_A_FIELD).asInteger();
  251. if (mWalkabilityCoefficientA < MIN_WALKABILITY_VALUE)
  252. {
  253. llwarns << "Malformed pathfinding terrain data: Bad walkability A value (too low). Clamping to "
  254. << MIN_WALKABILITY_VALUE << llendl;
  255. mWalkabilityCoefficientA = MIN_WALKABILITY_VALUE;
  256. }
  257. if (mWalkabilityCoefficientA > MAX_WALKABILITY_VALUE)
  258. {
  259. llwarns << "Malformed pathfinding terrain data: Bad walkability A value (too high). Clamping to "
  260. << MAX_WALKABILITY_VALUE << llendl;
  261. mWalkabilityCoefficientA = MAX_WALKABILITY_VALUE;
  262. }
  263. }
  264. else
  265. {
  266. llwarns << "Malformed pathfinding terrain data: missing walkability A"
  267. << llendl;
  268. }
  269. if (data.has(LINKSET_WALKABILITY_B_FIELD) &&
  270. data.get(LINKSET_WALKABILITY_B_FIELD).isInteger())
  271. {
  272. mWalkabilityCoefficientB =
  273. data.get(LINKSET_WALKABILITY_B_FIELD).asInteger();
  274. if (mWalkabilityCoefficientB < MIN_WALKABILITY_VALUE)
  275. {
  276. llwarns << "Malformed pathfinding terrain data: Bad walkability B value (too low). Clamping to "
  277. << MIN_WALKABILITY_VALUE << llendl;
  278. mWalkabilityCoefficientB = MIN_WALKABILITY_VALUE;
  279. }
  280. if (mWalkabilityCoefficientB > MAX_WALKABILITY_VALUE)
  281. {
  282. llwarns << "Malformed pathfinding terrain data: Bad walkability B value (too high). Clamping to "
  283. << MAX_WALKABILITY_VALUE << llendl;
  284. mWalkabilityCoefficientB = MAX_WALKABILITY_VALUE;
  285. }
  286. }
  287. else
  288. {
  289. llwarns << "Malformed pathfinding terrain data: missing walkability B"
  290. << llendl;
  291. }
  292. if (data.has(LINKSET_WALKABILITY_C_FIELD) &&
  293. data.get(LINKSET_WALKABILITY_C_FIELD).isInteger())
  294. {
  295. mWalkabilityCoefficientC =
  296. data.get(LINKSET_WALKABILITY_C_FIELD).asInteger();
  297. if (mWalkabilityCoefficientC < MIN_WALKABILITY_VALUE)
  298. {
  299. llwarns << "Malformed pathfinding terrain data: Bad walkability C value (too low). Clamping to "
  300. << MIN_WALKABILITY_VALUE << llendl;
  301. mWalkabilityCoefficientC = MIN_WALKABILITY_VALUE;
  302. }
  303. if (mWalkabilityCoefficientC > MAX_WALKABILITY_VALUE)
  304. {
  305. llwarns << "Malformed pathfinding terrain data: Bad walkability C value (too high). Clamping to "
  306. << MAX_WALKABILITY_VALUE << llendl;
  307. mWalkabilityCoefficientC = MAX_WALKABILITY_VALUE;
  308. }
  309. }
  310. else
  311. {
  312. llwarns << "Malformed pathfinding terrain data: missing walkability C"
  313. << llendl;
  314. }
  315. if (data.has(LINKSET_WALKABILITY_D_FIELD) &&
  316. data.get(LINKSET_WALKABILITY_D_FIELD).isInteger())
  317. {
  318. mWalkabilityCoefficientD =
  319. data.get(LINKSET_WALKABILITY_D_FIELD).asInteger();
  320. if (mWalkabilityCoefficientD < MIN_WALKABILITY_VALUE)
  321. {
  322. llwarns << "Malformed pathfinding terrain data: Bad walkability D value (too low). Clamping to "
  323. << MIN_WALKABILITY_VALUE << llendl;
  324. mWalkabilityCoefficientD = MIN_WALKABILITY_VALUE;
  325. }
  326. if (mWalkabilityCoefficientD > MAX_WALKABILITY_VALUE)
  327. {
  328. llwarns << "Malformed pathfinding terrain data: Bad walkability D value (too high). Clamping to "
  329. << MAX_WALKABILITY_VALUE << llendl;
  330. mWalkabilityCoefficientD = MAX_WALKABILITY_VALUE;
  331. }
  332. }
  333. else
  334. {
  335. llwarns << "Malformed pathfinding terrain data: missing walkability D"
  336. << llendl;
  337. }
  338. }
  339. bool LLPathfindingLinkset::isPhantom(ELinksetUse use)
  340. {
  341. switch (use)
  342. {
  343. case kWalkable:
  344. case kStaticObstacle:
  345. case kDynamicObstacle:
  346. return false;
  347. case kMaterialVolume:
  348. case kExclusionVolume:
  349. case kDynamicPhantom:
  350. return true;
  351. default:
  352. llassert(false);
  353. return false;
  354. }
  355. }
  356. LLPathfindingLinkset::ELinksetUse LLPathfindingLinkset::getLinksetUse(bool phantom,
  357. ENavMeshGenerationCategory category)
  358. {
  359. if (phantom)
  360. {
  361. switch (category)
  362. {
  363. case kNavMeshGenerationIgnore:
  364. return kDynamicPhantom;
  365. case kNavMeshGenerationInclude:
  366. return kMaterialVolume;
  367. case kNavMeshGenerationExclude:
  368. return kExclusionVolume;
  369. default:
  370. llassert(false);
  371. return kUnknown;
  372. }
  373. }
  374. switch (category)
  375. {
  376. case kNavMeshGenerationIgnore:
  377. return kDynamicObstacle;
  378. case kNavMeshGenerationInclude:
  379. return kWalkable;
  380. case kNavMeshGenerationExclude:
  381. return kStaticObstacle;
  382. default:
  383. llassert(false);
  384. return kUnknown;
  385. }
  386. }
  387. LLPathfindingLinkset::ENavMeshGenerationCategory LLPathfindingLinkset::getNavMeshGenerationCategory(ELinksetUse use)
  388. {
  389. switch (use)
  390. {
  391. case kWalkable:
  392. case kMaterialVolume:
  393. return kNavMeshGenerationInclude;
  394. case kStaticObstacle:
  395. case kExclusionVolume:
  396. return kNavMeshGenerationExclude;
  397. case kDynamicObstacle:
  398. case kDynamicPhantom:
  399. return kNavMeshGenerationIgnore;
  400. default:
  401. llassert(false);
  402. return kNavMeshGenerationIgnore;
  403. }
  404. }
  405. LLSD LLPathfindingLinkset::convertCategoryToLLSD(ENavMeshGenerationCategory category)
  406. {
  407. switch (category)
  408. {
  409. case kNavMeshGenerationIgnore:
  410. return LLSD(LINKSET_CATEGORY_VALUE_IGNORE);
  411. case kNavMeshGenerationInclude:
  412. return LLSD(LINKSET_CATEGORY_VALUE_INCLUDE);
  413. case kNavMeshGenerationExclude:
  414. return LLSD(LINKSET_CATEGORY_VALUE_EXCLUDE);
  415. default:
  416. llassert(false);
  417. return LLSD(LINKSET_CATEGORY_VALUE_IGNORE);
  418. }
  419. }
  420. LLPathfindingLinkset::ENavMeshGenerationCategory LLPathfindingLinkset::convertCategoryFromLLSD(const LLSD& data)
  421. {
  422. if (!data.isInteger())
  423. {
  424. llassert(false);
  425. return kNavMeshGenerationIgnore;
  426. }
  427. switch (data.asInteger())
  428. {
  429. case LINKSET_CATEGORY_VALUE_IGNORE:
  430. return kNavMeshGenerationIgnore;
  431. case LINKSET_CATEGORY_VALUE_INCLUDE:
  432. return kNavMeshGenerationInclude;
  433. case LINKSET_CATEGORY_VALUE_EXCLUDE:
  434. return kNavMeshGenerationExclude;
  435. default:
  436. llassert(false);
  437. return kNavMeshGenerationIgnore;
  438. }
  439. }