⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ghostconnection.cc

📁 五行MMORPG引擎系统V1.0
💻 CC
📖 第 1 页 / 共 3 页
字号:
   mGhostLookupTable[index] = giptr;
   //AssertFatal(validateGhostArray(), "Invalid ghost array!");
}

//-----------------------------------------------------------------------------

void GhostConnection::handleConnectionMessage(U32 message, U32 sequence, U32 ghostCount)
{
   if((  message == SendNextDownloadRequest
      || message == FileDownloadSizeMessage
      || message == GhostAlwaysStarting
      || message == GhostAlwaysDone
      || message == EndGhosting) && !isGhostingTo())
   {
      setLastError("Invalid packet.");
      return;
   }

   S32 i;
   GhostSave sv;
   switch(message)
   {
      case GhostAlwaysDone:
         mGhostingSequence = sequence;
         // ok, all the ghost always objects are now on the client... but!
         // it's possible that there were some file load errors...
         // if so, we need to indicate to the server to restart ghosting, after
         // we download all the files...
         sv.ghost = NULL;
         mGhostAlwaysSaveList.push_back(sv);
         if(mGhostAlwaysSaveList.size() == 1)
            loadNextGhostAlwaysObject(true);
         break;
      case ReadyForNormalGhosts:
         if(sequence != mGhostingSequence)
            return;
         Con::executef(this, 1, "onGhostAlwaysObjectsReceived");
         Con::printf("Ghost Always objects received.");
         mGhosting = true;
         for(i = 0; i < mGhostFreeIndex; i++)
         {
            if(mGhostArray[i]->flags & GhostInfo::ScopedEvent)
               mGhostArray[i]->flags &= ~(GhostInfo::Ghosting | GhostInfo::ScopedEvent);
         }
         break;
      case EndGhosting:
         // just delete all the local ghosts,
         // and delete all the ghosts in the current save list
         for(i = 0; i < MaxGhostCount; i++)
         {
            if(mLocalGhosts[i])
            {
               mLocalGhosts[i]->deleteObject();
               mLocalGhosts[i] = NULL;
            }
         }
         while(mGhostAlwaysSaveList.size())
         {
            delete mGhostAlwaysSaveList[0].ghost;
            mGhostAlwaysSaveList.pop_front();
         }
         break;
      case GhostAlwaysStarting:
         Con::executef(2, "onGhostAlwaysStarted", Con::getIntArg(ghostCount));
         break;
      case SendNextDownloadRequest:
         sendNextFileDownloadRequest();
         break;
      case FileDownloadSizeMessage:
         mCurrentFileBufferSize = sequence;
         mCurrentFileBuffer = dRealloc(mCurrentFileBuffer, mCurrentFileBufferSize);
         mCurrentFileBufferOffset = 0;
         break;
   }
}

void GhostConnection::activateGhosting()
{
   if(!isGhostingFrom())
      return;

   mGhostingSequence++;

   // iterate through the ghost always objects and InScope them...
   // also post em all to the other side.

   SimSet* ghostAlwaysSet = Sim::getGhostAlwaysSet();

   SimSet::iterator i;

   AssertFatal((mGhostFreeIndex == 0) && (mGhostZeroUpdateIndex == 0), "Error: ghosts in the ghost list before activate.");

   U32 sz = ghostAlwaysSet->size();
   S32 j;

   for(j = 0; j < sz; j++)
   {
      U32 idx = MaxGhostCount - sz + j;
      mGhostArray[j] = mGhostRefs + idx;
      mGhostArray[j]->arrayIndex = j;
   }
   for(j = sz; j < MaxGhostCount; j++)
   {
      U32 idx = j - sz;
      mGhostArray[j] = mGhostRefs + idx;
      mGhostArray[j]->arrayIndex = j;
   }
   mScoping = true; // so that objectInScope will work
   for(i = ghostAlwaysSet->begin(); i != ghostAlwaysSet->end(); i++)
   {
      AssertFatal(dynamic_cast<NetObject *>(*i) != NULL, avar("Non NetObject in GhostAlwaysSet: %s", (*i)->getClassName()));
      NetObject *obj = (NetObject *)(*i);
      if(obj->mNetFlags.test(NetObject::Ghostable))
         objectInScope(obj);
   }
   sendConnectionMessage(GhostAlwaysStarting, mGhostingSequence, ghostAlwaysSet->size());
   for(j = mGhostZeroUpdateIndex - 1; j >= 0; j--)
   {
      AssertFatal((mGhostArray[j]->flags & GhostInfo::ScopeAlways) != 0, "Non-scope always in the scope always list.")

      // we may end up resending state here, but at least initial state
      // will not be resent.
      mGhostArray[j]->updateMask = 0;
      ghostPushToZero(mGhostArray[j]);
      mGhostArray[j]->flags &= ~GhostInfo::NotYetGhosted;
      mGhostArray[j]->flags |= GhostInfo::ScopedEvent;

      postNetEvent(new GhostAlwaysObjectEvent(mGhostArray[j]->obj, mGhostArray[j]->index));
   }
   sendConnectionMessage(GhostAlwaysDone, mGhostingSequence);
   //AssertFatal(validateGhostArray(), "Invalid ghost array!");
}

