LifePlay-Revival/Docs/Migration/etat/CAM/CAM-COMMUN3-DIAG.md
edujiro5972 8084622450 LifePlay UE 5.8 : état de développement au 2026-10-19
Tickets : REP1-T4

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 22:57:42 +02:00

26 KiB
Raw Blame History

CAM-COMMUN3-DIAG : D8 KO, caméra collée à la nuque (2026-10-13)

Demande de Big Boss : quel Wall, pourquoi la tête est dans sa collision, quel correctif parmi (a), (b), (c). Lecture seule, sans UE ni MCP. Aucune écriture avant GO.

Sources :

  • journal partiel D:\Game\LifePlay_Backup_5.5\COMMUN-3\essais\LifePlay_commun3_partiel_2030_BOSS.log (MD5 d42c53f9…, heures UTC = locale − 2 h) ;
  • dump Room CAM-B2f-VAL_LPDumpFunction_20261013-195332.txt ;
  • composants Person CAM-T4_LPDumpComponents_20261011-004910.txt ;
  • carte ST/STE/STE-D_LPDumpComponents_20261010-113200.txt ;
  • StreetMap_Static ST/STA/dumps/StreetMap_Static__EventGraph.txt ;
  • CAM-B1-IMPL.md (B1-12).

1. Relevé du témoin (23 lignes Temoin C2, 18:25 à 18:29 UTC)

Objet touché par les deux sondes (Camera et Visibility, toujours identiques) Lignes Pièces (largeur de boîte X × Y)
StaticMeshComponent0 de Wall (caché), départ déjà dedans 16 665 × 640 (15), 847 × 815 (1)
StaticMeshComponent0 de Wall (caché), à 61-131 cm de la tête 4 257 × 1515 (rue, 2), 1028 × 990, 665 × 640
rien 3 rue 257 × 1515 (2), 847 × 815, marge de boîte 19 à 37 cm
Aucune ligne ne touche un personnage (Person_C : 0).

2. DIAG

Quel Wall (prouvé). Ce n'est pas un mur de Room (Wall1-4, ignorés avec Room par bIgnoreSelf). C'est l'acteur StaticMeshActor PersistentLevel.Wall de CentralLondon :

  • il fait partie des ShowOnlyActors des SceneCapture (STE-D_LPDumpComponents, l. 11) ;
  • GI.Wall le référence ;
  • c'est le panneau de fond qui montre l'image du lieu : StreetMap_Static.UpdateWall(Amenity) lui donne la texture AmenityBackgrounds (WallDM, paramètre PNG). Il est caché dès qu'une pièce est affichée : Room B1-12, GI.Wall caché = NON(Room.bHidden), nœud 88 ; et Wall caché en C1, nœud 438. Le témoin le donne toujours cache=1.

Pourquoi la tête est dedans (prouvé pour le fond, estimé pour la position).

  • Wall est fixe dans le niveau. La pièce, elle, est toujours posée au même point (Room loc = (-3131543, -14967213, -115) dans tous les relevés du journal COMMUN-2) mais change d'échelle selon le lieu (3,5 × 18, 8 × 8, 12 × 12, 45 × 45). Le panneau traverse donc l'intérieur de certaines pièces : 4 pièces différentes ici.
  • Le joueur le traverse sans être arrêté : la capsule de Person ignore WorldStatic (profil Custom, écarts Visibility / WorldStatic / Pawn Ignore, dump T4). Wall est un StaticMeshActor, donc WorldStatic (type par défaut, estimé).
  • Sa collision, invisible mais active, bloque Camera et Visibility. Les sondes partent de la douille head déjà dans le panneau : impact à 0 cm, bStartPenetrating. La caméra se place alors à 20 cm de la tête, à hauteur 0 (à 18:28-18:29, joueur immobile, 13 lignes de suite).

