FBT_FlyToTarget* UBTTask_FlyTo::TaskMemoryFromGenericPayload(void* GenericPayload) { // A brief explanation of the "NodeMemory" and "Generic Payload" business: // AFAICT, Behavior tree tasks operate as singletons and internally maintain an instance memory stack which maps instance data for every AI currently running this task. // So the BT Task itself is shared by all AI pawns and does not have sufficient information to handle our result delegate on its own. // Because of this, we use a custom delegate payload (which we passed earlier in "ExecuteTask") to lookup the actual AI owner and the correct NodeMemory // inside which we store the pathfinding results. auto payload = static_cast<FBT_FlyToTarget_Metadata*> (GenericPayload); auto ownerComp = payload ? payload->OwnerComp.Get() : NULL; // Is the pawn's BrainComponent still alive and valid? if (!ownerComp) return NULL; // Is it still working on this task or has it moved on to another one? if (ownerComp->GetActiveNode() != this) return NULL; // Validations passed, should be safe to work on NodeMemory now: auto nodeMemory = ownerComp->GetNodeMemory(this, ownerComp->GetActiveInstanceIdx()); auto myMemory = nodeMemory ? reinterpret_cast<FBT_FlyToTarget*> (nodeMemory) : NULL; return myMemory; }
void ShutDownCommentary( void ) { if ( GetActiveNode() ) { GetActiveNode()->AbortPlaying(); } // Destroy all the entities created by commentary for ( int i = m_hSpawnedEntities.Count()-1; i >= 0; i-- ) { if ( m_hSpawnedEntities[i] ) { UTIL_Remove( m_hSpawnedEntities[i] ); } } m_hSpawnedEntities.Purge(); m_iCommentaryNodeCount = 0; // Remove the commentary semaphore CBaseEntity *pSemaphore = gEntList.FindEntityByName( NULL, COMMENTARY_SPAWNED_SEMAPHORE ); if ( pSemaphore ) { UTIL_Remove( pSemaphore ); } // Remove our global convar callback cvar->InstallGlobalChangeCallback( NULL ); // Reset any convars that have been changed by the commentary for ( int i = 0; i < m_ModifiedConvars.Count(); i++ ) { ConVar *pConVar = (ConVar *)cvar->FindVar( m_ModifiedConvars[i].pszConvar ); if ( pConVar ) { pConVar->SetValue( m_ModifiedConvars[i].pszOrgValue ); } } m_ModifiedConvars.Purge(); m_hCurrentNode = NULL; m_hActiveCommentaryNode = NULL; }
virtual void FrameUpdatePrePlayerRunCommand( void ) { if ( !IsInCommentaryMode() ) return; CPointCommentaryNode *pCurrentNode = GetNodeUnderCrosshair(); // Changed nodes? if ( m_hCurrentNode != pCurrentNode ) { // Stop animating the old one if ( m_hCurrentNode.Get() ) { m_hCurrentNode->SetUnderCrosshair( false ); } // Start animating the new one if ( pCurrentNode ) { pCurrentNode->SetUnderCrosshair( true ); } m_hCurrentNode = pCurrentNode; } // Check for commentary node activations CBasePlayer *pPlayer = IGameSystem::RunCommandPlayer(); CUserCmd *pUserCmds = IGameSystem::RunCommandUserCmd(); if ( pPlayer ) { // Has the player pressed down an attack button? int buttonsChanged = m_afPlayersLastButtons ^ pUserCmds->buttons; int buttonsPressed = buttonsChanged & pUserCmds->buttons; m_afPlayersLastButtons = pUserCmds->buttons; if ( !(pUserCmds->buttons & COMMENTARY_BUTTONS) ) { m_iClearPressedButtons &= ~COMMENTARY_BUTTONS; } // Detect press events to start/stop commentary nodes if (buttonsPressed & COMMENTARY_BUTTONS) { // Looking at a node? if ( m_hCurrentNode ) { // Ignore input while an unstoppable node is playing if ( !GetActiveNode() || !GetActiveNode()->CannotBeStopped() ) { // If we have an active node already, stop it if ( GetActiveNode() && GetActiveNode() != m_hCurrentNode ) { GetActiveNode()->StopPlaying(); } m_hCurrentNode->PlayerActivated(); } // Prevent weapon firing when toggling nodes pUserCmds->buttons &= ~COMMENTARY_BUTTONS; m_iClearPressedButtons |= (buttonsPressed & COMMENTARY_BUTTONS); } else if ( GetActiveNode() && GetActiveNode()->HasViewTarget() ) { if ( !GetActiveNode()->CannotBeStopped() ) { GetActiveNode()->StopPlaying(); } // Prevent weapon firing when toggling nodes pUserCmds->buttons &= ~COMMENTARY_BUTTONS; m_iClearPressedButtons |= (buttonsPressed & COMMENTARY_BUTTONS); } } if ( GetActiveNode() && GetActiveNode()->PreventsMovement() ) { pUserCmds->buttons &= ~(IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT | IN_JUMP | IN_DUCK ); pUserCmds->upmove = 0; pUserCmds->sidemove = 0; pUserCmds->forwardmove = 0; } // When we swallow button down events, we have to keep clearing that button // until the player releases the button. Otherwise, the frame after we swallow // it, the code detects the button down and goes ahead as normal. pUserCmds->buttons &= ~m_iClearPressedButtons; } }