📄 ghostconnection.cc
字号:
{
if(!(mGhostArray[i]->flags & GhostInfo::InScope))
detachObject(mGhostArray[i]);
}
for(i = mGhostZeroUpdateIndex - 1; i >= 0; i--)
{
walk = mGhostArray[i];
if(walk->index > maxIndex)
maxIndex = walk->index;
// clear out any kill objects that haven't been ghosted yet
if((walk->flags & GhostInfo::KillGhost) && (walk->flags & GhostInfo::NotYetGhosted))
{
freeGhostInfo(walk);
continue;
}
// 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;
else
walk->priority = walk->obj->getUpdatePriority(&camInfo, walk->updateMask, walk->updateSkipCount);
}
else
walk->priority = 0;
}
GhostRef *updateList = NULL;
dQsort(mGhostArray, mGhostZeroUpdateIndex, sizeof(GhostInfo *), UQECompare);
// reset the array indices...
for(i = mGhostZeroUpdateIndex - 1; i >= 0; i--)
mGhostArray[i]->arrayIndex = i;
S32 sendSize = 1;
while(maxIndex >>= 1)
sendSize++;
if(sendSize < 3)
sendSize = 3;
bstream->writeInt(sendSize - 3, GhostIndexBitSize);
U32 count = 0;
//
for(i = mGhostZeroUpdateIndex - 1; i >= 0 && !bstream->isFull(); i--)
{
GhostInfo *walk = mGhostArray[i];
if(walk->flags & (GhostInfo::KillingGhost | GhostInfo::Ghosting))
continue;
bstream->writeFlag(true);
bstream->writeInt(walk->index, sendSize);
U32 updateMask = walk->updateMask;
GhostRef *upd = new GhostRef;
upd->nextRef = updateList;
updateList = upd;
upd->nextUpdateChain = walk->updateChain;
walk->updateChain = upd;
upd->ghost = walk;
upd->ghostInfoFlags = 0;
if(walk->flags & GhostInfo::KillGhost)
{
walk->flags &= ~GhostInfo::KillGhost;
walk->flags |= GhostInfo::KillingGhost;
walk->updateMask = 0;
upd->mask = updateMask;
ghostPushToZero(walk);
upd->ghostInfoFlags = GhostInfo::KillingGhost;
bstream->writeFlag(true); // killing ghost
}
else
{
bstream->writeFlag(false);
U32 startPos = bstream->getCurPos();
if(walk->flags & GhostInfo::NotYetGhosted)
{
S32 classId = walk->obj->getClassId(getNetClassGroup());
bstream->writeClassId(classId, NetClassTypeObject, getNetClassGroup());
#ifdef TORQUE_DEBUG_NET
bstream->writeInt(classId ^ DebugChecksum, 32);
#endif
walk->flags &= ~GhostInfo::NotYetGhosted;
walk->flags |= GhostInfo::Ghosting;
upd->ghostInfoFlags = GhostInfo::Ghosting;
}
#ifdef TORQUE_DEBUG_NET
else {
S32 classId = walk->obj->getClassId(getNetClassGroup());
bstream->writeClassId(classId, NetClassTypeObject, getNetClassGroup());
bstream->writeInt(classId ^ DebugChecksum, 32);
}
#endif
// update the object
U32 retMask(0);
//#ifdef _RPG_NOCOMMENT
retMask = walk->obj->packUpdate(this, updateMask, bstream);
//#endif
DEBUG_LOG(("PKLOG %d GHOST %d: %s", getId(), bstream->getCurPos() - 16 - startPos, walk->obj->getClassName()));
AssertFatal((retMask & (~updateMask)) == 0, "Cannot set new bits in packUpdate return");
walk->updateMask = retMask;
if(!retMask)
ghostPushToZero(walk);
upd->mask = updateMask & ~retMask;
//PacketStream::getStats()->addBits(PacketStats::Send, bstream->getCurPos() - startPos, walk->obj->getPersistTag());
#ifdef TORQUE_DEBUG_NET
bstream->writeInt(walk->index ^ DebugChecksum, 32);
#endif
}
walk->updateSkipCount = 0;
count++;
}
//Con::printf("Ghosts updated: %d (%d remain)", count, mGhostZeroUpdateIndex);
// no more objects...
bstream->writeFlag(false);
notify->ghostList = updateList;
}
void GhostConnection::ghostReadPacket(BitStream *bstream)
{
#ifdef TORQUE_DEBUG_NET
U32 sum = bstream->readInt(32);
AssertISV(sum == DebugChecksum, "Invalid checksum.");
#endif
if(!isGhostingTo())
return;
if(!bstream->readFlag())
return;
S32 idSize;
idSize = bstream->readInt( GhostIndexBitSize);
idSize += 3;
// while there's an object waiting...
while(bstream->readFlag())
{
gGhostUpdates++;
U32 index;
//S32 startPos = bstream->getCurPos();
index = (U32) bstream->readInt(idSize);
if(bstream->readFlag()) // is this ghost being deleted?
{
mGhostsActive--;
AssertFatal(mLocalGhosts[index] != NULL, "Error, NULL ghost encountered.");
mLocalGhosts[index]->deleteObject();
mLocalGhosts[index] = NULL;
}
else
{
if(!mLocalGhosts[index]) // it's a new ghost... cool
{
mGhostsActive++;
S32 classId = bstream->readClassId(NetClassTypeObject, getNetClassGroup());
if(classId == -1)
{
setLastError("Invalid packet.");
return;
}
NetObject *obj = (NetObject *) ConsoleObject::create(getNetClassGroup(), NetClassTypeObject, classId);
if(!obj)
{
setLastError("Invalid packet.");
return;
}
obj->mNetFlags = NetObject::IsGhost;
// object gets initial update before adding to the manager
obj->mNetIndex = index;
mLocalGhosts[index] = obj;
#ifdef TORQUE_DEBUG_NET
U32 checksum = bstream->readInt(32);
S32 origId = checksum ^ DebugChecksum;
AssertISV(mLocalGhosts[index] != NULL, "Invalid dest ghost.");
AssertISV(origId == mLocalGhosts[index]->getClassId(getNetClassGroup()),
avar("class id mismatch for dest class %s.",
mLocalGhosts[index]->getClassName()) );
#endif
//#ifdef _RPG_NOCOMMENT
mLocalGhosts[index]->unpackUpdate(this, bstream);
//#endif
if(!obj->registerObject())
{
if(!mErrorBuffer[0])
setLastError("Invalid packet.");
return;
}
//#ifdef _RPG_NOCOMMENT
if(mRemoteConnection)
obj->mServerObject = mRemoteConnection->resolveObjectFromGhostIndex(index);
//#endif
addObject(obj);
}
else
{
#ifdef TORQUE_DEBUG_NET
S32 classId = bstream->readClassId(NetClassTypeObject, getNetClassGroup());
U32 checksum = bstream->readInt(32);
S32 origId = checksum ^ DebugChecksum;
AssertISV(mLocalGhosts[index] != NULL, "Invalid dest ghost.");
AssertISV(origId == mLocalGhosts[index]->getClassId(getNetClassGroup()),
avar("class id mismatch for dest class %s.",
mLocalGhosts[index]->getClassName()) );
#endif
//#ifdef _RPG_NOCOMMENT
mLocalGhosts[index]->unpackUpdate(this, bstream);
//#endif
}
//PacketStream::getStats()->addBits(PacketStats::Receive, bstream->getCurPos() - startPos, ghostRefs[index].localGhost->getPersistTag());
#ifdef TORQUE_DEBUG_NET
U32 checksum = bstream->readInt(32);
S32 origIndex = checksum ^ DebugChecksum;
AssertISV(origIndex == index,
avar("unpackUpdate did not match packUpdate for object of class %s.",
mLocalGhosts[index]->getClassName()) );
#endif
if(mErrorBuffer[0])
return;
}
}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void GhostConnection::setScopeObject(NetObject *obj)
{
if(((NetObject *) mScopeObject) == obj)
return;
mScopeObject = obj;
}
void GhostConnection::detachObject(GhostInfo *info)
{
// mark it for ghost killin'
info->flags |= GhostInfo::KillGhost;
// if the mask is in the zero range, we've got to move it up...
if(!info->updateMask)
{
info->updateMask = 0xFFFFFFFF;
ghostPushNonZero(info);
}
if(info->obj)
{
if(info->prevObjectRef)
info->prevObjectRef->nextObjectRef = info->nextObjectRef;
else
info->obj->mFirstObjectRef = info->nextObjectRef;
if(info->nextObjectRef)
info->nextObjectRef->prevObjectRef = info->prevObjectRef;
// remove it from the lookup table
U32 id = info->obj->getId();
for(GhostInfo **walk = &mGhostLookupTable[id & (GhostLookupTableSize - 1)]; *walk; walk = &((*walk)->nextLookupInfo))
{
GhostInfo *temp = *walk;
if(temp == info)
{
*walk = temp->nextLookupInfo;
break;
}
}
info->prevObjectRef = info->nextObjectRef = NULL;
info->obj = NULL;
}
}
void GhostConnection::freeGhostInfo(GhostInfo *ghost)
{
AssertFatal(ghost->arrayIndex < mGhostFreeIndex, "Ghost already freed.");
if(ghost->arrayIndex < mGhostZeroUpdateIndex)
{
AssertFatal(ghost->updateMask != 0, "Invalid ghost mask.");
ghost->updateMask = 0;
ghostPushToZero(ghost);
}
ghostPushZeroToFree(ghost);
AssertFatal(ghost->updateChain == NULL, "Ack!");
}
//-----------------------------------------------------------------------------
void GhostConnection::objectLocalScopeAlways(NetObject *obj)
{
if(!isGhostingFrom())
return;
objectInScope(obj);
for(GhostInfo *walk = mGhostLookupTable[obj->getId() & (GhostLookupTableSize - 1)]; walk; walk = walk->nextLookupInfo)
{
if(walk->obj != obj)
continue;
walk->flags |= GhostInfo::ScopeLocalAlways;
return;
}
}
void GhostConnection::objectLocalClearAlways(NetObject *obj)
{
if(!isGhostingFrom())
return;
for(GhostInfo *walk = mGhostLookupTable[obj->getId() & (GhostLookupTableSize - 1)]; walk; walk = walk->nextLookupInfo)
{
if(walk->obj != obj)
continue;
walk->flags &= ~GhostInfo::ScopeLocalAlways;
return;
}
}
bool GhostConnection::validateGhostArray()
{
AssertFatal(mGhostZeroUpdateIndex >= 0 && mGhostZeroUpdateIndex <= mGhostFreeIndex, "Invalid update index range.");
AssertFatal(mGhostFreeIndex <= MaxGhostCount, "Invalid free index range.");
U32 i;
for(i = 0; i < mGhostZeroUpdateIndex; i ++)
{
AssertFatal(mGhostArray[i]->arrayIndex == i, "Invalid array index.");
AssertFatal(mGhostArray[i]->updateMask != 0, "Invalid ghost mask.");
}
for(; i < mGhostFreeIndex; i ++)
{
AssertFatal(mGhostArray[i]->arrayIndex == i, "Invalid array index.");
AssertFatal(mGhostArray[i]->updateMask == 0, "Invalid ghost mask.");
}
for(; i < MaxGhostCount; i++)
{
AssertFatal(mGhostArray[i]->arrayIndex == i, "Invalid array index.");
}
return true;
}
void GhostConnection::objectInScope(NetObject *obj)
{
if (!mScoping || !isGhostingFrom())
return;
if (obj->isScopeLocal() && !isLocalConnection())
return;
S32 index = obj->getId() & (GhostLookupTableSize - 1);
// check if it's already in scope
// the object may have been cleared out without the lookupTable being cleared
// so validate that the object pointers are the same.
for(GhostInfo *walk = mGhostLookupTable[index ]; walk; walk = walk->nextLookupInfo)
{
if(walk->obj != obj)
continue;
walk->flags |= GhostInfo::InScope;
return;
}
if (mGhostFreeIndex == MaxGhostCount)
{
AssertWarn(0,"GhostConnection::objectInScope: too many ghosts");
return;
}
GhostInfo *giptr = mGhostArray[mGhostFreeIndex];
ghostPushFreeToZero(giptr);
giptr->updateMask = 0xFFFFFFFF;
ghostPushNonZero(giptr);
giptr->flags = GhostInfo::NotYetGhosted | GhostInfo::InScope;
if(obj->mNetFlags.test(NetObject::ScopeAlways))
giptr->flags |= GhostInfo::ScopeAlways;
giptr->obj = obj;
giptr->updateChain = NULL;
giptr->updateSkipCount = 0;
giptr->connection = this;
giptr->nextObjectRef = obj->mFirstObjectRef;
if(obj->mFirstObjectRef)
obj->mFirstObjectRef->prevObjectRef = giptr;
giptr->prevObjectRef = NULL;
obj->mFirstObjectRef = giptr;
giptr->nextLookupInfo = mGhostLookupTable[index];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -