void plPXPhysical::SetSyncState(hsPoint3* pos, hsQuat* rot, hsVector3* linV, hsVector3* angV) { bool isLoading = plNetClientApp::GetInstance()->IsLoadingInitialAgeState(); bool isFirstIn = plNetClientApp::GetInstance()->GetJoinOrder() == 0; bool initialSync = isLoading && isFirstIn; // If the physical has fallen out of the sim, and this is initial age state, and we're // the first person in, reset it to the original position. (ie, prop the default state // we've got right now) if (pos && pos->fZ < kMaxNegativeZPos && initialSync) { SimLog("Physical %s loaded out of range state. Forcing initial state to server.", GetKeyName().c_str()); DirtySynchState(kSDLPhysical, plSynchedObject::kBCastToClients); return; } if (pos) ISetPositionSim(*pos); if (rot) ISetRotationSim(*rot); if (linV) SetLinearVelocitySim(*linV); if (angV) SetAngularVelocitySim(*angV); // If we're loading the age, then we should ensure the objects // stay asleep if they're supposed to be asleep. if (isLoading && GetProperty(plSimulationInterface::kStartInactive) && !fActor->readBodyFlag(NX_BF_KINEMATIC)) fActor->putToSleep(); SendNewLocation(false, true); }
void plResponderModifier::IFastForward(bool python) { ResponderLog(ILog(plStatusLog::kGreen, "Fast Forward")); fCurCommand = 0; plResponderState& state = fStates[fCurState]; while (fCurCommand < state.fCmds.Count()) { plMessage *msg = state.fCmds[fCurCommand].fMsg; msg = IGetFastForwardMsg(msg, python); if (msg) plgDispatch::MsgSend(msg); fCurCommand++; } ResponderLog(ILog(plStatusLog::kGreen, "Reset")); fCurCommand = -1; ISetResponderState(state.fSwitchToState); plSynchEnabler enable(true); DirtySynchState(kSDLResponder, 0); }
void plResponderModifier::Trigger(plNotifyMsg *msg) { #if 0 plNetClientApp::GetInstance()->DebugMsg("RM: Responder {} is triggering, num cmds={}, enabled={}, curCmd={}, t={f}\n", GetKeyName(), fStates[fCurState].fCmds.GetCount(), fEnabled, fCurCommand, hsTimer::GetSysSeconds()); #endif // If we're not in the middle of sending, reset and start sending commands if (fCurCommand == int8_t(-1) && fEnabled) { ResponderLog(ILog(plStatusLog::kGreen, "Trigger")); fNotifyMsgFlags = msg->GetAllBCastFlags(); fTriggerer = msg->GetSender(); fPlayerKey = msg->GetAvatarKey(); ISetResponderStateFromNotify(msg); proCollisionEventData *cEvent = (proCollisionEventData *)msg->FindEventRecord(proEventData::kCollision); fEnter = (cEvent ? cEvent->fEnter : false); fCompletedEvents.Reset(); fCurCommand = 0; DirtySynchState(kSDLResponder, 0); IContinueSending(); } else { ResponderLog(ILog(plStatusLog::kRed, "Rejected Trigger, %s", !fEnabled ? "responder disabled" : "responder is running")); } }
// Called after the simulation has run....sends new positions to the various scene objects // *** want to do this in response to an update message.... void plPXPhysical::SendNewLocation(bool synchTransform, bool isSynchUpdate) { // we only send if: // - the body is active or forceUpdate is on // - the mass is non-zero // - the physical is not passive bool bodyActive = !fActor->isSleeping(); bool dynamic = fActor->isDynamic(); if ((bodyActive || isSynchUpdate) && dynamic)// && fInitialTransform) { plProfile_Inc(MaySendLocation); if (!GetProperty(plSimulationInterface::kPassive)) { hsMatrix44 curl2w = fCachedLocal2World; // we're going to cache the transform before sending so we can recognize if it comes back IGetTransformGlobal(fCachedLocal2World); if (!CompareMatrices(curl2w, fCachedLocal2World, .0001f)) { plProfile_Inc(LocationsSent); plProfile_BeginLap(PhysicsUpdates, GetKeyName().c_str()); // quick peek at the translation...last time it was corrupted because we applied a non-unit quaternion // hsAssert(real_finite(fCachedLocal2World.fMap[0][3]) && // real_finite(fCachedLocal2World.fMap[1][3]) && // real_finite(fCachedLocal2World.fMap[2][3]), "Bad transform outgoing"); if (fCachedLocal2World.GetTranslate().fZ < kMaxNegativeZPos) { SimLog("Physical %s fell to %.1f (%.1f is the max). Suppressing.", GetKeyName().c_str(), fCachedLocal2World.GetTranslate().fZ, kMaxNegativeZPos); // Since this has probably been falling for a while, and thus not getting any syncs, // make sure to save it's current pos so we'll know to reset it later DirtySynchState(kSDLPhysical, plSynchedObject::kBCastToClients); IEnable(false); } hsMatrix44 w2l; fCachedLocal2World.GetInverse(&w2l); plCorrectionMsg *pCorrMsg = new plCorrectionMsg(GetObjectKey(), fCachedLocal2World, w2l, synchTransform); pCorrMsg->Send(); if (fProxyGen) fProxyGen->SetTransform(fCachedLocal2World, w2l); plProfile_EndLap(PhysicsUpdates, GetKeyName().c_str()); } } } }
bool plLayerAnimation::MsgReceive(plMessage* msg) { // pass sdl msg to sdlMod plSDLModifierMsg* sdlMsg = plSDLModifierMsg::ConvertNoRef(msg); if (sdlMsg && fLayerSDLMod) { if (fLayerSDLMod->MsgReceive(sdlMsg)) return true; // msg handled } bool retVal = false; plAnimCmdMsg* cmdMsg = plAnimCmdMsg::ConvertNoRef(msg); if( cmdMsg ) { // Evaluate first, so we'll be transitioning from our // real current state, whether we've been evaluated (in view) // lately or not. TopOfStack()->Eval(hsTimer::GetSysSeconds(), 0, 0); retVal = fTimeConvert.HandleCmd(cmdMsg); DirtySynchState(kSDLLayer, 0); } if( retVal ) { if( !fTimeConvert.IsStopped() || fTimeConvert.GetFlag(plAnimTimeConvert::kForcedMove) ) { ClaimChannels(fOwnedChannels); fCurrentTime = -1.f; // force an eval } } else { retVal = plLayerAnimationBase::MsgReceive(msg); } return retVal; }
bool plResponderModifier::IContinueSending() { // If we haven't been started, exit if (fCurCommand == int8_t(-1)) return false; plResponderState& state = fStates[fCurState]; while (fCurCommand < state.fCmds.Count()) { plMessage *msg = state.fCmds[fCurCommand].fMsg; if (msg) { // If this command needs to wait, and it's condition hasn't been met yet, exit int8_t wait = state.fCmds[fCurCommand].fWaitOn; if (wait != -1 && !fCompletedEvents.IsBitSet(wait)) { ResponderLog(ILog(plStatusLog::kWhite, "Command %d is waiting for command %d(id:%d)", int8_t(fCurCommand)+1, ICmdFromWait(wait)+1, wait)); return false; } if (!(fNotifyMsgFlags & plMessage::kNetNonLocal)|| !IIsLocalOnlyCmd(msg)) { // make sure outgoing msgs inherit net flags as part of cascade uint32_t msgFlags = msg->GetAllBCastFlags(); plNetClientApp::InheritNetMsgFlags(fNotifyMsgFlags, &msgFlags, true); msg->SetAllBCastFlags(msgFlags); // If this is a responder message, let it know which player triggered this if (plResponderMsg* responderMsg = plResponderMsg::ConvertNoRef(msg)) { responderMsg->fPlayerKey = fPlayerKey; } else if (plNotifyMsg* notifyMsg = plNotifyMsg::ConvertNoRef(msg)) { bool foundCollision = false; // If we find a collision event, this message is meant to trigger a multistage for (int i = 0; i < notifyMsg->GetEventCount(); i++) { proEventData* event = notifyMsg->GetEventRecord(i); if (event->fEventType == proEventData::kCollision) { proCollisionEventData* collisionEvent = (proCollisionEventData*)event; collisionEvent->fHitter = fPlayerKey; foundCollision = true; } } // No collision event, this message is for notifying the triggerer if (!foundCollision) { notifyMsg->ClearReceivers(); notifyMsg->AddReceiver(fTriggerer); } notifyMsg->SetSender(GetKey()); } else if (plLinkToAgeMsg* linkMsg = plLinkToAgeMsg::ConvertNoRef(msg)) { if (linkMsg->GetNumReceivers() == 0) { plUoid netUoid(kNetClientMgr_KEY); plKey netKey = hsgResMgr::ResMgr()->FindKey(netUoid); hsAssert(netKey,"NetClientMgr not found"); linkMsg->AddReceiver(netKey); } } else if (plArmatureEffectStateMsg* stateMsg = plArmatureEffectStateMsg::ConvertNoRef(msg)) { stateMsg->ClearReceivers(); stateMsg->AddReceiver(fPlayerKey); stateMsg->fAddSurface = fEnter; } else if (plSubWorldMsg* swMsg = plSubWorldMsg::ConvertNoRef(msg)) { plArmatureMod *avatar = plAvatarMgr::GetInstance()->GetLocalAvatar(); if(avatar) { swMsg->AddReceiver(avatar->GetKey()); } } // If we're in anim debug mode, check if this is an anim play // message so we can put up the cue if (fDebugAnimBox) { plAnimCmdMsg* animMsg = plAnimCmdMsg::ConvertNoRef(msg); if (animMsg && animMsg->Cmd(plAnimCmdMsg::kContinue)) IDebugPlayMsg(animMsg); } if (plTimerCallbackMsg *timerMsg = plTimerCallbackMsg::ConvertNoRef(msg)) { hsRefCnt_SafeRef(timerMsg); plgTimerCallbackMgr::NewTimer(timerMsg->fTime, timerMsg); } else { hsRefCnt_SafeRef(msg); plgDispatch::MsgSend(msg); } } } fCurCommand++; DirtySynchState(kSDLResponder, 0); } // Make sure all callbacks we need to wait on are done before allowing a state switch or restart for (int i = 0; i < state.fNumCallbacks; i++) { if (!fCompletedEvents.IsBitSet(i)) { ResponderLog(ILog(plStatusLog::kWhite, "Can't reset, waiting for command %d(id:%d)", ICmdFromWait(i)+1, i)); return false; } } ResponderLog(ILog(plStatusLog::kGreen, "Reset")); fCurCommand = -1; ISetResponderState(state.fSwitchToState); DirtySynchState(kSDLResponder, 0); return true; }
bool plResponderModifier::MsgReceive(plMessage* msg) { plNotifyMsg* pNMsg = plNotifyMsg::ConvertNoRef(msg); if (pNMsg) { if (pNMsg->fType == plNotifyMsg::kResponderFF) { ISetResponderStateFromNotify(pNMsg); IFastForward(true); } else if (pNMsg->fType == plNotifyMsg::kResponderChangeState) { ISetResponderStateFromNotify(pNMsg); DirtySynchState(kSDLResponder, 0); } else { // assumes state of 0 means untriggered and state of 1 is triggered if ((pNMsg->fState != 0 && (fFlags & kDetectTrigger)) || (pNMsg->fState == 0 && (fFlags & kDetectUnTrigger))) { Trigger(pNMsg); DirtySynchState(kSDLResponder, 0); } } return true; } plResponderEnableMsg *pEnableMsg = plResponderEnableMsg::ConvertNoRef(msg); if (pEnableMsg) { fEnabled = pEnableMsg->fEnable; DirtySynchState(kSDLResponder, 0); return true; } plEventCallbackMsg *pEventMsg = plEventCallbackMsg::ConvertNoRef(msg); plTimerCallbackMsg *timerMsg = plTimerCallbackMsg::ConvertNoRef(msg); if (pEventMsg || timerMsg) { uint32_t waitID = pEventMsg ? pEventMsg->fUser : timerMsg->fID; if (waitID != -1) { // Flag that this callback completed and try sending in case any commands were waiting on this fCompletedEvents.SetBit(waitID); ResponderLog(ILog(plStatusLog::kWhite, "Got callback from command %d(id:%d)", ICmdFromWait((int8_t)waitID)+1, waitID)); IContinueSending(); DirtySynchState(kSDLResponder, 0); } // The is one of the stop callbacks we generated for debug mode else if (fDebugAnimBox) IDebugAnimBox(false); return true; } // pass sdl msg to sdlMod plSDLModifierMsg* sdlMsg = plSDLModifierMsg::ConvertNoRef(msg); if (sdlMsg && fResponderSDLMod) { if (fResponderSDLMod->MsgReceive(sdlMsg)) return true; // msg handled } return plSingleModifier::MsgReceive(msg); }