ERR-008 : garde LPMapMarkersGuardSubsystem (WidgetComponents vides apres HideAllMarkers) (CHG-243)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
edujiro5972 2026-10-08 01:40:48 +02:00
parent 0f1a61c9fe
commit ebae9242a7
4 changed files with 181 additions and 1 deletions

View file

@ -1131,6 +1131,7 @@ Validation L7c/L7d (2026-10-02, parc, même cadrage) : la nuit reste claire (sol
| CHG-155 | 2026-10-05 | ShowCouple | Un lit est reconnu par son nom. Il ne bloque un déplacement que vers le bas, pour se poser ; le retour horizontal n'est plus arrêté et le contact ne renvoie plus la boîte | après avoir quitté le lit, la boîte ne pouvait plus y revenir | revenir au test `DoesPackageExist` et au filtre du flanc seul |
| CHG-156 | 2026-10-05 | Clavier | `LPKeyboardSubsystem` : bouton « Clavier » ajouté à l'exécution dans `MainMenu.SettingsScrollBox` ; panneau pour changer, ajouter ou retirer une touche (actions et axes clavier). Écrit dans `Saved/Config/Windows`, pas dans `GameSettings.sav` | pouvoir réaffecter les touches, dont Q, sans modifier les Blueprints | retirer `LPKeyboardSubsystem.h/.cpp` et la dépendance `UMG` |
| CHG-158 | 2026-10-05 | Réglages | `LPSettingsSubsystem` : onglets Audio, Video, Lewd, General, Keyboard, Misc au-dessus de `SettingsScrollBox`. Les lignes du Blueprint restent en place et sont montrées selon leur texte ; le reste va dans Misc. Keyboard affiche la liste des touches | la liste unique ne montrait pas le clavier | retirer `LPSettingsSubsystem.h/.cpp` |
| CHG-243 | 2026-10-08 | ERR-008 | `Source/LifePlay/LPMapMarkersGuardSubsystem.h/.cpp` (nouveaux) | garde runtime : si `MapMarkers.WidgetComponents` est vide, clear `Vector2Ds`, reconstitue depuis les `UWidgetComponent` existants ou ajoute un slot de focus invisible — évite le spam `Array_Get` / `Set Input Mode Game And UI` (FocusOnMapMarkers sans Length). Corrélé à l'approche PNJ (`updateAllPersonButtons` → `SpawnMapMarkers`). Live Coding PASS (nouvelle classe) | — → créés | supprimer ces deux fichiers |
| CHG-242 | 2026-10-08 | VQ-fix | `Source/LifePlay/LPSettingsSubsystem.cpp`, `LPSettingsSubsystem.h` | contraste UI Settings : `HardenSettingsControls` force un style Slate sombre/lisible sur toutes les cases et SpinBox (valeurs pâles sur fond flou) ; ticker Settings à 0 pour que `ApplyRows` gagne face au BP. Compile `LifePlayEditor` PASS | — → modifiés | retirer `HardenSettingsControls` / remettre ticker 0.5 |
| CHG-241 | 2026-10-08 | VQ-fix | `Source/LifePlay/LPSettingsSubsystem.cpp`, `Source/LifePlay/LPVideoQualitySubsystem.cpp` | correctifs post-VQ : (1) `CategoryOf` ignore les infobulles (faux positifs `screen`/`quality` → Sex Description, Map Marker, NewAnimationsOnly hors Video) + classements par nom UMG (`ShowFPS`, etc.) ; (2) `MainMenu.GI` rattaché sur l'écran titre (spinbox DoF / cases) ; (3) `RepairShowFPS` (style + enabled) ; (4) `ApplyRows` à chaque tick ouvert ; (5) `ApplyToScalability` n'écrit plus que les 4 `sg.*` en `SetByConsole` (fin du spam `SetByScalability ignored` sur ScreenPercentage/PoolSize/SSS). Live Coding PASS | — → modifiés | revenir sur les deux `.cpp` |
| CHG-240 | 2026-10-07 | VQ5 | `Docs/Migration/24_Eval_Agents_VideoQuality.md` (nouveau), `Docs/Migration/etat/VQ/VQ5/VQ5-VAL.md` (nouveau) | clôture VQ5 : évaluation des agents du chantier VQ (lots VQ0–VQ4 tenus/coupés/rollback, qualité des consignes, modèle ↔ complexité dont Fable bloqué → repli Sonnet en VQ2-T2, sync PASS en code et BLOCKED-UI en jeu). Décision **GO conditionnel** avec 3 recommandations. Annexe VQ5-VAL : chemins Overall / Custom / Recommended PASS (code), smoke `-nullrhi` de VQ4 relu (pas de nouveau run : aucun code changé, chemins non atteignables par console). Constat : `DefaultScalability.ini` s'écarte de `BaseScalability.ini` au niveau Epic (cascades 10 → 4, `RadiusThreshold`, `DetailMode`, `RefractionQuality` 2 → 3) ; VQ1-VAL jamais produit ; VQ1 et VQ2 sans CHG. Documentation seule, aucun code | — → créés | supprimer ces deux fichiers |

View file

@ -19,7 +19,7 @@
| ERR-005 | `getBeautyValue` : `Floats_*` index hors bornes | PIE 09-28 ; A/B 2026-10-01 : 0,08/perso en 4.27 contre 3,0 en 5.5 | 1 297 | moyenne | L7i | **corrigé (CHG-042, CX-B12)** — cause : `FString::Find` avec sous-chaîne vide (insensible à la casse, depuis le début) renvoie 0 en UE5 et « non trouvé » en 4.27 ; `Contains(x, "")` devenu vrai : `filterMorphList` appelé sans étiquette ne filtrait plus. 385 nœuds `Contains`/`Split`/`FindSubstring` rebranchés sur `LPStringCompat` ; **validé en jeu le 2026-10-01** : 52 → 2,3/min (4.27 : 1,3) |
| ERR-006 | `Accès à None` `NearVec` dans `Person::standIdle` | PIE 09-28 | 273 | moyenne | L7k | **corrigé indirectement par CX-B12** : par personnage 0,05 (4.27) → 0,38 (5.5) → 0,09 (5.5 + CX-B12) |
| ERR-007 | `Accès à None` `ContactMenu` dans `UpdateDailyPose` | PIE 09-28 | 257 | moyenne | L7k | **corrigé indirectement par CX-B12** : par personnage 0,12 (4.27) → 0,62 (5.5) → 0,20 (5.5 + CX-B12) |
| ERR-008 | `CallFunc_Array_Get_Item` à None dans `GI` | PIE 09-28 | 229 | moyenne | L5 | ouvert |
| ERR-008 | `CallFunc_Array_Get_Item` à None dans `GI` (`FocusOnMapMarkers` → `MapMarkers.WidgetComponents[0]` vide après `HideAllMarkers` / spawn sans amenité) | PIE 09-28 ; retour utilisateur 2026-10-08 (approche PNJ) | 229 | moyenne | L5 | **atténué (CHG-243)** : `LPMapMarkersGuardSubsystem` reconstitue / garantit `WidgetComponents[0]` + clear `Vector2Ds` ; garde BP Length encore souhaitable. Relecture 2026-10-08 : VQ/Settings hors cause ; approche corrélée via `updateAllPersonButtons`→`SpawnMapMarkers` ; `updateButtonSize` = `ButtonSM` seulement (≠ corps / ERR-043) |
| ERR-009 | `SpawnActor failed because no class was specified` | PIE 09-28 | 11 | moyenne | L6 | ouvert |
| ERR-010 | `LogLPModdingTrace` : instrumentation de portage à chaque `LoadTxt` | tous journaux | ≈ 1 300 à 5 400 / session | faible (bruit) | L3 | clos (CHG-016) : `LogModdingExtra` en Verbose |
| ERR-011 | `GetSocketInfoByName … No SkeletalMesh for CharacterMesh` | tous journaux | 80/perso en 4.27, 76 en 5.5 | bruit (existe en 4.27) | — | accepté |

View file

@ -0,0 +1,149 @@
// 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<FObjectPropertyBase>(GI->GetClass()->FindPropertyByName(TEXT("MapMarkers"))))
{
if (AActor* FromGI = Cast<AActor>(Prop->GetObjectPropertyValue_InContainer(GI)))
{
return FromGI;
}
}
for (TObjectIterator<AActor> 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<FArrayProperty>(Object->GetClass()->FindPropertyByName(Name)) : nullptr;
if (!Arr)
{
return;
}
FScriptArrayHelper Helper(Arr, Arr->ContainerPtrToValuePtr<void>(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<FArrayProperty>(Markers->GetClass()->FindPropertyByName(TEXT("WidgetComponents")));
if (!Arr || !CastField<FObjectPropertyBase>(Arr->Inner))
{
return;
}
FScriptArrayHelper Helper(Arr, Arr->ContainerPtrToValuePtr<void>(Markers));
for (int32 Index = Helper.Num() - 1; Index >= 0; --Index)
{
UObject* Entry = *reinterpret_cast<UObject**>(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<UWidgetComponent*> Existing;
Markers->GetComponents<UWidgetComponent>(Existing);
for (UWidgetComponent* Comp : Existing)
{
if (!IsValid(Comp))
{
continue;
}
const int32 Slot = Helper.AddValue();
*reinterpret_cast<UObject**>(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<UWidgetComponent>(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<UObject**>(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)"));
}
}

View file

@ -0,0 +1,30 @@
// Garde ERR-008 : GI.FocusOnMapMarkers lit MapMarkers.WidgetComponents[0] sans test de longueur.
// Apres HideAllMarkers (ou un spawn sans amenite), le tableau est vide → spam log + SetInputMode None.
// Ce sous-systeme maintient une entree valide (composant de focus invisible) et vide Vector2Ds
// quand le tableau est vide, pour eviter le desync AddMarker. Aucun Blueprint n'est modifie.
#pragma once
#include "CoreMinimal.h"
#include "Containers/Ticker.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "LPMapMarkersGuardSubsystem.generated.h"
class AActor;
UCLASS()
class LIFEPLAY_API ULPMapMarkersGuardSubsystem : public UGameInstanceSubsystem
{
GENERATED_BODY()
public:
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
virtual void Deinitialize() override;
private:
bool Tick(float DeltaTime);
void Guard(AActor* Markers);
FTSTicker::FDelegateHandle TickHandle;
bool bLoggedOnce = false;
};