124 lines
4.3 KiB
C++
124 lines
4.3 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
|
|
{
|
|
// Releves ERR-038 : les personnages de l'ancienne piece sont rendus ~2 s apres la reconstruction. Un personnage
|
|
// encore actif au-dela appartient a la nouvelle piece (le jeu peut peupler l'arrivee avant de la construire).
|
|
constexpr double SafetySeconds = 3.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;
|
|
}
|
|
|
|
}
|
|
|
|
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.
|
|
// Signature = forme de la piece (echelle de la racine de Room) : elle change a chaque reconstruction (tout trajet
|
|
// passe par la rue, de forme differente). Le nom du lieu n'est pas utilise : il peut se vider un instant sans
|
|
// que la piece change (releve ERR038_apres_20261002, 08:55:59).
|
|
const FString Signature = 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;
|
|
}
|