예제 #1
0
void HifiClientProcessList::ageTickCache(S32 numToAge, S32 len)
{
   for (ProcessObject * pobj = mHead.mProcessLink.next; pobj != &mHead; pobj = pobj->mProcessLink.next)
   {
      GameBase *obj = getGameBase(pobj);
      if ( obj && obj->getTypeMask() & GameBaseHiFiObjectType )
         obj->getTickCache().ageCache(numToAge,len);
   }
}
예제 #2
0
void HifiClientProcessList::clientCatchup(GameConnection * connection)
{
#ifdef TORQUE_DEBUG_NET_MOVES
   Con::printf("client catching up... (%i)%s", mCatchup, mForceHifiReset ? " reset" : "");
#endif

   if (connection->getControlObject() && connection->getControlObject()->isGhostUpdated())
      // if control object is reset, make sure moves are reset too
      connection->mMoveList->resetCatchup();

   const F32 maxVel = mSqrt(gMaxHiFiVelSq) * 1.25f;
   F32 dt = F32(mCatchup+1) * TickSec;
   Point3F bigDelta(maxVel*dt,maxVel*dt,maxVel*dt);

   // walk through all process objects looking for ones which were updated
   // -- during first pass merely collect neighbors which need to be reset and updated in unison
   ProcessObject * pobj;
   if (mCatchup && !mForceHifiReset)
   {
      for (pobj = mHead.mProcessLink.next; pobj != &mHead; pobj = pobj->mProcessLink.next)
      {
         GameBase *obj = getGameBase( pobj );
         static SimpleQueryList nearby;
         nearby.mList.clear();
         // check for nearby objects which need to be reset and then caught up
         // note the funky loop logic -- first time through obj is us, then
         // we start iterating through nearby list (to look for objects nearby
         // the nearby objects), which is why index starts at -1
         // [objects nearby the nearby objects also get added to the nearby list]
         for (S32 i=-1; obj; obj = ++i<nearby.mList.size() ? (GameBase*)nearby.mList[i] : NULL)
         {
            if (obj->isGhostUpdated() && (obj->getTypeMask() & GameBaseHiFiObjectType) && !obj->isNetNearbyAdded())
            {
               Point3F start = obj->getWorldSphere().center;
               Point3F end = start + 1.1f * dt * obj->getVelocity();
               F32 rad = 1.5f * obj->getWorldSphere().radius;

               // find nearby items not updated but are hi fi, mark them as updated (and restore old loc)
               // check to see if added items have neighbors that need updating
               Box3F box;
               Point3F rads(rad,rad,rad);
               box.minExtents = box.maxExtents = start;
               box.minExtents -= bigDelta + rads;
               box.maxExtents += bigDelta + rads;

               // CodeReview - this is left in for MBU, but also so we can deal with the issue later.
               // add marble blast hack so hifi networking can see hidden objects
               // (since hidden is under control of hifi networking)
               //  gForceNotHidden = true;

               S32 j = nearby.mList.size();
               gClientContainer.findObjects(box, GameBaseHiFiObjectType, SimpleQueryList::insertionCallback, &nearby);

               // CodeReview - this is left in for MBU, but also so we can deal with the issue later.
               // disable above hack
               //  gForceNotHidden = false;

               // drop anyone not heading toward us or already checked
               for (; j<nearby.mList.size(); j++)
               {
                  GameBase * obj2 = (GameBase*)nearby.mList[j];
                  // if both passive, these guys don't interact with each other
                  bool passive = obj->isHifiPassive() && obj2->isHifiPassive();
                  if (!obj2->isGhostUpdated() && !passive)
                  {
                     // compare swept spheres of obj and obj2
                     // if collide, reset obj2, setGhostUpdated(true), and continue
                     Point3F end2 = obj2->getWorldSphere().center;
                     Point3F start2 = end2 - 1.1f * dt * obj2->getVelocity();
                     F32 rad2 = 1.5f * obj->getWorldSphere().radius;
                     if (MathUtils::capsuleCapsuleOverlap(start,end,rad,start2,end2,rad2))
                     {
                        // better add obj2
                        obj2->getTickCache().beginCacheList();
                        TickCacheEntry * tce = obj2->getTickCache().incCacheList();
                        BitStream bs(tce->packetData,TickCacheEntry::MaxPacketSize);
                        obj2->readPacketData(connection,&bs);
                        obj2->setGhostUpdated(true);

                        // continue so we later add the neighbors too
                        continue;
                     }

                  }

                  // didn't pass above test...so don't add it or nearby objects
                  nearby.mList[j] = nearby.mList.last();
                  nearby.mList.decrement();
                  j--;
               }
               obj->setNetNearbyAdded(true);
            }
         }
      }
   }

   // save water mark -- for game base list
   FrameAllocatorMarker mark;

   // build ordered list of client objects which need to be caught up
   GameBaseListNode list;
   for (pobj = mHead.mProcessLink.next; pobj != &mHead; pobj = pobj->mProcessLink.next)
   {
      GameBase *obj = getGameBase( pobj );
      //GameBase *obj = dynamic_cast<GameBase*>( pobj );
      //GameBase *obj = (GameBase*)pobj;

      // Not a GameBase object so nothing to do.
      if ( !obj )
         continue;

      if (obj->isGhostUpdated() && (obj->getTypeMask() & GameBaseHiFiObjectType))
      {
         // construct process object and add it to the list
         // hold pointer to our object in mAfterObject
         GameBaseListNode * po = (GameBaseListNode*)FrameAllocator::alloc(sizeof(GameBaseListNode));
         po->mObject = obj;
         po->linkBefore(&list);

         // begin iterating through tick list (skip first tick since that is the state we've been reset to)
         obj->getTickCache().beginCacheList();
         obj->getTickCache().incCacheList();
      }
      else if (mForceHifiReset && (obj->getTypeMask() & GameBaseHiFiObjectType))
      {
         // add all hifi objects
         obj->getTickCache().beginCacheList();
         TickCacheEntry * tce = obj->getTickCache().incCacheList();
         BitStream bs(tce->packetData,TickCacheEntry::MaxPacketSize);
         obj->readPacketData(connection,&bs);
         obj->setGhostUpdated(true);

         // construct process object and add it to the list
         // hold pointer to our object in mAfterObject
         GameBaseListNode * po = (GameBaseListNode*)FrameAllocator::alloc(sizeof(GameBaseListNode));
         po->mObject = obj;
         po->linkBefore(&list);
      }
      else if (obj == connection->getControlObject() && obj->isGhostUpdated())
      {
         // construct process object and add it to the list
         // hold pointer to our object in mAfterObject
         // .. but this is not a hi fi object, so don't mess with tick cache
         GameBaseListNode * po = (GameBaseListNode*)FrameAllocator::alloc(sizeof(GameBaseListNode));
         po->mObject = obj;
         po->linkBefore(&list);
      }
      else if (obj->isGhostUpdated())
      {
         // not hifi but we were updated, so perform net smooth now
         obj->computeNetSmooth(mLastDelta);
      }

      // clear out work flags
      obj->setNetNearbyAdded(false);
      obj->setGhostUpdated(false);
   }

   // run through all the moves in the move list so we can play them with our control object
   Move* movePtr;
   U32 numMoves;
   connection->mMoveList->resetClientMoves();
   connection->mMoveList->getMoves(&movePtr, &numMoves);
   AssertFatal(mCatchup<=numMoves,"doh");

   // tick catchup time
   for (U32 m=0; m<mCatchup; m++)
   {
      for (GameBaseListNode * walk = list.mNext; walk != &list; walk = walk->mNext)
      {
         // note that we get object from after object not getGameBase function
         // this is because we are an on the fly linked list which uses mAfterObject
         // rather than the linked list embedded in GameBase (clean this up?)
         GameBase * obj = walk->mObject;

         // it's possible for a non-hifi object to get in here, but
         // only if it is a control object...make sure we don't do any
         // of the tick cache stuff if we are not hifi.
         bool hifi = obj->getTypeMask() & GameBaseHiFiObjectType;
         TickCacheEntry * tce = hifi ? obj->getTickCache().incCacheList() : NULL;

         // tick object
         if (obj==connection->getControlObject())
         {
            obj->processTick(movePtr);
            movePtr->checksum = obj->getPacketDataChecksum(connection);
            movePtr++;
         }
         else
         {
            AssertFatal(tce && hifi,"Should not get in here unless a hi fi object!!!");
            obj->processTick(tce->move);
         }

         if (hifi)
         {
            BitStream bs(tce->packetData,TickCacheEntry::MaxPacketSize);
            obj->writePacketData(connection,&bs);
         }
      }
      if (connection->getControlObject() == NULL)
         movePtr++;
   }
   connection->mMoveList->clearMoves(mCatchup);

   // Handle network error smoothing here...but only for control object
   GameBase * control = connection->getControlObject();
   if (control && !control->isNewGhost())
   {
      control->computeNetSmooth(mLastDelta);
      control->setNewGhost(false);
   }

   if (moveSync.doAction() && moveSync.moveDiff>0)
   {
      S32 moveDiff = moveSync.moveDiff;
#ifdef TORQUE_DEBUG_NET_MOVES
      Con::printf("client timewarping to catchup %i moves",moveDiff);
#endif
      while (moveDiff--)
         advanceObjects();
      moveSync.reset();
   }

#ifdef TORQUE_DEBUG_NET_MOVES
   Con::printf("---------");
#endif

   // all caught up
   mCatchup = 0;
}