Correction du DIAG de COMMUN-2. La cause « PNJ cachés en collision » était fausse. Le témoin ne voit aucun personnage, et le passage au canal Visibility (B2f) n'a rien changé, puisque Wall bloque aussi ce canal. La vraie cause de « caméra trop près autour des meubles » est très probablement Wall : le joueur debout près d'un meuble se trouve dans la bande du panneau. Le passage à Visibility reste neutre et peut rester en place.

Les 3 lignes « rien » (marge de boîte de 19 à 37 cm, rue étroite surtout) relèvent de la boîte B2e. C'est l'effet voulu, « toujours dans la pièce ».

3. Les 3 pistes

Piste Effet sur les 23 lignes Coût Risque Avis
(a) GI.Wall dans les acteurs ignorés des sondes les 20 lignes Wall (16 dedans + 4 à distance) Room : add_node_pin sur MakeArray_5 + connect_pins VariableGet_260.Wall (getter GI.Wall déjà présent) → nouvelle entrée [2] ; 2 écritures, aucun nœud créé nul hors caméra : seule la liste ActorsToIgnore des 3 sondes (459, 499, 505) change ; GI.Wall nul → entrée ignorée retenue
(b) ignorer un impact « départ déjà dedans » 16 lignes sur 20 : les 4 Wall à distance restent ≈ 4-6 nœuds par sonde (BreakHitResult, NOT, AND) × 3 masque aussi les vrais cas « dedans » ; ne traite pas la cause non
(c) collision des murs cachés en Ignore (Camera, Visibility) les 20 lignes 3 voies de masquage de Wall (PC, Room, GI) ou un sous-système C++ ; touche un acteur du niveau change le jeu hors caméra (clics, scènes) ; hors périmètre CAM non pour CAM ; voir § 5

4. Correctif proposé : B2g (Room par lp-mcp-bp, plus le témoin C++)

  1. Instantané .\Tools\Snapshot.ps1 -Lot CAM-B2g (Room F2B082D2911D9F7C7BE60C2CF30EE6D5 attendu).
  2. Room :
    • get_node_infos sur K2Node_MakeArray_5 (entrées [0] PlayerCharacter et [1] CamRoom ; sortie vers 459, 499 et 505) et sur K2Node_VariableGet_260 (Wall, self ← VariableGet_257.GI) ;
    • add_node_pin sur MakeArray_5, puis connect_pins 260.Wall → nouvelle entrée [2] ;
    • relecture, is_dirty = vrai, compilation stricte, save_assets de Room seul, MD5 différent.
  3. Témoin C++ (LPCameraModeSubsystem.cpp, WitnessC2) : ajouter GI.Wall aux acteurs ignorés, pour qu'il reste le miroir de la sonde de Room (2 lignes : lecture de Wall sur GI, AddIgnoredActor).
  • VAL :
    • V5 : MakeArray_5 a 3 entrées, [2] ← 260.Wall, aucune autre différence ;
    • V6 = référence ;
    • V7 au prochain build commun.
  • Essai : rejouer D8 dans la même chambre (665 × 640), près du meuble, debout immobile. La caméra reste derrière, à sa distance. Les lignes Temoin C2 ne doivent plus citer Wall.
  • Barème :
    • Room : a0 b1 c0 d0 e1 f0 = 2 → N1, ajusté à N3 (MCP par lp-mcp-bp) ; S = C3 1 + f 0 = 1 : une fiche ;
    • C++ : a0 b0 c0 d0 e1 f0 = 1 → N1 ; S = 0.

5. Hors CAM, à signaler (avis seulement)

Wall caché garde une collision qui bloque Visibility au milieu de certaines pièces. Les clics à la souris (GetHitResultUnderCursor, canal Visibility par défaut) pourraient donc buter sur ce panneau invisible, dans la même bande. C'est un défaut probable du jeu d'origine, non mesuré ici. S'il est confirmé, la piste (c), par exemple Wall en Ignore pour Visibility et Camera pendant qu'il est caché, relève du lot qui tient les clics ou le décor, pas de CAM.

