// Fill out your copyright notice in the Description page of Project Settings. #include "Tangible.h" #include "TangibleManager.h" #include "IntegrationGameModeBase.h" #define DEFAULT_BLUEPRINT (TEXT("TangibleStaticMesh")) #define LOCTEXT_NAMESPACE "Luprex Tangible" UlxTangible::UlxTangible() { Manager = nullptr; TangibleId = -1; CurrentActor = nullptr; ActorBlueprintName = TEXT(""); NearAccordingToLuprex = false; NearAccordingToUnreal = false; } void UlxTangible::Init(UlxTangibleManager* tm, int64 id) { Manager = tm; TangibleId = id; } #pragma optimize("", off) void UlxTangible::SetActorBlueprint(const FString &name) { // If we're already of the right class, do nothing. if (ActorBlueprintName == name) { return; } // Get the blueprint. // If the blueprint doesn't exist, or doesn't implement // TangibleInterface, then use the fallback blueprint. UClass *blueprint = Manager->GetTangibleClass(name); if ((!name.IsEmpty()) && (blueprint == nullptr)) { blueprint = Manager->GetTangibleClass(DEFAULT_BLUEPRINT); check(blueprint != nullptr); } // If there's already an actor, delete it. if (CurrentActor != nullptr) { // Remove the tangible component. This is probably // unnecessary, but it makes it more likely that we'll // catch bugs early. UlxTangibleComponent* comp = CurrentActor->GetComponentByClass(); if (comp != nullptr) { comp->DestroyComponent(); } // Now destroy the actor itself. According to various // documents I've read online, it may be necessary to take // further steps to delete the object. Not clear. CurrentActor->Destroy(); // If this actor previously was posessed by a player controller, // then it's not posessed anymore, because there is no actor any more. if (Manager->PossessedTangible == this) { Manager->PossessedTangible = nullptr; }; } // Update the blueprint name ActorBlueprintName = name; // Now create a new actor, unless the BP is nullptr. if (blueprint != nullptr) { UWorld* w = Manager->GetWorld(); FActorSpawnParameters params; // Currently, the actor is spawned at (0,0,0), which is not good. // We should spawn at the actor's current location. I'll get to it // eventually. FTransform transform; transform.SetLocation(FVector(0,0,0)); transform.SetRotation(FQuat(FRotator(0,0,0))); // Create the actor at the specified location even if there's something in the way. params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; // Normally, SpawnActor runs the BeginPlay entry point. We // want to delay that until after we've had a chance to set // up the TangibleComponent. params.bDeferConstruction = true; AActor* a = w->SpawnActor(blueprint, &transform, params); check(a != nullptr); // Insert a TangibleComponent into the actor. // Link the actor to its tangible, and the tangible to its actor. UActorComponent* ac = a->AddComponentByClass(UlxTangibleComponent::StaticClass(), false, FTransform::Identity, false); UlxTangibleComponent* tc = Cast(ac); check(tc != nullptr); tc->Tangible = this; CurrentActor = a; // This executes the BeginPlay entry point. We have to do this here // because we deferred it in SpawnActor. a->FinishSpawning(transform, true); } } void UlxTangible::UpdateAnimationQueue(std::string_view aq) { AnimTracker.Update(aq); } void UlxTangible::MaybeExecuteAnimStateChanged() { int limit = 3; while (AnimTracker.IsChanged()) { if (limit == 0) break; limit -= 1; AnimTracker.ClearChanged(); FString blueprint = AnimTracker.GetCurrentBlueprintName(); if (blueprint.IsEmpty()) blueprint = DEFAULT_BLUEPRINT; SetActorBlueprint(blueprint); AActor *actor = GetActor(); UFunction *aqchanged = UlxTangibleManager::GetAnimationQueueChanged(actor->GetClass()); if (aqchanged != nullptr) { actor->ProcessEvent(aqchanged, nullptr); } } } FVector UlxTangible::GetLocation() const { if (CurrentActor == nullptr) { return FVector(0,0,0); } else { return CurrentActor->GetActorLocation(); } } void UlxTangible::Destroy() { SetActorBlueprint(""); Manager = nullptr; TangibleId = -1; CurrentActor = nullptr; ActorBlueprintName = ""; AnimTracker.Clear(); NearAccordingToLuprex = false; NearAccordingToUnreal = false; } UlxTangible *UlxTangible::GetActorTangible(AActor *actor) { UlxTangibleComponent* comp = actor->GetComponentByClass(); check(comp != nullptr); UlxTangible *result = comp->Tangible.Get(); check(result != nullptr); return result; } void UlxTangible::GetCurrentAnimation(AActor *target, FlxAnimationStep &step) { step = GetActorTangible(target)->AnimTracker.GetCurrentAnimation(); } void UlxTangible::FinishedAnimation(AActor *target, const FlxAnimationStep &step, bool AutoUpdate) { if (target == nullptr) { UE_LOG(LogBlueprint, Error, TEXT("In FinishedAnimation, tangible cannot be null")); return; } UlxTangible *tan = GetActorTangible(target); if (AutoUpdate) { step.AutoUpdateXYZ(target); step.AutoUpdateFacing(target); step.AutoUpdatePlane(&(tan->Plane)); } tan->AnimTracker.FinishedAnimation(step.Hash); FString DebugString = UlxAnimationStepLibrary::AnimationStepDebugString(step); UE_LOG(LogBlueprint, Display, TEXT("Animation Finished: %s"), *DebugString); } FString UlxTangible::GetTangiblePlane(AActor* target) { return GetActorTangible(target)->Plane.ToString(); } void UlxTangible::SetTangiblePlane(AActor* target, const FString& plane) { GetActorTangible(target)->Plane = FName(plane); } bool UlxTangible::IsCurrentPlayer(AActor* target) { UlxTangible *tan = GetActorTangible(target); AIntegrationGameModeBase *gamemode = tan->Manager->GetGameMode(); return (tan->TangibleId == gamemode->PlayerId); } void UlxTangible::SetAutoFinish(AActor *target, const FString &action, const FVector &xyz) { UlxTangible *tan = GetActorTangible(target); tan->AnimTracker.SetAutoFinish(action, xyz); }