achivments #1

Closed
Ghost wants to merge 13 commits from achivments into main
18 changed files with 235 additions and 11 deletions
Showing only changes of commit 1c5f93d8b1 - Show all commits

View File

@ -110,6 +110,8 @@ namespace NEG.Utils.Achievments
private Dictionary<string, AchievmentDefinition> definitionCache;
private Dictionary<AchievmentDefinition, AchievmentData> dataCache;
private IAchievmentBackend activeBackend;
private AchievmentManager()
{
definitionCache = new Dictionary<string, AchievmentDefinition>();
@ -135,6 +137,7 @@ namespace NEG.Utils.Achievments
/// <remarks>Resets all achievments data</remarks>
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<T>(AchievmentData data) where T : AchievmentData
{
if (data is not T convetred)

View File

@ -8,10 +8,15 @@ namespace NEG.Utils.Achievments.AchievmentTypes
{
public override bool IsCompleted => CurrentProgress >= Def.ProgressRequired;
/// <summary>
/// Use to GET current progress
/// Do not SET the value directly use <see cref="AchievmentManager"/> or <see cref="Achievment"/> Instead <br/>
/// Unless you are in <see cref="IAchievmentBackend.GetStoredAchivment(AchievmentDefinition)">
/// </summary>
public float CurrentProgress
{
get => currentProgress;
internal set
set
{
if (Def.Clamped)
{

View File

@ -9,10 +9,15 @@ namespace NEG.Utils.Achievments.AchievmentTypes
{
public override bool IsCompleted => CurrentProgress >= Def.ProgressRequired;
/// <summary>
/// Use to GET current progress
/// Do not SET the value directly use <see cref="AchievmentManager"/> or <see cref="Achievment"/> Instead <br/>
/// Unless you are in <see cref="IAchievmentBackend.GetStoredAchivment(AchievmentDefinition)">
/// </summary>
public int CurrentProgress
{
get => currentProgress;
internal set
set
{
if (Def.Clamped)
{

View File

@ -8,7 +8,12 @@ namespace NEG.Utils.Achievments.AchievmentTypes
{
public override bool IsCompleted => CompletionState;
public bool CompletionState { get; internal set; } = false;
/// <summary>
/// Use to GET current progress
/// Do not SET the value directly use <see cref="AchievmentManager"/> or <see cref="Achievment"/> Instead <br/>
/// Unless you are in <see cref="IAchievmentBackend.GetStoredAchivment(AchievmentDefinition)">
/// </summary>
public bool CompletionState { get; set; } = false;
public ToggleAchievmentData(ToggleAchievmentDefinition def) : base(def)
{

View File

@ -0,0 +1,15 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace NEG.Utils.Achievments
{
public class AchievmentsUpdater : MonoBehaviour
Review

Should be created automaticly

Should be created automaticly
Review

How?

How?
Review

Create game object and add component?

Create game object and add component?
Review

When?

When?
Review

Duno it's your system

Duno it's your system
{
void Update()
{
Achievment.Instance.UpdateBackend();
}
}
}

View File

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

View File

@ -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
}
}
/// <summary>
/// This backend is not optimised at all, do not use in public builds
/// </summary>
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))

View File

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

View File

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

View File

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

View File

@ -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();
Review

No reaction for callback

No reaction for callback
Review

I asked about it, you said to ignore it, but I can change it

I asked about it, you said to ignore it, but I can change it
}
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);
Review

No reaction for bool

No reaction for bool
Review

will fix

will fix
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)
Review

Should be check when last time, min time of refresh sholub be greater than minute

Should be check when last time, min time of refresh sholub be greater than minute
Review

I dont understand

I dont understand
Review

look to documentatnion, you should fire storage callback withing minutes not seconds

look to documentatnion, you should fire storage callback withing minutes not seconds
{
//Reiterate on failure?
isDirty = !SteamUserStats.StoreStats();
Review

No reaction for callback

No reaction for callback
Review

will fix

will fix
}
}
}
#endif
}

View File

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

View File

@ -21,6 +21,11 @@ namespace NEG.Utils.Achievments
/// Constructs an AchievmentData for given <paramref name="definition"/>
/// </summary>
/// <remarks>May return null if there is no stored data for this achievment</remarks>
public AchievmentData GetStoredAchivment(AchievmentDefinition definition);
AchievmentData GetStoredAchivment(AchievmentDefinition definition);
/// <summary>
/// Used for e.g. syncing with upstream
/// </summary>
void Update();
}
}

View File

@ -1,5 +1,5 @@
{
"name": "NEG.Utils.Achivments",
"name": "NEG.Utils.Achievments",
"rootNamespace": "",
"references": [
"GUID:9e24947de15b9834991c9d8411ea37cf",

View File

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

View File

@ -4,7 +4,7 @@
"references": [
"UnityEngine.TestRunner",
"UnityEditor.TestRunner",
"NEG.Utils.Achivments"
"NEG.Utils.Achievments"
],
"includePlatforms": [],
"excludePlatforms": [],

View File

@ -4,10 +4,9 @@
"references": [
"UnityEngine.TestRunner",
"UnityEditor.TestRunner",
"NEG.Utils.Achivments",
"Unity.Addressables",
"Unity.ResourceManager",
""
"NEG.Utils.Achievments"
],
"includePlatforms": [
"Editor"