6. Second cas (18:30:11, 18:30:17, 18:30:23 UTC ; lignes relayées par Big Boss, après la copie partielle)

Signature : « caméra à 23 cm de la tête (hauteur +22) ; sonde Camera : rien ; sonde Visibility : rien ; boîte C2 : marge 149 cm (largeur X 847, Y 815) ». À 18:30:05, c'était encore le cas « Wall, départ déjà dedans ».

Hypothèses de Big Boss écartées (dump de Room après B2f) :

  • distance restée au minimum après le repli : non. C2Target n'a pas de mémoire. UpdateRoomCam appelle ComputeC2Target (467) à chaque passage de la minuterie, et la cible est recalculée depuis la tête (61, 62, puis 66 en repli). Seule la poursuite VInterpTo (468, vitesse 8) lisse le trajet : environ 0,3 s pour combler 90 %, pas 12 s.
  • molette : non. C2Dist est borné entre −75 et +125 autour de 200 cm, donc au moins 125 cm, jamais 23.
  • boîte B2e : non. La marge est de 149 cm.

Cause estimée : le même Wall, cette fois juste derrière la tête et non autour d'elle.

  1. La sonde principale 459 va de la tête vers la cible, derrière la rotation de contrôle. Elle touche Wall à quelques centimètres. La cible devient l'impact + normale × 20 (61), donc à moins de 80 cm.
  2. Le repli s'enclenche (95, seuil 80). La sonde 505 va de la tête vers « tête + 100 en Z + 60 cm vers l'arrière » (24, 23, 25). Elle traverse encore le panneau, juste derrière. La cible devient l'impact + normale × 20 (27, 66) : un point à environ 20 cm de la tête et un peu au-dessus. C'est exactement la signature : 23 cm, hauteur +22.
  3. Le témoin ne voit rien parce qu'il sonde vers la caméra, à plat. La caméra est presque à la verticale de la tête, légèrement ramenée vers l'avant par la normale × 20. La sonde part donc à l'opposé du panneau. Le témoin n'est pas faux, mais il est aveugle à ce cas : il ne refait pas le trajet de la sonde 459.
  • Statut : estimé. Il est cohérent avec la position du joueur juste après le cas « dedans » de 18:30:05 : il en sort de quelques centimètres et le panneau reste derrière lui. Il est à confirmer sur le journal définitif, ou par le témoin corrigé ci-dessous.

Effet du correctif (a) : les 3 sondes (459, 499, 505) partagent MakeArray_5. Ignorer GI.Wall couvre donc aussi ce second cas.

Complément au témoin C++ (B2g) pour que le cas devienne prouvable :

  • sonder aussi dans l'axe de la sonde 459 : à plat, vers l'arrière de la rotation de contrôle du PC, sur 250 cm ;
  • journaliser la distance tête → Room.C2Target. Une cible proche avec une sonde vers l'arrière qui touche désigne l'obstacle. Une cible lointaine avec une caméra proche désignerait la poursuite. Barème inchangé : N1, S = 0.

7. KO C1 : « la souris ne fait plus tourner la vue » (vers 18:37:50 UTC)

