#region copyright
// ---------------------------------------------------------------
// Copyright (C) Dmitriy Yukhanov - focus [https://codestage.net]
// ---------------------------------------------------------------
#endregion
#if UNITY_ANDROID && !UNITY_EDITOR
#define ACTK_ANDROID_DEVICE
#endif
namespace CodeStage.AntiCheat.Utils
{
using System;
using UnityEngine;
#if ACTK_ANDROID_DEVICE
using Common;
#endif
internal class TimeUtils
{
public const long TicksPerSecond = TimeSpan.TicksPerMillisecond * 1000;
#if ACTK_ANDROID_DEVICE
private const string RoutinesClassPath = "net.codestage.actk.androidnative.ACTkAndroidRoutines";
private static AndroidJavaClass routinesClass;
private static bool androidTimeReadAttemptWasMade;
#endif
///
/// Gets speed hacks unbiased current time ticks.
///
/// Reliable current time in ticks.
public static long GetReliableTicks()
{
long ticks = 0;
#if ACTK_ANDROID_DEVICE
ticks = TryReadTicksFromAndroidRoutine();
#endif
if (ticks == 0)
{
ticks = DateTime.UtcNow.Ticks;
}
return ticks;
}
public static long GetEnvironmentTicks()
{
return Environment.TickCount * TimeSpan.TicksPerMillisecond;
}
public static long GetRealtimeTicks()
{
return (long)(Time.realtimeSinceStartup * TicksPerSecond);
}
#if ACTK_ANDROID_DEVICE
private static long TryReadTicksFromAndroidRoutine()
{
long result = 0;
if (!androidTimeReadAttemptWasMade)
{
androidTimeReadAttemptWasMade = true;
try
{
routinesClass = new AndroidJavaClass(RoutinesClassPath);
}
catch (Exception e)
{
Debug.LogError(ACTkConstants.LogPrefix + "Couldn't create instance of the AndroidJavaClass: " + RoutinesClassPath + " !\n" + e);
}
}
if (routinesClass == null) return result;
try
{
// getting time in nanoseconds from the native Android timer
// since some random fixed and JVM initialization point
// (it even may be a future so value could be negative)
result = routinesClass.CallStatic("GetSystemNanoTime");
result /= 100;
}
catch (Exception e)
{
Debug.LogError(ACTkConstants.LogPrefix + "Couldn't call static method from the Android Routines Class!\n" + e);
}
return result;
}
~TimeUtils()
{
if (routinesClass != null)
{
routinesClass.Dispose();
}
}
#endif
}
}