LifePlay-Revival/Source/LifePlay/LPRoomTransitionSubsystem.cpp
2026-10-02 10:46:01 +02:00

129 lines
4.2 KiB
C++

// Portage UE 5.5 - voir LPRoomTransitionSubsystem.h
#include "LPRoomTransitionSubsystem.h"
#include "Components/SceneComponent.h"
#include "Engine/GameInstance.h"
#include "GameFramework/Actor.h"
#include "HAL/PlatformTime.h"
#include "LifePlay.h"
#include "UObject/UnrealType.h"
namespace
{
constexpr double SafetySeconds = 10.0;
template <typename T>
T* GetObjectProperty(const UObject* Container, const TCHAR* Name)
{
const FObjectPropertyBase* Prop = Container ? CastField<FObjectPropertyBase>(Container->GetClass()->FindPropertyByName(Name)) : nullptr;
return Prop ? Cast<T>(Prop->GetObjectPropertyValue_InContainer(Container)) : nullptr;
}
/** Contenu d'une variable tableau d'acteurs de GI (DummyPersonsInUse, PersonsUsedThisScene). */
TArray<AActor*> GetActorArray(const UObject* Container, const TCHAR* Name)
{
TArray<AActor*> Result;
const FArrayProperty* Prop = Container ? CastField<FArrayProperty>(Container->GetClass()->FindPropertyByName(Name)) : nullptr;
const FObjectPropertyBase* Inner = Prop ? CastField<FObjectPropertyBase>(Prop->Inner) : nullptr;
if (!Inner)
{
return Result;
}
FScriptArrayHelper Helper(Prop, Prop->ContainerPtrToValuePtr<void>(Container));
for (int32 i = 0; i < Helper.Num(); ++i)
{
if (AActor* Actor = Cast<AActor>(Inner->GetObjectPropertyValue(Helper.GetRawPtr(i))))
{
Result.Add(Actor);
}
}
return Result;
}
/** Valeur texte d'une variable de GI, quel que soit son type (chaine, nom, texte). */
FString GetPropertyText(const UObject* Container, const TCHAR* Name)
{
FString Text;
if (const FProperty* Prop = Container ? Container->GetClass()->FindPropertyByName(Name) : nullptr)
{
Prop->ExportTextItem_Direct(Text, Prop->ContainerPtrToValuePtr<void>(Container), nullptr, nullptr, PPF_None);
}
return Text;
}
}
void ULPRoomTransitionSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
Super::Initialize(Collection);
TickHandle = FTSTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateUObject(this, &ULPRoomTransitionSubsystem::Tick));
}
void ULPRoomTransitionSubsystem::Deinitialize()
{
FTSTicker::GetCoreTicker().RemoveTicker(TickHandle);
Super::Deinitialize();
}
bool ULPRoomTransitionSubsystem::Tick(float DeltaTime)
{
const UGameInstance* GI = GetGameInstance();
const AActor* Room = GetObjectProperty<AActor>(GI, TEXT("Room"));
const USceneComponent* Root = IsValid(Room) ? Room->GetRootComponent() : nullptr;
if (!Root)
{
return true;
}
const TArray<AActor*> InUse = GetActorArray(GI, TEXT("DummyPersonsInUse"));
const double Now = FPlatformTime::Seconds();
// 1. Suivi des personnages caches : rendus a la reserve, reaffiches par le jeu, ou delai de securite depasse.
for (auto It = Hidden.CreateIterator(); It; ++It)
{
AActor* Actor = It.Key().Get();
if (!IsValid(Actor) || !InUse.Contains(Actor) || !Actor->IsHidden())
{
It.RemoveCurrent();
}
else if (Now - It.Value() > SafetySeconds)
{
Actor->SetActorHiddenInGame(false);
UE_LOG(LogLifePlay, Log, TEXT("Changement de lieu : %s toujours actif apres %.0f s, reaffiche"), *Actor->GetName(), SafetySeconds);
It.RemoveCurrent();
}
}
// 2. Changement de piece : cacher les personnages actifs au tick precedent, sauf compagnon et scene en cours.
const FString Signature = GetPropertyText(GI, TEXT("CurrentAmenity")) + TEXT("|") + Root->GetRelativeScale3D().ToString();
if (!LastRoomSignature.IsEmpty() && Signature != LastRoomSignature)
{
const AActor* Companion = GetObjectProperty<AActor>(GI, TEXT("Companion"));
const TArray<AActor*> ScenePersons = GetActorArray(GI, TEXT("PersonsUsedThisScene"));
int32 Count = 0;
for (const TWeakObjectPtr<AActor>& Weak : LastInUse)
{
AActor* Actor = Weak.Get();
if (!IsValid(Actor) || Actor == Companion || ScenePersons.Contains(Actor) || Actor->IsHidden() || !InUse.Contains(Actor))
{
continue;
}
Actor->SetActorHiddenInGame(true);
Hidden.Add(Actor, Now);
++Count;
}
if (Count > 0)
{
UE_LOG(LogLifePlay, Log, TEXT("Changement de lieu (%s -> %s) : %d personnage(s) de la piece precedente caches"),
*LastRoomSignature, *Signature, Count);
}
}
LastRoomSignature = Signature;
LastInUse.Reset(InUse.Num());
for (AActor* Actor : InUse)
{
LastInUse.Add(Actor);
}
return true;
}