138 lines
4.0 KiB
C#
138 lines
4.0 KiB
C#
|
|
using UnityEngine;
|
|||
|
|
using System;
|
|||
|
|
using System.Collections;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
|
|||
|
|
public enum TimeValidationResult {
|
|||
|
|
Success,
|
|||
|
|
OffLine,
|
|||
|
|
TimeOut,
|
|||
|
|
HardwareTimeShiftFaster,
|
|||
|
|
HardwareTimeShiftLater,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public enum TimeValidateState {
|
|||
|
|
Requesting,
|
|||
|
|
Succeeded,
|
|||
|
|
Failed,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public class TimeValidateCoroutine {
|
|||
|
|
|
|||
|
|
private Action removeAction;
|
|||
|
|
public TimeValidateCoroutine(Action removeAction){
|
|||
|
|
this.removeAction = removeAction;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void Remove(){
|
|||
|
|
removeAction();
|
|||
|
|
removeAction = ActionExtensions.EmptyAction;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
static class TimeValidateCoroutineExtensions {
|
|||
|
|
public static void StopCoroutine(this TimeValidateCoroutine coroutine){
|
|||
|
|
if(coroutine != null) coroutine.Remove();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public class TimeValidator : SingletonMonoBehaviour<TimeValidator> {
|
|||
|
|
|
|||
|
|
[SerializeField]
|
|||
|
|
private float boundaryMinutes = 5;
|
|||
|
|
|
|||
|
|
private TimeValidateState state = TimeValidateState.Requesting;
|
|||
|
|
private List<Action<TimeValidationResult>> callbackList = new List<Action<TimeValidationResult>>();
|
|||
|
|
private TimeValidationResult result;
|
|||
|
|
private Coroutine coroutine;
|
|||
|
|
|
|||
|
|
#if !UNITY_EDITOR
|
|||
|
|
void Awake(){
|
|||
|
|
coroutine = BeginTimeValidation();
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
public TimeValidateCoroutine TimeValidation(Action<TimeValidationResult> callback){
|
|||
|
|
switch(state){
|
|||
|
|
case TimeValidateState.Requesting:
|
|||
|
|
callbackList.Add(callback);
|
|||
|
|
return new TimeValidateCoroutine(() => callbackList.Remove(callback));
|
|||
|
|
default:
|
|||
|
|
callback(result);
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void OnApplicationPause(bool pauseStatus){
|
|||
|
|
if(pauseStatus){
|
|||
|
|
this.SafeStopCoroutine(coroutine);
|
|||
|
|
state = TimeValidateState.Requesting;
|
|||
|
|
}else{
|
|||
|
|
coroutine = BeginTimeValidation();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
private Coroutine BeginTimeValidation(){
|
|||
|
|
#if DEVELOPMENT_BUILD
|
|||
|
|
state = TimeValidateState.Succeeded;
|
|||
|
|
result = TimeValidationResult.Success;
|
|||
|
|
return null;
|
|||
|
|
#else
|
|||
|
|
if(Application.internetReachability == NetworkReachability.NotReachable){
|
|||
|
|
state = TimeValidateState.Failed;
|
|||
|
|
result = TimeValidationResult.OffLine;
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
return StartCoroutine(TimeValidation(networkTime => {
|
|||
|
|
DateTime now = DateTime.UtcNow;
|
|||
|
|
bool isLater = networkTime < now;
|
|||
|
|
TimeSpan difference;
|
|||
|
|
if(isLater){
|
|||
|
|
difference = now - networkTime;
|
|||
|
|
}else{
|
|||
|
|
difference = networkTime - now;
|
|||
|
|
}
|
|||
|
|
var isSuccess = difference.TotalMinutes <= boundaryMinutes;
|
|||
|
|
if(isSuccess){
|
|||
|
|
state = TimeValidateState.Succeeded;
|
|||
|
|
result = TimeValidationResult.Success;
|
|||
|
|
}else{
|
|||
|
|
state = TimeValidateState.Failed;
|
|||
|
|
if(isLater){
|
|||
|
|
result = TimeValidationResult.HardwareTimeShiftLater;
|
|||
|
|
}else{
|
|||
|
|
result = TimeValidationResult.HardwareTimeShiftFaster;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
foreach(var callback in callbackList){
|
|||
|
|
callback(result);
|
|||
|
|
}
|
|||
|
|
callbackList.Clear();
|
|||
|
|
}, () => {
|
|||
|
|
state = TimeValidateState.Failed;
|
|||
|
|
result = TimeValidationResult.TimeOut;
|
|||
|
|
foreach(var callback in callbackList){
|
|||
|
|
callback(result);
|
|||
|
|
}
|
|||
|
|
callbackList.Clear();
|
|||
|
|
}));
|
|||
|
|
#endif
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private IEnumerator TimeValidation(Action<DateTime> succeededCallback, Action failedCallback){
|
|||
|
|
var retryCounter = 3;
|
|||
|
|
var isTimeOut = true;
|
|||
|
|
var timeout = 3000;
|
|||
|
|
while(isTimeOut && retryCounter > 0){
|
|||
|
|
yield return new NtpRequest().GetNetworkTime(this, result => {
|
|||
|
|
isTimeOut = false;
|
|||
|
|
succeededCallback(result);
|
|||
|
|
}, ActionExtensions.EmptyAction, timeout);
|
|||
|
|
--retryCounter;
|
|||
|
|
timeout *= 5;
|
|||
|
|
}
|
|||
|
|
if(isTimeOut){
|
|||
|
|
failedCallback();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|