318 lines
11 KiB
C#
318 lines
11 KiB
C#
|
|
using System;
|
||
|
|
using System.Collections;
|
||
|
|
using UnityEngine;
|
||
|
|
using UnityEngine.Events;
|
||
|
|
using UnityEngine.Serialization;
|
||
|
|
// ReSharper disable UnusedMember.Global
|
||
|
|
|
||
|
|
|
||
|
|
namespace ARLocation
|
||
|
|
{
|
||
|
|
using Utils;
|
||
|
|
|
||
|
|
[AddComponentMenu("AR+GPS/AR Location Provider")]
|
||
|
|
[HelpURL("https://http://docs.unity-ar-gps-location.com/guide/#arlocationprovider")]
|
||
|
|
[DisallowMultipleComponent]
|
||
|
|
public class ARLocationProvider : Singleton<ARLocationProvider>
|
||
|
|
{
|
||
|
|
[Serializable]
|
||
|
|
public class LocationEnabledUnityEvent : UnityEvent<Location> { }
|
||
|
|
[Serializable]
|
||
|
|
public class LocationUpdatedUnityEvent : UnityEvent<Location> { }
|
||
|
|
|
||
|
|
[Serializable]
|
||
|
|
public class CompassUpdatedUnityEvent : UnityEvent<HeadingReading> { }
|
||
|
|
|
||
|
|
[FormerlySerializedAs("LocationUpdateSettings")]
|
||
|
|
[Tooltip("The options for the Location Provider.")]
|
||
|
|
[Header("Update Settings")]
|
||
|
|
public LocationProviderOptions LocationProviderSettings = new LocationProviderOptions();
|
||
|
|
|
||
|
|
[Tooltip("The data of mock location. If present, overrides the Mock Location above.")]
|
||
|
|
[Header("Mock Data")]
|
||
|
|
public LocationData MockLocationData;
|
||
|
|
|
||
|
|
[Tooltip("The maximum wait time to wait for location initialization.")]
|
||
|
|
[Header("Initialization")]
|
||
|
|
public uint MaxWaitTime = 200;
|
||
|
|
|
||
|
|
[Tooltip("Wait this many seconds before starting location services. Useful when using Unity Remote.")]
|
||
|
|
public uint StartUpDelay;
|
||
|
|
|
||
|
|
[Header("Debug")]
|
||
|
|
[Tooltip("When debug mode is enabled, this component will print relevant messages to the console. Filter by 'ARLocationProvider' in the log output to see the messages.")]
|
||
|
|
public bool DebugMode;
|
||
|
|
|
||
|
|
[Header("Events")]
|
||
|
|
|
||
|
|
[Tooltip("Called after the first location is read.")]
|
||
|
|
public LocationEnabledUnityEvent OnEnabled = new LocationEnabledUnityEvent();
|
||
|
|
|
||
|
|
[Tooltip("Called after each new location update.")]
|
||
|
|
public LocationUpdatedUnityEvent OnLocationUpdated = new LocationUpdatedUnityEvent();
|
||
|
|
|
||
|
|
[Tooltip("Called after each new raw device GPS data is obtained.")]
|
||
|
|
public LocationUpdatedUnityEvent OnRawLocationUpdated = new LocationUpdatedUnityEvent();
|
||
|
|
|
||
|
|
[Tooltip("Called after each new compass update.")]
|
||
|
|
public CompassUpdatedUnityEvent OnCompassUpdated = new CompassUpdatedUnityEvent();
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Returns the current location provider.
|
||
|
|
/// </summary>
|
||
|
|
public ILocationProvider Provider { get; private set; }
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// If true, the location provider has received the first location data.
|
||
|
|
/// </summary>
|
||
|
|
public bool IsEnabled => Provider.IsEnabled;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// If true, the location provider has started, but no location data has been read.
|
||
|
|
/// </summary>
|
||
|
|
public bool HasStarted => Provider.HasStarted;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// The number of location updates so far.
|
||
|
|
/// </summary>
|
||
|
|
public int LocationUpdateCount => Provider.LocationUpdateCount;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// If true, updates are paused.
|
||
|
|
/// </summary>
|
||
|
|
public bool IsPaused => Provider.Paused;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// The latest location data.
|
||
|
|
/// </summary>
|
||
|
|
public LocationReading CurrentLocation => Provider.CurrentLocation;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// The previous location data.
|
||
|
|
/// </summary>
|
||
|
|
public LocationReading LastLocation => Provider.LastLocation;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// The current heading data.
|
||
|
|
/// </summary>
|
||
|
|
public HeadingReading CurrentHeading => Provider.CurrentHeading;
|
||
|
|
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Time since the location provider has started.
|
||
|
|
/// </summary>
|
||
|
|
public float TimeSinceStart => Time.time - Provider.StartTime;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// The distance from the initial measured position.
|
||
|
|
/// </summary>
|
||
|
|
public double DistanceFromStartPoint => Provider.DistanceFromStartPoint;
|
||
|
|
|
||
|
|
private int measurementCount;
|
||
|
|
private bool mute;
|
||
|
|
|
||
|
|
public event LocationUpdatedDelegate OnLocationUpdatedDelegate;
|
||
|
|
public event CompassUpdateDelegate OnCompassUpdateDelegate;
|
||
|
|
public event Action OnRestartDelegate;
|
||
|
|
|
||
|
|
public override void Awake()
|
||
|
|
{
|
||
|
|
base.Awake();
|
||
|
|
|
||
|
|
#if UNITY_EDITOR
|
||
|
|
Provider = new MockLocationProvider();
|
||
|
|
|
||
|
|
if (MockLocationData != null)
|
||
|
|
{
|
||
|
|
Logger.LogFromMethod("ARLocationProvider", "Awake", $"Using mock location {MockLocationData}", DebugMode);
|
||
|
|
((MockLocationProvider)Provider).mockLocation = MockLocationData.Location;
|
||
|
|
}
|
||
|
|
#elif ARGPS_CUSTOM_PROVIDER
|
||
|
|
// If you want to use a custom location provider, add 'ARGPS_CUSTOM_PROVIDER' to the define symbols in the Player
|
||
|
|
// settings, create a implementation of ILocationProvider, and instantiate it in the line below.
|
||
|
|
Provider = new ARGpsCustomLocationProvider();
|
||
|
|
#else
|
||
|
|
Provider = new UnityLocationProvider();
|
||
|
|
// Provider = LocProviderManager.GetProvider();
|
||
|
|
#endif
|
||
|
|
Logger.LogFromMethod("ARLocationProvider", "Awake", ": Using provider " + Provider.Name, DebugMode);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
private void InitProviderEventListeners()
|
||
|
|
{
|
||
|
|
Logger.LogFromMethod("ARLocationProvider", "InitProviderEventListeners", "Initializing location provider listeners.", DebugMode);
|
||
|
|
|
||
|
|
Provider.LocationUpdated += Provider_LocationUpdated;
|
||
|
|
Provider.CompassUpdated += Provider_CompassUpdated;
|
||
|
|
Provider.LocationUpdatedRaw += ProviderOnLocationUpdatedRaw;
|
||
|
|
|
||
|
|
Provider.OnEnabled(OnProviderEnabledDelegate);
|
||
|
|
|
||
|
|
if (Provider.IsEnabled)
|
||
|
|
{
|
||
|
|
ForceLocationUpdate();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void ProviderOnLocationUpdatedRaw(LocationReading currentLocation, LocationReading lastLocation)
|
||
|
|
{
|
||
|
|
OnRawLocationUpdated?.Invoke(currentLocation.ToLocation());
|
||
|
|
}
|
||
|
|
|
||
|
|
private void OnProviderEnabledDelegate()
|
||
|
|
{
|
||
|
|
Logger.LogFromMethod("ARLocationProvider", "OnProviderEnabledDelegate", "Provider enabled; emitting 'OnEnabled' event.", DebugMode);
|
||
|
|
OnEnabled?.Invoke(CurrentLocation.ToLocation());
|
||
|
|
}
|
||
|
|
|
||
|
|
IEnumerator Start()
|
||
|
|
{
|
||
|
|
InitProviderEventListeners();
|
||
|
|
|
||
|
|
Provider.Options = LocationProviderSettings;
|
||
|
|
|
||
|
|
Logger.LogFromMethod("ARLocationProvider", "Start", "Starting the location provider", DebugMode);
|
||
|
|
yield return StartCoroutine(Provider.Start(MaxWaitTime, StartUpDelay));
|
||
|
|
}
|
||
|
|
|
||
|
|
public void Mute()
|
||
|
|
{
|
||
|
|
Logger.LogFromMethod("ARLocationProvider", "Mute", "Muting ARLocationProvider.", DebugMode);
|
||
|
|
mute = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void Unmute(bool emit = true)
|
||
|
|
{
|
||
|
|
Logger.LogFromMethod("ARLocationProvider", "Mute", "Un-muting ARLocationProvider.", DebugMode);
|
||
|
|
mute = false;
|
||
|
|
if (Provider.IsEnabled && emit) ForceLocationUpdate();
|
||
|
|
}
|
||
|
|
|
||
|
|
private void Provider_CompassUpdated(HeadingReading heading, HeadingReading lastReading)
|
||
|
|
{
|
||
|
|
if (mute) return;
|
||
|
|
|
||
|
|
OnCompassUpdateDelegate?.Invoke(heading, lastReading);
|
||
|
|
OnCompassUpdated?.Invoke(heading);
|
||
|
|
}
|
||
|
|
|
||
|
|
private void Provider_LocationUpdated(LocationReading currentLocation, LocationReading lastLocation)
|
||
|
|
{
|
||
|
|
if (mute) return;
|
||
|
|
|
||
|
|
measurementCount++;
|
||
|
|
|
||
|
|
if ((LocationProviderSettings.MaxNumberOfUpdates > 0) && (measurementCount >= LocationProviderSettings.MaxNumberOfUpdates))
|
||
|
|
{
|
||
|
|
Provider.Pause();
|
||
|
|
}
|
||
|
|
|
||
|
|
Logger.LogFromMethod("ARLocationProvider", "Provider_LocationUpdated", $"New location {currentLocation}.", DebugMode);
|
||
|
|
|
||
|
|
OnLocationUpdatedDelegate?.Invoke(currentLocation, lastLocation);
|
||
|
|
OnLocationUpdated?.Invoke(currentLocation.ToLocation());
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Force the provider to emit a location update event. This wont force a new read of location, just emit
|
||
|
|
/// the last available measurement.
|
||
|
|
/// </summary>
|
||
|
|
public void ForceLocationUpdate()
|
||
|
|
{
|
||
|
|
Logger.LogFromMethod("ARLocationProvider", "ForceLocationUpdate", "Emitting a forced location update", DebugMode);
|
||
|
|
Provider.ForceLocationUpdate();
|
||
|
|
}
|
||
|
|
|
||
|
|
void Update()
|
||
|
|
{
|
||
|
|
if (Provider == null || !Provider.HasStarted)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
Provider.Update();
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Pauses location updates
|
||
|
|
/// </summary>
|
||
|
|
public void Pause()
|
||
|
|
{
|
||
|
|
Logger.LogFromMethod("ARLocationProvider", "Pause", "Pausing the location provider.", DebugMode);
|
||
|
|
Provider?.Pause();
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Resumes location updates
|
||
|
|
/// </summary>
|
||
|
|
public void Resume()
|
||
|
|
{
|
||
|
|
Logger.LogFromMethod("ARLocationProvider", "Resume", "Resuming the location provider.", DebugMode);
|
||
|
|
Provider?.Resume();
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Resets the location provider.
|
||
|
|
/// </summary>
|
||
|
|
public void Restart()
|
||
|
|
{
|
||
|
|
Logger.LogFromMethod("ARLocationProvider", "Restart", "Restarting the location provider.", DebugMode);
|
||
|
|
Provider?.Restart();
|
||
|
|
OnRestartDelegate?.Invoke();
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Register a delegate to location updates.
|
||
|
|
///
|
||
|
|
/// The `useRawIfEnabled` method if for situations where we want the latest data,
|
||
|
|
/// like when we are adding objects at runtime.
|
||
|
|
///
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="locationUpdatedDelegate"></param>
|
||
|
|
/// <param name="useRawIfEnabled"></param>
|
||
|
|
public void OnLocationUpdatedEvent(LocationUpdatedDelegate locationUpdatedDelegate, bool useRawIfEnabled = false)
|
||
|
|
{
|
||
|
|
if (IsEnabled)
|
||
|
|
{
|
||
|
|
locationUpdatedDelegate(CurrentLocation, useRawIfEnabled ? Provider.LastLocationRaw : LastLocation);
|
||
|
|
}
|
||
|
|
|
||
|
|
OnLocationUpdatedDelegate += locationUpdatedDelegate;
|
||
|
|
}
|
||
|
|
|
||
|
|
public void OnProviderRestartEvent(Action del)
|
||
|
|
{
|
||
|
|
OnRestartDelegate += del;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Register a delegate to compass/heading updates.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="compassUpdateDelegate"></param>
|
||
|
|
public void OnCompassUpdatedEvent(CompassUpdateDelegate compassUpdateDelegate)
|
||
|
|
{
|
||
|
|
OnCompassUpdateDelegate += compassUpdateDelegate;
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// RegisterRegister delegate for when the provider enables location updates.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="del">Del.</param>
|
||
|
|
public void OnEnabledEvent(LocationEnabledDelegate del)
|
||
|
|
{
|
||
|
|
Provider.OnEnabled(del);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Register a delegate for when the provider fails to initialize location services.
|
||
|
|
/// </summary>
|
||
|
|
/// <param name="del">Del.</param>
|
||
|
|
public void OnFailedEvent(LocationFailedDelegate del)
|
||
|
|
{
|
||
|
|
Provider.OnFail(del);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|