WorldBuilder.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. namespace ARLocation
  5. {
  6. public class WorldBuilder : MonoBehaviour
  7. {
  8. public PrefabDatabase PrefabDatabase;
  9. public string Id = "World";
  10. public bool UseLocalStorage;
  11. [System.Serializable]
  12. public class Entry
  13. {
  14. public Location Location;
  15. public float Rotation;
  16. public string MeshId;
  17. [System.NonSerialized]
  18. public GameObject Instance;
  19. }
  20. [System.Serializable]
  21. public class World
  22. {
  23. public List<Entry> Entries = new List<Entry>();
  24. }
  25. class State
  26. {
  27. public World World = new World();
  28. }
  29. private readonly State state = new State();
  30. public World GetWorld()
  31. {
  32. return state.World;
  33. }
  34. private bool initialized;
  35. public bool Initialized => initialized;
  36. IEnumerator Start()
  37. {
  38. yield return StartCoroutine(WaitForLocationServices());
  39. if (UseLocalStorage)
  40. {
  41. RestoreWorldFromLocalStorage();
  42. }
  43. initialized = true;
  44. }
  45. IEnumerator WaitForLocationServices()
  46. {
  47. while (!ARLocationProvider.Instance.IsEnabled)
  48. {
  49. yield return new WaitForSeconds(0.1f);
  50. }
  51. }
  52. public void AddEntry(string meshId, Vector3 worldPosition, float rotation = 0)
  53. {
  54. var location = ARLocationManager.Instance.GetLocationForWorldPosition(worldPosition);
  55. var entry = new Entry { Location = location, MeshId = meshId, Rotation = rotation };
  56. state.World.Entries.Add(entry);
  57. PlaceEntryAtLocation(entry);
  58. }
  59. void OnDestroy()
  60. {
  61. SaveWorld();
  62. }
  63. void OnApplicationPause(bool pause)
  64. {
  65. if (pause) SaveWorld();
  66. }
  67. void PlaceWorld()
  68. {
  69. state.World.Entries.ForEach(PlaceEntryAtLocation);
  70. }
  71. void PlaceEntryAtLocation(Entry entry)
  72. {
  73. var prefab = PrefabDatabase.GetEntryById(entry.MeshId);
  74. if (prefab == null)
  75. {
  76. Debug.LogWarning($"Invalid prefab '{entry.MeshId}'");
  77. return;
  78. }
  79. var location = entry.Location;
  80. var options = new PlaceAtLocation.PlaceAtOptions { };
  81. entry.Instance = PlaceAtLocation.CreatePlacedInstance(prefab, location, options, false);
  82. entry.Instance.transform.localEulerAngles = new Vector3(0, entry.Rotation, 0);
  83. }
  84. public string ToJson()
  85. {
  86. return JsonUtility.ToJson(state.World);
  87. }
  88. public void FromJson(string json)
  89. {
  90. ClearWorld();
  91. state.World = JsonUtility.FromJson<World>(json);
  92. PlaceWorld();
  93. }
  94. string GetJsonFilename()
  95. {
  96. var s = Id.Trim();
  97. if (s == "") s = "World";
  98. return Application.persistentDataPath + "/" + s + ".json";
  99. }
  100. public void SaveWorld()
  101. {
  102. if (!UseLocalStorage) return;
  103. string json = JsonUtility.ToJson(state.World);
  104. Debug.Log(json);
  105. try
  106. {
  107. System.IO.File.WriteAllText(GetJsonFilename(), json);
  108. }
  109. catch
  110. {
  111. Debug.Log("[ARLocation::WorldBuilder::SaveWorld]: Failed to open json file for writing.");
  112. return;
  113. }
  114. Debug.Log($"Written to json file '{GetJsonFilename()}'");
  115. }
  116. public void RestoreWorldFromLocalStorage()
  117. {
  118. if (!UseLocalStorage) return;
  119. string json = "";
  120. try
  121. {
  122. json = System.IO.File.ReadAllText(GetJsonFilename(), System.Text.Encoding.UTF8);
  123. }
  124. catch
  125. {
  126. Debug.Log("[ARLocation::WorldBuilder::RestoreWorld]: Failed to open json file for reading.");
  127. return;
  128. }
  129. state.World = JsonUtility.FromJson<World>(json);
  130. PlaceWorld();
  131. Debug.Log($"Restored world from json file '{GetJsonFilename()}'");
  132. }
  133. public void ClearWorld()
  134. {
  135. state.World.Entries.ForEach(e => {
  136. if (e.Instance != null)
  137. {
  138. Destroy(e.Instance);
  139. }
  140. });
  141. state.World = new World();
  142. }
  143. internal void MoveEntry(Entry entry, Vector3 point)
  144. {
  145. var location = ARLocationManager.Instance.GetLocationForWorldPosition(point);
  146. entry.Location = location;
  147. if (entry.Instance != null)
  148. {
  149. var placeAt = entry.Instance.GetComponent<PlaceAtLocation>();
  150. if (placeAt != null)
  151. {
  152. placeAt.Location = location;
  153. }
  154. }
  155. }
  156. public void RemoveEntry(Entry entry)
  157. {
  158. Destroy(entry.Instance);
  159. state.World.Entries.Remove(entry);
  160. }
  161. }
  162. }