void GhostConnection::packetReceived(PacketNotify *pnotify) { Parent::packetReceived(pnotify); GhostPacketNotify *notify = static_cast<GhostPacketNotify *>(pnotify); GhostRef *packRef = notify->ghostList; // loop through all the notifies in this packet while(packRef) { // make sure this packRef isn't the last one on the GhostInfo if(packRef->ghost->lastUpdateChain == packRef) packRef->ghost->lastUpdateChain = NULL; GhostRef *temp = packRef->nextRef; // if this object was ghosting , it is now ghosted if(packRef->ghostInfoFlags & GhostInfo::Ghosting) { packRef->ghost->flags &= ~GhostInfo::Ghosting; if(packRef->ghost->obj) packRef->ghost->obj->onGhostAvailable(this); } // otherwise, if it was dieing, free the ghost else if(packRef->ghostInfoFlags & GhostInfo::KillingGhost) freeGhostInfo(packRef->ghost); delete packRef; packRef = temp; } }
void GhostManager::packetReceived(DWORD key) { PacketObjectRef *packRef = (PacketObjectRef *) key; // loop through all the notifies in this packet while(packRef) { PacketObjectRef *temp = packRef->nextRef; AssertFatal(packRef->nextUpdateChain == NULL, "Out of order notify!!"); // clear this notify from the end of the object's notify // chain PacketObjectRef **walk = &(packRef->ghost->updateChain); while(*walk != packRef) { walk = &((*walk)->nextUpdateChain); } *walk = 0; // if this object was ghosting , it is now ghosted if(packRef->ghostInfoFlags & GhostInfo::Ghosting) packRef->ghost->flags &= ~GhostInfo::Ghosting; // otherwise, if it was dieing, free the ghost else if(packRef->ghostInfoFlags & GhostInfo::KillingGhost) freeGhostInfo(packRef->ghost); // add the ref to the free list packRef->nextRef = freePackRefList; freePackRefList = packRef; packRef = temp; } }
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; if(!bstream->writeFlag(mGhosting && mScopeObject.isValid())) return; // fill a packet (or two) with ghosting data // 2. call scoped objects' priority functions if the flag set is nonzero // A removed ghost is assumed to have a high priority // 3. call updates based on sorted priority until the packet is // full. set flags to zero for all updated objects GhostInfo *walk; for(S32 i = mGhostZeroUpdateIndex - 1; i >= 0; i--) { if(!(mGhostArray[i]->flags & GhostInfo::InScope)) detachObject(mGhostArray[i]); } U32 maxIndex = 0; for(S32 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(mScopeObject, walk->updateMask, walk->updateSkipCount); } else walk->priority = 0; } GhostRef *updateList = NULL; qsort(mGhostArray, mGhostZeroUpdateIndex, sizeof(GhostInfo *), UQECompare); // reset the array indices... for(S32 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, 3); // 0-7 3 bit number U32 count = 0; // for(S32 i = mGhostZeroUpdateIndex - 1; i >= 0 && !bstream->isFull(); i--) { GhostInfo *walk = mGhostArray[i]; if(walk->flags & (GhostInfo::KillingGhost | GhostInfo::Ghosting)) continue; size_t updateStart = bstream->getBitPosition(); U32 updateMask = walk->updateMask; U32 retMask = 0; bstream->writeFlag(true); bstream->writeInt(walk->index, sendSize); if(!bstream->writeFlag(walk->flags & GhostInfo::KillGhost)) { // this is an update of some kind: if(mConnectionParameters.mDebugObjectSizes) bstream->advanceBitPosition(BitStreamPosBitSize); size_t startPos = bstream->getBitPosition(); if(walk->flags & GhostInfo::NotYetGhosted) { S32 classId = walk->obj->getClassId(getNetClassGroup()); bstream->writeClassId(classId, NetClassTypeObject, getNetClassGroup()); NetObject::mIsInitialUpdate = true; } // update the object retMask = walk->obj->packUpdate(this, updateMask, bstream); if(NetObject::mIsInitialUpdate) { NetObject::mIsInitialUpdate = false; walk->obj->getClassRep()->addInitialUpdate(bstream->getBitPosition() - startPos); } else walk->obj->getClassRep()->addPartialUpdate(bstream->getBitPosition() - startPos); if(mConnectionParameters.mDebugObjectSizes){ size_t bpL = bstream->getBitPosition(); U32 bp = static_cast<U32>(bpL); TNLAssert(bp == bpL, "This stream position is too long"); bstream->writeIntAt(bp, BitStreamPosBitSize, startPos - BitStreamPosBitSize); } TNLLogMessageV(LogGhostConnection, ("GhostConnection %s GHOST %d", walk->obj->getClassName(), bstream->getBitPosition() - 16 - startPos)); TNLAssert((retMask & (~updateMask)) == 0, "Cannot set new bits in packUpdate return"); } // check for packet overrun, and rewind this update if there // was one: if(bstream->getBitSpaceAvailable() < MinimumPaddingBits) { bstream->setBitPosition(updateStart); bstream->clearError(); break; } // otherwise, create a record of this ghost update and // attach it to the packet. GhostRef *upd = new GhostRef; upd->nextRef = updateList; updateList = upd; if(walk->lastUpdateChain) walk->lastUpdateChain->updateChain = upd; walk->lastUpdateChain = upd; upd->ghost = walk; upd->ghostInfoFlags = 0; upd->updateChain = NULL; 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; } else { if(walk->flags & GhostInfo::NotYetGhosted) { walk->flags &= ~GhostInfo::NotYetGhosted; walk->flags |= GhostInfo::Ghosting; upd->ghostInfoFlags = GhostInfo::Ghosting; } walk->updateMask = retMask; if(!retMask) ghostPushToZero(walk); upd->mask = updateMask & ~retMask; walk->updateSkipCount = 0; count++; } } // count # of ghosts have been updated, // mGhostZeroUpdateIndex # of ghosts remain to be updated. // no more objects... bstream->writeFlag(false); notify->ghostList = updateList; }
bool GhostManager::writePacket(BitStream *bstream, DWORD &key) { if(curMode != GhostScopeAlwaysMode && curMode != GhostNormalMode && !(curMode == InactiveMode && ghostList) ) return false; // fill a packet (or two) with ghosting data // first step is to check all our polled ghosts: // 1. Scope query - find if any new objects have come into // scope and if any have gone out. // While the client rep is sending out the ghost always packets // the scope query is not called... just ghost always objects are in the list // 2. call scoped objects' priority functions if the flag set is nonzero // A removed ghost is assumed to have a high priority // If the client rep is sending out ghost always objects // then instead of the priority function, the instantiation // time is used for priority. No objects are updated until // all are ghosted during this phase. // 3. call updates based on sorted priority until the packet is // full. set flags to zero for all updated objects camInfo.camera = NULL; camInfo.pos.set(0,0,0); camInfo.orientation.set(0,1,0); camInfo.visibleDistance = 1; camInfo.fov = (float)(M_PI / 4.0f); camInfo.sinFov = 0.5; camInfo.cosFov = 0.5; GhostInfo *walk = ghostList; bstream->writeFlag(curMode == GhostScopeAlwaysMode); if(curMode == GhostNormalMode || curMode == InactiveMode) { if(curMode == GhostNormalMode) { while(walk) { if(!(walk->flags & GhostInfo::ScopeAlways)) walk->flags &= ~GhostInfo::InScope; walk = walk->nextRef; } if(scopeObject) scopeObject->buildScopeAndCameraInfo(this, &camInfo); } walk = ghostList; while(walk) { if(!(walk->flags & GhostInfo::InScope)) { walk->flags |= GhostInfo::KillGhost; // remove this ghostManager from the object's ghostRefs if(walk->obj) { Vector<GhostRef>::iterator i; for(i = walk->obj->ghosts.begin(); i != walk->obj->ghosts.end(); i++) { if(i->ghostManager == this) { walk->obj->ghosts.erase(i); break; } } walk->obj = NULL; } } walk = walk->nextRef; } } static Vector<UpdateQueueEntry> qPriority; static Vector<UpdateQueueEntry> qDelete; qPriority.clear(); qDelete.clear(); walk = ghostList; while(walk) { // clear out any kill objects that haven't been ghosted yet if((walk->flags & GhostInfo::KillGhost) && (walk->flags & GhostInfo::NotYetGhosted)) { GhostInfo *temp = walk->nextRef; freeGhostInfo(walk); walk = temp; 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) qDelete.push_back(UpdateQueueEntry(0, walk)); else if((walk->flags & GhostInfo::NotYetGhosted) && (curMode == GhostScopeAlwaysMode)) qPriority.push_back(UpdateQueueEntry(-walk->obj->getNumber(), walk)); else if(walk->updateMask && (curMode == GhostNormalMode)) { float priority; if(scopeObject) priority = walk->obj->getUpdatePriority(&camInfo, walk->updateMask, walk->updateSkipCount); else priority = 1; qPriority.push_back(UpdateQueueEntry(priority, walk)); } } walk = walk->nextRef; } PacketObjectRef *updateList = NULL; m_qsort((void *) &qPriority[0], qPriority.size(), sizeof(UpdateQueueEntry), UQECompare); Vector<UpdateQueueEntry>::iterator i = qDelete.begin(); int packedIdSize = sendIdSize - 3; // 0-7 3 bit number bstream->writeInt(packedIdSize, 3); for(;;i++) { if(i == qDelete.end()) i = qPriority.begin(); if(i == qPriority.end()) break; if(bstream->isFull()) { (*i).obj->updateSkipCount++; } else { walk = (*i).obj; if(walk->flags & (GhostInfo::KillGhost | GhostInfo::Ghosting) == (GhostInfo::KillGhost | GhostInfo::Ghosting)) continue; int startPos = bstream->getCurPos(); bstream->writeFlag(true); bstream->writeInt(walk->ghostIndex, sendIdSize); DWORD updateMask = walk->updateMask; PacketObjectRef *upd = freePackRefList; if(upd) freePackRefList = freePackRefList->nextRef; else upd = new PacketObjectRef; 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; upd->ghostInfoFlags = GhostInfo::KillingGhost; bstream->writeFlag(true); // killing ghost } else { bstream->writeFlag(false); if(walk->flags & GhostInfo::NotYetGhosted) { if(curMode == GhostScopeAlwaysMode) bstream->writeInt(walk->obj->getNumber(), 32); #ifdef DEBUG_NET if(!walk->obj->getClass()) { AssertFatal(0, avar("%s is not a persist declared class.", walk->obj->getClassName())); } #endif DWORD tag = walk->obj->getGhostTag(); AssertFatal(tag > 0 && tag < 1024, "Bad ghost tag."); walk->flags &= ~GhostInfo::NotYetGhosted; walk->flags |= GhostInfo::Ghosting; upd->ghostInfoFlags = GhostInfo::Ghosting; bstream->writeInt(tag, 10); } // update the object DWORD retMask = walk->obj->packUpdate(this, updateMask, bstream); AssertFatal((retMask & (~updateMask)) == 0, "Cannot set new bits in packUpdate return"); walk->updateMask = retMask; upd->mask = updateMask & ~retMask; PacketStream::getStats()->addBits(PacketStats::Send, bstream->getCurPos() - startPos, walk->obj->getPersistTag()); #ifdef DEBUG_NET // write out a checksum... // we'll check this on the other side for validation // later we can put in stuff to check sizes and such bstream->writeInt(walk->ghostIndex ^ DebugChecksum, 32); #endif } walk->updateSkipCount = 0; } } // no more objects... bstream->writeFlag(false); key = (DWORD) updateList; if(curMode == GhostScopeAlwaysMode) { // if this is our mode, // loop through all the objects // if they all have been ghosted, (ie, flags NotYetGhosted and // Ghosting are NOT set), then tag this packet as the ghost always // done packet // just a bit of advanced warning to the other side to add all its // objects. (if this packet is dropped - no big deal, read will // figure it out when it gets a normal ghost packet) walk = ghostList; bool allGhosted = true; while(walk) { if(walk->flags & (GhostInfo::NotYetGhosted | GhostInfo::Ghosting)) { allGhosted = false; break; } walk = walk->nextRef; } bstream->writeFlag(allGhosted); if(allGhosted) { curMode = GhostNormalMode; CSDelegate *delegate = (CSDelegate *) manager->findObject(SimCSDelegateId); if(delegate) delegate->onGhostAlwaysDone(getOwner()); } } return true; }