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}"); } } } }