DIAG (prouvé par le dump de Room après B2f et par l'historique git).

  • Ce n'est pas une régression de B2d, et l'orientation vers la marche n'est pas de B2d.
    • bOrientRotationToMovement = true et bUseControllerRotationYaw = false sont posés dans LPDirectControlSubsystem::Walk depuis le commit d'origine 5e901be (Proximité). git log -S bOrientRotationToMovement ne donne que ce commit. Le diff non commité de STG (3a, 3b) n'y touche pas.
    • En C1, la souris n'a jamais tourné la vue. C'est la décision Q11 de la SPEC (« C1 masque cheveux, soleil, mur ; pas de regard à la souris »).
    • Dans Room, CircleCamera (souris) et LeftRight (flèches) ne tournent la rotation de contrôle qu'en C2 (IfThenElse_96 / _97, condition PO_8 : vue = CamRoom). Hors C2, sans constructeur, sexe ni espace (IfThenElse_26, OR 19), la branche else est vide. Elle l'était déjà avant B2d.
  • Ce que voit le joueur en C1 :
    • la vue est attachée au maillage, au niveau de la tête (B1-3) : elle tourne seulement avec le corps ;
    • le corps se tourne vers la marche (bOrientRotationToMovement) ;
    • la marche suit le lacet de la rotation de contrôle (Walk, l. 908), qui ne change qu'en C2 (souris, flèches, PlaceC2). En C1, on ne choisit donc la direction du regard qu'en marchant. Après Q ou D, le corps regarde de côté, mais Z ramène vers l'axe de contrôle.
  • La piste « rétablir bUseControllerRotationYaw = true » ne marcherait pas (estimé fort). Le joueur n'est pas possédé par le PC : la marche tourne en « physique sans contrôleur », bRunPhysicsWithNoController (Walk, l. 875-879 ; la marche ne fonctionne que grâce à ce réglage). bUseControllerRotationYaw n'agit que par FaceRotation, appelée par le contrôleur du pion possédé. Sans contrôleur, le corps ne suivrait pas la souris.
  • Autre point : Walk remet bOrientRotationToMovement à vrai à chaque passage où il est faux (l. 888-892). Le couper ailleurs, dans Room par exemple, serait annulé à l'image suivante.

Correctif proposé : regard horizontal à la souris en C1, comme un jeu à la première personne. Il se fait en deux parties qui vont ensemble.

  1. Room (CAM, lp-mcp-bp) : la souris et les flèches gauche/droite tournent la rotation de contrôle en C1 aussi.
    • (N) BooleanOR : A ← PromotableOperator_8 (vue = CamRoom), B ← VariableGet_269.CamC1On ;
    • sortie → IfThenElse_96.Condition et IfThenElse_97.Condition (remplace PO_8 sur ces deux seules entrées) ;
    • PO_8 reste relié à 91, 98, 99 et 100 : molette et flèches haut/bas inchangées hors C2. 1 nœud, 4 liens. Barème : a0 b1 c0 d0 e1 f1 = 3 → N1, ajusté à N3 (MCP) ; S = C3 1 + f 1 = 2 < 3. Peut passer dans la même ouverture d'éditeur que B2g.
  2. LPDirectControlSubsystem::Walk (fichier STG, correctif exact) : en C1, le corps suit le lacet de contrôle et n'est plus orienté par la marche. En sortant de C1, on revient à l'orientation vers la marche.
// dans Walk, a la place du bloc « if (!Move->bOrientRotationToMovement) { ... } » (l. 888-892)
const bool bFirstPerson = FirstPersonView(GI, Pawn, PC);   // C1 : Room.CamC1On et vue = le joueur
if (Move->bOrientRotationToMovement == bFirstPerson)
{
	Move->bOrientRotationToMovement = !bFirstPerson;
	Character->bUseControllerRotationYaw = false;   // sans effet sans controleur ; garde l'etat d'origine
}
if (bFirstPerson)
{
	// C1 : le corps (et la vue attachee a la tete) suit le lacet de la souris, a chaque image.
	Character->SetActorRotation(FRotator(0.f, PC->GetControlRotation().Yaw, 0.f));
}

// espace anonyme, a cote de ScenePlaying
bool FirstPersonView(const UObject* GI, const APawn* Pawn, const APlayerController* PC)
{
	const FObjectPropertyBase* RoomProp = GI ? CastField<FObjectPropertyBase>(GI->GetClass()->FindPropertyByName(TEXT("Room"))) : nullptr;
	const UObject* Room = RoomProp ? RoomProp->GetObjectPropertyValue_InContainer(GI) : nullptr;
	const FBoolProperty* C1 = IsValid(Room) ? CastField<FBoolProperty>(Room->GetClass()->FindPropertyByName(TEXT("CamC1On"))) : nullptr;
	return C1 && C1->GetPropertyValue_InContainer(Room) && PC && PC->GetViewTarget() == Pawn;
}
  • En entrant en C1 par C, le corps prend le lacet de contrôle, donc la direction où regardait C2. La vue reste ainsi dans l'axe de la caméra précédente. Aucun alignement n'est nécessaire.
  • Pas de regard vertical (tangage) dans ce correctif : il faudrait tourner FirstPersonSM. C'est à décider à part.
  • Barème STG : a0 b1 c0 d1 e1 f1 = 4 → N1 ; S = 0 (code exact) + 1 = 1.
  • Essai :
    • en C1, la souris et les flèches gauche/droite tournent la vue sur place ;
    • Z avance là où l'on regarde, Q et D font un pas de côté sans tourner la vue ;
    • en C2, rien ne change ;
    • en revenant en C1, la vue regarde dans l'axe de la caméra C2.
  • Dépendance : sans la partie 1, la partie 2 fige le corps sur un lacet que rien ne change en C1. Les deux parties doivent entrer dans le même build.

8. Troisième cas (session 2, joueur assis, 18:54:08-20) et géométrie de Wall (prouvée)

Géométrie de Wall (prouvée, deux sources concordantes) :

  • relevé de la carte portage55/L6f/L6f_LPDumpComponents_20260930-112932.txt (-Filter=Wall) : StaticMesh = /Engine/BasicShapes/Cube, BodyInstance = (ObjectType=ECC_WorldStatic, CollisionProfileName="BlockAll"), RelativeLocation = (-3131490, -14967219, 26), RelativeScale3D = (0.1, 12.5625, 5.75) ;
  • boîte journalisée en jeu par ShowCouple (« coque Wall ignorée », journal COMMUN-2) : Min = (-3131495, -14967847.1, -261.5), Max = (-3131485, -14966590.9, 313.5).

C'est une plaque verticale de 10 cm d'épaisseur (X), longue de 12,56 m (Y) et haute de 5,75 m. Elle est fixe et se trouve à 53 cm du centre de la pièce (Room toujours en X = -3131543), parallèle à Y. Elle traverse donc toutes les pièces, pas seulement certaines (correction du § 2). Elle est cachée, mais BlockAll bloque Camera, Visibility et tout le reste. Le joueur la traverse, car sa capsule ignore WorldStatic. ShowCouple l'ignorait déjà comme « coque ».

Recoupement avec le témoin (session 1, MD5 27e654cc…) :

  • la longue série « départ déjà dedans » de 18:28:08 à 18:29:21 a lieu joueur immobile en X = -3131499,6 : dans la plaque, à 5 cm de la face X = -3131495 ;
  • à 18:30:11-23 (« rien », 23 cm, +22) puis 18:30:29 (« dedans », même caméra), le joueur est immobile en X = -3131522,9 : à 28 cm de la face, la tête oscille au bord de la plaque ;
  • les autres lignes ont une position relevée jusqu'à 5 s plus tôt (vidage périodique), le joueur étant en marche : elles ne se comparent pas.

Le troisième cas est le même mécanisme que le § 6 : la plaque juste derrière la tête.

  • La sonde 459 touche la plaque à quelques centimètres derrière, et la cible passe sous 80 cm.
  • Le repli 505 (haut 100, arrière 60) touche encore la plaque. Si la face est à environ 35 cm derrière la tête, la sphère de 20 cm la touche à environ 15 cm en arrière et 25 cm en haut. Avec la normale × 20 vers le joueur, on obtient environ 25 cm de la tête, hauteur +25 : la signature « 26 cm, +26 » est retrouvée.
  • Assis, la tête est plus basse, mais le calcul part de la douille head du maillage (455, et pareil pour le témoin). Les pistes « point de tête lu sur la capsule », « position assise décalée » et « tangage de C2 » sont donc écartées. Le tangage n'existe pas : MakeRotator(0, 0, lacet).
  • Le témoin dit « rien » parce qu'il sonde à plat vers la caméra. Ici, elle est presque à la verticale de la tête et un peu en avant, à cause de la normale × 20 : la sonde part à l'opposé de la plaque.
  • Contrôle à faire au journal définitif de la session 2 : X du joueur à 18:54 entre environ -3131560 et -3131420 (plaque à ±70 cm, selon la direction du regard). Si X sort nettement de cette bande, l'hypothèse tombe et le cas reste ouvert.

Le correctif (a) couvre les trois cas. Les 3 sondes (459, 499, 505) partagent MakeArray_5. Avec GI.Wall ignoré, ni la sonde principale ni le repli ne voient plus la plaque. Rien d'autre que la plaque ne bloque Visibility dans la pièce : les personnages l'ignorent, et Room est ignoré par bIgnoreSelf.

  • Variante plus robuste, au choix de Big Boss : ignorer tout acteur caché dans les sondes. Il faudrait un filtre sur HitActor.bHidden et un nouveau balayage, ce qui fait bien plus de nœuds. Non retenue : Wall est le seul cas relevé.

Conséquence hors CAM (renforce le § 5) : une paroi invisible et BlockAll coupe chaque pièce en deux, à 53 cm du centre. Pour la marche, le joueur ne la sent pas (WorldStatic ignoré). En revanche, tout tracé Visibility, comme les clics, ou WorldStatic, comme la sonde de ShowCouple qui l'ignore déjà, peut buter dessus. Il faudrait la passer en NoCollision, puisqu'elle ne sert que de fond aux SceneCapture, mais c'est une décision hors CAM : acteur du niveau, lot de décor ou STG.

9. Finalisation sur les journaux définitifs (bilan etat\BOSS\COMMUN-3-BILAN.md)

Journaux lus :

  • session 1 : LifePlay_commun3_session1_definitif_BOSS.log (27e654cc…, 275 relevés Room loc) ;
  • session 2 : LifePlay_commun3_session2_ferme_BOSS.log (61e37cf3…, 164 relevés Room loc). Dans les deux sessions, Room est toujours en (-3131543, -14967213, -115).

D8 cas 1 et 2 : prouvés, cause GI.Wall

Voir le § 8. La plaque est fixe : aucun Blueprint relevé ne la déplace. GI, PC, Room et StreetMap ne font que la cacher, changer sa visibilité ou son matériau (dumps lus). Les cas « dedans » relevés loin de la plaque ont une position vieille de 1 à 4 s, joueur en marche ou changement de pièce (18:56:54-59 en session 2) : ils ne s'y opposent pas.

D8 cas 3 (session 2, 18:53:20 à 18:54:38 UTC, assis) : mécanisme prouvé par élimination, objet probable

  • Le joueur (Bridget) est immobile pendant 80 s, en X = -3131579,5, Y = -14967396 (fnt_chair06-f-0-sit, _48). La caméra reste stable, à 26-27 cm de la tête et hauteur +26 (14 lignes).
  • Une sonde a forcément touché. Sans impact, la cible est à au moins 125 cm (C2Dist borné) et la caméra la rejoint en environ 0,3 s. C2Scripted n'est jamais mis à vrai (B4 non fait, seule écriture = faux). La boîte a une marge de 135 cm. Le repli sans impact place la cible à environ 117 cm. Seul un impact suivi du repli donne « 26 cm, +26 ».
  • Ce qui peut bloquer Visibility à moins de 80 cm :
    • Room : ignoré par bIgnoreSelf ;
    • le joueur et CamRoom : ignorés ;
    • les personnages : capsule et maillage ignorent Visibility, et le plus proche, Laura, visible, est à 187 cm ; les PNJ cachés sont à 212 cm et plus ;
    • il ne reste que la plaque Wall, à 84 cm du centre de la capsule, dans l'axe X.
  • Point non mesuré : la tête du personnage assis est-elle décalée d'environ 50 cm vers la plaque par rapport à la capsule ? C'est la condition géométrique pour obtenir 26 cm, +26. Le journal ne donne pas la position de la tête.
  • Le témoin dit « rien », car il sonde vers la caméra, presque à la verticale, et pas dans l'axe de la sonde 459.
  • Statut : probable. Le correctif (a) le couvre si l'objet est bien Wall. Le témoin complété (§ 10, C) le tranchera à COMMUN-4 : position de la tête, décalage par rapport à la capsule, distance de la cible et sonde dans l'axe de 459.

C1, souris : voir le § 7 (prouvé). Correctif en deux parties, Room (CAM) et Walk (STG).

10. Correctifs exacts pour COMMUN-4 (aucune écriture avant GO)

Id Fichier MD5 attendu avant écriture Écrit par Jeton
A. B2g (D8) Content/BPs/Room.uasset F2B082D2911D9F7C7BE60C2CF30EE6D5 lp-mcp-bp UE
B. B2h (C1, partie Room) Content/BPs/Room.uasset (même ouverture que A) idem, puis MD5 après A et B lp-mcp-bp UE
C. témoin C2 complété Source/LifePlay/LPCameraModeSubsystem.cpp 1DE73AA932AF2A056E1B8528CED4DCAB (.h 84F9BA30… inchangé) session CAM aucun (compilé au build)
D. C1, partie Walk Source/LifePlay/LPDirectControlSubsystem.cpp (STG) 827F19C0B7A78BDF578ACF4AE6C2289D (relevé du 2026-10-13, état STG non commité) STG aucun (compilé au build)
GI (E64B5B37…) et Person (8668A47C…) ne sont pas touchés.

A. B2g : GI.Wall ignoré par les 3 sondes de C2. Instantané .\Tools\Snapshot.ps1 -Lot CAM-B2g -Path Content\BPs\Room.uasset. Préfixe /Game/BPs/Room.Room:EventGraph., un appel MCP par message :

  1. get_node_infos K2Node_MakeArray_5 : entrées [0] ← VariableGet_261.PlayerCharacter, [1] ← VariableGet_268.CamRoom ; sortie Array → 459, 499, 505 .ActorsToIgnore. Et K2Node_VariableGet_260 : Wall, self ← VariableGet_257.GI, sortie → 88 et 438 .self.
  2. add_node_pin K2Node_MakeArray_5 → nouvelle entrée [2] (relever son PinID).
  3. connect_pins 260.Wall (sortie) → MakeArray_5.[2].
  4. Relecture des 3 entrées et des 3 sorties de MakeArray_5, puis de 88 et 438 (liens de 260 conservés). B ne crée ni ne supprime de nœud. Si elle vient seule, faire la séquence create_node / delete_node d'une Branche isolée avant l'enregistrement (amendement B2f-a), si is_dirty est faux.

B. B2h : en C1, la souris et les flèches gauche/droite tournent la rotation de contrôle (§ 7, partie 1). 5. create_node du OU booléen. Même type que K2Node_CommutativeAssociativeBinaryOperator_19 (BooleanOR) : prendre le type_id par find_node_types (filtre « OR »). 2 entrées A et B. 6. connect_pins PromotableOperator_8.ReturnValue → OR.A ; VariableGet_269.CamC1On → OR.B. 7. connect_pins OR.ReturnValue → IfThenElse_96.Condition, puis → IfThenElse_97.Condition. connect_pins remplace le lien d'entrée existant (PO_8) sur ces deux seules conditions. 8. Relecture :

  • PO_8 reste relié à 91, 98, 99, 100 et OR.A, et ne l'est plus à 96 ni 97 (amendement E1 : 100 = DownUp, hauteur de C2, omis dans la première liste ; écritures inchangées) ;
  • 269 garde ses liens (77, 82, 84) et ajoute OR.B ;
  • 96.then → 516 et 97.then → 518 sont inchangés.
  1. Pour A et B : is_dirty = vrai, compilation stricte, save_assets de Room seul, MD5 différent de F2B082D2. VAL : V5, avec seulement ces différences (MakeArray_5 [2], 1 nœud OR, conditions de 96 et 97), Room = 1261 nœuds ; V6 = référence. Barème A + B : a0 b1 c0 d0 e1 f1 = 3 → N1, ajusté à N3 (MCP) ; S = C3 1 + f 1 = 2 < 3 : une fiche.

C. Témoin C2 complété (LPCameraModeSubsystem.cpp, code exact) :

// LPCameraModeLocal
const FName GIWall(TEXT("Wall"));
const FName RoomC2Target(TEXT("C2Target"));

// WitnessC2, apres Query.AddIgnoredActor(Cam) : meme liste que MakeArray_5 apres B2g
if (AActor* Wall = Cast<AActor>(LPCameraModeLocal::ReadObject(GI, LPCameraModeLocal::GIWall)))
{
	Query.AddIgnoredActor(Wall);
}
// Probe prend la direction en parametre : auto Probe = [&](ECollisionChannel Channel, const FVector& Direction) -> FString
const FString CameraText = Probe(ECC_Camera, Dir);
const FString VisibilityText = Probe(ECC_Visibility, Dir);
// Axe de la sonde 459 : a plat, derriere la rotation de controle du PC.
const APlayerController* PC = World->GetFirstPlayerController();
const FVector Back = PC ? -FRotationMatrix(FRotator(0.f, PC->GetControlRotation().Yaw, 0.f)).GetUnitAxis(EAxis::X) : -Player->GetActorForwardVector();
const FString BackText = Probe(ECC_Visibility, Back);
FVector Target;
const FString TargetText = LPCameraModeLocal::ReadVector(Room, LPCameraModeLocal::RoomC2Target, Target) ? FString::Printf(TEXT("%.0f cm"), FVector::Dist(Head, Target)) : FString(TEXT("illisible"));
const FVector Offset = Head - Player->GetActorLocation();
UE_LOG(LogLifePlay, Log, TEXT("Temoin C2 : camera a %.0f cm de la tete (hauteur %+.0f) ; cible C2 a %s ; tete (%.0f, %.0f), decalage capsule %.0f cm ; vers la camera, Camera : %s, Visibility : %s ; vers l'arriere, Visibility : %s ; boite C2 : %s"),
	Distance, CamLoc.Z - Head.Z, *TargetText, Head.X, Head.Y, Offset.Size2D(), *CameraText, *VisibilityText, *BackText, *BoxText);

Sauvegarde Backup_5.5\CAM-B2g\Source\LifePlay\ avant modification. Barème : N1 ; S = 0.

D. Walk, partie STG : le code exact est au § 7. Le bloc à remplacer est maintenant aux l. 935-939 de la version 827F19C0 : if (!Move->bOrientRotationToMovement) { … }. La lecture de GI et PC se trouve en tête de Walk (l. 908 et suivantes). D n'a de sens qu'avec B : il faut les mettre dans le même build.

Cas de test pour COMMUN-4 :

  • D8 : rejouer la chambre et le joueur assis. Aucune ligne Temoin C2 sous 100 cm hors des rues étroites. Si une ligne reste, elle donne la cible, la tête et la sonde vers l'arrière.
  • C1 : la souris et les flèches gauche/droite tournent la vue ; Z avance là où l'on regarde ; C2 est inchangé.