Premier commit du cinquième front. Trois parties : - `unity/MyInfoMateVR/` : le projet Unity (6000.0.83f1, URP, Meta XR SDK 205), un APK unique pour tous les clients. Menu flottant à sélection au regard, appairage, chargement de scène GLB, POI, cache de contenu, télémétrie. - `unity-overlay/` : les mêmes scripts à recopier sur un projet Unity neuf, avec les pièges rencontrés consignés dans son README. - `viewer/` : viewer et éditeur de scène web autonome (Vite, TypeScript, three.js), partagé avec les autres fronts. - `docs/` : état des lieux, setup Unity, décisions d'architecture et plan d'exécution en 9 étapes. La scène est décrite par un `scene.json` poussé par `adb push` : l'app le préfère à celui embarqué dans l'APK. Les binaires (GLB, textures de l'échantillon Sponza, DLL Meta XR) passent par Git LFS dès ce premier commit — les y faire entrer après coup demanderait de réécrire l'historique. Les artefacts régénérés par l'éditeur et par CMake (`Library/`, `.utmp/`, Burst debug) sont ignorés. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
77 lines
3.1 KiB
C#
77 lines
3.1 KiB
C#
using MyInfoMate.Vr.Manifest;
|
|
using MyInfoMate.Vr.Scene;
|
|
using UnityEngine;
|
|
|
|
namespace MyInfoMate.Vr.Boot
|
|
{
|
|
/// <summary>
|
|
/// Point d'entrée de l'étape S2 : la scène n'est plus codée en dur, elle est
|
|
/// <b>construite à partir d'un JSON</b>.
|
|
///
|
|
/// Remplace <see cref="S1Bootstrap"/>, à 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 (<c>adb push</c> ou MQDH). En S6 il viendra du réseau et du cache disque
|
|
/// — et <see cref="SceneBuilder"/> ne changera pas d'une ligne, c'est le but.
|
|
/// </summary>
|
|
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<SceneBuilder>();
|
|
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Un manifeste poussé sur le casque l'emporte sur celui de l'APK :
|
|
/// <c>adb push scene.json /sdcard/Android/data/<package>/files/</c>.
|
|
///
|
|
/// C'est ce qui rend S2 vérifiable. Lu depuis StreamingAssets, le manifeste
|
|
/// est <b>dans</b> 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.
|
|
/// </summary>
|
|
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;
|
|
}
|
|
}
|
|
}
|