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);
}
Exemple #2
0
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);
}
Exemple #3
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());
            }
        }
    }
}
Exemple #5
0
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;
}
Exemple #6
0
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;
}
Exemple #7
0
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);
}