netGhost.cpp 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294
  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 "core/dnet.h"
  24. #include "console/simBase.h"
  25. #include "sim/netConnection.h"
  26. #include "core/stream/bitStream.h"
  27. #include "sim/netObject.h"
  28. //#include "core/resManager.h"
  29. #include "console/console.h"
  30. #include "console/consoleTypes.h"
  31. #include "console/engineAPI.h"
  32. #define DebugChecksum 0xF00DBAAD
  33. Signal<void()> NetConnection::smGhostAlwaysDone;
  34. extern U32 gGhostUpdates;
  35. class GhostAlwaysObjectEvent : public NetEvent
  36. {
  37. SimObjectId objectId;
  38. U32 ghostIndex;
  39. NetObject *object;
  40. bool validObject;
  41. public:
  42. typedef NetEvent Parent;
  43. GhostAlwaysObjectEvent(NetObject *obj = NULL, U32 index = 0)
  44. {
  45. if(obj)
  46. {
  47. objectId = obj->getId();
  48. ghostIndex = index;
  49. }
  50. object = NULL;
  51. }
  52. ~GhostAlwaysObjectEvent()
  53. { delete object; }
  54. void pack(NetConnection *ps, BitStream *bstream)
  55. {
  56. bstream->writeInt(ghostIndex, NetConnection::GhostIdBitSize);
  57. NetObject *obj = (NetObject *) Sim::findObject(objectId);
  58. if(bstream->writeFlag(obj != NULL))
  59. {
  60. S32 classId = obj->getClassId(ps->getNetClassGroup());
  61. bstream->writeClassId(classId, NetClassTypeObject, ps->getNetClassGroup());
  62. #ifdef TORQUE_NET_STATS
  63. U32 beginSize = bstream->getBitPosition();
  64. #endif
  65. U32 retMask = obj->packUpdate(ps, 0xFFFFFFFF, bstream);
  66. if ( retMask != 0 ) obj->setMaskBits( retMask );
  67. #ifdef TORQUE_NET_STATS
  68. obj->getClassRep()->updateNetStatPack(0xFFFFFFFF, bstream->getBitPosition() - beginSize);
  69. #endif
  70. }
  71. }
  72. void write(NetConnection *ps, BitStream *bstream)
  73. {
  74. bstream->writeInt(ghostIndex, NetConnection::GhostIdBitSize);
  75. if(bstream->writeFlag(validObject))
  76. {
  77. S32 classId = object->getClassId(ps->getNetClassGroup());
  78. bstream->writeClassId(classId, NetClassTypeObject, ps->getNetClassGroup());
  79. #ifdef TORQUE_NET_STATS
  80. U32 beginSize = bstream->getBitPosition();
  81. #endif
  82. U32 retMask = object->packUpdate(ps, 0xFFFFFFFF, bstream);
  83. if ( retMask != 0 ) object->setMaskBits( retMask );
  84. #ifdef TORQUE_NET_STATS
  85. object->getClassRep()->updateNetStatPack(0xFFFFFFFF, bstream->getBitPosition() - beginSize);
  86. #endif
  87. }
  88. }
  89. void unpack(NetConnection *ps, BitStream *bstream)
  90. {
  91. ghostIndex = bstream->readInt(NetConnection::GhostIdBitSize);
  92. if(bstream->readFlag())
  93. {
  94. S32 classId = bstream->readClassId(NetClassTypeObject, ps->getNetClassGroup());
  95. if(classId == -1)
  96. {
  97. ps->setLastError("Invalid packet. (invalid ghost class id)");
  98. return;
  99. }
  100. object = (NetObject *) ConsoleObject::create(ps->getNetClassGroup(), NetClassTypeObject, classId);
  101. if(!object)
  102. {
  103. ps->setLastError("Invalid packet. (failed to created from class id)");
  104. return;
  105. }
  106. object->mNetFlags = NetObject::IsGhost;
  107. object->mNetIndex = ghostIndex;
  108. #ifdef TORQUE_NET_STATS
  109. U32 beginSize = bstream->getBitPosition();
  110. #endif
  111. object->unpackUpdate(ps, bstream);
  112. #ifdef TORQUE_NET_STATS
  113. object->getClassRep()->updateNetStatUnpack(bstream->getBitPosition() - beginSize);
  114. #endif
  115. validObject = true;
  116. }
  117. else
  118. {
  119. object = new NetObject;
  120. validObject = false;
  121. }
  122. }
  123. void process(NetConnection *ps)
  124. {
  125. Con::executef("onGhostAlwaysObjectReceived");
  126. ps->setGhostAlwaysObject(object, ghostIndex);
  127. object = NULL;
  128. }
  129. DECLARE_CONOBJECT(GhostAlwaysObjectEvent);
  130. };
  131. IMPLEMENT_CO_NETEVENT_V1(GhostAlwaysObjectEvent);
  132. ConsoleDocClass( GhostAlwaysObjectEvent,
  133. "@brief Legacy or soon to be locked down object.\n\n"
  134. "Not intended for game development, for editors or internal use only.\n\n "
  135. "@internal");
  136. DefineEngineMethod( NetConnection, getGhostsActive, S32, (),,
  137. "@brief Provides the number of active ghosts on the connection.\n\n"
  138. "@returns The number of active ghosts.\n"
  139. "@see @ref ghosting_scoping for a description of the ghosting system.\n\n")
  140. {
  141. return object->getGhostsActive();
  142. }
  143. void NetConnection::setGhostTo(bool ghostTo)
  144. {
  145. if(mLocalGhosts) // if ghosting to this is already enabled, silently return
  146. return;
  147. if(ghostTo)
  148. {
  149. mLocalGhosts = new NetObject *[MaxGhostCount];
  150. for(S32 i = 0; i < MaxGhostCount; i++)
  151. mLocalGhosts[i] = NULL;
  152. }
  153. }
  154. void NetConnection::setGhostFrom(bool ghostFrom)
  155. {
  156. if(mGhostArray)
  157. return;
  158. if(ghostFrom)
  159. {
  160. mGhostFreeIndex = mGhostZeroUpdateIndex = 0;
  161. mGhostArray = new GhostInfo *[MaxGhostCount];
  162. mGhostRefs = new GhostInfo[MaxGhostCount];
  163. S32 i;
  164. for(i = 0; i < MaxGhostCount; i++)
  165. {
  166. mGhostRefs[i].obj = NULL;
  167. mGhostRefs[i].index = i;
  168. mGhostRefs[i].updateMask = 0;
  169. }
  170. mGhostLookupTable = new GhostInfo *[GhostLookupTableSize];
  171. for(i = 0; i < GhostLookupTableSize; i++)
  172. mGhostLookupTable[i] = 0;
  173. }
  174. }
  175. void NetConnection::ghostOnRemove()
  176. {
  177. if(mGhostArray)
  178. clearGhostInfo();
  179. }
  180. void NetConnection::ghostPacketDropped(PacketNotify *notify)
  181. {
  182. GhostRef *packRef = notify->ghostList;
  183. // loop through all the packRefs in the packet
  184. while(packRef)
  185. {
  186. GhostRef *temp = packRef->nextRef;
  187. U32 orFlags = 0;
  188. AssertFatal(packRef->nextUpdateChain == NULL, "Out of order notify!!");
  189. // clear out the ref for this object, plus or together all
  190. // flags from updates after this
  191. GhostRef **walk = &(packRef->ghost->updateChain);
  192. while(*walk != packRef)
  193. {
  194. orFlags |= (*walk)->mask;
  195. walk = &((*walk)->nextUpdateChain);
  196. }
  197. *walk = 0;
  198. // for any flags we haven't updated since this (dropped) packet
  199. // or them into the mask so they'll get updated soon
  200. orFlags = packRef->mask & ~orFlags;
  201. if(orFlags)
  202. {
  203. if(!packRef->ghost->updateMask)
  204. {
  205. packRef->ghost->updateMask = orFlags;
  206. ghostPushNonZero(packRef->ghost);
  207. }
  208. else
  209. packRef->ghost->updateMask |= orFlags;
  210. }
  211. // if this packet was ghosting an object, set it
  212. // to re ghost at it's earliest convenience
  213. if(packRef->ghostInfoFlags & GhostInfo::Ghosting)
  214. {
  215. packRef->ghost->flags |= GhostInfo::NotYetGhosted;
  216. packRef->ghost->flags &= ~GhostInfo::Ghosting;
  217. }
  218. // otherwise, if it was being deleted,
  219. // set it to re-delete
  220. else if(packRef->ghostInfoFlags & GhostInfo::KillingGhost)
  221. {
  222. packRef->ghost->flags |= GhostInfo::KillGhost;
  223. packRef->ghost->flags &= ~GhostInfo::KillingGhost;
  224. }
  225. delete packRef;
  226. packRef = temp;
  227. }
  228. }
  229. void NetConnection::ghostPacketReceived(PacketNotify *notify)
  230. {
  231. GhostRef *packRef = notify->ghostList;
  232. // loop through all the notifies in this packet
  233. while(packRef)
  234. {
  235. GhostRef *temp = packRef->nextRef;
  236. AssertFatal(packRef->nextUpdateChain == NULL, "Out of order notify!!");
  237. // clear this notify from the end of the object's notify
  238. // chain
  239. GhostRef **walk = &(packRef->ghost->updateChain);
  240. while(*walk != packRef)
  241. walk = &((*walk)->nextUpdateChain);
  242. *walk = 0;
  243. // if this object was ghosting , it is now ghosted
  244. if(packRef->ghostInfoFlags & GhostInfo::Ghosting)
  245. packRef->ghost->flags &= ~GhostInfo::Ghosting;
  246. // otherwise, if it was dieing, free the ghost
  247. else if(packRef->ghostInfoFlags & GhostInfo::KillingGhost)
  248. freeGhostInfo(packRef->ghost);
  249. delete packRef;
  250. packRef = temp;
  251. }
  252. }
  253. struct UpdateQueueEntry
  254. {
  255. F32 priority;
  256. GhostInfo *obj;
  257. UpdateQueueEntry(F32 in_priority, GhostInfo *in_obj)
  258. { priority = in_priority; obj = in_obj; }
  259. };
  260. static S32 QSORT_CALLBACK UQECompare(const void *a,const void *b)
  261. {
  262. GhostInfo *ga = *((GhostInfo **) a);
  263. GhostInfo *gb = *((GhostInfo **) b);
  264. F32 ret = ga->priority - gb->priority;
  265. return (ret < 0) ? -1 : ((ret > 0) ? 1 : 0);
  266. }
  267. void NetConnection::ghostWritePacket(BitStream *bstream, PacketNotify *notify)
  268. {
  269. #ifdef TORQUE_DEBUG_NET
  270. bstream->writeInt(DebugChecksum, 32);
  271. #endif
  272. notify->ghostList = NULL;
  273. if(!isGhostingFrom())
  274. return;
  275. if(!bstream->writeFlag(mGhosting))
  276. return;
  277. // fill a packet (or two) with ghosting data
  278. // first step is to check all our polled ghosts:
  279. // 1. Scope query - find if any new objects have come into
  280. // scope and if any have gone out.
  281. // 2. call scoped objects' priority functions if the flag set is nonzero
  282. // A removed ghost is assumed to have a high priority
  283. // 3. call updates based on sorted priority until the packet is
  284. // full. set flags to zero for all updated objects
  285. CameraScopeQuery camInfo;
  286. camInfo.camera = NULL;
  287. camInfo.pos.set(0,0,0);
  288. camInfo.orientation.set(0,1,0);
  289. camInfo.visibleDistance = 1;
  290. camInfo.fov = (F32)(3.1415f / 4.0f);
  291. camInfo.sinFov = 0.7071f;
  292. camInfo.cosFov = 0.7071f;
  293. GhostInfo *walk;
  294. // only need to worry about the ghosts that have update masks set...
  295. S32 maxIndex = 0;
  296. S32 i;
  297. for(i = 0; i < mGhostZeroUpdateIndex; i++)
  298. {
  299. // increment the updateSkip for everyone... it's all good
  300. walk = mGhostArray[i];
  301. walk->updateSkipCount++;
  302. if(!(walk->flags & (GhostInfo::ScopeAlways | GhostInfo::ScopeLocalAlways)))
  303. walk->flags &= ~GhostInfo::InScope;
  304. }
  305. if( mScopeObject )
  306. mScopeObject->onCameraScopeQuery( this, &camInfo );
  307. doneScopingScene();
  308. for(i = mGhostZeroUpdateIndex - 1; i >= 0; i--)
  309. {
  310. // [rene, 07-Mar-11] Killing ghosts depending on the camera scope queries
  311. // seems like a bad thing to me and something that definitely has the potential
  312. // of causing scoping to eat into bandwidth rather than preserve it. As soon
  313. // as an object comes back into scope, it will have to completely retransmit its
  314. // full server-side state from scratch.
  315. if(!(mGhostArray[i]->flags & GhostInfo::InScope))
  316. detachObject(mGhostArray[i]);
  317. }
  318. for(i = mGhostZeroUpdateIndex - 1; i >= 0; i--)
  319. {
  320. walk = mGhostArray[i];
  321. if(walk->index > maxIndex)
  322. maxIndex = walk->index;
  323. // clear out any kill objects that haven't been ghosted yet
  324. if((walk->flags & GhostInfo::KillGhost) && (walk->flags & GhostInfo::NotYetGhosted))
  325. {
  326. freeGhostInfo(walk);
  327. continue;
  328. }
  329. // don't do any ghost processing on objects that are being killed
  330. // or in the process of ghosting
  331. else if(!(walk->flags & (GhostInfo::KillingGhost | GhostInfo::Ghosting)))
  332. {
  333. if(walk->flags & GhostInfo::KillGhost)
  334. walk->priority = 10000;
  335. else
  336. walk->priority = walk->obj->getUpdatePriority(&camInfo, walk->updateMask, walk->updateSkipCount);
  337. }
  338. else
  339. walk->priority = 0;
  340. }
  341. GhostRef *updateList = NULL;
  342. dQsort(mGhostArray, mGhostZeroUpdateIndex, sizeof(GhostInfo *), UQECompare);
  343. // reset the array indices...
  344. for(i = mGhostZeroUpdateIndex - 1; i >= 0; i--)
  345. mGhostArray[i]->arrayIndex = i;
  346. S32 sendSize = 1;
  347. while(maxIndex >>= 1)
  348. sendSize++;
  349. if(sendSize < 3)
  350. sendSize = 3;
  351. bstream->writeInt(sendSize - 3, GhostIndexBitSize);
  352. U32 count = 0;
  353. //
  354. for(i = mGhostZeroUpdateIndex - 1; i >= 0 && !bstream->isFull(); i--)
  355. {
  356. GhostInfo *walk = mGhostArray[i];
  357. if(walk->flags & (GhostInfo::KillingGhost | GhostInfo::Ghosting))
  358. continue;
  359. bstream->writeFlag(true);
  360. bstream->writeInt(walk->index, sendSize);
  361. U32 updateMask = walk->updateMask;
  362. GhostRef *upd = new GhostRef;
  363. upd->nextRef = updateList;
  364. updateList = upd;
  365. upd->nextUpdateChain = walk->updateChain;
  366. walk->updateChain = upd;
  367. upd->ghost = walk;
  368. upd->ghostInfoFlags = 0;
  369. if(walk->flags & GhostInfo::KillGhost)
  370. {
  371. walk->flags &= ~GhostInfo::KillGhost;
  372. walk->flags |= GhostInfo::KillingGhost;
  373. walk->updateMask = 0;
  374. upd->mask = updateMask;
  375. ghostPushToZero(walk);
  376. upd->ghostInfoFlags = GhostInfo::KillingGhost;
  377. bstream->writeFlag(true); // killing ghost
  378. }
  379. else
  380. {
  381. bstream->writeFlag(false);
  382. #ifdef TORQUE_DEBUG_NET
  383. U32 startPos = bstream->getCurPos();
  384. #endif
  385. if(walk->flags & GhostInfo::NotYetGhosted)
  386. {
  387. S32 classId = walk->obj->getClassId(getNetClassGroup());
  388. bstream->writeClassId(classId, NetClassTypeObject, getNetClassGroup());
  389. #ifdef TORQUE_DEBUG_NET
  390. bstream->writeInt(classId ^ DebugChecksum, 32);
  391. #endif
  392. walk->flags &= ~GhostInfo::NotYetGhosted;
  393. walk->flags |= GhostInfo::Ghosting;
  394. upd->ghostInfoFlags = GhostInfo::Ghosting;
  395. }
  396. #ifdef TORQUE_DEBUG_NET
  397. else {
  398. S32 classId = walk->obj->getClassId(getNetClassGroup());
  399. bstream->writeClassId(classId, NetClassTypeObject, getNetClassGroup());
  400. bstream->writeInt(classId ^ DebugChecksum, 32);
  401. }
  402. #endif
  403. // update the object
  404. #ifdef TORQUE_NET_STATS
  405. U32 beginSize = bstream->getBitPosition();
  406. #endif
  407. U32 retMask = walk->obj->packUpdate(this, updateMask, bstream);
  408. #ifdef TORQUE_NET_STATS
  409. walk->obj->getClassRep()->updateNetStatPack(updateMask, bstream->getBitPosition() - beginSize);
  410. #endif
  411. DEBUG_LOG(("PKLOG %d GHOST %d: %s", getId(), bstream->getBitPosition() - 16 - startPos, walk->obj->getClassName()));
  412. AssertFatal((retMask & (~updateMask)) == 0, "Cannot set new bits in packUpdate return");
  413. ghostWriteExtra(walk->obj,bstream);
  414. walk->updateMask = retMask;
  415. if(!retMask)
  416. ghostPushToZero(walk);
  417. upd->mask = updateMask & ~retMask;
  418. //PacketStream::getStats()->addBits(PacketStats::Send, bstream->getCurPos() - startPos, walk->obj->getPersistTag());
  419. #ifdef TORQUE_DEBUG_NET
  420. bstream->writeInt(walk->index ^ DebugChecksum, 32);
  421. #endif
  422. }
  423. walk->updateSkipCount = 0;
  424. count++;
  425. }
  426. //Con::printf("Ghosts updated: %d (%d remain)", count, mGhostZeroUpdateIndex);
  427. // no more objects...
  428. bstream->writeFlag(false);
  429. notify->ghostList = updateList;
  430. }
  431. void NetConnection::ghostReadPacket(BitStream *bstream)
  432. {
  433. #ifdef TORQUE_DEBUG_NET
  434. U32 sum = bstream->readInt(32);
  435. AssertISV(sum == DebugChecksum, "Invalid checksum.");
  436. #endif
  437. if(!isGhostingTo())
  438. return;
  439. if(!bstream->readFlag())
  440. return;
  441. S32 idSize;
  442. idSize = bstream->readInt( GhostIndexBitSize);
  443. idSize += 3;
  444. // while there's an object waiting...
  445. gGhostUpdates = 0;
  446. while(bstream->readFlag())
  447. {
  448. gGhostUpdates++;
  449. U32 index;
  450. //S32 startPos = bstream->getCurPos();
  451. index = (U32) bstream->readInt(idSize);
  452. if(bstream->readFlag()) // is this ghost being deleted?
  453. {
  454. mGhostsActive--;
  455. AssertFatal(mLocalGhosts[index] != NULL, "Error, NULL ghost encountered.");
  456. mLocalGhosts[index]->deleteObject();
  457. mLocalGhosts[index] = NULL;
  458. }
  459. else
  460. {
  461. if(!mLocalGhosts[index]) // it's a new ghost... cool
  462. {
  463. mGhostsActive++;
  464. S32 classId = bstream->readClassId(NetClassTypeObject, getNetClassGroup());
  465. if(classId == -1)
  466. {
  467. setLastError("Invalid packet. (invalid new ghost class id)");
  468. return;
  469. }
  470. NetObject *obj = (NetObject *) ConsoleObject::create(getNetClassGroup(), NetClassTypeObject, classId);
  471. if(!obj)
  472. {
  473. setLastError("Invalid packet. (failed to create new ghost)");
  474. return;
  475. }
  476. // remove all flags associated with netobject
  477. obj->mNetFlags &= ~(BIT(NetObject::MaxNetFlagBit+1)-1);
  478. // we're a ghost...
  479. obj->mNetFlags |= NetObject::IsGhost;
  480. // object gets initial update before adding to the manager
  481. obj->mNetIndex = index;
  482. mLocalGhosts[index] = obj;
  483. #ifdef TORQUE_DEBUG_NET
  484. U32 checksum = bstream->readInt(32);
  485. S32 origId = checksum ^ DebugChecksum;
  486. AssertISV(mLocalGhosts[index] != NULL, "Invalid dest ghost.");
  487. AssertISV(origId == mLocalGhosts[index]->getClassId(getNetClassGroup()),
  488. avar("class id mismatch for dest class %s.",
  489. mLocalGhosts[index]->getClassName()) );
  490. #endif
  491. // give derived classes a chance to prepare ghost for reading
  492. ghostPreRead(mLocalGhosts[index],true);
  493. #ifdef TORQUE_NET_STATS
  494. U32 beginSize = bstream->getBitPosition();
  495. #endif
  496. mLocalGhosts[index]->unpackUpdate(this, bstream);
  497. #ifdef TORQUE_NET_STATS
  498. mLocalGhosts[index]->getClassRep()->updateNetStatUnpack(bstream->getBitPosition() - beginSize);
  499. #endif
  500. // Setup the remote object pointers before
  501. // we register so that it can be used from onAdd.
  502. if( mRemoteConnection )
  503. {
  504. obj->mServerObject = mRemoteConnection->resolveObjectFromGhostIndex(index);
  505. if ( obj->mServerObject )
  506. {
  507. obj->mServerObject->mClientObject = obj;
  508. // Sync selection flag as otherwise the editor will end up setting only
  509. // server-side flags when selecting an object that hasn't been ghosted yet
  510. // (usually the case when creating new objects).
  511. if( obj->mServerObject->isSelected() )
  512. obj->setSelected( true );
  513. }
  514. }
  515. if(!obj->registerObject())
  516. {
  517. if(mErrorBuffer.isEmpty())
  518. setLastError("Invalid packet. (failed to register ghost)");
  519. return;
  520. }
  521. addObject(obj);
  522. ghostReadExtra(mLocalGhosts[index],bstream,true);
  523. }
  524. else
  525. {
  526. #ifdef TORQUE_DEBUG_NET
  527. S32 classId = bstream->readClassId(NetClassTypeObject, getNetClassGroup());
  528. U32 checksum = bstream->readInt(32);
  529. S32 origId = checksum ^ DebugChecksum;
  530. AssertISV(mLocalGhosts[index] != NULL, "Invalid dest ghost.");
  531. AssertISV(origId == mLocalGhosts[index]->getClassId(getNetClassGroup()),
  532. avar("class id mismatch for dest class %s.",
  533. mLocalGhosts[index]->getClassName()) );
  534. #endif
  535. // give derived classes a chance to prepare ghost for reading
  536. ghostPreRead(mLocalGhosts[index],false);
  537. #ifdef TORQUE_NET_STATS
  538. U32 beginSize = bstream->getBitPosition();
  539. #endif
  540. mLocalGhosts[index]->unpackUpdate(this, bstream);
  541. #ifdef TORQUE_NET_STATS
  542. mLocalGhosts[index]->getClassRep()->updateNetStatUnpack(bstream->getBitPosition() - beginSize);
  543. #endif
  544. ghostReadExtra(mLocalGhosts[index],bstream,false);
  545. }
  546. //PacketStream::getStats()->addBits(PacketStats::Receive, bstream->getCurPos() - startPos, ghostRefs[index].localGhost->getPersistTag());
  547. #ifdef TORQUE_DEBUG_NET
  548. U32 checksum = bstream->readInt(32);
  549. S32 origIndex = checksum ^ DebugChecksum;
  550. AssertISV(origIndex == index,
  551. avar("unpackUpdate did not match packUpdate for object of class %s.",
  552. mLocalGhosts[index]->getClassName()) );
  553. #endif
  554. if(mErrorBuffer.isNotEmpty())
  555. return;
  556. }
  557. }
  558. }
  559. //-----------------------------------------------------------------------------
  560. //-----------------------------------------------------------------------------
  561. void NetConnection::setScopeObject(NetObject *obj)
  562. {
  563. if(((NetObject *) mScopeObject) == obj)
  564. return;
  565. mScopeObject = obj;
  566. }
  567. void NetConnection::detachObject(GhostInfo *info)
  568. {
  569. // mark it for ghost killin'
  570. info->flags |= GhostInfo::KillGhost;
  571. // if the mask is in the zero range, we've got to move it up...
  572. if(!info->updateMask)
  573. {
  574. info->updateMask = 0xFFFFFFFF;
  575. ghostPushNonZero(info);
  576. }
  577. if(info->obj)
  578. {
  579. if(info->prevObjectRef)
  580. info->prevObjectRef->nextObjectRef = info->nextObjectRef;
  581. else
  582. info->obj->mFirstObjectRef = info->nextObjectRef;
  583. if(info->nextObjectRef)
  584. info->nextObjectRef->prevObjectRef = info->prevObjectRef;
  585. // remove it from the lookup table
  586. U32 id = info->obj->getId();
  587. for(GhostInfo **walk = &mGhostLookupTable[id & (GhostLookupTableSize - 1)]; *walk; walk = &((*walk)->nextLookupInfo))
  588. {
  589. GhostInfo *temp = *walk;
  590. if(temp == info)
  591. {
  592. *walk = temp->nextLookupInfo;
  593. break;
  594. }
  595. }
  596. info->prevObjectRef = info->nextObjectRef = NULL;
  597. info->obj = NULL;
  598. }
  599. }
  600. void NetConnection::freeGhostInfo(GhostInfo *ghost)
  601. {
  602. AssertFatal(ghost->arrayIndex < mGhostFreeIndex, "Ghost already freed.");
  603. if(ghost->arrayIndex < mGhostZeroUpdateIndex)
  604. {
  605. AssertFatal(ghost->updateMask != 0, "Invalid ghost mask.");
  606. ghost->updateMask = 0;
  607. ghostPushToZero(ghost);
  608. }
  609. ghostPushZeroToFree(ghost);
  610. AssertFatal(ghost->updateChain == NULL, "Ack!");
  611. }
  612. //-----------------------------------------------------------------------------
  613. void NetConnection::objectLocalScopeAlways(NetObject *obj)
  614. {
  615. if(!isGhostingFrom())
  616. return;
  617. objectInScope(obj);
  618. for(GhostInfo *walk = mGhostLookupTable[obj->getId() & (GhostLookupTableSize - 1)]; walk; walk = walk->nextLookupInfo)
  619. {
  620. if(walk->obj != obj)
  621. continue;
  622. walk->flags |= GhostInfo::ScopeLocalAlways;
  623. return;
  624. }
  625. }
  626. void NetConnection::objectLocalClearAlways(NetObject *obj)
  627. {
  628. if(!isGhostingFrom())
  629. return;
  630. for(GhostInfo *walk = mGhostLookupTable[obj->getId() & (GhostLookupTableSize - 1)]; walk; walk = walk->nextLookupInfo)
  631. {
  632. if(walk->obj != obj)
  633. continue;
  634. walk->flags &= ~GhostInfo::ScopeLocalAlways;
  635. return;
  636. }
  637. }
  638. bool NetConnection::validateGhostArray()
  639. {
  640. AssertFatal(mGhostZeroUpdateIndex >= 0 && mGhostZeroUpdateIndex <= mGhostFreeIndex, "Invalid update index range.");
  641. AssertFatal(mGhostFreeIndex <= MaxGhostCount, "Invalid free index range.");
  642. U32 i;
  643. for(i = 0; i < mGhostZeroUpdateIndex; i ++)
  644. {
  645. AssertFatal(mGhostArray[i]->arrayIndex == i, "Invalid array index.");
  646. AssertFatal(mGhostArray[i]->updateMask != 0, "Invalid ghost mask.");
  647. }
  648. for(; i < mGhostFreeIndex; i ++)
  649. {
  650. AssertFatal(mGhostArray[i]->arrayIndex == i, "Invalid array index.");
  651. AssertFatal(mGhostArray[i]->updateMask == 0, "Invalid ghost mask.");
  652. }
  653. for(; i < MaxGhostCount; i++)
  654. {
  655. AssertFatal(mGhostArray[i]->arrayIndex == i, "Invalid array index.");
  656. }
  657. return true;
  658. }
  659. void NetConnection::objectInScope(NetObject *obj)
  660. {
  661. if (!mScoping || !isGhostingFrom())
  662. return;
  663. if (obj->isScopeLocal() && !isLocalConnection())
  664. return;
  665. S32 index = obj->getId() & (GhostLookupTableSize - 1);
  666. // check if it's already in scope
  667. // the object may have been cleared out without the lookupTable being cleared
  668. // so validate that the object pointers are the same.
  669. for(GhostInfo *walk = mGhostLookupTable[index ]; walk; walk = walk->nextLookupInfo)
  670. {
  671. if(walk->obj != obj)
  672. continue;
  673. walk->flags |= GhostInfo::InScope;
  674. // Make sure scope always if reflected on the ghostinfo too
  675. if (obj->mNetFlags.test(NetObject::ScopeAlways))
  676. walk->flags |= GhostInfo::ScopeAlways;
  677. return;
  678. }
  679. if (mGhostFreeIndex == MaxGhostCount)
  680. {
  681. AssertWarn(0,"NetConnection::objectInScope: too many ghosts");
  682. return;
  683. }
  684. GhostInfo *giptr = mGhostArray[mGhostFreeIndex];
  685. ghostPushFreeToZero(giptr);
  686. giptr->updateMask = 0xFFFFFFFF;
  687. ghostPushNonZero(giptr);
  688. giptr->flags = GhostInfo::NotYetGhosted | GhostInfo::InScope;
  689. if(obj->mNetFlags.test(NetObject::ScopeAlways))
  690. giptr->flags |= GhostInfo::ScopeAlways;
  691. giptr->obj = obj;
  692. giptr->updateChain = NULL;
  693. giptr->updateSkipCount = 0;
  694. giptr->connection = this;
  695. giptr->nextObjectRef = obj->mFirstObjectRef;
  696. if(obj->mFirstObjectRef)
  697. obj->mFirstObjectRef->prevObjectRef = giptr;
  698. giptr->prevObjectRef = NULL;
  699. obj->mFirstObjectRef = giptr;
  700. giptr->nextLookupInfo = mGhostLookupTable[index];
  701. mGhostLookupTable[index] = giptr;
  702. //AssertFatal(validateGhostArray(), "Invalid ghost array!");
  703. }
  704. //-----------------------------------------------------------------------------
  705. void NetConnection::handleConnectionMessage(U32 message, U32 sequence, U32 ghostCount)
  706. {
  707. if(( message == SendNextDownloadRequest
  708. || message == FileDownloadSizeMessage
  709. || message == GhostAlwaysStarting
  710. || message == GhostAlwaysDone
  711. || message == EndGhosting) && !isGhostingTo())
  712. {
  713. setLastError("Invalid packet. (not ghosting)");
  714. return;
  715. }
  716. S32 i;
  717. GhostSave sv;
  718. switch(message)
  719. {
  720. case GhostAlwaysDone:
  721. mGhostingSequence = sequence;
  722. NetConnection::smGhostAlwaysDone.trigger();
  723. // ok, all the ghost always objects are now on the client... but!
  724. // it's possible that there were some file load errors...
  725. // if so, we need to indicate to the server to restart ghosting, after
  726. // we download all the files...
  727. sv.ghost = NULL;
  728. sv.index = -1;
  729. mGhostAlwaysSaveList.push_back(sv);
  730. if(mGhostAlwaysSaveList.size() == 1)
  731. loadNextGhostAlwaysObject(true);
  732. break;
  733. case ReadyForNormalGhosts:
  734. if(sequence != mGhostingSequence)
  735. return;
  736. Con::executef(this, "onGhostAlwaysObjectsReceived");
  737. Con::printf("Ghost Always objects received.");
  738. mGhosting = true;
  739. for(i = 0; i < mGhostFreeIndex; i++)
  740. {
  741. if(mGhostArray[i]->flags & GhostInfo::ScopedEvent)
  742. mGhostArray[i]->flags &= ~(GhostInfo::Ghosting | GhostInfo::ScopedEvent);
  743. }
  744. break;
  745. case EndGhosting:
  746. onEndGhosting();
  747. // just delete all the local ghosts,
  748. // and delete all the ghosts in the current save list
  749. for(i = 0; i < MaxGhostCount; i++)
  750. {
  751. if(mLocalGhosts[i])
  752. {
  753. mLocalGhosts[i]->deleteObject();
  754. mLocalGhosts[i] = NULL;
  755. }
  756. }
  757. while(mGhostAlwaysSaveList.size())
  758. {
  759. delete mGhostAlwaysSaveList[0].ghost;
  760. mGhostAlwaysSaveList.pop_front();
  761. }
  762. break;
  763. case GhostAlwaysStarting:
  764. Con::executef("onGhostAlwaysStarted", Con::getIntArg(ghostCount));
  765. break;
  766. case SendNextDownloadRequest:
  767. sendNextFileDownloadRequest();
  768. break;
  769. case FileDownloadSizeMessage:
  770. mCurrentFileBufferSize = sequence;
  771. mCurrentFileBuffer = dRealloc(mCurrentFileBuffer, mCurrentFileBufferSize);
  772. mCurrentFileBufferOffset = 0;
  773. break;
  774. }
  775. }
  776. void NetConnection::activateGhosting()
  777. {
  778. if(!isGhostingFrom())
  779. return;
  780. mGhostingSequence++;
  781. // iterate through the ghost always objects and InScope them...
  782. // also post em all to the other side.
  783. SimSet* ghostAlwaysSet = Sim::getGhostAlwaysSet();
  784. SimSet::iterator i;
  785. AssertFatal((mGhostFreeIndex == 0) && (mGhostZeroUpdateIndex == 0), "Error: ghosts in the ghost list before activate.");
  786. U32 sz = ghostAlwaysSet->size();
  787. S32 j;
  788. for(j = 0; j < sz; j++)
  789. {
  790. U32 idx = MaxGhostCount - sz + j;
  791. mGhostArray[j] = mGhostRefs + idx;
  792. mGhostArray[j]->arrayIndex = j;
  793. }
  794. for(j = sz; j < MaxGhostCount; j++)
  795. {
  796. U32 idx = j - sz;
  797. mGhostArray[j] = mGhostRefs + idx;
  798. mGhostArray[j]->arrayIndex = j;
  799. }
  800. mScoping = true; // so that objectInScope will work
  801. for(i = ghostAlwaysSet->begin(); i != ghostAlwaysSet->end(); i++)
  802. {
  803. AssertFatal(dynamic_cast<NetObject *>(*i) != NULL, avar("Non NetObject in GhostAlwaysSet: %s", (*i)->getClassName()));
  804. NetObject *obj = (NetObject *)(*i);
  805. if(obj->mNetFlags.test(NetObject::Ghostable))
  806. objectInScope(obj);
  807. }
  808. // Send the initial ghosting connection message.
  809. sendConnectionMessage(GhostAlwaysStarting, mGhostingSequence, ghostAlwaysSet->size());
  810. // If this is the connection to the local client...
  811. if (getLocalClientConnection() == this)
  812. {
  813. // Get a pointer to the local client.
  814. NetConnection* pClient = NetConnection::getConnectionToServer();
  815. Con::executef("onGhostAlwaysStarted", Con::getIntArg(mGhostZeroUpdateIndex));
  816. // Set up a buffer for the object send.
  817. U8 iBuffer[4096];
  818. BitStream mStream(iBuffer, 4096);
  819. // Iterate through the scope always objects...
  820. for (j = mGhostZeroUpdateIndex - 1; j >= 0; j--)
  821. {
  822. AssertFatal((mGhostArray[j]->flags & GhostInfo::ScopeAlways) != 0, "NetConnection::activateGhosting: Non-scope always in the scope always list.")
  823. // Clear the ghost update mask and flags appropriately.
  824. mGhostArray[j]->updateMask = 0;
  825. ghostPushToZero(mGhostArray[j]);
  826. mGhostArray[j]->flags &= ~GhostInfo::NotYetGhosted;
  827. mGhostArray[j]->flags |= GhostInfo::ScopedEvent;
  828. // Set up a pointer to the new object.
  829. NetObject* pObject = 0;
  830. // If there's a valid ghost object...
  831. if (mGhostArray[j]->obj)
  832. {
  833. // Pack the server object's update.
  834. mStream.setPosition(0);
  835. mStream.clearCompressionPoint();
  836. U32 retMask = mGhostArray[j]->obj->packUpdate(this, 0xFFFFFFFF, &mStream);
  837. if ( retMask != 0 )
  838. mGhostArray[j]->obj->setMaskBits( retMask );
  839. // Create a new object instance for the client.
  840. pObject = (NetObject*)ConsoleObject::create(pClient->getNetClassGroup(), NetClassTypeObject, mGhostArray[j]->obj->getClassId(getNetClassGroup()));
  841. // Set the client object networking flags.
  842. pObject->mNetFlags = NetObject::IsGhost;
  843. pObject->mNetIndex = mGhostArray[j]->index;
  844. // Unpack the client object's update.
  845. mStream.setPosition(0);
  846. mStream.clearCompressionPoint();
  847. pObject->unpackUpdate(pClient, &mStream);
  848. }
  849. else
  850. {
  851. // Otherwise, create a new dummy netobject.
  852. pObject = new NetObject;
  853. }
  854. // Execute the appropriate console callback.
  855. Con::executef("onGhostAlwaysObjectReceived");
  856. // Set the ghost always object for the client.
  857. pClient->setGhostAlwaysObject(pObject, mGhostArray[j]->index);
  858. }
  859. }
  860. else
  861. {
  862. // Iterate through the scope always objects...
  863. for (j = mGhostZeroUpdateIndex - 1; j >= 0; j--)
  864. {
  865. AssertFatal((mGhostArray[j]->flags & GhostInfo::ScopeAlways) != 0, "NetConnection::activateGhosting: Non-scope always in the scope always list.")
  866. // Clear the ghost update mask and flags appropriately.
  867. mGhostArray[j]->updateMask = 0;
  868. ghostPushToZero(mGhostArray[j]);
  869. mGhostArray[j]->flags &= ~GhostInfo::NotYetGhosted;
  870. mGhostArray[j]->flags |= GhostInfo::ScopedEvent;
  871. // Post a network event to ghost the scope always object.
  872. postNetEvent(new GhostAlwaysObjectEvent(mGhostArray[j]->obj, mGhostArray[j]->index));
  873. }
  874. }
  875. // Send the ghosting always done message.
  876. sendConnectionMessage(GhostAlwaysDone, mGhostingSequence); //AssertFatal(validateGhostArray(), "Invalid ghost array!");
  877. }
  878. void NetConnection::clearGhostInfo()
  879. {
  880. // gotta clear out the ghosts...
  881. for(PacketNotify *walk = mNotifyQueueHead; walk; walk = walk->nextPacket)
  882. {
  883. ghostPacketReceived(walk);
  884. walk->ghostList = NULL;
  885. }
  886. for(S32 i = 0; i < MaxGhostCount; i++)
  887. {
  888. if(mGhostRefs[i].arrayIndex < mGhostFreeIndex)
  889. {
  890. detachObject(&mGhostRefs[i]);
  891. freeGhostInfo(&mGhostRefs[i]);
  892. }
  893. }
  894. AssertFatal((mGhostFreeIndex == 0) && (mGhostZeroUpdateIndex == 0), "Invalid indices.");
  895. }
  896. void NetConnection::resetGhosting()
  897. {
  898. if(!isGhostingFrom())
  899. return;
  900. // stop all ghosting activity
  901. // send a message to the other side notifying of this
  902. mGhosting = false;
  903. mScoping = false;
  904. sendConnectionMessage(EndGhosting, mGhostingSequence);
  905. mGhostingSequence++;
  906. clearGhostInfo();
  907. //AssertFatal(validateGhostArray(), "Invalid ghost array!");
  908. }
  909. void NetConnection::setGhostAlwaysObject(NetObject *object, U32 index)
  910. {
  911. if(!isGhostingTo())
  912. {
  913. object->deleteObject();
  914. setLastError("Invalid packet. (unexpected ghostalways)");
  915. return;
  916. }
  917. object->mNetFlags = NetObject::IsGhost;
  918. object->mNetIndex = index;
  919. // while there's an object waiting...
  920. if ( isLocalConnection() )
  921. {
  922. object->mServerObject = mRemoteConnection->resolveObjectFromGhostIndex(index);
  923. if ( object->mServerObject )
  924. object->mServerObject->mClientObject = object;
  925. }
  926. GhostSave sv;
  927. sv.ghost = object;
  928. sv.index = index;
  929. mGhostAlwaysSaveList.push_back(sv);
  930. // check if we are already downloading files for a previous object:
  931. if(mGhostAlwaysSaveList.size() == 1)
  932. loadNextGhostAlwaysObject(true); // the initial call always has "new" files
  933. }
  934. void NetConnection::fileDownloadSegmentComplete()
  935. {
  936. // this is called when a the file list has finished processing...
  937. // at this point we can try again to add the object
  938. // subclasses can override this to do, for example, datablock redos.
  939. if(mGhostAlwaysSaveList.size())
  940. loadNextGhostAlwaysObject(mNumDownloadedFiles != 0);
  941. }
  942. void NetConnection::loadNextGhostAlwaysObject(bool hadNewFiles)
  943. {
  944. if(!mGhostAlwaysSaveList.size())
  945. return;
  946. while(mGhostAlwaysSaveList.size())
  947. {
  948. if (isLocalConnection()) hadNewFiles = false;
  949. // only check for new files if this is the first load, or if new
  950. // files were downloaded from the server.
  951. // if(hadNewFiles)
  952. // gResourceManager->setMissingFileLogging(true);
  953. //
  954. // gResourceManager->clearMissingFileList();
  955. NetObject *object = mGhostAlwaysSaveList[0].ghost;
  956. U32 index = mGhostAlwaysSaveList[0].index;
  957. if(!object)
  958. {
  959. // a null object is used to signify that the last ghost in the list is down
  960. mGhostAlwaysSaveList.pop_front();
  961. AssertFatal(mGhostAlwaysSaveList.size() == 0, "Error! Ghost save list should be empty!");
  962. sendConnectionMessage(ReadyForNormalGhosts, mGhostingSequence);
  963. // gResourceManager->setMissingFileLogging(false);
  964. return;
  965. }
  966. mFilesWereDownloaded = hadNewFiles;
  967. if(!object->registerObject())
  968. {
  969. mFilesWereDownloaded = false;
  970. // make sure there's an error message if necessary
  971. if(mErrorBuffer.isEmpty())
  972. setLastError("Invalid packet. (failed to register ghost always)");
  973. // if there were no new files, make sure the error message
  974. // is the one from the last time we tried to add this object
  975. if(!hadNewFiles)
  976. {
  977. mErrorBuffer = mLastFileErrorBuffer;
  978. // gResourceManager->setMissingFileLogging(false);
  979. return;
  980. }
  981. // object failed to load, let's see if it had any missing files
  982. // if(!gResourceManager->getMissingFileList(mMissingFileList))
  983. // {
  984. // // no missing files, must be an error
  985. // // connection will automagically delete the ghost always list
  986. // // when this error is reported.
  987. // gResourceManager->setMissingFileLogging(false);
  988. // return;
  989. // }
  990. // ok, copy the error buffer out to a scratch pad for now
  991. mLastFileErrorBuffer = mErrorBuffer;
  992. mErrorBuffer = String();
  993. // request the missing files...
  994. mNumDownloadedFiles = 0;
  995. sendNextFileDownloadRequest();
  996. break;
  997. }
  998. mFilesWereDownloaded = false;
  999. // gResourceManager->setMissingFileLogging(false);
  1000. addObject(object);
  1001. mGhostAlwaysSaveList.pop_front();
  1002. AssertFatal(mLocalGhosts[index] == NULL, "Ghost already in table!");
  1003. mLocalGhosts[index] = object;
  1004. hadNewFiles = true;
  1005. }
  1006. }
  1007. //-----------------------------------------------------------------------------
  1008. NetObject *NetConnection::resolveGhost(S32 id)
  1009. {
  1010. return mLocalGhosts[id];
  1011. }
  1012. NetObject *NetConnection::resolveObjectFromGhostIndex(S32 id)
  1013. {
  1014. return mGhostRefs[id].obj;
  1015. }
  1016. S32 NetConnection::getGhostIndex(NetObject *obj)
  1017. {
  1018. if(!isGhostingFrom())
  1019. return obj->mNetIndex;
  1020. S32 index = obj->getId() & (GhostLookupTableSize - 1);
  1021. for(GhostInfo *gptr = mGhostLookupTable[index]; gptr; gptr = gptr->nextLookupInfo)
  1022. {
  1023. if(gptr->obj == obj && (gptr->flags & (GhostInfo::KillingGhost | GhostInfo::Ghosting | GhostInfo::NotYetGhosted | GhostInfo::KillGhost)) == 0)
  1024. return gptr->index;
  1025. }
  1026. return -1;
  1027. }
  1028. //-----------------------------------------------------------------------------
  1029. //-----------------------------------------------------------------------------
  1030. void NetConnection::ghostWriteStartBlock(ResizeBitStream *stream)
  1031. {
  1032. // Ok, writing the start block for the ghosts:
  1033. // here's how it goes.
  1034. //
  1035. // First we record out all the indices and class ids for all the objects
  1036. // This is so when the objects are read in, all the objects are instantiated
  1037. // before they are unpacked. The unpack code may reference other
  1038. // existing ghosts, so we want to make sure that all the ghosts are in the
  1039. // table with the correct pointers before any of the unpacks are called.
  1040. stream->write(mGhostingSequence);
  1041. // first write out the indices and ids:
  1042. for(U32 i = 0; i < MaxGhostCount; i++)
  1043. {
  1044. if(mLocalGhosts[i])
  1045. {
  1046. stream->writeFlag(true);
  1047. stream->writeInt(i, GhostIdBitSize);
  1048. stream->writeClassId(mLocalGhosts[i]->getClassId(getNetClassGroup()), NetClassTypeObject, getNetClassGroup());
  1049. stream->validate();
  1050. }
  1051. }
  1052. // mark off the end of the ghost list:
  1053. // it would be more space efficient to write out a count of active ghosts followed
  1054. // by index run lengths, but hey, what's a few bits here and there?
  1055. stream->writeFlag(false);
  1056. // then, for each ghost written into the start block, write the full pack update
  1057. // into the start block. For demos to work properly, packUpdate must
  1058. // be callable from client objects.
  1059. for(U32 i = 0; i < MaxGhostCount; i++)
  1060. {
  1061. if(mLocalGhosts[i])
  1062. {
  1063. U32 retMask = mLocalGhosts[i]->packUpdate(this, 0xFFFFFFFF, stream);
  1064. if ( retMask != 0 ) mLocalGhosts[i]->setMaskBits( retMask );
  1065. stream->validate();
  1066. }
  1067. }
  1068. }
  1069. void NetConnection::ghostReadStartBlock(BitStream *stream)
  1070. {
  1071. stream->read(&mGhostingSequence);
  1072. // read em back in.
  1073. // first, read in the index/class id, construct the object, and place it in mLocalGhosts[i]
  1074. while(stream->readFlag())
  1075. {
  1076. U32 index = stream->readInt(GhostIdBitSize);
  1077. S32 tag = stream->readClassId(NetClassTypeObject, getNetClassGroup());
  1078. NetObject *obj = (NetObject *) ConsoleObject::create(getNetClassGroup(), NetClassTypeObject, tag);
  1079. if(!obj)
  1080. {
  1081. setLastError("Invalid packet. (failed to create ghost from demo block)");
  1082. return;
  1083. }
  1084. obj->mNetFlags = NetObject::IsGhost;
  1085. obj->mNetIndex = index;
  1086. mLocalGhosts[index] = obj;
  1087. }
  1088. // now, all the ghosts are in the mLocalGhosts, so we loop
  1089. // through all non-null mLocalGhosts, unpacking the objects
  1090. // as we go:
  1091. for(U32 i = 0; i < MaxGhostCount; i++)
  1092. {
  1093. if(mLocalGhosts[i])
  1094. {
  1095. mLocalGhosts[i]->unpackUpdate(this, stream);
  1096. if(!mLocalGhosts[i]->registerObject())
  1097. {
  1098. if(mErrorBuffer.isEmpty())
  1099. setLastError("Invalid packet. (failed to register ghost from demo block)");
  1100. return;
  1101. }
  1102. addObject(mLocalGhosts[i]);
  1103. }
  1104. }
  1105. // MARKF - TODO - looks like we could have memory leaks here
  1106. // if there are errors.
  1107. }