void AMatineeActor::PostNetReceive() { Super::PostNetReceive(); if (MatineeData != NULL) { TArray<AActor*> ControlledActors; // Build a list of actors controlled by this matinee actor for( int32 InfoIndex = 0; InfoIndex < GroupActorInfos.Num(); ++InfoIndex ) { const FInterpGroupActorInfo& Info = GroupActorInfos[ InfoIndex ]; for (int32 ActorIndex = 0; ActorIndex < Info.Actors.Num(); ++ActorIndex ) { AActor* Actor = Info.Actors[ ActorIndex ]; if (Actor != NULL) { ControlledActors.Add( Actor ); } } } // if we just received the matinee action, set 'saved' values to default so we make sure to apply previously received values if (SavedInterpData == NULL) { AMatineeActor* Default = GetClass()->GetDefaultObject<AMatineeActor>(); SavedbIsPlaying = Default->bIsPlaying; SavedPosition = Default->InterpPosition; SavedbReversePlayback = Default->bReversePlayback; } // Handle replication of flag saying that bIsPlaying really should have replicated as true. if (SavedReplicationForceIsPlaying != ReplicationForceIsPlaying) { bIsPlaying = true; } // apply bReversePlayback if (SavedbReversePlayback!= bReversePlayback) { if (SavedbIsPlaying && bIsPlaying) { // notify actors that something has changed for (int32 ActorIndex = 0; ActorIndex < ControlledActors.Num(); ++ActorIndex ) { IMatineeInterface * IMI = Cast<IMatineeInterface>(ControlledActors[ActorIndex]); if (IMI) { IMI->InterpolationChanged(this); } } } } // start up interpolation, if necessary if (!SavedbIsPlaying && (bIsPlaying || InterpPosition != SavedPosition)) { InitInterp(); // if we're playing forward, call Play() to process any special properties on InterpAction that may affect the meaning of 'Position' (bNoResetOnRewind, etc) if (!bReversePlayback) { Play(); } // find affected actors and set their ControllingMatineeActor // @warning: this code requires the linked actors to be static object references (i.e., some other Kismet action can't be assigning them) // this might not work for AI pawns for (int32 ActorIndex = 0; ActorIndex < ControlledActors.Num(); ++ActorIndex ) { AActor* Actor = ControlledActors[ActorIndex]; UInterpGroupInst * GrInst = FindGroupInst(Actor); if (Actor != NULL && !Actor->IsPendingKill() && GrInst != NULL) { Actor->AddControllingMatineeActor(*this); // fire an event if we're really playing (and not just starting it up to do a position update) if (bIsPlaying) { IMatineeInterface * IMI = Cast<IMatineeInterface>(Actor); if (IMI) { IMI->InterpolationStarted(this); } } } } } // if we received a different current position if (InterpPosition != SavedPosition) { //@hack: negate fade tracks if we're updating a stopped matinee // the right fix is probably to pass bJump=true to UpdateInterp() when (!bIsPlaying && !SavedbIsPlaying), // but that may have lots of other side effects I don't have time to test right now TArray<FSavedFadeState> SavedFadeStates; if (!bIsPlaying && !SavedbIsPlaying && MatineeData != NULL) { for (FLocalPlayerIterator It(GEngine, GetWorld()); It; ++It) { if (It->PlayerController != NULL && It->PlayerController->PlayerCameraManager != NULL) { new(SavedFadeStates)FSavedFadeState(It->PlayerController->PlayerCameraManager); } } } if (bIsPlaying && SavedPosition != -1 && FMath::Abs(InterpPosition - SavedPosition) < ClientSidePositionErrorTolerance) { // The error value between us and the server is too small to change gameplay, but will cause visual pops InterpPosition = SavedPosition; } else { // set to position replicated from server UpdateInterp(InterpPosition, false, false); } } // terminate interpolation, if necessary if ((SavedbIsPlaying || InterpPosition != SavedPosition) && !bIsPlaying) { TermInterp(); // find affected actors and remove InterpAction from their LatentActions list for (int32 ActorIndex = 0; ActorIndex < ControlledActors.Num(); ++ActorIndex ) { AActor* Actor = ControlledActors[ ActorIndex ]; if (Actor != NULL) { Actor->RemoveControllingMatineeActor(*this); // fire an event if we were really playing (and not just starting it up to do a position update) if (SavedbIsPlaying) { IMatineeInterface * IMI = Cast<IMatineeInterface>(Actor); if (IMI) { IMI->InterpolationFinished(this); } } } } } } }
zOPER_EXPORT zLONG OPERATION InvokeInterp( zVIEW lpInterpSubtask, // Interpretor's subtask zVIEW lpAppSubtask, // application's subtask zPCHAR szSrcDLLName, // name of the dialog zPCHAR szOperationName, // operation to interp zPLONG plRC ) { zVIEW vXChecker; zSHORT nRC; zLONG lStepRC; zVIEW vStackObject; // view to the stack object zVIEW vS_View; zVIEW vZ_View; zVIEW vSO; zVIEW vSubtask = 0; zVIEW vTaskLPLR; zPVOID hWRKS = NULL; // Check to make sure the LPLR is active. GetViewByName( &vTaskLPLR, "TaskLPLR", lpAppSubtask, zLEVEL_TASK ); if ( vTaskLPLR == 0 ) InitializeLPLR( lpInterpSubtask, "" ); aInterpreterSave[ lMultiple ].vSubtask = lpInterpSubtask; if ( lMultiple > 0 ) { if ( lMultiple >= MAX_INTEPRETER_ENTRY ) { // Error, because number of recursive entries // is greater than MAX_INTEPRETER_ENTRY return( -99 ); } vSubtask = aInterpreterSave[ lMultiple -1 ].vSubtask; // save the global variables aInterpreterSave[ lMultiple -1 ].nStackPtr = g_nStackPtr; g_nStackPtr = 0; memcpy( aInterpreterSave[ lMultiple -1 ].nCallStack, g_nCallStack, zsizeof( g_nCallStack ) ); memset( g_nCallStack, 0, zsizeof( g_nCallStack ) ); aInterpreterSave[ lMultiple -1 ].vXPGView = g_vXPGView; g_vXPGView = 0; GetViewByName( &g_vStatementView, "StatementView", vSubtask, zLEVEL_SUBTASK ); aInterpreterSave[ lMultiple -1 ].vStatementView = g_vStatementView; g_vStatementView = 0; GetViewByName( &vSO, "StackObject", vSubtask, zLEVEL_SUBTASK ); aInterpreterSave[ lMultiple -1 ].vStackObject = vSO; memcpy( aInterpreterSave[ lMultiple -1 ].sValueStack, sValueStack, zsizeof( sValueStack ) ); memset( sValueStack, 0, zsizeof( sValueStack ) ); } lMultiple++; // see if we can load the XPG. if not, don't parse for now, exit out nRC = InitInterp( lpInterpSubtask, lpAppSubtask, szSrcDLLName ); if ( nRC < 0 ) { lStepRC = 1; // if the init failed return. goto EndOfInvokeInterp; } // Initialize the Working Storage Manager if ( WRKS_Init( &hWRKS ) < 0 ) { // Error in WRKS system MessageSend( vSubtask, "VM03002", "VML Interpretor", "Error Initializing Work Storage", zMSGQ_OBJECT_CONSTRAINT_ERROR, zBEEP ); TraceLineS( "VML Interpreter Error ","Initializing Work Storage" ); lStepRC = 1; // if the init failed return. goto EndOfInvokeInterp; } if ( setjmp( g_jbWRKS ) != 0 ) { // Error return from longjmp WRKS_Close( &hWRKS ); lStepRC = 1; goto EndOfInvokeInterp; } // get the program object as it was loaded by the init function. GetViewByName( &g_vXPGView, "XPG", lpInterpSubtask, zLEVEL_SUBTASK ); // try to position at the correct operation in the Subtask nRC = SetCursorFirstEntityByString( g_vXPGView, "Operation", "Name", szOperationName, "" ); if ( nRC != zCURSOR_SET ) { // no error message here, as we assume that the operation // to be called is a C operation. // Returning -1, the driver will try to load it from the DLL lStepRC = -1; goto EndOfInvokeInterp; } SetCursorFirstEntityByEntityCsr( g_vXPGView, "SourceFile", g_vXPGView, "SourceFileOfOperation", "" ); SetCursorFirstEntityByEntityCsr( g_vXPGView, "OperationSource", g_vXPGView, "Operation", "" ); SetCursorFirstEntity( g_vXPGView, "OperationText", "" ); SetCursorFirstEntity( g_vXPGView, "Statement", "" ); CreateViewFromViewForTask( &g_vStatementView, g_vXPGView, 0 ); // Create all of the entities needed in the stack object SetStackObjectFromViews( lpInterpSubtask, g_vXPGView, // View to the XPG g_vStatementView, // View to the statement 0 ); // index into the expression // Get the stack object as it was loaded with the XPG GetViewByName( &vStackObject, "StackObject", lpInterpSubtask, zLEVEL_SUBTASK ); // ###blob SetAttributeFromInteger( vStackObject, // "Variable", "Value", (zLONG)lpAppSubtask ); SetAttributeFromBlob( vStackObject, "Variable", "Value", &lpAppSubtask, sizeof( void * ) ); SetNameForView( g_vStatementView, "StatementView", lpInterpSubtask, zLEVEL_SUBTASK ); SetNameForView( lpAppSubtask, "ApplicationView", lpInterpSubtask, zLEVEL_SUBTASK ); GetViewByName( &vXChecker, "TZVSXCOO", lpInterpSubtask, zLEVEL_APPLICATION ); if ( vXChecker != 0 ) { nRC = SetCursorFirstEntityByString( vXChecker, "DialogOperation", "Name", szOperationName, "" ); if ( nRC == zCURSOR_SET ) { GetViewByName( &vZ_View, "ZeidonVML", vSubtask, zLEVEL_TASK ); GetViewByName( &vS_View, "XPG", vZ_View, zLEVEL_SUBTASK ); SetAttributeFromString( vS_View, "Operation", "CurrentDebugFlag", "Y" ); lStepRC = zXC_SETUP_DEBUGGER; goto EndOfInvokeInterp; } } // lStepRC = zXC_STEP_EXECUTED; #if 0 OperationCount( 3 ); OperationCount( 1 ); #endif // Loop through each statement using the Go function. lStepRC = Go( lpAppSubtask, hWRKS, plRC ); EndOfInvokeInterp: // close work storage manager if ( hWRKS ) WRKS_Close( &hWRKS ); lMultiple--; if ( lMultiple > 0 ) { vSubtask = aInterpreterSave[ lMultiple - 1 ].vSubtask; // restore the global variables g_nStackPtr = aInterpreterSave[ lMultiple - 1 ].nStackPtr; memcpy( g_nCallStack, aInterpreterSave[ lMultiple -1 ].nCallStack, zsizeof( g_nCallStack ) ); g_vXPGView = aInterpreterSave[ lMultiple - 1 ].vXPGView; SetNameForView( g_vXPGView, "XPG", vSubtask, zLEVEL_SUBTASK ); g_vStatementView = aInterpreterSave[ lMultiple - 1 ].vStatementView; SetNameForView( g_vStatementView, "StatementView", vSubtask, zLEVEL_SUBTASK ); vSO = aInterpreterSave[ lMultiple - 1 ].vStackObject; SetNameForView( vSO, "StackObject", vSubtask, zLEVEL_SUBTASK ); memcpy( sValueStack, aInterpreterSave[ lMultiple - 1 ].sValueStack, zsizeof( sValueStack ) ); } return( lStepRC ); }