std::pair<float, int> Layer::calculateOptimalLayerParms(const RodTemplate& rodTemplate) { // CUIDADO fix placeRadiusHint!!!!! double maxDsDistance = (*std::max_element(rodTemplate.begin(), rodTemplate.end(), [](const unique_ptr<BarrelModule>& m1, const unique_ptr<BarrelModule>& m2) { return m1->dsDistance() > m2->dsDistance(); } ))->dsDistance(); float moduleWidth = (*rodTemplate.rbegin())->minWidth(); float f = moduleWidth/2 - phiOverlap()/2; float gamma = atan(f/(placeRadiusHint() + bigDelta() + smallDelta() + maxDsDistance/2)) + atan(f/(placeRadiusHint() - bigDelta() + smallDelta() + maxDsDistance/2)); float tentativeModsPerSegment = 2*M_PI/(gamma * phiSegments()); float optimalRadius; int optimalModsPerSegment; switch (radiusMode()) { case SHRINK: optimalModsPerSegment = floor(tentativeModsPerSegment); optimalRadius = calculatePlaceRadius(optimalModsPerSegment*phiSegments(), bigDelta(), smallDelta(), maxDsDistance, moduleWidth, phiOverlap()); break; case ENLARGE: optimalModsPerSegment = ceil(tentativeModsPerSegment); optimalRadius = calculatePlaceRadius(optimalModsPerSegment*phiSegments(), bigDelta(), smallDelta(), maxDsDistance, moduleWidth, phiOverlap()); break; case FIXED: optimalModsPerSegment = ceil(tentativeModsPerSegment); optimalRadius = placeRadiusHint(); break; case AUTO: { int modsPerSegLo = floor(tentativeModsPerSegment); int modsPerSegHi = ceil(tentativeModsPerSegment); float radiusLo = calculatePlaceRadius(modsPerSegLo*phiSegments(), bigDelta(), smallDelta(), maxDsDistance, moduleWidth, phiOverlap()); float radiusHi = calculatePlaceRadius(modsPerSegHi*phiSegments(), bigDelta(), smallDelta(), maxDsDistance, moduleWidth, phiOverlap()); if (fabs(radiusHi - placeRadiusHint()) < fabs(radiusLo - placeRadiusHint())) { optimalRadius = radiusHi; optimalModsPerSegment = modsPerSegHi; } else { optimalRadius = radiusLo; optimalModsPerSegment = modsPerSegLo; } break; } default: throw PathfulException("Invalid value for enum radiusMode"); } return std::make_pair(optimalRadius, optimalModsPerSegment*phiSegments()); }
void Layer::buildStraight() { RodTemplate rodTemplate = makeRodTemplate(); std::pair<double, int> optimalLayerParms = calculateOptimalLayerParms(rodTemplate); placeRadius_ = optimalLayerParms.first; numRods_ = optimalLayerParms.second; if (!minBuildRadius.state() || !maxBuildRadius.state()) { minBuildRadius(placeRadius_); maxBuildRadius(placeRadius_); } float rodPhiRotation = 2*M_PI/numRods_; StraightRodPair* first = GeometryFactory::make<StraightRodPair>(); first->myid(1); first->minBuildRadius(minBuildRadius()-bigDelta()); first->maxBuildRadius(maxBuildRadius()+bigDelta()); if (buildNumModules() > 0) first->buildNumModules(buildNumModules()); else if (maxZ.state()) first->maxZ(maxZ()); first->smallDelta(smallDelta()); //first->ringNode = ringNode; // we need to pass on the contents of the ringNode to allow the RodPair to build the module decorators first->store(propertyTree()); first->build(rodTemplate); logINFO(Form("Copying rod %s", fullid(*this).c_str())); StraightRodPair* second = GeometryFactory::clone(*first); second->myid(2); if (!sameParityRods()) second->zPlusParity(first->zPlusParity()*-1); first->translateR(placeRadius_ + (bigParity() > 0 ? bigDelta() : -bigDelta())); //first->translate(XYZVector(placeRadius_+bigDelta(), 0, 0)); rods_.push_back(first); second->translateR(placeRadius_ + (bigParity() > 0 ? -bigDelta() : bigDelta())); //second->translate(XYZVector(placeRadius_-bigDelta(), 0, 0)); second->rotateZ(rodPhiRotation); rods_.push_back(second); for (int i = 2; i < numRods_; i++) { RodPair* rod = i%2 ? GeometryFactory::clone(*second) : GeometryFactory::clone(*first); // clone rods rod->myid(i+1); rod->rotateZ(rodPhiRotation*(i%2 ? i-1 : i)); rods_.push_back(rod); } }
void HifiClientProcessList::clientCatchup(GameConnection * connection) { #ifdef TORQUE_DEBUG_NET_MOVES Con::printf("client catching up... (%i)%s", mCatchup, mForceHifiReset ? " reset" : ""); #endif if (connection->getControlObject() && connection->getControlObject()->isGhostUpdated()) // if control object is reset, make sure moves are reset too connection->mMoveList->resetCatchup(); const F32 maxVel = mSqrt(gMaxHiFiVelSq) * 1.25f; F32 dt = F32(mCatchup+1) * TickSec; Point3F bigDelta(maxVel*dt,maxVel*dt,maxVel*dt); // walk through all process objects looking for ones which were updated // -- during first pass merely collect neighbors which need to be reset and updated in unison ProcessObject * pobj; if (mCatchup && !mForceHifiReset) { for (pobj = mHead.mProcessLink.next; pobj != &mHead; pobj = pobj->mProcessLink.next) { GameBase *obj = getGameBase( pobj ); static SimpleQueryList nearby; nearby.mList.clear(); // check for nearby objects which need to be reset and then caught up // note the funky loop logic -- first time through obj is us, then // we start iterating through nearby list (to look for objects nearby // the nearby objects), which is why index starts at -1 // [objects nearby the nearby objects also get added to the nearby list] for (S32 i=-1; obj; obj = ++i<nearby.mList.size() ? (GameBase*)nearby.mList[i] : NULL) { if (obj->isGhostUpdated() && (obj->getTypeMask() & GameBaseHiFiObjectType) && !obj->isNetNearbyAdded()) { Point3F start = obj->getWorldSphere().center; Point3F end = start + 1.1f * dt * obj->getVelocity(); F32 rad = 1.5f * obj->getWorldSphere().radius; // find nearby items not updated but are hi fi, mark them as updated (and restore old loc) // check to see if added items have neighbors that need updating Box3F box; Point3F rads(rad,rad,rad); box.minExtents = box.maxExtents = start; box.minExtents -= bigDelta + rads; box.maxExtents += bigDelta + rads; // CodeReview - this is left in for MBU, but also so we can deal with the issue later. // add marble blast hack so hifi networking can see hidden objects // (since hidden is under control of hifi networking) // gForceNotHidden = true; S32 j = nearby.mList.size(); gClientContainer.findObjects(box, GameBaseHiFiObjectType, SimpleQueryList::insertionCallback, &nearby); // CodeReview - this is left in for MBU, but also so we can deal with the issue later. // disable above hack // gForceNotHidden = false; // drop anyone not heading toward us or already checked for (; j<nearby.mList.size(); j++) { GameBase * obj2 = (GameBase*)nearby.mList[j]; // if both passive, these guys don't interact with each other bool passive = obj->isHifiPassive() && obj2->isHifiPassive(); if (!obj2->isGhostUpdated() && !passive) { // compare swept spheres of obj and obj2 // if collide, reset obj2, setGhostUpdated(true), and continue Point3F end2 = obj2->getWorldSphere().center; Point3F start2 = end2 - 1.1f * dt * obj2->getVelocity(); F32 rad2 = 1.5f * obj->getWorldSphere().radius; if (MathUtils::capsuleCapsuleOverlap(start,end,rad,start2,end2,rad2)) { // better add obj2 obj2->getTickCache().beginCacheList(); TickCacheEntry * tce = obj2->getTickCache().incCacheList(); BitStream bs(tce->packetData,TickCacheEntry::MaxPacketSize); obj2->readPacketData(connection,&bs); obj2->setGhostUpdated(true); // continue so we later add the neighbors too continue; } } // didn't pass above test...so don't add it or nearby objects nearby.mList[j] = nearby.mList.last(); nearby.mList.decrement(); j--; } obj->setNetNearbyAdded(true); } } } } // save water mark -- for game base list FrameAllocatorMarker mark; // build ordered list of client objects which need to be caught up GameBaseListNode list; for (pobj = mHead.mProcessLink.next; pobj != &mHead; pobj = pobj->mProcessLink.next) { GameBase *obj = getGameBase( pobj ); //GameBase *obj = dynamic_cast<GameBase*>( pobj ); //GameBase *obj = (GameBase*)pobj; // Not a GameBase object so nothing to do. if ( !obj ) continue; if (obj->isGhostUpdated() && (obj->getTypeMask() & GameBaseHiFiObjectType)) { // construct process object and add it to the list // hold pointer to our object in mAfterObject GameBaseListNode * po = (GameBaseListNode*)FrameAllocator::alloc(sizeof(GameBaseListNode)); po->mObject = obj; po->linkBefore(&list); // begin iterating through tick list (skip first tick since that is the state we've been reset to) obj->getTickCache().beginCacheList(); obj->getTickCache().incCacheList(); } else if (mForceHifiReset && (obj->getTypeMask() & GameBaseHiFiObjectType)) { // add all hifi objects obj->getTickCache().beginCacheList(); TickCacheEntry * tce = obj->getTickCache().incCacheList(); BitStream bs(tce->packetData,TickCacheEntry::MaxPacketSize); obj->readPacketData(connection,&bs); obj->setGhostUpdated(true); // construct process object and add it to the list // hold pointer to our object in mAfterObject GameBaseListNode * po = (GameBaseListNode*)FrameAllocator::alloc(sizeof(GameBaseListNode)); po->mObject = obj; po->linkBefore(&list); } else if (obj == connection->getControlObject() && obj->isGhostUpdated()) { // construct process object and add it to the list // hold pointer to our object in mAfterObject // .. but this is not a hi fi object, so don't mess with tick cache GameBaseListNode * po = (GameBaseListNode*)FrameAllocator::alloc(sizeof(GameBaseListNode)); po->mObject = obj; po->linkBefore(&list); } else if (obj->isGhostUpdated()) { // not hifi but we were updated, so perform net smooth now obj->computeNetSmooth(mLastDelta); } // clear out work flags obj->setNetNearbyAdded(false); obj->setGhostUpdated(false); } // run through all the moves in the move list so we can play them with our control object Move* movePtr; U32 numMoves; connection->mMoveList->resetClientMoves(); connection->mMoveList->getMoves(&movePtr, &numMoves); AssertFatal(mCatchup<=numMoves,"doh"); // tick catchup time for (U32 m=0; m<mCatchup; m++) { for (GameBaseListNode * walk = list.mNext; walk != &list; walk = walk->mNext) { // note that we get object from after object not getGameBase function // this is because we are an on the fly linked list which uses mAfterObject // rather than the linked list embedded in GameBase (clean this up?) GameBase * obj = walk->mObject; // it's possible for a non-hifi object to get in here, but // only if it is a control object...make sure we don't do any // of the tick cache stuff if we are not hifi. bool hifi = obj->getTypeMask() & GameBaseHiFiObjectType; TickCacheEntry * tce = hifi ? obj->getTickCache().incCacheList() : NULL; // tick object if (obj==connection->getControlObject()) { obj->processTick(movePtr); movePtr->checksum = obj->getPacketDataChecksum(connection); movePtr++; } else { AssertFatal(tce && hifi,"Should not get in here unless a hi fi object!!!"); obj->processTick(tce->move); } if (hifi) { BitStream bs(tce->packetData,TickCacheEntry::MaxPacketSize); obj->writePacketData(connection,&bs); } } if (connection->getControlObject() == NULL) movePtr++; } connection->mMoveList->clearMoves(mCatchup); // Handle network error smoothing here...but only for control object GameBase * control = connection->getControlObject(); if (control && !control->isNewGhost()) { control->computeNetSmooth(mLastDelta); control->setNewGhost(false); } if (moveSync.doAction() && moveSync.moveDiff>0) { S32 moveDiff = moveSync.moveDiff; #ifdef TORQUE_DEBUG_NET_MOVES Con::printf("client timewarping to catchup %i moves",moveDiff); #endif while (moveDiff--) advanceObjects(); moveSync.reset(); } #ifdef TORQUE_DEBUG_NET_MOVES Con::printf("---------"); #endif // all caught up mCatchup = 0; }