201 lines
5.2 KiB
C#
201 lines
5.2 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace ARLocation
|
|
{
|
|
public class WorldBuilder : MonoBehaviour
|
|
{
|
|
public PrefabDatabase PrefabDatabase;
|
|
public string Id = "World";
|
|
public bool UseLocalStorage;
|
|
|
|
[System.Serializable]
|
|
public class Entry
|
|
{
|
|
public Location Location;
|
|
public float Rotation;
|
|
public string MeshId;
|
|
|
|
[System.NonSerialized]
|
|
public GameObject Instance;
|
|
}
|
|
|
|
[System.Serializable]
|
|
public class World
|
|
{
|
|
public List<Entry> Entries = new List<Entry>();
|
|
}
|
|
|
|
class State
|
|
{
|
|
public World World = new World();
|
|
}
|
|
|
|
private readonly State state = new State();
|
|
|
|
public World GetWorld()
|
|
{
|
|
return state.World;
|
|
}
|
|
|
|
private bool initialized;
|
|
|
|
public bool Initialized => initialized;
|
|
|
|
IEnumerator Start()
|
|
{
|
|
yield return StartCoroutine(WaitForLocationServices());
|
|
|
|
if (UseLocalStorage)
|
|
{
|
|
RestoreWorldFromLocalStorage();
|
|
}
|
|
|
|
initialized = true;
|
|
}
|
|
|
|
IEnumerator WaitForLocationServices()
|
|
{
|
|
while (!ARLocationProvider.Instance.IsEnabled)
|
|
{
|
|
yield return new WaitForSeconds(0.1f);
|
|
}
|
|
}
|
|
|
|
public void AddEntry(string meshId, Vector3 worldPosition, float rotation = 0)
|
|
{
|
|
var location = ARLocationManager.Instance.GetLocationForWorldPosition(worldPosition);
|
|
var entry = new Entry { Location = location, MeshId = meshId, Rotation = rotation };
|
|
state.World.Entries.Add(entry);
|
|
PlaceEntryAtLocation(entry);
|
|
}
|
|
|
|
void OnDestroy()
|
|
{
|
|
SaveWorld();
|
|
}
|
|
|
|
void OnApplicationPause(bool pause)
|
|
{
|
|
if (pause) SaveWorld();
|
|
}
|
|
|
|
void PlaceWorld()
|
|
{
|
|
state.World.Entries.ForEach(PlaceEntryAtLocation);
|
|
}
|
|
|
|
void PlaceEntryAtLocation(Entry entry)
|
|
{
|
|
var prefab = PrefabDatabase.GetEntryById(entry.MeshId);
|
|
|
|
if (prefab == null)
|
|
{
|
|
Debug.LogWarning($"Invalid prefab '{entry.MeshId}'");
|
|
return;
|
|
}
|
|
|
|
var location = entry.Location;
|
|
var options = new PlaceAtLocation.PlaceAtOptions { };
|
|
|
|
entry.Instance = PlaceAtLocation.CreatePlacedInstance(prefab, location, options, false);
|
|
entry.Instance.transform.localEulerAngles = new Vector3(0, entry.Rotation, 0);
|
|
}
|
|
|
|
public string ToJson()
|
|
{
|
|
return JsonUtility.ToJson(state.World);
|
|
}
|
|
|
|
public void FromJson(string json)
|
|
{
|
|
ClearWorld();
|
|
state.World = JsonUtility.FromJson<World>(json);
|
|
PlaceWorld();
|
|
}
|
|
|
|
string GetJsonFilename()
|
|
{
|
|
var s = Id.Trim();
|
|
|
|
if (s == "") s = "World";
|
|
|
|
return Application.persistentDataPath + "/" + s + ".json";
|
|
}
|
|
|
|
public void SaveWorld()
|
|
{
|
|
if (!UseLocalStorage) return;
|
|
|
|
string json = JsonUtility.ToJson(state.World);
|
|
Debug.Log(json);
|
|
|
|
try
|
|
{
|
|
System.IO.File.WriteAllText(GetJsonFilename(), json);
|
|
}
|
|
catch
|
|
{
|
|
Debug.Log("[ARLocation::WorldBuilder::SaveWorld]: Failed to open json file for writing.");
|
|
return;
|
|
}
|
|
|
|
Debug.Log($"Written to json file '{GetJsonFilename()}'");
|
|
}
|
|
|
|
public void RestoreWorldFromLocalStorage()
|
|
{
|
|
if (!UseLocalStorage) return;
|
|
|
|
string json = "";
|
|
try
|
|
{
|
|
json = System.IO.File.ReadAllText(GetJsonFilename(), System.Text.Encoding.UTF8);
|
|
}
|
|
catch
|
|
{
|
|
Debug.Log("[ARLocation::WorldBuilder::RestoreWorld]: Failed to open json file for reading.");
|
|
return;
|
|
}
|
|
|
|
state.World = JsonUtility.FromJson<World>(json);
|
|
PlaceWorld();
|
|
Debug.Log($"Restored world from json file '{GetJsonFilename()}'");
|
|
}
|
|
|
|
public void ClearWorld()
|
|
{
|
|
state.World.Entries.ForEach(e => {
|
|
if (e.Instance != null)
|
|
{
|
|
Destroy(e.Instance);
|
|
}
|
|
});
|
|
state.World = new World();
|
|
}
|
|
|
|
internal void MoveEntry(Entry entry, Vector3 point)
|
|
{
|
|
var location = ARLocationManager.Instance.GetLocationForWorldPosition(point);
|
|
entry.Location = location;
|
|
|
|
if (entry.Instance != null)
|
|
{
|
|
var placeAt = entry.Instance.GetComponent<PlaceAtLocation>();
|
|
|
|
if (placeAt != null)
|
|
{
|
|
placeAt.Location = location;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void RemoveEntry(Entry entry)
|
|
{
|
|
Destroy(entry.Instance);
|
|
state.World.Entries.Remove(entry);
|
|
}
|
|
}
|
|
}
|