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"