pathedInterior.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "interior/pathedInterior.h"
  23. #include "core/stream/stream.h"
  24. #include "console/consoleTypes.h"
  25. #include "scene/sceneRenderState.h"
  26. #include "math/mathIO.h"
  27. #include "core/stream/bitStream.h"
  28. #include "interior/interior.h"
  29. #include "scene/simPath.h"
  30. #include "scene/pathManager.h"
  31. #include "core/frameAllocator.h"
  32. #include "scene/sceneManager.h"
  33. #include "sfx/sfxSystem.h"
  34. #include "sfx/sfxProfile.h"
  35. #include "sfx/sfxSource.h"
  36. #include "core/resourceManager.h"
  37. IMPLEMENT_CO_NETOBJECT_V1(PathedInterior);
  38. IMPLEMENT_CO_DATABLOCK_V1(PathedInteriorData);
  39. ConsoleDocClass( PathedInterior,
  40. "@brief Legacy interior related class, soon to be deprecated.\n\n"
  41. "Not intended for game development, for editors or internal use only.\n\n "
  42. "@internal");
  43. ConsoleDocClass( PathedInteriorData,
  44. "@brief Legacy interior related class, soon to be deprecated.\n\n"
  45. "Not intended for game development, for editors or internal use only.\n\n "
  46. "@internal");
  47. //--------------------------------------------------------------------------
  48. PathedInteriorData::PathedInteriorData()
  49. {
  50. for(U32 i = 0; i < MaxSounds; i++)
  51. sound[i] = NULL;
  52. }
  53. void PathedInteriorData::initPersistFields()
  54. {
  55. addField("StartSound", TYPEID< SFXProfile >(), Offset(sound[StartSound], PathedInteriorData));
  56. addField("SustainSound", TYPEID< SFXProfile >(), Offset(sound[SustainSound], PathedInteriorData));
  57. addField("StopSound", TYPEID< SFXProfile >(), Offset(sound[StopSound], PathedInteriorData));
  58. Parent::initPersistFields();
  59. }
  60. void PathedInteriorData::packData(BitStream *stream)
  61. {
  62. for (S32 i = 0; i < MaxSounds; i++)
  63. {
  64. if (stream->writeFlag(sound[i]))
  65. stream->writeRangedU32(packed? SimObjectId(sound[i]):
  66. sound[i]->getId(),DataBlockObjectIdFirst,DataBlockObjectIdLast);
  67. }
  68. Parent::packData(stream);
  69. }
  70. void PathedInteriorData::unpackData(BitStream* stream)
  71. {
  72. for (S32 i = 0; i < MaxSounds; i++) {
  73. sound[i] = NULL;
  74. if (stream->readFlag())
  75. sound[i] = (SFXProfile*)stream->readRangedU32(DataBlockObjectIdFirst,
  76. DataBlockObjectIdLast);
  77. }
  78. Parent::unpackData(stream);
  79. }
  80. bool PathedInteriorData::preload(bool server, String &errorStr)
  81. {
  82. if(!Parent::preload(server, errorStr))
  83. return false;
  84. // Resolve objects transmitted from server
  85. if (!server)
  86. {
  87. for (S32 i = 0; i < MaxSounds; i++)
  88. if (sound[i])
  89. Sim::findObject(SimObjectId(sound[i]),sound[i]);
  90. }
  91. return true;
  92. }
  93. PathedInterior::PathedInterior()
  94. {
  95. mNetFlags.set(Ghostable);
  96. mTypeMask = InteriorObjectType;
  97. mCurrentPosition = 0;
  98. mTargetPosition = 0;
  99. mPathKey = 0xFFFFFFFF;
  100. mStopped = false;
  101. mSustainSound = NULL;
  102. }
  103. PathedInterior::~PathedInterior()
  104. {
  105. //
  106. }
  107. PathedInterior *PathedInterior::mClientPathedInteriors = NULL;
  108. //--------------------------------------------------------------------------
  109. void PathedInterior::initPersistFields()
  110. {
  111. addField("interiorResource", TypeFilename, Offset(mInteriorResName, PathedInterior));
  112. addField("interiorIndex", TypeS32, Offset(mInteriorResIndex, PathedInterior));
  113. addField("basePosition", TypeMatrixPosition, Offset(mBaseTransform, PathedInterior));
  114. addField("baseRotation", TypeMatrixRotation, Offset(mBaseTransform, PathedInterior));
  115. addField("baseScale", TypePoint3F, Offset(mBaseScale, PathedInterior));
  116. Parent::initPersistFields();
  117. }
  118. //--------------------------------------------------------------------------
  119. bool PathedInterior::onAdd()
  120. {
  121. if(!Parent::onAdd())
  122. return false;
  123. // Load the interior resource and extract the interior that is us.
  124. mInteriorRes = ResourceManager::get().load(mInteriorResName);
  125. if (bool(mInteriorRes) == false)
  126. return false;
  127. mInterior = mInteriorRes->getSubObject(mInteriorResIndex);
  128. if (mInterior == NULL)
  129. return false;
  130. // Setup bounding information
  131. mObjBox = mInterior->getBoundingBox();
  132. resetWorldBox();
  133. setScale(mBaseScale);
  134. setTransform(mBaseTransform);
  135. if (isClientObject()) {
  136. mNextClientPI = mClientPathedInteriors;
  137. mClientPathedInteriors = this;
  138. mInterior->prepForRendering(mInteriorRes.getPath().getFullPath().c_str());
  139. // gInteriorLMManager.addInstance(mInterior->getLMHandle(), mLMHandle, NULL, this);
  140. }
  141. if(isClientObject())
  142. {
  143. Point3F initialPos( 0.0, 0.0, 0.0 );
  144. mBaseTransform.getColumn(3, &initialPos);
  145. Point3F pathPos( 0.0, 0.0, 0.0 );
  146. //gClientPathManager->getPathPosition(mPathKey, 0, pathPos);
  147. mOffset = initialPos - pathPos;
  148. //gClientPathManager->getPathPosition(mPathKey, mCurrentPosition, pathPos);
  149. MatrixF mat = getTransform();
  150. mat.setColumn(3, pathPos + mOffset);
  151. setTransform(mat);
  152. }
  153. addToScene();
  154. return true;
  155. }
  156. bool PathedInterior::onNewDataBlock( GameBaseData *dptr, bool reload )
  157. {
  158. mDataBlock = dynamic_cast<PathedInteriorData*>(dptr);
  159. if ( isClientObject() )
  160. {
  161. SFX_DELETE( mSustainSound );
  162. if ( mDataBlock->sound[PathedInteriorData::SustainSound] )
  163. mSustainSound = SFX->createSource( mDataBlock->sound[PathedInteriorData::SustainSound], &getTransform() );
  164. if ( mSustainSound )
  165. mSustainSound->play();
  166. }
  167. return Parent::onNewDataBlock(dptr,reload);
  168. }
  169. void PathedInterior::onRemove()
  170. {
  171. if(isClientObject())
  172. {
  173. SFX_DELETE( mSustainSound );
  174. PathedInterior **walk = &mClientPathedInteriors;
  175. while(*walk)
  176. {
  177. if(*walk == this)
  178. {
  179. *walk = mNextClientPI;
  180. break;
  181. }
  182. walk = &((*walk)->mNextClientPI);
  183. }
  184. /* if(bool(mInteriorRes) && mLMHandle != 0xFFFFFFFF)
  185. {
  186. if (mInterior->getLMHandle() != 0xFFFFFFFF)
  187. gInteriorLMManager.removeInstance(mInterior->getLMHandle(), mLMHandle);
  188. }*/
  189. }
  190. removeFromScene();
  191. Parent::onRemove();
  192. }
  193. //------------------------------------------------------------------------------
  194. bool PathedInterior::buildPolyList(AbstractPolyList* list, const Box3F& wsBox, const SphereF&)
  195. {
  196. if (bool(mInteriorRes) == false)
  197. return false;
  198. // Setup collision state data
  199. list->setTransform(&getTransform(), getScale());
  200. list->setObject(this);
  201. return mInterior->buildPolyList(list, wsBox, mWorldToObj, getScale());
  202. }
  203. //--------------------------------------------------------------------------
  204. void PathedInterior::prepRenderImage( SceneRenderState* state )
  205. {
  206. if (mPathKey == SimPath::Path::NoPathIndex)
  207. return;
  208. /*
  209. SceneRenderImage* image = new SceneRenderImage;
  210. image->obj = this;
  211. state->insertRenderImage(image);
  212. */
  213. }
  214. extern ColorF gInteriorFogColor;
  215. void PathedInterior::renderObject(SceneRenderState* state)
  216. {
  217. }
  218. void PathedInterior::resolvePathKey()
  219. {
  220. if(mPathKey == 0xFFFFFFFF && !isGhost())
  221. {
  222. mPathKey = getPathKey();
  223. Point3F pathPos( 0.0, 0.0, 0.0 );
  224. Point3F initialPos( 0.0, 0.0, 0.0 );
  225. mBaseTransform.getColumn(3, &initialPos);
  226. //gServerPathManager->getPathPosition(mPathKey, 0, pathPos);
  227. mOffset = initialPos - pathPos;
  228. }
  229. }
  230. //--------------------------------------------------------------------------
  231. U32 PathedInterior::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
  232. {
  233. U32 retMask = Parent::packUpdate(con, mask, stream);
  234. resolvePathKey();
  235. if (stream->writeFlag(mask & InitialUpdateMask))
  236. {
  237. // Inital update...
  238. stream->writeString(mInteriorResName);
  239. stream->write(mInteriorResIndex);
  240. stream->writeAffineTransform(mBaseTransform);
  241. mathWrite(*stream, mBaseScale);
  242. stream->write(mPathKey);
  243. }
  244. if(stream->writeFlag((mask & NewPositionMask) && mPathKey != SimPath::Path::NoPathIndex))
  245. stream->writeInt(S32(mCurrentPosition), gServerPathManager->getPathTimeBits(mPathKey));
  246. if(stream->writeFlag((mask & NewTargetMask) && mPathKey != SimPath::Path::NoPathIndex))
  247. {
  248. if(stream->writeFlag(mTargetPosition < 0))
  249. {
  250. stream->writeFlag(mTargetPosition == -1);
  251. }
  252. else
  253. stream->writeInt(S32(mTargetPosition), gServerPathManager->getPathTimeBits(mPathKey));
  254. }
  255. return retMask;
  256. }
  257. void PathedInterior::unpackUpdate(NetConnection* con, BitStream* stream)
  258. {
  259. Parent::unpackUpdate(con, stream);
  260. MatrixF tempXForm;
  261. Point3F tempScale;
  262. if (stream->readFlag())
  263. {
  264. // Initial
  265. mInteriorResName = stream->readSTString();
  266. stream->read(&mInteriorResIndex);
  267. stream->readAffineTransform(&tempXForm);
  268. mathRead(*stream, &tempScale);
  269. mBaseTransform = tempXForm;
  270. mBaseScale = tempScale;
  271. stream->read(&mPathKey);
  272. }
  273. if(stream->readFlag())
  274. {
  275. Point3F pathPos(0.0f, 0.0f, 0.0f);
  276. mCurrentPosition = stream->readInt(gClientPathManager->getPathTimeBits(mPathKey));
  277. if(isProperlyAdded())
  278. {
  279. //gClientPathManager->getPathPosition(mPathKey, mCurrentPosition, pathPos);
  280. MatrixF mat = getTransform();
  281. mat.setColumn(3, pathPos + mOffset);
  282. setTransform(mat);
  283. }
  284. }
  285. if(stream->readFlag())
  286. {
  287. if(stream->readFlag())
  288. {
  289. mTargetPosition = stream->readFlag() ? -1 : -2;
  290. }
  291. else
  292. mTargetPosition = stream->readInt(gClientPathManager->getPathTimeBits(mPathKey));
  293. }
  294. }
  295. void PathedInterior::processTick(const Move* move)
  296. {
  297. if(isServerObject())
  298. {
  299. S32 timeMs = 32;
  300. if(mCurrentPosition != mTargetPosition)
  301. {
  302. S32 delta;
  303. if(mTargetPosition == -1)
  304. delta = timeMs;
  305. else if(mTargetPosition == -2)
  306. delta = -timeMs;
  307. else
  308. {
  309. delta = mTargetPosition - (S32)mCurrentPosition;
  310. if(delta < -timeMs)
  311. delta = -timeMs;
  312. else if(delta > timeMs)
  313. delta = timeMs;
  314. }
  315. mCurrentPosition += delta;
  316. U32 totalTime = gClientPathManager->getPathTotalTime(mPathKey);
  317. while(mCurrentPosition > totalTime)
  318. mCurrentPosition -= totalTime;
  319. while(mCurrentPosition < 0)
  320. mCurrentPosition += totalTime;
  321. }
  322. }
  323. }
  324. void PathedInterior::computeNextPathStep(U32 timeDelta)
  325. {
  326. S32 timeMs = timeDelta;
  327. mStopped = false;
  328. if(mCurrentPosition == mTargetPosition)
  329. {
  330. mExtrudedBox = getWorldBox();
  331. mCurrentVelocity.set(0,0,0);
  332. }
  333. else
  334. {
  335. S32 delta = 0;
  336. if(mTargetPosition < 0)
  337. {
  338. if(mTargetPosition == -1)
  339. delta = timeMs;
  340. else if(mTargetPosition == -2)
  341. delta = -timeMs;
  342. mCurrentPosition += delta;
  343. U32 totalTime = gClientPathManager->getPathTotalTime(mPathKey);
  344. while(mCurrentPosition >= totalTime)
  345. mCurrentPosition -= totalTime;
  346. while(mCurrentPosition < 0)
  347. mCurrentPosition += totalTime;
  348. }
  349. else
  350. {
  351. delta = mTargetPosition - (S32)mCurrentPosition;
  352. if(delta < -timeMs)
  353. delta = -timeMs;
  354. else if(delta > timeMs)
  355. delta = timeMs;
  356. mCurrentPosition += delta;
  357. }
  358. Point3F curPoint;
  359. Point3F newPoint( 0.0, 0.0, 0.0 );
  360. MatrixF mat = getTransform();
  361. mat.getColumn(3, &curPoint);
  362. //gClientPathManager->getPathPosition(mPathKey, mCurrentPosition, newPoint);
  363. newPoint += mOffset;
  364. Point3F displaceDelta = newPoint - curPoint;
  365. mExtrudedBox = getWorldBox();
  366. if(displaceDelta.x < 0)
  367. mExtrudedBox.minExtents.x += displaceDelta.x;
  368. else
  369. mExtrudedBox.maxExtents.x += displaceDelta.x;
  370. if(displaceDelta.y < 0)
  371. mExtrudedBox.minExtents.y += displaceDelta.y;
  372. else
  373. mExtrudedBox.maxExtents.y += displaceDelta.y;
  374. if(displaceDelta.z < 0)
  375. mExtrudedBox.minExtents.z += displaceDelta.z;
  376. else
  377. mExtrudedBox.maxExtents.z += displaceDelta.z;
  378. mCurrentVelocity = displaceDelta * 1000 / F32(timeDelta);
  379. }
  380. Point3F pos;
  381. mExtrudedBox.getCenter(&pos);
  382. MatrixF mat = getTransform();
  383. mat.setColumn(3, pos);
  384. if ( mSustainSound )
  385. {
  386. mSustainSound->setTransform( mat );
  387. mSustainSound->setVelocity( getVelocity() );
  388. }
  389. }
  390. Point3F PathedInterior::getVelocity()
  391. {
  392. return mCurrentVelocity;
  393. }
  394. void PathedInterior::advance(F64 timeDelta)
  395. {
  396. if(mStopped)
  397. return;
  398. if(mCurrentVelocity.len() == 0)
  399. {
  400. // if(mSustainHandle)
  401. // {
  402. // alxStop(mSustainHandle);
  403. // mSustainHandle = 0;
  404. // }
  405. return;
  406. }
  407. MatrixF mat = getTransform();
  408. Point3F newPoint;
  409. mat.getColumn(3, &newPoint);
  410. newPoint += mCurrentVelocity * timeDelta / 1000.0f;
  411. //gClientPathManager->getPathPosition(mPathKey, mCurrentPosition, newPoint);
  412. mat.setColumn(3, newPoint);// + mOffset);
  413. setTransform(mat);
  414. setRenderTransform(mat);
  415. }
  416. U32 PathedInterior::getPathKey()
  417. {
  418. AssertFatal(isServerObject(), "Error, must be a server object to call this...");
  419. SimGroup* myGroup = getGroup();
  420. AssertFatal(myGroup != NULL, "No group for this object?");
  421. for (SimGroup::iterator itr = myGroup->begin(); itr != myGroup->end(); itr++) {
  422. SimPath::Path* pPath = dynamic_cast<SimPath::Path*>(*itr);
  423. if (pPath != NULL) {
  424. U32 pathKey = pPath->getPathIndex();
  425. AssertFatal(pathKey != SimPath::Path::NoPathIndex, "Error, path must have event over at this point...");
  426. return pathKey;
  427. }
  428. }
  429. return SimPath::Path::NoPathIndex;
  430. }
  431. void PathedInterior::setPathPosition(S32 newPosition)
  432. {
  433. resolvePathKey();
  434. if(newPosition < 0)
  435. newPosition = 0;
  436. if(newPosition > S32(gServerPathManager->getPathTotalTime(mPathKey)))
  437. newPosition = S32(gServerPathManager->getPathTotalTime(mPathKey));
  438. mCurrentPosition = mTargetPosition = newPosition;
  439. setMaskBits(NewPositionMask | NewTargetMask);
  440. }
  441. void PathedInterior::setTargetPosition(S32 newPosition)
  442. {
  443. resolvePathKey();
  444. if(newPosition < -2)
  445. newPosition = 0;
  446. if(newPosition > S32(gServerPathManager->getPathTotalTime(mPathKey)))
  447. newPosition = gServerPathManager->getPathTotalTime(mPathKey);
  448. if(mTargetPosition != newPosition)
  449. {
  450. mTargetPosition = newPosition;
  451. setMaskBits(NewTargetMask);
  452. }
  453. }
  454. ConsoleMethod(PathedInterior, setPathPosition, void, 3, 3, "")
  455. {
  456. ((PathedInterior *) object)->setPathPosition(dAtoi(argv[2]));
  457. }
  458. ConsoleMethod(PathedInterior, setTargetPosition, void, 3, 3, "")
  459. {
  460. ((PathedInterior *) object)->setTargetPosition(dAtoi(argv[2]));
  461. }
  462. //--------------------------------------------------------------------------
  463. bool PathedInterior::readPI(Stream& stream)
  464. {
  465. mName = stream.readSTString();
  466. mInteriorResName = stream.readSTString();
  467. stream.read(&mInteriorResIndex);
  468. stream.read(&mPathIndex);
  469. mathRead(stream, &mOffset);
  470. U32 numTriggers;
  471. stream.read(&numTriggers);
  472. mTriggers.setSize(numTriggers);
  473. for (S32 i = 0; i < mTriggers.size(); i++)
  474. mTriggers[i] = stream.readSTString();
  475. return (stream.getStatus() == Stream::Ok);
  476. }
  477. bool PathedInterior::writePI(Stream& stream) const
  478. {
  479. stream.writeString(mName);
  480. stream.writeString(mInteriorResName);
  481. stream.write(mInteriorResIndex);
  482. stream.write(mPathIndex);
  483. mathWrite(stream, mOffset);
  484. stream.write(mTriggers.size());
  485. for (S32 i = 0; i < mTriggers.size(); i++)
  486. stream.writeString(mTriggers[i]);
  487. return (stream.getStatus() == Stream::Ok);
  488. }
  489. PathedInterior* PathedInterior::clone() const
  490. {
  491. PathedInterior* pClone = new PathedInterior;
  492. pClone->mName = mName;
  493. pClone->mInteriorResName = mInteriorResName;
  494. pClone->mInteriorResIndex = mInteriorResIndex;
  495. pClone->mPathIndex = mPathIndex;
  496. pClone->mOffset = mOffset;
  497. return pClone;
  498. }