38 KiB
Fiche STE-GEL1-S — Niveau N3 — Modèle prévu (modèle de l'agent lp-cart) | utilisé claude-sonnet-5-5 — Agent lp-cart — Skills sk-protocol, ue-cpp-build, lp-commandlets, lp-paths (préchargés), lp-mcp (lu : § 1-4), lp-doc (gabarits)
STE-GEL1-SPEC : garde C2 dans TopRight, pas de tri par distance au-delà de 2 000 résultats (2026-10-14)
Lecture seule stricte (Read, Grep, Glob ; quelques Bash en lecture : git, md5sum, grep -a sur binaires, ls). Aucun éditeur, MCP, commandlet, build ni jeu.
Copie D:\Game\LifePlay-master 5.8, branche ue5.8, HEAD 0745917. Gabarit SPEC : D:\Game\LifePlay-Sandbox\Tools\claude\skills\lp-doc\gabarits.md:36-38 (sections 1 à 7 ci-dessous).
Correspondance avec la rubrique 7 de la fiche : objectif = § 1 ; corps de SortByDistance = § 1.1 ; fichiers et ordre = § 2 ; préalables = § 2.0 ; garde au geste près = § 2.2 ; comportement = § 2.3 ; repli = § 3 ; risques et Q# = § 4 ; interdits = § 5 ; critères V5 / V6 = § 7.
Statut : complet et exécutable (les deux dumps D1 sont lus ; aucune donnée manquante pour la variante principale). Trois points à lire avant l'IMPL :
- Le n² est établi sur D1 (structure du graphe, § 1.1) ; le chiffrage en secondes reste estimé (pas de trace Insights).
- Au-delà de 2 000 résultats, les 1 000 widgets affichés sont les 1 000 premiers de
Resultsdans l'ordre d'import des bâtiments, pas les 1 000 plus proches (§ 1.4, § 2.3). SortByDistanceexiste en deux exemplaires : celui deTopRight(cible) et un homonyme défini dansContent\BPs\StreetMap_Static.uasset(§ 1.2) ; hors C2.
Abréviations (chemins absolus) :
- D =
D:\Game\LifePlay-master 5.8\Docs\Migration\etat\ST\STE\dumps\; SBD = DTopRight__SortByDistance_D1.txt(29 nœuds ; listing 1 = l. 1-129, listing 2 d'exécution = l. 130-179) ; EG = DTopRight__EventGraph_D1.txt(907 nœuds ; listing 1 = l. 1-4188, second listing dès l. 4189, non lu). - DIAG =
STE-GEL1-DIAG.md, D1R =STE-GEL1-D1.md(dansetat\ST\STE\) ; UE =D:\Game\Launcher\Engine\UE_5.8\Engine\Source\(moteur installé, lu) ; LD =Source\LifePlay\LPDebugSubsystem.cpp(arbre de travail,Mà l'état initial) ; SM =Plugins\StreetMap\Source\StreetMapRuntime\StreetMap.cpp. - J5 =
D:\Game\LifePlay_Backup_5.5\COMMUN-5\essais\LifePlay_commun5_session1_BOSS.log.
État relevé (Bash, lecture) : git rev-parse --short HEAD → 0745917 ; md5sum Content/UI/TopRight.uasset → 1fcb94a60061b418e9deeb08bc1a990d (= 1FCB94A6… des dumps, D1R:28 et 43) ; git status --short -- Content/UI/TopRight.uasset Plugins/StreetMap → aucune ligne (non modifiés) ; git log --oneline -1 -- Content/UI/TopRight.uasset → f32df0d (STE-H10).
Les numéros de ligne du DIAG (« dump D9 périmé ») sont refaits sur D1 : PrintString l. 2832 (D9 : 2834), appel SortByDistance l. 2613 (2615), boucle de widgets l. 772-792 (774-791).
1. Objectif mesurable
Insérer dans TopRight:EventGraph une Branche entre le PrintString « at least 2 result » et l'appel de SortByDistance : si Array_Length(Results) <= 2000, l'exécution suit le chemin actuel (tri puis boucle de widgets) ; sinon elle saute le tri et va directement à la boucle de widgets (MacroInstance_1, ForEachLoopWithBreak), Results restant tel que rendu par la recherche. Décision de l'utilisateur du 2026-10-14 (DIAG, « Décision de l'utilisateur »). La recherche vide sur « All » reste permise.
Attendus mesurables (§ 7) : TopRight:EventGraph 907 → 909 nœuds (2 créés), 1 coupure, 5 liens, 1 set_pin_value ; SortByDistance inchangé (29 nœuds, mêmes liens) ; LPTestStringCompat 3120 / 0 / 60 ; en jeu (V6), la recherche vide sur « All » à CentralLondon ne produit plus de LPDebug hitch de plusieurs dizaines de secondes (avant : 34 229,3 ms, J5:1830-1831 relu) mais moins de 2 000 ms, et une recherche ciblée reste triée par distance.
1.1 Corps de SortByDistance (SBD, 29 nœuds) : algorithme, coût, n² confirmé
Entrées / sorties : FunctionEntry_1551 → Buildings (tableau de StreetMapBuilding) et Player Position (Vector2D) (SBD:2-5) ; FunctionResult_0 → SortedBuildings (SBD:100-102). Variables locales : FirstPoints, DistanceFloats, IndicesOrdered, BuildingsSorted (SBD:26-27, 33-34, 42-43, 55-56, 62-63, 83-86, 98-99).
| Phase | Nœuds (SBD) | Ce qu'elle fait | Coût |
|---|---|---|---|
| A | MacroInstance_23 ForEachLoop sur Buildings (6-12) ; BreakStruct_24 (13-18) ; CallFunction_5637 GI_C::FindCenterOfPolygon(BuildingPoints) (106-112) ; CallArrayFunction_46 Array_Add(FirstPoints, Center) (19-25) |
un centre par bâtiment | n tours, linéaire. Ordre de grandeur : 49 425 appels de FindCenterOfPolygon = 0,742 s inclus (Docs\18_Build_Debug.md:234, relu ; contexte City, transposé ici : estimé) |
| B | MacroInstance_31 ForEachLoop sur FirstPoints (35-41) ; CallFunction_695 Subtract_Vector2DVector2D(centre, Player Position) (28-32) ; CallFunction_1025 VSize2D (44-47) ; CallArrayFunction_89 Array_Add(DistanceFloats) (48-54) |
une distance par bâtiment | n tours, linéaire |
| C | MacroInstance_51 WhileLoop (57-61), Condition ← CallFunction_6094 Less_DoubleDouble(MinValue, constante ≈ 10⁶³) (123-127) ; corps : CallArrayFunction_121 Array_Add(IndicesOrdered, IndexOfMinValue) (64-70) puis CallArrayFunction_308 Array_Set(DistanceFloats, IndexOfMinValue, constante ≈ 10⁶³, bSizeToFit=false) (115-122) ; CallFunction_1460 MinOfFloatArray(DistanceFloats) (71-75) |
tri par sélection : à chaque tour, minimum du tableau entier, indice ajouté à IndicesOrdered, entrée neutralisée |
n tours × ≥ 1 passe sur n valeurs = Θ(n²) |
| D | MacroInstance_70 ForEachLoop sur IndicesOrdered (76-82) ; GetArrayItem_119(Buildings, indice) (94-97) ; CallArrayFunction_151 Array_Add(BuildingsSorted) (87-93) ; FunctionResult_0 |
recopie des bâtiments dans l'ordre | n tours, linéaire (copie de structure avec tableau de points) |
Verdict n² : établi (structure) :
- La phase C neutralise exactement une entrée par tour (
Array_Setà l'indice du minimum, SBD:115-122) et s'arrête quand le minimum atteint la constante (SBD:123-127) : n tours pour n bâtiments. - Chaque tour lit tout
DistanceFloats(VariableGet_120→CallFunction_1460.FloatArray, SBD:42-43, 73) :MinOfFloatArrayappelleFMath::Min(FloatArray, &IndexOfMinValue)(UE\Runtime\Engine\Private\KismetMathLibrary.cpp:406-409), bouclefor v = 1 … Num-1(UE\Runtime\Core\Public\GenericPlatform\GenericPlatformMath.h:1026-1054, boucle l. 1039-1047). Soit n × n lectures : 49 425² ≈ 2,44 × 10⁹. - Estimé (mécanisme moteur lu, durée non mesurée) : (i)
MinOfFloatArrayprendconst TArray<float>&(KismetMathLibrary.h:764) alors que le tableau Blueprint est en double : le compilateur insère une conversion de conteneur double → float (UE\Editor\KismetCompiler\Private\KismetCastingUtils.cpp:240-244,FloatingPointCastType::Container), donc une recopie des n valeurs à chaque appel ; (ii)CallFunction_1460est un nœud pur à trois consommateurs (CallFunction_6094.A←MinValue,CallArrayFunction_121.NewItemetCallArrayFunction_308.Index←IndexOfMinValue, SBD:74-75) : le compilateur Kismet incorpore le code d'un nœud pur à chaque nœud qui en consomme la sortie (UE\Editor\KismetCompiler\Private\KismetCompiler.cpp:2881-2897), soit 2 à 3 évaluations complètes par tour (la part de laConditionde la macro WhileLoop n'est pas lue). Cohérent avec 34,2 s / 2,44 × 10⁹ ≈ 14 ns par élément et par tour. D3 (Insights) non fait. - Extrapolation quadratique (estimée, linéaire négligé) du tri conservé à la borne : n = 2 000 → (2 000 / 49 425)² × 34,2 s ≈ 0,056 s.
- Tableau vide (hors C2, estimé) :
FMath::Mind'un tableau vide rendINDEX_NONEetT()(GenericPlatformMath.h:1028-1035), doncMinValue= 0 < constante : laWhileLoopne se termine pas avantMaximumLoopIterationCount=100000000(Config\DefaultEngine.ini:51). La recherche TopRight est protégée parArray_Length > 1(EG:2848-2861) ; les autres appelants (§ 1.2) ne sont pas lus.
1.2 Autres appelants de SortByDistance (hors C2, à lister)
| Où | Preuve | Statut |
|---|---|---|
TopRight:EventGraph, CallFunction_132 |
EG:2613-2619 ; Grep SortByDistance sur EG (listing 1) → 1 seule ligne (2613) |
appel visé par C2 |
Person (4 appels TopRight_C::SortByDistance) |
dump 5.5 Docs\Migration\etat\portage55\L6f\L6f_dump_Person.txt l. 9842, 9979, 10167, 10519 (self ← TopRight, Buildings ← résultat de recherche) ; SortedBuildings (vide) aux l. 9848, 9985, 10173, 10525 (sortie non reliée dans ce dump ancien : estimé « résultat jeté », à relire) ; Content\BPs\Person.uasset : grep -a -o → 1 occurrence du nom (5.8) |
nombre d'appels en 5.8 non établi (dump 5.5 antérieur à ee2821a, STE-H8-DIAG.md:144-145) ; Q2 du DIAG non tranchée ; tableaux petits (O9 : 3 appels, 7,6 ms, DIAG § 5.2) |
StreetMap_Static |
Content\BPs\StreetMap_Static.uasset : grep -a -o -E → 12 × SortByDistance, 1 × SortByDistance.K2Node_FunctionEntry_9, 1 × SortByDistance.K2Node_FunctionResult_0 |
fonction homonyme définie dans ce Blueprint (entrée et résultat de fonction), non un appel ; contenu non dumpé ; ses appelants sont inconnus. Hors chemin de la recherche |
Autres graphes de TopRight |
le nom figure 16 fois dans la table de noms de TopRight.uasset (`grep -a -o -F … |
wc -l` → 16, = DIAG § 3.3) : ne dit pas combien d'appels |
| Reste du projet | grep -rlaF "SortByDistance" sur Content\BPs, Content\UI → Person, StreetMap_Static, TopRight seuls ; sur Content\Scenes, Structs, Developers, Collections, Render, Characters → aucun fichier ; Grep Content\Modules → 0 ; Grep Source → 0 ; Grep Plugins (*.cpp,h,ini,py,json,md) → 0 |
Content\Maps n'existe pas (message grep) ; non scannés : Heavy, AnimPacks, FreeAnimationsPack, Movies, Quaternius, Retarget_ue5, Saves, __External*__ (assets non Blueprint) |
1.3 Chemin de la recherche dans l'EventGraph (EG, listing 1)
| Nœud | Rôle | Liens (EG) |
|---|---|---|
CustomEvent_17 TextCommit |
entrée | then → CallArrayFunction_10 (Array_Clear Results) (839-842, 2584-2588) → … CallFunction_1570 (SearchResultBox.ClearChildren, 829-832) → MacroInstance_0 (IsValid de CurrentCityExpansion, 2573-2577) |
VariableSet_7 / CallFunction_134 |
si l'extension est valide : Results = SearchByBuildingNameFromArray(...) |
2601-2612 |
CallArrayFunction_17 Array_Append |
Results += SearchByBuildingName(Term, AmenityFilter) (CallFunction_804, 767-771) |
then → IfThenElse_6.execute (2592-2597) |
IfThenElse_6 |
Array_Length(Results) > 1 : CallArrayFunction_11 (2848-2851) → CallFunction_139 Greater_IntInt(B=1) (2852-2856) |
then → CallFunction_10470 ; else → MacroInstance_1.Exec (2857-2861) |
CallFunction_10470 DetermineBirdviewLooking |
impur ; sort Vector2d |
execute ← IfThenElse_6.then ; then → CallFunction_7736.execute ; Vector2d → CallFunction_7735.InVec et CallFunction_132.Player Position (2843-2847) |
CallFunction_7736 PrintString |
texte « … at least 2 result » (EG:3366) | then → CallFunction_132.execute (2832-2842, lien à couper) |
CallFunction_132 SortByDistance |
cible | then → VariableSet_26.execute ; Buildings ← VariableGet_546.Results ; Player Position ← CallFunction_10470.Vector2d ; SortedBuildings → VariableSet_26.Results (2613-2619) |
VariableSet_26 |
Results = SortedBuildings |
then → MacroInstance_1.Exec (2620-2625) |
MacroInstance_1 ForEachLoopWithBreak |
Exec ← VariableSet_26.then, IfThenElse_6.else ; Array ← VariableGet_547.Results ; Array Index → CallFunction_1338.A ; Break ← Knot_0 |
772-779 |
CallFunction_1338 / IfThenElse_76 / Knot_0 |
Less_IntInt(Array Index, 1000) ; then → CreateWidget_0 ; else → Knot_0 → Break |
780-792 : au plus 1 000 widgets (indices 0 à 999) |
VariableGet_546 Results |
3 consommateurs : Array_Append_17.TargetArray, CallFunction_132.Buildings, CallArrayFunction_11.TargetArray |
2589-2591 |
Results n'est lu ou écrit que par 5 nœuds (VariableGet_11, _546, _547, VariableSet_7, _26 : Grep variable 'Results' sur EG → l. 2581, 2589, 2598, 2607, 2620) : aucun autre consommateur ne dépend de l'ordre trié que la boucle d'affichage.
1.4 Quels 1 000 résultats s'affichent au-delà de 2 000 (point amont)
- Ordre de
Results: d'abord les résultats deCurrentCityExpansion.Buildingssi l'extension est valide (VariableSet_7, EG:2601-2612), puis ceux deStreetMap.SearchByBuildingNameajoutés à la suite (Array_Append_17, EG:2592-2597). Établi par le flux. - Terme vide :
Results = Buildings(copie dans l'ordre du tableau,SM:87-90) ; terme non vide : boucle surBuildingsdans l'ordre (SM:77-85) ; filtre d'aménité : parcourt la liste dans l'ordre (SM:133-139). Établi. - Ordre de
Buildings: ajout au fil de l'import, une entrée parWayOSM de type bâtiment (Plugins\StreetMap\Source\StreetMapImporting\StreetMapFactory.cpp:547-560,new (StreetMapRef.Buildings)l. 321) : ordre des ways du fichier OSM (estimé : le remplissage deOSMFile.Waysn'est pas relu). - Donc, sans tri : les 1 000 premiers bâtiments de l'ordre d'import (ceux de l'extension d'abord) sont affichés, sans lien avec la vue ; avec tri, c'étaient les 1 000 plus proches. Un bâtiment sans nom produit un widget sans
SetTextdans les deux cas (IfThenElse_150, EG:858-871) ; la part de bâtiments sans nom parmi les 1 000 premiers n'est pas mesurée.
2. Fichiers touchés, ordre
Un seul fichier : Content\UI\TopRight.uasset, un seul graphe : EventGraph (refPath /Game/UI/TopRight.TopRight:EventGraph, format de STE-H10-SPEC.md:91, 487). Ni SortByDistance, ni Person, ni StreetMap_Static, ni GI, ni le C++, ni le plugin StreetMap. Pas de build pour l'IMPL (le build empaqueté de V6 relève de BUILD).
2.0 Préalables (dans l'ordre, avant tout create_node)
- P0 : UE-GO de Big Boss (DIAG, « Décision de l'utilisateur » : IMPL sous instantané et UE-GO) ; gel annoncé à toutes les sessions (
ListAgents,lp-mcp§ 1.7) ; aucune autre IMPL surTopRighten cours. - P1 (dumps) : D1 présents (SBD, EG). Refaire seulement si le MD5 de
TopRight.uassetà l'entrée diffère de1fcb94a60061b418e9deeb08bc1a990d:.\Tools\RunCommandlet.ps1 -Lot STE-GEL1 -Commandlet LPDumpFunction -Args '-BP=TopRight -Fn=EventGraph -Pins -Exec' -EtatDir "D:\Game\LifePlay-master 5.8\Docs\Migration\etat\ST\STE"(forme de D1R:11-13), éditeur fermé (.\Tools\UeState.ps1 -Kind Editeur= 0). - P2 : MD5 de
TopRight.uassetrelevé juste avant l'IMPL (attendu1fcb94a6…) = valeur de repli. - P3 :
.\Tools\Snapshot.ps1 -Lot STE-GEL1 -Path Content\UI\TopRight.uasset(paramètres-Lot,-Path:Tools\Snapshot.ps1:17-19) ; manifesteD:\Game\LifePlay_Backup_5.5\STE-GEL1\manifest.csv; éditeur headless (lp-mcp§ 2) ;AssetTools.load_asset/Game/UI/TopRight(rend/Game/UI/TopRight.TopRight). - P4 :
get_node_infos {nodes:[{refPath:"/Game/UI/TopRight.TopRight:EventGraph.K2Node_<Nom>"}]}(dix nœuds au plus par appel) pour :CallFunction_7736,CallFunction_132,VariableSet_26,MacroInstance_1,IfThenElse_6,CallFunction_10470,CallArrayFunction_11,CallFunction_139,VariableGet_546. Liens = colonne « Avant » du § 2.2. Relever les indices (attendus, non relus :7736.thensortie 0 ;132.executeentrée 0 ;MacroInstance_1.Execentrée 0 ;CallArrayFunction_11.ReturnValuesortie 0 ;VariableGet_546.Resultssortie 0). Contrôler que7736.thenn'a qu'un lien (→132.execute), que132.executen'a qu'une source, queMacroInstance_1.Execen a deux. Tout écart : arrêt et rapport.- P4b (graphes non dumpés) :
find_nodes {graph:{refPath:"/Game/UI/TopRight.TopRight:<Graphe>"}, title:"SortByDistance"}sur les autres graphes deTopRight(liste :LPDumpFunction -BP=TopRightsans-Fn, D9 deSTE-H8-DIAG.md:500) ; résultat noté, sans effet sur la garde.
- P4b (graphes non dumpés) :
- P5 : avant chaque
create_node,find_node_types {graph:{refPath:"/Game/UI/TopRight.TopRight:EventGraph"}, type_id_filter:<filtre>, context_pins:[]}; letype_idattendu doit figurer dans la réponse :- Branche : filtre
Branche→Utilitaires|ContrôleDeFlux|Branche(relu en 5.8 :STE-H3d-IMPL.md:69,STG-B7a-IMPL.md:28). - Comparateur
<=entier : filtregal, aveccontext_pins= la brocheCallArrayFunction_11.ReturnValue; réponse relue enSTG-B7a-IMPL.md:24:Utilitaires|Opérateurs|Égalà(==),…Inférieurouégalà(<=),…Supérieuràouégalà(>=)(préfixeUtilitaires|Opérateurs|relu en clair surInférieurà(<)etÉgalà(==),STG-B7a-IMPL.md:25, 32) ; second essai : filtreOpérateurs|. Type attendu :Utilitaires|Opérateurs|Inférieurouégalà(<=)(suffixe relu seulement dans la liste abrégée : il doit être lu en clair ici). Absent : repli (b), § 3. Le filtreLessne rend aucun comparateur (STG-B7a-IMPL.md:21). - Pas de nouvel
Array_Length:CallArrayFunction_11est réutilisé (si jamais nécessaire :Utilitaires|Tableau|Length,STE-H10-IMPL.md:49). - Après création :
get_node_infosdu nouveau nœud (indices relevés).
- Branche : filtre
- P6 : la valeur de seuil (2 000) et l'absence de message à l'utilisateur sont celles de la décision du 2026-10-14 (Q-GEL1-1 facultative).
2.1 Conventions (reprises de STE-H3g-SPEC.md § 2.1, lp-mcp § 3-4)
- Cascade de Branche, jamais AND / OR / Select purs ; une sortie de données peut alimenter plusieurs entrées (les liens existants restent).
delete_nodeinterdit. AucunFunctionResultcréé. - Un opérateur promotable (
Utilitaires|Opérateurs|…) se type par sa première liaison : relier avantset_pin_value(STG-B1-IMPL.md:193,STG-B7a-IMPL.md:44). Un seulset_pin_valueici (le seuil), contrairement àSTE-H3g-SPEC.md:93. - Après la garde :
compile_blueprint {blueprint:{refPath:"/Game/UI/TopRight.TopRight"}, warnings_as_errors:true}→null, journal de l'éditeur lu (aucune ligne Error / Warning liée à TopRight) ; puissave_assets {asset_paths:["/Game/UI/TopRight"]}; fermeture de l'éditeur,UeState.ps1= 0, MD5 relevé (hyper_blueprint_debug_inspectabsent du serveur,STE-H3d-IMPL.md:156). - Positions (
pos) libres, à côté deCallFunction_7736, sans chevauchement.
2.2 La garde au geste près (variante principale (a))
Emplacement : dans l'EventGraph, avant l'appel CallFunction_132, sur le lien CallFunction_7736.then → CallFunction_132.execute (EG:2834). Choix argumenté :
| Dans l'EventGraph (retenu) | En tête de SortByDistance |
|
|---|---|---|
| Nœuds | 2 | ≥ 3 et une sortie SortedBuildings à fournir sans tri : second nœud de retour ou variable locale (convention : aucun FunctionResult créé) |
| Appelants touchés | la seule recherche TopRight (cible de C2) | aussi les 4 appels Person (Q2 non tranchée), l'ordre de leurs listes pourrait changer |
| Réversibilité | un lien rétabli | fonction partagée à modifier |
Nœuds créés (noms de la SPEC ; noms réels K2Node_* à noter dans l'IMPL) :
GEL-B: BrancheUtilitaires|ContrôleDeFlux|Branche(entréesexecute0,Condition1 ; sortiesthen0,else1 ;STE-H3d-IMPL.md:69).GEL-OP: opérateur<=(type_id lu en P5) ; broches attenduesA(entrée 0),B(entrée 1),ReturnValue(sortie 0), à relever avant câblage.
Séquence (un appel à la fois, relecture get_node_infos après chaque groupe) :
create_nodeGEL-B. 2.create_nodeGEL-OP.connect_pinsCallArrayFunction_11.ReturnValue(sortie 0) →GEL-OP.A: l'opérateur prend le type entier ; relireget_node_infos:AetBde type entier. Sinon arrêt (repli (b), § 3).set_pin_valueGEL-OP.B=2000; relire2000.connect_pinsGEL-OP.ReturnValue→GEL-B.Condition(1).break_pinsCallFunction_7736.then/CallFunction_132.execute.connect_pinsCallFunction_7736.then→GEL-B.execute(0).connect_pinsGEL-B.then(0) →CallFunction_132.execute.connect_pinsGEL-B.else(1) →MacroInstance_1.Exec. Volume : 2 nœuds créés, 1break_pins, 5connect_pins(3, 5, 7, 8, 9), 1set_pin_value;EventGraph907 → 909 nœuds ; 1 lien perdu, 5 gagnés (net +4).
| Broche | Avant | Après |
|---|---|---|
CallFunction_7736.then |
→ CallFunction_132.execute |
→ GEL-B.execute (seul) |
CallFunction_132.execute |
← CallFunction_7736.then |
← GEL-B.then (seul) |
MacroInstance_1.Exec |
← VariableSet_26.then, IfThenElse_6.else |
← VariableSet_26.then, IfThenElse_6.else, GEL-B.else (3 sources) |
CallArrayFunction_11.ReturnValue |
→ CallFunction_139.A |
→ CallFunction_139.A, GEL-OP.A |
GEL-B.Condition / GEL-OP.B |
n'existent pas | ← GEL-OP.ReturnValue / 2000 |
Inchangés à la relecture : CallFunction_132.Buildings ← VariableGet_546.Results, .Player Position ← CallFunction_10470.Vector2d, .then → VariableSet_26.execute ; VariableSet_26.then → MacroInstance_1.Exec ; IfThenElse_6 (then → CallFunction_10470, else → MacroInstance_1.Exec) ; CallFunction_139.B = 1 ; MacroInstance_1.Array ← VariableGet_547.Results ; CallFunction_1338.B = 1000 ; le PrintString et DetermineBirdviewLooking s'exécutent toujours (le marqueur « at least 2 result » du journal reste).
2.3 Comportement avant / après
| Cas | n = Array_Length(Results) |
Avant | Après | Changé |
|---|---|---|---|---|
| 1 | 0 ou 1 | IfThenElse_6.else → boucle (pas d'impression, pas de tri) |
idem | non |
| 2 | 2 à 2 000 | impression, tri complet, boucle ≤ 1 000 widgets | idem, plus une Branche vers then |
non (mêmes nœuds, mêmes entrées : identique par construction) |
| 3 | 2 001 et plus | impression, tri Θ(n²), 1 000 plus proches affichés | impression, pas de tri, 1 000 premiers de Results (§ 1.4) |
oui |
- Nombre affiché :
min(n, 1 000)dans les trois cas (CallFunction_1338.B= 1000, EG:780-784), inchangé. - Qui dépasse 2 000 : la recherche vide sur « All » à
CentralLondon(49 425 bâtiments,Docs\Journal_Modifications.md:820, relu ; 49 425 appels deFindCenterOfPolygon,18_Build_Debug.md:234). Les 279 autres villes totalisent 53 050 − 49 425 = 3 625 bâtiments (U8_LPCheckStreetMap_20261011-003558.txt:52, déduction : estimé), donc au plus une autre ville peut dépasser 2 000. Un filtre d'aménité garde au plus 5 191 bâtiments à Londres (Journal l. 820) et 6 635 au total (U8 txt:53) : un type très fréquent pourrait dépasser 2 000 (répartition par type non mesurée). Une recherche par terme court : non mesurée. - Coût résiduel pour n ≥ 2 001 : copies natives de
SearchByBuildingNameetArray_Append(n structures avec tableau de points), 1 000CreateWidget/AddChild: non mesuré, attendu bien inférieur au gel (V6 : seuil 2 000 ms). - Aucun message ni indicateur n'est ajouté pour dire que la liste n'est pas triée (non demandé : Q-GEL1-1).
3. Repli
- Avant écriture : instantané (P3), MD5 de départ (P2).
- Aucun
save_assetstant quecompile_blueprintn'est pas à 0 diagnostic. Échec avant enregistrement : fermer l'éditeur sans enregistrer (le.uassetreste l'instantané), contrôler le MD5, rapporter. Aucun correctif improvisé. - Après enregistrement, lien relu différent,
type_idintrouvable, nœud inattendu : arrêt, rapport ; sur décision de l'orchestrateur, éditeur fermé :.\Tools\Restore.ps1 -Lot STE-GEL1 -Only Content\UI\TopRight.uasset -WhatIf(paramètres-Only,-WhatIf:Tools\Restore.ps1:18, 21), puis sans-WhatIf; MD5 = valeur de P2. UnRestoredéfait toute autre écriture surTopRightfaite depuis l'instantané (IMPL jamais entrelacées). - Après commit (gardien) :
git revertdu commit du ticket STE-GEL1. - Repli de conception (b) — si
Inférieurouégalà(<=)est absent de P5, si l'opérateur ne prend pas le type entier, ou si la compilation signale l'opérateur : remplacerGEL-OPparGEL-IV,Utilitaires|Tableau|IsValidIndex(relu :STE-H3d-IMPL.md:68,STE-H10-IMPL.md:59;TargetArrayentrée 0,IndexToTestentrée 1,ReturnValuesortie 0).GEL-IV.TargetArray←VariableGet_546.Results;IndexToTest=2000(set_pin_value).IsValidIndex(2000)est vrai si et seulement si n ≥ 2 001 (GenericArray_IsValidIndex→FScriptArrayHelper::IsValidIndex,0 ≤ i < Num,UE\Runtime\CoreUObject\Public\UObject\UnrealType.h:4295-4298,KismetArrayLibrary.cpp:583-595). Polarité inversée :GEL-IV.ReturnValue→GEL-B.Condition;GEL-B.then(n > 2 000) →MacroInstance_1.Exec;GEL-B.else→CallFunction_132.execute. Même volume (2 nœuds, 1 coupure, 5 liens, 1set_pin_value), même total 909 ; seulMacroInstance_1.ExecetCallFunction_132.executechangent de source (GEL-B.then/GEL-B.else). - Repli de fond si le hitch subsiste après la garde : C1 (tri natif, DIAG § 4.1), nouvelle SPEC.
4. Risques R#, questions Q#
- R-GEL1-1 : au-delà de 2 000, la liste montre les 1 000 premiers bâtiments de l'import, pas les plus proches (§ 1.4) ; effet voulu par la décision du 2026-10-14, à dire à la VAL.
- R-GEL1-2 : la garde supprime le n², pas le coût linéaire (copies natives, 1 000 widgets) : hitch résiduel non mesuré ; V6 fixe le seuil à 2 000 ms.
- R-GEL1-3 : typage de l'opérateur promotable en entier : relu pour des flottants et des objets (
STG-B7a-IMPL.md:55, 58), pas pour des entiers ; suffixe<=relu en liste abrégée seulement. Repli (b). - R-GEL1-4 : le temps de 34 s est attribué au n² par la structure du graphe (établi) et par le moteur (estimé), sans Insights (D3 non fait) ; si V6-a échoue, le coût est ailleurs (copies, widgets) : ne pas rouvrir
SortByDistance, repartir d'un DIAG. - R-GEL1-5 : appelants non couverts (§ 1.2) :
Person(4 appels en 5.5),StreetMap_Static(fonction homonyme), autres graphes deTopRight;SortByDistancesur tableau vide ne se termine pas (estimé) : hors C2. - R-GEL1-6 :
TopRightetStreetMapnon modifiés (MD5,git status), maisGI,Person,RoomsontMdans l'arbre : ne pas les mettre au ticket. - R-GEL1-7 :
LPDebugSubsystem.cppestM: les lignes citées (§ 6, § 7) sont celles de l'arbre de travail, pas du HEAD (le DIAG citait 664-688) ; le build de V6 doit être compilé depuis cet arbre. - Q-GEL1-1 (utilisateur, facultative) : afficher un signe quand la liste n'est pas triée (texte « résultats non triés ») ? Non spécifié : la décision ne le demande pas.
- Q-GEL1-2 (orchestrateur) :
Person.recommend*(Q2 du DIAG) et le doublonStreetMap_Static.SortByDistance: hors C2, non tranchés ; un dump-BP=StreetMap_Static -Fn=SortByDistanceet unfind_nodessurPersonles établiraient. - Q-GEL1-3 (orchestrateur) : variante (a) (
<=, conforme à la fiche) avec (b) en repli sans nouvelle SPEC, ou (b) d'emblée (type_id 100 % relu, polarité inversée). Recommandation : (a) puis (b). - Q-GEL1-4 (orchestrateur) : build de V6 : le prochain build COMMUN, lancé avec
-ScriptStackOnWarnings -LPHitchLog(sans-LPHitchLog, aucune ligne de hitch : § 7).
5. Interdits
- Aucune modification de
SortByDistance, deIfThenElse_6, deCallFunction_139(B = 1), deCallFunction_1338(B = 1000), duPrintString, deDetermineBirdviewLooking, des autres graphes deTopRight, deGI,Person,StreetMap_Static, du C++ et du plugin StreetMap. - Aucun
delete_node, aucun AND / OR / Select pur, aucunFunctionResultcréé, aucuntype_idnon relu (P5), aucune écriture HyperAIStudio (outils Epic seulement,lp-mcp§ 1.1), aucune fusion avec une autre IMPL surTopRight. - Pas d'IMPL sans P0 à P5. Pas de commit par l'agent : ticket au gardien (
lp-repo).
6. Valeurs moteur lues dans le moteur installé (UE = D:\Game\Launcher\Engine\UE_5.8\Engine\Source\)
UKismetMathLibrary::MinOfFloatArray(const TArray<float>&, int32&, float&):UE\Runtime\Engine\Classes\Kismet\KismetMathLibrary.h:764; corpsUE\Runtime\Engine\Private\KismetMathLibrary.cpp:406-409(MinValue = FMath::Min(FloatArray, &IndexOfMinValue)).FMath::Min(const TArray<T>&, int32* MinIndex):UE\Runtime\Core\Public\GenericPlatform\GenericPlatformMath.h:1026-1054; tableau vide →INDEX_NONEetT()(1028-1035) ; boucle linéaire (1039-1047).- Conversion de conteneur double → float d'un tableau passé à un paramètre float :
UE\Editor\KismetCompiler\Private\KismetCastingUtils.cpp:240-244. - Nœud pur incorporé à chaque nœud consommateur :
UE\Editor\KismetCompiler\Private\KismetCompiler.cpp:2881-2897. GenericArray_Length(Num()ou 0 si nul) :UE\Runtime\Engine\Private\KismetArrayLibrary.cpp:411-421;GenericArray_IsValidIndex: 583-595 ;FScriptArrayHelper::IsValidIndex=Index >= 0 && Index < Num():UE\Runtime\CoreUObject\Public\UObject\UnrealType.h:4295-4298.- Garde de boucle infinie :
MaximumLoopIterationCount=100000000(Config\DefaultEngine.ini:51). - Journal de hitch (code du jeu, arbre de travail) : option
-LPHitchLoget seuil 50 ms ou-LPHitchMs=(LD:652-654) ; sans l'option, aucune mesure (LD:723-726) ; ligneLPDebug hitch : %.1f ms (seuil %.1f) #%den Warning, 100 premières lignes puis une sur 25 (LD:729-738, condition l. 733) ; au démarrageLPDebug hitch : actif, seuil 50.0 ms(LD:663) ; bilan... max %.1f ms(LD:748-753) par la commande consoleLifePlay.HitchSummary(LD:617-624). - Non lu (estimé) : la macro
WhileLoop(assetStandardMacros) et donc le nombre exact d'évaluations de laCondition; le remplissage deOSMFile.Ways; le code deFilterByAmenityaprèsSM:139.
7. Critères de VAL (commande → attendu)
V5 : VAL statique (éditeur fermé, Tools\UeState.ps1 = 0 avant et après)
- Entrée :
md5sum Content/UI/TopRight.uasset(noté, ≠1fcb94a6…après l'IMPL) ;git status --short -- Content:TopRights'ajoute auxMdéjà présents sans en modifier (MD5 identiques avant / après). - Dump EventGraph :
.\Tools\RunCommandlet.ps1 -Lot STE-GEL1V -Commandlet LPDumpFunction -Args '-BP=TopRight -Fn=EventGraph -Pins -Exec' -EtatDir "D:\Game\LifePlay-master 5.8\Docs\Migration\etat\ST\STE"→code=0, journal :=== TopRight :: EventGraph (909 noeuds) ===(premier listing seul, les-Pins -Execsont doublés :STE-H3g-VAL.md:43). Liens attendus :CallFunction_7736.then→GEL-B.executeseul ;CallFunction_132.execute←GEL-B.thenseul ;MacroInstance_1.Exec←VariableSet_26.then,IfThenElse_6.else,GEL-B.else;GEL-B.Condition←GEL-OP.ReturnValue;GEL-OP.A←CallArrayFunction_11.ReturnValue(qui gardeCallFunction_139.A),GEL-OP.B=2000;GEL-B:thenseul versCallFunction_132,elseseul versMacroInstance_1. Variante (b) :GEL-IV.TargetArray←VariableGet_546.Results,IndexToTest=2000, polarité inversée (§ 3). - Dump SortByDistance : même commande avec
-Fn=SortByDistance→=== TopRight :: SortByDistance (29 noeuds) ===et listing 1 identique à SBD:1-129 (nœuds et liens comparés en ensembles triés ;Tools\DiffRemplacementNoeuds.pynon applicable,STE-H3g-VAL.md:42). - Diff EG avant / après (avant = EG listing 1, l. 1-4188 ; après = premier listing du dump 2) : 2 nœuds nouveaux, 0 disparu ; broches modifiées sur nœuds communs :
CallFunction_7736(then),CallFunction_132(execute),MacroInstance_1(Exec),CallArrayFunction_11(ReturnValue) et rien d'autre ; 1 lien coupé, 5 nouveaux (comptés orientés, commeSTE-H3g-VAL.md:33). - Compilation :
compile_blueprint … warnings_as_errors:true→nullà l'IMPL, journal éditeur sans Error / Warning pour TopRight ;.\Tools\RunCommandlet.ps1 -Lot STE-GEL1V -Commandlet CompileAllBlueprints -EtatDir …: GrepError:.*/Game/→ 0 ;CC_Shadersà part (référenceSTE-H3g-VAL.md:35:code=3, 25 erreurs, 3 erreurs de compilation, 55 avertissements, 420a réussi, identiques) ; une ligneLa compilation de TopRight a réussi. LPTestStringCompat:.\Tools\RunCommandlet.ps1 -Lot STE-GEL1V -Commandlet LPTestStringCompat -EtatDir …→=== 3120 cas : compat != herite(UE4) : 0 ; moteur != herite(UE4) : 60 ===(STE-H3g-VAL.md:36).- Instantané intact :
md5sum D:\Game\LifePlay_Backup_5.5\STE-GEL1\Content\UI\TopRight.uasset=1fcb94a60061b418e9deeb08bc1a990d.
V6 : essai en jeu (build Development empaqueté par BUILD, ligne de commande -ScriptStackOnWarnings -LPHitchLog)
- Preuve que le parcours est rejoué : journal avec
LPDebug hitch : actif, seuil 50.0 ms(LD:663) ; mondeCentralLondon; vue aérienne ; panneau de recherche ouvert. Sans-LPHitchLog, aucune ligne de hitch n'existe (LD:723-726) : un « aucun hitch » ne prouve alors rien. - V6-a (cas du gel) :
CentralLondon, vue aérienne, terme vide, filtre « All », valider. Attendu : une ligneLogBlueprintUserMessages: [TopRight_C_…] X=… Y=… at least 2 result(forme de J5:1830) puis aucune ligneLPDebug hitch : <ms>supérieure ou égale à 2 000 ms dans cette image ni la suivante (avant :34229.3 ms, même image[214], J5:1830-1831). Mesure :.\Tools\LogStats.ps1 -Latest <journal> -Pattern 'at least 2 result','LPDebug hitch'; piège : les lignes de hitch s'arrêtent à 100 puis une sur 25 (LD:733) ; faire l'essai en début de session, ou liremaxparLifePlay.HitchSummary(LD:748-753) juste après (lemaxest celui de toute la session). Cible visée : moins de 1 500 ms (estimée). Affichage : au plus 1 000 widgets (contrôle visuel). - V6-b (le tri est conservé) : recherche ciblée (terme ou filtre donnant entre 2 et 2 000 résultats) depuis une même vue (la vue est imprimée :
X=… Y=…) : les 20 premiers résultats sont identiques, dans l'ordre, à ceux d'un build d'avant (même terme, même vue) ; la ligneat least 2 resultest présente ; hitch de la recherche du même ordre qu'avant (moins d'1 s attendu : 6 635 bâtiments ≈ 0,6 s, DIAG § 3.4, estimé). - V6-c (seuil) : le nombre exact n n'est pas journalisé (D4 non fait, impression temporaire interdite) : V6 ne contrôle pas la frontière 2 000 / 2 001 ; elle est établie par la valeur
2000lue au dump (V5-2). Non mesuré par V6. - Non-régression :
fatal|Unhandled|Critical|Assertion→ 0 ;.\Tools\LogStats.ps1 -Compare <journal>,<J5>: aucune famille nouvelle ; si le build n'existe pas encore, V6 est reporté à la prochaine session COMMUN (précédent :STE-H3g-VAL.md:39).
Fichiers à commiter (dépôt jeu, branche ue5.8, ticket au gardien) :
- A
Docs/Migration/etat/ST/STE/STE-GEL1-SPEC.md
Tours : 27 / 40 (comptés à la main, Write compris ; Tools/FicheStats.py fait foi)
Constats
Commandes (outils Grep / Read / Glob sauf mention) et comptes bruts :
- C1 Bash :
git rev-parse --short HEAD→0745917;md5sum Content/UI/TopRight.uasset→1fcb94a60061b418e9deeb08bc1a990d;git status --short -- Content/UI/TopRight.uasset Plugins/StreetMap→ aucune ligne ;git log --oneline -1 -- Content/UI/TopRight.uasset→f32df0d. - C2 En-têtes : SBD:1
(29 noeuds), SBD:130(29 noeuds); EG:1(907 noeuds), EG:4189(907 noeuds). GrepSortByDistancesur EG → 1 ligne (2613) ; Grepat leastsur EG → 1 ligne (3366). Grepvariable 'Results'sur EG → 2581, 2589, 2598, 2607, 2620. - C3 Bash (lecture, binaires : le Grep s'arrête au premier octet nul,
STE-H3g-SPEC.mdC8) :grep -rlaF "SortByDistance" Content/BPs Content/UI Content/Maps --include=*.uasset --include=*.umap→Content/BPs/Person.uasset,Content/BPs/StreetMap_Static.uasset,Content/UI/TopRight.uasset(+grep: Content/Maps: No such file or directory, code 2) ; même commande surContent/Scenes Structs Developers Collections Render Characters→ aucune sortie ;grep -a -o -E "[A-Za-z0-9_/.:]{0,50}SortByDistance[A-Za-z0-9_/.:]{0,30}":StreetMap_Static→12 SortByDistance,1 SortByDistance.K2Node_FunctionEntry_9,1 SortByDistance.K2Node_FunctionResult_0;Person→1 SortByDistance; contrôleTopRight(grep -a -o -F … | wc -l) →16. - C4 Grep
SortByDistance:Content\Modules→ 0 ;Source→ 0 ;Plugins(*.cpp,h,ini,py,json,md) → 0 ;L6f_dump_Person.txt→ 9842, 9979, 10167, 10519 ;Person__graphes_D9.txt(en-tête=== Person : 134 graphe(s) ===) → 0. - C5 Lectures moteur : § 6 (toutes relues le 2026-10-14) ;
FMath::Minavec indice enGenericPlatformMath.h:1026-1054. - C6 J5:1829-1831 relues :
… [TopRight_C_2147482047] X=20411.688 Y=0.000 at least 2 resultpuisLPDebug hitch : 34229.3 ms (seuil 50.0) #12, même image[214]. - C7 Sources de chiffres relues :
Docs\Journal_Modifications.md:820(49 425 bâtiments, 5 191 aménités,CentralLondon) ;U8_LPCheckStreetMap_20261011-003558.txt:52-53(53 050 bâtiments, 6 635 avec amenity, 280 villes) ;Docs\18_Build_Debug.md:234(FindCenterOfPolygon0,742 s inclus, 49 425 appels). - Écarts à la fiche : (1) la fiche cite
Source\LifePlay\StreetMap.cpp:87-90; ce fichier n'existe pas (Glob**/StreetMap.cppsurSource: aucun) ; le code est àPlugins\StreetMap\Source\StreetMapRuntime\StreetMap.cpp:87-90(mêmes lignes) ; (2) plan du livrable : gabaritlp-doc(sections 1 à 7) avec la correspondance de la fiche en tête ; (3) Bash en lecture pourgrep -asur binaires,git,md5sum,ls(le Grep n'ouvre pas les.uassetpar dossier) ; aucun refus du crochet, aucun caractère>dans les commandes. - Non mesuré : la durée de chaque phase de
SortByDistance(D3 Insights) ; le nombre d'évaluations deMinOfFloatArraypar tour ; n à l'image 214 (49 425 estimé) ; la répartition des aménités par type ; le coût résiduel de la boucle de 1 000 widgets ; le contenu deStreetMap_Static.SortByDistance; les appelants dePersonen 5.8 ; les autres graphes deTopRight. - Lecture seule respectée ; un seul fichier écrit (ce livrable, non suivi). Aucun nom d'utilisateur ni chemin de profil cité.
Décision de l'orchestrateur (2026-10-14)
- Q-GEL1-3 : variante (a) (
<=), repli (b) sans nouvelle SPEC si P5 ne trouve pas le type_id.