From 991c9ccdcca2f063dcec799fffcef9eda67b6298 Mon Sep 17 00:00:00 2001 From: LubieKakao1212 Date: Wed, 21 Dec 2022 15:13:55 +0100 Subject: [PATCH 01/12] Achivment system (untested) --- Achivments.meta | 8 + Achivments/AchivmentData.cs | 22 ++ Achivments/AchivmentData.cs.meta | 11 + Achivments/AchivmentDefinition.cs | 34 ++++ Achivments/AchivmentDefinition.cs.meta | 11 + Achivments/AchivmentDefinitionCollection.cs | 13 ++ .../AchivmentDefinitionCollection.cs.meta | 11 + Achivments/AchivmentManager.cs | 191 ++++++++++++++++++ Achivments/AchivmentManager.cs.meta | 11 + Achivments/AchivmentManagerConfig.cs | 25 +++ Achivments/AchivmentManagerConfig.cs.meta | 11 + Achivments/Backend.meta | 8 + Achivments/IAchivmentCallbackReciever.cs | 23 +++ Achivments/IAchivmentCallbackReciever.cs.meta | 11 + Achivments/IAchivmentManagerConfig.cs | 21 ++ Achivments/IAchivmentManagerConfig.cs.meta | 11 + Achivments/IAchivmentStorage.cs | 11 + Achivments/IAchivmentStorage.cs.meta | 11 + Achivments/NEG.Utils.Achivments.asmdef | 17 ++ Achivments/NEG.Utils.Achivments.asmdef.meta | 7 + 20 files changed, 468 insertions(+) create mode 100644 Achivments.meta create mode 100644 Achivments/AchivmentData.cs create mode 100644 Achivments/AchivmentData.cs.meta create mode 100644 Achivments/AchivmentDefinition.cs create mode 100644 Achivments/AchivmentDefinition.cs.meta create mode 100644 Achivments/AchivmentDefinitionCollection.cs create mode 100644 Achivments/AchivmentDefinitionCollection.cs.meta create mode 100644 Achivments/AchivmentManager.cs create mode 100644 Achivments/AchivmentManager.cs.meta create mode 100644 Achivments/AchivmentManagerConfig.cs create mode 100644 Achivments/AchivmentManagerConfig.cs.meta create mode 100644 Achivments/Backend.meta create mode 100644 Achivments/IAchivmentCallbackReciever.cs create mode 100644 Achivments/IAchivmentCallbackReciever.cs.meta create mode 100644 Achivments/IAchivmentManagerConfig.cs create mode 100644 Achivments/IAchivmentManagerConfig.cs.meta create mode 100644 Achivments/IAchivmentStorage.cs create mode 100644 Achivments/IAchivmentStorage.cs.meta create mode 100644 Achivments/NEG.Utils.Achivments.asmdef create mode 100644 Achivments/NEG.Utils.Achivments.asmdef.meta diff --git a/Achivments.meta b/Achivments.meta new file mode 100644 index 0000000..b169e48 --- /dev/null +++ b/Achivments.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ff9bb206aea50d14997771b9a0cc2b04 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achivments/AchivmentData.cs b/Achivments/AchivmentData.cs new file mode 100644 index 0000000..274abbd --- /dev/null +++ b/Achivments/AchivmentData.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json.Linq; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace NEG.Utils.Achivments +{ + public class AchivmentData + { + public AchivmentDefinition Achivment { get; private set; } + + public int ProgressLeft { get; internal set; } + + public bool IsCompleted => ProgressLeft <= 0; + + public AchivmentData(AchivmentDefinition achivment, int progressLeft) + { + Achivment = achivment; + ProgressLeft = progressLeft; + } + } +} \ No newline at end of file diff --git a/Achivments/AchivmentData.cs.meta b/Achivments/AchivmentData.cs.meta new file mode 100644 index 0000000..b67c171 --- /dev/null +++ b/Achivments/AchivmentData.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fad96d35cce2d3e469d300e6e48a048a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achivments/AchivmentDefinition.cs b/Achivments/AchivmentDefinition.cs new file mode 100644 index 0000000..703d34d --- /dev/null +++ b/Achivments/AchivmentDefinition.cs @@ -0,0 +1,34 @@ +using Newtonsoft.Json.Linq; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace NEG.Utils.Achivments +{ + [CreateAssetMenu(menuName = "Achivments/AchivmentDefinition")] + public class AchivmentDefinition : ScriptableObject + { + public JToken AdditionalData + { + get + { + additionalData ??= JObject.Parse(additionalDataInitializer); + return additionalData; + } + } + + [field: SerializeField] + public string Id { get; private set; } + + [field: Tooltip("Amount of progress required for completion, required to be at leas 1, otherwise would be considered completed from the beginning")] + [field: Min(1)] + [field: SerializeField] + public int ProgressRequired { get; private set; } = 1; + + [SerializeField] + [Tooltip("Temporary until json editor is a thing")] + private string additionalDataInitializer; + + private JToken additionalData; + } +} \ No newline at end of file diff --git a/Achivments/AchivmentDefinition.cs.meta b/Achivments/AchivmentDefinition.cs.meta new file mode 100644 index 0000000..aaaa367 --- /dev/null +++ b/Achivments/AchivmentDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f9bd42dd58472044b8ecc0d69caa7da8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achivments/AchivmentDefinitionCollection.cs b/Achivments/AchivmentDefinitionCollection.cs new file mode 100644 index 0000000..9feb592 --- /dev/null +++ b/Achivments/AchivmentDefinitionCollection.cs @@ -0,0 +1,13 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace NEG.Utils.Achivments +{ + [CreateAssetMenu(menuName = "Achivments/Collection")] + public class AchivmentDefinitionCollection : ScriptableObject + { + [field: SerializeField] + public List Achivments { get; private set; } = new List(); + } +} \ No newline at end of file diff --git a/Achivments/AchivmentDefinitionCollection.cs.meta b/Achivments/AchivmentDefinitionCollection.cs.meta new file mode 100644 index 0000000..59d4a05 --- /dev/null +++ b/Achivments/AchivmentDefinitionCollection.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ef37a873be859d042bda22dee624e429 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achivments/AchivmentManager.cs b/Achivments/AchivmentManager.cs new file mode 100644 index 0000000..ead9a9a --- /dev/null +++ b/Achivments/AchivmentManager.cs @@ -0,0 +1,191 @@ +using System.Collections; +using System.Collections.Generic; +using System; +using UnityEngine; +using UnityEngine.AddressableAssets; +using System.Runtime.CompilerServices; + +namespace NEG.Utils.Achivments +{ + public class AchivmentManager + { + public class Builder + { + public const string DefaultAchivmentsConfigLabel = "Achivments"; + + private AchivmentManager manager = new AchivmentManager(); + private IAchivmentStorage storage; + + public static Builder FromDefaultConfig() + { + return FromLabeledConfig(DefaultAchivmentsConfigLabel); + } + + public static Builder FromLabeledConfig(string label) + { + var builder = new Builder(); + + var handle = Addressables.LoadAssetsAsync(DefaultAchivmentsConfigLabel, 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 WithLabeledDefinitions(string label) + { + var handle = Addressables.LoadAssetsAsync(label, delegate { }, Addressables.MergeMode.Union, false); + + var achivmentCollections = handle.WaitForCompletion(); + + foreach (var achivmentCollection in achivmentCollections) + WithDefinitionsFrom(achivmentCollection); + + return this; + } + + public Builder WithDefinitionsFrom(AchivmentDefinitionCollection collection) + { + foreach (var def in collection.Achivments) + { + manager.RegisterAchivment(def); + } + + return this; + } + + public Builder LoadedFrom(IAchivmentStorage storageIn) + { + if (storage != null) + { + throw new ApplicationException("Cannot Load achivment data from multiple storage instances"); + } + + this.storage = storageIn; + + return this; + } + + public Builder WithCallbackReciever(IAchivmentCallbackReciever callbackReciever) + { + manager.AddCallbackReciever(callbackReciever); + return this; + } + + public AchivmentManager Build() + { + if (storage != null) + { + manager.LoadFrom(storage); + } + return manager; + } + } + + public delegate void AchivmentSetCallback(AchivmentData achivment); + public delegate void AchivmentProgressSetCallback(AchivmentData achivment, int progressLeft); + + public event AchivmentSetCallback AchivmentSet; + public event AchivmentProgressSetCallback AchivmentProgressSet; + + private Dictionary definitionCache; + private Dictionary dataCache; + + private AchivmentManager() + { + definitionCache = new Dictionary(); + dataCache = new Dictionary(); + } + + private void RegisterAchivment(AchivmentDefinition definition) + { + if (!definitionCache.ContainsKey(definition.Id)) + { + definitionCache.Add(definition.Id, definition); + dataCache.Add(definition, new AchivmentData(definition, definition.ProgressRequired)); + } + else + { + Debug.LogWarning($"Duplicate Achivment with ID: {definition.Id}"); + } + } + + private void LoadFrom(IAchivmentStorage achivmentStorage) + { + foreach (var entry in definitionCache) + { + var storedProgress = achivmentStorage.GetStoredAchivmentProgress(entry.Key); + + dataCache[entry.Value].ProgressLeft = storedProgress; + } + } + + public void AddCallbackRecievers(IEnumerable initialCallbacks) + { + foreach (var callback in initialCallbacks) + { + AddCallbackReciever(callback); + } + } + + public void AddCallbackReciever(IAchivmentCallbackReciever callback) + { + AchivmentSet += callback.SetAchivment; + AchivmentProgressSet += callback.SetAchivmentProgress; + } + + public void RemoveCallbackReciever(IAchivmentCallbackReciever callback) + { + AchivmentSet -= callback.SetAchivment; + AchivmentProgressSet -= callback.SetAchivmentProgress; + } + + public void SetAchivment(string id) + { + var data = GetAchivmentForId(id); + data.ProgressLeft = 0; + AchivmentSet?.Invoke(data); + } + + public void AddProgress(string id, int amount) + { + var data = GetAchivmentForId(id); + if (data.IsCompleted) + { + return; + } + data.ProgressLeft = Mathf.Max(data.ProgressLeft - amount, 0); + AchivmentProgressSet?.Invoke(data, data.Achivment.ProgressRequired - data.ProgressLeft); + + if (data.IsCompleted) + { + AchivmentSet?.Invoke(data); + } + } + + private AchivmentData GetAchivmentForId(string id) + { + var def = definitionCache.GetValueOrDefault(id); + if (def != null) + { + return dataCache[def]; + } + else + { + throw new ApplicationException("Invalid achivment id"); + } + } + } +} \ No newline at end of file diff --git a/Achivments/AchivmentManager.cs.meta b/Achivments/AchivmentManager.cs.meta new file mode 100644 index 0000000..fc0282b --- /dev/null +++ b/Achivments/AchivmentManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 841f326ebfd59e646835bf81432d3ae4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achivments/AchivmentManagerConfig.cs b/Achivments/AchivmentManagerConfig.cs new file mode 100644 index 0000000..19402d8 --- /dev/null +++ b/Achivments/AchivmentManagerConfig.cs @@ -0,0 +1,25 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace NEG.Utils.Achivments +{ + [CreateAssetMenu(menuName = "Achivments/BaseConfig")] + public class AchivmentManagerConfig : ScriptableObject, IAchivmentManagerConfig + { + public const string DefaultAchivmentsCollectionLabel = "Achivments"; + + [field: SerializeField] + public string AchivmentCollectionAssetLabel { get; private set; } = DefaultAchivmentsCollectionLabel; + + public void Apply(AchivmentManager.Builder builder) + { + builder.WithLabeledDefinitions(AchivmentCollectionAssetLabel); + } + + public void ApplyLast(AchivmentManager.Builder builder) + { + + } + } +} \ No newline at end of file diff --git a/Achivments/AchivmentManagerConfig.cs.meta b/Achivments/AchivmentManagerConfig.cs.meta new file mode 100644 index 0000000..3e43f82 --- /dev/null +++ b/Achivments/AchivmentManagerConfig.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/Achivments/Backend.meta b/Achivments/Backend.meta new file mode 100644 index 0000000..4ba2000 --- /dev/null +++ b/Achivments/Backend.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 48ec3460d89c2f144827761002d7f4d9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achivments/IAchivmentCallbackReciever.cs b/Achivments/IAchivmentCallbackReciever.cs new file mode 100644 index 0000000..e57defb --- /dev/null +++ b/Achivments/IAchivmentCallbackReciever.cs @@ -0,0 +1,23 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace NEG.Utils.Achivments +{ + public interface IAchivmentCallbackReciever + { + /// + /// Called when an achivment is completed + /// + /// + /// + void SetAchivment(AchivmentData achivment); + + /// + /// Called when achivment progress changes + /// + /// + /// Current achivment progress, equal to - + void SetAchivmentProgress(AchivmentData achivment, int progress); + } +} \ No newline at end of file diff --git a/Achivments/IAchivmentCallbackReciever.cs.meta b/Achivments/IAchivmentCallbackReciever.cs.meta new file mode 100644 index 0000000..beb55a4 --- /dev/null +++ b/Achivments/IAchivmentCallbackReciever.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/Achivments/IAchivmentManagerConfig.cs b/Achivments/IAchivmentManagerConfig.cs new file mode 100644 index 0000000..10351e1 --- /dev/null +++ b/Achivments/IAchivmentManagerConfig.cs @@ -0,0 +1,21 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace NEG.Utils.Achivments +{ + public interface IAchivmentManagerConfig + { + /// + /// Used to Apply config data + /// + /// + void Apply(AchivmentManager.Builder builder); + + /// + /// Called after was called on every other config + /// + /// + void ApplyLast(AchivmentManager.Builder builder); + } +} \ No newline at end of file diff --git a/Achivments/IAchivmentManagerConfig.cs.meta b/Achivments/IAchivmentManagerConfig.cs.meta new file mode 100644 index 0000000..2fa22ce --- /dev/null +++ b/Achivments/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/Achivments/IAchivmentStorage.cs b/Achivments/IAchivmentStorage.cs new file mode 100644 index 0000000..eade987 --- /dev/null +++ b/Achivments/IAchivmentStorage.cs @@ -0,0 +1,11 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace NEG.Utils.Achivments +{ + public interface IAchivmentStorage + { + public int GetStoredAchivmentProgress(string id); + } +} \ No newline at end of file diff --git a/Achivments/IAchivmentStorage.cs.meta b/Achivments/IAchivmentStorage.cs.meta new file mode 100644 index 0000000..3204777 --- /dev/null +++ b/Achivments/IAchivmentStorage.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/Achivments/NEG.Utils.Achivments.asmdef b/Achivments/NEG.Utils.Achivments.asmdef new file mode 100644 index 0000000..85119ec --- /dev/null +++ b/Achivments/NEG.Utils.Achivments.asmdef @@ -0,0 +1,17 @@ +{ + "name": "NEG.Utils.Achivments", + "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/Achivments/NEG.Utils.Achivments.asmdef.meta b/Achivments/NEG.Utils.Achivments.asmdef.meta new file mode 100644 index 0000000..14bc2c4 --- /dev/null +++ b/Achivments/NEG.Utils.Achivments.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 380ad496eab7ace4b98ceede94941223 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: -- 2.47.2 From 9dfb118f88a5b10d1541cd590adc4e436112fff8 Mon Sep 17 00:00:00 2001 From: LubieKakao1212 Date: Mon, 2 Jan 2023 11:54:46 +0100 Subject: [PATCH 02/12] fix --- Achivments/AchivmentManager.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Achivments/AchivmentManager.cs b/Achivments/AchivmentManager.cs index ead9a9a..0367b35 100644 --- a/Achivments/AchivmentManager.cs +++ b/Achivments/AchivmentManager.cs @@ -1,9 +1,11 @@ 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.Achivments { @@ -24,8 +26,8 @@ namespace NEG.Utils.Achivments public static Builder FromLabeledConfig(string label) { var builder = new Builder(); - - var handle = Addressables.LoadAssetsAsync(DefaultAchivmentsConfigLabel, delegate { }, Addressables.MergeMode.Union, false); + + var handle = Addressables.LoadAssetsAsync((IEnumerable)new string[] { label }, delegate { }, Addressables.MergeMode.Union, false); var configs = handle.WaitForCompletion(); @@ -46,7 +48,7 @@ namespace NEG.Utils.Achivments public Builder WithLabeledDefinitions(string label) { - var handle = Addressables.LoadAssetsAsync(label, delegate { }, Addressables.MergeMode.Union, false); + var handle = Addressables.LoadAssetsAsync((IEnumerable)new string[] { label }, delegate { }, Addressables.MergeMode.Union, false); var achivmentCollections = handle.WaitForCompletion(); @@ -184,7 +186,7 @@ namespace NEG.Utils.Achivments } else { - throw new ApplicationException("Invalid achivment id"); + throw new ApplicationException($"Invalid achivment id {id}"); } } } -- 2.47.2 From 1bd77d9628ecbbf8f6e5ed397d54023bd6b3d4d5 Mon Sep 17 00:00:00 2001 From: LubieKakao1212 Date: Mon, 2 Jan 2023 16:13:04 +0100 Subject: [PATCH 03/12] Abstracified achievment types, removed achievment loading (will be restored in future commits) --- Achivments.meta => Achievments.meta | 0 Achievments/AchievmentManager.cs | 341 ++++++++++++++++++ .../AchievmentManager.cs.meta | 2 +- .../AchievmentTypes.meta | 2 +- Achievments/AchievmentTypes/AchievmentData.cs | 21 ++ .../AchievmentTypes/AchievmentData.cs.meta | 2 +- .../AchievmentTypes/AchievmentDefinition.cs | 15 + .../AchievmentDefinition.cs.meta | 2 +- .../AchievmentTypes/FloatAchievmentData.cs | 35 ++ .../FloatAchievmentData.cs.meta | 11 + .../FloatAchievmentDefinition.cs | 29 ++ .../FloatAchievmentDefinition.cs.meta | 11 + .../AchievmentTypes/IntAchievmentData.cs | 36 ++ .../AchievmentTypes/IntAchievmentData.cs.meta | 11 + .../IntAchievmentDefinition.cs | 27 ++ .../IntAchievmentDefinition.cs.meta | 11 + .../AchievmentTypes/ToggleAchievmentData.cs | 18 + .../ToggleAchievmentData.cs.meta | 11 + .../ToggleAchievmentDefinition.cs | 15 + .../ToggleAchievmentDefinition.cs.meta | 11 + .../AchivmentDefinitionCollection.cs | 6 +- .../AchivmentDefinitionCollection.cs.meta | 0 .../AchivmentManagerConfig.cs | 6 +- .../AchivmentManagerConfig.cs.meta | 0 Achievments/IAchievmentCallbackReciever.cs | 23 ++ .../IAchievmentCallbackReciever.cs.meta | 0 .../IAchivmentManagerConfig.cs | 8 +- .../IAchivmentManagerConfig.cs.meta | 0 .../IAchivmentStorage.cs | 2 +- .../IAchivmentStorage.cs.meta | 0 .../NEG.Utils.Achivments.asmdef | 0 .../NEG.Utils.Achivments.asmdef.meta | 0 Achivments/AchivmentData.cs | 22 -- Achivments/AchivmentDefinition.cs | 34 -- Achivments/AchivmentManager.cs | 193 ---------- Achivments/IAchivmentCallbackReciever.cs | 23 -- 36 files changed, 642 insertions(+), 286 deletions(-) rename Achivments.meta => Achievments.meta (100%) create mode 100644 Achievments/AchievmentManager.cs rename Achivments/AchivmentManager.cs.meta => Achievments/AchievmentManager.cs.meta (83%) rename Achivments/Backend.meta => Achievments/AchievmentTypes.meta (77%) create mode 100644 Achievments/AchievmentTypes/AchievmentData.cs rename Achivments/AchivmentData.cs.meta => Achievments/AchievmentTypes/AchievmentData.cs.meta (83%) create mode 100644 Achievments/AchievmentTypes/AchievmentDefinition.cs rename Achivments/AchivmentDefinition.cs.meta => Achievments/AchievmentTypes/AchievmentDefinition.cs.meta (83%) create mode 100644 Achievments/AchievmentTypes/FloatAchievmentData.cs create mode 100644 Achievments/AchievmentTypes/FloatAchievmentData.cs.meta create mode 100644 Achievments/AchievmentTypes/FloatAchievmentDefinition.cs create mode 100644 Achievments/AchievmentTypes/FloatAchievmentDefinition.cs.meta create mode 100644 Achievments/AchievmentTypes/IntAchievmentData.cs create mode 100644 Achievments/AchievmentTypes/IntAchievmentData.cs.meta create mode 100644 Achievments/AchievmentTypes/IntAchievmentDefinition.cs create mode 100644 Achievments/AchievmentTypes/IntAchievmentDefinition.cs.meta create mode 100644 Achievments/AchievmentTypes/ToggleAchievmentData.cs create mode 100644 Achievments/AchievmentTypes/ToggleAchievmentData.cs.meta create mode 100644 Achievments/AchievmentTypes/ToggleAchievmentDefinition.cs create mode 100644 Achievments/AchievmentTypes/ToggleAchievmentDefinition.cs.meta rename {Achivments => Achievments}/AchivmentDefinitionCollection.cs (59%) rename {Achivments => Achievments}/AchivmentDefinitionCollection.cs.meta (100%) rename {Achivments => Achievments}/AchivmentManagerConfig.cs (79%) rename {Achivments => Achievments}/AchivmentManagerConfig.cs.meta (100%) create mode 100644 Achievments/IAchievmentCallbackReciever.cs rename Achivments/IAchivmentCallbackReciever.cs.meta => Achievments/IAchievmentCallbackReciever.cs.meta (100%) rename {Achivments => Achievments}/IAchivmentManagerConfig.cs (58%) rename {Achivments => Achievments}/IAchivmentManagerConfig.cs.meta (100%) rename {Achivments => Achievments}/IAchivmentStorage.cs (85%) rename {Achivments => Achievments}/IAchivmentStorage.cs.meta (100%) rename {Achivments => Achievments}/NEG.Utils.Achivments.asmdef (100%) rename {Achivments => Achievments}/NEG.Utils.Achivments.asmdef.meta (100%) delete mode 100644 Achivments/AchivmentData.cs delete mode 100644 Achivments/AchivmentDefinition.cs delete mode 100644 Achivments/AchivmentManager.cs delete mode 100644 Achivments/IAchivmentCallbackReciever.cs diff --git a/Achivments.meta b/Achievments.meta similarity index 100% rename from Achivments.meta rename to Achievments.meta diff --git a/Achievments/AchievmentManager.cs b/Achievments/AchievmentManager.cs new file mode 100644 index 0000000..64f26cd --- /dev/null +++ b/Achievments/AchievmentManager.cs @@ -0,0 +1,341 @@ +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 IAchivmentStorage storage; + + 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 WithLabeledDefinitions(string label) + { + var handle = Addressables.LoadAssetsAsync((IEnumerable)new string[] { label }, delegate { }, Addressables.MergeMode.Union, false); + + var achivmentCollections = handle.WaitForCompletion(); + + foreach (var achivmentCollection in achivmentCollections) + WithDefinitionsFrom(achivmentCollection); + + return this; + } + + public Builder WithDefinitionsFrom(AchivmentDefinitionCollection collection) + { + foreach (var def in collection.Achivments) + { + manager.RegisterAchivment(def); + } + + return this; + } + + public Builder LoadedFrom(IAchivmentStorage storageIn) + { + if (storage != null) + { + throw new ApplicationException("Cannot Load achivment data from multiple storage instances"); + } + + this.storage = storageIn; + + return this; + } + + public Builder WithCallbackReciever(IAchievmentCallbackReciever callbackReciever) + { + manager.AddCallbackReciever(callbackReciever); + return this; + } + + public AchievmentManager Build() + { + //TODO + /*if (storage != null) + { + manager.LoadFrom(storage); + }*/ + 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 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}"); + } + } + + /*private void LoadFrom(IAchivmentStorage achivmentStorage) + { + foreach (var entry in definitionCache) + { + var storedProgress = achivmentStorage.GetStoredAchivmentProgress(entry.Key); + + dataCache[entry.Value].ProgressLeft = storedProgress; + } + }*/ + + 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 + /// + /// + /// + 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 .
+ /// If there is no achievment at a given id throws an . If achievment at a given id is of a wrong tupe throws an + ///
+ /// + public void SetToggleAchivment(string id) + { + ManipulateAchievment(id, (achievment) => achievment.CompletionState = true); + } + + /// + /// Gets a completion state from a .
+ /// If there is no achievment at a given id throws an . If achievment at a given id is of a wrong tupe throws an + ///
+ /// + 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 .
+ /// If there is no achievment at a given id throws an . If achievment at a given id is of a wrong tupe throws an . + ///
+ /// + public void SetIntProgress(string id, int progress) + { + ManipulateAchievment(id, (achievment) => achievment.CurrentProgress = progress); + } + + /// + /// Changes progress of a given by , after which sends , also if the achievment is completed sends a .
+ /// If there is no achievment at a given id throws an . If achievment at a given id is of a wrong tupe throws an + ///
+ /// + public void CangeIntProgress(string id, int delta) + { + ManipulateAchievment(id, (achievment) => achievment.CurrentProgress += delta); + } + + /// + /// Gets current progress from a .
+ /// If there is no achievment at a given id throws an . If achievment at a given id is of a wrong tupe throws an + ///
+ /// + 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 .
+ /// If there is no achievment at a given id throws an . If achievment at a given id is of a wrong tupe throws an + ///
+ /// + public void SetFloatProgress(string id, float progress) + { + ManipulateAchievment(id, (achievment) => achievment.CurrentProgress = progress); + } + + /// + /// Changes progress of a given by , after which sends , also if the achievment is completed sends a .
+ /// If there is no achievment at a given id throws an . If achievment at a given id is of a wrong tupe throws an + ///
+ /// + public void CangeFloatProgress(string id, float delta) + { + ManipulateAchievment(id, (achievment) => achievment.CurrentProgress += delta); + } + + /// + /// Gets current progress from a .
+ /// If there is no achievment at a given id throws an . If achievment at a given id is of a wrong tupe throws an + ///
+ /// + 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 either there is no achievment under id or achievment under id is of a different type + public T GetAchievmentForId(string id) where T : AchievmentData + { + return CheckAchievmentType(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 ApplicationException($"Invalid achivment id {id}"); + } + } + + private T CheckAchievmentType(AchievmentData data) where T : AchievmentData + { + if (data is not T convetred) + { + throw new ApplicationException($"Attempting to perform an operation on an invalid achievment type. Expected {typeof(T)} got {data.GetType()}"); + } + return convetred; + } + + /// + /// + /// + /// + /// + /// Action to perform on the achievment + private void ManipulateAchievment(string id, Action manipulation) where T : AchievmentData + { + var data = GetAchievmentForId(id); + + if (CheckNotCompleted(data)) + { + return; + } + + manipulation(data); + + SendUpdateCallbacks(data); + } + + /// + /// 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.Achivment.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/Achivments/AchivmentManager.cs.meta b/Achievments/AchievmentManager.cs.meta similarity index 83% rename from Achivments/AchivmentManager.cs.meta rename to Achievments/AchievmentManager.cs.meta index fc0282b..64e574c 100644 --- a/Achivments/AchivmentManager.cs.meta +++ b/Achievments/AchievmentManager.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 841f326ebfd59e646835bf81432d3ae4 +guid: 7339f725e382e4b4bab7db6d7cc14b30 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Achivments/Backend.meta b/Achievments/AchievmentTypes.meta similarity index 77% rename from Achivments/Backend.meta rename to Achievments/AchievmentTypes.meta index 4ba2000..bb52672 100644 --- a/Achivments/Backend.meta +++ b/Achievments/AchievmentTypes.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 48ec3460d89c2f144827761002d7f4d9 +guid: 79e626bf8b94e5f4d813912f9b1d304e folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Achievments/AchievmentTypes/AchievmentData.cs b/Achievments/AchievmentTypes/AchievmentData.cs new file mode 100644 index 0000000..86a154d --- /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 Achivment { get; private set; } + + public abstract bool IsCompleted { get; } + + public AchievmentData(AchievmentDefinition achivment) + { + Achivment = achivment; + } + } +} \ No newline at end of file diff --git a/Achivments/AchivmentData.cs.meta b/Achievments/AchievmentTypes/AchievmentData.cs.meta similarity index 83% rename from Achivments/AchivmentData.cs.meta rename to Achievments/AchievmentTypes/AchievmentData.cs.meta index b67c171..5fb4884 100644 --- a/Achivments/AchivmentData.cs.meta +++ b/Achievments/AchievmentTypes/AchievmentData.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: fad96d35cce2d3e469d300e6e48a048a +guid: 1f39500a9deabad43b87bc76122646fc MonoImporter: externalObjects: {} serializedVersion: 2 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/Achivments/AchivmentDefinition.cs.meta b/Achievments/AchievmentTypes/AchievmentDefinition.cs.meta similarity index 83% rename from Achivments/AchivmentDefinition.cs.meta rename to Achievments/AchievmentTypes/AchievmentDefinition.cs.meta index aaaa367..1d52a8a 100644 --- a/Achivments/AchivmentDefinition.cs.meta +++ b/Achievments/AchievmentTypes/AchievmentDefinition.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: f9bd42dd58472044b8ecc0d69caa7da8 +guid: 4aef60a6b4e41e243845a476862049e1 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Achievments/AchievmentTypes/FloatAchievmentData.cs b/Achievments/AchievmentTypes/FloatAchievmentData.cs new file mode 100644 index 0000000..27a43ed --- /dev/null +++ b/Achievments/AchievmentTypes/FloatAchievmentData.cs @@ -0,0 +1,35 @@ +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; + + public float CurrentProgress + { + get => currentProgress; + internal 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)Achivment; + + 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..94e900a --- /dev/null +++ b/Achievments/AchievmentTypes/IntAchievmentData.cs @@ -0,0 +1,36 @@ +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; + + public int CurrentProgress + { + get => currentProgress; + internal 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)Achivment; + + 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..c0b9dfa --- /dev/null +++ b/Achievments/AchievmentTypes/ToggleAchievmentData.cs @@ -0,0 +1,18 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace NEG.Utils.Achievments.AchievmentTypes +{ + public class ToggleAchievmentData : AchievmentData + { + public override bool IsCompleted => CompletionState; + + public bool CompletionState { get; internal 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/Achivments/AchivmentDefinitionCollection.cs b/Achievments/AchivmentDefinitionCollection.cs similarity index 59% rename from Achivments/AchivmentDefinitionCollection.cs rename to Achievments/AchivmentDefinitionCollection.cs index 9feb592..fb804d6 100644 --- a/Achivments/AchivmentDefinitionCollection.cs +++ b/Achievments/AchivmentDefinitionCollection.cs @@ -2,12 +2,14 @@ using System.Collections; using System.Collections.Generic; using UnityEngine; -namespace NEG.Utils.Achivments +namespace NEG.Utils.Achievments { + using AchievmentTypes; + [CreateAssetMenu(menuName = "Achivments/Collection")] public class AchivmentDefinitionCollection : ScriptableObject { [field: SerializeField] - public List Achivments { get; private set; } = new List(); + public List Achivments { get; private set; } = new List(); } } \ No newline at end of file diff --git a/Achivments/AchivmentDefinitionCollection.cs.meta b/Achievments/AchivmentDefinitionCollection.cs.meta similarity index 100% rename from Achivments/AchivmentDefinitionCollection.cs.meta rename to Achievments/AchivmentDefinitionCollection.cs.meta diff --git a/Achivments/AchivmentManagerConfig.cs b/Achievments/AchivmentManagerConfig.cs similarity index 79% rename from Achivments/AchivmentManagerConfig.cs rename to Achievments/AchivmentManagerConfig.cs index 19402d8..4815d84 100644 --- a/Achivments/AchivmentManagerConfig.cs +++ b/Achievments/AchivmentManagerConfig.cs @@ -2,7 +2,7 @@ using System.Collections; using System.Collections.Generic; using UnityEngine; -namespace NEG.Utils.Achivments +namespace NEG.Utils.Achievments { [CreateAssetMenu(menuName = "Achivments/BaseConfig")] public class AchivmentManagerConfig : ScriptableObject, IAchivmentManagerConfig @@ -12,12 +12,12 @@ namespace NEG.Utils.Achivments [field: SerializeField] public string AchivmentCollectionAssetLabel { get; private set; } = DefaultAchivmentsCollectionLabel; - public void Apply(AchivmentManager.Builder builder) + public void Apply(AchievmentManager.Builder builder) { builder.WithLabeledDefinitions(AchivmentCollectionAssetLabel); } - public void ApplyLast(AchivmentManager.Builder builder) + public void ApplyLast(AchievmentManager.Builder builder) { } diff --git a/Achivments/AchivmentManagerConfig.cs.meta b/Achievments/AchivmentManagerConfig.cs.meta similarity index 100% rename from Achivments/AchivmentManagerConfig.cs.meta rename to Achievments/AchivmentManagerConfig.cs.meta diff --git a/Achievments/IAchievmentCallbackReciever.cs b/Achievments/IAchievmentCallbackReciever.cs new file mode 100644 index 0000000..6c6a87d --- /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 achivment); + + /// + /// Called when achivment progress changes + /// + /// + void AchievmentStateChanged(AchievmentData achivment); + } +} \ No newline at end of file diff --git a/Achivments/IAchivmentCallbackReciever.cs.meta b/Achievments/IAchievmentCallbackReciever.cs.meta similarity index 100% rename from Achivments/IAchivmentCallbackReciever.cs.meta rename to Achievments/IAchievmentCallbackReciever.cs.meta diff --git a/Achivments/IAchivmentManagerConfig.cs b/Achievments/IAchivmentManagerConfig.cs similarity index 58% rename from Achivments/IAchivmentManagerConfig.cs rename to Achievments/IAchivmentManagerConfig.cs index 10351e1..15628c9 100644 --- a/Achivments/IAchivmentManagerConfig.cs +++ b/Achievments/IAchivmentManagerConfig.cs @@ -2,7 +2,7 @@ using System.Collections; using System.Collections.Generic; using UnityEngine; -namespace NEG.Utils.Achivments +namespace NEG.Utils.Achievments { public interface IAchivmentManagerConfig { @@ -10,12 +10,12 @@ namespace NEG.Utils.Achivments /// Used to Apply config data /// /// - void Apply(AchivmentManager.Builder builder); + void Apply(AchievmentManager.Builder builder); /// - /// Called after was called on every other config + /// Called after was called on every other config /// /// - void ApplyLast(AchivmentManager.Builder builder); + void ApplyLast(AchievmentManager.Builder builder); } } \ No newline at end of file diff --git a/Achivments/IAchivmentManagerConfig.cs.meta b/Achievments/IAchivmentManagerConfig.cs.meta similarity index 100% rename from Achivments/IAchivmentManagerConfig.cs.meta rename to Achievments/IAchivmentManagerConfig.cs.meta diff --git a/Achivments/IAchivmentStorage.cs b/Achievments/IAchivmentStorage.cs similarity index 85% rename from Achivments/IAchivmentStorage.cs rename to Achievments/IAchivmentStorage.cs index eade987..00f0799 100644 --- a/Achivments/IAchivmentStorage.cs +++ b/Achievments/IAchivmentStorage.cs @@ -2,7 +2,7 @@ using System.Collections; using System.Collections.Generic; using UnityEngine; -namespace NEG.Utils.Achivments +namespace NEG.Utils.Achievments { public interface IAchivmentStorage { diff --git a/Achivments/IAchivmentStorage.cs.meta b/Achievments/IAchivmentStorage.cs.meta similarity index 100% rename from Achivments/IAchivmentStorage.cs.meta rename to Achievments/IAchivmentStorage.cs.meta diff --git a/Achivments/NEG.Utils.Achivments.asmdef b/Achievments/NEG.Utils.Achivments.asmdef similarity index 100% rename from Achivments/NEG.Utils.Achivments.asmdef rename to Achievments/NEG.Utils.Achivments.asmdef diff --git a/Achivments/NEG.Utils.Achivments.asmdef.meta b/Achievments/NEG.Utils.Achivments.asmdef.meta similarity index 100% rename from Achivments/NEG.Utils.Achivments.asmdef.meta rename to Achievments/NEG.Utils.Achivments.asmdef.meta diff --git a/Achivments/AchivmentData.cs b/Achivments/AchivmentData.cs deleted file mode 100644 index 274abbd..0000000 --- a/Achivments/AchivmentData.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Newtonsoft.Json.Linq; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace NEG.Utils.Achivments -{ - public class AchivmentData - { - public AchivmentDefinition Achivment { get; private set; } - - public int ProgressLeft { get; internal set; } - - public bool IsCompleted => ProgressLeft <= 0; - - public AchivmentData(AchivmentDefinition achivment, int progressLeft) - { - Achivment = achivment; - ProgressLeft = progressLeft; - } - } -} \ No newline at end of file diff --git a/Achivments/AchivmentDefinition.cs b/Achivments/AchivmentDefinition.cs deleted file mode 100644 index 703d34d..0000000 --- a/Achivments/AchivmentDefinition.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Newtonsoft.Json.Linq; -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace NEG.Utils.Achivments -{ - [CreateAssetMenu(menuName = "Achivments/AchivmentDefinition")] - public class AchivmentDefinition : ScriptableObject - { - public JToken AdditionalData - { - get - { - additionalData ??= JObject.Parse(additionalDataInitializer); - return additionalData; - } - } - - [field: SerializeField] - public string Id { get; private set; } - - [field: Tooltip("Amount of progress required for completion, required to be at leas 1, otherwise would be considered completed from the beginning")] - [field: Min(1)] - [field: SerializeField] - public int ProgressRequired { get; private set; } = 1; - - [SerializeField] - [Tooltip("Temporary until json editor is a thing")] - private string additionalDataInitializer; - - private JToken additionalData; - } -} \ No newline at end of file diff --git a/Achivments/AchivmentManager.cs b/Achivments/AchivmentManager.cs deleted file mode 100644 index 0367b35..0000000 --- a/Achivments/AchivmentManager.cs +++ /dev/null @@ -1,193 +0,0 @@ -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.Achivments -{ - public class AchivmentManager - { - public class Builder - { - public const string DefaultAchivmentsConfigLabel = "Achivments"; - - private AchivmentManager manager = new AchivmentManager(); - private IAchivmentStorage storage; - - 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 WithLabeledDefinitions(string label) - { - var handle = Addressables.LoadAssetsAsync((IEnumerable)new string[] { label }, delegate { }, Addressables.MergeMode.Union, false); - - var achivmentCollections = handle.WaitForCompletion(); - - foreach (var achivmentCollection in achivmentCollections) - WithDefinitionsFrom(achivmentCollection); - - return this; - } - - public Builder WithDefinitionsFrom(AchivmentDefinitionCollection collection) - { - foreach (var def in collection.Achivments) - { - manager.RegisterAchivment(def); - } - - return this; - } - - public Builder LoadedFrom(IAchivmentStorage storageIn) - { - if (storage != null) - { - throw new ApplicationException("Cannot Load achivment data from multiple storage instances"); - } - - this.storage = storageIn; - - return this; - } - - public Builder WithCallbackReciever(IAchivmentCallbackReciever callbackReciever) - { - manager.AddCallbackReciever(callbackReciever); - return this; - } - - public AchivmentManager Build() - { - if (storage != null) - { - manager.LoadFrom(storage); - } - return manager; - } - } - - public delegate void AchivmentSetCallback(AchivmentData achivment); - public delegate void AchivmentProgressSetCallback(AchivmentData achivment, int progressLeft); - - public event AchivmentSetCallback AchivmentSet; - public event AchivmentProgressSetCallback AchivmentProgressSet; - - private Dictionary definitionCache; - private Dictionary dataCache; - - private AchivmentManager() - { - definitionCache = new Dictionary(); - dataCache = new Dictionary(); - } - - private void RegisterAchivment(AchivmentDefinition definition) - { - if (!definitionCache.ContainsKey(definition.Id)) - { - definitionCache.Add(definition.Id, definition); - dataCache.Add(definition, new AchivmentData(definition, definition.ProgressRequired)); - } - else - { - Debug.LogWarning($"Duplicate Achivment with ID: {definition.Id}"); - } - } - - private void LoadFrom(IAchivmentStorage achivmentStorage) - { - foreach (var entry in definitionCache) - { - var storedProgress = achivmentStorage.GetStoredAchivmentProgress(entry.Key); - - dataCache[entry.Value].ProgressLeft = storedProgress; - } - } - - public void AddCallbackRecievers(IEnumerable initialCallbacks) - { - foreach (var callback in initialCallbacks) - { - AddCallbackReciever(callback); - } - } - - public void AddCallbackReciever(IAchivmentCallbackReciever callback) - { - AchivmentSet += callback.SetAchivment; - AchivmentProgressSet += callback.SetAchivmentProgress; - } - - public void RemoveCallbackReciever(IAchivmentCallbackReciever callback) - { - AchivmentSet -= callback.SetAchivment; - AchivmentProgressSet -= callback.SetAchivmentProgress; - } - - public void SetAchivment(string id) - { - var data = GetAchivmentForId(id); - data.ProgressLeft = 0; - AchivmentSet?.Invoke(data); - } - - public void AddProgress(string id, int amount) - { - var data = GetAchivmentForId(id); - if (data.IsCompleted) - { - return; - } - data.ProgressLeft = Mathf.Max(data.ProgressLeft - amount, 0); - AchivmentProgressSet?.Invoke(data, data.Achivment.ProgressRequired - data.ProgressLeft); - - if (data.IsCompleted) - { - AchivmentSet?.Invoke(data); - } - } - - private AchivmentData GetAchivmentForId(string id) - { - var def = definitionCache.GetValueOrDefault(id); - if (def != null) - { - return dataCache[def]; - } - else - { - throw new ApplicationException($"Invalid achivment id {id}"); - } - } - } -} \ No newline at end of file diff --git a/Achivments/IAchivmentCallbackReciever.cs b/Achivments/IAchivmentCallbackReciever.cs deleted file mode 100644 index e57defb..0000000 --- a/Achivments/IAchivmentCallbackReciever.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace NEG.Utils.Achivments -{ - public interface IAchivmentCallbackReciever - { - /// - /// Called when an achivment is completed - /// - /// - /// - void SetAchivment(AchivmentData achivment); - - /// - /// Called when achivment progress changes - /// - /// - /// Current achivment progress, equal to - - void SetAchivmentProgress(AchivmentData achivment, int progress); - } -} \ No newline at end of file -- 2.47.2 From af47348919bf8664e99fc49d15723da06847c4b4 Mon Sep 17 00:00:00 2001 From: LubieKakao1212 Date: Wed, 4 Jan 2023 13:07:03 +0100 Subject: [PATCH 04/12] Added AchievmentExceptions, fixed some names --- Achievments/AchievmentException.cs | 44 ++++++++++++++++++++++ Achievments/AchievmentException.cs.meta | 11 ++++++ Achievments/AchievmentManager.cs | 8 ++-- Achievments/IAchievmentCallbackReciever.cs | 8 ++-- 4 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 Achievments/AchievmentException.cs create mode 100644 Achievments/AchievmentException.cs.meta diff --git a/Achievments/AchievmentException.cs b/Achievments/AchievmentException.cs new file mode 100644 index 0000000..3ae6dea --- /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 AchievmentTypeExcetion : AchievmentException + { + /// + /// Expected achievment type under + /// + /// + /// + public Type Expected { get; private set; } + + /// + /// Actual achievment type under + /// + /// + /// + public Type Actual { get; private set; } + + public AchievmentTypeExcetion(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 index 64f26cd..56e361a 100644 --- a/Achievments/AchievmentManager.cs +++ b/Achievments/AchievmentManager.cs @@ -264,7 +264,7 @@ namespace NEG.Utils.Achievments /// throws an if either there is no achievment under id or achievment under id is of a different type public T GetAchievmentForId(string id) where T : AchievmentData { - return CheckAchievmentType(GetAchievmentForId(id)); + return ValidateAchievmentType(GetAchievmentForId(id)); } /// @@ -281,15 +281,15 @@ namespace NEG.Utils.Achievments } else { - throw new ApplicationException($"Invalid achivment id {id}"); + throw new AchievmentException($"Invalid achivment id {id}", id); } } - private T CheckAchievmentType(AchievmentData data) where T : AchievmentData + private T ValidateAchievmentType(AchievmentData data) where T : AchievmentData { if (data is not T convetred) { - throw new ApplicationException($"Attempting to perform an operation on an invalid achievment type. Expected {typeof(T)} got {data.GetType()}"); + throw new AchievmentTypeExcetion($"Attempting to perform an operation on an invalid achievment type. Expected {typeof(T)} got {data.GetType()}", data.Achivment.Id, typeof(T), data.GetType()); } return convetred; } diff --git a/Achievments/IAchievmentCallbackReciever.cs b/Achievments/IAchievmentCallbackReciever.cs index 6c6a87d..133a4e5 100644 --- a/Achievments/IAchievmentCallbackReciever.cs +++ b/Achievments/IAchievmentCallbackReciever.cs @@ -11,13 +11,13 @@ namespace NEG.Utils.Achievments /// /// Called when an achivment is completed /// - /// - void AchievmentCompleted(AchievmentData achivment); + /// + void AchievmentCompleted(AchievmentData achievment); /// /// Called when achivment progress changes /// - /// - void AchievmentStateChanged(AchievmentData achivment); + /// + void AchievmentStateChanged(AchievmentData achievment); } } \ No newline at end of file -- 2.47.2 From d731193948d8a0c3d2d0e7764b7b82522c0cd858 Mon Sep 17 00:00:00 2001 From: LubieKakao1212 Date: Mon, 2 Jan 2023 11:55:02 +0100 Subject: [PATCH 05/12] =?UTF-8?q?=EF=BB=BFsome=20basic=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Achievments/Tests.meta | 8 ++ Achievments/Tests/ConfigTests.cs | 90 +++++++++++++++++++ Achievments/Tests/ConfigTests.cs.meta | 11 +++ .../Tests/NEG.Utils.Achivments.Tests.asmdef | 27 ++++++ .../NEG.Utils.Achivments.Tests.asmdef.meta | 7 ++ Achievments/Tests/TestAssets.meta | 8 ++ .../TestAssets/AchivmentCollection.asset | 17 ++++ .../TestAssets/AchivmentCollection.asset.meta | 8 ++ Achievments/Tests/TestAssets/BaseConfig.asset | 15 ++++ .../Tests/TestAssets/BaseConfig.asset.meta | 8 ++ Achievments/Tests/TestAssets/NoProgress.asset | 17 ++++ .../Tests/TestAssets/NoProgress.asset.meta | 8 ++ .../Tests/TestAssets/WithProgress.asset | 17 ++++ .../Tests/TestAssets/WithProgress.asset.meta | 8 ++ 14 files changed, 249 insertions(+) create mode 100644 Achievments/Tests.meta create mode 100644 Achievments/Tests/ConfigTests.cs create mode 100644 Achievments/Tests/ConfigTests.cs.meta create mode 100644 Achievments/Tests/NEG.Utils.Achivments.Tests.asmdef create mode 100644 Achievments/Tests/NEG.Utils.Achivments.Tests.asmdef.meta create mode 100644 Achievments/Tests/TestAssets.meta create mode 100644 Achievments/Tests/TestAssets/AchivmentCollection.asset create mode 100644 Achievments/Tests/TestAssets/AchivmentCollection.asset.meta create mode 100644 Achievments/Tests/TestAssets/BaseConfig.asset create mode 100644 Achievments/Tests/TestAssets/BaseConfig.asset.meta create mode 100644 Achievments/Tests/TestAssets/NoProgress.asset create mode 100644 Achievments/Tests/TestAssets/NoProgress.asset.meta create mode 100644 Achievments/Tests/TestAssets/WithProgress.asset create mode 100644 Achievments/Tests/TestAssets/WithProgress.asset.meta 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..a688b16 --- /dev/null +++ b/Achievments/Tests/ConfigTests.cs @@ -0,0 +1,90 @@ +using System.Collections; +using System.Collections.Generic; +using NUnit.Framework; +using UnityEngine; +using UnityEngine.TestTools; +using NEG.Utils.Achivments; + +public class ConfigTests +{ + public const string AchivmentDefOnlyLabel = "TestAchivments"; + public const string AchivmentSetLabel = "TestAchivments"; + public const string AchivmentProgressLabel = "TestAchivments"; + + public const string NoProgressAchivment = "NO_PROGRESS"; + public const string WithProgressAchivment = "WITH_PROGRESS"; + + [Test] + public void AchivmentDefOnly() + { + AchivmentManager manager = AchivmentManager.Builder.FromLabeledConfig(AchivmentDefOnlyLabel).Build(); + + //Shoud not throw + manager.SetAchivment(NoProgressAchivment); + //Shoud not throw + manager.SetAchivment(WithProgressAchivment); + } + + [Test] + public void AchivmentSet() + { + var callbackTester = new TestCallbackRereiver(); + + AchivmentManager manager = AchivmentManager.Builder.FromLabeledConfig(AchivmentDefOnlyLabel) + .WithCallbackReciever(callbackTester) + .Build(); + + //Shoud not throw + manager.SetAchivment(NoProgressAchivment); + + //Shoud not throw + manager.SetAchivment(WithProgressAchivment); + } + + [Test] + public void AchivmentProgress() + { + AchivmentManager manager = AchivmentManager.Builder.FromLabeledConfig(AchivmentProgressLabel).Build(); + } + + private class TestCallbackRereiver : IAchivmentCallbackReciever + { + public int LastProgressUpdated { get; private set; } = -1; + public string LastIdUpdated { get; private set; } = null; + public string LastIdSet { get; private set; } = null; + + public void SetAchivment(AchivmentData achivment) + { + LastIdSet = achivment.Achivment.Id; + } + + public void SetAchivmentProgress(AchivmentData achivment, int progress) + { + LastIdUpdated = achivment.Achivment.Id; + LastProgressUpdated = progress; + } + + public void Reset() + { + LastIdSet = null; + LastIdUpdated = null; + LastProgressUpdated = -1; + } + + public void TestSetCallbackst(AchivmentManager manager, string id) + { + manager.SetAchivment(id); + Assert.AreEqual(id, LastIdSet); + Assert.AreEqual(null, LastIdUpdated); + Assert.AreEqual(-1, LastProgressUpdated); + } + + public void TestProgressCallback(AchivmentManager manager, string id, int progress, int expectedProgress, bool shouldSet) + { + manager.AddProgress(id, progress); + //Assert.AreEqual(, LastIdSet); + Assert.AreEqual(null, LastIdUpdated); + Assert.AreEqual(-1, LastProgressUpdated); + } + } +} 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..929e13a --- /dev/null +++ b/Achievments/Tests/NEG.Utils.Achivments.Tests.asmdef @@ -0,0 +1,27 @@ +{ + "name": "NEG.Utils.Achivments.Tests", + "rootNamespace": "", + "references": [ + "UnityEngine.TestRunner", + "UnityEditor.TestRunner", + "NEG.Utils.Achivments", + "Unity.Addressables", + "Unity.ResourceManager", + "" + ], + "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/AchivmentCollection.asset b/Achievments/Tests/TestAssets/AchivmentCollection.asset new file mode 100644 index 0000000..19ed1a9 --- /dev/null +++ b/Achievments/Tests/TestAssets/AchivmentCollection.asset @@ -0,0 +1,17 @@ +%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: ef37a873be859d042bda22dee624e429, type: 3} + m_Name: AchivmentCollection + m_EditorClassIdentifier: + k__BackingField: + - {fileID: 11400000, guid: 553d34779f9a31d4891686d6d34e8033, type: 2} + - {fileID: 11400000, guid: adbb4fd3d7472eb49933ac9958d499ff, type: 2} diff --git a/Achievments/Tests/TestAssets/AchivmentCollection.asset.meta b/Achievments/Tests/TestAssets/AchivmentCollection.asset.meta new file mode 100644 index 0000000..3747185 --- /dev/null +++ b/Achievments/Tests/TestAssets/AchivmentCollection.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4d95138fe57571c4299aa325a378e4ea +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/Tests/TestAssets/BaseConfig.asset b/Achievments/Tests/TestAssets/BaseConfig.asset new file mode 100644 index 0000000..467b029 --- /dev/null +++ b/Achievments/Tests/TestAssets/BaseConfig.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: 88120b6e616164f489387a6a32a25dee, type: 3} + m_Name: BaseConfig + m_EditorClassIdentifier: + k__BackingField: TestAchivments 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/NoProgress.asset b/Achievments/Tests/TestAssets/NoProgress.asset new file mode 100644 index 0000000..e186a84 --- /dev/null +++ b/Achievments/Tests/TestAssets/NoProgress.asset @@ -0,0 +1,17 @@ +%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: f9bd42dd58472044b8ecc0d69caa7da8, type: 3} + m_Name: NoProgress + m_EditorClassIdentifier: + k__BackingField: NO_PROGRESS + k__BackingField: 1 + additionalDataInitializer: diff --git a/Achievments/Tests/TestAssets/NoProgress.asset.meta b/Achievments/Tests/TestAssets/NoProgress.asset.meta new file mode 100644 index 0000000..f005e8f --- /dev/null +++ b/Achievments/Tests/TestAssets/NoProgress.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 553d34779f9a31d4891686d6d34e8033 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Achievments/Tests/TestAssets/WithProgress.asset b/Achievments/Tests/TestAssets/WithProgress.asset new file mode 100644 index 0000000..d343175 --- /dev/null +++ b/Achievments/Tests/TestAssets/WithProgress.asset @@ -0,0 +1,17 @@ +%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: f9bd42dd58472044b8ecc0d69caa7da8, type: 3} + m_Name: WithProgress + m_EditorClassIdentifier: + k__BackingField: WITH_PROGRESS + k__BackingField: 100 + additionalDataInitializer: diff --git a/Achievments/Tests/TestAssets/WithProgress.asset.meta b/Achievments/Tests/TestAssets/WithProgress.asset.meta new file mode 100644 index 0000000..cec1de2 --- /dev/null +++ b/Achievments/Tests/TestAssets/WithProgress.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: adbb4fd3d7472eb49933ac9958d499ff +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: -- 2.47.2 From bf79b07ea416c1178285777adbda8cde1f74ba45 Mon Sep 17 00:00:00 2001 From: LubieKakao1212 Date: Wed, 4 Jan 2023 16:20:17 +0100 Subject: [PATCH 06/12] Implemented Tests (All Green), Fixed some names and documentation --- Achievments/AchievmentException.cs | 4 +- Achievments/AchievmentManager.cs | 25 +- Achievments/Tests/ConfigTests.cs | 426 +++++++++++++++--- .../TestAssets/AchivmentCollection.asset | 5 +- Achievments/Tests/TestAssets/Float.asset | 18 + ...NoProgress.asset.meta => Float.asset.meta} | 2 +- .../{WithProgress.asset => Int.asset} | 9 +- ...WithProgress.asset.meta => Int.asset.meta} | 2 +- .../{NoProgress.asset => Toggle.asset} | 8 +- .../Tests/TestAssets/Toggle.asset.meta | 8 + 10 files changed, 412 insertions(+), 95 deletions(-) create mode 100644 Achievments/Tests/TestAssets/Float.asset rename Achievments/Tests/TestAssets/{NoProgress.asset.meta => Float.asset.meta} (79%) rename Achievments/Tests/TestAssets/{WithProgress.asset => Int.asset} (64%) rename Achievments/Tests/TestAssets/{WithProgress.asset.meta => Int.asset.meta} (79%) rename Achievments/Tests/TestAssets/{NoProgress.asset => Toggle.asset} (59%) create mode 100644 Achievments/Tests/TestAssets/Toggle.asset.meta diff --git a/Achievments/AchievmentException.cs b/Achievments/AchievmentException.cs index 3ae6dea..041c7b9 100644 --- a/Achievments/AchievmentException.cs +++ b/Achievments/AchievmentException.cs @@ -18,7 +18,7 @@ namespace NEG.Utils.Achievments } } - public class AchievmentTypeExcetion : AchievmentException + public class AchievmentTypeException : AchievmentException { /// /// Expected achievment type under @@ -34,7 +34,7 @@ namespace NEG.Utils.Achievments /// public Type Actual { get; private set; } - public AchievmentTypeExcetion(string message, string achievmentId, Type expectedType, Type actualType) : base(message, achievmentId) + public AchievmentTypeException(string message, string achievmentId, Type expectedType, Type actualType) : base(message, achievmentId) { Expected = expectedType; Actual = actualType; diff --git a/Achievments/AchievmentManager.cs b/Achievments/AchievmentManager.cs index 56e361a..7ae0dd2 100644 --- a/Achievments/AchievmentManager.cs +++ b/Achievments/AchievmentManager.cs @@ -164,6 +164,7 @@ namespace NEG.Utils.Achievments /// /// /// + /// throws an if there is no achievment under id public bool IsCompleted(string id) { return GetAchievmentForId(id).IsCompleted; @@ -172,9 +173,9 @@ namespace NEG.Utils.Achievments #region Toggle /// /// Sets a as completed, after which sends , also if the achievment is completed sends a .
- /// If there is no achievment at a given id throws an . If achievment at a given id is of a wrong tupe throws an ///
/// + /// throws an if there is no achievment under id or an if achievment under id is of a different type public void SetToggleAchivment(string id) { ManipulateAchievment(id, (achievment) => achievment.CompletionState = true); @@ -182,9 +183,9 @@ namespace NEG.Utils.Achievments /// /// Gets a completion state from a .
- /// If there is no achievment at a given id throws an . If achievment at a given id is of a wrong tupe throws an ///
/// + /// 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; @@ -194,9 +195,9 @@ namespace NEG.Utils.Achievments #region Int /// /// Sets progress of a given to , after which sends , also if the achievment is completed sends a .
- /// If there is no achievment at a given id throws an . If achievment at a given id is of a wrong tupe throws an . ///
/// + /// throws an if there is no achievment under id or an if achievment under id is of a different type public void SetIntProgress(string id, int progress) { ManipulateAchievment(id, (achievment) => achievment.CurrentProgress = progress); @@ -204,19 +205,19 @@ namespace NEG.Utils.Achievments /// /// Changes progress of a given by , after which sends , also if the achievment is completed sends a .
- /// If there is no achievment at a given id throws an . If achievment at a given id is of a wrong tupe throws an ///
/// - public void CangeIntProgress(string id, int delta) + /// throws an if there is no achievment under id or an if achievment under id is of a different type + public void ChangeIntProgress(string id, int delta) { ManipulateAchievment(id, (achievment) => achievment.CurrentProgress += delta); } /// /// Gets current progress from a .
- /// If there is no achievment at a given id throws an . If achievment at a given id is of a wrong tupe throws an ///
/// + /// 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; @@ -226,9 +227,9 @@ namespace NEG.Utils.Achievments #region Float /// /// Sets progress of a given to , after which sends , also if the achievment is completed sends a .
- /// If there is no achievment at a given id throws an . If achievment at a given id is of a wrong tupe throws an ///
/// + /// throws an if there is no achievment under id or an if achievment under id is of a different type public void SetFloatProgress(string id, float progress) { ManipulateAchievment(id, (achievment) => achievment.CurrentProgress = progress); @@ -236,19 +237,19 @@ namespace NEG.Utils.Achievments /// /// Changes progress of a given by , after which sends , also if the achievment is completed sends a .
- /// If there is no achievment at a given id throws an . If achievment at a given id is of a wrong tupe throws an ///
/// - public void CangeFloatProgress(string id, float delta) + /// throws an if there is no achievment under id or an if achievment under id is of a different type + public void ChangeFloatProgress(string id, float delta) { ManipulateAchievment(id, (achievment) => achievment.CurrentProgress += delta); } /// /// Gets current progress from a .
- /// If there is no achievment at a given id throws an . If achievment at a given id is of a wrong tupe throws an ///
/// + /// 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; @@ -261,7 +262,7 @@ namespace NEG.Utils.Achievments ///
/// Type of the achievment /// Id of requested achievment - /// throws an if either there is no achievment under id or achievment under id is of a different type + /// 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)); @@ -289,7 +290,7 @@ namespace NEG.Utils.Achievments { if (data is not T convetred) { - throw new AchievmentTypeExcetion($"Attempting to perform an operation on an invalid achievment type. Expected {typeof(T)} got {data.GetType()}", data.Achivment.Id, typeof(T), data.GetType()); + throw new AchievmentTypeException($"Attempting to perform an operation on an invalid achievment type. Expected {typeof(T)} got {data.GetType()}", data.Achivment.Id, typeof(T), data.GetType()); } return convetred; } diff --git a/Achievments/Tests/ConfigTests.cs b/Achievments/Tests/ConfigTests.cs index a688b16..832b657 100644 --- a/Achievments/Tests/ConfigTests.cs +++ b/Achievments/Tests/ConfigTests.cs @@ -1,90 +1,380 @@ +using System; using System.Collections; using System.Collections.Generic; using NUnit.Framework; using UnityEngine; using UnityEngine.TestTools; -using NEG.Utils.Achivments; -public class ConfigTests +namespace NEG.Utils.Achievments.Tests { - public const string AchivmentDefOnlyLabel = "TestAchivments"; - public const string AchivmentSetLabel = "TestAchivments"; - public const string AchivmentProgressLabel = "TestAchivments"; + using AchievmentTypes; + using static Internal.Extensions; - public const string NoProgressAchivment = "NO_PROGRESS"; - public const string WithProgressAchivment = "WITH_PROGRESS"; - - [Test] - public void AchivmentDefOnly() + public class ConfigTests { - AchivmentManager manager = AchivmentManager.Builder.FromLabeledConfig(AchivmentDefOnlyLabel).Build(); + public const string AchievmentsLabel = "TestAchivments"; - //Shoud not throw - manager.SetAchivment(NoProgressAchivment); - //Shoud not throw - manager.SetAchivment(WithProgressAchivment); + 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.Achivment.Id; + } + + public void AchievmentStateChanged(AchievmentData achievment) + { + LastDataUpdated = achievment; + } + } } - [Test] - public void AchivmentSet() + namespace Internal { - var callbackTester = new TestCallbackRereiver(); + 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); + } - AchivmentManager manager = AchivmentManager.Builder.FromLabeledConfig(AchivmentDefOnlyLabel) - .WithCallbackReciever(callbackTester) - .Build(); + public static void TestValidIdAndType(string id, Action manipulation, string testName) + { + Assert.DoesNotThrow(() => manipulation(id), $"{testName}: Invalid type or id"); + } - //Shoud not throw - manager.SetAchivment(NoProgressAchivment); + public static void TestInvalidId(this AchievmentManager manager, string id, string testName) + { + TestInvalidId(id, (id) => manager.GetAchievmentForId(id), testName); + } - //Shoud not throw - manager.SetAchivment(WithProgressAchivment); - } + public static void TestInvalidId(string id, Action manipulation, string testName) + { + var exception = Assert.Throws(() => manipulation(id), $"Expected to fail with {typeof(AchievmentTypeException)}"); - [Test] - public void AchivmentProgress() - { - AchivmentManager manager = AchivmentManager.Builder.FromLabeledConfig(AchivmentProgressLabel).Build(); - } + Assert.AreEqual(exception.Id, id, $"{testName}: Achievment id does not match"); + } - private class TestCallbackRereiver : IAchivmentCallbackReciever - { - public int LastProgressUpdated { get; private set; } = -1; - public string LastIdUpdated { get; private set; } = null; - public string LastIdSet { get; private set; } = null; + 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)}"); - public void SetAchivment(AchivmentData achivment) - { - LastIdSet = achivment.Achivment.Id; - } + 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"); + } - public void SetAchivmentProgress(AchivmentData achivment, int progress) - { - LastIdUpdated = achivment.Achivment.Id; - LastProgressUpdated = progress; - } - - public void Reset() - { - LastIdSet = null; - LastIdUpdated = null; - LastProgressUpdated = -1; - } - - public void TestSetCallbackst(AchivmentManager manager, string id) - { - manager.SetAchivment(id); - Assert.AreEqual(id, LastIdSet); - Assert.AreEqual(null, LastIdUpdated); - Assert.AreEqual(-1, LastProgressUpdated); - } - - public void TestProgressCallback(AchivmentManager manager, string id, int progress, int expectedProgress, bool shouldSet) - { - manager.AddProgress(id, progress); - //Assert.AreEqual(, LastIdSet); - Assert.AreEqual(null, LastIdUpdated); - Assert.AreEqual(-1, LastProgressUpdated); } } -} +} \ No newline at end of file diff --git a/Achievments/Tests/TestAssets/AchivmentCollection.asset b/Achievments/Tests/TestAssets/AchivmentCollection.asset index 19ed1a9..25bd3ce 100644 --- a/Achievments/Tests/TestAssets/AchivmentCollection.asset +++ b/Achievments/Tests/TestAssets/AchivmentCollection.asset @@ -13,5 +13,6 @@ MonoBehaviour: m_Name: AchivmentCollection m_EditorClassIdentifier: k__BackingField: - - {fileID: 11400000, guid: 553d34779f9a31d4891686d6d34e8033, type: 2} - - {fileID: 11400000, guid: adbb4fd3d7472eb49933ac9958d499ff, type: 2} + - {fileID: 11400000, guid: 7734df2e5d4033346aac56f0a2b2a836, type: 2} + - {fileID: 11400000, guid: c704b1ea2247ad540842a9caff628211, type: 2} + - {fileID: 11400000, guid: c71840de74e747e45afc82ecf8922dcd, type: 2} 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/NoProgress.asset.meta b/Achievments/Tests/TestAssets/Float.asset.meta similarity index 79% rename from Achievments/Tests/TestAssets/NoProgress.asset.meta rename to Achievments/Tests/TestAssets/Float.asset.meta index f005e8f..326ee38 100644 --- a/Achievments/Tests/TestAssets/NoProgress.asset.meta +++ b/Achievments/Tests/TestAssets/Float.asset.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 553d34779f9a31d4891686d6d34e8033 +guid: 7734df2e5d4033346aac56f0a2b2a836 NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 diff --git a/Achievments/Tests/TestAssets/WithProgress.asset b/Achievments/Tests/TestAssets/Int.asset similarity index 64% rename from Achievments/Tests/TestAssets/WithProgress.asset rename to Achievments/Tests/TestAssets/Int.asset index d343175..5e61751 100644 --- a/Achievments/Tests/TestAssets/WithProgress.asset +++ b/Achievments/Tests/TestAssets/Int.asset @@ -9,9 +9,10 @@ MonoBehaviour: m_GameObject: {fileID: 0} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f9bd42dd58472044b8ecc0d69caa7da8, type: 3} - m_Name: WithProgress + m_Script: {fileID: 11500000, guid: 5318fea685aa56646a3310c38a9a9bac, type: 3} + m_Name: Int m_EditorClassIdentifier: - k__BackingField: WITH_PROGRESS + k__BackingField: INT k__BackingField: 100 - additionalDataInitializer: + k__BackingField: 0 + k__BackingField: 0 diff --git a/Achievments/Tests/TestAssets/WithProgress.asset.meta b/Achievments/Tests/TestAssets/Int.asset.meta similarity index 79% rename from Achievments/Tests/TestAssets/WithProgress.asset.meta rename to Achievments/Tests/TestAssets/Int.asset.meta index cec1de2..b89ba06 100644 --- a/Achievments/Tests/TestAssets/WithProgress.asset.meta +++ b/Achievments/Tests/TestAssets/Int.asset.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: adbb4fd3d7472eb49933ac9958d499ff +guid: c704b1ea2247ad540842a9caff628211 NativeFormatImporter: externalObjects: {} mainObjectFileID: 11400000 diff --git a/Achievments/Tests/TestAssets/NoProgress.asset b/Achievments/Tests/TestAssets/Toggle.asset similarity index 59% rename from Achievments/Tests/TestAssets/NoProgress.asset rename to Achievments/Tests/TestAssets/Toggle.asset index e186a84..afd65bb 100644 --- a/Achievments/Tests/TestAssets/NoProgress.asset +++ b/Achievments/Tests/TestAssets/Toggle.asset @@ -9,9 +9,7 @@ MonoBehaviour: m_GameObject: {fileID: 0} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f9bd42dd58472044b8ecc0d69caa7da8, type: 3} - m_Name: NoProgress + m_Script: {fileID: 11500000, guid: 608c7e921b8b16b42919fc6f55b67fcb, type: 3} + m_Name: Toggle m_EditorClassIdentifier: - k__BackingField: NO_PROGRESS - k__BackingField: 1 - additionalDataInitializer: + 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: -- 2.47.2 From 36840271af4e68f35167aedc7ff84a813547f774 Mon Sep 17 00:00:00 2001 From: LubieKakao1212 Date: Thu, 19 Jan 2023 15:57:13 +0100 Subject: [PATCH 07/12] more typo fixes --- Achievments/AchievmentManager.cs | 30 ++++++++++--------- ...erConfig.cs => AchievmentManagerConfig.cs} | 2 +- ...s.meta => AchievmentManagerConfig.cs.meta} | 0 Achievments/AchievmentTypes/AchievmentData.cs | 4 +-- .../AchievmentTypes/FloatAchievmentData.cs | 2 +- .../AchievmentTypes/IntAchievmentData.cs | 2 +- Achievments/Achievments.cs | 22 ++++++++++++++ Achievments/Achievments.cs.meta | 11 +++++++ Achievments/TODO.txt | 5 ++++ Achievments/TODO.txt.meta | 7 +++++ Achievments/Tests/ConfigTests.cs | 2 +- 11 files changed, 67 insertions(+), 20 deletions(-) rename Achievments/{AchivmentManagerConfig.cs => AchievmentManagerConfig.cs} (88%) rename Achievments/{AchivmentManagerConfig.cs.meta => AchievmentManagerConfig.cs.meta} (100%) create mode 100644 Achievments/Achievments.cs create mode 100644 Achievments/Achievments.cs.meta create mode 100644 Achievments/TODO.txt create mode 100644 Achievments/TODO.txt.meta diff --git a/Achievments/AchievmentManager.cs b/Achievments/AchievmentManager.cs index 7ae0dd2..38b46f0 100644 --- a/Achievments/AchievmentManager.cs +++ b/Achievments/AchievmentManager.cs @@ -176,9 +176,9 @@ namespace NEG.Utils.Achievments /// /// /// throws an if there is no achievment under id or an if achievment under id is of a different type - public void SetToggleAchivment(string id) + public bool SetToggleAchivment(string id) { - ManipulateAchievment(id, (achievment) => achievment.CompletionState = true); + return ManipulateAchievment(id, (achievment) => achievment.CompletionState = true); } /// @@ -198,9 +198,9 @@ namespace NEG.Utils.Achievments /// /// /// throws an if there is no achievment under id or an if achievment under id is of a different type - public void SetIntProgress(string id, int progress) + public bool SetIntProgress(string id, int progress) { - ManipulateAchievment(id, (achievment) => achievment.CurrentProgress = progress); + return ManipulateAchievment(id, (achievment) => achievment.CurrentProgress = progress); } /// @@ -208,9 +208,9 @@ namespace NEG.Utils.Achievments /// /// /// throws an if there is no achievment under id or an if achievment under id is of a different type - public void ChangeIntProgress(string id, int delta) + public bool ChangeIntProgress(string id, int delta) { - ManipulateAchievment(id, (achievment) => achievment.CurrentProgress += delta); + return ManipulateAchievment(id, (achievment) => achievment.CurrentProgress += delta); } /// @@ -230,9 +230,9 @@ namespace NEG.Utils.Achievments /// /// /// throws an if there is no achievment under id or an if achievment under id is of a different type - public void SetFloatProgress(string id, float progress) + public bool SetFloatProgress(string id, float progress) { - ManipulateAchievment(id, (achievment) => achievment.CurrentProgress = progress); + return ManipulateAchievment(id, (achievment) => achievment.CurrentProgress = progress); } /// @@ -240,9 +240,9 @@ namespace NEG.Utils.Achievments /// /// /// throws an if there is no achievment under id or an if achievment under id is of a different type - public void ChangeFloatProgress(string id, float delta) + public bool ChangeFloatProgress(string id, float delta) { - ManipulateAchievment(id, (achievment) => achievment.CurrentProgress += delta); + return ManipulateAchievment(id, (achievment) => achievment.CurrentProgress += delta); } /// @@ -290,7 +290,7 @@ namespace NEG.Utils.Achievments { 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.Achivment.Id, typeof(T), data.GetType()); + 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; } @@ -301,18 +301,20 @@ namespace NEG.Utils.Achievments /// /// /// Action to perform on the achievment - private void ManipulateAchievment(string id, Action manipulation) where T : AchievmentData + private bool ManipulateAchievment(string id, Action manipulation) where T : AchievmentData { var data = GetAchievmentForId(id); if (CheckNotCompleted(data)) { - return; + return true; } manipulation(data); SendUpdateCallbacks(data); + + return data.IsCompleted; } /// @@ -324,7 +326,7 @@ namespace NEG.Utils.Achievments { if (data.IsCompleted) { - Debug.LogWarning($"Achievment already completed: {data.Achivment.Id}"); + Debug.LogWarning($"Achievment already completed: {data.Achievment.Id}"); } return data.IsCompleted; } diff --git a/Achievments/AchivmentManagerConfig.cs b/Achievments/AchievmentManagerConfig.cs similarity index 88% rename from Achievments/AchivmentManagerConfig.cs rename to Achievments/AchievmentManagerConfig.cs index 4815d84..b6584f4 100644 --- a/Achievments/AchivmentManagerConfig.cs +++ b/Achievments/AchievmentManagerConfig.cs @@ -5,7 +5,7 @@ using UnityEngine; namespace NEG.Utils.Achievments { [CreateAssetMenu(menuName = "Achivments/BaseConfig")] - public class AchivmentManagerConfig : ScriptableObject, IAchivmentManagerConfig + public class AchievmentManagerConfig : ScriptableObject, IAchivmentManagerConfig { public const string DefaultAchivmentsCollectionLabel = "Achivments"; diff --git a/Achievments/AchivmentManagerConfig.cs.meta b/Achievments/AchievmentManagerConfig.cs.meta similarity index 100% rename from Achievments/AchivmentManagerConfig.cs.meta rename to Achievments/AchievmentManagerConfig.cs.meta diff --git a/Achievments/AchievmentTypes/AchievmentData.cs b/Achievments/AchievmentTypes/AchievmentData.cs index 86a154d..9407979 100644 --- a/Achievments/AchievmentTypes/AchievmentData.cs +++ b/Achievments/AchievmentTypes/AchievmentData.cs @@ -9,13 +9,13 @@ namespace NEG.Utils.Achievments.AchievmentTypes { public abstract class AchievmentData { - public AchievmentDefinition Achivment { get; private set; } + public AchievmentDefinition Achievment { get; private set; } public abstract bool IsCompleted { get; } public AchievmentData(AchievmentDefinition achivment) { - Achivment = achivment; + Achievment = achivment; } } } \ No newline at end of file diff --git a/Achievments/AchievmentTypes/FloatAchievmentData.cs b/Achievments/AchievmentTypes/FloatAchievmentData.cs index 27a43ed..9b76dbe 100644 --- a/Achievments/AchievmentTypes/FloatAchievmentData.cs +++ b/Achievments/AchievmentTypes/FloatAchievmentData.cs @@ -23,7 +23,7 @@ namespace NEG.Utils.Achievments.AchievmentTypes public float ProgressLeft => Def.ProgressRequired - CurrentProgress; - private FloatAchievmentDefinition Def => (FloatAchievmentDefinition)Achivment; + private FloatAchievmentDefinition Def => (FloatAchievmentDefinition)Achievment; private float currentProgress; diff --git a/Achievments/AchievmentTypes/IntAchievmentData.cs b/Achievments/AchievmentTypes/IntAchievmentData.cs index 94e900a..e9e13f5 100644 --- a/Achievments/AchievmentTypes/IntAchievmentData.cs +++ b/Achievments/AchievmentTypes/IntAchievmentData.cs @@ -24,7 +24,7 @@ namespace NEG.Utils.Achievments.AchievmentTypes public int ProgressLeft => Def.ProgressRequired - CurrentProgress; - private IntAchievmentDefinition Def => (IntAchievmentDefinition)Achivment; + private IntAchievmentDefinition Def => (IntAchievmentDefinition)Achievment; private int currentProgress; diff --git a/Achievments/Achievments.cs b/Achievments/Achievments.cs new file mode 100644 index 0000000..fcaa854 --- /dev/null +++ b/Achievments/Achievments.cs @@ -0,0 +1,22 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace NEG.Utils.Achievments +{ + public static class Achievments + { + public static AchievmentManager Instance + { + get + { + if (instance == null) + { + instance = + } + } + } + private static AchievmentManager instance; + + } +} \ No newline at end of file diff --git a/Achievments/Achievments.cs.meta b/Achievments/Achievments.cs.meta new file mode 100644 index 0000000..d293cde --- /dev/null +++ b/Achievments/Achievments.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/TODO.txt b/Achievments/TODO.txt new file mode 100644 index 0000000..bf02039 --- /dev/null +++ b/Achievments/TODO.txt @@ -0,0 +1,5 @@ +Static Achievments class +Implement Storage again +Fix typos +Merge AchievmentCollection with AchievmentManagerConfig +Static backend constructors \ 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/ConfigTests.cs b/Achievments/Tests/ConfigTests.cs index 832b657..9a995f2 100644 --- a/Achievments/Tests/ConfigTests.cs +++ b/Achievments/Tests/ConfigTests.cs @@ -325,7 +325,7 @@ namespace NEG.Utils.Achievments.Tests public void AchievmentCompleted(AchievmentData achievment) { LastTypeSet = achievment.GetType(); - LastIdSet = achievment.Achivment.Id; + LastIdSet = achievment.Achievment.Id; } public void AchievmentStateChanged(AchievmentData achievment) -- 2.47.2 From d0b47345722dcf29248bfd463a36793fbaa49f7b Mon Sep 17 00:00:00 2001 From: LubieKakao1212 Date: Fri, 20 Jan 2023 20:27:39 +0100 Subject: [PATCH 08/12] Implemented static Achievments class, implemented propper backend api, merged AchievmentManagerConfig and AchievmentCollection --- Achievments/AchievmentManager.cs | 68 +++++---- Achievments/AchievmentManagerConfig.cs | 7 +- Achievments/Achievments.cs | 133 +++++++++++++++++- Achievments/AchivmentDefinitionCollection.cs | 3 +- Achievments/IAchievmentBackend.cs | 26 ++++ ...age.cs.meta => IAchievmentBackend.cs.meta} | 0 Achievments/IAchivmentStorage.cs | 11 -- Achievments/TODO.txt | 4 +- Achievments/Tests/ConfigTests.cs | 2 +- .../TestAssets/AchivmentCollection.asset | 18 --- .../TestAssets/AchivmentCollection.asset.meta | 8 -- Achievments/Tests/TestAssets/BaseConfig.asset | 5 +- 12 files changed, 209 insertions(+), 76 deletions(-) create mode 100644 Achievments/IAchievmentBackend.cs rename Achievments/{IAchivmentStorage.cs.meta => IAchievmentBackend.cs.meta} (100%) delete mode 100644 Achievments/IAchivmentStorage.cs delete mode 100644 Achievments/Tests/TestAssets/AchivmentCollection.asset delete mode 100644 Achievments/Tests/TestAssets/AchivmentCollection.asset.meta diff --git a/Achievments/AchievmentManager.cs b/Achievments/AchievmentManager.cs index 38b46f0..244e384 100644 --- a/Achievments/AchievmentManager.cs +++ b/Achievments/AchievmentManager.cs @@ -18,7 +18,7 @@ namespace NEG.Utils.Achievments public const string DefaultAchivmentsConfigLabel = "Achivments"; private AchievmentManager manager = new AchievmentManager(); - private IAchivmentStorage storage; + private IAchievmentBackend backend; public static Builder FromDefaultConfig() { @@ -47,20 +47,8 @@ namespace NEG.Utils.Achievments return builder; } - - public Builder WithLabeledDefinitions(string label) - { - var handle = Addressables.LoadAssetsAsync((IEnumerable)new string[] { label }, delegate { }, Addressables.MergeMode.Union, false); - - var achivmentCollections = handle.WaitForCompletion(); - - foreach (var achivmentCollection in achivmentCollections) - WithDefinitionsFrom(achivmentCollection); - - return this; - } - public Builder WithDefinitionsFrom(AchivmentDefinitionCollection collection) + public Builder WithDefinitionsFrom(AchievmentManagerConfig collection) { foreach (var def in collection.Achivments) { @@ -70,14 +58,26 @@ namespace NEG.Utils.Achievments return this; } - public Builder LoadedFrom(IAchivmentStorage storageIn) + public Builder WithLabeledBackend(string label) { - if (storage != null) + 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("Cannot Load achivment data from multiple storage instances"); + throw new ApplicationException("There can only be one Achievment Backend at a time"); } - this.storage = storageIn; + this.backend = backendIn; return this; } @@ -90,11 +90,13 @@ namespace NEG.Utils.Achievments public AchievmentManager Build() { - //TODO - /*if (storage != null) + if (backend != null) { - manager.LoadFrom(storage); - }*/ + manager.InitBackend(backend); + }else + { + Debug.LogWarning("No AchievmentBackend selected. Is this intended?"); + } return manager; } } @@ -127,15 +129,27 @@ namespace NEG.Utils.Achievments } } - /*private void LoadFrom(IAchivmentStorage achivmentStorage) + /// + /// Initializes a backend syncing achievments data with it and redistering it as a callback reciever + /// + /// Resets all achievments data + private void InitBackend(IAchievmentBackend achievmentBackend) { - foreach (var entry in definitionCache) + foreach (var definition in definitionCache.Values) { - var storedProgress = achivmentStorage.GetStoredAchivmentProgress(entry.Key); + var storedProgress = achievmentBackend.GetStoredAchivment(definition); - dataCache[entry.Value].ProgressLeft = storedProgress; + if (storedProgress != null) + { + dataCache[definition] = storedProgress; + } + else + { + dataCache[definition] = definition.Construct(); + } } - }*/ + AddCallbackReciever(achievmentBackend); + } public void AddCallbackRecievers(IEnumerable initialCallbacks) { diff --git a/Achievments/AchievmentManagerConfig.cs b/Achievments/AchievmentManagerConfig.cs index b6584f4..95dc214 100644 --- a/Achievments/AchievmentManagerConfig.cs +++ b/Achievments/AchievmentManagerConfig.cs @@ -1,3 +1,4 @@ +using NEG.Utils.Achievments.AchievmentTypes; using System.Collections; using System.Collections.Generic; using UnityEngine; @@ -7,14 +8,12 @@ namespace NEG.Utils.Achievments [CreateAssetMenu(menuName = "Achivments/BaseConfig")] public class AchievmentManagerConfig : ScriptableObject, IAchivmentManagerConfig { - public const string DefaultAchivmentsCollectionLabel = "Achivments"; - [field: SerializeField] - public string AchivmentCollectionAssetLabel { get; private set; } = DefaultAchivmentsCollectionLabel; + public List Achivments { get; private set; } = new List(); public void Apply(AchievmentManager.Builder builder) { - builder.WithLabeledDefinitions(AchivmentCollectionAssetLabel); + builder.WithDefinitionsFrom(this); } public void ApplyLast(AchievmentManager.Builder builder) diff --git a/Achievments/Achievments.cs b/Achievments/Achievments.cs index fcaa854..866c6b0 100644 --- a/Achievments/Achievments.cs +++ b/Achievments/Achievments.cs @@ -1,3 +1,5 @@ +using NEG.Utils.Achievments.AchievmentTypes; +using System; using System.Collections; using System.Collections.Generic; using UnityEngine; @@ -6,17 +8,144 @@ namespace NEG.Utils.Achievments { public static class Achievments { - public static AchievmentManager Instance + public static AchievmentManager Instance { get { if (instance == null) { - instance = + instance = AchievmentManager.Builder.FromDefaultConfig() + .WithLabeledBackend(BackendLabel) + .Build(); } + return instance; } } + + internal static string BackendLabel + { + get => backendLabel; + set + { + if (backendLabel != null) + { + throw new ApplicationException("Multiple AchievmentBackends enabled, this is not allowed"); + } + backendLabel = value; + } + } + private static string backendLabel; + 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 + } } \ No newline at end of file diff --git a/Achievments/AchivmentDefinitionCollection.cs b/Achievments/AchivmentDefinitionCollection.cs index fb804d6..ec914c7 100644 --- a/Achievments/AchivmentDefinitionCollection.cs +++ b/Achievments/AchivmentDefinitionCollection.cs @@ -9,7 +9,6 @@ namespace NEG.Utils.Achievments [CreateAssetMenu(menuName = "Achivments/Collection")] public class AchivmentDefinitionCollection : ScriptableObject { - [field: SerializeField] - public List Achivments { get; private set; } = new List(); + } } \ No newline at end of file diff --git a/Achievments/IAchievmentBackend.cs b/Achievments/IAchievmentBackend.cs new file mode 100644 index 0000000..b97d863 --- /dev/null +++ b/Achievments/IAchievmentBackend.cs @@ -0,0 +1,26 @@ +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 + public AchievmentData GetStoredAchivment(AchievmentDefinition definition); + } +} \ No newline at end of file diff --git a/Achievments/IAchivmentStorage.cs.meta b/Achievments/IAchievmentBackend.cs.meta similarity index 100% rename from Achievments/IAchivmentStorage.cs.meta rename to Achievments/IAchievmentBackend.cs.meta diff --git a/Achievments/IAchivmentStorage.cs b/Achievments/IAchivmentStorage.cs deleted file mode 100644 index 00f0799..0000000 --- a/Achievments/IAchivmentStorage.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace NEG.Utils.Achievments -{ - public interface IAchivmentStorage - { - public int GetStoredAchivmentProgress(string id); - } -} \ No newline at end of file diff --git a/Achievments/TODO.txt b/Achievments/TODO.txt index bf02039..bce4482 100644 --- a/Achievments/TODO.txt +++ b/Achievments/TODO.txt @@ -1,5 +1,5 @@ Static Achievments class -Implement Storage again +Implement Storage again API (done) Fix typos -Merge AchievmentCollection with AchievmentManagerConfig +Merge AchievmentCollection with AchievmentManagerConfig (done) Static backend constructors \ No newline at end of file diff --git a/Achievments/Tests/ConfigTests.cs b/Achievments/Tests/ConfigTests.cs index 9a995f2..50bca12 100644 --- a/Achievments/Tests/ConfigTests.cs +++ b/Achievments/Tests/ConfigTests.cs @@ -12,7 +12,7 @@ namespace NEG.Utils.Achievments.Tests public class ConfigTests { - public const string AchievmentsLabel = "TestAchivments"; + public const string AchievmentsLabel = "TestAchievments"; public const string AchievmentIdToggle = "TOGGLE"; public const string AchievmentIdInt = "INT"; diff --git a/Achievments/Tests/TestAssets/AchivmentCollection.asset b/Achievments/Tests/TestAssets/AchivmentCollection.asset deleted file mode 100644 index 25bd3ce..0000000 --- a/Achievments/Tests/TestAssets/AchivmentCollection.asset +++ /dev/null @@ -1,18 +0,0 @@ -%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: ef37a873be859d042bda22dee624e429, type: 3} - m_Name: AchivmentCollection - 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/AchivmentCollection.asset.meta b/Achievments/Tests/TestAssets/AchivmentCollection.asset.meta deleted file mode 100644 index 3747185..0000000 --- a/Achievments/Tests/TestAssets/AchivmentCollection.asset.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 4d95138fe57571c4299aa325a378e4ea -NativeFormatImporter: - externalObjects: {} - mainObjectFileID: 11400000 - userData: - assetBundleName: - assetBundleVariant: diff --git a/Achievments/Tests/TestAssets/BaseConfig.asset b/Achievments/Tests/TestAssets/BaseConfig.asset index 467b029..1511dcb 100644 --- a/Achievments/Tests/TestAssets/BaseConfig.asset +++ b/Achievments/Tests/TestAssets/BaseConfig.asset @@ -12,4 +12,7 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 88120b6e616164f489387a6a32a25dee, type: 3} m_Name: BaseConfig m_EditorClassIdentifier: - k__BackingField: TestAchivments + k__BackingField: + - {fileID: 11400000, guid: 7734df2e5d4033346aac56f0a2b2a836, type: 2} + - {fileID: 11400000, guid: c704b1ea2247ad540842a9caff628211, type: 2} + - {fileID: 11400000, guid: c71840de74e747e45afc82ecf8922dcd, type: 2} -- 2.47.2 From 0270c50090b70f4b1455ae7171af60082f28523c Mon Sep 17 00:00:00 2001 From: LubieKakao1212 Date: Tue, 14 Feb 2023 12:49:35 +0100 Subject: [PATCH 09/12] Implemented local backend (untested) --- Achievments/Backend.meta | 8 ++ Achievments/Backend/LoacalBaackend.meta | 8 ++ .../LoacalBaackend/LoaclBackendConfig.cs | 129 ++++++++++++++++++ .../LoacalBaackend/LoaclBackendConfig.cs.meta | 11 ++ 4 files changed, 156 insertions(+) create mode 100644 Achievments/Backend.meta create mode 100644 Achievments/Backend/LoacalBaackend.meta create mode 100644 Achievments/Backend/LoacalBaackend/LoaclBackendConfig.cs create mode 100644 Achievments/Backend/LoacalBaackend/LoaclBackendConfig.cs.meta 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/LoaclBackendConfig.cs b/Achievments/Backend/LoacalBaackend/LoaclBackendConfig.cs new file mode 100644 index 0000000..27b9b2a --- /dev/null +++ b/Achievments/Backend/LoacalBaackend/LoaclBackendConfig.cs @@ -0,0 +1,129 @@ +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 +{ + public class LoaclBackendConfig : ScriptableObject, IAchievmentBackendConfig + { + [SerializeField] + private string saveLocation; + + public IAchievmentBackend ConstructBackend() + { + + } + } + + 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; + + token.Replace(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; + } + + + token.Replace(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; + } + + 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/LoaclBackendConfig.cs.meta b/Achievments/Backend/LoacalBaackend/LoaclBackendConfig.cs.meta new file mode 100644 index 0000000..39bcb87 --- /dev/null +++ b/Achievments/Backend/LoacalBaackend/LoaclBackendConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6a1257a87feec064697193df412554d4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: -- 2.47.2 From 1e6204e57ec91f030de385a1750d5f32fb0ed40a Mon Sep 17 00:00:00 2001 From: LubieKakao1212 Date: Tue, 14 Feb 2023 13:45:19 +0100 Subject: [PATCH 10/12] Local Backend Auto registration, files and typo cleanup --- Achievments/{Achievments.cs => Achievment.cs} | 11 +++++++++-- .../{Achievments.cs.meta => Achievment.cs.meta} | 0 Achievments/AchievmentManagerConfig.cs | 2 +- Achievments/AchivmentDefinitionCollection.cs | 14 -------------- Achievments/AchivmentDefinitionCollection.cs.meta | 11 ----------- .../Backend/LoacalBaackend/LoaclBackendConfig.cs | 11 ++++++++++- 6 files changed, 20 insertions(+), 29 deletions(-) rename Achievments/{Achievments.cs => Achievment.cs} (94%) rename Achievments/{Achievments.cs.meta => Achievment.cs.meta} (100%) delete mode 100644 Achievments/AchivmentDefinitionCollection.cs delete mode 100644 Achievments/AchivmentDefinitionCollection.cs.meta diff --git a/Achievments/Achievments.cs b/Achievments/Achievment.cs similarity index 94% rename from Achievments/Achievments.cs rename to Achievments/Achievment.cs index 866c6b0..ef4803f 100644 --- a/Achievments/Achievments.cs +++ b/Achievments/Achievment.cs @@ -6,7 +6,10 @@ using UnityEngine; namespace NEG.Utils.Achievments { - public static class Achievments + /// + /// Static utility for achievment managment + /// + public static class Achievment { public static AchievmentManager Instance { @@ -22,11 +25,15 @@ namespace NEG.Utils.Achievments } } - internal static string BackendLabel + public static string BackendLabel { get => backendLabel; set { + if(instance != null) + { + throw new ApplicationException("Achievments - Cannot set backend label, Managed already created"); + } if (backendLabel != null) { throw new ApplicationException("Multiple AchievmentBackends enabled, this is not allowed"); diff --git a/Achievments/Achievments.cs.meta b/Achievments/Achievment.cs.meta similarity index 100% rename from Achievments/Achievments.cs.meta rename to Achievments/Achievment.cs.meta diff --git a/Achievments/AchievmentManagerConfig.cs b/Achievments/AchievmentManagerConfig.cs index 95dc214..371a722 100644 --- a/Achievments/AchievmentManagerConfig.cs +++ b/Achievments/AchievmentManagerConfig.cs @@ -5,7 +5,7 @@ using UnityEngine; namespace NEG.Utils.Achievments { - [CreateAssetMenu(menuName = "Achivments/BaseConfig")] + [CreateAssetMenu(menuName = "Achievments/Config/BaseConfig")] public class AchievmentManagerConfig : ScriptableObject, IAchivmentManagerConfig { [field: SerializeField] diff --git a/Achievments/AchivmentDefinitionCollection.cs b/Achievments/AchivmentDefinitionCollection.cs deleted file mode 100644 index ec914c7..0000000 --- a/Achievments/AchivmentDefinitionCollection.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Collections; -using System.Collections.Generic; -using UnityEngine; - -namespace NEG.Utils.Achievments -{ - using AchievmentTypes; - - [CreateAssetMenu(menuName = "Achivments/Collection")] - public class AchivmentDefinitionCollection : ScriptableObject - { - - } -} \ No newline at end of file diff --git a/Achievments/AchivmentDefinitionCollection.cs.meta b/Achievments/AchivmentDefinitionCollection.cs.meta deleted file mode 100644 index 59d4a05..0000000 --- a/Achievments/AchivmentDefinitionCollection.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ef37a873be859d042bda22dee624e429 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Achievments/Backend/LoacalBaackend/LoaclBackendConfig.cs b/Achievments/Backend/LoacalBaackend/LoaclBackendConfig.cs index 27b9b2a..3431616 100644 --- a/Achievments/Backend/LoacalBaackend/LoaclBackendConfig.cs +++ b/Achievments/Backend/LoacalBaackend/LoaclBackendConfig.cs @@ -8,14 +8,23 @@ using UnityEngine; namespace NEG.Utils.Achievments { + [CreateAssetMenu(menuName = "Achievments/Config/Backend/Local")] public class LoaclBackendConfig : ScriptableObject, IAchievmentBackendConfig { + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] + private static void Init() + { +#if LOCAL_ACHIEVMENT_BACKEND + Achievments.BackendLabel = "LocalAchievments"; +#endif + } + [SerializeField] private string saveLocation; public IAchievmentBackend ConstructBackend() { - + return new LocalBackend(saveLocation); } } -- 2.47.2 From e71f0ec8da4ad8d229bf3caf57a9ec0af6644522 Mon Sep 17 00:00:00 2001 From: LubieKakao1212 Date: Fri, 17 Feb 2023 13:09:17 +0100 Subject: [PATCH 11/12] Local backend tests + Some related fixes --- Achievments/Achievment.cs | 56 +++++++++++++---- ...BackendConfig.cs => LocalBackendConfig.cs} | 7 +-- ...fig.cs.meta => LocalBackendConfig.cs.meta} | 0 Achievments/PlaymodeTests.meta | 8 +++ Achievments/PlaymodeTests/BackendTests.cs | 62 +++++++++++++++++++ .../PlaymodeTests/BackendTests.cs.meta | 11 ++++ ...EG.Utils.Achievments.Tests.Playmode.asmdef | 22 +++++++ ...ils.Achievments.Tests.Playmode.asmdef.meta | 7 +++ Achievments/PlaymodeTests/TestAssets.meta | 8 +++ .../TestAssets/TestLocalBackend.asset | 15 +++++ .../TestAssets/TestLocalBackend.asset.meta | 8 +++ Achievments/TODO.txt | 6 +- 12 files changed, 191 insertions(+), 19 deletions(-) rename Achievments/Backend/LoacalBaackend/{LoaclBackendConfig.cs => LocalBackendConfig.cs} (96%) rename Achievments/Backend/LoacalBaackend/{LoaclBackendConfig.cs.meta => LocalBackendConfig.cs.meta} (100%) create mode 100644 Achievments/PlaymodeTests.meta create mode 100644 Achievments/PlaymodeTests/BackendTests.cs create mode 100644 Achievments/PlaymodeTests/BackendTests.cs.meta create mode 100644 Achievments/PlaymodeTests/NEG.Utils.Achievments.Tests.Playmode.asmdef create mode 100644 Achievments/PlaymodeTests/NEG.Utils.Achievments.Tests.Playmode.asmdef.meta create mode 100644 Achievments/PlaymodeTests/TestAssets.meta create mode 100644 Achievments/PlaymodeTests/TestAssets/TestLocalBackend.asset create mode 100644 Achievments/PlaymodeTests/TestAssets/TestLocalBackend.asset.meta diff --git a/Achievments/Achievment.cs b/Achievments/Achievment.cs index ef4803f..448fd58 100644 --- a/Achievments/Achievment.cs +++ b/Achievments/Achievment.cs @@ -17,7 +17,7 @@ namespace NEG.Utils.Achievments { if (instance == null) { - instance = AchievmentManager.Builder.FromDefaultConfig() + instance = AchievmentManager.Builder.FromLabeledConfig(ConfigLabel) .WithLabeledBackend(BackendLabel) .Build(); } @@ -32,17 +32,37 @@ namespace NEG.Utils.Achievments { if(instance != null) { - throw new ApplicationException("Achievments - Cannot set backend label, Managed already created"); + //Log + Quit helps debug builds + Debug.LogError("Achievments - Cannot set backend label, Managed already created"); + Application.Quit(1); } if (backendLabel != null) { - throw new ApplicationException("Multiple AchievmentBackends enabled, this is not allowed"); + //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) @@ -56,7 +76,7 @@ namespace NEG.Utils.Achievments /// throws an if there is no achievment under id public static bool IsCompleted(string id) { - return instance.IsCompleted(id); + return Instance.IsCompleted(id); } #region Toggle @@ -68,7 +88,7 @@ namespace NEG.Utils.Achievments /// 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); + return Instance.SetToggleAchivment(id); } /// @@ -79,7 +99,7 @@ namespace NEG.Utils.Achievments /// 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); + return Instance.GetToggleState(id); } #endregion @@ -92,7 +112,7 @@ namespace NEG.Utils.Achievments /// 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); + return Instance.SetIntProgress(id, progress); } /// @@ -103,7 +123,7 @@ namespace NEG.Utils.Achievments /// 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); + return Instance.ChangeIntProgress(id, delta); } /// @@ -114,7 +134,7 @@ namespace NEG.Utils.Achievments /// 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); + return Instance.GetIntProgress(id); } #endregion @@ -127,7 +147,7 @@ namespace NEG.Utils.Achievments /// 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); + return Instance.SetFloatProgress(id, progress); } /// @@ -138,7 +158,7 @@ namespace NEG.Utils.Achievments /// 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); + return Instance.ChangeFloatProgress(id, delta); } /// @@ -149,10 +169,22 @@ namespace NEG.Utils.Achievments /// 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); + 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/Backend/LoacalBaackend/LoaclBackendConfig.cs b/Achievments/Backend/LoacalBaackend/LocalBackendConfig.cs similarity index 96% rename from Achievments/Backend/LoacalBaackend/LoaclBackendConfig.cs rename to Achievments/Backend/LoacalBaackend/LocalBackendConfig.cs index 3431616..71b6e22 100644 --- a/Achievments/Backend/LoacalBaackend/LoaclBackendConfig.cs +++ b/Achievments/Backend/LoacalBaackend/LocalBackendConfig.cs @@ -9,7 +9,7 @@ using UnityEngine; namespace NEG.Utils.Achievments { [CreateAssetMenu(menuName = "Achievments/Config/Backend/Local")] - public class LoaclBackendConfig : ScriptableObject, IAchievmentBackendConfig + public class LocalBackendConfig : ScriptableObject, IAchievmentBackendConfig { [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)] private static void Init() @@ -51,7 +51,7 @@ namespace NEG.Utils.Achievments achievmentObj["completed"] = true; - token.Replace(achievmentObj); + jobj[id] = achievmentObj; SaveJson(jobj); } @@ -81,8 +81,7 @@ namespace NEG.Utils.Achievments break; } - - token.Replace(achievmentObj); + jobj[id] = achievmentObj; SaveJson(jobj); } diff --git a/Achievments/Backend/LoacalBaackend/LoaclBackendConfig.cs.meta b/Achievments/Backend/LoacalBaackend/LocalBackendConfig.cs.meta similarity index 100% rename from Achievments/Backend/LoacalBaackend/LoaclBackendConfig.cs.meta rename to Achievments/Backend/LoacalBaackend/LocalBackendConfig.cs.meta 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..f5e9f8e --- /dev/null +++ b/Achievments/PlaymodeTests/BackendTests.cs @@ -0,0 +1,62 @@ +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() + { + //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); + + } + } +} \ 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..f8c24bd --- /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.Achivments" + ], + "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 index bce4482..ca82cc6 100644 --- a/Achievments/TODO.txt +++ b/Achievments/TODO.txt @@ -1,5 +1,5 @@ -Static Achievments class +Static Achievments class (done) Implement Storage again API (done) -Fix typos +Fix typos Merge AchievmentCollection with AchievmentManagerConfig (done) -Static backend constructors \ No newline at end of file +Static backend constructors (done) \ No newline at end of file -- 2.47.2 From 1c5f93d8b1c22f9772e8679c69e291bcd5fc568c Mon Sep 17 00:00:00 2001 From: LubieKakao1212 Date: Fri, 17 Feb 2023 14:56:31 +0100 Subject: [PATCH 12/12] Steam Backend + Some fixes --- Achievments/AchievmentManager.cs | 10 +- .../AchievmentTypes/FloatAchievmentData.cs | 7 +- .../AchievmentTypes/IntAchievmentData.cs | 7 +- .../AchievmentTypes/ToggleAchievmentData.cs | 7 +- Achievments/AchievmentsUpdater.cs | 15 +++ Achievments/AchievmentsUpdater.cs.meta | 11 ++ .../LoacalBaackend/LocalBackendConfig.cs | 10 +- Achievments/Backend/SteamBackend.meta | 8 ++ ...ils.Achivmnets.Backend.SteamBackend.asmdef | 19 +++ ...chivmnets.Backend.SteamBackend.asmdef.meta | 7 ++ .../SteamBackend/SteamBackendConfig.cs | 115 ++++++++++++++++++ .../SteamBackend/SteamBackendConfig.cs.meta | 11 ++ Achievments/IAchievmentBackend.cs | 7 +- ...ts.asmdef => NEG.Utils.Achievments.asmdef} | 2 +- ...meta => NEG.Utils.Achievments.asmdef.meta} | 0 Achievments/PlaymodeTests/BackendTests.cs | 5 +- ...EG.Utils.Achievments.Tests.Playmode.asmdef | 2 +- .../Tests/NEG.Utils.Achivments.Tests.asmdef | 3 +- 18 files changed, 235 insertions(+), 11 deletions(-) create mode 100644 Achievments/AchievmentsUpdater.cs create mode 100644 Achievments/AchievmentsUpdater.cs.meta create mode 100644 Achievments/Backend/SteamBackend.meta create mode 100644 Achievments/Backend/SteamBackend/NEG.Utils.Achivmnets.Backend.SteamBackend.asmdef create mode 100644 Achievments/Backend/SteamBackend/NEG.Utils.Achivmnets.Backend.SteamBackend.asmdef.meta create mode 100644 Achievments/Backend/SteamBackend/SteamBackendConfig.cs create mode 100644 Achievments/Backend/SteamBackend/SteamBackendConfig.cs.meta rename Achievments/{NEG.Utils.Achivments.asmdef => NEG.Utils.Achievments.asmdef} (91%) rename Achievments/{NEG.Utils.Achivments.asmdef.meta => NEG.Utils.Achievments.asmdef.meta} (100%) diff --git a/Achievments/AchievmentManager.cs b/Achievments/AchievmentManager.cs index 244e384..6aaa90f 100644 --- a/Achievments/AchievmentManager.cs +++ b/Achievments/AchievmentManager.cs @@ -109,7 +109,9 @@ namespace NEG.Utils.Achievments private Dictionary definitionCache; private Dictionary dataCache; - + + private IAchievmentBackend activeBackend; + private AchievmentManager() { definitionCache = new Dictionary(); @@ -135,6 +137,7 @@ namespace NEG.Utils.Achievments /// Resets all achievments data private void InitBackend(IAchievmentBackend achievmentBackend) { + activeBackend = achievmentBackend; foreach (var definition in definitionCache.Values) { var storedProgress = achievmentBackend.GetStoredAchivment(definition); @@ -300,6 +303,11 @@ namespace NEG.Utils.Achievments } } + internal void UpdateBackend() + { + activeBackend?.Update(); + } + private T ValidateAchievmentType(AchievmentData data) where T : AchievmentData { if (data is not T convetred) diff --git a/Achievments/AchievmentTypes/FloatAchievmentData.cs b/Achievments/AchievmentTypes/FloatAchievmentData.cs index 9b76dbe..b9ef389 100644 --- a/Achievments/AchievmentTypes/FloatAchievmentData.cs +++ b/Achievments/AchievmentTypes/FloatAchievmentData.cs @@ -8,10 +8,15 @@ namespace NEG.Utils.Achievments.AchievmentTypes { 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; - internal set + set { if (Def.Clamped) { diff --git a/Achievments/AchievmentTypes/IntAchievmentData.cs b/Achievments/AchievmentTypes/IntAchievmentData.cs index e9e13f5..3460aea 100644 --- a/Achievments/AchievmentTypes/IntAchievmentData.cs +++ b/Achievments/AchievmentTypes/IntAchievmentData.cs @@ -9,10 +9,15 @@ namespace NEG.Utils.Achievments.AchievmentTypes { 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; - internal set + set { if (Def.Clamped) { diff --git a/Achievments/AchievmentTypes/ToggleAchievmentData.cs b/Achievments/AchievmentTypes/ToggleAchievmentData.cs index c0b9dfa..0075d49 100644 --- a/Achievments/AchievmentTypes/ToggleAchievmentData.cs +++ b/Achievments/AchievmentTypes/ToggleAchievmentData.cs @@ -8,7 +8,12 @@ namespace NEG.Utils.Achievments.AchievmentTypes { public override bool IsCompleted => CompletionState; - public bool CompletionState { get; internal set; } = false; + /// + /// 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/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/LoacalBaackend/LocalBackendConfig.cs b/Achievments/Backend/LoacalBaackend/LocalBackendConfig.cs index 71b6e22..7afdda4 100644 --- a/Achievments/Backend/LoacalBaackend/LocalBackendConfig.cs +++ b/Achievments/Backend/LoacalBaackend/LocalBackendConfig.cs @@ -15,7 +15,7 @@ namespace NEG.Utils.Achievments private static void Init() { #if LOCAL_ACHIEVMENT_BACKEND - Achievments.BackendLabel = "LocalAchievments"; + Achievment.BackendLabel = "LocalAchievments"; #endif } @@ -28,6 +28,9 @@ namespace NEG.Utils.Achievments } } + /// + /// This backend is not optimised at all, do not use in public builds + /// public class LocalBackend : IAchievmentBackend { private string saveLocation; @@ -115,6 +118,11 @@ namespace NEG.Utils.Achievments return achievment; } + public void Update() + { + //Nothing here + } + private JObject LoadJson() { if (Directory.Exists(Path.GetDirectoryName(saveLocation)) && File.Exists(saveLocation)) 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 index b97d863..f868b6c 100644 --- a/Achievments/IAchievmentBackend.cs +++ b/Achievments/IAchievmentBackend.cs @@ -21,6 +21,11 @@ namespace NEG.Utils.Achievments /// Constructs an AchievmentData for given ///
/// May return null if there is no stored data for this achievment - public AchievmentData GetStoredAchivment(AchievmentDefinition definition); + AchievmentData GetStoredAchivment(AchievmentDefinition definition); + + /// + /// Used for e.g. syncing with upstream + /// + void Update(); } } \ No newline at end of file diff --git a/Achievments/NEG.Utils.Achivments.asmdef b/Achievments/NEG.Utils.Achievments.asmdef similarity index 91% rename from Achievments/NEG.Utils.Achivments.asmdef rename to Achievments/NEG.Utils.Achievments.asmdef index 85119ec..5d6fce1 100644 --- a/Achievments/NEG.Utils.Achivments.asmdef +++ b/Achievments/NEG.Utils.Achievments.asmdef @@ -1,5 +1,5 @@ { - "name": "NEG.Utils.Achivments", + "name": "NEG.Utils.Achievments", "rootNamespace": "", "references": [ "GUID:9e24947de15b9834991c9d8411ea37cf", diff --git a/Achievments/NEG.Utils.Achivments.asmdef.meta b/Achievments/NEG.Utils.Achievments.asmdef.meta similarity index 100% rename from Achievments/NEG.Utils.Achivments.asmdef.meta rename to Achievments/NEG.Utils.Achievments.asmdef.meta diff --git a/Achievments/PlaymodeTests/BackendTests.cs b/Achievments/PlaymodeTests/BackendTests.cs index f5e9f8e..e3f6bd8 100644 --- a/Achievments/PlaymodeTests/BackendTests.cs +++ b/Achievments/PlaymodeTests/BackendTests.cs @@ -37,6 +37,7 @@ namespace NEG.Utils.Achievments.Tests [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); @@ -56,7 +57,9 @@ namespace NEG.Utils.Achievments.Tests 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/NEG.Utils.Achievments.Tests.Playmode.asmdef b/Achievments/PlaymodeTests/NEG.Utils.Achievments.Tests.Playmode.asmdef index f8c24bd..e1754a3 100644 --- a/Achievments/PlaymodeTests/NEG.Utils.Achievments.Tests.Playmode.asmdef +++ b/Achievments/PlaymodeTests/NEG.Utils.Achievments.Tests.Playmode.asmdef @@ -4,7 +4,7 @@ "references": [ "UnityEngine.TestRunner", "UnityEditor.TestRunner", - "NEG.Utils.Achivments" + "NEG.Utils.Achievments" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/Achievments/Tests/NEG.Utils.Achivments.Tests.asmdef b/Achievments/Tests/NEG.Utils.Achivments.Tests.asmdef index 929e13a..32915c0 100644 --- a/Achievments/Tests/NEG.Utils.Achivments.Tests.asmdef +++ b/Achievments/Tests/NEG.Utils.Achivments.Tests.asmdef @@ -4,10 +4,9 @@ "references": [ "UnityEngine.TestRunner", "UnityEditor.TestRunner", - "NEG.Utils.Achivments", "Unity.Addressables", "Unity.ResourceManager", - "" + "NEG.Utils.Achievments" ], "includePlatforms": [ "Editor" -- 2.47.2