📄 ghostconnection.cc
字号:
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 + -