void GhostConnection::clearGhostInfo()
{
   // gotta clear out the ghosts...
   for(PacketNotify *walk = mNotifyQueueHead; walk; walk = walk->nextPacket)
   {
      ghostPacketReceived(walk);
      walk->ghostList = NULL;
   }
   for(S32 i = 0; i < MaxGhostCount; i++)
   {
      if(mGhostRefs[i].arrayIndex < mGhostFreeIndex)
      {
         detachObject(&mGhostRefs[i]);
         freeGhostInfo(&mGhostRefs[i]);
      }
   }
   AssertFatal((mGhostFreeIndex == 0) && (mGhostZeroUpdateIndex == 0), "Invalid indices.");
}

void GhostConnection::resetGhosting()
{
   if(!isGhostingFrom())
      return;
   // stop all ghosting activity
   // send a message to the other side notifying of this

   mGhosting = false;
   mScoping = false;
   sendConnectionMessage(EndGhosting, mGhostingSequence);
   mGhostingSequence++;
   clearGhostInfo();
   //AssertFatal(validateGhostArray(), "Invalid ghost array!");
}

void GhostConnection::setGhostAlwaysObject(NetObject *object, U32 index)
{
   if(!isGhostingTo())
   {
      object->deleteObject();
      setLastError("Invalid packet.");
      return;
   }
   object->mNetFlags = NetObject::IsGhost;
   object->mNetIndex = index;

   // while there's an object waiting...
   if (isLocalConnection()) {
//#ifdef _RPG_NOCOMMENT
      object->mServerObject = mRemoteConnection->resolveObjectFromGhostIndex(index);
//#endif
   }

   GhostSave sv;
   sv.ghost = object;
   sv.index = index;
   mGhostAlwaysSaveList.push_back(sv);

   // check if we are already downloading files for a previous object:
   if(mGhostAlwaysSaveList.size() == 1)
      loadNextGhostAlwaysObject(true);  // the initial call always has "new" files

}

void GhostConnection::fileDownloadSegmentComplete()
{
   // this is called when a the file list has finished processing...
   // at this point we can try again to add the object
   // subclasses can override this to do, for example, datablock redos.
   if(mGhostAlwaysSaveList.size())
      loadNextGhostAlwaysObject(mNumDownloadedFiles != 0);
}

void GhostConnection::loadNextGhostAlwaysObject(bool hadNewFiles)
{
   if(!mGhostAlwaysSaveList.size())
      return;

   while(mGhostAlwaysSaveList.size())
   {
      // only check for new files if this is the first load, or if new
      // files were downloaded from the server.
      if(hadNewFiles)
         ResourceManager->setMissingFileLogging(true);
      ResourceManager->clearMissingFileList();
      NetObject *object = mGhostAlwaysSaveList[0].ghost;
      U32 index = mGhostAlwaysSaveList[0].index;

      if(!object)
      {
         // a null object is used to signify that the last ghost in the list is down
         mGhostAlwaysSaveList.pop_front();
         AssertFatal(mGhostAlwaysSaveList.size() == 0, "Error! Ghost save list should be empty!");
         sendConnectionMessage(ReadyForNormalGhosts, mGhostingSequence);
         ResourceManager->setMissingFileLogging(false);
         return;
      }
      mFilesWereDownloaded = hadNewFiles;

      if(!object->registerObject())
      {
         mFilesWereDownloaded = false;
         // make sure there's an error message if necessary
         if(!mErrorBuffer[0])
            setLastError("Invalid packet.");

         // if there were no new files, make sure the error message
         // is the one from the last time we tried to add this object
         if(!hadNewFiles)
         {
            dStrcpy(mErrorBuffer, mLastFileErrorBuffer);
            ResourceManager->setMissingFileLogging(false);
            return;
         }

         // object failed to load, let's see if it had any missing files
         if(!ResourceManager->getMissingFileList(mMissingFileList))
         {
            // no missing files, must be an error
            // connection will automagically delete the ghost always list
            // when this error is reported.
            ResourceManager->setMissingFileLogging(false);
            return;
         }

         // ok, copy the error buffer out to a scratch pad for now
         dStrcpy(mLastFileErrorBuffer, mErrorBuffer);
         mErrorBuffer[0] = 0;

         // request the missing files...
         mNumDownloadedFiles = 0;
         sendNextFileDownloadRequest();
         break;
      }
      mFilesWereDownloaded = false;
      ResourceManager->setMissingFileLogging(false);
      addObject(object);
      mGhostAlwaysSaveList.pop_front();

      AssertFatal(mLocalGhosts[index] == NULL, "Ghost already in table!");
      mLocalGhosts[index] = object;
      hadNewFiles = true;
   }
}

