// Voir LPMapMarkersGuardSubsystem.h. #include "LPMapMarkersGuardSubsystem.h" #include "Components/WidgetComponent.h" #include "Engine/GameInstance.h" #include "GameFramework/Actor.h" #include "LifePlay.h" #include "UObject/UnrealType.h" namespace LPMapMarkersGuard { AActor* FindMapMarkers(UGameInstance* GI) { if (!GI) { return nullptr; } if (const FObjectPropertyBase* Prop = CastField(GI->GetClass()->FindPropertyByName(TEXT("MapMarkers")))) { if (AActor* FromGI = Cast(Prop->GetObjectPropertyValue_InContainer(GI))) { return FromGI; } } for (TObjectIterator It; It; ++It) { AActor* Candidate = *It; if (!Candidate || Candidate->HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject)) { continue; } if (Candidate->GetClass()->GetName() != TEXT("MapMarkers_C")) { continue; } if (Candidate->GetGameInstance() != GI) { continue; } return Candidate; } return nullptr; } void ClearArrayProp(UObject* Object, FName Name) { FArrayProperty* Arr = Object ? CastField(Object->GetClass()->FindPropertyByName(Name)) : nullptr; if (!Arr) { return; } FScriptArrayHelper Helper(Arr, Arr->ContainerPtrToValuePtr(Object)); Helper.EmptyValues(); } } void ULPMapMarkersGuardSubsystem::Initialize(FSubsystemCollectionBase& Collection) { Super::Initialize(Collection); TickHandle = FTSTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateUObject(this, &ULPMapMarkersGuardSubsystem::Tick), 0.25f); } void ULPMapMarkersGuardSubsystem::Deinitialize() { FTSTicker::GetCoreTicker().RemoveTicker(TickHandle); Super::Deinitialize(); } bool ULPMapMarkersGuardSubsystem::Tick(float DeltaTime) { (void)DeltaTime; if (AActor* Markers = LPMapMarkersGuard::FindMapMarkers(GetGameInstance())) { Guard(Markers); } return true; } void ULPMapMarkersGuardSubsystem::Guard(AActor* Markers) { FArrayProperty* Arr = CastField(Markers->GetClass()->FindPropertyByName(TEXT("WidgetComponents"))); if (!Arr || !CastField(Arr->Inner)) { return; } FScriptArrayHelper Helper(Arr, Arr->ContainerPtrToValuePtr(Markers)); for (int32 Index = Helper.Num() - 1; Index >= 0; --Index) { UObject* Entry = *reinterpret_cast(Helper.GetRawPtr(Index)); if (!IsValid(Entry)) { Helper.RemoveValues(Index); } } if (Helper.Num() > 0) { return; } // Desync HideAllMarkers : composants detruits, Vector2Ds encore pleins → AddMarker ne recree rien. LPMapMarkersGuard::ClearArrayProp(Markers, TEXT("Vector2Ds")); TArray Existing; Markers->GetComponents(Existing); for (UWidgetComponent* Comp : Existing) { if (!IsValid(Comp)) { continue; } const int32 Slot = Helper.AddValue(); *reinterpret_cast(Helper.GetRawPtr(Slot)) = Comp; } if (Helper.Num() > 0) { if (!bLoggedOnce) { bLoggedOnce = true; UE_LOG(LogLifePlay, Display, TEXT("MapMarkers : WidgetComponents reconstitue depuis %d composant(s) (ERR-008)"), Helper.Num()); } return; } UWidgetComponent* Focus = NewObject(Markers, TEXT("LPFocusWidgetComponent")); if (!Focus) { return; } if (USceneComponent* Root = Markers->GetRootComponent()) { Focus->SetupAttachment(Root); } Focus->SetHiddenInGame(true); Focus->SetVisibility(false); Focus->SetCollisionEnabled(ECollisionEnabled::NoCollision); Focus->RegisterComponent(); const int32 Slot = Helper.AddValue(); *reinterpret_cast(Helper.GetRawPtr(Slot)) = Focus; if (!bLoggedOnce) { bLoggedOnce = true; UE_LOG(LogLifePlay, Display, TEXT("MapMarkers : slot de focus WidgetComponents[0] ajoute (ERR-008, SetInputMode sans crash)")); } }