diff --git a/Achievments.meta b/Achievments.meta new file mode 100644 index 0000000..b169e48 --- /dev/null +++ b/Achievments.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ff9bb206aea50d14997771b9a0cc2b04 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/Achievment.cs b/Achievments/Achievment.cs new file mode 100644 index 0000000..448fd58 --- /dev/null +++ b/Achievments/Achievment.cs @@ -0,0 +1,190 @@ +using NEG.Utils.Achievments.AchievmentTypes; +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace NEG.Utils.Achievments +{ + /// + /// Static utility for achievment managment + /// + public static class Achievment + { + public static AchievmentManager Instance + { + get + { + if (instance == null) + { + instance = AchievmentManager.Builder.FromLabeledConfig(ConfigLabel) + .WithLabeledBackend(BackendLabel) + .Build(); + } + return instance; + } + } + + public static string BackendLabel + { + get => backendLabel; + set + { + if(instance != null) + { + //Log + Quit helps debug builds + Debug.LogError("Achievments - Cannot set backend label, Managed already created"); + Application.Quit(1); + } + if (backendLabel != null) + { + //Log + Quit helps debug builds + Debug.LogError("Multiple AchievmentBackends enabled, this is not allowed"); + Application.Quit(1); + } + backendLabel = value; + } + } + private static string backendLabel; + + /// + /// You shouldn't have any reason to change this + /// Used for tests. + /// + public static string ConfigLabel + { + private get => configLabel; + set => configLabel = value; + } + + /// + /// You shouldn't have any reason to change this + /// Used for tests. + /// + private static string configLabel = "Achivments"; + + private static AchievmentManager instance; + + #region Achievment Manipulation (Sets, Gets) + + /// + /// Returns if an achivment at a given id is completed + /// + /// + /// + /// + /// throws an if there is no achievment under id + public static bool IsCompleted(string id) + { + return Instance.IsCompleted(id); + } + + #region Toggle + /// + /// Sets a as completed.
+ ///
+ /// + /// + /// throws an if there is no achievment under id or an if achievment under id is of a different type + public static bool SetToggleAchivment(string id) + { + return Instance.SetToggleAchivment(id); + } + + /// + /// Gets a completion state from a .
+ ///
+ /// + /// + /// throws an if there is no achievment under id or an if achievment under id is of a different type + public static bool GetToggleState(string id) + { + return Instance.GetToggleState(id); + } + #endregion + + #region Int + /// + /// Sets progress of a given to
+ ///
+ /// + /// + /// throws an if there is no achievment under id or an if achievment under id is of a different type + public static bool SetIntProgress(string id, int progress) + { + return Instance.SetIntProgress(id, progress); + } + + /// + /// Changes progress of a given by
+ ///
+ /// \ + /// + /// throws an if there is no achievment under id or an if achievment under id is of a different type + public static bool ChangeIntProgress(string id, int delta) + { + return Instance.ChangeIntProgress(id, delta); + } + + /// + /// Gets current progress from a .
+ ///
+ /// + /// + /// throws an if there is no achievment under id or an if achievment under id is of a different type + public static int GetIntProgress(string id) + { + return Instance.GetIntProgress(id); + } + #endregion + + #region Float + /// + /// Sets progress of a given to
+ ///
+ /// + /// + /// throws an if there is no achievment under id or an if achievment under id is of a different type + public static bool SetFloatProgress(string id, float progress) + { + return Instance.SetFloatProgress(id, progress); + } + + /// + /// Changes progress of a given by
+ ///
+ /// + /// + /// throws an if there is no achievment under id or an if achievment under id is of a different type + public static bool ChangeFloatProgress(string id, float delta) + { + return Instance.ChangeFloatProgress(id, delta); + } + + /// + /// Gets current progress from a .
+ ///
+ /// + /// + /// throws an if there is no achievment under id or an if achievment under id is of a different type + public static float GetFloatProgress(string id) + { + return Instance.GetFloatProgress(id); + } + #endregion + #endregion + + #region Test Api + /// + /// You shouldn't have any reason to use this
+ /// Use at your own risk, may cause unexpected behaviour
+ /// Used for tests + ///
+ public static void NullifyInstance() + { + instance = null; + } + #endregion + + } +} \ No newline at end of file diff --git a/Achievments/Achievment.cs.meta b/Achievments/Achievment.cs.meta new file mode 100644 index 0000000..d293cde --- /dev/null +++ b/Achievments/Achievment.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 696bafd4c06b0a8458f008103441ea7f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/AchievmentException.cs b/Achievments/AchievmentException.cs new file mode 100644 index 0000000..041c7b9 --- /dev/null +++ b/Achievments/AchievmentException.cs @@ -0,0 +1,44 @@ +using JetBrains.Annotations; +using System; + +namespace NEG.Utils.Achievments +{ + public class AchievmentException : ApplicationException + { + /// + /// Id of related achievment + /// + /// + /// + public string Id { get; private set; } + + public AchievmentException(string message, string achievmentId) : base(message) + { + Id = achievmentId; + } + } + + public class AchievmentTypeException : AchievmentException + { + /// + /// Expected achievment type under + /// + /// + /// + public Type Expected { get; private set; } + + /// + /// Actual achievment type under + /// + /// + /// + public Type Actual { get; private set; } + + public AchievmentTypeException(string message, string achievmentId, Type expectedType, Type actualType) : base(message, achievmentId) + { + Expected = expectedType; + Actual = actualType; + } + } + +} \ No newline at end of file diff --git a/Achievments/AchievmentException.cs.meta b/Achievments/AchievmentException.cs.meta new file mode 100644 index 0000000..b09eea7 --- /dev/null +++ b/Achievments/AchievmentException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 241344322b9771049b6962e48ac98085 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/AchievmentManager.cs b/Achievments/AchievmentManager.cs new file mode 100644 index 0000000..6aaa90f --- /dev/null +++ b/Achievments/AchievmentManager.cs @@ -0,0 +1,366 @@ +using System.Collections; +using System.Collections.Generic; +using System; +using System.Linq; +using UnityEngine; +using UnityEngine.AddressableAssets; +using System.Runtime.CompilerServices; +using UnityEditor; + +namespace NEG.Utils.Achievments +{ + using AchievmentTypes; + + public class AchievmentManager + { + public class Builder + { + public const string DefaultAchivmentsConfigLabel = "Achivments"; + + private AchievmentManager manager = new AchievmentManager(); + private IAchievmentBackend backend; + + public static Builder FromDefaultConfig() + { + return FromLabeledConfig(DefaultAchivmentsConfigLabel); + } + + public static Builder FromLabeledConfig(string label) + { + var builder = new Builder(); + + var handle = Addressables.LoadAssetsAsync((IEnumerable)new string[] { label }, delegate { }, Addressables.MergeMode.Union, false); + + var configs = handle.WaitForCompletion(); + + foreach (var config in configs) + { + config.Apply(builder); + } + + foreach (var config in configs) + { + config.ApplyLast(builder); + } + + Addressables.Release(handle); + + return builder; + } + + public Builder WithDefinitionsFrom(AchievmentManagerConfig collection) + { + foreach (var def in collection.Achivments) + { + manager.RegisterAchivment(def); + } + + return this; + } + + public Builder WithLabeledBackend(string label) + { + var backendConfigHandle = Addressables.LoadAssetAsync(label); + + var backendConfig = backendConfigHandle.WaitForCompletion(); + + WithBackend(backendConfig.ConstructBackend()); + + Addressables.Release(backendConfigHandle); + return this; + } + + public Builder WithBackend(IAchievmentBackend backendIn) + { + if (backend != null) + { + throw new ApplicationException("There can only be one Achievment Backend at a time"); + } + + this.backend = backendIn; + + return this; + } + + public Builder WithCallbackReciever(IAchievmentCallbackReciever callbackReciever) + { + manager.AddCallbackReciever(callbackReciever); + return this; + } + + public AchievmentManager Build() + { + if (backend != null) + { + manager.InitBackend(backend); + }else + { + Debug.LogWarning("No AchievmentBackend selected. Is this intended?"); + } + return manager; + } + } + + public delegate void AchievmentCompletedCallback(AchievmentData achivment); + public delegate void AchievmentStateChangedCallback(AchievmentData achivment); + + public event AchievmentCompletedCallback AchievmentCompleted; + public event AchievmentStateChangedCallback AchievmentStateChanged; + + private Dictionary definitionCache; + private Dictionary dataCache; + + private IAchievmentBackend activeBackend; + + private AchievmentManager() + { + definitionCache = new Dictionary(); + dataCache = new Dictionary(); + } + + private void RegisterAchivment(AchievmentDefinition definition) + { + if (!definitionCache.ContainsKey(definition.Id)) + { + definitionCache.Add(definition.Id, definition); + dataCache.Add(definition, definition.Construct()); + } + else + { + Debug.LogWarning($"Duplicate Achivment with ID: {definition.Id}"); + } + } + + /// + /// Initializes a backend syncing achievments data with it and redistering it as a callback reciever + /// + /// Resets all achievments data + private void InitBackend(IAchievmentBackend achievmentBackend) + { + activeBackend = achievmentBackend; + foreach (var definition in definitionCache.Values) + { + var storedProgress = achievmentBackend.GetStoredAchivment(definition); + + if (storedProgress != null) + { + dataCache[definition] = storedProgress; + } + else + { + dataCache[definition] = definition.Construct(); + } + } + AddCallbackReciever(achievmentBackend); + } + + public void AddCallbackRecievers(IEnumerable initialCallbacks) + { + foreach (var callback in initialCallbacks) + { + AddCallbackReciever(callback); + } + } + + public void AddCallbackReciever(IAchievmentCallbackReciever callback) + { + AchievmentCompleted += callback.AchievmentCompleted; + AchievmentStateChanged += callback.AchievmentStateChanged; + } + + public void RemoveCallbackReciever(IAchievmentCallbackReciever callback) + { + AchievmentCompleted -= callback.AchievmentCompleted; + AchievmentStateChanged -= callback.AchievmentStateChanged; + } + + #region Achievment Manipulation (Sets, Gets) + + /// + /// Returns if an achivment at a given id is completed + /// + /// + /// + /// throws an if there is no achievment under id + public bool IsCompleted(string id) + { + return GetAchievmentForId(id).IsCompleted; + } + + #region Toggle + /// + /// Sets a as completed, after which sends , also if the achievment is completed sends a .
+ ///
+ /// + /// throws an if there is no achievment under id or an if achievment under id is of a different type + public bool SetToggleAchivment(string id) + { + return ManipulateAchievment(id, (achievment) => achievment.CompletionState = true); + } + + /// + /// Gets a completion state from a .
+ ///
+ /// + /// throws an if there is no achievment under id or an if achievment under id is of a different type + public bool GetToggleState(string id) + { + return GetAchievmentForId(id).CompletionState; + } + #endregion + + #region Int + /// + /// Sets progress of a given to , after which sends , also if the achievment is completed sends a .
+ ///
+ /// + /// throws an if there is no achievment under id or an if achievment under id is of a different type + public bool SetIntProgress(string id, int progress) + { + return ManipulateAchievment(id, (achievment) => achievment.CurrentProgress = progress); + } + + /// + /// Changes progress of a given by , after which sends , also if the achievment is completed sends a .
+ ///
+ /// + /// throws an if there is no achievment under id or an if achievment under id is of a different type + public bool ChangeIntProgress(string id, int delta) + { + return ManipulateAchievment(id, (achievment) => achievment.CurrentProgress += delta); + } + + /// + /// Gets current progress from a .
+ ///
+ /// + /// throws an if there is no achievment under id or an if achievment under id is of a different type + public int GetIntProgress(string id) + { + return GetAchievmentForId(id).CurrentProgress; + } + #endregion + + #region Float + /// + /// Sets progress of a given to , after which sends , also if the achievment is completed sends a .
+ ///
+ /// + /// throws an if there is no achievment under id or an if achievment under id is of a different type + public bool SetFloatProgress(string id, float progress) + { + return ManipulateAchievment(id, (achievment) => achievment.CurrentProgress = progress); + } + + /// + /// Changes progress of a given by , after which sends , also if the achievment is completed sends a .
+ ///
+ /// + /// throws an if there is no achievment under id or an if achievment under id is of a different type + public bool ChangeFloatProgress(string id, float delta) + { + return ManipulateAchievment(id, (achievment) => achievment.CurrentProgress += delta); + } + + /// + /// Gets current progress from a .
+ ///
+ /// + /// throws an if there is no achievment under id or an if achievment under id is of a different type + public float GetFloatProgress(string id) + { + return GetAchievmentForId(id).CurrentProgress; + } + #endregion + #endregion + + /// + /// Returns an achievment of type under + /// + /// Type of the achievment + /// Id of requested achievment + /// throws an if there is no achievment under id or an if achievment under id is of a different type + public T GetAchievmentForId(string id) where T : AchievmentData + { + return ValidateAchievmentType(GetAchievmentForId(id)); + } + + /// + /// Returns an achievment under + /// + /// Id of requested achievment + /// throws an if there is no achievment under id + public AchievmentData GetAchievmentForId(string id) + { + var def = definitionCache.GetValueOrDefault(id); + if (def != null) + { + return dataCache[def]; + } + else + { + throw new AchievmentException($"Invalid achivment id {id}", id); + } + } + + internal void UpdateBackend() + { + activeBackend?.Update(); + } + + private T ValidateAchievmentType(AchievmentData data) where T : AchievmentData + { + if (data is not T convetred) + { + throw new AchievmentTypeException($"Attempting to perform an operation on an invalid achievment type. Expected {typeof(T)} got {data.GetType()}", data.Achievment.Id, typeof(T), data.GetType()); + } + return convetred; + } + + /// + /// + /// + /// + /// + /// Action to perform on the achievment + private bool ManipulateAchievment(string id, Action manipulation) where T : AchievmentData + { + var data = GetAchievmentForId(id); + + if (CheckNotCompleted(data)) + { + return true; + } + + manipulation(data); + + SendUpdateCallbacks(data); + + return data.IsCompleted; + } + + /// + /// Helper method to print a warning if an achievment is already completed + /// + /// + /// Completion state + private bool CheckNotCompleted(AchievmentData data) + { + if (data.IsCompleted) + { + Debug.LogWarning($"Achievment already completed: {data.Achievment.Id}"); + } + return data.IsCompleted; + } + + private void SendUpdateCallbacks(AchievmentData data) + { + AchievmentStateChanged?.Invoke(data); + + if (data.IsCompleted) + { + AchievmentCompleted?.Invoke(data); + } + } + } +} \ No newline at end of file diff --git a/Achievments/AchievmentManager.cs.meta b/Achievments/AchievmentManager.cs.meta new file mode 100644 index 0000000..64e574c --- /dev/null +++ b/Achievments/AchievmentManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7339f725e382e4b4bab7db6d7cc14b30 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/AchievmentManagerConfig.cs b/Achievments/AchievmentManagerConfig.cs new file mode 100644 index 0000000..371a722 --- /dev/null +++ b/Achievments/AchievmentManagerConfig.cs @@ -0,0 +1,24 @@ +using NEG.Utils.Achievments.AchievmentTypes; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace NEG.Utils.Achievments +{ + [CreateAssetMenu(menuName = "Achievments/Config/BaseConfig")] + public class AchievmentManagerConfig : ScriptableObject, IAchivmentManagerConfig + { + [field: SerializeField] + public List Achivments { get; private set; } = new List(); + + public void Apply(AchievmentManager.Builder builder) + { + builder.WithDefinitionsFrom(this); + } + + public void ApplyLast(AchievmentManager.Builder builder) + { + + } + } +} \ No newline at end of file diff --git a/Achievments/AchievmentManagerConfig.cs.meta b/Achievments/AchievmentManagerConfig.cs.meta new file mode 100644 index 0000000..3e43f82 --- /dev/null +++ b/Achievments/AchievmentManagerConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 88120b6e616164f489387a6a32a25dee +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/AchievmentTypes.meta b/Achievments/AchievmentTypes.meta new file mode 100644 index 0000000..bb52672 --- /dev/null +++ b/Achievments/AchievmentTypes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 79e626bf8b94e5f4d813912f9b1d304e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/AchievmentTypes/AchievmentData.cs b/Achievments/AchievmentTypes/AchievmentData.cs new file mode 100644 index 0000000..9407979 --- /dev/null +++ b/Achievments/AchievmentTypes/AchievmentData.cs @@ -0,0 +1,21 @@ +using Newtonsoft.Json.Linq; +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using UnityEngine; + +namespace NEG.Utils.Achievments.AchievmentTypes +{ + public abstract class AchievmentData + { + public AchievmentDefinition Achievment { get; private set; } + + public abstract bool IsCompleted { get; } + + public AchievmentData(AchievmentDefinition achivment) + { + Achievment = achivment; + } + } +} \ No newline at end of file diff --git a/Achievments/AchievmentTypes/AchievmentData.cs.meta b/Achievments/AchievmentTypes/AchievmentData.cs.meta new file mode 100644 index 0000000..5fb4884 --- /dev/null +++ b/Achievments/AchievmentTypes/AchievmentData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1f39500a9deabad43b87bc76122646fc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/AchievmentTypes/AchievmentDefinition.cs b/Achievments/AchievmentTypes/AchievmentDefinition.cs new file mode 100644 index 0000000..b43c4d3 --- /dev/null +++ b/Achievments/AchievmentTypes/AchievmentDefinition.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json.Linq; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace NEG.Utils.Achievments.AchievmentTypes +{ + public abstract class AchievmentDefinition : ScriptableObject + { + [field: SerializeField] + public string Id { get; private set; } + + public abstract AchievmentData Construct(); + } +} \ No newline at end of file diff --git a/Achievments/AchievmentTypes/AchievmentDefinition.cs.meta b/Achievments/AchievmentTypes/AchievmentDefinition.cs.meta new file mode 100644 index 0000000..1d52a8a --- /dev/null +++ b/Achievments/AchievmentTypes/AchievmentDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4aef60a6b4e41e243845a476862049e1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/AchievmentTypes/FloatAchievmentData.cs b/Achievments/AchievmentTypes/FloatAchievmentData.cs new file mode 100644 index 0000000..b9ef389 --- /dev/null +++ b/Achievments/AchievmentTypes/FloatAchievmentData.cs @@ -0,0 +1,40 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace NEG.Utils.Achievments.AchievmentTypes +{ + public class FloatAchievmentData : AchievmentData + { + public override bool IsCompleted => CurrentProgress >= Def.ProgressRequired; + + /// + /// Use to GET current progress + /// Do not SET the value directly use or Instead
+ /// Unless you are in + ///
+ public float CurrentProgress + { + get => currentProgress; + set + { + if (Def.Clamped) + { + value = Mathf.Max(value, Def.LowerBound); + } + currentProgress = Mathf.Min(value, Def.ProgressRequired); + } + } + + public float ProgressLeft => Def.ProgressRequired - CurrentProgress; + + private FloatAchievmentDefinition Def => (FloatAchievmentDefinition)Achievment; + + private float currentProgress; + + public FloatAchievmentData(FloatAchievmentDefinition def) : base(def) + { + currentProgress = def.InitialProgress; + } + } +} \ No newline at end of file diff --git a/Achievments/AchievmentTypes/FloatAchievmentData.cs.meta b/Achievments/AchievmentTypes/FloatAchievmentData.cs.meta new file mode 100644 index 0000000..8d1afc2 --- /dev/null +++ b/Achievments/AchievmentTypes/FloatAchievmentData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 32572809c0644434d8e64878a3c22f0e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/AchievmentTypes/FloatAchievmentDefinition.cs b/Achievments/AchievmentTypes/FloatAchievmentDefinition.cs new file mode 100644 index 0000000..19dac84 --- /dev/null +++ b/Achievments/AchievmentTypes/FloatAchievmentDefinition.cs @@ -0,0 +1,29 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace NEG.Utils.Achievments.AchievmentTypes +{ + [CreateAssetMenu(menuName = "Achievments/Float Achievment")] + public class FloatAchievmentDefinition : AchievmentDefinition + { + [field: Tooltip("Amount of progress required for completion, required to be at leas 1, otherwise would be considered completed from the beginning")] + [field: Min(0)] + [field: SerializeField] + public float ProgressRequired { get; private set; } = 1; + + [field: SerializeField] + public float InitialProgress { get; private set; } = 0; + + [field: SerializeField] + public bool Clamped { get; private set; } = false; + + public float LowerBound { get; private set; } = 0; + + + public override AchievmentData Construct() + { + return new FloatAchievmentData(this); + } + } +} \ No newline at end of file diff --git a/Achievments/AchievmentTypes/FloatAchievmentDefinition.cs.meta b/Achievments/AchievmentTypes/FloatAchievmentDefinition.cs.meta new file mode 100644 index 0000000..4a7def5 --- /dev/null +++ b/Achievments/AchievmentTypes/FloatAchievmentDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2d7270d5452c9b04ca07ef43a491a18d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/AchievmentTypes/IntAchievmentData.cs b/Achievments/AchievmentTypes/IntAchievmentData.cs new file mode 100644 index 0000000..3460aea --- /dev/null +++ b/Achievments/AchievmentTypes/IntAchievmentData.cs @@ -0,0 +1,41 @@ +using System.Collections; +using System.Collections.Generic; +using System.Runtime.Serialization.Formatters; +using UnityEngine; + +namespace NEG.Utils.Achievments.AchievmentTypes +{ + public class IntAchievmentData : AchievmentData + { + public override bool IsCompleted => CurrentProgress >= Def.ProgressRequired; + + /// + /// Use to GET current progress + /// Do not SET the value directly use or Instead
+ /// Unless you are in + ///
+ public int CurrentProgress + { + get => currentProgress; + set + { + if (Def.Clamped) + { + value = Mathf.Max(value, Def.LowerBound); + } + currentProgress = Mathf.Min(value, Def.ProgressRequired); + } + } + + public int ProgressLeft => Def.ProgressRequired - CurrentProgress; + + private IntAchievmentDefinition Def => (IntAchievmentDefinition)Achievment; + + private int currentProgress; + + public IntAchievmentData(IntAchievmentDefinition def) : base(def) + { + currentProgress = def.InitialProgress; + } + } +} \ No newline at end of file diff --git a/Achievments/AchievmentTypes/IntAchievmentData.cs.meta b/Achievments/AchievmentTypes/IntAchievmentData.cs.meta new file mode 100644 index 0000000..52c3e80 --- /dev/null +++ b/Achievments/AchievmentTypes/IntAchievmentData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0a121b6e6fa8ecc45ab4506c15e5f46e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/AchievmentTypes/IntAchievmentDefinition.cs b/Achievments/AchievmentTypes/IntAchievmentDefinition.cs new file mode 100644 index 0000000..aa87274 --- /dev/null +++ b/Achievments/AchievmentTypes/IntAchievmentDefinition.cs @@ -0,0 +1,27 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace NEG.Utils.Achievments.AchievmentTypes +{ + [CreateAssetMenu(menuName = "Achievments/Int Achievment")] + public class IntAchievmentDefinition : AchievmentDefinition + { + [field: Tooltip("Amount of progress required for completion, required to be at leas 1, otherwise would be considered completed from the beginning")] + [field: SerializeField] + public int ProgressRequired { get; private set; } = 1; + + [field: SerializeField] + public int InitialProgress { get; private set; } = 0; + + [field: SerializeField] + public bool Clamped { get; private set; } = false; + + public int LowerBound { get; private set; } = 0; + + public override AchievmentData Construct() + { + return new IntAchievmentData(this); + } + } +} \ No newline at end of file diff --git a/Achievments/AchievmentTypes/IntAchievmentDefinition.cs.meta b/Achievments/AchievmentTypes/IntAchievmentDefinition.cs.meta new file mode 100644 index 0000000..16c6c30 --- /dev/null +++ b/Achievments/AchievmentTypes/IntAchievmentDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5318fea685aa56646a3310c38a9a9bac +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/AchievmentTypes/ToggleAchievmentData.cs b/Achievments/AchievmentTypes/ToggleAchievmentData.cs new file mode 100644 index 0000000..0075d49 --- /dev/null +++ b/Achievments/AchievmentTypes/ToggleAchievmentData.cs @@ -0,0 +1,23 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace NEG.Utils.Achievments.AchievmentTypes +{ + public class ToggleAchievmentData : AchievmentData + { + public override bool IsCompleted => CompletionState; + + /// + /// Use to GET current progress + /// Do not SET the value directly use or Instead
+ /// Unless you are in + ///
+ public bool CompletionState { get; set; } = false; + + public ToggleAchievmentData(ToggleAchievmentDefinition def) : base(def) + { + + } + } +} diff --git a/Achievments/AchievmentTypes/ToggleAchievmentData.cs.meta b/Achievments/AchievmentTypes/ToggleAchievmentData.cs.meta new file mode 100644 index 0000000..84bacbf --- /dev/null +++ b/Achievments/AchievmentTypes/ToggleAchievmentData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1e0806da00902994f9aeb26d295956f0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/AchievmentTypes/ToggleAchievmentDefinition.cs b/Achievments/AchievmentTypes/ToggleAchievmentDefinition.cs new file mode 100644 index 0000000..25fd6f0 --- /dev/null +++ b/Achievments/AchievmentTypes/ToggleAchievmentDefinition.cs @@ -0,0 +1,15 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace NEG.Utils.Achievments.AchievmentTypes +{ + [CreateAssetMenu(menuName = "Achievments/Toggle Achievment")] + public class ToggleAchievmentDefinition : AchievmentDefinition + { + public override AchievmentData Construct() + { + return new ToggleAchievmentData(this); + } + } +} diff --git a/Achievments/AchievmentTypes/ToggleAchievmentDefinition.cs.meta b/Achievments/AchievmentTypes/ToggleAchievmentDefinition.cs.meta new file mode 100644 index 0000000..c10231a --- /dev/null +++ b/Achievments/AchievmentTypes/ToggleAchievmentDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 608c7e921b8b16b42919fc6f55b67fcb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/AchievmentsUpdater.cs b/Achievments/AchievmentsUpdater.cs new file mode 100644 index 0000000..3b6980a --- /dev/null +++ b/Achievments/AchievmentsUpdater.cs @@ -0,0 +1,15 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + + +namespace NEG.Utils.Achievments +{ + public class AchievmentsUpdater : MonoBehaviour + { + void Update() + { + Achievment.Instance.UpdateBackend(); + } + } +} \ No newline at end of file diff --git a/Achievments/AchievmentsUpdater.cs.meta b/Achievments/AchievmentsUpdater.cs.meta new file mode 100644 index 0000000..13c7c08 --- /dev/null +++ b/Achievments/AchievmentsUpdater.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b5a8c2721326a014bb32737116e4d74b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/Backend.meta b/Achievments/Backend.meta new file mode 100644 index 0000000..a5e7f74 --- /dev/null +++ b/Achievments/Backend.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3541d03056defb3468d957da0b69a7b9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/Backend/LoacalBaackend.meta b/Achievments/Backend/LoacalBaackend.meta new file mode 100644 index 0000000..46efe33 --- /dev/null +++ b/Achievments/Backend/LoacalBaackend.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e0226747b74e86c4b8e89d01e9eeeb3f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/Backend/LoacalBaackend/LocalBackendConfig.cs b/Achievments/Backend/LoacalBaackend/LocalBackendConfig.cs new file mode 100644 index 0000000..7afdda4 --- /dev/null +++ b/Achievments/Backend/LoacalBaackend/LocalBackendConfig.cs @@ -0,0 +1,145 @@ +using NEG.Utils.Achievments.AchievmentTypes; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using UnityEngine; + +namespace NEG.Utils.Achievments +{ + [CreateAssetMenu(menuName = "Achievments/Config/Backend/Local")] + public class LocalBackendConfig : ScriptableObject, IAchievmentBackendConfig + { + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] + private static void Init() + { +#if LOCAL_ACHIEVMENT_BACKEND + Achievment.BackendLabel = "LocalAchievments"; +#endif + } + + [SerializeField] + private string saveLocation; + + public IAchievmentBackend ConstructBackend() + { + return new LocalBackend(saveLocation); + } + } + + /// + /// This backend is not optimised at all, do not use in public builds + /// + public class LocalBackend : IAchievmentBackend + { + private string saveLocation; + + public LocalBackend(string saveLocation) + { + this.saveLocation = saveLocation; + } + + public void AchievmentCompleted(AchievmentData achievment) + { + string id = achievment.Achievment.Id; + JObject jobj = LoadJson(); + + JToken token = jobj[id]; + + if (token is not JObject achievmentObj) + { + achievmentObj = new JObject(); + } + + achievmentObj["completed"] = true; + + jobj[id] = achievmentObj; + + SaveJson(jobj); + } + + public void AchievmentStateChanged(AchievmentData achievment) + { + string id = achievment.Achievment.Id; + JObject jobj = LoadJson(); + + JToken token = jobj[id]; + + if (token is not JObject achievmentObj) + { + achievmentObj = new JObject(); + } + + switch (achievment) + { + case IntAchievmentData intAchievment: + achievmentObj["data"] = intAchievment.CurrentProgress; + break; + case FloatAchievmentData floatAchievment: + achievmentObj["data"] = floatAchievment.CurrentProgress; + break; + case ToggleAchievmentData toggleAchievment: + achievmentObj["data"] = toggleAchievment.IsCompleted; + break; + } + + jobj[id] = achievmentObj; + + SaveJson(jobj); + } + + public AchievmentData GetStoredAchivment(AchievmentDefinition definition) + { + JObject jobj = LoadJson(); + + JToken token = jobj[definition.Id]; + + if (token is not JObject) + { + return null; + } + + AchievmentData achievment = definition.Construct(); + + switch (achievment) + { + case IntAchievmentData intAchievment: + intAchievment.CurrentProgress = (int)token["data"]; + break; + case FloatAchievmentData floatAchievment: + floatAchievment.CurrentProgress = (float)token["data"]; + break; + case ToggleAchievmentData toggleAchievment: + toggleAchievment.CompletionState = (bool)token["data"]; + break; + } + + return achievment; + } + + public void Update() + { + //Nothing here + } + + private JObject LoadJson() + { + if (Directory.Exists(Path.GetDirectoryName(saveLocation)) && File.Exists(saveLocation)) + { + return JObject.Parse(File.ReadAllText(saveLocation)); + } + return new JObject(); + } + + private void SaveJson(JObject obj) + { + if (!Directory.Exists(Path.GetDirectoryName(saveLocation))) + { + Directory.CreateDirectory(Path.GetDirectoryName(saveLocation)); + } + + File.WriteAllText(saveLocation, obj.ToString(Formatting.Indented)); + } + } +} \ No newline at end of file diff --git a/Achievments/Backend/LoacalBaackend/LocalBackendConfig.cs.meta b/Achievments/Backend/LoacalBaackend/LocalBackendConfig.cs.meta new file mode 100644 index 0000000..39bcb87 --- /dev/null +++ b/Achievments/Backend/LoacalBaackend/LocalBackendConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6a1257a87feec064697193df412554d4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/Backend/SteamBackend.meta b/Achievments/Backend/SteamBackend.meta new file mode 100644 index 0000000..f611099 --- /dev/null +++ b/Achievments/Backend/SteamBackend.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: db06184b29a56ba44aa446107ada7f66 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/Backend/SteamBackend/NEG.Utils.Achivmnets.Backend.SteamBackend.asmdef b/Achievments/Backend/SteamBackend/NEG.Utils.Achivmnets.Backend.SteamBackend.asmdef new file mode 100644 index 0000000..750a792 --- /dev/null +++ b/Achievments/Backend/SteamBackend/NEG.Utils.Achivmnets.Backend.SteamBackend.asmdef @@ -0,0 +1,19 @@ +{ + "name": "NEG.Utils.Achivmnets.Backend.SteamBackend", + "rootNamespace": "", + "references": [ + "GUID:380ad496eab7ace4b98ceede94941223", + "GUID:68bd7fdb68ef2684e982e8a9825b18a5" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [ + "STEAM_ACHIEVMENT_BACKEND" + ], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Achievments/Backend/SteamBackend/NEG.Utils.Achivmnets.Backend.SteamBackend.asmdef.meta b/Achievments/Backend/SteamBackend/NEG.Utils.Achivmnets.Backend.SteamBackend.asmdef.meta new file mode 100644 index 0000000..8828da9 --- /dev/null +++ b/Achievments/Backend/SteamBackend/NEG.Utils.Achivmnets.Backend.SteamBackend.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 243913f72edbe1c4294164fe2ed9dc0c +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/Backend/SteamBackend/SteamBackendConfig.cs b/Achievments/Backend/SteamBackend/SteamBackendConfig.cs new file mode 100644 index 0000000..d651182 --- /dev/null +++ b/Achievments/Backend/SteamBackend/SteamBackendConfig.cs @@ -0,0 +1,115 @@ +using NEG.Utils.Achievments.AchievmentTypes; +#if STEAM_ACHIEVMENT_BACKEND +using Steamworks; +#endif +using UnityEngine; + +namespace NEG.Utils.Achievments +{ + [CreateAssetMenu(menuName = "Achievments/Config/Backend/Local")] + public class SteamBackendConfig : ScriptableObject, IAchievmentBackendConfig + { + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] + private static void Init() + { +#if STEAM_ACHIEVMENT_BACKEND + Achievment.BackendLabel = "SteamAchievments"; +#endif + } + + public IAchievmentBackend ConstructBackend() + { + return new SteamBackend(); + } + } + +#if STEAM_ACHIEVMENT_BACKEND + public class SteamBackend : IAchievmentBackend + { + private bool isDirty = false; + + public SteamBackend() + { + // + SteamUserStats.RequestCurrentStats(); + } + + public void AchievmentCompleted(AchievmentData achievment) + { + SteamUserStats.SetAchievement(achievment.Achievment.Id); + isDirty = true; + } + + public void AchievmentStateChanged(AchievmentData achievment) + { + string id = achievment.Achievment.Id; + + switch (achievment) + { + case IntAchievmentData intAchievment: + SteamUserStats.SetStat(id, intAchievment.CurrentProgress); + break; + case FloatAchievmentData floatAchievment: + SteamUserStats.SetStat(id, floatAchievment.CurrentProgress); + break; + case ToggleAchievmentData toggleAchievment: + //Do nothing, Achievment completed will also be called + break; + } + isDirty = true; + } + + public AchievmentData GetStoredAchivment(AchievmentDefinition definition) + { + string id = definition.Id; + + AchievmentData achievment = definition.Construct(); + + switch (achievment) + { + case IntAchievmentData intAchievment: + if (SteamUserStats.GetStat(id, out int statI)) + { + intAchievment.CurrentProgress = statI; + } + else + { + Debug.Log("Cannot get user stat, is steam initialised correctly?"); + } + break; + case FloatAchievmentData floatAchievment: + if (SteamUserStats.GetStat(id, out float statF)) + { + floatAchievment.CurrentProgress = statF; + } + else + { + Debug.Log("Cannot get user stat, is steam initialised correctly?"); + } + break; + case ToggleAchievmentData toggleAchievment: + if (SteamUserStats.GetAchievement(id, out bool ach)) + { + toggleAchievment.CompletionState = ach; + } + else + { + Debug.Log("Cannot get user stat, is steam initialised correctly?"); + } + break; + } + + return achievment; + } + + public void Update() + { + if (isDirty) + { + //Reiterate on failure? + isDirty = !SteamUserStats.StoreStats(); + } + } + } +#endif +} \ No newline at end of file diff --git a/Achievments/Backend/SteamBackend/SteamBackendConfig.cs.meta b/Achievments/Backend/SteamBackend/SteamBackendConfig.cs.meta new file mode 100644 index 0000000..f519037 --- /dev/null +++ b/Achievments/Backend/SteamBackend/SteamBackendConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ad7436a24c5bdb84fa2e60e027b7a734 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/IAchievmentBackend.cs b/Achievments/IAchievmentBackend.cs new file mode 100644 index 0000000..f868b6c --- /dev/null +++ b/Achievments/IAchievmentBackend.cs @@ -0,0 +1,31 @@ +using NEG.Utils.Achievments.AchievmentTypes; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace NEG.Utils.Achievments +{ + /// + /// Used to construct instance + /// + public interface IAchievmentBackendConfig + { + /// Constructed backend + public IAchievmentBackend ConstructBackend(); + } + + + public interface IAchievmentBackend : IAchievmentCallbackReciever + { + /// + /// Constructs an AchievmentData for given + /// + /// May return null if there is no stored data for this achievment + AchievmentData GetStoredAchivment(AchievmentDefinition definition); + + /// + /// Used for e.g. syncing with upstream + /// + void Update(); + } +} \ No newline at end of file diff --git a/Achievments/IAchievmentBackend.cs.meta b/Achievments/IAchievmentBackend.cs.meta new file mode 100644 index 0000000..3204777 --- /dev/null +++ b/Achievments/IAchievmentBackend.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cfab45a1ce7cc0a4899f35a61b6a60f6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/IAchievmentCallbackReciever.cs b/Achievments/IAchievmentCallbackReciever.cs new file mode 100644 index 0000000..133a4e5 --- /dev/null +++ b/Achievments/IAchievmentCallbackReciever.cs @@ -0,0 +1,23 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace NEG.Utils.Achievments +{ + using AchievmentTypes; + + public interface IAchievmentCallbackReciever + { + /// + /// Called when an achivment is completed + /// + /// + void AchievmentCompleted(AchievmentData achievment); + + /// + /// Called when achivment progress changes + /// + /// + void AchievmentStateChanged(AchievmentData achievment); + } +} \ No newline at end of file diff --git a/Achievments/IAchievmentCallbackReciever.cs.meta b/Achievments/IAchievmentCallbackReciever.cs.meta new file mode 100644 index 0000000..beb55a4 --- /dev/null +++ b/Achievments/IAchievmentCallbackReciever.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7218fed73c5be2c4ba31eca9fe44d37a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/IAchivmentManagerConfig.cs b/Achievments/IAchivmentManagerConfig.cs new file mode 100644 index 0000000..15628c9 --- /dev/null +++ b/Achievments/IAchivmentManagerConfig.cs @@ -0,0 +1,21 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace NEG.Utils.Achievments +{ + public interface IAchivmentManagerConfig + { + /// + /// Used to Apply config data + /// + /// + void Apply(AchievmentManager.Builder builder); + + /// + /// Called after was called on every other config + /// + /// + void ApplyLast(AchievmentManager.Builder builder); + } +} \ No newline at end of file diff --git a/Achievments/IAchivmentManagerConfig.cs.meta b/Achievments/IAchivmentManagerConfig.cs.meta new file mode 100644 index 0000000..2fa22ce --- /dev/null +++ b/Achievments/IAchivmentManagerConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bd4b0d54603883447b6458263d6b3605 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/NEG.Utils.Achievments.asmdef b/Achievments/NEG.Utils.Achievments.asmdef new file mode 100644 index 0000000..5d6fce1 --- /dev/null +++ b/Achievments/NEG.Utils.Achievments.asmdef @@ -0,0 +1,17 @@ +{ + "name": "NEG.Utils.Achievments", + "rootNamespace": "", + "references": [ + "GUID:9e24947de15b9834991c9d8411ea37cf", + "GUID:84651a3751eca9349aac36a66bba901b" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Achievments/NEG.Utils.Achievments.asmdef.meta b/Achievments/NEG.Utils.Achievments.asmdef.meta new file mode 100644 index 0000000..14bc2c4 --- /dev/null +++ b/Achievments/NEG.Utils.Achievments.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 380ad496eab7ace4b98ceede94941223 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/PlaymodeTests.meta b/Achievments/PlaymodeTests.meta new file mode 100644 index 0000000..852d17f --- /dev/null +++ b/Achievments/PlaymodeTests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d7c140577a904c8419a760a8ac6133c7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/PlaymodeTests/BackendTests.cs b/Achievments/PlaymodeTests/BackendTests.cs new file mode 100644 index 0000000..e3f6bd8 --- /dev/null +++ b/Achievments/PlaymodeTests/BackendTests.cs @@ -0,0 +1,65 @@ +using System.Collections; +using System.Collections.Generic; +using System.IO; +using NUnit.Framework; +using UnityEngine; + +namespace NEG.Utils.Achievments.Tests +{ + public class BackendTests + { + //If stests start to fail first make sure these are correct in relation to test config asset + public const string configLabel = "TestAchievments"; + public const string backendLabel = "AchievmentsLocalTests"; + public const string saveLocation = "./LocalAchievments/Tests.json"; + + public const string AchievmentIdToggle = "TOGGLE"; + public const string AchievmentIdInt = "INT"; + public const string AchievmentIdFloat = "FLOAT"; + + [OneTimeSetUp] + public void OneTtimeSetup() + { + Achievment.BackendLabel = backendLabel; + Achievment.ConfigLabel = configLabel; + } + + [TearDown] + public void TearDown() + { + Achievment.NullifyInstance(); + if (File.Exists(saveLocation)) + { + File.Delete(saveLocation); + } + } + + [Test] + public void ReadWrite() + { +#if ACHIEVMENT_BACKEND_TESTS + //We assume that the achievments are set correctly because otherwise other tests would fail + Achievment.SetToggleAchivment(AchievmentIdToggle); + Achievment.SetIntProgress(AchievmentIdInt, 20); + Achievment.SetFloatProgress(AchievmentIdFloat, 20); + + //We need to assume NullifyInstance works correctly because we dont have access to an AchievmentManager which has not syncked yet + Achievment.NullifyInstance(); + + Assert.IsTrue(Achievment.IsCompleted(AchievmentIdToggle)); + Assert.AreEqual(Achievment.GetIntProgress(AchievmentIdInt), 20); + Assert.AreEqual(Achievment.GetFloatProgress(AchievmentIdFloat), 20, 0f); + + Achievment.SetIntProgress(AchievmentIdInt, 30); + Achievment.SetFloatProgress(AchievmentIdFloat, 30); + + Achievment.NullifyInstance(); + + Assert.AreEqual(Achievment.GetIntProgress(AchievmentIdInt), 30); + Assert.AreEqual(Achievment.GetFloatProgress(AchievmentIdFloat), 30, 0f); +#else + throw new System.Exception("Backend tests are not enabled. To enable Backend tests add define ACHIEVMENT_BACKEND_TESTS"); +#endif + } + } +} \ No newline at end of file diff --git a/Achievments/PlaymodeTests/BackendTests.cs.meta b/Achievments/PlaymodeTests/BackendTests.cs.meta new file mode 100644 index 0000000..a543b95 --- /dev/null +++ b/Achievments/PlaymodeTests/BackendTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c09ce9536c2c5f541bb7d07d5eca1d69 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/PlaymodeTests/NEG.Utils.Achievments.Tests.Playmode.asmdef b/Achievments/PlaymodeTests/NEG.Utils.Achievments.Tests.Playmode.asmdef new file mode 100644 index 0000000..e1754a3 --- /dev/null +++ b/Achievments/PlaymodeTests/NEG.Utils.Achievments.Tests.Playmode.asmdef @@ -0,0 +1,22 @@ +{ + "name": "NEG.Utils.Achievments.Tests.Playmode", + "rootNamespace": "", + "references": [ + "UnityEngine.TestRunner", + "UnityEditor.TestRunner", + "NEG.Utils.Achievments" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [ + "nunit.framework.dll" + ], + "autoReferenced": false, + "defineConstraints": [ + "UNITY_INCLUDE_TESTS" + ], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Achievments/PlaymodeTests/NEG.Utils.Achievments.Tests.Playmode.asmdef.meta b/Achievments/PlaymodeTests/NEG.Utils.Achievments.Tests.Playmode.asmdef.meta new file mode 100644 index 0000000..1bb12eb --- /dev/null +++ b/Achievments/PlaymodeTests/NEG.Utils.Achievments.Tests.Playmode.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 38e8b1e483202e14182d34baaea3958e +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/PlaymodeTests/TestAssets.meta b/Achievments/PlaymodeTests/TestAssets.meta new file mode 100644 index 0000000..ebead8c --- /dev/null +++ b/Achievments/PlaymodeTests/TestAssets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fad16eb700fc70c408c359dca9a76fc9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/PlaymodeTests/TestAssets/TestLocalBackend.asset b/Achievments/PlaymodeTests/TestAssets/TestLocalBackend.asset new file mode 100644 index 0000000..5cb8195 --- /dev/null +++ b/Achievments/PlaymodeTests/TestAssets/TestLocalBackend.asset @@ -0,0 +1,15 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6a1257a87feec064697193df412554d4, type: 3} + m_Name: TestLocalBackend + m_EditorClassIdentifier: + saveLocation: ./LocalAchievments/Tests.json diff --git a/Achievments/PlaymodeTests/TestAssets/TestLocalBackend.asset.meta b/Achievments/PlaymodeTests/TestAssets/TestLocalBackend.asset.meta new file mode 100644 index 0000000..dd21e44 --- /dev/null +++ b/Achievments/PlaymodeTests/TestAssets/TestLocalBackend.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 47c9689c811dc9842a5a5e9ca19c6e3c +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/TODO.txt b/Achievments/TODO.txt new file mode 100644 index 0000000..ca82cc6 --- /dev/null +++ b/Achievments/TODO.txt @@ -0,0 +1,5 @@ +Static Achievments class (done) +Implement Storage again API (done) +Fix typos +Merge AchievmentCollection with AchievmentManagerConfig (done) +Static backend constructors (done) \ No newline at end of file diff --git a/Achievments/TODO.txt.meta b/Achievments/TODO.txt.meta new file mode 100644 index 0000000..df317ce --- /dev/null +++ b/Achievments/TODO.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 94e4aa3c6dc078c4db6a47949655f8a5 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/Tests.meta b/Achievments/Tests.meta new file mode 100644 index 0000000..ddd7f84 --- /dev/null +++ b/Achievments/Tests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bab659ddb2d136440a51c5c9b76fefcb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/Tests/ConfigTests.cs b/Achievments/Tests/ConfigTests.cs new file mode 100644 index 0000000..50bca12 --- /dev/null +++ b/Achievments/Tests/ConfigTests.cs @@ -0,0 +1,380 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using NUnit.Framework; +using UnityEngine; +using UnityEngine.TestTools; + +namespace NEG.Utils.Achievments.Tests +{ + using AchievmentTypes; + using static Internal.Extensions; + + public class ConfigTests + { + public const string AchievmentsLabel = "TestAchievments"; + + public const string AchievmentIdToggle = "TOGGLE"; + public const string AchievmentIdInt = "INT"; + public const string AchievmentIdFloat = "FLOAT"; + public const string AchievmentIdInvalid = "huptyrz"; + public const int RandomProgress = 15; + public const int ProgressChangeDelta = 15; + public const int CompletedProgress = 100; + public const int OvershootProgress = 150; + + #region Id And Types + [Test] + public void AchivmentInvalidId() + { + AchievmentManager manager = AchievmentManager.Builder.FromLabeledConfig(AchievmentsLabel).Build(); + + TestInvalidId(AchievmentIdInvalid, (id) => manager.GetAchievmentForId(id), "Get"); + } + + [Test] + public void AchivmentInvalidType() + { + AchievmentManager manager = AchievmentManager.Builder.FromLabeledConfig(AchievmentsLabel).Build(); + + manager.TestInvalidType(AchievmentIdToggle, "Toggle"); + manager.TestInvalidType(AchievmentIdInt, "Int"); + manager.TestInvalidType(AchievmentIdFloat, "Float"); + } + + [Test] + public void AchivmentCorrectIdAndType() + { + AchievmentManager manager = AchievmentManager.Builder.FromLabeledConfig(AchievmentsLabel).Build(); + + manager.TestValidIdAndType(AchievmentIdToggle, "Toggle"); + manager.TestValidIdAndType(AchievmentIdInt, "Int"); + manager.TestValidIdAndType(AchievmentIdFloat, "Float"); + } + #endregion + + #region Toggle + [Test] + public void AchivmentToggleSet() + { + var callbackTester = new TestCallbackRereiver(); + + AchievmentManager manager = AchievmentManager.Builder.FromLabeledConfig(AchievmentsLabel) + .WithCallbackReciever(callbackTester) + .Build(); + + manager.SetToggleAchivment(AchievmentIdToggle); + callbackTester.TestCompleted(AchievmentIdToggle); + callbackTester.Reset(); + + manager.SetToggleAchivment(AchievmentIdToggle); + callbackTester.TestNoChanges(); + } + + #endregion + + #region Int + [Test] + public void AchivmentIntSetLess() + { + var callbackTester = new TestCallbackRereiver(); + + AchievmentManager manager = AchievmentManager.Builder.FromLabeledConfig(AchievmentsLabel) + .WithCallbackReciever(callbackTester) + .Build(); + + //Set progress to some value progress + manager.SetIntProgress(AchievmentIdInt, RandomProgress); + var data = callbackTester.GetChanged(); + + Assert.AreEqual(RandomProgress, data.CurrentProgress); + Assert.IsFalse(data.IsCompleted); + callbackTester.Reset(); + } + + [Test] + public void AchivmentIntSetEqual() + { + var callbackTester = new TestCallbackRereiver(); + + AchievmentManager manager = AchievmentManager.Builder.FromLabeledConfig(AchievmentsLabel) + .WithCallbackReciever(callbackTester) + .Build(); + + //Set progress to some value equal to required value + manager.SetIntProgress(AchievmentIdInt, CompletedProgress); + var data = callbackTester.GetChanged(); + Assert.AreEqual(CompletedProgress, data.CurrentProgress); + callbackTester.TestCompleted(AchievmentIdInt); + callbackTester.Reset(); + + //Do that again, this time nothing sould change + manager.SetIntProgress(AchievmentIdInt, CompletedProgress); + callbackTester.TestNoChanges(); + callbackTester.Reset(); + + } + + [Test] + public void AchivmentIntSetGreater() + { + var callbackTester = new TestCallbackRereiver(); + + AchievmentManager manager = AchievmentManager.Builder.FromLabeledConfig(AchievmentsLabel) + .WithCallbackReciever(callbackTester) + .Build(); + + //Set progress to some value greater than required + manager.SetIntProgress(AchievmentIdInt, OvershootProgress); + var data = callbackTester.GetChanged(); + //Testing against completed progress, should be clamped down + Assert.AreEqual(CompletedProgress, data.CurrentProgress); + callbackTester.TestCompleted(AchievmentIdInt); + callbackTester.Reset(); + + //Do that again, this time nothing sould change + manager.SetIntProgress(AchievmentIdInt, OvershootProgress); + callbackTester.TestNoChanges(); + callbackTester.Reset(); + } + + [Test] + public void AchivmentIntChangeCompletion() + { + var callbackTester = new TestCallbackRereiver(); + + AchievmentManager manager = AchievmentManager.Builder.FromLabeledConfig(AchievmentsLabel) + .WithCallbackReciever(callbackTester) + .Build(); + + //Add progresss one interval below completion + for (int i = 0; i < CompletedProgress / ProgressChangeDelta; i++) + { + manager.ChangeIntProgress(AchievmentIdInt, ProgressChangeDelta); + callbackTester.TestNotCompleted(); + var changed = callbackTester.GetChanged(); + + Assert.AreEqual((i + 1) * ProgressChangeDelta, changed.CurrentProgress); + callbackTester.Reset(); + } + + //Add progress one more time, should now be completed + manager.ChangeIntProgress(AchievmentIdInt, ProgressChangeDelta); + var changed1 = callbackTester.GetChanged(); + Assert.AreEqual(CompletedProgress, changed1.CurrentProgress); + callbackTester.TestCompleted(AchievmentIdInt); + callbackTester.Reset(); + + //Do that again, this time nothing should change + manager.ChangeIntProgress(AchievmentIdInt, ProgressChangeDelta); + callbackTester.TestNoChanges(); + callbackTester.Reset(); + + //Do that again, but down this time also nothing should change + manager.ChangeIntProgress(AchievmentIdInt, -ProgressChangeDelta); + callbackTester.TestNoChanges(); + callbackTester.Reset(); + } + #endregion + + #region Float + [Test] + public void AchivmentFloatSetLess() + { + var callbackTester = new TestCallbackRereiver(); + + AchievmentManager manager = AchievmentManager.Builder.FromLabeledConfig(AchievmentsLabel) + .WithCallbackReciever(callbackTester) + .Build(); + + //Set progress to some value progress + manager.SetFloatProgress(AchievmentIdFloat, RandomProgress); + var data = callbackTester.GetChanged(); + + Assert.AreEqual((float)RandomProgress, data.CurrentProgress); + Assert.IsFalse(data.IsCompleted); + callbackTester.Reset(); + } + + [Test] + public void AchivmentFloatSetEqual() + { + var callbackTester = new TestCallbackRereiver(); + + AchievmentManager manager = AchievmentManager.Builder.FromLabeledConfig(AchievmentsLabel) + .WithCallbackReciever(callbackTester) + .Build(); + + //Set progress to some value equal to required value + manager.SetFloatProgress(AchievmentIdFloat, CompletedProgress); + var data = callbackTester.GetChanged(); + Assert.AreEqual((float)CompletedProgress, data.CurrentProgress); + callbackTester.TestCompleted(AchievmentIdFloat); + callbackTester.Reset(); + + //Do that again, this time nothing sould change + manager.SetFloatProgress(AchievmentIdFloat, CompletedProgress); + callbackTester.TestNoChanges(); + callbackTester.Reset(); + + } + + [Test] + public void AchivmentFloatSetGreater() + { + var callbackTester = new TestCallbackRereiver(); + + AchievmentManager manager = AchievmentManager.Builder.FromLabeledConfig(AchievmentsLabel) + .WithCallbackReciever(callbackTester) + .Build(); + + //Set progress to some value greater than required + manager.SetFloatProgress(AchievmentIdFloat, OvershootProgress); + var data = callbackTester.GetChanged(); + //Testing against completed progress, should be clamped down + Assert.AreEqual((float)CompletedProgress, data.CurrentProgress); + callbackTester.TestCompleted(AchievmentIdFloat); + callbackTester.Reset(); + + //Do that again, this time nothing sould change + manager.SetFloatProgress(AchievmentIdFloat, OvershootProgress); + callbackTester.TestNoChanges(); + callbackTester.Reset(); + } + + [Test] + public void AchivmentFloatChangeCompletion() + { + var callbackTester = new TestCallbackRereiver(); + + AchievmentManager manager = AchievmentManager.Builder.FromLabeledConfig(AchievmentsLabel) + .WithCallbackReciever(callbackTester) + .Build(); + + //Add progresss one interval below completion + for (int i = 0; i < CompletedProgress / ProgressChangeDelta; i++) + { + manager.ChangeFloatProgress(AchievmentIdFloat, ProgressChangeDelta); + callbackTester.TestNotCompleted(); + var changed = callbackTester.GetChanged(); + + Assert.AreEqual((i + 1) * ProgressChangeDelta, changed.CurrentProgress, 0.0f); + callbackTester.Reset(); + } + + //Add progress one more time, should now be completed + manager.ChangeFloatProgress(AchievmentIdFloat, ProgressChangeDelta); + var changed1 = callbackTester.GetChanged(); + Assert.AreEqual((float)CompletedProgress, changed1.CurrentProgress); + callbackTester.TestCompleted(AchievmentIdFloat); + callbackTester.Reset(); + + //Do that again, this time nothing should change + manager.ChangeFloatProgress(AchievmentIdFloat, ProgressChangeDelta); + callbackTester.TestNoChanges(); + callbackTester.Reset(); + + //Do that again, but down this time also nothing should change + manager.ChangeFloatProgress(AchievmentIdFloat, -ProgressChangeDelta); + callbackTester.TestNoChanges(); + callbackTester.Reset(); + } + #endregion + + private class TestCallbackRereiver : IAchievmentCallbackReciever + { + public AchievmentData LastDataUpdated { get; private set; } = null; + public Type LastTypeSet { get; private set; } = null; + public string LastIdSet { get; private set; } = null; + + public void Reset() + { + LastDataUpdated = null; + LastTypeSet = null; + LastIdSet = null; + } + + public T GetChanged() where T : AchievmentData + { + Assert.IsInstanceOf(typeof(T), LastDataUpdated); + + return (T)LastDataUpdated; + } + + public void TestNoChanges() + { + Assert.IsNull(LastDataUpdated); + Assert.IsNull(LastTypeSet); + Assert.IsNull(LastIdSet); + } + + public void TestNotCompleted() + { + //No need to also check LastTypeSet, they are both set or bot null + Assert.IsNull(LastIdSet); + } + + public void TestCompleted(string id) + { + Assert.AreEqual(typeof(Type), LastTypeSet); + Assert.AreEqual(id, LastIdSet); + //Shold not be null: if we axpect achievment to be completed it must have also been updated + Assert.IsTrue(LastDataUpdated.IsCompleted); + } + + public void AchievmentCompleted(AchievmentData achievment) + { + LastTypeSet = achievment.GetType(); + LastIdSet = achievment.Achievment.Id; + } + + public void AchievmentStateChanged(AchievmentData achievment) + { + LastDataUpdated = achievment; + } + } + } + + namespace Internal + { + public static class Extensions + { + public static void TestValidIdAndType(this AchievmentManager manager, string id, string testName) where Type : AchievmentData + { + TestValidIdAndType(id, (id) => manager.GetAchievmentForId(id), testName); + } + + public static void TestValidIdAndType(string id, Action manipulation, string testName) + { + Assert.DoesNotThrow(() => manipulation(id), $"{testName}: Invalid type or id"); + } + + public static void TestInvalidId(this AchievmentManager manager, string id, string testName) + { + TestInvalidId(id, (id) => manager.GetAchievmentForId(id), testName); + } + + public static void TestInvalidId(string id, Action manipulation, string testName) + { + var exception = Assert.Throws(() => manipulation(id), $"Expected to fail with {typeof(AchievmentTypeException)}"); + + Assert.AreEqual(exception.Id, id, $"{testName}: Achievment id does not match"); + } + + public static void TestInvalidType(this AchievmentManager manager, string id, string testName) where Expected : AchievmentData where Actual : AchievmentData + { + TestInvalidType(id, (id) => manager.GetAchievmentForId(id), testName); + } + + public static void TestInvalidType(string id, Action manipulation, string testName) where Expected : AchievmentData where Actual : AchievmentData + { + var exception = Assert.Throws(() => manipulation(id), $"Expected to fail with {typeof(AchievmentTypeException)}"); + + Assert.AreEqual(id, exception.Id, $"{testName}: Achievment id does not match"); + Assert.AreSame(typeof(Expected), exception.Expected, $"{testName}: Target achievment type does not match"); + Assert.AreSame(typeof(Actual), exception.Actual, $"{testName}: Actual achievment type does not match"); + } + + } + } +} \ No newline at end of file diff --git a/Achievments/Tests/ConfigTests.cs.meta b/Achievments/Tests/ConfigTests.cs.meta new file mode 100644 index 0000000..fb7923b --- /dev/null +++ b/Achievments/Tests/ConfigTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c47a38eaf8bffa849b130320427701cc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/Tests/NEG.Utils.Achivments.Tests.asmdef b/Achievments/Tests/NEG.Utils.Achivments.Tests.asmdef new file mode 100644 index 0000000..32915c0 --- /dev/null +++ b/Achievments/Tests/NEG.Utils.Achivments.Tests.asmdef @@ -0,0 +1,26 @@ +{ + "name": "NEG.Utils.Achivments.Tests", + "rootNamespace": "", + "references": [ + "UnityEngine.TestRunner", + "UnityEditor.TestRunner", + "Unity.Addressables", + "Unity.ResourceManager", + "NEG.Utils.Achievments" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [ + "nunit.framework.dll" + ], + "autoReferenced": false, + "defineConstraints": [ + "UNITY_INCLUDE_TESTS" + ], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/Achievments/Tests/NEG.Utils.Achivments.Tests.asmdef.meta b/Achievments/Tests/NEG.Utils.Achivments.Tests.asmdef.meta new file mode 100644 index 0000000..8d89c87 --- /dev/null +++ b/Achievments/Tests/NEG.Utils.Achivments.Tests.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 18b8be0ae04b6ad45ba52b2ddeb8198d +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/Tests/TestAssets.meta b/Achievments/Tests/TestAssets.meta new file mode 100644 index 0000000..98c83f5 --- /dev/null +++ b/Achievments/Tests/TestAssets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3f7445ed9dd5a4548b89d56c196cbec7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/Tests/TestAssets/BaseConfig.asset b/Achievments/Tests/TestAssets/BaseConfig.asset new file mode 100644 index 0000000..1511dcb --- /dev/null +++ b/Achievments/Tests/TestAssets/BaseConfig.asset @@ -0,0 +1,18 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 88120b6e616164f489387a6a32a25dee, type: 3} + m_Name: BaseConfig + m_EditorClassIdentifier: + k__BackingField: + - {fileID: 11400000, guid: 7734df2e5d4033346aac56f0a2b2a836, type: 2} + - {fileID: 11400000, guid: c704b1ea2247ad540842a9caff628211, type: 2} + - {fileID: 11400000, guid: c71840de74e747e45afc82ecf8922dcd, type: 2} diff --git a/Achievments/Tests/TestAssets/BaseConfig.asset.meta b/Achievments/Tests/TestAssets/BaseConfig.asset.meta new file mode 100644 index 0000000..5f01ffd --- /dev/null +++ b/Achievments/Tests/TestAssets/BaseConfig.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 15513fd07fae44548bac5d923171a2a3 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/Tests/TestAssets/Float.asset b/Achievments/Tests/TestAssets/Float.asset new file mode 100644 index 0000000..8d39d71 --- /dev/null +++ b/Achievments/Tests/TestAssets/Float.asset @@ -0,0 +1,18 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2d7270d5452c9b04ca07ef43a491a18d, type: 3} + m_Name: Float + m_EditorClassIdentifier: + k__BackingField: FLOAT + k__BackingField: 100 + k__BackingField: 0 + k__BackingField: 0 diff --git a/Achievments/Tests/TestAssets/Float.asset.meta b/Achievments/Tests/TestAssets/Float.asset.meta new file mode 100644 index 0000000..326ee38 --- /dev/null +++ b/Achievments/Tests/TestAssets/Float.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7734df2e5d4033346aac56f0a2b2a836 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/Tests/TestAssets/Int.asset b/Achievments/Tests/TestAssets/Int.asset new file mode 100644 index 0000000..5e61751 --- /dev/null +++ b/Achievments/Tests/TestAssets/Int.asset @@ -0,0 +1,18 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5318fea685aa56646a3310c38a9a9bac, type: 3} + m_Name: Int + m_EditorClassIdentifier: + k__BackingField: INT + k__BackingField: 100 + k__BackingField: 0 + k__BackingField: 0 diff --git a/Achievments/Tests/TestAssets/Int.asset.meta b/Achievments/Tests/TestAssets/Int.asset.meta new file mode 100644 index 0000000..b89ba06 --- /dev/null +++ b/Achievments/Tests/TestAssets/Int.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c704b1ea2247ad540842a9caff628211 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/Tests/TestAssets/Toggle.asset b/Achievments/Tests/TestAssets/Toggle.asset new file mode 100644 index 0000000..afd65bb --- /dev/null +++ b/Achievments/Tests/TestAssets/Toggle.asset @@ -0,0 +1,15 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 608c7e921b8b16b42919fc6f55b67fcb, type: 3} + m_Name: Toggle + m_EditorClassIdentifier: + k__BackingField: TOGGLE diff --git a/Achievments/Tests/TestAssets/Toggle.asset.meta b/Achievments/Tests/TestAssets/Toggle.asset.meta new file mode 100644 index 0000000..ca5f86a --- /dev/null +++ b/Achievments/Tests/TestAssets/Toggle.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c71840de74e747e45afc82ecf8922dcd +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: