Achivment system (untested)

This commit is contained in:
LubieKakao1212 2022-12-21 15:13:55 +01:00
parent 1318e8fea4
commit 991c9ccdcc
20 changed files with 468 additions and 0 deletions

8
Achivments.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ff9bb206aea50d14997771b9a0cc2b04
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fad96d35cce2d3e469d300e6e48a048a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f9bd42dd58472044b8ecc0d69caa7da8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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<AchivmentDefinition> Achivments { get; private set; } = new List<AchivmentDefinition>();
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ef37a873be859d042bda22dee624e429
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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<AchivmentManagerConfig>(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<AchivmentDefinitionCollection>(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<string, AchivmentDefinition> definitionCache;
private Dictionary<AchivmentDefinition, AchivmentData> dataCache;
private AchivmentManager()
{
definitionCache = new Dictionary<string, AchivmentDefinition>();
dataCache = new Dictionary<AchivmentDefinition, AchivmentData>();
}
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<IAchivmentCallbackReciever> 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");
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 841f326ebfd59e646835bf81432d3ae4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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)
{
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 88120b6e616164f489387a6a32a25dee
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
Achivments/Backend.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 48ec3460d89c2f144827761002d7f4d9
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,23 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace NEG.Utils.Achivments
{
public interface IAchivmentCallbackReciever
{
/// <summary>
/// Called when an achivment is completed
/// </summary>
/// <param name="achivment"></param>
/// <param name="getState"></param>
void SetAchivment(AchivmentData achivment);
/// <summary>
/// Called when achivment progress changes
/// </summary>
/// <param name="achivment"></param>
/// <param name="progress">Current achivment progress, equal to <paramref name="achivment"/> <see cref="AchivmentDefinition.ProgressRequired"/> - <see cref="AchivmentData.ProgressLeft"/></param>
void SetAchivmentProgress(AchivmentData achivment, int progress);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7218fed73c5be2c4ba31eca9fe44d37a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,21 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace NEG.Utils.Achivments
{
public interface IAchivmentManagerConfig
{
/// <summary>
/// Used to Apply config data
/// </summary>
/// <param name="builder"></param>
void Apply(AchivmentManager.Builder builder);
/// <summary>
/// Called after <see cref="Apply(AchivmentManager.Builder)"/> was called on every other config
/// </summary>
/// <param name="builder"></param>
void ApplyLast(AchivmentManager.Builder builder);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bd4b0d54603883447b6458263d6b3605
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

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

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cfab45a1ce7cc0a4899f35a61b6a60f6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -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
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 380ad496eab7ace4b98ceede94941223
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: