Game Development Community

Making ghosting work without ghosting objects

by Anthony Lovell · in Torque Game Engine · 09/06/2006 (4:44 pm) · 0 replies

Edit: I faxed in and mailed in a copy of your contributor rights waiver form around 2-3 weeks ago. So please consider this as being offered to TNL under those conditions.

The problem: I was failing to see my NetObjects ghosted, and it turns out that the reason was that I had no scoping object. There are certainly some worthwhile ways to use ghosting (objectScopeLocalAlways/objectClearLocalAlways) that do not rely on scoping objects, and so I want to propose that my pair of fixes to GhostConnection's ::writePacket() method which fix this be considered a bug fix.

First fix:
void GhostConnection::writePacket(BitStream *bstream, PacketNotify *pnotify)
{
   Parent::writePacket(bstream, pnotify);
   GhostPacketNotify *notify = static_cast<GhostPacketNotify *>(pnotify);

   if(mConnectionParameters.mDebugObjectSizes)
      bstream->writeInt(DebugChecksum, 32);

   notify->ghostList = NULL;
   
   if(!doesGhostFrom())
      return;

#ifdef MY_FIX
   if(!bstream->writeFlag(mGhosting))
      return;
#else
   if(!bstream->writeFlag(mGhosting && mScopeObject.isValid()))
      return;
#endif

And, further down in the same function:

// don't do any ghost processing on objects that are being killed
      // or in the process of ghosting
      else if(!(walk->flags & (GhostInfo::KillingGhost | GhostInfo::Ghosting)))
      {
         if(walk->flags & GhostInfo::KillGhost)
            walk->priority = 10000;
#ifdef MY_FIX // this code should be made to work without a scoping object, right?
         else if (mScopeObject.isNull())
            walk->priority = F32(walk->updateSkipCount) * 0.1f; // cribbed from NetObject::getUpdatePriority()
#endif
         else
            walk->priority = walk->obj->getUpdatePriority(mScopeObject, walk->updateMask, walk->updateSkipCount);
      }
      else
         walk->priority = 0;

Along with this fix, I'll offer some logging additions whose absence made my problem much more difficult to detect and rectify. Basically, TNL has a nice logging system, but there are a fair number of places in the code where an early return is made from a function owing to some fairly surprising condition, and these really (I felt) merited a log message. The short list follows without much commentary.

void GhostConnection::objectLocalScopeAlways(NetObject *obj)
{
   // TONE added this log msg
   if(!doesGhostFrom()) {
      TNLLogMessageV(LogGhostConnection, ("WARNING: objectLocalScopeAlways() called, but !doesGhostFrom()"));
      return;
   }

void GhostConnection::objectLocalClearAlways(NetObject *obj)
{
   // TONE added this log msg
   if(!doesGhostFrom()) {
      TNLLogMessageV(LogGhostConnection, ("WARNING: objectLocalClearAlways() called, but !doesGhostFrom()"));
      return;
   }

d GhostConnection::objectInScope(NetObject *obj)
{
      // TONE added these log messages
   if (!mScoping) {
      TNLLogMessageV(LogGhostConnection, ("WARNING: objectInScope() called, but !mScoping"));
      return;
   }
   if (!doesGhostFrom()) {   
      TNLLogMessageV(LogGhostConnection, ("WARNING: objectInScope() called, but !doesGhostFrom()"));
      return;
   }
   if (!obj->isGhostable()) {
      TNLLogMessageV(LogGhostConnection, ("WARNING: objectInScope() called for !%s->isGhostable()", obj->getClassName()));
		return;
   }
   if (obj->isScopeLocal() && !isLocalConnection()) {
      TNLLogMessageV(LogGhostConnection, ("WARNING: objectInScope() called for a %s which isScopeLocal() on non-local connection", obj->getClassName()));
		return;
   }
   // end of TONE's alterations

further down in GhostConnection::objectInScope:
// TONE added this warning
   if (mGhostFreeIndex == MaxGhostCount) {
      TNLLogMessageV(LogGhostConnection, ("ERROR: objectInScopeCalled, but maxGhosts=%d has been reached!", MaxGhostCount));
      return;
   }

void GhostConnection::activateGhosting()
{
   if(!doesGhostFrom()) {
      // TONE added this logging message
      TNLLogMessageV(LogGhostConnection, ("ERROR: activateGhosting() called, but !doesGhostFrom()"));
      return;
   }

And one in NetInterface.cc
void NetInterface::handleConnectChallengeRequest(const Address &addr, BitStream *stream)
{
   // TONE added logging
   if(!mAllowConnections) {
      TNLLogMessageV(LogNetInterface, ("WARNING: Received Connect Challenge Request from %s, but !mAllowConnections", addr.toString()));
      return;
   }