Esempio n. 1
0
bool ACharacter::CanUseRootMotionRepMove(const FSimulatedRootMotionReplicatedMove& RootMotionRepMove, const FAnimMontageInstance& ClientMontageInstance) const
{
    // Ignore outdated moves.
    if( GetWorld()->TimeSince(RootMotionRepMove.Time) <= 0.5f )
    {
        // Make sure montage being played matched between client and server.
        if( RootMotionRepMove.RootMotion.AnimMontage && (RootMotionRepMove.RootMotion.AnimMontage == ClientMontageInstance.Montage) )
        {
            UAnimMontage * AnimMontage = ClientMontageInstance.Montage;
            const float ServerPosition = RootMotionRepMove.RootMotion.Position;
            const float ClientPosition = ClientMontageInstance.GetPosition();
            const float DeltaPosition = (ClientPosition - ServerPosition);
            const int32 CurrentSectionIndex = AnimMontage->GetSectionIndexFromPosition(ClientPosition);
            if( CurrentSectionIndex != INDEX_NONE )
            {
                const int32 NextSectionIndex = (CurrentSectionIndex < ClientMontageInstance.NextSections.Num()) ? ClientMontageInstance.NextSections[CurrentSectionIndex] : INDEX_NONE;

                // We can only extract root motion if we are within the same section.
                // It's not trivial to jump through sections in a deterministic manner, but that is luckily not frequent.
                const bool bSameSections = (AnimMontage->GetSectionIndexFromPosition(ServerPosition) == CurrentSectionIndex);
                // if we are looping and just wrapped over, skip. That's also not easy to handle and not frequent.
                const bool bHasLooped = (NextSectionIndex == CurrentSectionIndex) && (FMath::Abs(DeltaPosition) > (AnimMontage->GetSectionLength(CurrentSectionIndex) / 2.f));
                // Can only simulate forward in time, so we need to make sure server move is not ahead of the client.
                const bool bServerAheadOfClient = ((DeltaPosition * ClientMontageInstance.GetPlayRate()) < 0.f);

                UE_LOG(LogRootMotion, Log,  TEXT("\t\tACharacter::CanUseRootMotionRepMove ServerPosition: %.3f, ClientPosition: %.3f, DeltaPosition: %.3f, bSameSections: %d, bHasLooped: %d, bServerAheadOfClient: %d"),
                       ServerPosition, ClientPosition, DeltaPosition, bSameSections, bHasLooped, bServerAheadOfClient);

                return bSameSections && !bHasLooped && !bServerAheadOfClient;
            }
        }
    }
    return false;
}
Esempio n. 2
0
float UAnimInstance::PlaySlotAnimation(UAnimSequenceBase* Asset, FName SlotNodeName, float BlendInTime, float BlendOutTime, float InPlayRate)
{
	// create temporary montage and play
	bool bValidAsset = Asset && !Asset->IsA(UAnimMontage::StaticClass());
	if (!bValidAsset)
	{
		// user warning
		UE_LOG(LogAnimation, Warning, TEXT("Invalid Asset. If Montage, use Montage_Play"));
		return 0.f;
	}

	if (SlotNodeName == NAME_None)
	{
		// user warning
		UE_LOG(LogAnimation, Warning, TEXT("SlotNode Name is required. Make sure to add Slot Node in your anim graph and name it."));
		return 0.f;
	}

	USkeleton * AssetSkeleton = Asset->GetSkeleton();
	if (!CurrentSkeleton->IsCompatible(AssetSkeleton))
	{
		UE_LOG(LogAnimation, Warning, TEXT("The Skeleton isn't compatible"));
		return 0.f;
	}

	// now play
	UAnimMontage * NewMontage = NewObject<UAnimMontage>();
	NewMontage->SetSkeleton(AssetSkeleton);

	// add new track
	FSlotAnimationTrack NewTrack;
	NewTrack.SlotName = SlotNodeName;
	FAnimSegment NewSegment;
	NewSegment.AnimReference = Asset;
	NewSegment.AnimStartTime = 0.f;
	NewSegment.AnimEndTime = Asset->SequenceLength;
	NewSegment.AnimPlayRate = 1.f;
	NewSegment.StartPos = 0.f;
	NewMontage->SequenceLength = Asset->SequenceLength;
	NewTrack.AnimTrack.AnimSegments.Add(NewSegment);
		
	FCompositeSection NewSection;
	NewSection.SectionName = TEXT("Default");
	NewSection.StartTime = 0.f;

	// add new section
	NewMontage->CompositeSections.Add(NewSection);
	NewMontage->BlendInTime = BlendInTime;
	NewMontage->BlendOutTime = BlendOutTime;
	NewMontage->SlotAnimTracks.Add(NewTrack);

	return Montage_Play(NewMontage, InPlayRate);
}
Esempio n. 3
0
bool UAnimInstance::IsPlayingSlotAnimation(UAnimSequenceBase* Asset, FName SlotNodeName )
{
	// check if this is playing
	FAnimMontageInstance * CurrentInstance = GetActiveMontageInstance();
	// make sure what is active right now is transient that we created by request
	if ( CurrentInstance && CurrentInstance->Montage && CurrentInstance->Montage->GetOuter() == GetTransientPackage() )
	{
		UAnimMontage * CurMontage = CurrentInstance->Montage;

		const FAnimTrack * AnimTrack = CurMontage->GetAnimationData(SlotNodeName);
		if (AnimTrack && AnimTrack->AnimSegments.Num() == 1)
		{
			// find if the 
			return (AnimTrack->AnimSegments[0].AnimReference == Asset);
		}
	}

	return false;
}
UObject* UAnimMontageFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn)
{
	if (TargetSkeleton || SourceAnimation)
	{
		UAnimMontage* AnimMontage = ConstructObject<UAnimMontage>(Class,InParent,Name,Flags);

		if(SourceAnimation)
		{
			USkeleton* SourceSkeleton = SourceAnimation->GetSkeleton();
			//Make sure we haven't asked to create an AnimComposite with mismatching skeletons
			check(TargetSkeleton == NULL || TargetSkeleton == SourceSkeleton);
			TargetSkeleton = SourceSkeleton;

			FAnimSegment NewSegment;
			NewSegment.AnimReference = SourceAnimation;
			NewSegment.AnimStartTime = 0.f;
			NewSegment.AnimEndTime = SourceAnimation->SequenceLength;
			NewSegment.AnimPlayRate = 1.f;
			NewSegment.LoopingCount = 1;
			NewSegment.StartPos = 0.f;

			FSlotAnimationTrack NewTrack;
			NewTrack.AnimTrack.AnimSegments.Add(NewSegment);

			NewTrack.SlotName = FAnimSlotGroup::DefaultSlotName;
			AnimMontage->SlotAnimTracks.Add( NewTrack );
			AnimMontage->SetSequenceLength(SourceAnimation->SequenceLength);
		}

		AnimMontage->SetSkeleton(TargetSkeleton);

		return AnimMontage;
	}

	return NULL;
}
PyObject *py_ue_add_anim_composite_section(ue_PyUObject * self, PyObject * args)
{
	ue_py_check(self);

	char *name;
	float time;
	if (!PyArg_ParseTuple(args, "sf:add_anim_composite_section", &name, &time))
		return nullptr;

	UAnimMontage *anim = ue_py_check_type<UAnimMontage>(self);
	if (!anim)
		return PyErr_Format(PyExc_Exception, "UObject is not a UAnimMontage.");

	return PyLong_FromLong(anim->AddAnimCompositeSection(FName(UTF8_TO_TCHAR(name)), time));
}