//-----------------------------------------------------------------------------

NetObject *GhostConnection::resolveGhost(S32 id)
{
   return mLocalGhosts[id];
}

NetObject *GhostConnection::resolveObjectFromGhostIndex(S32 id)
{
   return mGhostRefs[id].obj;
}

S32 GhostConnection::getGhostIndex(NetObject *obj)
{
   if(!isGhostingFrom())
      return obj->mNetIndex;
   S32 index = obj->getId() & (GhostLookupTableSize - 1);

   for(GhostInfo *gptr = mGhostLookupTable[index]; gptr; gptr = gptr->nextLookupInfo)
   {
      if(gptr->obj == obj && (gptr->flags & (GhostInfo::KillingGhost | GhostInfo::Ghosting | GhostInfo::NotYetGhosted | GhostInfo::KillGhost)) == 0)
         return gptr->index;
   }
   return -1;
}

//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------

void GhostConnection::ghostWriteStartBlock(ResizeBitStream *stream)
{
   // Ok, writing the start block for the ghosts:
   // here's how it goes.
   //
   // First we record out all the indices and class ids for all the objects
   // This is so when the objects are read in, all the objects are instantiated
   // before they are unpacked.  The unpack code may reference other
   // existing ghosts, so we want to make sure that all the ghosts are in the
   // table with the correct pointers before any of the unpacks are called.

   stream->write(mGhostingSequence);

   // first write out the indices and ids:
   for(U32 i = 0; i < MaxGhostCount; i++)
   {
      if(mLocalGhosts[i])
      {
         stream->writeFlag(true);
         stream->writeInt(i, GhostIdBitSize);
         stream->writeClassId(mLocalGhosts[i]->getClassId(getNetClassGroup()), NetClassTypeObject, getNetClassGroup());
         stream->validate();
      }
   }
   // mark off the end of the ghost list:
   // it would be more space efficient to write out a count of active ghosts followed
   // by index run lengths, but hey, what's a few bits here and there?

   stream->writeFlag(false);

   // then, for each ghost written into the start block, write the full pack update
   // into the start block.  For demos to work properly, packUpdate must
   // be callable from client objects.
   for(U32 i = 0; i < MaxGhostCount; i++)
   {
      if(mLocalGhosts[i])
      {
//#ifdef _RPG_NOCOMMENT
         mLocalGhosts[i]->packUpdate(this, 0xFFFFFFFF, stream);
//#endif
         stream->validate();
      }
   }
}

void GhostConnection::ghostReadStartBlock(BitStream *stream)
{
   stream->read(&mGhostingSequence);

   // read em back in.
   // first, read in the index/class id, construct the object, and place it in mLocalGhosts[i]

   while(stream->readFlag())
   {
      U32 index = stream->readInt(GhostIdBitSize);
      S32 tag = stream->readClassId(NetClassTypeObject, getNetClassGroup());
      NetObject *obj = (NetObject *) ConsoleObject::create(getNetClassGroup(), NetClassTypeObject, tag);
      if(!obj)
      {
         setLastError("Invalid packet.");
         return;
      }
      obj->mNetFlags = NetObject::IsGhost;
      obj->mNetIndex = index;
      mLocalGhosts[index] = obj;
   }

   // now, all the ghosts are in the mLocalGhosts, so we loop
   // through all non-null mLocalGhosts, unpacking the objects
   // as we go:

   for(U32 i = 0; i < MaxGhostCount; i++)
   {
      if(mLocalGhosts[i])
      {
//#ifdef _RPG_NOCOMMENT
         mLocalGhosts[i]->unpackUpdate(this, stream);
//#endif
         if(!mLocalGhosts[i]->registerObject())
         {
            if(mErrorBuffer[0])
               setLastError("Invalid packet.");
            return;
         }
         addObject(mLocalGhosts[i]);
      }
   }
   // MARKF - TODO - looks like we could have memory leaks here
   // if there are errors.
}


//};//namespace CS

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -