130 lines
4.2 KiB
C++
130 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;
|
||
|
|
}
|