FString UHTNPlannerComponent::GetDebugInfoString() const
{
	return FString::Printf(TEXT("HTN Planner: %s\n"), *GetNameSafe(CurrentPlannerAsset));
}
void UGameplayCueManager::OnWorldCreated(UWorld* NewWorld, const UWorld::InitializationValues IV )
{
	// Attempting to track down rare GC error where PreallocationInfo_Internal.OwningWorld is not cleaned up.
	ABILITY_LOG(Display, TEXT("UGameplayCueManager::OnWorldCreated %s Key 0x%X . Current PreallocationInfo_Internal: Key 0x%X"), *GetNameSafe(NewWorld), GetTypeHash(FObjectKey(NewWorld)), GetTypeHash(PreallocationInfo_Internal.OwningWorldKey));

	PreallocationInfo_Internal.PreallocatedInstances.Reset();
	PreallocationInfo_Internal.OwningWorldKey = FObjectKey(NewWorld);
}
AGameplayCueNotify_Actor* UGameplayCueManager::GetInstancedCueActor(AActor* TargetActor, UClass* CueClass, const FGameplayCueParameters& Parameters)
{
	QUICK_SCOPE_CYCLE_COUNTER(STAT_GameplayCueManager_GetInstancedCueActor);


	// First, see if this actor already have a GameplayCueNotifyActor already going for this CueClass
	AGameplayCueNotify_Actor* CDO = Cast<AGameplayCueNotify_Actor>(CueClass->ClassDefaultObject);
	FGCNotifyActorKey	NotifyKey(TargetActor, CueClass, 
							CDO->bUniqueInstancePerInstigator ? Parameters.GetInstigator() : nullptr, 
							CDO->bUniqueInstancePerSourceObject ? Parameters.GetSourceObject() : nullptr);

	AGameplayCueNotify_Actor* SpawnedCue = nullptr;
	if (TWeakObjectPtr<AGameplayCueNotify_Actor>* WeakPtrPtr = NotifyMapActor.Find(NotifyKey))
	{		
		SpawnedCue = WeakPtrPtr->Get();
		// If the cue is scheduled to be destroyed, don't reuse it, create a new one instead
		if (SpawnedCue && SpawnedCue->GameplayCuePendingRemove() == false)
		{
			if (SpawnedCue->GetOwner() != TargetActor)
			{
				// This should not happen. This means we think we can recycle and GC actor that is currently being used by someone else.
				ABILITY_LOG(Warning, TEXT("GetInstancedCueActor attempting to reuse GC Actor with a different owner! %s (Target: %s). Using GC Actor: %s. Current Owner: %s"), *GetNameSafe(CueClass), *GetNameSafe(TargetActor), *GetNameSafe(SpawnedCue), *GetNameSafe(SpawnedCue->GetOwner()));
			}
			else
			{
				UE_CLOG((GameplayCueActorRecycleDebug>0), LogAbilitySystem, Display, TEXT("::GetInstancedCueActor Using Existing %s (Target: %s). Using GC Actor: %s"), *GetNameSafe(CueClass), *GetNameSafe(TargetActor), *GetNameSafe(SpawnedCue));
				return SpawnedCue;
			}
		}
	}

	// We don't have an instance for this, and we need one, so make one
	if (ensure(TargetActor) && ensure(CueClass))
	{
		AActor* NewOwnerActor = TargetActor;
#if WITH_EDITOR
		// Don't set owner if we are using fake CDO actor to do anim previewing
		NewOwnerActor= (TargetActor && TargetActor->HasAnyFlags(RF_ClassDefaultObject) == false ? TargetActor : nullptr);
#endif

		// Look to reuse an existing one that is stored on the CDO:
		if (GameplayCueActorRecycle > 0)
		{
			FPreallocationInfo& Info = GetPreallocationInfo(GetWorld());
			TArray<AGameplayCueNotify_Actor*>* PreallocatedList = Info.PreallocatedInstances.Find(CueClass);
			if (PreallocatedList && PreallocatedList->Num() > 0)
			{
				SpawnedCue = PreallocatedList->Pop(false);
				checkf(SpawnedCue && SpawnedCue->IsPendingKill() == false, TEXT("Spawned Cue is pending kill or null: %s"), *GetNameSafe(SpawnedCue));
				SpawnedCue->bInRecycleQueue = false;				
				SpawnedCue->SetActorHiddenInGame(false);
				SpawnedCue->SetOwner(NewOwnerActor);
				SpawnedCue->SetActorLocationAndRotation(TargetActor->GetActorLocation(), TargetActor->GetActorRotation());

				UE_CLOG((GameplayCueActorRecycleDebug>0), LogAbilitySystem, Display, TEXT("GetInstancedCueActor Popping Recycled %s (Target: %s). Using GC Actor: %s"), *GetNameSafe(CueClass), *GetNameSafe(TargetActor), *GetNameSafe(SpawnedCue));
#if WITH_EDITOR
				// let things know that we 'spawned'
				ISequenceRecorder& SequenceRecorder	= FModuleManager::LoadModuleChecked<ISequenceRecorder>("SequenceRecorder");
				SequenceRecorder.NotifyActorStartRecording(SpawnedCue);
#endif
			}
		}

		// If we can't reuse, then spawn a new one
		if (SpawnedCue == nullptr)
		{
			FActorSpawnParameters SpawnParams;
			SpawnParams.Owner = NewOwnerActor;
			if (SpawnedCue == nullptr)
			{
				if (LogGameplayCueActorSpawning)
				{
					ABILITY_LOG(Warning, TEXT("Spawning GameplaycueActor: %s"), *CueClass->GetName());
				}

				SpawnedCue = GetWorld()->SpawnActor<AGameplayCueNotify_Actor>(CueClass, TargetActor->GetActorLocation(), TargetActor->GetActorRotation(), SpawnParams);
			}
		}

		// Associate this GameplayCueNotifyActor with this target actor/key
		if (ensure(SpawnedCue))
		{
			SpawnedCue->NotifyKey = NotifyKey;
			NotifyMapActor.Add(NotifyKey, SpawnedCue);
		}
	}

	UE_CLOG((GameplayCueActorRecycleDebug>0), LogAbilitySystem, Display, TEXT("GetInstancedCueActor  Returning %s (Target: %s). Using GC Actor: %s"), *GetNameSafe(CueClass), *GetNameSafe(TargetActor), *GetNameSafe(SpawnedCue));
	return SpawnedCue;
}
bool UMovementComponent::ResolvePenetrationImpl(const FVector& ProposedAdjustment, const FHitResult& Hit, const FQuat& NewRotationQuat)
{
	// SceneComponent can't be in penetration, so this function really only applies to PrimitiveComponent.
	const FVector Adjustment = ConstrainDirectionToPlane(ProposedAdjustment);
	if (!Adjustment.IsZero() && UpdatedPrimitive)
	{
		// See if we can fit at the adjusted location without overlapping anything.
		AActor* ActorOwner = UpdatedComponent->GetOwner();
		if (!ActorOwner)
		{
			return false;
		}

		UE_LOG(LogMovement, Verbose, TEXT("ResolvePenetration: %s.%s at location %s inside %s.%s at location %s by %.3f (netmode: %d)"),
			   *ActorOwner->GetName(),
			   *UpdatedComponent->GetName(),
			   *UpdatedComponent->GetComponentLocation().ToString(),
			   *GetNameSafe(Hit.GetActor()),
			   *GetNameSafe(Hit.GetComponent()),
			   Hit.Component.IsValid() ? *Hit.GetComponent()->GetComponentLocation().ToString() : TEXT("<unknown>"),
			   Hit.PenetrationDepth,
			   (uint32)GetNetMode());

		// We really want to make sure that precision differences or differences between the overlap test and sweep tests don't put us into another overlap,
		// so make the overlap test a bit more restrictive.
		const float OverlapInflation = CVarPenetrationOverlapCheckInflation.GetValueOnGameThread();
		bool bEncroached = OverlapTest(Hit.TraceStart + Adjustment, NewRotationQuat, UpdatedPrimitive->GetCollisionObjectType(), UpdatedPrimitive->GetCollisionShape(OverlapInflation), ActorOwner);
		if (!bEncroached)
		{
			// Move without sweeping.
			MoveUpdatedComponent(Adjustment, NewRotationQuat, false, nullptr, ETeleportType::TeleportPhysics);
			UE_LOG(LogMovement, Verbose, TEXT("ResolvePenetration:   teleport by %s"), *Adjustment.ToString());
			return true;
		}
		else
		{
			// Disable MOVECOMP_NeverIgnoreBlockingOverlaps if it is enabled, otherwise we wouldn't be able to sweep out of the object to fix the penetration.
			TGuardValue<EMoveComponentFlags> ScopedFlagRestore(MoveComponentFlags, EMoveComponentFlags(MoveComponentFlags & (~MOVECOMP_NeverIgnoreBlockingOverlaps)));

			// Try sweeping as far as possible...
			FHitResult SweepOutHit(1.f);
			bool bMoved = MoveUpdatedComponent(Adjustment, NewRotationQuat, true, &SweepOutHit, ETeleportType::TeleportPhysics);
			UE_LOG(LogMovement, Verbose, TEXT("ResolvePenetration:   sweep by %s (success = %d)"), *Adjustment.ToString(), bMoved);
			
			// Still stuck?
			if (!bMoved && SweepOutHit.bStartPenetrating)
			{
				// Combine two MTD results to get a new direction that gets out of multiple surfaces.
				const FVector SecondMTD = GetPenetrationAdjustment(SweepOutHit);
				const FVector CombinedMTD = Adjustment + SecondMTD;
				if (SecondMTD != Adjustment && !CombinedMTD.IsZero())
				{
					bMoved = MoveUpdatedComponent(CombinedMTD, NewRotationQuat, true, nullptr, ETeleportType::TeleportPhysics);
					UE_LOG(LogMovement, Verbose, TEXT("ResolvePenetration:   sweep by %s (MTD combo success = %d)"), *CombinedMTD.ToString(), bMoved);
				}
			}

			// Still stuck?
			if (!bMoved)
			{
				// Try moving the proposed adjustment plus the attempted move direction. This can sometimes get out of penetrations with multiple objects
				const FVector MoveDelta = ConstrainDirectionToPlane(Hit.TraceEnd - Hit.TraceStart);
				if (!MoveDelta.IsZero())
				{
					bMoved = MoveUpdatedComponent(Adjustment + MoveDelta, NewRotationQuat, true, nullptr, ETeleportType::TeleportPhysics);
					UE_LOG(LogMovement, Verbose, TEXT("ResolvePenetration:   sweep by %s (adjusted attempt success = %d)"), *(Adjustment + MoveDelta).ToString(), bMoved);
				}
			}	

			return bMoved;
		}
	}

	return false;
}
bool FGameplayCueTranslationManager::TranslateTag_Internal(FGameplayCueTranslatorNode& Node, FGameplayTag& OutTag, const FName& TagName, AActor* TargetActor, const FGameplayCueParameters& Parameters)
{
	for (FGameplayCueTranslationLink& Link : Node.Links)
	{
		// Have CDO give us TranslationIndex. This is 0 - (number of name swaps this class gave us)
		int32 TranslationIndex = Link.RulesCDO->GameplayCueToTranslationIndex(TagName, TargetActor, Parameters);
		if (TranslationIndex != INDEX_NONE)
		{
			// Use the link's NodeLookup to get the real NodeIndex
			FGameplayCueTranslatorNodeIndex NodeIndex = Link.NodeLookup[TranslationIndex];
			if (NodeIndex != INDEX_NONE)
			{
				// Warn if more links?
				FGameplayCueTranslatorNode& InnerNode = TranslationLUT[NodeIndex];

				UE_LOG(LogGameplayCueTranslator, Verbose, TEXT("Translating %s --> %s (via %s)"), *TagName.ToString(), *InnerNode.CachedGameplayTagName.ToString(), *GetNameSafe(Link.RulesCDO));

				OutTag = InnerNode.CachedGameplayTag;
				
				TranslateTag_Internal(InnerNode, OutTag, InnerNode.CachedGameplayTagName, TargetActor, Parameters);
				return true;
			}
		}
	}

	return false;
}
/** Convert a BoneSpace FTransform to ComponentSpace. */
void FAnimationRuntime::ConvertBoneSpaceTransformToCS
(
	USkeletalMeshComponent * SkelComp,  
	FCSPose<FCompactPose> & MeshBases,
	/*inout*/ FTransform& BoneSpaceTM, 
	FCompactPoseBoneIndex BoneIndex,
	uint8 Space
)
{
	switch( Space )
	{
		case BCS_WorldSpace : 
			BoneSpaceTM.SetToRelativeTransform(SkelComp->ComponentToWorld);
			break;

		case BCS_ComponentSpace :
			// Component Space, no change.
			break;

		case BCS_ParentBoneSpace :
			if( BoneIndex != INDEX_NONE )
			{
				const FCompactPoseBoneIndex ParentIndex = MeshBases.GetPose().GetParentBoneIndex(BoneIndex);
				if( ParentIndex != INDEX_NONE )
				{
					const FTransform& ParentTM = MeshBases.GetComponentSpaceTransform(ParentIndex);
					BoneSpaceTM *= ParentTM;
				}
			}
			break;

		case BCS_BoneSpace :
			if( BoneIndex != INDEX_NONE )
			{
				const FTransform& BoneTM = MeshBases.GetComponentSpaceTransform(BoneIndex);
				BoneSpaceTM *= BoneTM;
			}
			break;

		default:
			UE_LOG(LogAnimation, Warning, TEXT("ConvertBoneSpaceTransformToCS: Unknown BoneSpace %d  for Mesh: %s"), Space, *GetNameSafe(SkelComp->SkeletalMesh));
			break;
	}
}
bool UMovementComponent::ShouldSkipUpdate(float DeltaTime) const
{
	if (UpdatedComponent == nullptr)
	{
		return true;
	}
		
	if (UpdatedComponent->Mobility != EComponentMobility::Movable)
	{
#if WITH_EDITOR
		if (!bEditorWarnedStaticMobilityMove)
		{
			if (UWorld * World = GetWorld())
			{
				if (World->HasBegunPlay() && IsRegistered())
				{
					const_cast<UMovementComponent*>(this)->bEditorWarnedStaticMobilityMove = true;
					FMessageLog("PIE").Warning(FText::Format(LOCTEXT("InvalidMove", "Mobility of {0} : {1} has to be 'Movable' if you'd like to move it with {2}. "),
						FText::FromString(GetNameSafe(UpdatedComponent->GetOwner())), FText::FromString(UpdatedComponent->GetName()), FText::FromString(GetClass()->GetName())));
				}
			}
		}
#endif

		return true;
	}

	if (bUpdateOnlyIfRendered)
	{
		if (GetNetMode() == NM_DedicatedServer)
		{
			// Dedicated servers never render
			return true;
		}

		const float RenderTimeThreshold = 0.41f;
		UWorld* TheWorld = GetWorld();
		if (UpdatedPrimitive && TheWorld->TimeSince(UpdatedPrimitive->LastRenderTime) <= RenderTimeThreshold)
		{
			return false; // Rendered, don't skip it.
		}

		// Most components used with movement components don't actually render, so check attached children render times.
		TArray<USceneComponent*> Children;
		UpdatedComponent->GetChildrenComponents(true, Children);
		for (auto Child : Children)
		{
			const UPrimitiveComponent* PrimitiveChild = Cast<UPrimitiveComponent>(Child);
			if (PrimitiveChild)
			{
				if (PrimitiveChild->IsRegistered() && TheWorld->TimeSince(PrimitiveChild->LastRenderTime) <= RenderTimeThreshold)
				{
					return false; // Rendered, don't skip it.
				}
			}
		}

		// No children were recently rendered, safely skip the update.
		return true;
	}

	return false;
}
void AShooterWeapon_Instant::ServerNotifyHit_Implementation(const FHitResult Impact, FVector_NetQuantizeNormal ShootDir, int32 RandomSeed, float ReticleSpread)
{
    const float WeaponAngleDot = FMath::Abs(FMath::Sin(ReticleSpread * PI / 180.f));

    // if we have an instigator, calculate dot between the view and the shot
    if (Instigator && (Impact.GetActor() || Impact.bBlockingHit))
    {
        const FVector Origin = GetMuzzleLocation();
        const FVector ViewDir = (Impact.Location - Origin).GetSafeNormal();

        // is the angle between the hit and the view within allowed limits (limit + weapon max angle)
        const float ViewDotHitDir = FVector::DotProduct(Instigator->GetViewRotation().Vector(), ViewDir);
        if (ViewDotHitDir > InstantConfig.AllowedViewDotHitDir - WeaponAngleDot)
        {
            if (CurrentState != EWeaponState::Idle)
            {
                if (Impact.GetActor() == NULL)
                {
                    if (Impact.bBlockingHit)
                    {
                        ProcessInstantHit_Confirmed(Impact, Origin, ShootDir, RandomSeed, ReticleSpread);
                    }
                }
                // assume it told the truth about static things because the don't move and the hit
                // usually doesn't have significant gameplay implications
                else if (Impact.GetActor()->IsRootComponentStatic() || Impact.GetActor()->IsRootComponentStationary())
                {
                    ProcessInstantHit_Confirmed(Impact, Origin, ShootDir, RandomSeed, ReticleSpread);
                }
                else
                {
                    // Get the component bounding box
                    const FBox HitBox = Impact.GetActor()->GetComponentsBoundingBox();

                    // calculate the box extent, and increase by a leeway
                    FVector BoxExtent = 0.5 * (HitBox.Max - HitBox.Min);
                    BoxExtent *= InstantConfig.ClientSideHitLeeway;

                    // avoid precision errors with really thin objects
                    BoxExtent.X = FMath::Max(20.0f, BoxExtent.X);
                    BoxExtent.Y = FMath::Max(20.0f, BoxExtent.Y);
                    BoxExtent.Z = FMath::Max(20.0f, BoxExtent.Z);

                    // Get the box center
                    const FVector BoxCenter = (HitBox.Min + HitBox.Max) * 0.5;

                    // if we are within client tolerance
                    if (FMath::Abs(Impact.Location.Z - BoxCenter.Z) < BoxExtent.Z &&
                            FMath::Abs(Impact.Location.X - BoxCenter.X) < BoxExtent.X &&
                            FMath::Abs(Impact.Location.Y - BoxCenter.Y) < BoxExtent.Y)
                    {
                        ProcessInstantHit_Confirmed(Impact, Origin, ShootDir, RandomSeed, ReticleSpread);
                    }
                    else
                    {
                        UE_LOG(LogShooterWeapon, Log, TEXT("%s Rejected client side hit of %s (outside bounding box tolerance)"), *GetNameSafe(this), *GetNameSafe(Impact.GetActor()));
                    }
                }
            }
        }
        else if (ViewDotHitDir <= InstantConfig.AllowedViewDotHitDir)
        {
            UE_LOG(LogShooterWeapon, Log, TEXT("%s Rejected client side hit of %s (facing too far from the hit direction)"), *GetNameSafe(this), *GetNameSafe(Impact.GetActor()));
        }
        else
        {
            UE_LOG(LogShooterWeapon, Log, TEXT("%s Rejected client side hit of %s"), *GetNameSafe(this), *GetNameSafe(Impact.GetActor()));
        }
    }
}
Beispiel #9
0
void AAIController::StopMovement()
{
	UE_VLOG(this, LogAINavigation, Log, TEXT("AAIController::StopMovement: %s STOP MOVEMENT"), *GetNameSafe(GetPawn()));
	PathFollowingComponent->AbortMove(TEXT("StopMovement"));
}
bool UNavigationComponent::FindSimplePathToActor(const AActor* NewGoalActor, float RepathDistance)
{
	bool bPathGenerationSucceeded = false;

	if (bIsPaused && NewGoalActor != NULL && GoalActor == NewGoalActor
		&& Path.IsValid() && Path->IsValid() && Path->GetOwner() == NULL)
	{
		RepathDistanceSq = FMath::Square(RepathDistance);
		OriginalGoalActorLocation = GetCurrentMoveGoal(NewGoalActor, GetOwner());

		bPathGenerationSucceeded = ResumePath();
	}
	else 
	{
		if (NewGoalActor != NULL)
		{
			const FVector NewGoalActorLocation = GetCurrentMoveGoal(NewGoalActor, GetOwner());
			bPathGenerationSucceeded = GenerateSimplePath(NewGoalActorLocation);

			if (bPathGenerationSucceeded)
			{
				GoalActor = NewGoalActor;
				RepathDistanceSq = FMath::Square(RepathDistance);
				OriginalGoalActorLocation = NewGoalActorLocation;
				bUseSimplePath = true;

				// if doing sync pathfinding enabling component's ticking needs to be done now
				SetComponentTickEnabledAsync(true);
			}
		}

		if (!bPathGenerationSucceeded)
		{
			UE_VLOG(GetOwner(), LogNavigation, Warning, TEXT("Failed to generate simple path to %s"), *GetNameSafe(NewGoalActor));
		}
	}

	if (bPathGenerationSucceeded == false)
	{
		ResetTransientData();
	}

	return bPathGenerationSucceeded;
}
bool UNavigationComponent::FindPathToActor(const AActor* NewGoalActor, TSharedPtr<const FNavigationQueryFilter> QueryFilter, float RepathDistance)
{
	bool bPathGenerationSucceeded = false;

	if (bIsPaused && NewGoalActor != NULL && GoalActor == NewGoalActor 
		&& Path.IsValid() && Path->IsValid())
	{
		RepathDistanceSq = FMath::Square(RepathDistance);
		OriginalGoalActorLocation = GetCurrentMoveGoal(NewGoalActor, GetOwner());

		if (bDoAsyncPathfinding == true)
		{
			FSimpleDelegateGraphTask::CreateAndDispatchWhenReady(
				FSimpleDelegateGraphTask::FDelegate::CreateUObject(this, &UNavigationComponent::DeferredResumePath)
				, TEXT("Deferred resume path")
				, NULL
				, ENamedThreads::GameThread
				);
			bPathGenerationSucceeded = true;
		}
		else
		{
			bPathGenerationSucceeded = ResumePath();
		}
	}
	else
	{
		if (NewGoalActor != NULL)
		{
			const FVector NewGoalActorLocation = GetCurrentMoveGoal(NewGoalActor, GetOwner());
			if (bDoAsyncPathfinding == true)
			{
				bPathGenerationSucceeded = AsyncGeneratePathTo(NewGoalActorLocation, QueryFilter);
			}
			else
			{
				bPathGenerationSucceeded = GeneratePathTo(NewGoalActorLocation, QueryFilter);
			}

			if (bPathGenerationSucceeded)
			{
				// if there's a specific query filter store it
				StoredQueryFilter = QueryFilter;

				GoalActor = NewGoalActor;
				RepathDistanceSq = FMath::Square(RepathDistance);
				OriginalGoalActorLocation = NewGoalActorLocation;
				bUseSimplePath = false;

				if (bDoAsyncPathfinding == false)
				{
					// if doing sync pathfinding enabling component's ticking needs to be done now
					SetComponentTickEnabledAsync(true);
				}
			}
		}

		if (!bPathGenerationSucceeded)
		{
			UE_VLOG(GetOwner(), LogNavigation, Log, TEXT("%s failed to generate path to %s"), *GetNameSafe(GetOwner()), *GetNameSafe(NewGoalActor));
		}
	}

	if (bPathGenerationSucceeded == false)
	{
		ResetTransientData();
	}

	return bPathGenerationSucceeded;
}
FString FGameplayEffectSpec::ToSimpleString() const
{
	return FString::Printf(TEXT("%s"), *GetNameSafe(Def));
}
void FKismetBytecodeDisassembler::ProcessCommon(int32& ScriptIndex, EExprToken Opcode)
{
	switch (Opcode)
	{
	case EX_PrimitiveCast:
		{
			// A type conversion.
			uint8 ConversionType = ReadBYTE(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: PrimitiveCast of type %d"), *Indents, (int32)Opcode, ConversionType);
			AddIndent();

			Ar.Logf(TEXT("%s Argument:"), *Indents);
			ProcessCastByte(ConversionType, ScriptIndex);

			//@TODO:
			//Ar.Logf(TEXT("%s Expression:"), *Indents);
			//SerializeExpr( ScriptIndex );
			break;
		}
	case EX_ObjToInterfaceCast:
		{
			// A conversion from an object variable to a native interface variable.
			// We use a different bytecode to avoid the branching each time we process a cast token

			// the interface class to convert to
			UClass* InterfaceClass = ReadPointer<UClass>(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: ObjToInterfaceCast to %s"), *Indents, (int32)Opcode, *InterfaceClass->GetName());

			SerializeExpr( ScriptIndex );
			break;
		}
	case EX_CrossInterfaceCast:
		{
			// A conversion from one interface variable to a different interface variable.
			// We use a different bytecode to avoid the branching each time we process a cast token

			// the interface class to convert to
			UClass* InterfaceClass = ReadPointer<UClass>(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: InterfaceToInterfaceCast to %s"), *Indents, (int32)Opcode, *InterfaceClass->GetName());

			SerializeExpr( ScriptIndex );
			break;
		}
	case EX_InterfaceToObjCast:
		{
			// A conversion from an interface variable to a object variable.
			// We use a different bytecode to avoid the branching each time we process a cast token

			// the interface class to convert to
			UClass* ObjectClass = ReadPointer<UClass>(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: InterfaceToObjCast to %s"), *Indents, (int32)Opcode, *ObjectClass->GetName());

			SerializeExpr( ScriptIndex );
			break;
		}
	case EX_Let:
		{
			Ar.Logf(TEXT("%s $%X: Let (Variable = Expression)"), *Indents, (int32)Opcode);
			AddIndent();

			// Variable expr.
			Ar.Logf(TEXT("%s Variable:"), *Indents);
			SerializeExpr( ScriptIndex );

			// Assignment expr.
			Ar.Logf(TEXT("%s Expression:"), *Indents);
			SerializeExpr( ScriptIndex );

			DropIndent();
			break;
		}
	case EX_LetObj:
	case EX_LetWeakObjPtr:
		{
			if( Opcode == EX_LetObj )
			{
				Ar.Logf(TEXT("%s $%X: Let Obj (Variable = Expression)"), *Indents, (int32)Opcode);
			}
			else
			{
				Ar.Logf(TEXT("%s $%X: Let WeakObjPtr (Variable = Expression)"), *Indents, (int32)Opcode);
			}
			AddIndent();

			// Variable expr.
			Ar.Logf(TEXT("%s Variable:"), *Indents);
			SerializeExpr( ScriptIndex );

			// Assignment expr.
			Ar.Logf(TEXT("%s Expression:"), *Indents);
			SerializeExpr( ScriptIndex );

			DropIndent();
			break;
		}
	case EX_LetBool:
		{
			Ar.Logf(TEXT("%s $%X: LetBool (Variable = Expression)"), *Indents, (int32)Opcode);
			AddIndent();

			// Variable expr.
			Ar.Logf(TEXT("%s Variable:"), *Indents);
			SerializeExpr( ScriptIndex );

			// Assignment expr.
			Ar.Logf(TEXT("%s Expression:"), *Indents);
			SerializeExpr( ScriptIndex );

			DropIndent();
			break;
		}
	case Ex_LetValueOnPersistentFrame:
		{
			Ar.Logf(TEXT("%s $%X: LetValueOnPersistentFrame"), *Indents, (int32)Opcode);
			AddIndent();

			auto Prop = ReadPointer<UProperty>(ScriptIndex);
			Ar.Logf(TEXT("%s Destination variable: %s, offset: %d"), *Indents, *GetNameSafe(Prop), 
				Prop ? Prop->GetOffset_ForDebug() : 0);
			
			Ar.Logf(TEXT("%s Expression:"), *Indents);
			SerializeExpr(ScriptIndex);

			DropIndent();

			break;
		}
	case EX_StructMemberContext:
		{
			Ar.Logf(TEXT("%s $%X: Struct member context "), *Indents, (int32)Opcode);
			AddIndent();

			UProperty* Prop = ReadPointer<UProperty>(ScriptIndex);

			Ar.Logf(TEXT("%s Expression within struct %s, offset %d"), *Indents, *(Prop->GetName()), 
				Prop->GetOffset_ForDebug()); // although that isn't a UFunction, we are not going to indirect the props of a struct, so this should be fine

			Ar.Logf(TEXT("%s Expression to struct:"), *Indents);
			SerializeExpr( ScriptIndex );

			DropIndent();

			break;
		}
	case EX_LetDelegate:
		{
			Ar.Logf(TEXT("%s $%X: LetDelegate (Variable = Expression)"), *Indents, (int32)Opcode);
			AddIndent();

			// Variable expr.
			Ar.Logf(TEXT("%s Variable:"), *Indents);
			SerializeExpr( ScriptIndex );
				
			// Assignment expr.
			Ar.Logf(TEXT("%s Expression:"), *Indents);
			SerializeExpr( ScriptIndex );

			DropIndent();
			break;
		}
	case EX_LetMulticastDelegate:
		{
			Ar.Logf(TEXT("%s $%X: LetMulticastDelegate (Variable = Expression)"), *Indents, (int32)Opcode);
			AddIndent();

			// Variable expr.
			Ar.Logf(TEXT("%s Variable:"), *Indents);
			SerializeExpr( ScriptIndex );
				
			// Assignment expr.
			Ar.Logf(TEXT("%s Expression:"), *Indents);
			SerializeExpr( ScriptIndex );

			DropIndent();
			break;
		}

	case EX_ComputedJump:
		{
			Ar.Logf(TEXT("%s $%X: Computed Jump, offset specified by expression:"), *Indents, (int32)Opcode);

			AddIndent();
			SerializeExpr( ScriptIndex );
			DropIndent();

			break;
		}

	case EX_Jump:
		{
			CodeSkipSizeType SkipCount = ReadSkipCount(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: Jump to offset 0x%X"), *Indents, (int32)Opcode, SkipCount);
			break;
		}
	case EX_LocalVariable:
		{
			UProperty* PropertyPtr = ReadPointer<UProperty>(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: Local variable named %s"), *Indents, (int32)Opcode, PropertyPtr ? *PropertyPtr->GetName() : TEXT("(null)"));
			break;
		}
	case EX_InstanceVariable:
		{
			UProperty* PropertyPtr = ReadPointer<UProperty>(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: Instance variable named %s"), *Indents, (int32)Opcode, PropertyPtr ? *PropertyPtr->GetName() : TEXT("(null)"));
			break;
		}
	case EX_LocalOutVariable:
		{
			UProperty* PropertyPtr = ReadPointer<UProperty>(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: Local out variable named %s"), *Indents, (int32)Opcode, PropertyPtr ? *PropertyPtr->GetName() : TEXT("(null)"));
			break;
		}
	case EX_InterfaceContext:
		{
			Ar.Logf(TEXT("%s $%X: EX_InterfaceContext:"), *Indents, (int32)Opcode);
			SerializeExpr(ScriptIndex);
			break;
		}
	case EX_DeprecatedOp4A:
		{
			Ar.Logf(TEXT("%s $%X: This opcode has been removed and does nothing."), *Indents, (int32)Opcode);
			break;
		}
	case EX_Nothing:
		{
			Ar.Logf(TEXT("%s $%X: EX_Nothing"), *Indents, (int32)Opcode);
			break;
		}
	case EX_EndOfScript:
		{
			Ar.Logf(TEXT("%s $%X: EX_EndOfScript"), *Indents, (int32)Opcode);
			break;
		}
	case EX_EndFunctionParms:
		{
			Ar.Logf(TEXT("%s $%X: EX_EndFunctionParms"), *Indents, (int32)Opcode);
			break;
		}
	case EX_EndStructConst:
		{
			Ar.Logf(TEXT("%s $%X: EX_EndStructConst"), *Indents, (int32)Opcode);
			break;
		}
	case EX_EndArray:
		{
			Ar.Logf(TEXT("%s $%X: EX_EndArray"), *Indents, (int32)Opcode);
			break;
		}
	case EX_IntZero:
		{
			Ar.Logf(TEXT("%s $%X: EX_IntZero"), *Indents, (int32)Opcode);
			break;
		}
	case EX_IntOne:
		{
			Ar.Logf(TEXT("%s $%X: EX_IntOne"), *Indents, (int32)Opcode);
			break;
		}
	case EX_True:
		{
			Ar.Logf(TEXT("%s $%X: EX_True"), *Indents, (int32)Opcode);
			break;
		}
	case EX_False:
		{
			Ar.Logf(TEXT("%s $%X: EX_False"), *Indents, (int32)Opcode);
			break;
		}
	case EX_NoObject:
		{
			Ar.Logf(TEXT("%s $%X: EX_NoObject"), *Indents, (int32)Opcode);
			break;
		}
	case EX_NoInterface:
		{
			Ar.Logf(TEXT("%s $%X: EX_NoObject"), *Indents, (int32)Opcode);
			break;
		}
	case EX_Self:
		{
			Ar.Logf(TEXT("%s $%X: EX_Self"), *Indents, (int32)Opcode);
			break;
		}
	case EX_EndParmValue:
		{
			Ar.Logf(TEXT("%s $%X: EX_EndParmValue"), *Indents, (int32)Opcode);
			break;
		}
	case EX_Return:
		{
			Ar.Logf(TEXT("%s $%X: Return expression"), *Indents, (int32)Opcode);

			SerializeExpr( ScriptIndex ); // Return expression.
			break;
		}
	case EX_FinalFunction:
		{
			UStruct* StackNode = ReadPointer<UStruct>(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: Final Function (stack node %s::%s)"), *Indents, (int32)Opcode, StackNode ? *StackNode->GetOuter()->GetName() : TEXT("(null)"), StackNode ? *StackNode->GetName() : TEXT("(null)"));

			while (SerializeExpr( ScriptIndex ) != EX_EndFunctionParms)
			{
				// Params
			}
			break;
		}
	case EX_CallMulticastDelegate:
		{
			UStruct* StackNode = ReadPointer<UStruct>(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: CallMulticastDelegate (signature %s::%s) delegate:"), *Indents, (int32)Opcode, StackNode ? *StackNode->GetOuter()->GetName() : TEXT("(null)"), StackNode ? *StackNode->GetName() : TEXT("(null)"));
			SerializeExpr( ScriptIndex );
			Ar.Logf(TEXT("Params:"));
			while (SerializeExpr( ScriptIndex ) != EX_EndFunctionParms)
			{
				// Params
			}
			break;
		}
	case EX_VirtualFunction:
		{
			FString FunctionName = ReadName(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: Virtual Function named %s"), *Indents, (int32)Opcode, *FunctionName);

			while (SerializeExpr(ScriptIndex) != EX_EndFunctionParms)
			{
			}
			break;
		}
	case EX_Context:
	case EX_Context_FailSilent:
		{
			Ar.Logf(TEXT("%s $%X: %s"), *Indents, (int32)Opcode, TEXT("Context"));
			AddIndent();

			// Object expression.
			Ar.Logf(TEXT("%s ObjectExpression:"), *Indents);
			SerializeExpr( ScriptIndex );

			if (Opcode == EX_Context_FailSilent)
			{
				Ar.Logf(TEXT(" Can fail silently on access none "));
			}

			// Code offset for NULL expressions.
			CodeSkipSizeType SkipCount = ReadSkipCount(ScriptIndex);
			Ar.Logf(TEXT("%s Skip Bytes: 0x%X"), *Indents, SkipCount);

			// Property corresponding to the r-value data, in case the l-value needs to be mem-zero'd
			UField* Field = ReadPointer<UField>(ScriptIndex);
			Ar.Logf(TEXT("%s R-Value Property: %s"), *Indents, Field ? *Field->GetName() : TEXT("(null)"));

			// Property type, in case the r-value is a non-property such as dynamic array length
			uint8 PropType = ReadBYTE(ScriptIndex);
			Ar.Logf(TEXT("%s PropertyTypeIfNeeded: %d"), *Indents, PropType);

			// Context expression.
			Ar.Logf(TEXT("%s ContextExpression:"), *Indents);
			SerializeExpr( ScriptIndex );

			DropIndent();
			break;
		}
	case EX_IntConst:
		{
			int32 ConstValue = ReadINT(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: literal int32 %d"), *Indents, (int32)Opcode, ConstValue);
			break;
		}
	case EX_SkipOffsetConst:
		{
			CodeSkipSizeType ConstValue = ReadSkipCount(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: literal CodeSkipSizeType 0x%X"), *Indents, (int32)Opcode, ConstValue);
			break;
		}
	case EX_FloatConst:
		{
			float ConstValue = ReadFLOAT(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: literal float %f"), *Indents, (int32)Opcode, ConstValue);
			break;
		}
	case EX_StringConst:
		{
			FString ConstValue = ReadString8(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: literal ansi string \"%s\""), *Indents, (int32)Opcode, *ConstValue);
			break;
		}
	case EX_UnicodeStringConst:
		{
			FString ConstValue = ReadString16(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: literal unicode string \"%s\""), *Indents, (int32)Opcode, *ConstValue);
			break;
		}
	case EX_TextConst:
		{
			Ar.Logf(TEXT("%s $%X: literal text"), *Indents, (int32)Opcode);
			break;
		}
	case EX_ObjectConst:
		{
			UObject* Pointer = ReadPointer<UObject>(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: EX_ObjectConst (%p:%s)"), *Indents, (int32)Opcode, Pointer, *Pointer->GetFullName());
			break;
		}
	case EX_NameConst:
		{
			FString ConstValue = ReadName(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: literal name %s"), *Indents, (int32)Opcode, *ConstValue);
			break;
		}
	case EX_RotationConst:
		{
			float Pitch = ReadFLOAT(ScriptIndex);
			float Yaw = ReadFLOAT(ScriptIndex);
			float Roll = ReadFLOAT(ScriptIndex);

			Ar.Logf(TEXT("%s $%X: literal rotation (%f,%f,%f)"), *Indents, (int32)Opcode, Pitch, Yaw, Roll);
			break;
		}
	case EX_VectorConst:
		{
			float X = ReadFLOAT(ScriptIndex);
			float Y = ReadFLOAT(ScriptIndex);
			float Z = ReadFLOAT(ScriptIndex);

			Ar.Logf(TEXT("%s $%X: literal vector (%f,%f,%f)"), *Indents, (int32)Opcode, X, Y, Z);
			break;
		}
	case EX_TransformConst:
		{

			float RotX = ReadFLOAT(ScriptIndex);
			float RotY = ReadFLOAT(ScriptIndex);
			float RotZ = ReadFLOAT(ScriptIndex);
			float RotW = ReadFLOAT(ScriptIndex);

			float TransX = ReadFLOAT(ScriptIndex);
			float TransY = ReadFLOAT(ScriptIndex);
			float TransZ = ReadFLOAT(ScriptIndex);

			float ScaleX = ReadFLOAT(ScriptIndex);
			float ScaleY = ReadFLOAT(ScriptIndex);
			float ScaleZ = ReadFLOAT(ScriptIndex);

			Ar.Logf(TEXT("%s $%X: literal transform R(%f,%f,%f,%f) T(%f,%f,%f) S(%f,%f,%f)"), *Indents, (int32)Opcode, TransX, TransY, TransZ, RotX, RotY, RotZ, RotW, ScaleX, ScaleY, ScaleZ);
			break;
		}
	case EX_StructConst:
		{
			UScriptStruct* Struct = ReadPointer<UScriptStruct>(ScriptIndex);
			int32 SerializedSize = ReadINT(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: literal struct %s (serialized size: %d)"), *Indents, (int32)Opcode, *Struct->GetName(), SerializedSize);
			while( SerializeExpr(ScriptIndex) != EX_EndStructConst )
			{
				// struct contents
			}
			break;
		}
	case EX_SetArray:
		{
 			Ar.Logf(TEXT("%s $%X: set array"), *Indents, (int32)Opcode);
			SerializeExpr(ScriptIndex);
 			while( SerializeExpr(ScriptIndex) != EX_EndArray)
 			{
 				// Array contents
 			}
 			break;
		}
	case EX_ByteConst:
		{
			uint8 ConstValue = ReadBYTE(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: literal byte %d"), *Indents, (int32)Opcode, ConstValue);
			break;
		}
	case EX_IntConstByte:
		{
			int32 ConstValue = ReadBYTE(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: literal int %d"), *Indents, (int32)Opcode, ConstValue);
			break;
		}
	case EX_MetaCast:
		{
			UClass* Class = ReadPointer<UClass>(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: MetaCast to %s of expr:"), *Indents, (int32)Opcode, *Class->GetName());
			SerializeExpr( ScriptIndex );
			break;
		}
	case EX_DynamicCast:
		{
			UClass* Class = ReadPointer<UClass>(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: DynamicCast to %s of expr:"), *Indents, (int32)Opcode, *Class->GetName());
			SerializeExpr( ScriptIndex );
			break;
		}
	case EX_JumpIfNot:
		{
			// Code offset.
			CodeSkipSizeType SkipCount = ReadSkipCount(ScriptIndex);
				
			Ar.Logf(TEXT("%s $%X: Jump to offset 0x%X if not expr:"), *Indents, (int32)Opcode, SkipCount);

			// Boolean expr.
			SerializeExpr( ScriptIndex );
			break;
		}
	case EX_Assert:
		{
			uint16 LineNumber = ReadWORD(ScriptIndex);
			uint8 InDebugMode = ReadBYTE(ScriptIndex);

			Ar.Logf(TEXT("%s $%X: assert at line %d, in debug mode = %d with expr:"), *Indents, (int32)Opcode, LineNumber, InDebugMode);
			SerializeExpr( ScriptIndex ); // Assert expr.
			break;
		}
	case EX_Skip:
		{
			CodeSkipSizeType W = ReadSkipCount(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: possibly skip 0x%X bytes of expr:"), *Indents, (int32)Opcode, W);

			// Expression to possibly skip.
			SerializeExpr( ScriptIndex );

			break;
		}
	case EX_InstanceDelegate:
		{
			// the name of the function assigned to the delegate.
			FString FuncName = ReadName(ScriptIndex);

			Ar.Logf(TEXT("%s $%X: instance delegate function named %s"), *Indents, (int32)Opcode, *FuncName);
			break;
		}
	case EX_AddMulticastDelegate:
		{
			Ar.Logf(TEXT("%s $%X: Add MC delegate"), *Indents, (int32)Opcode);
			SerializeExpr( ScriptIndex );
			SerializeExpr( ScriptIndex );
			break;
		}
	case EX_RemoveMulticastDelegate:
		{
			Ar.Logf(TEXT("%s $%X: Remove MC delegate"), *Indents, (int32)Opcode);
			SerializeExpr( ScriptIndex );
			SerializeExpr( ScriptIndex );
			break;
		}
	case EX_ClearMulticastDelegate:
		{
			Ar.Logf(TEXT("%s $%X: Clear MC delegate"), *Indents, (int32)Opcode);
			SerializeExpr( ScriptIndex );
			break;
		}
	case EX_BindDelegate:
		{
			// the name of the function assigned to the delegate.
			FString FuncName = ReadName(ScriptIndex);

			Ar.Logf(TEXT("%s $%X: BindDelegate '%s' "), *Indents, (int32)Opcode, *FuncName);

			Ar.Logf(TEXT("%s Delegate:"), *Indents);
			SerializeExpr( ScriptIndex );

			Ar.Logf(TEXT("%s Object:"), *Indents);
			SerializeExpr( ScriptIndex );

			break;
		}
	case EX_PushExecutionFlow:
		{
			CodeSkipSizeType SkipCount = ReadSkipCount(ScriptIndex);
			Ar.Logf(TEXT("%s $%X: FlowStack.Push(0x%X);"), *Indents, (int32)Opcode, SkipCount);
			break;
		}
	case EX_PopExecutionFlow:
		{
			Ar.Logf(TEXT("%s $%X: if (FlowStack.Num()) { jump to statement at FlowStack.Pop(); } else { ERROR!!! }"), *Indents, (int32)Opcode);
			break;
		}
	case EX_PopExecutionFlowIfNot:
		{
			Ar.Logf(TEXT("%s $%X: if (!condition) { if (FlowStack.Num()) { jump to statement at FlowStack.Pop(); } else { ERROR!!! } }"), *Indents, (int32)Opcode);
			// Boolean expr.
			SerializeExpr( ScriptIndex );
			break;
		}
	case EX_Breakpoint:
		{
			Ar.Logf(TEXT("%s $%X: <<< BREAKPOINT >>>"), *Indents, (int32)Opcode);
			break;
		}
	case EX_WireTracepoint:
		{
			Ar.Logf(TEXT("%s $%X: .. wire debug site .."), *Indents, (int32)Opcode);
			break;
		}
	case EX_Tracepoint:
		{
			Ar.Logf(TEXT("%s $%X: .. debug site .."), *Indents, (int32)Opcode);
			break;
		}
	default:
		{
			// This should never occur.
			UE_LOG(LogScriptDisassembler, Warning, TEXT("Unknown bytecode 0x%02X; ignoring it"), (uint8)Opcode );
			break;
		}
	}
}
void UHTNPlannerComponent::StartPlanner(UHTNPlanner& Asset)
{
	if(CurrentPlannerAsset == &Asset && PlannerHasBeenStarted())
	{
		UE_VLOG(GetOwner(), LogHTNPlanner, Log, TEXT("Skipping HTN Planner start request - it's already running"));
		return;
	}
	else if(CurrentPlannerAsset)
	{
		UE_VLOG(GetOwner(), LogHTNPlanner, Log, TEXT("Abandoning HTN Planner %s to start new one (%s)"),
				*GetNameSafe(CurrentPlannerAsset), *Asset.GetName());
	}

	StopPlanner();
	bDepthFirstSearch = Asset.bDepthFirstSearch;

	// reset and initialize the stack
	PlanningStack.Reset(10);	// probably safe to start with space for 10 elements, TODO could make this a very advanced parameter?
	BestPlan = MakeShareable<FHTNPlan>(new FHTNPlan());
	BestCost = TNumericLimits<float>::Max();

	if(PreviousPlan.IsValid())
	{
		// we have a valid previous plan to re-use
		// should initialize the number of buckets to the max similarity value + 1 (because 0 index), 
		// which is size of previous plan's search history
		int32 PreviousPlanSearchHistorySize = PreviousPlan->GetSearchHistory().Num();

		PastStreakStacks.Reset(PreviousPlanSearchHistorySize + 1);
		PastStreakStacks.AddDefaulted(PreviousPlanSearchHistorySize + 1);
		StreakEndedQueues.Reset(PreviousPlanSearchHistorySize + 1);
		StreakEndedQueues.AddDefaulted(PreviousPlanSearchHistorySize + 1);
		StreakStacks.Reset(PreviousPlanSearchHistorySize + 1);
		StreakStacks.AddDefaulted(PreviousPlanSearchHistorySize + 1);

		CurrentMatchingStreakLength = 0;
		MaxCurrentMatchingStreakLength = 0;
		MaxEndedMatchingStreakLength = 0;
		MaxPastMatchingStreakLength = 0;

		NumLeaves = 0;
		TotalLeafStreakLengths = 0;

		bHitLeaf = false;
		bIgnoringPlanReuse = false;

		MinMatchingStreakLength = DefaultMinMatchingStreakLength;
		//MinMatchingStreakLength = (int32)(PreviousPlanSearchHistorySize * 0.15);
	}

	TSharedPtr<FHTNWorldState> InitialWorldState;
	if(Asset.EmptyWorldState.IsValid())
	{
		InitialWorldState = Asset.EmptyWorldState->Copy();
	}
	else if(EmptyWorldState.IsValid())
	{
		InitialWorldState = EmptyWorldState->Copy();
	}
	else
	{
		UE_LOG(LogHTNPlanner, Warning, TEXT("No valid initial world state has been set in either the HTNPlanner asset or the HTNPlannerComponent!"));
		StopPlanner();
		return;
	}
	
	InitialWorldState->Initialize(GetOwner(), BlackboardComp);

	FHTNStackElement FirstStackElement;
	FirstStackElement.Plan = BestPlan;
	FirstStackElement.TaskNetwork = (*(Asset.TaskNetwork)) ? InstantiateNetwork(Asset.TaskNetwork) : Asset.TaskNetworkInstance;
	FirstStackElement.WorldState = InitialWorldState;
	FirstStackElement.Cost = 0.f;

	AddStackElement(FirstStackElement);	// TO DO maybe should explicitly Move the FirstStackElement?

	// prepare to start the planning process
	CurrentPlannerAsset = &Asset;
	bIsRunning = true;
	ScheduleExecutionUpdate();

#if HTN_LOG_RUNTIME_STATS
	StartPlanningTime = FDateTime::MinValue();
	CumulativeSearchTimespan = FTimespan::Zero();
	CumulativeSearchTimeMs = 0.0;
	CumulativeSearchTimeMsTillLastImprovement = 0.0;
	CumulativeSearchTimeMsTillFirstPlan = 0.0;
	CumulativeFrameCount = 0;
	NumNodesExpanded = 0;
	FirstPlanCost = TNumericLimits<float>::Max();
#endif // HTN_LOG_RUNTIME_STATS
}
FString UBlackboardKeyType_Class::DescribeSelf() const
{
	return *GetNameSafe(BaseClass);
}
Beispiel #16
0
FAIRequestID AAIController::RequestPathAndMove(const FAIMoveRequest& MoveRequest, FPathFindingQuery& Query)
{
	FAIRequestID RequestID;

	UNavigationSystem* NavSys = UNavigationSystem::GetCurrent(GetWorld());
	if (NavSys)
	{
		FPathFindingResult PathResult = NavSys->FindPathSync(Query);
		if (PathResult.Result != ENavigationQueryResult::Error)
		{
			if (PathResult.IsSuccessful() && PathResult.Path.IsValid())
			{
				if (MoveRequest.IsUsingPathfinding())
				{
					if (MoveRequest.HasGoalActor())
					{
						PathResult.Path->SetGoalActorObservation(*MoveRequest.GetGoalActor(), 100.0f);
					}

					PathResult.Path->EnableRecalculationOnInvalidation(true);
				}

				RequestID = RequestMove(MoveRequest, PathResult.Path);
			}
		}
		else
		{
			UE_VLOG(this, LogAINavigation, Error, TEXT("Trying to find path to %s resulted in Error"), *GetNameSafe(MoveRequest.GetGoalActor()));
		}
	}

	return RequestID;
}
Beispiel #17
0
bool FaceFX::GetAnimationBounds(const UFaceFXAnim* Animation, float& OutStart, float& OutEnd)
{
	ffx_anim_handle_t* AnimHandle = FaceFX::LoadAnimation(Animation->GetData());
	if (!AnimHandle)
	{
		return false;
	}

	bool Result = true;
	if (!FaceFX::Check(ffx_get_anim_bounds(AnimHandle, &OutStart, &OutEnd)))
	{
		UE_LOG(LogFaceFX, Error, TEXT("FaceFX::GetAnimationBounds. FaceFX call <ffx_get_anim_bounds> failed. %s. Asset: %s"), *FaceFX::GetFaceFXError(), *GetNameSafe(Animation));
		Result = false;
	}

	ffx_destroy_anim_handle(&AnimHandle, nullptr, nullptr);
	AnimHandle = nullptr;

	return Result;
}
FString UBlackboardKeyType_NativeEnum::DescribeSelf() const
{
	return *GetNameSafe(EnumType);
}
FBlueprintCompiledStatement* FKCHandler_MathExpression::GenerateFunctionRPN(UEdGraphNode* CurrentNode, FKismetFunctionContext& Context, UK2Node_MathExpression& MENode, FBPTerminal* ResultTerm, TMap<UEdGraphPin*, UEdGraphPin*>& InnerToOuterInput)
{
	UK2Node_CallFunction* CallFunctionNode = Cast<UK2Node_CallFunction>(CurrentNode);
	UFunction* Function = CallFunctionNode ? CallFunctionNode->GetTargetFunction() : nullptr;
	if (!CanBeCalledByMathExpression(Function))
	{
		CompilerContext.MessageLog.Error(*FString::Printf(*LOCTEXT("WrongFunction_Error", "Function '%s' cannot be called inside Math Expression @@ - @@").ToString(), *GetNameSafe(Function)), CallFunctionNode, &MENode);
		return nullptr;
	}

	FBlueprintCompiledStatement* NewDetachedStatement = new FBlueprintCompiledStatement();
	FBlueprintCompiledStatement& Statement = *NewDetachedStatement;
	Statement.FunctionToCall = Function;
	Statement.FunctionContext = nullptr;
	Statement.Type = KCST_CallFunction;
	Statement.LHS = ResultTerm; // required only for the first node

	check(CallFunctionNode);

	TArray<FBPTerminal*> RHSTerms;
	for (TFieldIterator<UProperty> It(Function); It && (It->PropertyFlags & CPF_Parm); ++It)
	{
		UProperty* Property = *It;
		if (Property && !Property->HasAnyPropertyFlags(CPF_ReturnParm | CPF_OutParm))
		{
			UEdGraphPin* PinToTry = nullptr;
			{
				UEdGraphPin* PinMatch = CallFunctionNode->FindPin(Property->GetName());
				const bool bGoodPin = PinMatch && FKismetCompilerUtilities::IsTypeCompatibleWithProperty(PinMatch, Property, CompilerContext.MessageLog, CompilerContext.GetSchema(), Context.NewClass);
				PinToTry = bGoodPin ? FEdGraphUtilities::GetNetFromPin(PinMatch) : nullptr;
			}

			FBPTerminal* RHSTerm = nullptr;
			{
				UEdGraphPin** OuterInputPtr = PinToTry ? InnerToOuterInput.Find(PinToTry) : nullptr;
				UEdGraphPin* OuterInputNet = (OuterInputPtr && *OuterInputPtr) ? FEdGraphUtilities::GetNetFromPin(*OuterInputPtr) : nullptr;
				FBPTerminal** OuterTerm = OuterInputNet ? Context.NetMap.Find(OuterInputNet) : nullptr;
				// Input is an outer term
				if (OuterTerm && *OuterTerm)
				{
					RHSTerm = *OuterTerm;
				}
			}

			if (!RHSTerm)
			{
				FBPTerminal** Term = PinToTry ? Context.NetMap.Find(PinToTry) : nullptr;
				const bool bValidTerm = Term && *Term;
				// Input is a literal term
				// Input is a variable
				if (bValidTerm && ((*Term)->bIsLiteral || (*Term)->AssociatedVarProperty))
				{
					RHSTerm = *Term;
				}
				// Input is an InlineGeneratedParameter
				else if (bValidTerm)
				{
					ensure(!(*Term)->InlineGeneratedParameter);
					UEdGraphNode* SourceNode = PinToTry ? PinToTry->GetOwningNodeUnchecked() : nullptr;
					FBlueprintCompiledStatement* InlineGeneratedParameterStatement = GenerateFunctionRPN(SourceNode, Context, MENode, nullptr, InnerToOuterInput);
					if (InlineGeneratedParameterStatement)
					{
						Context.AllGeneratedStatements.Add(InlineGeneratedParameterStatement);
						RHSTerm = *Term;
						RHSTerm->InlineGeneratedParameter = InlineGeneratedParameterStatement;
					}
				}
			}

			if (RHSTerm)
			{
				RHSTerms.Add(RHSTerm);
			}
			else
			{
				CompilerContext.MessageLog.Error(*FString::Printf(*LOCTEXT("FindPinParameter_Error", "Could not find a pin for the parameter %s of %s on @@").ToString(), *GetNameSafe(Property), *GetNameSafe(Function)), CallFunctionNode);
			}
		}
	}
	Statement.RHS = RHSTerms;
	return &Statement;
}
Beispiel #20
0
bool FAnimMontageInstance::SetNextSectionID(int32 const & SectionID, int32 const & NewNextSectionID)
{
	bool const bHasValidNextSection = NextSections.IsValidIndex(SectionID);

	// disconnect prev section
	if (bHasValidNextSection && (NextSections[SectionID] != INDEX_NONE) && PrevSections.IsValidIndex(NextSections[SectionID]))
	{
		PrevSections[NextSections[SectionID]] = INDEX_NONE;
	}

	// update in-reverse next section
	if (PrevSections.IsValidIndex(NewNextSectionID))
	{
		PrevSections[NewNextSectionID] = SectionID;
	}

	// update next section for the SectionID
	// NextSection can be invalid
	if (bHasValidNextSection)
	{
		NextSections[SectionID] = NewNextSectionID;
		OnMontagePositionChanged(GetSectionNameFromID(NewNextSectionID));
		return true;
	}

	UE_LOG(LogAnimation, Warning, TEXT("SetNextSectionName %s to %s failed for Montage %s"),
		*GetSectionNameFromID(SectionID).ToString(), *GetSectionNameFromID(NewNextSectionID).ToString(), *GetNameSafe(Montage));

	return false;
}
FVector UMovementComponent::GetPlaneConstraintNormalFromAxisSetting(EPlaneConstraintAxisSetting AxisSetting) const
{
	if (AxisSetting == EPlaneConstraintAxisSetting::UseGlobalPhysicsSetting)
	{
		ESettingsDOF::Type GlobalSetting = UPhysicsSettings::Get()->DefaultDegreesOfFreedom;
		switch (GlobalSetting)
		{
		case ESettingsDOF::Full3D:	return FVector::ZeroVector;
		case ESettingsDOF::YZPlane:	return FVector(1.f, 0.f, 0.f);
		case ESettingsDOF::XZPlane:	return FVector(0.f, 1.f, 0.f);
		case ESettingsDOF::XYPlane:	return FVector(0.f, 0.f, 1.f);
		default:
			checkf(false, TEXT("GetPlaneConstraintNormalFromAxisSetting: Unknown global axis setting %d for %s"), int32(GlobalSetting), *GetNameSafe(GetOwner()));
			return FVector::ZeroVector;
		}
	}

	switch(AxisSetting)
	{
	case EPlaneConstraintAxisSetting::Custom:	return PlaneConstraintNormal;
	case EPlaneConstraintAxisSetting::X:		return FVector(1.f, 0.f, 0.f);
	case EPlaneConstraintAxisSetting::Y:		return FVector(0.f, 1.f, 0.f);
	case EPlaneConstraintAxisSetting::Z:		return FVector(0.f, 0.f, 1.f);
	default:
		checkf(false, TEXT("GetPlaneConstraintNormalFromAxisSetting: Unknown axis %d for %s"), int32(AxisSetting), *GetNameSafe(GetOwner()));
		return FVector::ZeroVector;
	}
}
Beispiel #22
0
void UCheatManager::TickCollisionDebug()
{
	// If we are debugging capsule tracing
	if(bDebugCapsuleSweep)
	{
		APlayerController* PC = GetOuterAPlayerController();
		if(PC)
		{
			// Get view location to act as start point
			FVector ViewLoc;
			FRotator ViewRot;
			PC->GetPlayerViewPoint(ViewLoc, ViewRot);
			FVector ViewDir = ViewRot.Vector();
			FVector End = ViewLoc + (DebugTraceDistance * ViewDir);

			// Fill in params and do trace
			static const FName TickCollisionDebugName(TEXT("TickCollisionDebug"));
			FCollisionQueryParams CapsuleParams(TickCollisionDebugName, false, PC->GetPawn());
			CapsuleParams.bTraceComplex = bDebugCapsuleTraceComplex;

			if (bDebugCapsuleSweep)
			{
				// If we get a hit, draw the capsule
				FHitResult Result;
				bool bHit = GetWorld()->SweepSingle(Result, ViewLoc, End, FQuat::Identity, DebugTraceChannel, FCollisionShape::MakeCapsule(DebugCapsuleRadius, DebugCapsuleHalfHeight), CapsuleParams);
				if(bHit)
				{
					AddCapsuleSweepDebugInfo(ViewLoc, End, Result.ImpactPoint, Result.Normal, Result.ImpactNormal, Result.Location, DebugCapsuleHalfHeight, DebugCapsuleRadius, false, (Result.bStartPenetrating && Result.bBlockingHit)? true: false);
					UE_LOG(LogCollision, Log, TEXT("Collision component (%s) : Actor (%s)"), *GetNameSafe(Result.Component.Get()), *GetNameSafe(Result.GetActor()));
				}
			}
		}
	}

	// draw
	for (int32 TraceIdx=0; TraceIdx < DebugTraceInfoList.Num(); ++TraceIdx)
	{
		FDebugTraceInfo & TraceInfo = DebugTraceInfoList[TraceIdx];
		DrawDebugDirectionalArrow(GetWorld(), TraceInfo.LineTraceStart, TraceInfo.LineTraceEnd, 10.f, FColor::White, SDPG_World);
		// if it's current trace index, use highlight color
		if (CurrentTraceIndex == TraceIdx)
		{
			if (TraceInfo.bInsideOfObject)
			{
				DrawDebugCapsule(GetWorld(), TraceInfo.HitLocation, TraceInfo.CapsuleHalfHeight, TraceInfo.CapsuleRadius, FQuat::Identity, FColor(255,100,64));
			}
			else
			{
				DrawDebugCapsule(GetWorld(), TraceInfo.HitLocation, TraceInfo.CapsuleHalfHeight, TraceInfo.CapsuleRadius, FQuat::Identity, FColor(255,200,128));
			}
		}
		else
		{
			if (TraceInfo.bInsideOfObject)
			{
				DrawDebugCapsule(GetWorld(), TraceInfo.HitLocation, TraceInfo.CapsuleHalfHeight, TraceInfo.CapsuleRadius, FQuat::Identity, FColor(64,100,255));
			}
			else
			{
				DrawDebugCapsule(GetWorld(), TraceInfo.HitLocation, TraceInfo.CapsuleHalfHeight, TraceInfo.CapsuleRadius, FQuat::Identity, FColor(128,200,255));
			}
		}

		DrawDebugDirectionalArrow(GetWorld(), TraceInfo.HitNormalStart, TraceInfo.HitNormalEnd, 5, FColor(255,64,64), SDPG_World);

		DrawDebugDirectionalArrow(GetWorld(), TraceInfo.HitNormalStart, TraceInfo.HitImpactNormalEnd, 5, FColor(64,64,255), SDPG_World);
	}

	FLinearColor CurrentColor(255.f/255.f,96.f/255.f,96/255.f);
	FLinearColor DeltaColor = (FLinearColor(1.0f, 1.0f, 1.0f, 1.0f) - CurrentColor)*0.1f;
	int32 TotalCount=0;

	if ( DebugTracePawnInfoList.Num() > 0 )
	{
		// the latest will draw very red-ish to whiter color as it gets older. 
		for (int32 TraceIdx=CurrentTracePawnIndex; TotalCount<10; TraceIdx=SAFE_TRACEINDEX_DECREASE(TraceIdx), CurrentColor+=DeltaColor, ++TotalCount)
		{
			FDebugTraceInfo & TraceInfo = DebugTracePawnInfoList[TraceIdx];
			DrawDebugDirectionalArrow(GetWorld(), TraceInfo.LineTraceStart, TraceInfo.LineTraceEnd, 10.f, FColor(200,200,100), SDPG_World);

			if (TraceInfo.bInsideOfObject)
			{
				DrawDebugCapsule(GetWorld(), TraceInfo.HitLocation, TraceInfo.CapsuleHalfHeight, TraceInfo.CapsuleRadius, FQuat::Identity, FColor(64, 64, 255));
			}
			else
			{
				DrawDebugCapsule(GetWorld(), TraceInfo.HitLocation, TraceInfo.CapsuleHalfHeight, TraceInfo.CapsuleRadius, FQuat::Identity, CurrentColor.Quantize());
			}
			DrawDebugDirectionalArrow(GetWorld(), TraceInfo.HitNormalStart, TraceInfo.HitNormalEnd, 5.f, FColor(255,64,64), SDPG_World);
		}
	}
}
/* Validate Normal of OutResult. We're on hunt for invalid normal */
static void CheckHitResultNormal(const FHitResult& OutResult, const TCHAR* Message, const FVector & Start=FVector::ZeroVector, const FVector & End = FVector::ZeroVector, const PxGeometry* const Geom=NULL)
{
	if(!OutResult.bStartPenetrating && !OutResult.Normal.IsNormalized())
	{
		UE_LOG(LogPhysics, Warning, TEXT("(%s) Non-normalized OutResult.Normal from capsule conversion: %s (Component- %s)"), Message, *OutResult.Normal.ToString(), *GetNameSafe(OutResult.Component.Get()));
		// now I'm adding Outresult input
		UE_LOG(LogPhysics, Warning, TEXT("Start Loc(%s), End Loc(%s), Hit Loc(%s), ImpactNormal(%s)"), *Start.ToString(), *End.ToString(), *OutResult.Location.ToString(), *OutResult.ImpactNormal.ToString() );
		if (Geom != NULL)
		{
			// I only seen this crash on capsule
			if (Geom->getType() == PxGeometryType::eCAPSULE)
			{
				const PxCapsuleGeometry * Capsule = (PxCapsuleGeometry*)Geom;
				UE_LOG(LogPhysics, Warning, TEXT("Capsule radius (%f), Capsule Halfheight (%f)"), Capsule->radius, Capsule->halfHeight);
			}
		}
		check(OutResult.Normal.IsNormalized());
	}
}
Beispiel #24
0
void USkeletalMeshComponent::PerformBlendPhysicsBones(const TArray<FBoneIndexType>& InRequiredBones, TArray<FTransform>& InLocalAtoms)
{
	// Get drawscale from Owner (if there is one)
	FVector TotalScale3D = ComponentToWorld.GetScale3D();
	FVector RecipScale3D = TotalScale3D.Reciprocal();

	UPhysicsAsset * const PhysicsAsset = GetPhysicsAsset();
	check( PhysicsAsset );

	if (GetNumSpaceBases() == 0)
	{
		return;
	}

	// Get the scene, and do nothing if we can't get one.
	FPhysScene* PhysScene = nullptr;
	if (GetWorld() != nullptr)
	{
		PhysScene = GetWorld()->GetPhysicsScene();
	}

	if (PhysScene == nullptr)
	{
		return;
	}

	// Make sure scratch space is big enough.
	TArray<FAssetWorldBoneTM> WorldBoneTMs;
	WorldBoneTMs.Reset();
	WorldBoneTMs.AddZeroed(GetNumSpaceBases());
	
	FTransform LocalToWorldTM = ComponentToWorld;
	LocalToWorldTM.RemoveScaling();

	TArray<FTransform>& EditableSpaceBases = GetEditableSpaceBases();

	struct FBodyTMPair
	{
		FBodyInstance* BI;
		FTransform TM;
	};

	TArray<FBodyTMPair> PendingBodyTMs;

#if WITH_PHYSX
	// Lock the scenes we need (flags set in InitArticulated)
	if (bHasBodiesInSyncScene)
	{
		SCENE_LOCK_READ(PhysScene->GetPhysXScene(PST_Sync))
	}

	if (bHasBodiesInAsyncScene)
	{
		SCENE_LOCK_READ(PhysScene->GetPhysXScene(PST_Async))
	}
#endif

	// For each bone - see if we need to provide some data for it.
	for(int32 i=0; i<InRequiredBones.Num(); i++)
	{
		int32 BoneIndex = InRequiredBones[i];

		// See if this is a physics bone..
		int32 BodyIndex = PhysicsAsset ? PhysicsAsset->FindBodyIndex(SkeletalMesh->RefSkeleton.GetBoneName(BoneIndex)) : INDEX_NONE;
		// need to update back to physX so that physX knows where it was after blending
		bool bUpdatePhysics = false;
		FBodyInstance* BodyInstance = NULL;

		// If so - get its world space matrix and its parents world space matrix and calc relative atom.
		if(BodyIndex != INDEX_NONE )
		{	
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
			// tracking down TTP 280421. Remove this if this doesn't happen. 
			if ( !ensure(Bodies.IsValidIndex(BodyIndex)) )
			{
				UE_LOG(LogPhysics, Warning, TEXT("%s(Mesh %s, PhysicsAsset %s)"), 
					*GetName(), *GetNameSafe(SkeletalMesh), *GetNameSafe(PhysicsAsset));
				if ( PhysicsAsset )
				{
					UE_LOG(LogPhysics, Warning, TEXT(" - # of BodySetup (%d), # of Bodies (%d), Invalid BodyIndex(%d)"), 
						PhysicsAsset->BodySetup.Num(), Bodies.Num(), BodyIndex);
				}
				continue;
			}
#endif
			BodyInstance = Bodies[BodyIndex];

			//if simulated body copy back and blend with animation
			if(BodyInstance->IsInstanceSimulatingPhysics())
			{
				FTransform PhysTM = BodyInstance->GetUnrealWorldTransform_AssumesLocked();

				// Store this world-space transform in cache.
				WorldBoneTMs[BoneIndex].TM = PhysTM;
				WorldBoneTMs[BoneIndex].bUpToDate = true;

				float UsePhysWeight = (bBlendPhysics)? 1.f : BodyInstance->PhysicsBlendWeight;

				// Find this bones parent matrix.
				FTransform ParentWorldTM;

				// if we wan't 'full weight' we just find 
				if(UsePhysWeight > 0.f)
				{
					if(BoneIndex == 0)
					{
						ParentWorldTM = LocalToWorldTM;
					}
					else
					{
						// If not root, get parent TM from cache (making sure its up-to-date).
						int32 ParentIndex = SkeletalMesh->RefSkeleton.GetParentIndex(BoneIndex);
						UpdateWorldBoneTM(WorldBoneTMs, ParentIndex, this, LocalToWorldTM, TotalScale3D);
						ParentWorldTM = WorldBoneTMs[ParentIndex].TM;
					}


					// Then calc rel TM and convert to atom.
					FTransform RelTM = PhysTM.GetRelativeTransform(ParentWorldTM);
					RelTM.RemoveScaling();
					FQuat RelRot(RelTM.GetRotation());
					FVector RelPos =  RecipScale3D * RelTM.GetLocation();
					FTransform PhysAtom = FTransform(RelRot, RelPos, InLocalAtoms[BoneIndex].GetScale3D());

					// Now blend in this atom. See if we are forcing this bone to always be blended in
					InLocalAtoms[BoneIndex].Blend( InLocalAtoms[BoneIndex], PhysAtom, UsePhysWeight );

					if(BoneIndex == 0)
					{
						//We must update RecipScale3D based on the atom scale of the root
						TotalScale3D *= InLocalAtoms[0].GetScale3D();
						RecipScale3D = TotalScale3D.Reciprocal();
					}

					if (UsePhysWeight < 1.f)
					{
						bUpdatePhysics = true;
					}
				}
			}
		}

		// Update SpaceBases entry for this bone now
		if( BoneIndex == 0 )
		{
			EditableSpaceBases[0] = InLocalAtoms[0];
		}
		else
		{
			const int32 ParentIndex	= SkeletalMesh->RefSkeleton.GetParentIndex(BoneIndex);
			EditableSpaceBases[BoneIndex] = InLocalAtoms[BoneIndex] * EditableSpaceBases[ParentIndex];

			/**
			* Normalize rotations.
			* We want to remove any loss of precision due to accumulation of error.
			* i.e. A componentSpace transform is the accumulation of all of its local space parents. The further down the chain, the greater the error.
			* SpaceBases are used by external systems, we feed this to PhysX, send this to gameplay through bone and socket queries, etc.
			* So this is a good place to make sure all transforms are normalized.
			*/
			EditableSpaceBases[BoneIndex].NormalizeRotation();
		}

		if (bUpdatePhysics && BodyInstance)
		{
			//This is extremely inefficient. We need to obtain a write lock which will block other threads from blending
			//For now I'm juts deferring it to the end of this loop, but in general we need to move it all out of here and do it when the blend task is done
			FBodyTMPair* BodyTMPair = new (PendingBodyTMs) FBodyTMPair;
			BodyTMPair->BI = BodyInstance;
			BodyTMPair->TM = EditableSpaceBases[BoneIndex] * ComponentToWorld;
		}
	}

#if WITH_PHYSX
	//See above for read lock instead of write lock
	// Unlock the scenes 
	if (bHasBodiesInSyncScene)
	{
		SCENE_UNLOCK_READ(PhysScene->GetPhysXScene(PST_Sync))
	}

	if (bHasBodiesInAsyncScene)
	{
		SCENE_UNLOCK_READ(PhysScene->GetPhysXScene(PST_Async))
	}

	if(PendingBodyTMs.Num())
	{
		//This is extremely inefficient. We need to obtain a write lock which will block other threads from blending
		//For now I'm juts deferring it to the end of this loop, but in general we need to move it all out of here and do it when the blend task is done

		if (bHasBodiesInSyncScene)
		{
			SCENE_LOCK_WRITE(PhysScene->GetPhysXScene(PST_Sync))
		}

		if (bHasBodiesInAsyncScene)
		{
			SCENE_LOCK_WRITE(PhysScene->GetPhysXScene(PST_Async))
		}

		for (const FBodyTMPair& BodyTMPair : PendingBodyTMs)
		{
			BodyTMPair.BI->SetBodyTransform(BodyTMPair.TM, ETeleportType::TeleportPhysics);
		}

		if (bHasBodiesInSyncScene)
		{
			SCENE_UNLOCK_WRITE(PhysScene->GetPhysXScene(PST_Sync))
		}

		if (bHasBodiesInAsyncScene)
		{
			SCENE_UNLOCK_WRITE(PhysScene->GetPhysXScene(PST_Async))
		}
    }
#endif
	

	// Transforms updated, cached local bounds are now out of date.
	InvalidateCachedBounds();
}
void FGameplayCueTranslationManager::PrintTranslationTable_r(FGameplayCueTranslatorNode& Node, FString IdentStr)
{
	if (Node.Links.Num() > 0)
	{
		if (IdentStr.IsEmpty())
		{
			UE_LOG(LogGameplayCueTranslator, Display, TEXT("%s %s"), *Node.CachedGameplayTagName.ToString(), Node.CachedGameplayTag.IsValid() ? TEXT("") : TEXT("*"));
		}

		for (FGameplayCueTranslationLink& Link : Node.Links)
		{
			for (FGameplayCueTranslatorNodeIndex& Index : Link.NodeLookup)
			{
				if (Index.IsValid())
				{
					FGameplayCueTranslatorNode& InnerNode = TranslationLUT[Index];

					if (InnerNode.CachedGameplayTag.IsValid())
					{
						UE_LOG(LogGameplayCueTranslator, Display, TEXT("%s -> %s [%s]"), *IdentStr, *InnerNode.CachedGameplayTag.ToString(), *GetNameSafe(Link.RulesCDO) );
						TotalNumTranslations++;
					}
					else
					{
						UE_LOG(LogGameplayCueTranslator, Display, TEXT("%s -> %s [%s] *"), *IdentStr, *InnerNode.CachedGameplayTagName.ToString(), *GetNameSafe(Link.RulesCDO) );
						TotalNumTheoreticalTranslations++;
					}

					PrintTranslationTable_r(InnerNode, IdentStr + TEXT("  "));
				}
			}
		}

		UE_LOG(LogGameplayCueTranslator, Display, TEXT(""));
	}
}
Beispiel #26
0
void USkeletalMeshComponent::UpdateKinematicBonesToAnim(const TArray<FTransform>& InSpaceBases, ETeleportType Teleport, bool bNeedsSkinning)
{
	SCOPE_CYCLE_COUNTER(STAT_UpdateRBBones);

	// This below code produces some interesting result here
	// - below codes update physics data, so if you don't update pose, the physics won't have the right result
	// - but if we just update physics bone without update current pose, it will have stale data
	// If desired, pass the animation data to the physics joints so they can be used by motors.
	// See if we are going to need to update kinematics
	const bool bUpdateKinematics = (KinematicBonesUpdateType != EKinematicBonesUpdateToPhysics::SkipAllBones);
	const bool bTeleport = Teleport == ETeleportType::TeleportPhysics;
	// If desired, update physics bodies associated with skeletal mesh component to match.
	if(!bUpdateKinematics && !(bTeleport && IsAnySimulatingPhysics()))
	{
		// nothing to do 
		return;
	}

	// Get the scene, and do nothing if we can't get one.
	FPhysScene* PhysScene = nullptr;
	if (GetWorld() != nullptr)
	{
		PhysScene = GetWorld()->GetPhysicsScene();
	}

	if(PhysScene == nullptr)
	{
		return;
	}

	const FTransform& CurrentLocalToWorld = ComponentToWorld;

	// Gracefully handle NaN
	if(CurrentLocalToWorld.ContainsNaN())
	{
		return;
	}

	// If desired, draw the skeleton at the point where we pass it to the physics.
	if (bShowPrePhysBones && SkeletalMesh && InSpaceBases.Num() == SkeletalMesh->RefSkeleton.GetNum())
	{
		for (int32 i = 1; i<InSpaceBases.Num(); i++)
		{
			FVector ThisPos = CurrentLocalToWorld.TransformPosition(InSpaceBases[i].GetLocation());

			int32 ParentIndex = SkeletalMesh->RefSkeleton.GetParentIndex(i);
			FVector ParentPos = CurrentLocalToWorld.TransformPosition(InSpaceBases[ParentIndex].GetLocation());

			GetWorld()->LineBatcher->DrawLine(ThisPos, ParentPos, AnimSkelDrawColor, SDPG_Foreground);
		}
	}

	// warn if it has non-uniform scale
	const FVector& MeshScale3D = CurrentLocalToWorld.GetScale3D();
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
	if( !MeshScale3D.IsUniform() )
	{
		UE_LOG(LogPhysics, Log, TEXT("USkeletalMeshComponent::UpdateKinematicBonesToAnim : Non-uniform scale factor (%s) can cause physics to mismatch for %s  SkelMesh: %s"), *MeshScale3D.ToString(), *GetFullName(), SkeletalMesh ? *SkeletalMesh->GetFullName() : TEXT("NULL"));
	}
#endif


	if (bEnablePerPolyCollision == false)
	{
		const UPhysicsAsset* const PhysicsAsset = GetPhysicsAsset();
		if (PhysicsAsset && SkeletalMesh && Bodies.Num() > 0)
		{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
			if (!ensure(PhysicsAsset->BodySetup.Num() == Bodies.Num()))
			{
				// related to TTP 280315
				UE_LOG(LogPhysics, Warning, TEXT("Mesh (%s) has PhysicsAsset(%s), and BodySetup(%d) and Bodies(%d) don't match"),
					*SkeletalMesh->GetName(), *PhysicsAsset->GetName(), PhysicsAsset->BodySetup.Num(), Bodies.Num());
				return;
			}
#endif

#if WITH_PHYSX
			// Lock the scenes we need (flags set in InitArticulated)
			if(bHasBodiesInSyncScene)
			{
				SCENE_LOCK_WRITE(PhysScene->GetPhysXScene(PST_Sync))
			}

			if (bHasBodiesInAsyncScene)
			{
				SCENE_LOCK_WRITE(PhysScene->GetPhysXScene(PST_Async))
			}
#endif

			// Iterate over each body
			for (int32 i = 0; i < Bodies.Num(); i++)
			{
				// If we have a physics body, and its kinematic...
				FBodyInstance* BodyInst = Bodies[i];
				check(BodyInst);

				if (bTeleport || (BodyInst->IsValidBodyInstance() && !BodyInst->IsInstanceSimulatingPhysics()))
				{
					const int32 BoneIndex = BodyInst->InstanceBoneIndex;

					// If we could not find it - warn.
					if (BoneIndex == INDEX_NONE || BoneIndex >= GetNumSpaceBases())
					{
						const FName BodyName = PhysicsAsset->BodySetup[i]->BoneName;
						UE_LOG(LogPhysics, Log, TEXT("UpdateRBBones: WARNING: Failed to find bone '%s' need by PhysicsAsset '%s' in SkeletalMesh '%s'."), *BodyName.ToString(), *PhysicsAsset->GetName(), *SkeletalMesh->GetName());
					}
					else
					{
#if WITH_PHYSX
						// update bone transform to world
						const FTransform BoneTransform = InSpaceBases[BoneIndex] * CurrentLocalToWorld;
						if(BoneTransform.ContainsNaN())
						{
							const FName BodyName = PhysicsAsset->BodySetup[i]->BoneName;
							UE_LOG(LogPhysics, Warning, TEXT("UpdateKinematicBonesToAnim: Trying to set transform with bad data %s on PhysicsAsset '%s' in SkeletalMesh '%s' for bone '%s'"), *BoneTransform.ToHumanReadableString(), *PhysicsAsset->GetName(), *SkeletalMesh->GetName(), *BodyName.ToString());
							continue;
						}					

						// If kinematic and not teleporting, set kinematic target
						PxRigidDynamic* PRigidDynamic = BodyInst->GetPxRigidDynamic_AssumesLocked();
						if (!IsRigidBodyNonKinematic_AssumesLocked(PRigidDynamic) && !bTeleport)
						{
							PhysScene->SetKinematicTarget_AssumesLocked(BodyInst, BoneTransform, true);
						}
						// Otherwise, set global pose
						else
						{
							const PxTransform PNewPose = U2PTransform(BoneTransform);
							ensure(PNewPose.isValid());
							PRigidDynamic->setGlobalPose(PNewPose);
						}
#endif


						// now update scale
						// if uniform, we'll use BoneTranform
						if (MeshScale3D.IsUniform())
						{
							// @todo UE4 should we update scale when it's simulated?
							BodyInst->UpdateBodyScale(BoneTransform.GetScale3D());
						}
						else
						{
							// @note When you have non-uniform scale on mesh base,
							// hierarchical bone transform can update scale too often causing performance issue
							// So we just use mesh scale for all bodies when non-uniform
							// This means physics representation won't be accurate, but
							// it is performance friendly by preventing too frequent physics update
							BodyInst->UpdateBodyScale(MeshScale3D);
						}
					}
				}
				else
				{
					//make sure you have physics weight or blendphysics on, otherwise, you'll have inconsistent representation of bodies
					// @todo make this to be kismet log? But can be too intrusive
					if (!bBlendPhysics && BodyInst->PhysicsBlendWeight <= 0.f && BodyInst->BodySetup.IsValid())
					{
						UE_LOG(LogPhysics, Warning, TEXT("%s(Mesh %s, PhysicsAsset %s, Bone %s) is simulating, but no blending. "),
							*GetName(), *GetNameSafe(SkeletalMesh), *GetNameSafe(PhysicsAsset), *BodyInst->BodySetup.Get()->BoneName.ToString());
					}
				}
			}

#if WITH_PHYSX
			// Unlock the scenes 
			if (bHasBodiesInSyncScene)
			{
				SCENE_UNLOCK_WRITE(PhysScene->GetPhysXScene(PST_Sync))
			}

			if (bHasBodiesInAsyncScene)
			{
				SCENE_UNLOCK_WRITE(PhysScene->GetPhysXScene(PST_Async))
			}
#endif
		}
	}
	else
	{
		//per poly update requires us to update all vertex positions
		if (MeshObject)
void UGameplayCueManager::OnWorldCleanup(UWorld* World, bool bSessionEnded, bool bCleanupResources)
{
	// Attempting to track down rare GC error where PreallocationInfo_Internal.OwningWorld is not cleaned up.
	ABILITY_LOG(Display, TEXT("UGameplayCueManager::OnWorldCleanup %s Key 0x%X . Current PreallocationInfo_Internal: Key 0x%X"), *GetNameSafe(World), GetTypeHash(FObjectKey(World)), GetTypeHash(PreallocationInfo_Internal.OwningWorldKey));

#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
	DumpPreallocationStats(World);
#endif

	if (PreallocationInfo_Internal.OwningWorldKey == FObjectKey(World))
	{
		// Reset PreallocationInfo_Internal
		OnWorldCreated(nullptr, UWorld::InitializationValues());
		ABILITY_LOG(Display, TEXT("UGameplayCueManager::OnWorldCleanup Reset PreallocationInfo_Internal"));
	}
	else
	{
		ABILITY_LOG(Display, TEXT("UGameplayCueManager::OnWorldCleanup did NOT Reset PreallocationInfo_Internal"));
	}

#if WITH_EDITOR
	for (int32 idx=0; idx < PreallocationInfoList_Internal.Num(); ++idx)
	{
		if (PreallocationInfoList_Internal[idx].OwningWorldKey == FObjectKey(World))
		{
			ABILITY_LOG(Display, TEXT("UGameplayCueManager::OnWorldCleanup Removing PreallocationInfoList_Internal element %d"), idx);
			PreallocationInfoList_Internal.RemoveAtSwap(idx, 1, false);
			idx--;
		}
	}
#endif	
	
}
FString UBlackboardKeyType_Class::DescribeValue(const UBlackboardComponent& OwnerComp, const uint8* RawData) const
{
	return *GetNameSafe(GetValue(this, RawData));
}
void UGameplayCueManager::NotifyGameplayCueActorFinished(AGameplayCueNotify_Actor* Actor)
{
	if (GameplayCueActorRecycle)
	{
		if (Actor->bInRecycleQueue)
		{
			// We are already in the recycle queue. This can happen normally
			// (For example the GC is removed and the owner is destroyed in the same frame)
			return;
		}

		AGameplayCueNotify_Actor* CDO = Actor->GetClass()->GetDefaultObject<AGameplayCueNotify_Actor>();
		if (CDO && Actor->Recycle())
		{
			ensure(Actor->IsPendingKill() == false);
			Actor->bInRecycleQueue = true;

			// Remove this now from our internal map so that it doesn't get reused like a currently active cue would
			if (TWeakObjectPtr<AGameplayCueNotify_Actor>* WeakPtrPtr = NotifyMapActor.Find(Actor->NotifyKey))
			{
				WeakPtrPtr->Reset();
			}

			UE_CLOG((GameplayCueActorRecycleDebug>0), LogAbilitySystem, Display, TEXT("NotifyGameplayCueActorFinished %s"), *GetNameSafe(Actor));

			Actor->SetOwner(nullptr);
			Actor->SetActorHiddenInGame(true);
			Actor->DetachRootComponentFromParent();

			FPreallocationInfo& Info = GetPreallocationInfo(Actor->GetWorld());
			TArray<AGameplayCueNotify_Actor*>& PreAllocatedList = Info.PreallocatedInstances.FindOrAdd(Actor->GetClass());

			// Put the actor back in the list
			if (ensureMsgf(PreAllocatedList.Contains(Actor)==false, TEXT("GC Actor PreallocationList already contains Actor %s"), *GetNameSafe(Actor)))
			{
				PreAllocatedList.Push(Actor);
			}
			
#if WITH_EDITOR
			// let things know that we 'de-spawned'
			ISequenceRecorder& SequenceRecorder	= FModuleManager::LoadModuleChecked<ISequenceRecorder>("SequenceRecorder");
			SequenceRecorder.NotifyActorStopRecording(Actor);
#endif
			return;
		}
	}	

	// We didn't recycle, so just destroy
	Actor->Destroy();
}
bool AAIController::RunBehaviorTree(UBehaviorTree* BTAsset)
{
	// @todo: find BrainComponent and see if it's BehaviorTreeComponent
	// Also check if BTAsset requires BlackBoardComponent, and if so 
	// check if BB type is accepted by BTAsset.
	// Spawn BehaviorTreeComponent if none present. 
	// Spawn BlackBoardComponent if none present, but fail if one is present but is not of compatible class
	if (BTAsset == NULL)
	{
		UE_VLOG(this, LogBehaviorTree, Warning, TEXT("RunBehaviorTree: Unable to run NULL behavior tree"));
		return false;
	}

	bool bSuccess = true;
	bool bShouldInitializeBlackboard = false;

	// see if need a blackboard component at all
	UBlackboardComponent* BlackboardComp = NULL;
	if (BTAsset->BlackboardAsset)
	{
		BlackboardComp = FindComponentByClass<UBlackboardComponent>();
		if (BlackboardComp == NULL)
		{
			BlackboardComp = ConstructObject<UBlackboardComponent>(UBlackboardComponent::StaticClass(), this, TEXT("BlackboardComponent"));
			if (BlackboardComp != NULL)
			{
				BlackboardComp->InitializeBlackboard(BTAsset->BlackboardAsset);
				
				BlackboardComp->RegisterComponent();
				bShouldInitializeBlackboard = true;
			}
		}
		else if (BlackboardComp->GetBlackboardAsset() == NULL)
		{
			BlackboardComp->InitializeBlackboard(BTAsset->BlackboardAsset);
		}
		else if (BlackboardComp->GetBlackboardAsset() != BTAsset->BlackboardAsset)
		{
			bSuccess = false;
			UE_VLOG(this, LogBehaviorTree, Log, TEXT("RunBehaviorTree: BTAsset %s requires blackboard %s while already has %s instantiated"),
				*GetNameSafe(BTAsset), *GetNameSafe(BTAsset->BlackboardAsset), *GetNameSafe(BlackboardComp->GetBlackboardAsset()) );
		}
	}
	
	if (bSuccess)
	{
		UBehaviorTreeComponent* BTComp = Cast<UBehaviorTreeComponent>(BrainComponent);
		if (BTComp == NULL)
		{
			UE_VLOG(this, LogBehaviorTree, Log, TEXT("RunBehaviorTree: spawning BehaviorTreeComponent.."));

			BrainComponent = BTComp = ConstructObject<UBehaviorTreeComponent>(UBehaviorTreeComponent::StaticClass(), this, TEXT("BTComponent"));
			BrainComponent->RegisterComponent();

			if (BrainComponent->bWantsInitializeComponent)
			{
				// make sure that newly created component is initialized before running BT
				// both blackboard and BT to must exist before calling it!
				BrainComponent->InitializeComponent();
			}
		}

		if (bShouldInitializeBlackboard && BlackboardComp && BlackboardComp->bWantsInitializeComponent)
		{
			// make sure that newly created component is initialized before running BT
			// both blackboard and BT to must exist before calling it!

			BlackboardComp->InitializeComponent();
		}

		check(BTComp != NULL);
		BTComp->StartTree(BTAsset, EBTExecutionMode::Looped);
	}

	return bSuccess;
}