DC1 : plugin LPAnimCore (LPAnimRedirect, LPCoupleSim) ; LifePlay ne depend plus de LPAnimMeasure (CHG-234)
Plugins/LPAnimCore (Runtime, PreDefault, toutes configurations) recoit la partie runtime de l'ancien LPAnimMeasure de l'addon. LifePlay.Build.cs : LPAnimMeasure -> LPAnimCore. LifePlayEditorTools depend encore de LPAnimMeasure jusqu'a DC2. Pin addon 3e9c32f. Validation : DC1-BUILD code 0, DC1-VAL PASS (tournees Mesure identiques a SB2-REF, controle visuel utilisateur marche et ShowCouple). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
19e704b02c
commit
d8a0f859ce
18 changed files with 1103 additions and 14 deletions
|
|
@ -80,6 +80,7 @@ Structure plate (pas de sous-dossier `Public/`) : `PublicIncludePaths.Add(Module
|
|||
| Plugin | Cible | Remarque |
|
||||
|---|---|---|
|
||||
| `ModdingExtra` | runtime | entrée/sortie des données ; trace d'appel en catégorie `LogModdingExtra` (`Verbose`) |
|
||||
| `LPAnimCore` | runtime | lot DC1 : `LPAnimRedirect` (redirection des clips) et `LPCoupleSim` (géométrie du couple), rapatriés de l'addon ; module `LPAnimCore` dans `Plugins/LPAnimCore` |
|
||||
| `StreetMap` | runtime | porté LWC ; 280 villes vérifiées identiques à 4.27 (L7h) |
|
||||
| `EnhancedInput` | runtime | système d'entrée actif ; exécute les 34 actions héritées de `DefaultInput.ini` |
|
||||
| `McpAutomationBridge` | **éditeur uniquement** (`TargetAllowList: Editor`) | pilotage de l'éditeur par serveur MCP ; jamais publié (contient un jeton) |
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ Rien n'est supprimé : un résultat précédent est déplacé dans `precedent_<d
|
|||
Réalisé par `Tools/anim/AnimPipeline.ps1` (CHG-223) ; ordre réel des étapes 6 et 7 : la livraison dans le mod précède les fiches et le catalogue, puis vient la cuisson DLC.
|
||||
|
||||
Le jeu résout les clés par `Room.Dailies` ; les clips des mods y sont ajoutés par `ULPModDailiesSubsystem` (CHG-209).
|
||||
`LPAnimRedirect` ne sert plus qu'à la sandbox et au personnage piloté.
|
||||
`LPAnimRedirect` ne sert plus qu'à la sandbox et au personnage piloté. Depuis le lot DC1, `LPAnimRedirect` et `LPCoupleSim` sont dans le plugin `LPAnimCore` du jeu (`Plugins/LPAnimCore`) ; la mesure reste dans le module `LPAnimMeasure` de l'addon.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ Le lot S2 sort la chaîne de mesure de `LifePlay` vers un module Runtime dédié
|
|||
|
||||
- **Contenu** : `LPPoseMeasure`, `LPSkeletonProfile`, `LPPoseOrchestrator`, `LPAnimRedirect` (8 fichiers déplacés) + `LPAnimMeasure.Build.cs`, `LPAnimMeasure.h/.cpp` (catégorie de journal `LogLPAnimMeasure`, ex-`LogLifePlay` pour les lignes `POSET` / `PROFIL` / `ORCH` / `MESURE`).
|
||||
- **Exports** : `LPANIMMEASURE_API` remplace `LIFEPLAY_API` ; 6 symboles ajoutés pour `LPPairSandbox.cpp` (`KeyBones`, `LogReport`, `TFitReport`, `Run`, `Restore`, `SampleAt`) ; les structs de données restent header-only.
|
||||
- **Rupture du couplage** : `LPAnimRedirect` ne lit plus `LPSandboxConfig`. `FLifePlayModule::StartupModule()` (`LifePlay.cpp`) appelle `LPAnimRedirect::SetUALRoot(FLPSandboxConfig::Get().QuaterniusUALRoot)` ; défaut interne `/Game/Quaternius/UAL` (identique à celui de la config).
|
||||
- **Rupture du couplage** : `LPAnimRedirect` ne lit plus `LPSandboxConfig`. l'addon (`LPSandbox.cpp:17`) appelle `LPAnimRedirect::SetUALRoot(FLPSandboxConfig::Get().QuaterniusUALRoot)` (`FLifePlayModule::StartupModule()` ne l'appelle plus) ; depuis DC1, `LPAnimRedirect` et `LPCoupleSim` sont dans le plugin du jeu `Plugins/LPAnimCore` ; défaut interne `/Game/Quaternius/UAL` (identique à celui de la config).
|
||||
- **Déclaration** : entrée `Runtime` / `Default` dans `LifePlay.uproject`, placée avant `LifePlay` ; `ExtraModuleNames` des deux `*.Target.cs`.
|
||||
|
||||
### Graphe de dépendances des modules
|
||||
|
|
@ -86,7 +86,11 @@ flowchart LR
|
|||
LPET["LifePlayEditorTools<br/>(Editor)"] -->|Public| LP["LifePlay<br/>(Runtime, module primaire)"]
|
||||
LPET -->|Public<br/>FLPPose dans LPAnimChecks.h| AM["LPAnimMeasure<br/>(Runtime, nouveau S2)"]
|
||||
LP -->|Public<br/>LPPairSandbox, LPDirectControl| AM
|
||||
LP -.->|"StartupModule : SetUALRoot(QuaterniusUALRoot)"| AM
|
||||
LP -->|Public DC1| AC["LPAnimCore<br/>(plugin du jeu : LPAnimRedirect, LPCoupleSim)"]
|
||||
AM -->|Private DC1| AC
|
||||
SB["LPSandbox<br/>(addon)"] -->|DC1| AM
|
||||
SB -->|DC1| AC
|
||||
SB -.->|"LPSandbox.cpp:17 : SetUALRoot(QuaterniusUALRoot)"| AC
|
||||
AM -->|Public| ENG["Core, CoreUObject, Engine"]
|
||||
AM -->|Private| JSON["Json"]
|
||||
```
|
||||
|
|
@ -96,8 +100,11 @@ Règles : `LPAnimMeasure` ne dépend ni de `LifePlay` ni de `LifePlayEditorTools
|
|||
| De | Vers | Type | Motif |
|
||||
|---|---|---|---|
|
||||
| `LifePlay` | `LPAnimMeasure` | Public | `LPPairSandbox.h/.cpp`, `LPDirectControlSubsystem.cpp`, `LifePlay.cpp` |
|
||||
| `LifePlay` | `LPAnimCore` | Public | DC1 : `LPAnimRedirect`, `LPCoupleSim` (plugin du jeu `Plugins/LPAnimCore`) |
|
||||
| `LPAnimMeasure` | `LPAnimCore` | Private | DC1 : la mesure utilise `LPAnimRedirect` |
|
||||
| `LPSandbox` | `LPAnimMeasure`, `LPAnimCore` | Public | DC1 : mesure et redirection / géométrie du couple |
|
||||
| `LifePlayEditorTools` | `LifePlay` | Public | existant |
|
||||
| `LifePlayEditorTools` | `LPAnimMeasure` | Public | `LPAnimChecks.h` expose `FLPPose` ; commandlets `LPAnimEval`, `LPAnimCatalog`, `LPAnimTwist` |
|
||||
| `LifePlayEditorTools` | `LPAnimMeasure` | Public | `LPAnimChecks.h` expose `FLPPose` ; commandlets `LPAnimEval`, `LPAnimCatalog`, `LPAnimTwist` (jusqu'à DC2) |
|
||||
| `LPAnimMeasure` | `Core`, `CoreUObject`, `Engine` / `Json` | Public / Privé | animations, squelettes ; lecture de `Tools/anim/profiles/*.json` |
|
||||
| `LPAnimMeasure` | `LifePlay`, `LifePlayEditorTools` | **aucune** | évite un cycle de modules |
|
||||
|
||||
|
|
@ -117,12 +124,12 @@ D:\Game\
|
|||
|
||||
- **Liaison** : `LifePlay.uproject` déclare `"AdditionalPluginDirectories": ["../LifePlay-Sandbox/Plugins"]` (chemin relatif au `.uproject`) et active `LPSandbox` dans `Plugins`. UBT et l'éditeur y trouvent `LPSandbox.uplugin` (modules `LPSandbox` et `LPAnimMeasure`) ; les DLL du plugin sont compilées avec le jeu (`Build.bat LifePlayEditor Win64 Development`).
|
||||
- **Pourquoi pas un submodule** : l'addon est un `uproject` mince qui contient le plugin sous `Plugins/LPSandbox/`. Un submodule monté sur `Plugins/LPSandbox` du jeu donnerait `Plugins/LPSandbox/Plugins/LPSandbox/` (plugin imbriqué, non scanné au bon niveau) ; un submodule `External/LifePlay-Sandbox` dupliquerait l'addon à côté du sibling et rendrait ambigu l'exemplaire chargé. Un clone sibling évite les deux problèmes.
|
||||
- **Pin** : le jeu consomme un commit précis de l'addon, consigné à la main dans `S3-INT.md` (aujourd'hui `16905c68070992f5139dab907b41b461fb765957`, `lot/SB4-final`, SB4 ouverture par déclencheur éphémère non mémorisée ; précédents : `3d858527fccfdddd8711c7c7448fa001442e0b8a` SB2-O1 correction de `ShowRoom`, `fece7e9a0e63b3058b5d24d96d669a3c9c0e9add` SB2 bibliothèques de scène et de personnages, caméra du socle, état des modes sorti vers les mods, `82dae58380b76c45f60541fd7cb5a0a409700e10` SB1 registre de mods et barre latérale, `3b21fd180c04f0fa49a1b5c9ef1b517ade1cb362` SB0 conception de la sandbox modulaire, `f09c42e5a2bc613cf269cce76c878461ca41c8b7` S7-T2 uplugin, `c1fdd29e2c1036c7d6365ba6389eff5d2f8c8c96` S5-T2 `LPCoupleSim`, `f8102647ccdebad37e4977ccbf2c51e583823a80`, S4-T3). Le pin est mis à jour (hash dans `S3-INT.md` et README de l'addon) à chaque évolution de l'addon que le jeu doit prendre. Reproduire :
|
||||
- **Pin** : le jeu consomme un commit précis de l'addon, consigné à la main dans `S3-INT.md` (aujourd'hui `3e9c32f1f27b1abdaf7731dc90496c27ee061718`, `lot/DC1-animcore`, DC1 `LPAnimRedirect` et `LPCoupleSim` rapatriés dans le plugin `LPAnimCore` du jeu ; précédents : `16905c68070992f5139dab907b41b461fb765957` SB4 ouverture par déclencheur éphémère non mémorisée, `3d858527fccfdddd8711c7c7448fa001442e0b8a` SB2-O1 correction de `ShowRoom`, `fece7e9a0e63b3058b5d24d96d669a3c9c0e9add` SB2 bibliothèques de scène et de personnages, caméra du socle, état des modes sorti vers les mods, `82dae58380b76c45f60541fd7cb5a0a409700e10` SB1 registre de mods et barre latérale, `3b21fd180c04f0fa49a1b5c9ef1b517ade1cb362` SB0 conception de la sandbox modulaire, `f09c42e5a2bc613cf269cce76c878461ca41c8b7` S7-T2 uplugin, `c1fdd29e2c1036c7d6365ba6389eff5d2f8c8c96` S5-T2 `LPCoupleSim`, `f8102647ccdebad37e4977ccbf2c51e583823a80`, S4-T3). Le pin est mis à jour (hash dans `S3-INT.md` et README de l'addon) à chaque évolution de l'addon que le jeu doit prendre. Reproduire :
|
||||
|
||||
```powershell
|
||||
cd D:\Game
|
||||
git clone https://github.com/edujiro5972/LifePlay-Sandbox.git
|
||||
git -C LifePlay-Sandbox checkout 16905c68070992f5139dab907b41b461fb765957
|
||||
git -C LifePlay-Sandbox checkout 3e9c32f1f27b1abdaf7731dc90496c27ee061718
|
||||
# le jeu doit être cloné à côté : D:\Game\LifePlay-master 5.5
|
||||
```
|
||||
|
||||
|
|
@ -179,11 +186,12 @@ Le lot S5 ferme la **dérive de fork** entre la sandbox (`LPSandbox/LPCoupleSim.
|
|||
- [x] **SB2-O1** : correction du défaut O1 (`etat/sandbox/SB2/SB2-O1-BUILD.md` PASS, contrôle visuel utilisateur 2026-10-07 ; tag `lot-SB2-O1-valide`).
|
||||
- [x] Reports SB2 : (O1) traité (SB2-O1, `3d858527fccfdddd8711c7c7448fa001442e0b8a` : `ShowRoom` symétrique de `HideRoom`, contrôle visuel utilisateur 2026-10-07 « c'est bon ») ; (E3) sans `lps_lib_scene`, la pièce est construite quand même : non traité, séparation physique abandonnée à la porte G-SB3 (décision utilisateur 2026-10-07).
|
||||
- [x] **DC0** : cartographie et SPEC du découplage jeu / sandbox (`etat/sandbox/DC0/DC0-SPEC.md`, approuvée par l'utilisateur 2026-10-07) ; plan `24_Plan_Decouplage_Sandbox.md`.
|
||||
- [ ] **DC1** : Plugin LPAnimCore dans le jeu, LPAnimMeasure réduit à la mesure (DC1-T1..T5).
|
||||
- [x] **DC1** : Plugin LPAnimCore dans le jeu, LPAnimMeasure réduit à la mesure (DC1-T1..T5) (DC1-VAL PASS, contrôle visuel utilisateur 2026-10-07 ; tag addon lot-DC1-valide).
|
||||
- [ ] **DC2** : Commandlets de mods vers un module éditeur de la sandbox (DC2-T1..T5).
|
||||
- [ ] **DC3** : Scripts, données et sources de mods vers la sandbox (DC3-T1..T5).
|
||||
- [ ] **DC4** : Preuve « jeu seul », docs, évaluation (DC4-T1..T4).
|
||||
- [ ] Reports DC0 (lot propriétaire **DC1**) : § Rupture du couplage : la mention d'un appel à SetUALRoot par FLifePlayModule::StartupModule() est périmée ; seul l'addon l'appelle (LPSandbox.cpp:17, LPSandboxMeasure.cpp:39) — voir DC0-CART b2.
|
||||
- [ ] Intégration des déplacements dans le jeu à améliorer (remarque utilisateur au contrôle visuel DC1, 2026-10-07) ; lot propriétaire : à définir, hors DC.
|
||||
- [x] Reports DC0 (lot propriétaire **DC1**, traité : texte corrigé en § Rupture du couplage) : § Rupture du couplage : la mention d'un appel à SetUALRoot par FLifePlayModule::StartupModule() est périmée ; seul l'addon l'appelle (LPSandbox.cpp:17, LPSandboxMeasure.cpp:39) — voir DC0-CART b2.
|
||||
## Lots (S0 … S8)
|
||||
|
||||
| Lot | Objet (une ligne) |
|
||||
|
|
|
|||
|
|
@ -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-234 | 2026-10-07 | DC1 | jeu : `Plugins/LPAnimCore/*` (nouveau plugin : `LPAnimRedirect.*`, `LPCoupleSim.h`, `LPCoupleSimCore.cpp`), `LifePlay.uproject`, `Source/LifePlay/LifePlay.Build.cs`, docs (`21_Sandbox_Addon.md`, `20_Chaine_Animations.md`, `07_Architecture_5.5.md`, `etat/sandbox/S3/S3-INT.md`, `etat/sandbox/DC1/*`) ; addon `D:\Game\LifePlay-Sandbox` : `LPSandbox.uproject`, `LPSandbox.uplugin`, `LPAnimMeasure.Build.cs`, `LPAnimMeasure.h`, `LPSandbox.Build.cs`, suppression de `LPAnimRedirect.*`, `LPCoupleSim.h`, `LPCoupleSimCore.cpp` (commit `3e9c32f1f27b1abdaf7731dc90496c27ee061718`, branche `lot/DC1-animcore`, tag `lot-DC1-valide`) | lot DC1 : `LPAnimRedirect` et `LPCoupleSim` rapatriés dans le plugin `LPAnimCore` du jeu, `LPAnimMeasure` réduit à la mesure ; compilation PASS, DC1-VAL PASS, contrôle visuel utilisateur 2026-10-07 ; report DC0 SetUALRoot traité. Motif : le jeu public doit compiler sans le dépôt privé `LifePlay-Sandbox` (premier pas du découplage) | pin `16905c6` → `3e9c32f` (hash complet `3e9c32f1f27b1abdaf7731dc90496c27ee061718`) | `.\Tools\Restore.ps1 -Lot DC1` (jeu) et `.\Tools\Restore.ps1 -Lot DC1-addon -ProjectRoot D:\Game\LifePlay-Sandbox` ; pin `16905c6` |
|
||||
| CHG-233 | 2026-10-07 | DC0 | `Docs/Migration/24_Plan_Decouplage_Sandbox.md` (nouveau), `Docs/Migration/etat/sandbox/DC0/DC0-CART.md`, `DC0-SPEC.md`, `DC0-VAL.md` (nouveaux) | lot DC0 : plan du découplage jeu / sandbox (lots DC0 à DC4), cartographie et SPEC approuvées par l'utilisateur le 2026-10-07 (plugin `LPAnimCore` dans le jeu, module éditeur `LPModTools` et tout l'outillage de mods dans l'addon, dépôt Sandbox privé) ; documentation seule, aucun code. Motif : le jeu public doit compiler sans le dépôt privé `LifePlay-Sandbox` (`LifePlay` et `LifePlayEditorTools` dépendent de `LPAnimMeasure`) | aucun pin (documentation seule) | supprimer ces fichiers (documentation seule) ; rien n'est commité dans le dépôt du jeu ni poussé |
|
||||
| CHG-232 | 2026-10-07 | SB4 | addon `D:\Game\LifePlay-Sandbox` : `Plugins/LPSandbox/Source/LPSandbox/LPPairSandbox.cpp`, `LPSandboxModRegistry.cpp`, `LPSandboxModRegistry.h` (SB4-T0 : ouverture par déclencheur éphémère non mémorisée, `sandbox_mode.txt` du pilote), `README.md` (commits `16905c68070992f5139dab907b41b461fb765957` code + pin, tag `lot-SB4-valide`, branche `lot/SB4-final`, tag d'entrée `lot-SB4-avant` = `30e8c18`) ; jeu : `Docs/Migration/etat/sandbox/SB4/SB4-BUILD.md`, `SB4-VAL.md`, `SB4-EVAL.md`, `Docs/Migration/23_Cycle_De_Vie_Mod.md` (§ 7), `Docs/Migration/21_Sandbox_Addon.md`, `Docs/Migration/etat/sandbox/S3/S3-INT.md` | lot SB4 (dernier lot de la sandbox modulaire) : SB4-T0 correctif (ouverture par déclencheur éphémère, `Open=lps_couple` intact), compilation PASS, validation finale F1 à F4 PASS (démarrage, tournées Quaternius et FreeAnimationsPack identiques à SB2-REF, LPAnimEval identique), doc 23 § 7, évaluation `SB4-EVAL.md` : décision GO pour transposer au jeu par petits lots | pin `3d85852` → `16905c6` (hash complet `16905c68070992f5139dab907b41b461fb765957`) | `.\Tools\Restore.ps1 -Lot SB4` (docs du jeu), `.\Tools\Restore.ps1 -Lot SB4-addon -ProjectRoot D:\Game\LifePlay-Sandbox` et `git -C D:\Game\LifePlay-Sandbox checkout lot-SB4-avant` ; rien n'est commité dans le dépôt du jeu ni poussé |
|
||||
| CHG-231 | 2026-10-07 | SB2-O1 | addon `D:\Game\LifePlay-Sandbox` : `Plugins/LPSandbox/Source/LPSandbox/LPSandboxScene.cpp` (`ALPSandboxScene::ShowRoom` : `SetHiddenInGame(false)` puis `SetVisibility(true, true)` sur meubles et murs), `README.md` (commits `3d858527fccfdddd8711c7c7448fa001442e0b8a` code + `30e8c18` pin, tag `lot-SB2-O1-valide`, branche `lot/SB2-O1`, tag d'entrée `lot-SB2-O1-avant` = `b4ca206`) ; jeu : `Docs/Migration/etat/sandbox/SB2/SB2-O1-BUILD.md`, `Docs/Migration/etat/sandbox/S3/S3-INT.md`, `Docs/Migration/21_Sandbox_Addon.md` (pin, reports SB2, porte G-SB3) | mini-lot SB2-O1 : correction du défaut O1 (meubles et murs invisibles au retour de Mesure, `ShowRoom` rendu symétrique de `HideRoom`) ; compilation PASS ; tournée freeanims identique à SB2-REF (73/73 fichiers, JSON/CSV/TXT identiques) ; contrôle visuel utilisateur « c'est bon » (meubles et murs visibles en revenant de Mesure vers Couple et Interaction). Porte G-SB3 (décision utilisateur 2026-10-07) : SB3 abandonné (plugins physiques séparés non faits) ; les mods du jeu sont du contenu (.lpmod + pak), leurs dépendances sont vérifiées par le registre (prouvé en SB1/SB2), coût ≈ 1 à 1,5 lot, `LPAnimMeasure` utilisé par le jeu en Shipping ; on passe à SB4 ; E3 non traité | pin `fece7e9` → `3d85852` (hash complet `3d858527fccfdddd8711c7c7448fa001442e0b8a`) | `.\Tools\Restore.ps1 -Lot SB2-O1` (docs du jeu), `.\Tools\Restore.ps1 -Lot SB2-O1-addon -ProjectRoot D:\Game\LifePlay-Sandbox` et `git -C D:\Game\LifePlay-Sandbox checkout lot-SB2-O1-avant` ; rien n'est commité dans le dépôt du jeu ni poussé |
|
||||
|
|
|
|||
66
Docs/Migration/etat/sandbox/DC1/DC1-BUILD.md
Normal file
66
Docs/Migration/etat/sandbox/DC1/DC1-BUILD.md
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
# DC1-BUILD : Compilation LifePlayEditor
|
||||
|
||||
## Fiche DC1-T2
|
||||
|
||||
| Élément | Valeur |
|
||||
|---------|--------|
|
||||
| Lot | DC1 (plugin LPAnimCore) |
|
||||
| Tâche | DC1-T2 |
|
||||
| Agent | A-BUILD |
|
||||
| Modèle prévu | haiku |
|
||||
| Modèle utilisé | haiku |
|
||||
| Date | 2026-10-07 |
|
||||
|
||||
## Commande lancée
|
||||
|
||||
```
|
||||
& 'D:\Game\Launcher\Engine\UE_5.5\Engine\Build\BatchFiles\Build.bat' LifePlayEditor Win64 Development -Project='D:\Game\LifePlay-master 5.5\LifePlay.uproject' -WaitMutex *> 'D:\Game\LifePlay-master 5.5\Docs\Migration\etat\sandbox\DC1\DC1_Build_LifePlayEditor.txt'
|
||||
```
|
||||
|
||||
## Verdict
|
||||
|
||||
**PASS** — Code de sortie : **0**
|
||||
|
||||
## Erreurs
|
||||
|
||||
Aucune
|
||||
|
||||
## Avertissements
|
||||
|
||||
- **2 messages UBT** : lignes 46-47, non-blocants, concernant le renommage des niveaux d'avertissement en UBT (DeprecationWarningLevel, MSVCDeprecationWarningLevel).
|
||||
- **1 dépendance dépréciée** : ligne 50, McpAutomationBridge dépend de StructUtils (déprécié en 5.5).
|
||||
- **Aucun avertissement** concernant LPAnimCore, LPAnimMeasure, LPSandbox ou LifePlay.Build.cs
|
||||
|
||||
## Tableau des DLL
|
||||
|
||||
| Nom | Date (LastWriteTime) | Taille |
|
||||
|-----|----------------------|--------|
|
||||
| UnrealEditor-LPAnimCore.dll | 07/10/2026 16:16:52 | 0,23 MB |
|
||||
| UnrealEditor-LPAnimMeasure.dll | 07/10/2026 16:16:56 | 0,50 MB |
|
||||
| UnrealEditor-LifePlay.dll | 07/10/2026 16:17:14 | 1,16 MB |
|
||||
| UnrealEditor-LifePlayEditorTools.dll | 07/10/2026 16:17:21 | 1,06 MB |
|
||||
|
||||
Toutes les DLL datent d'aujourd'hui (07/10/2026), témoignant de la compilation réussie.
|
||||
|
||||
## Structures compilées
|
||||
|
||||
- **Module LPAnimCore** : compilé avec succès, DLL générée et présente.
|
||||
- **Module LPAnimMeasure** : compilé avec succès, DLL générée et présente.
|
||||
- **Module LifePlay** : compilé avec succès, DLL générée et présente.
|
||||
- **Module LifePlayEditorTools** : compilé avec succès, DLL générée et présente.
|
||||
- **Module LPSandbox** : compilé avec succès depuis les plugins additionnels (AdditionalPluginDirectories).
|
||||
|
||||
## Vérifications
|
||||
|
||||
- **Éditeur Unreal** : aucun processus en cours au démarrage ✓
|
||||
- **D:\Game\LifePlay-Sandbox\Plugins\LPSandbox\Binaries** : N'existe pas (conforme : le dépôt addon est séparé) ✓
|
||||
|
||||
## Journal complet
|
||||
|
||||
- Fichier : `D:\Game\LifePlay-master 5.5\Docs\Migration\etat\sandbox\DC1\DC1_Build_LifePlayEditor.txt`
|
||||
- Durée totale : 58,66 secondes
|
||||
- Actions exécutées : 95/95
|
||||
|
||||
## Conclusion
|
||||
|
||||
Compilation complétée avec succès. Le plugin LPAnimCore est compilé et prêt pour la suite du pipeline DC1.
|
||||
28
Docs/Migration/etat/sandbox/DC1/DC1-DOC.md
Normal file
28
Docs/Migration/etat/sandbox/DC1/DC1-DOC.md
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# DC1-DOC — Pin et documentation du lot DC1
|
||||
|
||||
**Fiche DC1-T4 (A-INT, partie pin) et DC1-T5 (A-DOC) — Modèle prévu sonnet | utilisé sonnet**
|
||||
|
||||
- Date : 2026-10-07. Aucune commande git d'écriture, aucun fichier de code. Les fins de ligne (LF) des fichiers sont conservées.
|
||||
- Nouveau pin de l'addon : `3e9c32f1f27b1abdaf7731dc90496c27ee061718` (`3e9c32f`, branche `lot/DC1-animcore`, tag `lot-DC1-valide`, local, non poussé). Pin précédent : `16905c68070992f5139dab907b41b461fb765957` (SB4).
|
||||
|
||||
## DC1-T4 (partie pin)
|
||||
|
||||
| Fichier | Lignes touchées |
|
||||
|---|---|
|
||||
| `Docs/Migration/etat/sandbox/S3/S3-INT.md` | 11 (commit pin), 13 (ancien pin ajouté en tête des pins précédents), 49 (checkout) |
|
||||
| `Docs/Migration/21_Sandbox_Addon.md` | 127 (paragraphe Pin : nouveau hash en tête, SB4 en tête des précédents), 132 (checkout) |
|
||||
| `D:\Game\LifePlay-Sandbox\README.md` | 69 (commit pin), 75 (checkout) |
|
||||
|
||||
## DC1-T5 (documentation)
|
||||
|
||||
| Fichier | Lignes touchées |
|
||||
|---|---|
|
||||
| `Docs/Migration/Journal_Modifications.md` | 1134 : CHG-234 (7 colonnes), juste au-dessus de CHG-233 |
|
||||
| `Docs/Migration/21_Sandbox_Addon.md` | 79 (Rupture du couplage : c'est l'addon `LPSandbox.cpp:17` qui appelle `SetUALRoot`, `LPAnimRedirect` / `LPCoupleSim` dans `Plugins/LPAnimCore`) ; 89 à 93 (graphe mermaid : `LPAnimCore`, `LPSandbox`) ; 103 à 105 et 107 (tableau des dépendances) ; 189 (case DC1 cochée) ; 193 (entrée de registre non cochée « Intégration des déplacements… », lot à définir hors DC) ; 194 (report DC0 SetUALRoot coché) |
|
||||
| `Docs/Migration/20_Chaine_Animations.md` | 84 (précision : `LPAnimRedirect` et `LPCoupleSim` dans le plugin `LPAnimCore` du jeu, mesure dans `LPAnimMeasure`) |
|
||||
| `Docs/Migration/07_Architecture_5.5.md` | 83 (ligne `LPAnimCore` dans le tableau 2.3 Plugins) |
|
||||
| `Docs/Migration/etat/sandbox/DC1/DC1-DOC.md` | nouveau |
|
||||
|
||||
## Contrôle
|
||||
|
||||
`git diff --stat` (lecture seule) : 07 = 1 ligne, 20 = 1 ligne modifiée, 21 = 22 lignes (15 ajoutées, 7 retirées), Journal = 1 ligne, S3-INT = 3 lignes modifiées, README addon = 2 lignes modifiées. Aucun fichier réécrit en entier.
|
||||
35
Docs/Migration/etat/sandbox/DC1/DC1-IMPL.md
Normal file
35
Docs/Migration/etat/sandbox/DC1/DC1-IMPL.md
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# DC1-IMPL — Plugin LPAnimCore
|
||||
|
||||
- **Fiche** : DC1-T1 (A-IMPL-H) — **Modèle** : M3 opus | opus (session principale) — **Dépend de** : DC0-SPEC § 1
|
||||
- **Instantanés** : `D:\Game\LifePlay_Backup_5.5\DC1` (jeu : `LifePlay.uproject`, `LifePlay.Build.cs`, `Plugins\LPAnimCore` absent)
|
||||
et `DC1-addon` (16 fichiers de l'addon). Retour arrière proposé : `.\Tools\Restore.ps1 -Lot DC1` et
|
||||
`.\Tools\Restore.ps1 -Lot DC1-addon -ProjectRoot D:\Game\LifePlay-Sandbox`.
|
||||
- **Branche addon** : `lot/DC1-animcore` (depuis `lot/SB4-final` = `4795ea2`).
|
||||
|
||||
## Jeu
|
||||
|
||||
| Fichier | Changement |
|
||||
|---|---|
|
||||
| `Plugins/LPAnimCore/LPAnimCore.uplugin` | nouveau : module `LPAnimCore`, Runtime, `PreDefault`, Win64, toutes configurations |
|
||||
| `Plugins/LPAnimCore/Source/LPAnimCore/LPAnimCore.Build.cs` | nouveau : `Core`, `CoreUObject`, `Engine` publics, structure plate |
|
||||
| `Plugins/LPAnimCore/Source/LPAnimCore/LPAnimCore.cpp` | nouveau : `IMPLEMENT_MODULE(FDefaultModuleImpl, LPAnimCore)` |
|
||||
| `…/LPAnimRedirect.h/.cpp`, `LPCoupleSim.h`, `LPCoupleSimCore.cpp` | copiés de l'addon ; seules différences : `LPANIMMEASURE_API` → `LPANIMCORE_API` (6 dans `LPAnimRedirect.h` dont 3 lignes, 18 dans `LPCoupleSim.h`) et le commentaire de `SetUALRoot` (périmé : c'est l'addon qui l'appelle, pas `LifePlay`) ; `LPAnimRedirect.cpp` et `LPCoupleSimCore.cpp` identiques octet pour octet (CRLF conservé) |
|
||||
| `LifePlay.uproject` | plugin `LPAnimCore` activé (avant `LPSandbox`, qui reste `Optional`) |
|
||||
| `Source/LifePlay/LifePlay.Build.cs` | `LPAnimMeasure` → `LPAnimCore` (public) |
|
||||
|
||||
Empreintes SHA-256 (16 premiers caractères) : `LPAnimCore.Build.cs` cabb05d300fb9f33, `LPAnimCore.cpp` 2eabcff54d205a58,
|
||||
`LPAnimRedirect.cpp` b0a04db568abfae1, `LPAnimRedirect.h` 89304d2e67da47f1, `LPCoupleSim.h` c560a4a8811a2a87,
|
||||
`LPCoupleSimCore.cpp` 7a0a276fa9638a75.
|
||||
|
||||
## Addon
|
||||
|
||||
| Fichier | Changement |
|
||||
|---|---|
|
||||
| `Plugins/LPSandbox/Source/LPAnimMeasure/LPAnimRedirect.h/.cpp`, `LPCoupleSim.h`, `LPCoupleSimCore.cpp` | supprimés (`git rm`) |
|
||||
| `LPAnimMeasure.Build.cs` | `LPAnimCore` en dépendance privée (`LPPoseOrchestrator.cpp`) |
|
||||
| `LPAnimMeasure.h` | commentaire d'en-tête |
|
||||
| `LPSandbox/LPSandbox.Build.cs` | `LPAnimCore` en dépendance publique |
|
||||
| `LPSandbox.uplugin` | `"Plugins": [ LPAnimCore ]`, description |
|
||||
| `LPSandbox.uproject` | `AdditionalPluginDirectories` → `../LifePlay-master 5.5/Plugins/LPAnimCore` |
|
||||
|
||||
`LifePlayEditorTools.Build.cs` inchangé (garde `LPAnimMeasure` jusqu'à DC2).
|
||||
124
Docs/Migration/etat/sandbox/DC1/DC1-VAL.md
Normal file
124
Docs/Migration/etat/sandbox/DC1/DC1-VAL.md
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
# DC1-VAL — Validation automatique du lot DC1 (DC1-T3, partie automatique)
|
||||
|
||||
**Fiche DC1-T3 — Modèle prévu sonnet | utilisé sonnet**
|
||||
|
||||
- Date : 2026-10-07. Build testé : celui de `DC1-BUILD.md` (code 0, non recompilé). Lot DC1 : LPAnimRedirect et LPCoupleSim déplacés dans le plugin du jeu `Plugins\LPAnimCore`.
|
||||
- Journaux copiés dans `D:\Game\LifePlay_Backup_5.5\DC1-VAL\` : `F1.log`, `F2_quaternius_sandbox.log`, `F2_quaternius_console.txt`, `F2_freeanims_sandbox.log`, `F2_freeanims_console.txt` (+ `F2_*_result.txt` : code et durée).
|
||||
- Procédure : méthode de `SB4-VAL.md` / `SB2-VAL.md` (lanceur `LifePlay_pair_sandbox.bat` lancé depuis PowerShell, attente de `Ouvert :`, copie du journal, arrêt du seul `UnrealEditor` lancé ; tournées par `AnimPipeline.ps1 -Pack <pack> -From 5 -To 5`, aucun éditeur avant chaque lancement). Aucun git (hors `status`), aucune modification de source, script ou ini.
|
||||
- Incident sans effet : une première tentative freeanims, lancée par erreur dans Windows PowerShell 5.1 (`Start-Process powershell`), a échoué immédiatement : `ECHEC : Impossible de trouver un paramètre correspondant au nom « AsHashtable ».` (cmdlet PowerShell 7 ; erreur de mon lancement, pas du build ; aucun éditeur lancé). Relancée dans pwsh 7 (comme le quaternius) ; seul ce second lancement est retenu.
|
||||
|
||||
## Tableau des essais
|
||||
|
||||
| Essai | Attendu | Constaté (lignes recopiées) | Verdict |
|
||||
|---|---|---|---|
|
||||
| F1 démarrage | 7 modules, ordre, aucun refus, `Ouvert : lps_couple`, aucun Error/Ensure/Fatal LPSandbox/LPAnimCore/LPAnimMeasure | `LogLPSandboxMods: Display: Modules : 7 sandbox, 16 jeu ; ordre : lps_system_core, lps_system_animmeasure, lps_lib_scene, lps_lib_actors, lps_couple, lps_interaction, lps_asset_integration` ; les 7 en `pret` ; `LogLPSandboxMods: Display: Ouvert : lps_couple`. Lignes citant LPAnimCore : `LogPluginManager: Mounting Project plugin LPAnimCore` et `LogConfig: Branch 'LPAnimCore' had been unloaded. Reloading on-demand took 0.10ms` (aucune erreur de chargement du module). Aucune ligne de refus de module (le mot « refus » n'apparaît que dans `UTS: Unable to launch the Unreal Trace Server ... Accès refusé`, avertissement d'environnement). Seul `Error` : `LogLifePlay: Error: Coiffures : GI.HairstyleTable ou GI.MorphableHairs introuvable sur GameInstance_0, table laissee telle quelle` (connu, préexistant, hors LPSandbox). Aucun `Ensure`/`Fatal`. Corps, boîte AgMakeout et poses chargés comme à SB2. | PASS |
|
||||
| F2 quaternius : avant | `Open=lps_couple` | `Saved\sandbox_mods.ini:3:Open=lps_couple` | PASS |
|
||||
| F2 quaternius : journal | `Ouvert : lps_asset_integration (declencheur, non memorise)` + `TOURNEE fermeture demandee` | `LogLPSandbox: Warning: TOURNEE debut 43 clips, 129 etapes` ; `LogLPSandboxMods: Display: Ouvert : lps_asset_integration (declencheur, non memorise)` ; tournée 43 clips ; fermeture demandée. Code 0, 1139 s, verdict `avertissement`. Seul Error : Coiffures. | PASS |
|
||||
| F2 quaternius : après | `Open=lps_couple` | `Saved\sandbox_mods.ini:3:Open=lps_couple` | PASS |
|
||||
| F2 freeanims : avant | `Open=lps_couple` | `Saved\sandbox_mods.ini:3:Open=lps_couple` | PASS |
|
||||
| F2 freeanims : journal | idem | `LogLPSandbox: Warning: TOURNEE debut 10 clips, 30 etapes` ; `LogLPSandboxMods: Display: Ouvert : lps_asset_integration (declencheur, non memorise)` ; `TOURNEE debut 10 clips, 697 etapes` ; `LogLPSandbox: Warning: TOURNEE fermeture demandee`. Code 0, 458 s, verdict `ok`. Seul Error : Coiffures. | PASS |
|
||||
| F2 freeanims : après | `Open=lps_couple` | `Saved\sandbox_mods.ini:3:Open=lps_couple` | PASS |
|
||||
| F3 quaternius | fichiers identiques, verdict `avertissement`, 8 mêmes avertissements | voir détail | PASS |
|
||||
| F3 freeanims | fichiers de données identiques, verdict `ok` | voir détail (20 images diffèrent, les mêmes qu'à SB2/SB4) | PASS (images : à juger) |
|
||||
| F4 état final | ini standard, aucun éditeur, git recopié | voir ci-dessous | PASS |
|
||||
|
||||
## Détail F3
|
||||
|
||||
Référence : `D:\Game\LifePlay_Backup_5.5\SB2-REF\<pack>\` ; nouveau : `Saved\AnimPipeline\<pack>\`. Comparaison par SHA-256 de chaque fichier commun.
|
||||
|
||||
### quaternius (verdict `avertissement`)
|
||||
|
||||
- Liste de fichiers : 44 / 44, identique ; 44 fichiers comparés (critère > 40 : OK).
|
||||
- Seuls fichiers dont le SHA-256 diffère : `etapes\5_evaluation.json` (champs `debut`, `fin`, `duree_s` 1136 → 1139), `etat.json` (`fin`, `maj`) et `rapport.html` (seule ligne différente : « Généré le » 07/10/2026 12:10:18 → 16:21:02). Tous les autres `.json`, `.csv`, `.txt` (dont `rapport.json`, `eval_*.csv`, `controles_*.csv`, `retarget_pose_*.txt`) sont identiques : 41 fichiers identiques sur 44.
|
||||
- Verdict `5_evaluation.json` : `avertissement` dans la référence et dans le nouveau ; 8 avertissements dans chacun, listes identiques (comparées en JSON).
|
||||
- Images : aucune dans ce pack.
|
||||
|
||||
### freeanims (verdict `ok`, 0 avertissement)
|
||||
|
||||
- Liste de fichiers : 73 / 73, identique ; 73 fichiers comparés (critère > 70 : OK).
|
||||
- Mêmes exclusions : `etapes\5_evaluation.json` (`debut`, `fin`, `duree_s` 435 → 458), `etat.json` (`fin`, `maj`) et `rapport.html` (« Généré le » 12:31:18 → 17:08:32 uniquement) diffèrent ; tous les `.json`/`.csv`/`.txt` hors ces fichiers sont identiques.
|
||||
- Verdict `ok` des deux côtés, 0 avertissement des deux côtés.
|
||||
- Images qui diffèrent : 20 fichiers, exactement les mêmes noms que dans SB4-VAL (rendu non déterministe déjà constaté à SB1/SB2/SB4), octets réf → nouveau :
|
||||
|
||||
| Fichier (sous `sandbox\`) | Réf → nouveau |
|
||||
|---|---|
|
||||
| planches\AS_AirKiss.jpg | 148577 → 148509 |
|
||||
| planches\AS_AttackInLevitation2.jpg | 139248 → 139290 |
|
||||
| planches\AS_ChillDriving.jpg | 187537 → 187639 |
|
||||
| planches\AS_ComboHands.jpg | 159892 → 160037 |
|
||||
| planches\AS_EatingOnParty.jpg | 141254 → 141301 |
|
||||
| planches\AS_FlyingUp.jpg | 119045 → 118961 |
|
||||
| planches\AS_GoForward.jpg | 150812 → 150701 |
|
||||
| planches\AS_Rest.jpg | 138425 → 138540 |
|
||||
| planches\AS_RightLegKick2.jpg | 88121 → 88080 |
|
||||
| planches\AS_Talk.jpg | 144201 → 144319 |
|
||||
| vignettes\AS_AirKiss.png | 261470 → 261921 |
|
||||
| vignettes\AS_AttackInLevitation2.png | 252870 → 253271 |
|
||||
| vignettes\AS_ChillDriving.png | 289192 → 289225 |
|
||||
| vignettes\AS_ComboHands.png | 269493 → 269106 |
|
||||
| vignettes\AS_EatingOnParty.png | 263747 → 263738 |
|
||||
| vignettes\AS_FlyingUp.png | 263615 → 263387 |
|
||||
| vignettes\AS_GoForward.png | 257039 → 256829 |
|
||||
| vignettes\AS_Rest.png | 242540 → 242649 |
|
||||
| vignettes\AS_RightLegKick2.png | 265941 → 265478 |
|
||||
| vignettes\AS_Talk.png | 260083 → 260572 |
|
||||
|
||||
Écarts de taille inférieurs à 0,2 %. Soit 73 − 3 (fichiers exclus) − 20 (images) = 50 fichiers de données strictement identiques.
|
||||
|
||||
## État final (F4)
|
||||
|
||||
- `Saved\sandbox_mods.ini` :
|
||||
```
|
||||
[Mods]
|
||||
Order=lps_couple,lps_interaction,lps_asset_integration
|
||||
Open=lps_couple
|
||||
[Enabled]
|
||||
lps_couple=true
|
||||
lps_interaction=true
|
||||
lps_asset_integration=true
|
||||
```
|
||||
- Processus `UnrealEditor` : 0.
|
||||
- `git -C D:\Game\LifePlay-Sandbox status --short` (changements DC1 non commités, attendu ; code de l'addon retiré vers le jeu) :
|
||||
```
|
||||
M LPSandbox.uproject
|
||||
M Plugins/LPSandbox/LPSandbox.uplugin
|
||||
M Plugins/LPSandbox/Source/LPAnimMeasure/LPAnimMeasure.Build.cs
|
||||
M Plugins/LPSandbox/Source/LPAnimMeasure/LPAnimMeasure.h
|
||||
D Plugins/LPSandbox/Source/LPAnimMeasure/LPAnimRedirect.cpp
|
||||
D Plugins/LPSandbox/Source/LPAnimMeasure/LPAnimRedirect.h
|
||||
D Plugins/LPSandbox/Source/LPAnimMeasure/LPCoupleSim.h
|
||||
D Plugins/LPSandbox/Source/LPAnimMeasure/LPCoupleSimCore.cpp
|
||||
M Plugins/LPSandbox/Source/LPSandbox/LPSandbox.Build.cs
|
||||
```
|
||||
|
||||
## Anomalies
|
||||
|
||||
- Aucune nouvelle. `Error` Coiffures (LogLifePlay) présent à chaque lancement, préexistant. Avertissement `UTS: Unable to launch the Unreal Trace Server ... Accès refusé` : environnement, sans lien.
|
||||
- 20 images freeanims différentes (rendu non déterministe, mêmes fichiers qu'à SB2 et SB4) : à juger visuellement si souhaité.
|
||||
- Durées légèrement plus longues que la référence (quaternius 1139 s contre 1136 s ; freeanims 458 s contre 435 s) : sans signification (charge machine), dans l'ordre de grandeur.
|
||||
- Tentative freeanims ratée par mon mauvais interpréteur (voir en-tête) : sans conséquence.
|
||||
|
||||
## Verdict global de la partie automatique
|
||||
|
||||
**PASS** : F1 (7 modules, ordre inchangé, plugin LPAnimCore monté, aucun refus ni Error du module), F2 (ouverture par déclencheur non mémorisée, `Open=lps_couple` intact après les deux tournées), F3 (quaternius `avertissement` avec les 8 mêmes avertissements, 44 fichiers ; freeanims `ok`, 73 fichiers ; tous fichiers de données identiques, seules différences : dates, « Généré le » et 20 images non déterministes) et F4 satisfaits. Le déplacement de LPAnimRedirect et LPCoupleSim n'a rien changé aux résultats des commandlets AP.
|
||||
|
||||
## Reste à valider par l'utilisateur
|
||||
|
||||
(a) Marche du jeu avec clips convertis (`LPAnimTarget.ini` = game).
|
||||
(b) ShowCouple.
|
||||
|
||||
## Modèles par fiche
|
||||
|
||||
| Fiche | Modèle prévu | Modèle utilisé |
|
||||
|---|---|---|
|
||||
| DC1-T2 | haiku | haiku |
|
||||
| DC1-T3 | sonnet | sonnet |
|
||||
|
||||
## Contrôle visuel utilisateur (2026-10-07)
|
||||
|
||||
(a) marche du jeu avec clips convertis (`LPAnimTarget.ini` = `game`, jeu lancé depuis l'éditeur compilé DC1) et
|
||||
(b) ShowCouple : **confirmés** par l'utilisateur (« oui, je confirme »). `LPAnimTarget.ini` remis à son état d'avant le
|
||||
test (`Target=sandbox`). Remarque utilisateur : l'intégration des déplacements dans le jeu reste à améliorer (hors
|
||||
périmètre DC, inscrit au registre des reports de `21`).
|
||||
|
||||
**Verdict DC1-T3 : PASS.**
|
||||
|
|
@ -8,9 +8,9 @@ Date : 2026-10-06 — Role A-INT
|
|||
|---|---|
|
||||
| Repo addon | https://github.com/edujiro5972/LifePlay-Sandbox.git |
|
||||
| Branche | `main` |
|
||||
| **Commit pin** | `16905c68070992f5139dab907b41b461fb765957` (`16905c6`, SB4, **local, non pousse** au 2026-10-07) |
|
||||
| **Commit pin** | `3e9c32f1f27b1abdaf7731dc90496c27ee061718` (`3e9c32f`, DC1 : `LPAnimRedirect` et `LPCoupleSim` rapatries dans le plugin `LPAnimCore` du jeu, branche `lot/DC1-animcore`, tag `lot-DC1-valide`, **local, non pousse** au 2026-10-07) |
|
||||
| Contenu du commit | S5-T2 : `LPCoupleSim` (géométrie du couple partagée jeu/addon) ; inclut S4-T3 (retrait GM Interaction legacy), S4-T2 (découpe `LPPairSandbox.cpp`) et S3-T4 (`StartupModule` → `SetUALRoot`) |
|
||||
| Pins précédents | `3d858527fccfdddd8711c7c7448fa001442e0b8a` (SB2-O1), `82dae58380b76c45f60541fd7cb5a0a409700e10` (SB1), `f09c42e5a2bc613cf269cce76c878461ca41c8b7` (S7-T2), `c1fdd29e2c1036c7d6365ba6389eff5d2f8c8c96` (S5-T2), `f8102647ccdebad37e4977ccbf2c51e583823a80` (S4-T3), `4de1f0b6764ed3bc575bb687630d3f070e1be221` (S3-T4) |
|
||||
| Pins précédents | `16905c68070992f5139dab907b41b461fb765957` (SB4), `3d858527fccfdddd8711c7c7448fa001442e0b8a` (SB2-O1), `82dae58380b76c45f60541fd7cb5a0a409700e10` (SB1), `f09c42e5a2bc613cf269cce76c878461ca41c8b7` (S7-T2), `c1fdd29e2c1036c7d6365ba6389eff5d2f8c8c96` (S5-T2), `f8102647ccdebad37e4977ccbf2c51e583823a80` (S4-T3), `4de1f0b6764ed3bc575bb687630d3f070e1be221` (S3-T4) |
|
||||
|
||||
## Structure
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ sur la copie effectivement chargee. Pin manuel a la place (ci-dessous).
|
|||
```powershell
|
||||
cd D:\Game
|
||||
git clone https://github.com/edujiro5972/LifePlay-Sandbox.git
|
||||
git -C LifePlay-Sandbox checkout 16905c68070992f5139dab907b41b461fb765957
|
||||
git -C LifePlay-Sandbox checkout 3e9c32f1f27b1abdaf7731dc90496c27ee061718
|
||||
# Le jeu doit etre clone a cote : D:\Game\LifePlay-master 5.5
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@
|
|||
}
|
||||
],
|
||||
"Plugins": [
|
||||
{
|
||||
"Name": "LPAnimCore",
|
||||
"Enabled": true
|
||||
},
|
||||
{
|
||||
"Name": "LPSandbox",
|
||||
"Enabled": true,
|
||||
|
|
|
|||
21
Plugins/LPAnimCore/LPAnimCore.uplugin
Normal file
21
Plugins/LPAnimCore/LPAnimCore.uplugin
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"FileVersion": 3,
|
||||
"Version": 1,
|
||||
"VersionName": "1.0.0",
|
||||
"FriendlyName": "LPAnimCore",
|
||||
"Description": "LifePlay : redirection des clips convertis (LPAnimRedirect) et geometrie commune du couple (LPCoupleSim). Utilise par le jeu (LifePlay) et par l'addon LifePlay-Sandbox. Compile dans toutes les configurations.",
|
||||
"Category": "LifePlay",
|
||||
"CreatedBy": "LifePlay",
|
||||
"CanContainContent": false,
|
||||
"Installed": false,
|
||||
"SupportedTargetPlatforms": [
|
||||
"Win64"
|
||||
],
|
||||
"Modules": [
|
||||
{
|
||||
"Name": "LPAnimCore",
|
||||
"Type": "Runtime",
|
||||
"LoadingPhase": "PreDefault"
|
||||
}
|
||||
]
|
||||
}
|
||||
18
Plugins/LPAnimCore/Source/LPAnimCore/LPAnimCore.Build.cs
Normal file
18
Plugins/LPAnimCore/Source/LPAnimCore/LPAnimCore.Build.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
// Module LPAnimCore (lot DC1, Docs/Migration/24_Plan_Decouplage_Sandbox.md) : partie runtime de l'ancien
|
||||
// LPAnimMeasure utilisee par le jeu (LPAnimRedirect, LPCoupleSim). Aucune dependance vers LifePlay ni vers
|
||||
// l'addon LifePlay-Sandbox ; l'addon (LPSandbox, LPAnimMeasure) depend de ce module, jamais l'inverse.
|
||||
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class LPAnimCore : ModuleRules
|
||||
{
|
||||
public LPAnimCore(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
// Structure plate (comme LPAnimMeasure).
|
||||
PublicIncludePaths.Add(ModuleDirectory);
|
||||
|
||||
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine" });
|
||||
}
|
||||
}
|
||||
5
Plugins/LPAnimCore/Source/LPAnimCore/LPAnimCore.cpp
Normal file
5
Plugins/LPAnimCore/Source/LPAnimCore/LPAnimCore.cpp
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// Module LPAnimCore (lot DC1) : LPAnimRedirect, LPCoupleSim.
|
||||
|
||||
#include "Modules/ModuleManager.h"
|
||||
|
||||
IMPLEMENT_MODULE(FDefaultModuleImpl, LPAnimCore)
|
||||
62
Plugins/LPAnimCore/Source/LPAnimCore/LPAnimRedirect.cpp
Normal file
62
Plugins/LPAnimCore/Source/LPAnimCore/LPAnimRedirect.cpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
#include "LPAnimRedirect.h"
|
||||
|
||||
#include "Misc/ConfigCacheIni.h"
|
||||
#include "Misc/Paths.h"
|
||||
|
||||
namespace LPAnimRedirect
|
||||
{
|
||||
static FString IniPath()
|
||||
{
|
||||
return FPaths::Combine(FPaths::ProjectSavedDir(), TEXT("Config/Windows/LPAnimTarget.ini"));
|
||||
}
|
||||
|
||||
// Defaut identique a FLPSandboxConfig::QuaterniusUALRoot : sans appel a SetUALRoot
|
||||
// (commandlet isole, test), le comportement est inchange.
|
||||
static FString& UALRoot()
|
||||
{
|
||||
static FString Root = TEXT("/Game/Quaternius/UAL");
|
||||
return Root;
|
||||
}
|
||||
|
||||
void SetUALRoot(const FString& Root)
|
||||
{
|
||||
if (!Root.IsEmpty())
|
||||
{
|
||||
UALRoot() = Root;
|
||||
}
|
||||
}
|
||||
|
||||
const FString& GetUALRoot()
|
||||
{
|
||||
return UALRoot();
|
||||
}
|
||||
|
||||
bool IsGameTarget()
|
||||
{
|
||||
FString Target;
|
||||
GConfig->GetString(TEXT("LifePlay.Anim"), TEXT("Target"), Target, IniPath());
|
||||
return Target.Equals(TEXT("game"), ESearchCase::IgnoreCase);
|
||||
}
|
||||
|
||||
FString ClipPath(const FString& AssetName)
|
||||
{
|
||||
return FString::Printf(TEXT("%s/%s.%s"), *GetUALRoot(), *AssetName, *AssetName);
|
||||
}
|
||||
|
||||
static FString& BodyRoot()
|
||||
{
|
||||
static FString Root;
|
||||
return Root;
|
||||
}
|
||||
|
||||
void SetBodyRoot(const FString& Root)
|
||||
{
|
||||
BodyRoot() = Root;
|
||||
}
|
||||
|
||||
FString BodyClipPath(const FString& AssetName)
|
||||
{
|
||||
const FString& Root = BodyRoot().IsEmpty() ? GetUALRoot() : BodyRoot();
|
||||
return FString::Printf(TEXT("%s/%s.%s"), *Root, *AssetName, *AssetName);
|
||||
}
|
||||
}
|
||||
27
Plugins/LPAnimCore/Source/LPAnimCore/LPAnimRedirect.h
Normal file
27
Plugins/LPAnimCore/Source/LPAnimCore/LPAnimRedirect.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// Choisit qui joue les clips convertis (Bridget / Michael).
|
||||
// Saved/Config/Windows/LPAnimTarget.ini : Target=sandbox ou Target=game.
|
||||
// sandbox : seule la sandbox les joue. game : la marche du jeu les joue.
|
||||
// Les fichiers restent dans /Game/Quaternius/UAL.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
namespace LPAnimRedirect
|
||||
{
|
||||
LPANIMCORE_API bool IsGameTarget();
|
||||
|
||||
LPANIMCORE_API FString ClipPath(const FString& AssetName);
|
||||
|
||||
// Racine des clips convertis. L'addon LifePlay-Sandbox (module LPSandbox) la fixe au
|
||||
// demarrage depuis Config/LPSandbox.ini (cle Sandbox.Roots/QuaterniusUALRoot) ; sans
|
||||
// l'addon, le defaut interne s'applique (lot DC1 : ce module ne lit aucune config de l'addon).
|
||||
LPANIMCORE_API void SetUALRoot(const FString& Root);
|
||||
|
||||
LPANIMCORE_API const FString& GetUALRoot();
|
||||
|
||||
// Lot AP7 : clips convertis (<Prefixe><Clip>, Bridget B_, Michael M_) dans un dossier distinct de celui des
|
||||
// clips source (pack UE5 : /Game/AnimPacks/<pack>). Vide = meme dossier que les clips source (Quaternius).
|
||||
LPANIMCORE_API void SetBodyRoot(const FString& Root);
|
||||
LPANIMCORE_API FString BodyClipPath(const FString& AssetName);
|
||||
}
|
||||
215
Plugins/LPAnimCore/Source/LPAnimCore/LPCoupleSim.h
Normal file
215
Plugins/LPAnimCore/Source/LPAnimCore/LPCoupleSim.h
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
// Geometrie commune du couple (lot S5-T2, voir Docs/Migration/etat/sandbox/S5/S5-CART.md).
|
||||
// Une seule source de verite pour : la transformation mesh -> acteur, l'echantillonnage des poses,
|
||||
// le padding et le recalage de la boite englobante, le placement des corps, et le glissement du couple.
|
||||
//
|
||||
// Deux appelants, qui partagent la geometrie mais gardent leurs reglages :
|
||||
// - addon : ALPPairSandboxStage (LPSandbox/LPCoupleSim.cpp) -> FSweepOptions::Sandbox()
|
||||
// - jeu : ULPShowCoupleSubsystem (LifePlay/LPShowCoupleSubsystem.cpp) -> FSweepOptions::Show()
|
||||
//
|
||||
// Tout ce qui differe d'un cote a l'autre passe par FBoxFitParams ou FSweepOptions : le code
|
||||
// de mesure et de boite n'est plus duplique, mais aucune option n'est alignee d'office.
|
||||
// Regle du module : aucune dependance vers LifePlay ni vers LPSandbox.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Engine/EngineTypes.h"
|
||||
#include "Templates/Function.h"
|
||||
|
||||
class AActor;
|
||||
class ACharacter;
|
||||
class UAnimSequence;
|
||||
class UBoxComponent;
|
||||
class UCharacterMovementComponent;
|
||||
class UPrimitiveComponent;
|
||||
class USkeletalMeshComponent;
|
||||
class UWorld;
|
||||
|
||||
namespace LPCoupleSim
|
||||
{
|
||||
// Demi-hauteur de capsule par defaut (Person et sandbox ont la meme valeur nominale).
|
||||
inline constexpr double DefaultCapsuleHalf = 88.0;
|
||||
// Pas d'echantillonnage d'une AnimSequence (0, L/8, ... 7L/8).
|
||||
inline constexpr int32 PoseSamples = 8;
|
||||
// Normale au-dela de laquelle une surface est consideree comme un appui (marche, lit).
|
||||
inline constexpr float WalkableNormalZ = 0.6f;
|
||||
// Penetration en-dessous de laquelle on ne depenetre pas.
|
||||
inline constexpr float MinPenetrationDepth = 1.f;
|
||||
// Tolerance de comparaison de position avant teleportation.
|
||||
inline constexpr float MoveEpsilon = 0.1f;
|
||||
// Rotation du mesh squelettique sous l'acteur (lacet -90).
|
||||
inline constexpr double MeshYawDegrees = -90.0;
|
||||
|
||||
// Parametres de mesure. Les valeurs par defaut sont celles du jeu ; la sandbox surcharge
|
||||
// CapsuleHalf et FloorLocalZ (son sol est a z = +10, donc son plancher local vaut 18 - PlayerSpot.Z).
|
||||
struct FBoxFitParams
|
||||
{
|
||||
double CapsuleHalf = DefaultCapsuleHalf;
|
||||
|
||||
// Voie "animations" : FitCoupleBox (sandbox) et FitBox (jeu).
|
||||
FVector AnimPad = FVector(12.0, 12.0, 6.0);
|
||||
double AnimMaxSize = 800.0;
|
||||
|
||||
// Voie "corps vivants" : FitToBodies (jeu).
|
||||
FVector LivePad = FVector(4.0, 4.0, 4.0);
|
||||
FVector LiveMinExtent = FVector(8.0, 8.0, 8.0);
|
||||
double LiveMaxSize = 400.0;
|
||||
double LiveAnchorRadius = 140.0;
|
||||
|
||||
// Fond de boite, en Z local de l'acteur : la plante des pieds est a -CapsuleHalf.
|
||||
double FloorLocalZ = -DefaultCapsuleHalf;
|
||||
double MinExtentZ = 20.0;
|
||||
};
|
||||
|
||||
struct FBoxFit
|
||||
{
|
||||
FVector Center = FVector::ZeroVector;
|
||||
FVector Extent = FVector::ZeroVector;
|
||||
// false : mesure absente ou hors plafond ; l'appelant garde la boite precedente.
|
||||
bool bValid = false;
|
||||
};
|
||||
|
||||
// --- Niveau pur : aucun UObject, aucun UWorld. Testable sans monde. ---
|
||||
|
||||
// Transformation commune du repere du mesh vers celui de l'acteur.
|
||||
LPANIMCORE_API FTransform MeshToActor(double CapsuleHalf);
|
||||
|
||||
// Espace composant a partir des transformations locales et de la table des parents
|
||||
// (Parents[i] < i, ou INDEX_NONE pour la racine, comme dans un FReferenceSkeleton).
|
||||
LPANIMCORE_API void ComposeComponentSpace(
|
||||
const TArray<int32>& Parents, const TArray<FTransform>& Local, TArray<FTransform>& OutComponent);
|
||||
|
||||
// Ajoute la position de chaque os (espace composant) a la boite, via MeshToActor.
|
||||
LPANIMCORE_API void AccumulatePoints(
|
||||
const TArray<FTransform>& Component, const FTransform& ToActor, FBox& InOutBounds);
|
||||
|
||||
// Os ecartes de la mesure des corps vivants (extremites et accessoires : la boite suivrait une
|
||||
// main tendue). La voie "animations" ne les ecarte pas : ecart E6 de la cartographie.
|
||||
LPANIMCORE_API bool IsExcludedLiveBone(const FString& BoneName);
|
||||
|
||||
// Boite brute -> boite finale, voie "animations" : padding, plafond, recalage du fond sur FloorLocalZ.
|
||||
LPANIMCORE_API FBoxFit FitFromAnimBounds(const FBox& Bounds, const FBoxFitParams& Params);
|
||||
|
||||
// Boite brute -> boite finale, voie "corps vivants" : padding, etendue minimale, plafond. Pas de recalage.
|
||||
LPANIMCORE_API FBoxFit FitFromLiveBounds(const FBox& Bounds, const FBoxFitParams& Params);
|
||||
|
||||
// Glissement le long d'une surface. TimeFraction : 1 - Hit.Time pour la part de course restante.
|
||||
// bFlattenZ : la sandbox annule la composante verticale (son Z est verrouille par ailleurs).
|
||||
LPANIMCORE_API FVector SlideWish(
|
||||
const FVector& Wish, const FVector& Normal, float TimeFraction, bool bFlattenZ);
|
||||
|
||||
// --- Niveau lecture : assets et composants, sans effet de bord. ---
|
||||
|
||||
// Demi-hauteur reelle du personnage, avec repli (une capsule non initialisee mesure 0).
|
||||
LPANIMCORE_API double CapsuleHalfOf(const ACharacter* Who, double Fallback = DefaultCapsuleHalf);
|
||||
|
||||
// Echantillonne une AnimSequence et ajoute les os a la boite. Os animes seulement,
|
||||
// GetBoneTransform en donnees compressees (raw = false), rejet des poses NaN.
|
||||
LPANIMCORE_API bool AccumulateAnimBounds(
|
||||
const UAnimSequence* Anim, const FTransform& ToActor, FBox& InOutBounds, int32 Samples = PoseSamples);
|
||||
|
||||
// Ajoute les os affiches d'un mesh squelettique a la boite : ancre pelvis / hip, rayon
|
||||
// LiveAnchorRadius, os exclus. Le mesh doit etre a jour (appel apres le tick d'animation).
|
||||
LPANIMCORE_API void AccumulateLiveBody(
|
||||
const USkeletalMeshComponent* Mesh, const FBoxFitParams& Params, FBox& InOutBounds);
|
||||
|
||||
// --- Niveau effets de bord : boite, corps, balayage. ---
|
||||
|
||||
// Cree la boite si besoin (profil commun : objet Pawn, tout Ignore sauf WorldDynamic = Block,
|
||||
// cachee, hors navigation) et applique l'etat de collision. Retourne la boite a stocker.
|
||||
LPANIMCORE_API UBoxComponent* EnsureBox(
|
||||
ACharacter* Lead, UBoxComponent* Existing, FName Name, bool bEnabled);
|
||||
|
||||
// Etendue, centre et rotation nulle. Sans effet si Fit n'est pas valide.
|
||||
LPANIMCORE_API void ApplyBoxFit(UBoxComponent* Box, const FBoxFit& Fit);
|
||||
|
||||
// Place le mesh squelettique sous l'acteur (plante des pieds a -CapsuleHalf, lacet -90).
|
||||
LPANIMCORE_API void PlaceBodyMesh(ACharacter* Body, double CapsuleHalf);
|
||||
|
||||
// --- Soudure du partenaire ---
|
||||
|
||||
// Etat de mouvement memorise avant gel, pour le rendre a la sortie du show.
|
||||
struct FSavedMove
|
||||
{
|
||||
TWeakObjectPtr<UCharacterMovementComponent> Move;
|
||||
TEnumAsByte<EMovementMode> Mode = MOVE_None;
|
||||
float Gravity = 1.f;
|
||||
bool bTick = true;
|
||||
};
|
||||
|
||||
// Arrete le mouvement, le desactive et coupe son tick. Retourne l'etat d'avant.
|
||||
LPANIMCORE_API FSavedMove SaveAndFreeze(ACharacter* Body);
|
||||
// Rend l'etat memorise, puis vide la memoire.
|
||||
LPANIMCORE_API void RestoreMove(FSavedMove& Saved);
|
||||
|
||||
// Attache le partenaire au porteur et le pose sur son point (relatif nul).
|
||||
LPANIMCORE_API void AttachPartner(ACharacter* Lead, ACharacter* Partner);
|
||||
// Detache en gardant la position monde.
|
||||
LPANIMCORE_API void Unweld(ACharacter* Partner);
|
||||
|
||||
// --- Balayage du couple ---
|
||||
|
||||
// Tout ce qui differe entre la sandbox et le jeu. Partir de Sandbox() ou de Show().
|
||||
struct FSweepOptions
|
||||
{
|
||||
// Nombre de passes de glissement.
|
||||
int32 MaxIterations = 3;
|
||||
// SweepMultiByChannel (jeu : lits et depenetration ont besoin de tous les contacts)
|
||||
// ou SweepSingleByChannel (sandbox).
|
||||
bool bMultiSweep = true;
|
||||
// Annule la composante verticale du glissement (sandbox).
|
||||
bool bFlattenZ = false;
|
||||
// Un contact dont la normale depasse WalkableNormalZ laisse passer le pas entier (sandbox).
|
||||
// Voie simple seulement.
|
||||
bool bAcceptWalkableStep = false;
|
||||
// Sortir des penetrations au lieu de s'arreter net. Voie multiple seulement.
|
||||
bool bDepenetrate = true;
|
||||
// Ignorer tous les ACharacter du monde (jeu : les PNJ ne bloquent pas le couple).
|
||||
bool bIgnoreAllCharacters = true;
|
||||
// Appui franchissable : le couple se pose dessus au lieu d'etre bloque (jeu : les lits).
|
||||
TFunction<bool(const UPrimitiveComponent*)> IsWalkableSupport;
|
||||
// Acteur a ignorer entierement (jeu : la coque de la chambre, nommee Wall / Wall_*).
|
||||
TFunction<bool(const AActor*)> IsIgnoredShell;
|
||||
// Appele pour chaque acteur ignore par IsIgnoredShell, afin que l'appelant journalise.
|
||||
TFunction<void(const AActor*)> OnIgnoredShell;
|
||||
|
||||
// Reglages du jeu : 3 passes, balayage multiple, depenetration, PNJ et coque ignores.
|
||||
static FSweepOptions Show()
|
||||
{
|
||||
FSweepOptions Out;
|
||||
return Out;
|
||||
}
|
||||
|
||||
// Reglages de la sandbox : 2 passes, balayage simple, arret net en penetration,
|
||||
// marches franchissables, glissement a plat, aucun PNJ ignore.
|
||||
static FSweepOptions Sandbox()
|
||||
{
|
||||
FSweepOptions Out;
|
||||
Out.MaxIterations = 2;
|
||||
Out.bMultiSweep = false;
|
||||
Out.bFlattenZ = true;
|
||||
Out.bAcceptWalkableStep = true;
|
||||
Out.bDepenetrate = false;
|
||||
Out.bIgnoreAllCharacters = false;
|
||||
return Out;
|
||||
}
|
||||
};
|
||||
|
||||
struct FSweepResult
|
||||
{
|
||||
// Position d'acteur retenue (From si rien n'a bouge).
|
||||
FVector Location = FVector::ZeroVector;
|
||||
// Dernier bloqueur en penetration, "Acteur/Composant", pour le journal. Vide sinon.
|
||||
FString Blocker;
|
||||
FVector BlockerNormal = FVector::ZeroVector;
|
||||
float BlockerDepth = 0.f;
|
||||
bool bMoved = false;
|
||||
};
|
||||
|
||||
// Resout un deplacement du couple : la boite glisse, From est la position d'acteur de depart
|
||||
// (sandbox : la position courante du porteur ; jeu : la derniere position sure), Wish le
|
||||
// deplacement voulu. La fonction ne deplace rien : l'appelant applique FSweepResult::Location.
|
||||
LPANIMCORE_API FSweepResult ResolveCoupleMove(
|
||||
UWorld* World, const UBoxComponent* Box, const ACharacter* Lead, const ACharacter* Partner,
|
||||
const FVector& From, const FVector& Wish, const FSweepOptions& Options);
|
||||
}
|
||||
474
Plugins/LPAnimCore/Source/LPAnimCore/LPCoupleSimCore.cpp
Normal file
474
Plugins/LPAnimCore/Source/LPAnimCore/LPCoupleSimCore.cpp
Normal file
|
|
@ -0,0 +1,474 @@
|
|||
// Geometrie commune du couple (lot S5-T2) - voir LPCoupleSim.h.
|
||||
// Nom de fichier distinct de LPSandbox/LPCoupleSim.cpp : deux modules, deux unites de traduction.
|
||||
|
||||
#include "LPCoupleSim.h"
|
||||
|
||||
#include "Animation/AnimSequence.h"
|
||||
#include "Animation/Skeleton.h"
|
||||
#include "Components/BoxComponent.h"
|
||||
#include "Components/CapsuleComponent.h"
|
||||
#include "Components/SkeletalMeshComponent.h"
|
||||
#include "Engine/World.h"
|
||||
#include "EngineUtils.h"
|
||||
#include "GameFramework/Character.h"
|
||||
#include "GameFramework/CharacterMovementComponent.h"
|
||||
|
||||
namespace LPCoupleSim
|
||||
{
|
||||
|
||||
FTransform MeshToActor(const double CapsuleHalf)
|
||||
{
|
||||
return FTransform(FRotator(0.0, MeshYawDegrees, 0.0), FVector(0.0, 0.0, -CapsuleHalf));
|
||||
}
|
||||
|
||||
void ComposeComponentSpace(const TArray<int32>& Parents, const TArray<FTransform>& Local, TArray<FTransform>& OutComponent)
|
||||
{
|
||||
const int32 Num = Local.Num();
|
||||
OutComponent.SetNum(Num, EAllowShrinking::No);
|
||||
for (int32 Bone = 0; Bone < Num; ++Bone)
|
||||
{
|
||||
const int32 Parent = Parents.IsValidIndex(Bone) ? Parents[Bone] : INDEX_NONE;
|
||||
OutComponent[Bone] = Parent == INDEX_NONE ? Local[Bone] : Local[Bone] * OutComponent[Parent];
|
||||
}
|
||||
}
|
||||
|
||||
void AccumulatePoints(const TArray<FTransform>& Component, const FTransform& ToActor, FBox& InOutBounds)
|
||||
{
|
||||
for (const FTransform& Bone : Component)
|
||||
{
|
||||
InOutBounds += ToActor.TransformPosition(Bone.GetLocation());
|
||||
}
|
||||
}
|
||||
|
||||
bool IsExcludedLiveBone(const FString& BoneName)
|
||||
{
|
||||
static const TCHAR* Excluded[] = {
|
||||
TEXT("hand"), TEXT("finger"), TEXT("foot"), TEXT("toe"), TEXT("twist"),
|
||||
TEXT("breast"), TEXT("hair"), TEXT("eye"), TEXT("jaw"), TEXT("weapon"), TEXT("ik")
|
||||
};
|
||||
for (const TCHAR* Part : Excluded)
|
||||
{
|
||||
if (BoneName.Contains(Part, ESearchCase::IgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
FBoxFit FitFromAnimBounds(const FBox& Bounds, const FBoxFitParams& Params)
|
||||
{
|
||||
FBoxFit Fit;
|
||||
if (!Bounds.IsValid || Bounds.GetSize().GetMax() > Params.AnimMaxSize)
|
||||
{
|
||||
return Fit;
|
||||
}
|
||||
Fit.Center = Bounds.GetCenter();
|
||||
Fit.Extent = Bounds.GetExtent() + Params.AnimPad;
|
||||
const double Bottom = Fit.Center.Z - Fit.Extent.Z;
|
||||
if (Bottom < Params.FloorLocalZ)
|
||||
{
|
||||
const double Cut = Params.FloorLocalZ - Bottom;
|
||||
Fit.Extent.Z = FMath::Max(Params.MinExtentZ, Fit.Extent.Z - Cut * 0.5);
|
||||
Fit.Center.Z += Cut * 0.5;
|
||||
}
|
||||
Fit.bValid = true;
|
||||
return Fit;
|
||||
}
|
||||
|
||||
FBoxFit FitFromLiveBounds(const FBox& Bounds, const FBoxFitParams& Params)
|
||||
{
|
||||
FBoxFit Fit;
|
||||
if (!Bounds.IsValid || Bounds.GetSize().GetMax() > Params.LiveMaxSize)
|
||||
{
|
||||
return Fit;
|
||||
}
|
||||
Fit.Center = Bounds.GetCenter();
|
||||
Fit.Extent = Bounds.GetExtent() + Params.LivePad;
|
||||
Fit.Extent.X = FMath::Max(Fit.Extent.X, Params.LiveMinExtent.X);
|
||||
Fit.Extent.Y = FMath::Max(Fit.Extent.Y, Params.LiveMinExtent.Y);
|
||||
Fit.Extent.Z = FMath::Max(Fit.Extent.Z, Params.LiveMinExtent.Z);
|
||||
Fit.bValid = true;
|
||||
return Fit;
|
||||
}
|
||||
|
||||
FVector SlideWish(const FVector& Wish, const FVector& Normal, const float TimeFraction, const bool bFlattenZ)
|
||||
{
|
||||
FVector Out = FVector::VectorPlaneProject(Wish * TimeFraction, Normal);
|
||||
if (bFlattenZ)
|
||||
{
|
||||
Out.Z = 0.0;
|
||||
}
|
||||
return Out;
|
||||
}
|
||||
|
||||
double CapsuleHalfOf(const ACharacter* Who, const double Fallback)
|
||||
{
|
||||
const UCapsuleComponent* Cap = Who ? Who->GetCapsuleComponent() : nullptr;
|
||||
return (Cap && Cap->GetUnscaledCapsuleHalfHeight() > 1.f) ? Cap->GetUnscaledCapsuleHalfHeight() : Fallback;
|
||||
}
|
||||
|
||||
bool AccumulateAnimBounds(const UAnimSequence* Anim, const FTransform& ToActor, FBox& InOutBounds, const int32 Samples)
|
||||
{
|
||||
const USkeleton* Skeleton = Anim ? Anim->GetSkeleton() : nullptr;
|
||||
if (!Skeleton || Samples <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const FReferenceSkeleton& Ref = Skeleton->GetReferenceSkeleton();
|
||||
const TArray<FTransform>& RefPose = Ref.GetRefBonePose();
|
||||
const int32 Num = RefPose.Num();
|
||||
if (Num <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Seuls les os pilotes par le clip sont lus ; les autres gardent leur repos.
|
||||
TArray<int32> Animated;
|
||||
for (const FTrackToSkeletonMap& Track : Anim->GetCompressedTrackToSkeletonMapTable())
|
||||
{
|
||||
if (RefPose.IsValidIndex(Track.BoneTreeIndex))
|
||||
{
|
||||
Animated.Add(Track.BoneTreeIndex);
|
||||
}
|
||||
}
|
||||
TArray<int32> Parents;
|
||||
Parents.SetNumUninitialized(Num);
|
||||
for (int32 Bone = 0; Bone < Num; ++Bone)
|
||||
{
|
||||
Parents[Bone] = Ref.GetParentIndex(Bone);
|
||||
}
|
||||
const double Length = FMath::Max(Anim->GetPlayLength(), 0.01);
|
||||
TArray<FTransform> Local;
|
||||
TArray<FTransform> Component;
|
||||
Local.SetNum(Num);
|
||||
Component.SetNum(Num);
|
||||
for (int32 Step = 0; Step < Samples; ++Step)
|
||||
{
|
||||
const double Time = Length * Step / static_cast<double>(Samples);
|
||||
for (int32 Bone = 0; Bone < Num; ++Bone)
|
||||
{
|
||||
Local[Bone] = RefPose[Bone];
|
||||
}
|
||||
for (const int32 Index : Animated)
|
||||
{
|
||||
FTransform Xform = RefPose[Index];
|
||||
Anim->GetBoneTransform(Xform, FSkeletonPoseBoneIndex(Index), Time, false);
|
||||
if (!Xform.ContainsNaN())
|
||||
{
|
||||
Local[Index] = Xform;
|
||||
}
|
||||
}
|
||||
ComposeComponentSpace(Parents, Local, Component);
|
||||
AccumulatePoints(Component, ToActor, InOutBounds);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AccumulateLiveBody(const USkeletalMeshComponent* Mesh, const FBoxFitParams& Params, FBox& InOutBounds)
|
||||
{
|
||||
if (!Mesh)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const TArray<FTransform>& Bones = Mesh->GetComponentSpaceTransforms();
|
||||
const int32 Num = Bones.Num();
|
||||
if (Num <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
const FTransform ToActor = Mesh->GetRelativeTransform();
|
||||
int32 Pelvis = INDEX_NONE;
|
||||
for (int32 Bone = 0; Bone < Num; ++Bone)
|
||||
{
|
||||
const FName Name = Mesh->GetBoneName(Bone);
|
||||
if (Name == TEXT("pelvis") || Name == TEXT("hip"))
|
||||
{
|
||||
Pelvis = Bone;
|
||||
break;
|
||||
}
|
||||
}
|
||||
FVector Anchor = FVector::ZeroVector;
|
||||
const bool bAnchor = Pelvis != INDEX_NONE && !Bones[Pelvis].ContainsNaN();
|
||||
if (bAnchor)
|
||||
{
|
||||
Anchor = ToActor.TransformPosition(Bones[Pelvis].GetLocation());
|
||||
}
|
||||
const double RadiusSquared = Params.LiveAnchorRadius * Params.LiveAnchorRadius;
|
||||
for (int32 Bone = 0; Bone < Num; ++Bone)
|
||||
{
|
||||
if (Bones[Bone].ContainsNaN() || IsExcludedLiveBone(Mesh->GetBoneName(Bone).ToString()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const FVector Point = ToActor.TransformPosition(Bones[Bone].GetLocation());
|
||||
if (bAnchor && FVector::DistSquared(Point, Anchor) > RadiusSquared)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
InOutBounds += Point;
|
||||
}
|
||||
}
|
||||
|
||||
UBoxComponent* EnsureBox(ACharacter* Lead, UBoxComponent* Existing, const FName Name, const bool bEnabled)
|
||||
{
|
||||
if (!Lead)
|
||||
{
|
||||
return Existing;
|
||||
}
|
||||
UBoxComponent* Box = Existing;
|
||||
if (!Box)
|
||||
{
|
||||
Box = NewObject<UBoxComponent>(Lead, Name);
|
||||
Box->SetupAttachment(Lead->GetRootComponent());
|
||||
Box->SetCollisionObjectType(ECC_Pawn);
|
||||
Box->SetCollisionResponseToAllChannels(ECR_Ignore);
|
||||
Box->SetCollisionResponseToChannel(ECC_WorldDynamic, ECR_Block);
|
||||
Box->SetHiddenInGame(true);
|
||||
Box->SetCanEverAffectNavigation(false);
|
||||
Box->RegisterComponent();
|
||||
}
|
||||
Box->SetCollisionEnabled(bEnabled ? ECollisionEnabled::QueryAndPhysics : ECollisionEnabled::NoCollision);
|
||||
return Box;
|
||||
}
|
||||
|
||||
void ApplyBoxFit(UBoxComponent* Box, const FBoxFit& Fit)
|
||||
{
|
||||
if (!Box || !Fit.bValid)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Box->SetBoxExtent(Fit.Extent);
|
||||
Box->SetRelativeLocation(Fit.Center);
|
||||
Box->SetRelativeRotation(FRotator::ZeroRotator);
|
||||
}
|
||||
|
||||
void PlaceBodyMesh(ACharacter* Body, const double CapsuleHalf)
|
||||
{
|
||||
if (USkeletalMeshComponent* Mesh = Body ? Body->GetMesh() : nullptr)
|
||||
{
|
||||
Mesh->SetRelativeLocation(FVector(0.0, 0.0, -CapsuleHalf));
|
||||
Mesh->SetRelativeRotation(FRotator(0.0, MeshYawDegrees, 0.0));
|
||||
}
|
||||
}
|
||||
|
||||
FSavedMove SaveAndFreeze(ACharacter* Body)
|
||||
{
|
||||
FSavedMove Saved;
|
||||
UCharacterMovementComponent* Move = Body ? Body->GetCharacterMovement() : nullptr;
|
||||
if (!Move)
|
||||
{
|
||||
return Saved;
|
||||
}
|
||||
Saved.Move = Move;
|
||||
Saved.Mode = Move->MovementMode;
|
||||
Saved.Gravity = Move->GravityScale;
|
||||
Saved.bTick = Move->IsComponentTickEnabled();
|
||||
Move->StopMovementImmediately();
|
||||
Move->DisableMovement();
|
||||
Move->SetComponentTickEnabled(false);
|
||||
return Saved;
|
||||
}
|
||||
|
||||
void RestoreMove(FSavedMove& Saved)
|
||||
{
|
||||
if (UCharacterMovementComponent* Move = Saved.Move.Get())
|
||||
{
|
||||
Move->SetComponentTickEnabled(Saved.bTick);
|
||||
Move->SetMovementMode(Saved.Mode);
|
||||
Move->GravityScale = Saved.Gravity;
|
||||
}
|
||||
Saved = FSavedMove();
|
||||
}
|
||||
|
||||
void AttachPartner(ACharacter* Lead, ACharacter* Partner)
|
||||
{
|
||||
if (!Lead || !Partner)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (Partner->GetAttachParentActor() != Lead)
|
||||
{
|
||||
Partner->AttachToActor(Lead, FAttachmentTransformRules::SnapToTargetNotIncludingScale);
|
||||
}
|
||||
Partner->SetActorRelativeLocation(FVector::ZeroVector);
|
||||
Partner->SetActorRelativeRotation(FRotator::ZeroRotator);
|
||||
}
|
||||
|
||||
void Unweld(ACharacter* Partner)
|
||||
{
|
||||
if (Partner)
|
||||
{
|
||||
Partner->DetachFromActor(FDetachmentTransformRules::KeepWorldTransform);
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
// Voie simple (sandbox) : un contact a la fois, arret net en penetration, marches franchissables.
|
||||
void ResolveSingle(UWorld& World, const FCollisionShape& Shape, const FQuat& Rot, const FVector& BoxOffset,
|
||||
const FCollisionQueryParams& Params, const FSweepOptions& Options, const FVector& Wish, FVector& InOutBase)
|
||||
{
|
||||
FVector Slide = Wish;
|
||||
for (int32 Step = 0; Step < Options.MaxIterations && !Slide.IsNearlyZero(); ++Step)
|
||||
{
|
||||
const FVector Start = InOutBase + BoxOffset;
|
||||
FHitResult Hit;
|
||||
const bool bHit = World.SweepSingleByChannel(Hit, Start, Start + Slide, Rot, ECC_Pawn, Shape, Params);
|
||||
if (bHit && Options.bAcceptWalkableStep && Hit.Normal.Z > WalkableNormalZ)
|
||||
{
|
||||
InOutBase += Slide;
|
||||
return;
|
||||
}
|
||||
const FVector StepDelta = Slide * (bHit ? Hit.Time : 1.f);
|
||||
if (!StepDelta.IsNearlyZero() && !Hit.bStartPenetrating)
|
||||
{
|
||||
InOutBase += StepDelta;
|
||||
}
|
||||
if (!bHit || Hit.bStartPenetrating)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Slide = SlideWish(Slide, Hit.Normal, 1.f - Hit.Time, Options.bFlattenZ);
|
||||
}
|
||||
}
|
||||
|
||||
// Voie multiple (jeu) : tous les contacts, depenetration, appuis franchissables.
|
||||
void ResolveMulti(UWorld& World, const FCollisionShape& Shape, const FQuat& Rot, const FVector& BoxOffset,
|
||||
const FCollisionQueryParams& Params, const FSweepOptions& Options, const FVector& Wish,
|
||||
FVector& InOutBase, FSweepResult& InOutResult)
|
||||
{
|
||||
FVector Slide = Wish;
|
||||
for (int32 Step = 0; Step < Options.MaxIterations; ++Step)
|
||||
{
|
||||
const FVector Start = InOutBase + BoxOffset;
|
||||
TArray<FHitResult> Hits;
|
||||
World.SweepMultiByChannel(Hits, Start, Start + Slide, Rot, ECC_Pawn, Shape, Params);
|
||||
const FHitResult* Block = nullptr;
|
||||
const FHitResult* Deepest = nullptr;
|
||||
FVector Exit = FVector::ZeroVector;
|
||||
bool bStopNet = false;
|
||||
for (const FHitResult& Hit : Hits)
|
||||
{
|
||||
if (Options.IsWalkableSupport && Options.IsWalkableSupport(Hit.GetComponent()))
|
||||
{
|
||||
// Descente sur l'appui : on s'y pose. Deja dedans : on annule la descente et on le traverse.
|
||||
if (!Hit.bStartPenetrating && Hit.Normal.Z > WalkableNormalZ && Slide.Z < -1.f)
|
||||
{
|
||||
Block = &Hit;
|
||||
break;
|
||||
}
|
||||
if (Hit.bStartPenetrating && Hit.Normal.Z > WalkableNormalZ && Slide.Z < 0.f)
|
||||
{
|
||||
Slide.Z = 0.0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (Hit.bStartPenetrating)
|
||||
{
|
||||
if (!Options.bDepenetrate)
|
||||
{
|
||||
bStopNet = true;
|
||||
break;
|
||||
}
|
||||
if (Hit.PenetrationDepth < MinPenetrationDepth)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!Deepest || Hit.PenetrationDepth > Deepest->PenetrationDepth)
|
||||
{
|
||||
Deepest = &Hit;
|
||||
Exit = Hit.Normal * Hit.PenetrationDepth;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
Block = &Hit;
|
||||
break;
|
||||
}
|
||||
if (bStopNet)
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Mur vertical traverse et course qui pointe dedans : le glissement longe le mur.
|
||||
if (Deepest && FMath::Abs(Deepest->Normal.Z) <= WalkableNormalZ && (Slide | Deepest->Normal) < 0.f)
|
||||
{
|
||||
InOutResult.Blocker = FString::Printf(TEXT("%s/%s"),
|
||||
*GetNameSafe(Deepest->GetActor()), *GetNameSafe(Deepest->GetComponent()));
|
||||
InOutResult.BlockerNormal = Deepest->Normal;
|
||||
InOutResult.BlockerDepth = Deepest->PenetrationDepth;
|
||||
Slide = SlideWish(Slide, Deepest->Normal, 1.f, Options.bFlattenZ);
|
||||
}
|
||||
if (!Exit.IsNearlyZero())
|
||||
{
|
||||
InOutBase += Exit;
|
||||
continue;
|
||||
}
|
||||
if (Slide.IsNearlyZero())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!Block)
|
||||
{
|
||||
InOutBase += Slide;
|
||||
return;
|
||||
}
|
||||
InOutBase += Slide * Block->Time;
|
||||
Slide = SlideWish(Slide, Block->Normal, 1.f - Block->Time, Options.bFlattenZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FSweepResult ResolveCoupleMove(UWorld* World, const UBoxComponent* Box, const ACharacter* Lead,
|
||||
const ACharacter* Partner, const FVector& From, const FVector& Wish, const FSweepOptions& Options)
|
||||
{
|
||||
FSweepResult Result;
|
||||
Result.Location = From;
|
||||
if (!World || !Box || !Lead || Wish.IsNearlyZero())
|
||||
{
|
||||
return Result;
|
||||
}
|
||||
FCollisionQueryParams Params(SCENE_QUERY_STAT(LPCoupleSim), false, Lead);
|
||||
if (Partner)
|
||||
{
|
||||
Params.AddIgnoredActor(Partner);
|
||||
}
|
||||
if (Options.bIgnoreAllCharacters)
|
||||
{
|
||||
for (TActorIterator<ACharacter> It(World); It; ++It)
|
||||
{
|
||||
Params.AddIgnoredActor(*It);
|
||||
}
|
||||
}
|
||||
if (Options.IsIgnoredShell)
|
||||
{
|
||||
for (TActorIterator<AActor> It(World); It; ++It)
|
||||
{
|
||||
if (!Options.IsIgnoredShell(*It))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Params.AddIgnoredActor(*It);
|
||||
if (Options.OnIgnoredShell)
|
||||
{
|
||||
Options.OnIgnoredShell(*It);
|
||||
}
|
||||
}
|
||||
}
|
||||
// La boite suit le porteur : son decalage monde est fixe pendant la resolution (la rotation ne change pas).
|
||||
const FVector BoxOffset = Box->GetComponentLocation() - Lead->GetActorLocation();
|
||||
const FCollisionShape Shape = FCollisionShape::MakeBox(Box->GetScaledBoxExtent());
|
||||
const FQuat Rot = Box->GetComponentQuat();
|
||||
FVector Base = From;
|
||||
if (Options.bMultiSweep)
|
||||
{
|
||||
ResolveMulti(*World, Shape, Rot, BoxOffset, Params, Options, Wish, Base, Result);
|
||||
}
|
||||
else
|
||||
{
|
||||
ResolveSingle(*World, Shape, Rot, BoxOffset, Params, Options, Wish, Base);
|
||||
}
|
||||
Result.Location = Base;
|
||||
Result.bMoved = !Base.Equals(From, MoveEpsilon);
|
||||
return Result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -40,9 +40,9 @@ public class LifePlay : ModuleRules
|
|||
// Releve de collision (-LPCollisionLog) : nombre de triangles des trimesh Chaos.
|
||||
PrivateDependencyModuleNames.Add("Chaos");
|
||||
|
||||
// Lot S2 / S3 : LPAnimMeasure (plugin LPSandbox) — LPDirectControlSubsystem et
|
||||
// LifePlayEditorTools incluent LPAnimRedirect / LPPoseMeasure.
|
||||
PublicDependencyModuleNames.Add("LPAnimMeasure");
|
||||
// Lot DC1 : LPAnimCore (plugin du jeu, Plugins/LPAnimCore) — LPDirectControlSubsystem inclut
|
||||
// LPAnimRedirect, LPShowCoupleSubsystem.h inclut LPCoupleSim (dependance publique).
|
||||
PublicDependencyModuleNames.Add("LPAnimCore");
|
||||
|
||||
// Uncomment if you are using Slate UI
|
||||
// PrivateDependencyModuleNames.AddRange(new string[] { "Slate", "SlateCore" });
|
||||
|
|
|
|||
Loading…
Reference in a new issue