using MyInfoMate.Vr.Manifest; using MyInfoMate.Vr.Scene; using UnityEngine; namespace MyInfoMate.Vr.Boot { /// /// Point d'entrée de l'étape S2 : la scène n'est plus codée en dur, elle est /// construite à partir d'un JSON. /// /// Remplace , à garder côte à côte le temps de valider /// S1 : l'un prouve la chaîne technique, l'autre prouve le contrat de données. /// /// Le manifeste est ici un fichier de StreamingAssets, poussé sur le casque à la /// main (adb push ou MQDH). En S6 il viendra du réseau et du cache disque /// — et ne changera pas d'une ligne, c'est le but. /// public class S2Bootstrap : MonoBehaviour { [Header("Manifeste dans Assets/StreamingAssets")] [SerializeField] string manifestFile = "scene.json"; [Header("Langue de démarrage — vide = langue par défaut du manifeste")] [SerializeField] string language = ""; SceneBuilder _builder; async void Start() { var head = Camera.main != null ? Camera.main.transform : null; if (head == null) Debug.LogError("[S2] Aucune caméra active : le rig VR n'est pas dans la scène. " + "Meta → Tools → Building Blocks → Camera Rig."); var rig = head != null ? head.root : null; var url = ManifestUrl(); var result = await ManifestReader.LoadAsync(url); if (!result.Ok) { // Le refus est le livrable : on affiche la phrase, on ne charge rien, // et on ne laisse pas une scène vide faire croire à une panne. SceneMessage.Show(result.Error, head); return; } _builder = gameObject.AddComponent(); var chosen = string.IsNullOrEmpty(language) ? result.Manifest.DefaultLanguage : language; if (!await _builder.BuildAsync(result.Manifest, head, rig, chosen)) SceneMessage.Show("Le décor de cette scène n'a pas pu être chargé.", head); } /// /// Un manifeste poussé sur le casque l'emporte sur celui de l'APK : /// adb push scene.json /sdcard/Android/data/<package>/files/. /// /// C'est ce qui rend S2 vérifiable. Lu depuis StreamingAssets, le manifeste /// est dans l'APK : changer une valeur demanderait un rebuild, et le /// critère « on modifie le JSON, on relance, sans recompiler » n'aurait plus /// d'objet. En S6 la même priorité vaudra pour le cache disque. /// string ManifestUrl() { var pushed = System.IO.Path.Combine(Application.persistentDataPath, manifestFile); if (!System.IO.File.Exists(pushed)) return GltfLoader.StreamingAssetsUrl(manifestFile); Debug.Log($"[S2] Manifeste poussé : {pushed}"); return new System.Uri(pushed).AbsoluteUri; } } }