entity.cpp 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018
  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 "platform/platform.h"
  23. #include "T3D/entity.h"
  24. #include "core/stream/bitStream.h"
  25. #include "console/consoleTypes.h"
  26. #include "console/consoleObject.h"
  27. #include "sim/netConnection.h"
  28. #include "scene/sceneRenderState.h"
  29. #include "scene/sceneManager.h"
  30. #include "T3D/gameBase/gameProcess.h"
  31. #include "console/engineAPI.h"
  32. #include "T3D/gameBase/gameConnection.h"
  33. #include "math/mathIO.h"
  34. #include "math/mTransform.h"
  35. #include "T3D/components/coreInterfaces.h"
  36. #include "T3D/components/render/renderComponentInterface.h"
  37. #include "T3D/components/collision/collisionComponent.h"
  38. #include "gui/controls/guiTreeViewCtrl.h"
  39. #include "assets/assetManager.h"
  40. #include "assets/assetQuery.h"
  41. #include "T3D/assets/ComponentAsset.h"
  42. #include "console/consoleInternal.h"
  43. #include "T3D/gameBase/std/stdMoveList.h"
  44. #include "T3D/prefab.h"
  45. #include "T3D/gameBase/gameConnection.h"
  46. #include <thread>
  47. //
  48. #include "gfx/sim/debugDraw.h"
  49. //
  50. #include "T3D/sfx/sfx3DWorld.h"
  51. extern bool gEditingMission;
  52. // Client prediction
  53. static F32 sMinWarpTicks = 0.5f; // Fraction of tick at which instant warp occurs
  54. static S32 sMaxWarpTicks = 3; // Max warp duration in ticks
  55. static S32 sMaxPredictionTicks = 30; // Number of ticks to predict
  56. IMPLEMENT_CO_NETOBJECT_V1(Entity);
  57. ConsoleDocClass(Entity,
  58. "@brief Base Entity class.\n\n"
  59. "Entity is typically made up of a shape and up to two particle emitters. In most cases Entity objects are "
  60. "not created directly. They are usually produced automatically by other means, such as through the Explosion "
  61. "class. When an explosion goes off, its ExplosionData datablock determines what Entity to emit.\n"
  62. "@tsexample\n"
  63. "datablock ExplosionData(GrenadeLauncherExplosion)\n"
  64. "{\n"
  65. " // Assiging Entity data\n"
  66. " Entity = GrenadeEntity;\n\n"
  67. " // Adjust how Entity is ejected\n"
  68. " EntityThetaMin = 10;\n"
  69. " EntityThetaMax = 60;\n"
  70. " EntityNum = 4;\n"
  71. " EntityNumVariance = 2;\n"
  72. " EntityVelocity = 25;\n"
  73. " EntityVelocityVariance = 5;\n\n"
  74. " // Note: other ExplosionData properties are not listed for this example\n"
  75. "};\n"
  76. "@endtsexample\n\n"
  77. "@note Entity are client side only objects.\n"
  78. "@see EntityData\n"
  79. "@see ExplosionData\n"
  80. "@see Explosion\n"
  81. "@ingroup FX\n"
  82. );
  83. Entity::Entity()
  84. {
  85. //mTypeMask |= DynamicShapeObjectType | StaticObjectType | ;
  86. mTypeMask |= EntityObjectType;
  87. mNetFlags.set(Ghostable | ScopeAlways);
  88. mPos = Point3F(0, 0, 0);
  89. mRot = Point3F(0, 0, 0);
  90. mDelta.pos = mDelta.posVec = Point3F::Zero;
  91. mDelta.rot[0].identity();
  92. mDelta.rot[1].identity();
  93. mDelta.warpOffset.set(0.0f, 0.0f, 0.0f);
  94. mDelta.warpTicks = mDelta.warpCount = 0;
  95. mDelta.dt = 1.0f;
  96. mDelta.move = NullMove;
  97. mComponents.clear();
  98. mStartComponentUpdate = false;
  99. mInitialized = false;
  100. mLifetimeMS = 0;
  101. mGameObjectAssetId = StringTable->insert("");
  102. }
  103. Entity::~Entity()
  104. {
  105. }
  106. void Entity::initPersistFields()
  107. {
  108. Parent::initPersistFields();
  109. removeField("DataBlock");
  110. addGroup("Transform");
  111. removeField("Position");
  112. addProtectedField("Position", TypePoint3F, Offset(mPos, Entity), &_setPosition, &_getPosition, "Object world orientation.");
  113. removeField("Rotation");
  114. addProtectedField("Rotation", TypeRotationF, Offset(mRot, Entity), &_setRotation, &_getRotation, "Object world orientation.");
  115. //These are basically renamed mountPos/Rot. pretty much there for conveinence
  116. addField("LocalPosition", TypeMatrixPosition, Offset(mMount.xfm, Entity), "Position we are mounted at ( object space of our mount object ).");
  117. addField("LocalRotation", TypeMatrixRotation, Offset(mMount.xfm, Entity), "Rotation we are mounted at ( object space of our mount object ).");
  118. endGroup("Transform");
  119. addGroup("Misc");
  120. addField("LifetimeMS", TypeS32, Offset(mLifetimeMS, Entity), "Object world orientation.");
  121. endGroup("Misc");
  122. addGroup("GameObject");
  123. addProtectedField("gameObjectName", TypeGameObjectAssetPtr, Offset(mGameObjectAsset, Entity), &_setGameObject, &defaultProtectedGetFn,
  124. "The asset Id used for the game object this entity is based on.");
  125. endGroup("GameObject");
  126. }
  127. //
  128. bool Entity::_setPosition(void *object, const char *index, const char *data)
  129. {
  130. Entity* so = static_cast<Entity*>(object);
  131. if (so)
  132. {
  133. Point3F pos;
  134. if (!dStrcmp(data, ""))
  135. pos = Point3F(0, 0, 0);
  136. else
  137. Con::setData(TypePoint3F, &pos, 0, 1, &data);
  138. so->setTransform(pos, so->mRot);
  139. }
  140. return false;
  141. }
  142. const char * Entity::_getPosition(void* obj, const char* data)
  143. {
  144. Entity* so = static_cast<Entity*>(obj);
  145. if (so)
  146. {
  147. Point3F pos = so->getPosition();
  148. static const U32 bufSize = 256;
  149. char* returnBuffer = Con::getReturnBuffer(bufSize);
  150. dSprintf(returnBuffer, bufSize, "%g %g %g", pos.x, pos.y, pos.z);
  151. return returnBuffer;
  152. }
  153. return "0 0 0";
  154. }
  155. bool Entity::_setRotation(void *object, const char *index, const char *data)
  156. {
  157. Entity* so = static_cast<Entity*>(object);
  158. if (so)
  159. {
  160. RotationF rot;
  161. Con::setData(TypeRotationF, &rot, 0, 1, &data);
  162. //so->mRot = rot;
  163. //MatrixF mat = rot.asMatrixF();
  164. //mat.setPosition(so->getPosition());
  165. //so->setTransform(mat);
  166. so->setTransform(so->getPosition(), rot);
  167. }
  168. return false;
  169. }
  170. const char * Entity::_getRotation(void* obj, const char* data)
  171. {
  172. Entity* so = static_cast<Entity*>(obj);
  173. if (so)
  174. {
  175. EulerF eulRot = so->mRot.asEulerF();
  176. static const U32 bufSize = 256;
  177. char* returnBuffer = Con::getReturnBuffer(bufSize);
  178. dSprintf(returnBuffer, bufSize, "%g %g %g", mRadToDeg(eulRot.x), mRadToDeg(eulRot.y), mRadToDeg(eulRot.z));
  179. return returnBuffer;
  180. }
  181. return "0 0 0";
  182. }
  183. bool Entity::onAdd()
  184. {
  185. if (!Parent::onAdd())
  186. return false;
  187. mObjBox = Box3F(Point3F(-0.5, -0.5, -0.5), Point3F(0.5, 0.5, 0.5));
  188. resetWorldBox();
  189. setObjectBox(mObjBox);
  190. addToScene();
  191. //Make sure we get positioned
  192. if (isServerObject())
  193. {
  194. setMaskBits(TransformMask);
  195. setMaskBits(NamespaceMask);
  196. }
  197. else
  198. {
  199. //We can shortcut the initialization here because stuff generally ghosts down in order, and onPostAdd isn't called on ghosts.
  200. onPostAdd();
  201. }
  202. if (mLifetimeMS != 0)
  203. mStartTimeMS = Platform::getRealMilliseconds();
  204. return true;
  205. }
  206. void Entity::onRemove()
  207. {
  208. clearComponents(true);
  209. removeFromScene();
  210. onDataSet.removeAll();
  211. mGameObjectAsset.clear();
  212. Parent::onRemove();
  213. }
  214. void Entity::onPostAdd()
  215. {
  216. mInitialized = true;
  217. //everything's done and added. go ahead and initialize the components
  218. for (U32 i = 0; i < mComponents.size(); i++)
  219. {
  220. mComponents[i]->onComponentAdd();
  221. }
  222. //Set up the networked components
  223. mNetworkedComponents.clear();
  224. for (U32 i = 0; i < mComponents.size(); i++)
  225. {
  226. if (mComponents[i]->isNetworked())
  227. {
  228. NetworkedComponent netComp;
  229. netComp.componentIndex = i;
  230. netComp.updateState = NetworkedComponent::Adding;
  231. netComp.updateMaskBits = -1;
  232. mNetworkedComponents.push_back(netComp);
  233. }
  234. }
  235. if (!mNetworkedComponents.empty())
  236. {
  237. setMaskBits(AddComponentsMask);
  238. setMaskBits(ComponentsUpdateMask);
  239. }
  240. if (isMethod("onAdd"))
  241. Con::executef(this, "onAdd");
  242. }
  243. bool Entity::_setGameObject(void *object, const char *index, const char *data)
  244. {
  245. // Sanity!
  246. AssertFatal(data != NULL, "Cannot use a NULL asset Id.");
  247. return true; //rbI->setMeshAsset(data);
  248. }
  249. void Entity::setDataField(StringTableEntry slotName, const char *array, const char *value)
  250. {
  251. Parent::setDataField(slotName, array, value);
  252. onDataSet.trigger(this, slotName, value);
  253. }
  254. void Entity::onStaticModified(const char* slotName, const char* newValue)
  255. {
  256. Parent::onStaticModified(slotName, newValue);
  257. onDataSet.trigger(this, slotName, newValue);
  258. }
  259. //Updating
  260. void Entity::processTick(const Move* move)
  261. {
  262. if (!isHidden())
  263. {
  264. if (mDelta.warpCount < mDelta.warpTicks)
  265. {
  266. mDelta.warpCount++;
  267. // Set new pos.
  268. mObjToWorld.getColumn(3, &mDelta.pos);
  269. mDelta.pos += mDelta.warpOffset;
  270. mDelta.rot[0] = mDelta.rot[1];
  271. mDelta.rot[1].interpolate(mDelta.warpRot[0], mDelta.warpRot[1], F32(mDelta.warpCount) / mDelta.warpTicks);
  272. setTransform(mDelta.pos, mDelta.rot[1]);
  273. // Pos backstepping
  274. mDelta.posVec.x = -mDelta.warpOffset.x;
  275. mDelta.posVec.y = -mDelta.warpOffset.y;
  276. mDelta.posVec.z = -mDelta.warpOffset.z;
  277. }
  278. else
  279. {
  280. if (isMounted())
  281. {
  282. MatrixF mat;
  283. mMount.object->getMountTransform(mMount.node, mMount.xfm, &mat);
  284. Parent::setTransform(mat);
  285. Parent::setRenderTransform(mat);
  286. }
  287. else
  288. {
  289. if (!move)
  290. {
  291. if (isGhost())
  292. {
  293. // If we haven't run out of prediction time,
  294. // predict using the last known move.
  295. if (mPredictionCount-- <= 0)
  296. return;
  297. move = &mDelta.move;
  298. }
  299. else
  300. {
  301. move = &NullMove;
  302. }
  303. }
  304. }
  305. }
  306. Move prevMove = lastMove;
  307. if (move != NULL)
  308. lastMove = *move;
  309. else
  310. lastMove = NullMove;
  311. if (move && isServerObject())
  312. {
  313. if ((move->y != 0 || prevMove.y != 0)
  314. || (move->x != 0 || prevMove.x != 0)
  315. || (move->z != 0 || prevMove.x != 0))
  316. {
  317. if (isMethod("moveVectorEvent"))
  318. Con::executef(this, "moveVectorEvent", move->x, move->y, move->z);
  319. }
  320. if (move->yaw != 0)
  321. {
  322. if (isMethod("moveYawEvent"))
  323. Con::executef(this, "moveYawEvent", move->yaw);
  324. }
  325. if (move->pitch != 0)
  326. {
  327. if (isMethod("movePitchEvent"))
  328. Con::executef(this, "movePitchEvent", move->pitch);
  329. }
  330. if (move->roll != 0)
  331. {
  332. if (isMethod("moveRollEvent"))
  333. Con::executef(this, "moveRollEvent", move->roll);
  334. }
  335. for (U32 i = 0; i < MaxTriggerKeys; i++)
  336. {
  337. if (move->trigger[i] != prevMove.trigger[i])
  338. {
  339. if (isMethod("moveTriggerEvent"))
  340. Con::executef(this, "moveTriggerEvent", i, move->trigger[i]);
  341. }
  342. }
  343. }
  344. // Save current rigid state interpolation
  345. mDelta.posVec = getPosition();
  346. mDelta.rot[0] = mRot.asQuatF();
  347. //Handle any script updates, which can include physics stuff
  348. if (isServerObject() && isMethod("processTick"))
  349. Con::executef(this, "processTick");
  350. // Wrap up interpolation info
  351. mDelta.pos = getPosition();
  352. mDelta.posVec -= getPosition();
  353. mDelta.rot[1] = mRot.asQuatF();
  354. setTransform(getPosition(), mRot);
  355. //Lifetime test
  356. if (mLifetimeMS != 0)
  357. {
  358. S32 currentTime = Platform::getRealMilliseconds();
  359. if (currentTime - mStartTimeMS >= mLifetimeMS)
  360. deleteObject();
  361. }
  362. }
  363. }
  364. void Entity::advanceTime(F32 dt)
  365. {
  366. }
  367. void Entity::interpolateTick(F32 dt)
  368. {
  369. if (dt == 0.0f)
  370. {
  371. setRenderTransform(mDelta.pos, mDelta.rot[1]);
  372. }
  373. else
  374. {
  375. QuatF rot;
  376. rot.interpolate(mDelta.rot[1], mDelta.rot[0], dt);
  377. Point3F pos = mDelta.pos + mDelta.posVec * dt;
  378. setRenderTransform(pos, rot);
  379. }
  380. mDelta.dt = dt;
  381. }
  382. //Render
  383. void Entity::prepRenderImage(SceneRenderState *state)
  384. {
  385. }
  386. //Networking
  387. U32 Entity::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
  388. {
  389. U32 retMask = Parent::packUpdate(con, mask, stream);
  390. if (stream->writeFlag(mask & TransformMask))
  391. {
  392. stream->writeCompressedPoint(mPos);
  393. mathWrite(*stream, getRotation());
  394. mDelta.move.pack(stream);
  395. stream->writeFlag(!(mask & NoWarpMask));
  396. }
  397. if (stream->writeFlag(mask & BoundsMask))
  398. {
  399. mathWrite(*stream, mObjBox);
  400. }
  401. if (stream->writeFlag(mask & AddComponentsMask))
  402. {
  403. U32 toAddComponentCount = 0;
  404. for (U32 i = 0; i < mNetworkedComponents.size(); i++)
  405. {
  406. if (mNetworkedComponents[i].updateState == NetworkedComponent::Adding)
  407. {
  408. toAddComponentCount++;
  409. }
  410. }
  411. //you reaaaaally shouldn't have >255 networked components on a single entity
  412. stream->writeInt(toAddComponentCount, 8);
  413. for (U32 i = 0; i < mNetworkedComponents.size(); i++)
  414. {
  415. if (mNetworkedComponents[i].updateState == NetworkedComponent::Adding)
  416. {
  417. const char* className = mComponents[mNetworkedComponents[i].componentIndex]->getClassName();
  418. stream->writeString(className, strlen(className));
  419. mNetworkedComponents[i].updateState = NetworkedComponent::Updating;
  420. }
  421. }
  422. }
  423. if (stream->writeFlag(mask & RemoveComponentsMask))
  424. {
  425. /*U32 toRemoveComponentCount = 0;
  426. for (U32 i = 0; i < mNetworkedComponents.size(); i++)
  427. {
  428. if (mNetworkedComponents[i].updateState == NetworkedComponent::Adding)
  429. {
  430. toRemoveComponentCount++;
  431. }
  432. }
  433. //you reaaaaally shouldn't have >255 networked components on a single entity
  434. stream->writeInt(toRemoveComponentCount, 8);
  435. for (U32 i = 0; i < mNetworkedComponents.size(); i++)
  436. {
  437. if (mNetworkedComponents[i].updateState == NetworkedComponent::Removing)
  438. {
  439. stream->writeInt(i, 16);
  440. }
  441. }*/
  442. /*for (U32 i = 0; i < mNetworkedComponents.size(); i++)
  443. {
  444. if (mNetworkedComponents[i].updateState == NetworkedComponent::UpdateState::Removing)
  445. {
  446. removeComponent(mComponents[mNetworkedComponents[i].componentIndex], true);
  447. mNetworkedComponents.erase(i);
  448. i--;
  449. }
  450. }*/
  451. }
  452. //Update our components
  453. if (stream->writeFlag(mask & ComponentsUpdateMask))
  454. {
  455. U32 toUpdateComponentCount = 0;
  456. for (U32 i = 0; i < mNetworkedComponents.size(); i++)
  457. {
  458. if (mNetworkedComponents[i].updateState == NetworkedComponent::Updating)
  459. {
  460. toUpdateComponentCount++;
  461. }
  462. }
  463. //you reaaaaally shouldn't have >255 networked components on a single entity
  464. stream->writeInt(toUpdateComponentCount, 8);
  465. bool forceUpdate = false;
  466. for (U32 i = 0; i < mNetworkedComponents.size(); i++)
  467. {
  468. if (mNetworkedComponents[i].updateState == NetworkedComponent::Updating)
  469. {
  470. stream->writeInt(i, 8);
  471. mNetworkedComponents[i].updateMaskBits = mComponents[mNetworkedComponents[i].componentIndex]->packUpdate(con, mNetworkedComponents[i].updateMaskBits, stream);
  472. if (mNetworkedComponents[i].updateMaskBits != 0)
  473. forceUpdate = true;
  474. else
  475. mNetworkedComponents[i].updateState = NetworkedComponent::None;
  476. }
  477. }
  478. //If we have leftover, we need to re-iterate our packing
  479. if (forceUpdate)
  480. setMaskBits(ComponentsUpdateMask);
  481. }
  482. /*if (stream->writeFlag(mask & NamespaceMask))
  483. {
  484. const char* name = getName();
  485. if (stream->writeFlag(name && name[0]))
  486. stream->writeString(String(name));
  487. if (stream->writeFlag(mSuperClassName && mSuperClassName[0]))
  488. stream->writeString(String(mSuperClassName));
  489. if (stream->writeFlag(mClassName && mClassName[0]))
  490. stream->writeString(String(mClassName));
  491. }*/
  492. return retMask;
  493. }
  494. void Entity::unpackUpdate(NetConnection *con, BitStream *stream)
  495. {
  496. Parent::unpackUpdate(con, stream);
  497. if (stream->readFlag())
  498. {
  499. Point3F pos;
  500. stream->readCompressedPoint(&pos);
  501. RotationF rot;
  502. mathRead(*stream, &rot);
  503. mDelta.move.unpack(stream);
  504. if (stream->readFlag() && isProperlyAdded())
  505. {
  506. // Determine number of ticks to warp based on the average
  507. // of the client and server velocities.
  508. Point3F cp = mDelta.pos + mDelta.posVec * mDelta.dt;
  509. mDelta.warpOffset = pos - cp;
  510. // Calc the distance covered in one tick as the average of
  511. // the old speed and the new speed from the server.
  512. VectorF vel = pos - mDelta.pos;
  513. F32 dt, as = vel.len() * 0.5 * TickSec;
  514. // Cal how many ticks it will take to cover the warp offset.
  515. // If it's less than what's left in the current tick, we'll just
  516. // warp in the remaining time.
  517. if (!as || (dt = mDelta.warpOffset.len() / as) > sMaxWarpTicks)
  518. dt = mDelta.dt + sMaxWarpTicks;
  519. else
  520. dt = (dt <= mDelta.dt) ? mDelta.dt : mCeil(dt - mDelta.dt) + mDelta.dt;
  521. // Adjust current frame interpolation
  522. if (mDelta.dt)
  523. {
  524. mDelta.pos = cp + (mDelta.warpOffset * (mDelta.dt / dt));
  525. mDelta.posVec = (cp - mDelta.pos) / mDelta.dt;
  526. QuatF cr;
  527. cr.interpolate(mDelta.rot[1], mDelta.rot[0], mDelta.dt);
  528. mDelta.rot[1].interpolate(cr, rot.asQuatF(), mDelta.dt / dt);
  529. mDelta.rot[0].extrapolate(mDelta.rot[1], cr, mDelta.dt);
  530. }
  531. // Calculated multi-tick warp
  532. mDelta.warpCount = 0;
  533. mDelta.warpTicks = (S32)(mFloor(dt));
  534. if (mDelta.warpTicks)
  535. {
  536. mDelta.warpOffset = pos - mDelta.pos;
  537. mDelta.warpOffset /= mDelta.warpTicks;
  538. mDelta.warpRot[0] = mDelta.rot[1];
  539. mDelta.warpRot[1] = rot.asQuatF();
  540. }
  541. }
  542. else
  543. {
  544. // Set the entity to the server position
  545. mDelta.dt = 0;
  546. mDelta.pos = pos;
  547. mDelta.posVec.set(0, 0, 0);
  548. mDelta.rot[1] = mDelta.rot[0] = rot.asQuatF();
  549. mDelta.warpCount = mDelta.warpTicks = 0;
  550. setTransform(pos, rot);
  551. }
  552. }
  553. if (stream->readFlag())
  554. {
  555. mathRead(*stream, &mObjBox);
  556. resetWorldBox();
  557. }
  558. //AddComponentMask
  559. if (stream->readFlag())
  560. {
  561. U32 addedComponentCount = stream->readInt(8);
  562. for (U32 i = 0; i < addedComponentCount; i++)
  563. {
  564. char className[256] = "";
  565. stream->readString(className);
  566. //Change to components, so iterate our list and create any new components
  567. // Well, looks like we have to create a new object.
  568. const char* componentType = className;
  569. ConsoleObject *object = ConsoleObject::create(componentType);
  570. // Finally, set currentNewObject to point to the new one.
  571. Component* newComponent = dynamic_cast<Component *>(object);
  572. if (newComponent)
  573. {
  574. addComponent(newComponent);
  575. }
  576. }
  577. }
  578. //RemoveComponentMask
  579. if (stream->readFlag())
  580. {
  581. }
  582. //ComponentUpdateMask
  583. if (stream->readFlag())
  584. {
  585. U32 updatingComponents = stream->readInt(8);
  586. for (U32 i = 0; i < updatingComponents; i++)
  587. {
  588. U32 updateComponentIndex = stream->readInt(8);
  589. Component* comp = mComponents[updateComponentIndex];
  590. comp->unpackUpdate(con, stream);
  591. }
  592. }
  593. /*if (stream->readFlag())
  594. {
  595. if (stream->readFlag())
  596. {
  597. char name[256];
  598. stream->readString(name);
  599. assignName(name);
  600. }
  601. if (stream->readFlag())
  602. {
  603. char superClassname[256];
  604. stream->readString(superClassname);
  605. mSuperClassName = superClassname;
  606. }
  607. if (stream->readFlag())
  608. {
  609. char classname[256];
  610. stream->readString(classname);
  611. mClassName = classname;
  612. }
  613. linkNamespaces();
  614. }*/
  615. }
  616. void Entity::setComponentNetMask(Component* comp, U32 mask)
  617. {
  618. setMaskBits(Entity::ComponentsUpdateMask);
  619. for (U32 i = 0; i < mNetworkedComponents.size(); i++)
  620. {
  621. U32 netCompId = mComponents[mNetworkedComponents[i].componentIndex]->getId();
  622. U32 compId = comp->getId();
  623. if (netCompId == compId &&
  624. (mNetworkedComponents[i].updateState == NetworkedComponent::None || mNetworkedComponents[i].updateState == NetworkedComponent::Updating))
  625. {
  626. mNetworkedComponents[i].updateState = NetworkedComponent::Updating;
  627. mNetworkedComponents[i].updateMaskBits |= mask;
  628. break;
  629. }
  630. }
  631. }
  632. //Manipulation
  633. void Entity::setTransform(const MatrixF &mat)
  634. {
  635. MatrixF oldTransform = getTransform();
  636. if (isMounted())
  637. {
  638. // Use transform from mounted object
  639. Point3F newPos = mat.getPosition();
  640. Point3F parentPos = mMount.object->getTransform().getPosition();
  641. Point3F newOffset = newPos - parentPos;
  642. if (!newOffset.isZero())
  643. {
  644. mPos = newOffset;
  645. }
  646. Point3F matEul = mat.toEuler();
  647. if (matEul != Point3F(0, 0, 0))
  648. {
  649. Point3F mountEul = mMount.object->getTransform().toEuler();
  650. Point3F diff = matEul - mountEul;
  651. mRot = diff;
  652. }
  653. else
  654. {
  655. mRot = Point3F(0, 0, 0);
  656. }
  657. RotationF addRot = mRot + RotationF(mMount.object->getTransform());
  658. MatrixF transf = addRot.asMatrixF();
  659. transf.setPosition(mPos + mMount.object->getPosition());
  660. Parent::setTransform(transf);
  661. if (transf != oldTransform)
  662. setMaskBits(TransformMask);
  663. }
  664. else
  665. {
  666. //Are we part of a prefab?
  667. /*Prefab* p = Prefab::getPrefabByChild(this);
  668. if (p)
  669. {
  670. //just let our prefab know we moved
  671. p->childTransformUpdated(this, mat);
  672. }*/
  673. //else
  674. {
  675. //mRot.set(mat);
  676. //Parent::setTransform(mat);
  677. RotationF rot = RotationF(mat);
  678. EulerF tempRot = rot.asEulerF(RotationF::Degrees);
  679. Point3F pos;
  680. mat.getColumn(3,&pos);
  681. setTransform(pos, rot);
  682. }
  683. }
  684. }
  685. void Entity::setTransform(const Point3F& position, const RotationF& rotation)
  686. {
  687. MatrixF oldTransform = getTransform();
  688. if (isMounted())
  689. {
  690. mPos = position;
  691. mRot = rotation;
  692. RotationF addRot = mRot + RotationF(mMount.object->getTransform());
  693. MatrixF transf = addRot.asMatrixF();
  694. transf.setPosition(mPos + mMount.object->getPosition());
  695. Parent::setTransform(transf);
  696. if (transf != oldTransform)
  697. setMaskBits(TransformMask);
  698. }
  699. else
  700. {
  701. /*MatrixF newMat, imat, xmat, ymat, zmat;
  702. Point3F radRot = Point3F(mDegToRad(rotation.x), mDegToRad(rotation.y), mDegToRad(rotation.z));
  703. xmat.set(EulerF(radRot.x, 0, 0));
  704. ymat.set(EulerF(0.0f, radRot.y, 0.0f));
  705. zmat.set(EulerF(0, 0, radRot.z));
  706. imat.mul(zmat, xmat);
  707. newMat.mul(imat, ymat);*/
  708. MatrixF newMat = rotation.asMatrixF();
  709. newMat.setColumn(3, position);
  710. mPos = position;
  711. mRot = rotation;
  712. //if (isServerObject())
  713. // setMaskBits(TransformMask);
  714. //setTransform(temp);
  715. // This test is a bit expensive so turn it off in release.
  716. #ifdef TORQUE_DEBUG
  717. //AssertFatal( mat.isAffine(), "SceneObject::setTransform() - Bad transform (non affine)!" );
  718. #endif
  719. //PROFILE_SCOPE(Entity_setTransform);
  720. // Update the transforms.
  721. Parent::setTransform(newMat);
  722. U32 compCount = mComponents.size();
  723. for (U32 i = 0; i < compCount; ++i)
  724. {
  725. mComponents[i]->ownerTransformSet(&newMat);
  726. }
  727. Point3F newPos = newMat.getPosition();
  728. RotationF newRot = newMat;
  729. Point3F oldPos = oldTransform.getPosition();
  730. RotationF oldRot = oldTransform;
  731. if (newPos != oldPos || newRot != oldRot)
  732. setMaskBits(TransformMask);
  733. }
  734. }
  735. void Entity::setRenderTransform(const MatrixF &mat)
  736. {
  737. Parent::setRenderTransform(mat);
  738. }
  739. void Entity::setRenderTransform(const Point3F& position, const RotationF& rotation)
  740. {
  741. if (isMounted())
  742. {
  743. mPos = position;
  744. mRot = rotation;
  745. RotationF addRot = mRot + RotationF(mMount.object->getTransform());
  746. MatrixF transf = addRot.asMatrixF();
  747. transf.setPosition(mPos + mMount.object->getPosition());
  748. Parent::setRenderTransform(transf);
  749. }
  750. else
  751. {
  752. MatrixF newMat = rotation.asMatrixF();
  753. newMat.setColumn(3, position);
  754. mPos = position;
  755. mRot = rotation;
  756. Parent::setRenderTransform(newMat);
  757. U32 compCount = mComponents.size();
  758. for (U32 i = 0; i < compCount; ++i)
  759. {
  760. mComponents[i]->ownerTransformSet(&newMat);
  761. }
  762. }
  763. }
  764. MatrixF Entity::getTransform()
  765. {
  766. if (isMounted())
  767. {
  768. MatrixF mat;
  769. //Use transform from mount
  770. mMount.object->getMountTransform(mMount.node, mMount.xfm, &mat);
  771. Point3F transPos = mat.getPosition() + mPos;
  772. mat.mul(mRot.asMatrixF());
  773. mat.setPosition(transPos);
  774. return mat;
  775. }
  776. else
  777. {
  778. return Parent::getTransform();
  779. }
  780. }
  781. void Entity::setMountOffset(const Point3F& posOffset)
  782. {
  783. if (isMounted())
  784. {
  785. mMount.xfm.setColumn(3, posOffset);
  786. //mPos = posOffset;
  787. setMaskBits(MountedMask);
  788. }
  789. }
  790. void Entity::setMountRotation(const EulerF& rotOffset)
  791. {
  792. if (isMounted())
  793. {
  794. MatrixF temp, imat, xmat, ymat, zmat;
  795. Point3F radRot = Point3F(mDegToRad(rotOffset.x), mDegToRad(rotOffset.y), mDegToRad(rotOffset.z));
  796. xmat.set(EulerF(radRot.x, 0, 0));
  797. ymat.set(EulerF(0.0f, radRot.y, 0.0f));
  798. zmat.set(EulerF(0, 0, radRot.z));
  799. imat.mul(zmat, xmat);
  800. temp.mul(imat, ymat);
  801. temp.setColumn(3, mMount.xfm.getPosition());
  802. mMount.xfm = temp;
  803. setMaskBits(MountedMask);
  804. }
  805. }
  806. //
  807. void Entity::getCameraTransform(F32* pos, MatrixF* mat)
  808. {
  809. Vector<CameraInterface*> updaters = getComponents<CameraInterface>();
  810. for (Vector<CameraInterface*>::iterator it = updaters.begin(); it != updaters.end(); it++)
  811. {
  812. if ((*it)->getCameraTransform(pos, mat))
  813. {
  814. return;
  815. }
  816. }
  817. }
  818. void Entity::getMountTransform(S32 index, const MatrixF &xfm, MatrixF *outMat)
  819. {
  820. RenderComponentInterface* renderInterface = getComponent<RenderComponentInterface>();
  821. if (renderInterface)
  822. {
  823. renderInterface->getShapeInstance()->animate();
  824. S32 nodeCount = renderInterface->getShapeInstance()->getShape()->nodes.size();
  825. if (index >= 0 && index < nodeCount)
  826. {
  827. MatrixF mountTransform = renderInterface->getShapeInstance()->mNodeTransforms[index];
  828. mountTransform.mul(xfm);
  829. const Point3F& scale = getScale();
  830. // The position of the mount point needs to be scaled.
  831. Point3F position = mountTransform.getPosition();
  832. position.convolve(scale);
  833. mountTransform.setPosition(position);
  834. // Also we would like the object to be scaled to the model.
  835. outMat->mul(mObjToWorld, mountTransform);
  836. return;
  837. }
  838. }
  839. // Then let SceneObject handle it.
  840. Parent::getMountTransform(index, xfm, outMat);
  841. }
  842. void Entity::getRenderMountTransform(F32 delta, S32 index, const MatrixF &xfm, MatrixF *outMat)
  843. {
  844. RenderComponentInterface* renderInterface = getComponent<RenderComponentInterface>();
  845. if (renderInterface && renderInterface->getShapeInstance())
  846. {
  847. renderInterface->getShapeInstance()->animate();
  848. S32 nodeCount = renderInterface->getShapeInstance()->getShape()->nodes.size();
  849. if (index >= 0 && index < nodeCount)
  850. {
  851. MatrixF mountTransform = renderInterface->getShapeInstance()->mNodeTransforms[index];
  852. mountTransform.mul(xfm);
  853. const Point3F& scale = getScale();
  854. // The position of the mount point needs to be scaled.
  855. Point3F position = mountTransform.getPosition();
  856. position.convolve(scale);
  857. mountTransform.setPosition(position);
  858. // Also we would like the object to be scaled to the model.
  859. outMat->mul(getRenderTransform(), mountTransform);
  860. return;
  861. }
  862. }
  863. // Then let SceneObject handle it.
  864. Parent::getMountTransform(index, xfm, outMat);
  865. }
  866. //
  867. //These basically just redirect to any collision behaviors we have
  868. bool Entity::castRay(const Point3F &start, const Point3F &end, RayInfo* info)
  869. {
  870. Vector<CastRayInterface*> updaters = getComponents<CastRayInterface>();
  871. for (Vector<CastRayInterface*>::iterator it = updaters.begin(); it != updaters.end(); it++)
  872. {
  873. if ((*it)->castRay(start, end, info))
  874. {
  875. return true;
  876. }
  877. }
  878. return false;
  879. }
  880. bool Entity::castRayRendered(const Point3F &start, const Point3F &end, RayInfo *info)
  881. {
  882. Vector<CastRayRenderedInterface*> updaters = getComponents<CastRayRenderedInterface>();
  883. for (Vector<CastRayRenderedInterface*>::iterator it = updaters.begin(); it != updaters.end(); it++)
  884. {
  885. if ((*it)->castRayRendered(start, end, info))
  886. {
  887. return true;
  888. }
  889. }
  890. return false;
  891. }
  892. bool Entity::buildPolyList(PolyListContext context, AbstractPolyList* polyList, const Box3F &box, const SphereF &sphere)
  893. {
  894. Con::errorf("Build Poly List not yet implemented as a passthrough for Entity");
  895. /*Vector<BuildPolyListInterface*> updaters = getComponents<BuildPolyListInterface>();
  896. for (Vector<BuildPolyListInterface*>::iterator it = updaters.begin(); it != updaters.end(); it++)
  897. {
  898. return (*it)->buildPolyList(context, polyList, box, sphere);
  899. }*/
  900. return false;
  901. }
  902. void Entity::buildConvex(const Box3F& box, Convex* convex)
  903. {
  904. Vector<CollisionComponent*> colliders = getComponents<CollisionComponent>();
  905. for (Vector<CollisionComponent*>::iterator it = colliders.begin(); it != colliders.end(); it++)
  906. {
  907. (*it)->buildConvex(box, convex);
  908. }
  909. }
  910. //
  911. // Mounting and heirarchy manipulation
  912. void Entity::mountObject(SceneObject* objB, const MatrixF& txfm)
  913. {
  914. Parent::mountObject(objB, -1, txfm);
  915. Parent::addObject(objB);
  916. }
  917. void Entity::mountObject(SceneObject *obj, S32 node, const MatrixF &xfm)
  918. {
  919. Parent::mountObject(obj, node, xfm);
  920. }
  921. void Entity::onMount(SceneObject *obj, S32 node)
  922. {
  923. deleteNotify(obj);
  924. // Are we mounting to a GameBase object?
  925. Entity *entityObj = dynamic_cast<Entity*>(obj);
  926. if (entityObj && entityObj->getControlObject() != this)
  927. processAfter(entityObj);
  928. if (!isGhost()) {
  929. setMaskBits(MountedMask);
  930. //TODO implement this callback
  931. //onMount_callback( this, obj, node );
  932. }
  933. }
  934. void Entity::onUnmount(SceneObject *obj, S32 node)
  935. {
  936. clearNotify(obj);
  937. Entity *entityObj = dynamic_cast<Entity*>(obj);
  938. if (entityObj && entityObj->getControlObject() != this)
  939. clearProcessAfter();
  940. if (!isGhost()) {
  941. setMaskBits(MountedMask);
  942. //TODO implement this callback
  943. //onUnmount_callback( this, obj, node );
  944. }
  945. }
  946. void Entity::setControllingClient(GameConnection* client)
  947. {
  948. if (isGhost() && gSFX3DWorld)
  949. {
  950. if (gSFX3DWorld->getListener() == this && !client && getControllingClient() && getControllingClient()->isConnectionToServer())
  951. {
  952. // We are the current listener and are no longer a controller object on the
  953. // connection, so clear our listener status.
  954. gSFX3DWorld->setListener(NULL);
  955. }
  956. else if (client && client->isConnectionToServer() && !getControllingObject())
  957. {
  958. // We're on the local client and not controlled by another object, so make
  959. // us the current SFX listener.
  960. gSFX3DWorld->setListener(this);
  961. }
  962. }
  963. Parent::setControllingClient(client);
  964. }
  965. //Heirarchy stuff
  966. void Entity::addObject(SimObject* object)
  967. {
  968. Component* component = dynamic_cast<Component*>(object);
  969. if (component)
  970. {
  971. addComponent(component);
  972. return;
  973. }
  974. Entity* e = dynamic_cast<Entity*>(object);
  975. if (e)
  976. {
  977. MatrixF offset;
  978. //offset.mul(getWorldTransform(), e->getWorldTransform());
  979. //check if we're mounting to a node on a shape we have
  980. String node = e->getDataField("mountNode", NULL);
  981. if (!node.isEmpty())
  982. {
  983. RenderComponentInterface *renderInterface = getComponent<RenderComponentInterface>();
  984. if (renderInterface)
  985. {
  986. TSShape* shape = renderInterface->getShape();
  987. S32 nodeIdx = shape->findNode(node);
  988. mountObject(e, nodeIdx, MatrixF::Identity);
  989. }
  990. else
  991. {
  992. mountObject(e, MatrixF::Identity);
  993. }
  994. }
  995. else
  996. {
  997. /*Point3F posOffset = mPos - e->getPosition();
  998. mPos = posOffset;
  999. RotationF rotOffset = mRot - e->getRotation();
  1000. mRot = rotOffset;
  1001. setMaskBits(TransformMask);
  1002. mountObject(e, MatrixF::Identity);*/
  1003. mountObject(e, MatrixF::Identity);
  1004. }
  1005. //e->setMountOffset(e->getPosition() - getPosition());
  1006. //Point3F diff = getWorldTransform().toEuler() - e->getWorldTransform().toEuler();
  1007. //e->setMountRotation(Point3F(mRadToDeg(diff.x),mRadToDeg(diff.y),mRadToDeg(diff.z)));
  1008. //mountObject(e, offset);
  1009. }
  1010. else
  1011. {
  1012. SceneObject* so = dynamic_cast<SceneObject*>(object);
  1013. if (so)
  1014. {
  1015. //get the difference and build it as our offset!
  1016. Point3F posOffset = so->getPosition() - mPos;
  1017. RotationF rotOffset = RotationF(so->getTransform()) - mRot;
  1018. MatrixF offset = rotOffset.asMatrixF();
  1019. offset.setPosition(posOffset);
  1020. mountObject(so, offset);
  1021. return;
  1022. }
  1023. }
  1024. Parent::addObject(object);
  1025. }
  1026. void Entity::removeObject(SimObject* object)
  1027. {
  1028. Entity* e = dynamic_cast<Entity*>(object);
  1029. if (e)
  1030. {
  1031. mPos = mPos + e->getPosition();
  1032. mRot = mRot + e->getRotation();
  1033. unmountObject(e);
  1034. setMaskBits(TransformMask);
  1035. }
  1036. else
  1037. {
  1038. SceneObject* so = dynamic_cast<SceneObject*>(object);
  1039. if (so)
  1040. unmountObject(so);
  1041. }
  1042. Parent::removeObject(object);
  1043. }
  1044. bool Entity::addComponent(Component *comp)
  1045. {
  1046. if (comp == NULL)
  1047. return false;
  1048. //double-check were not re-adding anything
  1049. mComponents.push_back(comp);
  1050. // Register the component with this owner.
  1051. comp->setOwner(this);
  1052. comp->setIsServerObject(isServerObject());
  1053. //if we've already been added and this is being added after the fact(at runtime),
  1054. //then just go ahead and call it's onComponentAdd so it can get to work
  1055. //if (mInitialized)
  1056. {
  1057. comp->onComponentAdd();
  1058. if (comp->isNetworked())
  1059. {
  1060. NetworkedComponent netComp;
  1061. netComp.componentIndex = mComponents.size() - 1;
  1062. netComp.updateState = NetworkedComponent::Adding;
  1063. netComp.updateMaskBits = -1;
  1064. mNetworkedComponents.push_back(netComp);
  1065. setMaskBits(AddComponentsMask);
  1066. setMaskBits(ComponentsUpdateMask);
  1067. }
  1068. }
  1069. onComponentAdded.trigger(comp);
  1070. return true;
  1071. }
  1072. SimObject* Entity::findObjectByInternalName(StringTableEntry internalName, bool searchChildren)
  1073. {
  1074. for (U32 i = 0; i < mComponents.size(); i++)
  1075. {
  1076. if (mComponents[i]->getInternalName() == internalName)
  1077. {
  1078. return mComponents[i];
  1079. }
  1080. }
  1081. return Parent::findObjectByInternalName(internalName, searchChildren);
  1082. }
  1083. //////////////////////////////////////////////////////////////////////////
  1084. bool Entity::removeComponent(Component *comp, bool deleteComponent)
  1085. {
  1086. if (comp == NULL)
  1087. return false;
  1088. if(mComponents.remove(comp))
  1089. {
  1090. AssertFatal(comp->isProperlyAdded(), "Don't know how but a component is not registered w/ the sim");
  1091. //setComponentsDirty();
  1092. onComponentRemoved.trigger(comp);
  1093. comp->onComponentRemove(); //in case the behavior needs to do cleanup on the owner
  1094. comp->setOwner(NULL);
  1095. if (deleteComponent)
  1096. comp->safeDeleteObject();
  1097. return true;
  1098. }
  1099. return false;
  1100. }
  1101. //////////////////////////////////////////////////////////////////////////
  1102. //NOTE:
  1103. //The actor class calls this and flags the deletion of the behaviors to false so that behaviors that should no longer be attached during
  1104. //a network update will indeed be removed from the object. The reason it doesn't delete them is because when clearing the local behavior
  1105. //list, it would delete them, purging the ghost, and causing a crash when the unpack update tried to fetch any existing behaviors' ghosts
  1106. //to re-add them. Need to implement a clean clear function that will clear the local list, and only delete unused behaviors during an update.
  1107. void Entity::clearComponents(bool deleteComponents)
  1108. {
  1109. if (!deleteComponents)
  1110. {
  1111. while (mComponents.size() > 0)
  1112. {
  1113. removeComponent(mComponents.first(), deleteComponents);
  1114. }
  1115. }
  1116. else
  1117. {
  1118. while (mComponents.size() > 0)
  1119. {
  1120. Component* comp = mComponents.first();
  1121. if (comp)
  1122. {
  1123. comp->onComponentRemove(); //in case the behavior needs to do cleanup on the owner
  1124. comp->deleteObject();
  1125. }
  1126. }
  1127. }
  1128. }
  1129. //////////////////////////////////////////////////////////////////////////
  1130. Component *Entity::getComponent(const U32 index) const
  1131. {
  1132. if (index < mComponents.size())
  1133. return mComponents[index];
  1134. return NULL;
  1135. }
  1136. Component *Entity::getComponent(String componentType)
  1137. {
  1138. for (U32 i = 0; i < mComponents.size(); i++)
  1139. {
  1140. Component* comp = mComponents[i];
  1141. /*String namespaceName = comp->getNamespace()->mName;
  1142. //check our namespace first
  1143. if (namespaceName == componentType)
  1144. {
  1145. return comp;
  1146. }
  1147. else
  1148. {*/
  1149. //lets scan up, just to be sure
  1150. Namespace *NS = comp->getNamespace();
  1151. //we shouldn't ever go past Component into net object, as we're no longer dealing with component classes
  1152. while (dStrcmp(NS->getName(), "SimObject"))
  1153. {
  1154. String namespaceName = NS->getName();
  1155. if (namespaceName == componentType)
  1156. {
  1157. return comp;
  1158. }
  1159. else
  1160. {
  1161. NS = NS->getParent();
  1162. }
  1163. }
  1164. //}
  1165. }
  1166. return NULL;
  1167. }
  1168. void Entity::onInspect()
  1169. {
  1170. Vector<EditorInspectInterface*> updaters = getComponents<EditorInspectInterface>();
  1171. for (Vector<EditorInspectInterface*>::iterator it = updaters.begin(); it != updaters.end(); it++)
  1172. {
  1173. (*it)->onInspect();
  1174. }
  1175. }
  1176. void Entity::onEndInspect()
  1177. {
  1178. Vector<EditorInspectInterface*> updaters = getComponents<EditorInspectInterface>();
  1179. for (Vector<EditorInspectInterface*>::iterator it = updaters.begin(); it != updaters.end(); it++) {
  1180. (*it)->onEndInspect();
  1181. }
  1182. GuiTreeViewCtrl *editorTree = dynamic_cast<GuiTreeViewCtrl*>(Sim::findObject("EditorTree"));
  1183. if (!editorTree)
  1184. return;
  1185. S32 componentItemIdx = editorTree->findItemByName("Components");
  1186. editorTree->removeItem(componentItemIdx, false);
  1187. }
  1188. static void writeTabs(Stream &stream, U32 count)
  1189. {
  1190. char tab[] = " ";
  1191. while (count--)
  1192. stream.write(3, (void*)tab);
  1193. }
  1194. void Entity::write(Stream &stream, U32 tabStop, U32 flags)
  1195. {
  1196. // Do *not* call parent on this
  1197. /*VectorPtr<ComponentObject *> &componentList = lockComponentList();
  1198. // export selected only?
  1199. if( ( flags & SelectedOnly ) && !isSelected() )
  1200. {
  1201. for( BehaviorObjectIterator i = componentList.begin(); i != componentList.end(); i++ )
  1202. (*i)->write(stream, tabStop, flags);
  1203. goto write_end;
  1204. }*/
  1205. //catch if we have any written behavior fields already in the file, and clear them. We don't need to double-up
  1206. //the entries for no reason.
  1207. /*if(getFieldDictionary())
  1208. {
  1209. //get our dynamic field count, then parse through them to see if they're a behavior or not
  1210. //reset it
  1211. SimFieldDictionary* fieldDictionary = getFieldDictionary();
  1212. SimFieldDictionaryIterator itr(fieldDictionary);
  1213. for (S32 i = 0; i < fieldDictionary->getNumFields(); i++)
  1214. {
  1215. if (!(*itr))
  1216. break;
  1217. SimFieldDictionary::Entry* entry = *itr;
  1218. if(strstr(entry->slotName, "_behavior"))
  1219. {
  1220. entry->slotName = "";
  1221. entry->value = "";
  1222. }
  1223. ++itr;
  1224. }
  1225. }*/
  1226. //all existing written behavior fields should be cleared. now write the object block
  1227. writeTabs(stream, tabStop);
  1228. char buffer[1024];
  1229. dSprintf(buffer, sizeof(buffer), "new %s(%s) {\r\n", getClassName(), getName() ? getName() : "");
  1230. stream.write(dStrlen(buffer), buffer);
  1231. writeFields(stream, tabStop + 1);
  1232. stream.write(1, "\n");
  1233. ////first, write out our behavior objects
  1234. // NOW we write the behavior fields proper
  1235. if (mComponents.size() > 0)
  1236. {
  1237. // Pack out the behaviors into fields
  1238. for (U32 i = 0; i < mComponents.size(); i++)
  1239. {
  1240. writeTabs(stream, tabStop + 1);
  1241. dSprintf(buffer, sizeof(buffer), "new %s() {\r\n", mComponents[i]->getClassName());
  1242. stream.write(dStrlen(buffer), buffer);
  1243. //bi->writeFields( stream, tabStop + 2 );
  1244. mComponents[i]->packToStream(stream, tabStop + 2, i - 1, flags);
  1245. writeTabs(stream, tabStop + 1);
  1246. stream.write(4, "};\r\n");
  1247. }
  1248. }
  1249. //
  1250. //if (size() > 0)
  1251. // stream.write(2, "\r\n");
  1252. for (U32 i = 0; i < size(); i++)
  1253. {
  1254. SimObject* child = (*this)[i];
  1255. if (child->getCanSave())
  1256. child->write(stream, tabStop + 1, flags);
  1257. }
  1258. //stream.write(2, "\r\n");
  1259. writeTabs(stream, tabStop);
  1260. stream.write(4, "};\r\n");
  1261. //write_end:
  1262. //unlockComponentList();
  1263. }
  1264. SimObject* Entity::getTamlChild(const U32 childIndex) const
  1265. {
  1266. // Sanity!
  1267. AssertFatal(childIndex < getTamlChildCount(), "SimSet::getTamlChild() - Child index is out of range.");
  1268. // For when the assert is not used.
  1269. if (childIndex >= getTamlChildCount())
  1270. return NULL;
  1271. //we always order components first, child objects second
  1272. if (childIndex >= getComponentCount())
  1273. return at(childIndex - getComponentCount());
  1274. else
  1275. return getComponent(childIndex);
  1276. }
  1277. //
  1278. void Entity::onCameraScopeQuery(NetConnection* connection, CameraScopeQuery* query)
  1279. {
  1280. // Object itself is in scope.
  1281. Parent::onCameraScopeQuery(connection, query);
  1282. if (CameraInterface* cI = getComponent<CameraInterface>())
  1283. {
  1284. cI->onCameraScopeQuery(connection, query);
  1285. }
  1286. }
  1287. //
  1288. void Entity::setObjectBox(const Box3F& objBox)
  1289. {
  1290. mObjBox = objBox;
  1291. resetWorldBox();
  1292. if (isServerObject())
  1293. setMaskBits(BoundsMask);
  1294. }
  1295. void Entity::updateContainer()
  1296. {
  1297. PROFILE_SCOPE(Entity_updateContainer);
  1298. // Update container drag and buoyancy properties
  1299. containerInfo.box = getWorldBox();
  1300. //containerInfo.mass = mMass;
  1301. getContainer()->findObjects(containerInfo.box, WaterObjectType | PhysicalZoneObjectType, findRouter, &containerInfo);
  1302. //mWaterCoverage = info.waterCoverage;
  1303. //mLiquidType = info.liquidType;
  1304. //mLiquidHeight = info.waterHeight;
  1305. //setCurrentWaterObject( info.waterObject );
  1306. // This value might be useful as a datablock value,
  1307. // This is what allows the player to stand in shallow water (below this coverage)
  1308. // without jiggling from buoyancy
  1309. /*if (info.waterCoverage >= 0.25f)
  1310. {
  1311. // water viscosity is used as drag for in water.
  1312. // ShapeBaseData drag is used for drag outside of water.
  1313. // Combine these two components to calculate this ShapeBase object's
  1314. // current drag.
  1315. mDrag = (info.waterCoverage * info.waterViscosity) +
  1316. (1.0f - info.waterCoverage) * mDrag;
  1317. //mBuoyancy = (info.waterDensity / mDataBlock->density) * info.waterCoverage;
  1318. }
  1319. //mAppliedForce = info.appliedForce;
  1320. mGravityMod = info.gravityScale;*/
  1321. }
  1322. //
  1323. void Entity::notifyComponents(String signalFunction, String argA, String argB, String argC, String argD, String argE)
  1324. {
  1325. for (U32 i = 0; i < mComponents.size(); i++)
  1326. {
  1327. // We can do this because both are in the string table
  1328. Component *comp = mComponents[i];
  1329. if (comp->isActive())
  1330. {
  1331. if (comp->isMethod(signalFunction))
  1332. Con::executef(comp, signalFunction, argA, argB, argC, argD, argE);
  1333. }
  1334. }
  1335. }
  1336. void Entity::setComponentsDirty()
  1337. {
  1338. /*if (mToLoadComponents.empty())
  1339. mStartComponentUpdate = true;
  1340. //we need to build a list of behaviors that need to be pushed across the network
  1341. for (U32 i = 0; i < mComponents.size(); i++)
  1342. {
  1343. // We can do this because both are in the string table
  1344. Component *comp = mComponents[i];
  1345. if (comp->isNetworked())
  1346. {
  1347. bool unique = true;
  1348. for (U32 i = 0; i < mToLoadComponents.size(); i++)
  1349. {
  1350. if (mToLoadComponents[i]->getId() == comp->getId())
  1351. {
  1352. unique = false;
  1353. break;
  1354. }
  1355. }
  1356. if (unique)
  1357. mToLoadComponents.push_back(comp);
  1358. }
  1359. }
  1360. setMaskBits(ComponentsMask);*/
  1361. }
  1362. void Entity::setComponentDirty(Component *comp, bool forceUpdate)
  1363. {
  1364. for (U32 i = 0; i < mComponents.size(); i++)
  1365. {
  1366. if (mComponents[i]->getId() == comp->getId())
  1367. {
  1368. mComponents[i]->setOwner(this);
  1369. return;
  1370. }
  1371. }
  1372. //if (!found)
  1373. // return;
  1374. //if(mToLoadComponents.empty())
  1375. // mStartComponentUpdate = true;
  1376. /*if (comp->isNetworked() || forceUpdate)
  1377. {
  1378. bool unique = true;
  1379. for (U32 i = 0; i < mToLoadComponents.size(); i++)
  1380. {
  1381. if (mToLoadComponents[i]->getId() == comp->getId())
  1382. {
  1383. unique = false;
  1384. break;
  1385. }
  1386. }
  1387. if (unique)
  1388. mToLoadComponents.push_back(comp);
  1389. }
  1390. setMaskBits(ComponentsMask);*/
  1391. }
  1392. DefineEngineMethod(Entity, mountObject, bool,
  1393. (SceneObject* objB, TransformF txfm), (MatrixF::Identity),
  1394. "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
  1395. "@param objB Object to mount onto us\n"
  1396. "@param slot Mount slot ID\n"
  1397. "@param txfm (optional) mount offset transform\n"
  1398. "@return true if successful, false if failed (objB is not valid)")
  1399. {
  1400. if (objB)
  1401. {
  1402. //BUG: Unsure how it broke, but atm the default transform passed in here is rotated 180 degrees. This doesn't happen
  1403. //for the SceneObject mountobject method. Hackish, but for now, just default to a clean MatrixF::Identity
  1404. object->mountObject(objB, /*MatrixF::Identity*/txfm.getMatrix());
  1405. return true;
  1406. }
  1407. return false;
  1408. }
  1409. DefineEngineMethod(Entity, setMountOffset, void,
  1410. (Point3F posOffset), (Point3F(0, 0, 0)),
  1411. "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
  1412. "@param objB Object to mount onto us\n"
  1413. "@param slot Mount slot ID\n"
  1414. "@param txfm (optional) mount offset transform\n"
  1415. "@return true if successful, false if failed (objB is not valid)")
  1416. {
  1417. object->setMountOffset(posOffset);
  1418. }
  1419. DefineEngineMethod(Entity, setMountRotation, void,
  1420. (EulerF rotOffset), (EulerF(0, 0, 0)),
  1421. "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
  1422. "@param objB Object to mount onto us\n"
  1423. "@param slot Mount slot ID\n"
  1424. "@param txfm (optional) mount offset transform\n"
  1425. "@return true if successful, false if failed (objB is not valid)")
  1426. {
  1427. object->setMountRotation(rotOffset);
  1428. }
  1429. DefineEngineMethod(Entity, getMountTransform, TransformF, (), ,
  1430. "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
  1431. "@param objB Object to mount onto us\n"
  1432. "@param slot Mount slot ID\n"
  1433. "@param txfm (optional) mount offset transform\n"
  1434. "@return true if successful, false if failed (objB is not valid)")
  1435. {
  1436. MatrixF mat;
  1437. object->getMountTransform(0, MatrixF::Identity, &mat);
  1438. return mat;
  1439. }
  1440. DefineEngineMethod(Entity, setBox, void,
  1441. (Point3F box), (Point3F(1, 1, 1)),
  1442. "@brief Mount objB to this object at the desired slot with optional transform.\n\n"
  1443. "@param objB Object to mount onto us\n"
  1444. "@param slot Mount slot ID\n"
  1445. "@param txfm (optional) mount offset transform\n"
  1446. "@return true if successful, false if failed (objB is not valid)")
  1447. {
  1448. object->setObjectBox(Box3F(-box, box));
  1449. }
  1450. /*DefineEngineMethod(Entity, callOnComponents, void, (const char* functionName), ,
  1451. "Get the number of static fields on the object.\n"
  1452. "@return The number of static fields defined on the object.")
  1453. {
  1454. object->callOnComponents(functionName);
  1455. }
  1456. ConsoleMethod(Entity, callMethod, void, 3, 64, "(methodName, argi) Calls script defined method\n"
  1457. "@param methodName The method's name as a string\n"
  1458. "@param argi Any arguments to pass to the method\n"
  1459. "@return No return value"
  1460. "@note %obj.callMethod( %methodName, %arg1, %arg2, ... );\n")
  1461. {
  1462. object->callMethodArgList(argc - 1, argv + 2);
  1463. }
  1464. ConsoleMethod(Entity, addComponents, void, 2, 2, "() - Add all fielded behaviors\n"
  1465. "@return No return value")
  1466. {
  1467. object->addComponents();
  1468. }*/
  1469. DefineEngineMethod(Entity, addComponent, bool, (Component* comp),,
  1470. "@brief Add a behavior to the object\n"
  1471. "@param bi The behavior instance to add"
  1472. "@return (bool success) Whether or not the behavior was successfully added")
  1473. {
  1474. if (comp != NULL)
  1475. {
  1476. bool success = object->addComponent(comp);
  1477. if (success)
  1478. {
  1479. //Placed here so we can differentiate against adding a new behavior during runtime, or when we load all
  1480. //fielded behaviors on mission load. This way, we can ensure that we only call the callback
  1481. //once everything is loaded. This avoids any problems with looking for behaviors that haven't been added yet, etc.
  1482. if (comp->isMethod("onBehaviorAdd"))
  1483. Con::executef(comp, "onBehaviorAdd");
  1484. return true;
  1485. }
  1486. }
  1487. return false;
  1488. }
  1489. DefineEngineMethod(Entity, removeComponent, bool, (Component* comp, bool deleteComponent), (true),
  1490. "@param bi The behavior instance to remove\n"
  1491. "@param deleteBehavior Whether or not to delete the behavior\n"
  1492. "@return (bool success) Whether the behavior was successfully removed")
  1493. {
  1494. return object->removeComponent(comp, deleteComponent);
  1495. }
  1496. DefineEngineMethod(Entity, clearComponents, void, (),, "Clear all behavior instances\n"
  1497. "@return No return value")
  1498. {
  1499. object->clearComponents();
  1500. }
  1501. DefineEngineMethod(Entity, getComponentByIndex, Component*, (S32 index),,
  1502. "@brief Gets a particular behavior\n"
  1503. "@param index The index of the behavior to get\n"
  1504. "@return (ComponentInstance bi) The behavior instance you requested")
  1505. {
  1506. return object->getComponent(index);
  1507. }
  1508. DefineEngineMethod(Entity, getComponent, Component*, (String componentName), (""),
  1509. "Get the number of static fields on the object.\n"
  1510. "@return The number of static fields defined on the object.")
  1511. {
  1512. return object->getComponent(componentName);
  1513. }
  1514. /*ConsoleMethod(Entity, getBehaviorByType, S32, 3, 3, "(string BehaviorTemplateName) - gets a behavior\n"
  1515. "@param BehaviorTemplateName The name of the template of the behavior instance you want\n"
  1516. "@return (ComponentInstance bi) The behavior instance you requested")
  1517. {
  1518. ComponentInstance *bInstance = object->getComponentByType(StringTable->insert(argv[2]));
  1519. return (bInstance != NULL) ? bInstance->getId() : 0;
  1520. }*/
  1521. /*ConsoleMethod(Entity, reOrder, bool, 3, 3, "(ComponentInstance inst, [int desiredIndex = 0])\n"
  1522. "@param inst The behavior instance you want to reorder\n"
  1523. "@param desiredIndex The index you want the behavior instance to be reordered to\n"
  1524. "@return (bool success) Whether or not the behavior instance was successfully reordered")
  1525. {
  1526. Component *inst = dynamic_cast<Component *>(Sim::findObject(argv[1]));
  1527. if (inst == NULL)
  1528. return false;
  1529. U32 idx = 0;
  1530. if (argc > 2)
  1531. idx = dAtoi(argv[2]);
  1532. return object->reOrder(inst, idx);
  1533. }*/
  1534. DefineEngineMethod(Entity, getComponentCount, S32, (),,
  1535. "@brief Get the count of behaviors on an object\n"
  1536. "@return (int count) The number of behaviors on an object")
  1537. {
  1538. return object->getComponentCount();
  1539. }
  1540. DefineEngineMethod(Entity, setComponentDirty, void, (S32 componentID, bool forceUpdate), (0, false),
  1541. "Get the number of static fields on the object.\n"
  1542. "@return The number of static fields defined on the object.")
  1543. {
  1544. /*Component* comp;
  1545. if (Sim::findObject(componentID, comp))
  1546. object->setComponentDirty(comp, forceUpdate);*/
  1547. }
  1548. DefineEngineMethod(Entity, getMoveVector, VectorF, (),,
  1549. "Get the number of static fields on the object.\n"
  1550. "@return The number of static fields defined on the object.")
  1551. {
  1552. //fetch our last move
  1553. if (object->lastMove.x != 0 || object->lastMove.y != 0 || object->lastMove.z != 0)
  1554. return VectorF(object->lastMove.x, object->lastMove.y, object->lastMove.z);
  1555. return VectorF::Zero;
  1556. }
  1557. DefineEngineMethod(Entity, getMoveRotation, VectorF, (), ,
  1558. "Get the number of static fields on the object.\n"
  1559. "@return The number of static fields defined on the object.")
  1560. {
  1561. //fetch our last move
  1562. if (object->lastMove.pitch != 0 || object->lastMove.roll != 0 || object->lastMove.yaw != 0)
  1563. return VectorF(object->lastMove.pitch, object->lastMove.roll, object->lastMove.yaw);
  1564. return VectorF::Zero;
  1565. }
  1566. DefineEngineMethod(Entity, getMoveTrigger, bool, (S32 triggerNum), (0),
  1567. "Get the number of static fields on the object.\n"
  1568. "@return The number of static fields defined on the object.")
  1569. {
  1570. if (object->getControllingClient() != NULL && triggerNum < MaxTriggerKeys)
  1571. {
  1572. return object->lastMove.trigger[triggerNum];
  1573. }
  1574. return false;
  1575. }
  1576. DefineEngineMethod(Entity, getForwardVector, VectorF, (), ,
  1577. "Get the direction this object is facing.\n"
  1578. "@return a vector indicating the direction this object is facing.\n"
  1579. "@note This is the object's y axis.")
  1580. {
  1581. VectorF forVec = object->getTransform().getForwardVector();
  1582. return forVec;
  1583. }
  1584. DefineEngineMethod(Entity, setForwardVector, void, (VectorF newForward), (VectorF(0,0,0)),
  1585. "Get the number of static fields on the object.\n"
  1586. "@return The number of static fields defined on the object.")
  1587. {
  1588. object->setForwardVector(newForward);
  1589. }
  1590. DefineEngineMethod(Entity, lookAt, void, (Point3F lookPosition),,
  1591. "Get the number of static fields on the object.\n"
  1592. "@return The number of static fields defined on the object.")
  1593. {
  1594. //object->setForwardVector(newForward);
  1595. }
  1596. DefineEngineMethod(Entity, rotateTo, void, (Point3F lookPosition, F32 degreePerSecond), (1.0),
  1597. "Get the number of static fields on the object.\n"
  1598. "@return The number of static fields defined on the object.")
  1599. {
  1600. //object->setForwardVector(newForward);
  1601. }
  1602. DefineEngineMethod(Entity, notify, void, (String signalFunction, String argA, String argB, String argC, String argD, String argE),
  1603. ("", "", "", "", "", ""),
  1604. "Triggers a signal call to all components for a certain function.")
  1605. {
  1606. if (signalFunction == String(""))
  1607. return;
  1608. object->notifyComponents(signalFunction, argA, argB, argC, argD, argE);
  1609. }
  1610. DefineEngineFunction(findEntitiesByTag, const char*, (SimGroup* searchingGroup, String tags), (nullAsType<SimGroup*>(), ""),
  1611. "Finds all entities that have the provided tags.\n"
  1612. "@param searchingGroup The SimGroup to search inside. If null, we'll search the entire dictionary(this can be slow!).\n"
  1613. "@param tags Word delimited list of tags to search for. If multiple tags are included, the list is eclusively parsed, requiring all tags provided to be found on an entity for a match.\n"
  1614. "@return A word list of IDs of entities that match the tag search terms.")
  1615. {
  1616. //if (tags.isEmpty())
  1617. return "";
  1618. /*if (searchingGroup == nullptr)
  1619. {
  1620. searchingGroup = Sim::getRootGroup();
  1621. }
  1622. StringTableEntry entityStr = StringTable->insert("Entity");
  1623. std::thread threadBob;
  1624. std::thread::id a = threadBob.get_id();
  1625. std::thread::id b = std::this_thread::get_id().;
  1626. if (a == b)
  1627. {
  1628. //do
  1629. }
  1630. for (SimGroup::iterator itr = searchingGroup->begin(); itr != searchingGroup->end(); itr++)
  1631. {
  1632. Entity* ent = dynamic_cast<Entity*>((*itr));
  1633. if (ent != nullptr)
  1634. {
  1635. ent->mTags.
  1636. }
  1637. }
  1638. object->notifyComponents(signalFunction, argA, argB, argC, argD, argE);*/
  1639. }