Browse Source

Initial commit

James Peret 2 years ago
commit
1b8b8ab09f

+ 71 - 0
.gitignore

@@ -0,0 +1,71 @@
+# This .gitignore file should be placed at the root of your Unity project directory
+#
+# Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore
+#
+/[Ll]ibrary/
+/[Tt]emp/
+/[Oo]bj/
+/[Bb]uild/
+/[Bb]uilds/
+/[Ll]ogs/
+/[Uu]ser[Ss]ettings/
+
+# MemoryCaptures can get excessive in size.
+# They also could contain extremely sensitive data
+/[Mm]emoryCaptures/
+
+# Asset meta data should only be ignored when the corresponding asset is also ignored
+!/[Aa]ssets/**/*.meta
+
+# Uncomment this line if you wish to ignore the asset store tools plugin
+# /[Aa]ssets/AssetStoreTools*
+
+# Autogenerated Jetbrains Rider plugin
+/[Aa]ssets/Plugins/Editor/JetBrains*
+
+# Visual Studio cache directory
+.vs/
+
+# Gradle cache directory
+.gradle/
+
+# Autogenerated VS/MD/Consulo solution and project files
+ExportedObj/
+.consulo/
+*.csproj
+*.unityproj
+*.sln
+*.suo
+*.tmp
+*.user
+*.userprefs
+*.pidb
+*.booproj
+*.svd
+*.pdb
+*.mdb
+*.opendb
+*.VC.db
+
+# Unity3D generated meta files
+*.pidb.meta
+*.pdb.meta
+*.mdb.meta
+
+# Unity3D generated file on crash reports
+sysinfo.txt
+
+# Builds
+*.apk
+*.aab
+*.unitypackage
+
+# Crashlytics generated file
+crashlytics-build.properties
+
+# Packed Addressables
+/[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin*
+
+# Temporary auto-generated Android Assets
+/[Aa]ssets/[Ss]treamingAssets/aa.meta
+/[Aa]ssets/[Ss]treamingAssets/aa/*

+ 8 - 0
Editor.meta

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

+ 8 - 0
Editor/Icons.meta

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

BIN
Editor/Icons/831725.png


+ 108 - 0
Editor/Icons/831725.png.meta

@@ -0,0 +1,108 @@
+fileFormatVersion: 2
+guid: 474bff1a86879204da0166ec12e79c56
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 11
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 0
+    sRGBTexture: 1
+    linearTexture: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapsPreserveCoverage: 0
+    alphaTestReferenceValue: 0.5
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: 0.25
+    normalMapFilter: 0
+  isReadable: 0
+  streamingMipmaps: 0
+  streamingMipmapsPriority: 0
+  vTOnly: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 6
+  cubemapConvolution: 0
+  seamlessCubemap: 0
+  textureFormat: 1
+  maxTextureSize: 2048
+  textureSettings:
+    serializedVersion: 2
+    filterMode: 1
+    aniso: 1
+    mipBias: 0
+    wrapU: 1
+    wrapV: 1
+    wrapW: 0
+  nPOTScale: 0
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 1
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: 0.5, y: 0.5}
+  spritePixelsToUnits: 100
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spriteGenerateFallbackPhysicsShape: 1
+  alphaUsage: 1
+  alphaIsTransparency: 1
+  spriteTessellationDetail: -1
+  textureType: 8
+  textureShape: 1
+  singleChannelComponent: 0
+  flipbookRows: 1
+  flipbookColumns: 1
+  maxTextureSizeSet: 0
+  compressionQualitySet: 0
+  textureFormatSet: 0
+  ignorePngGamma: 0
+  applyGammaDecoding: 0
+  platformSettings:
+  - serializedVersion: 3
+    buildTarget: DefaultTexturePlatform
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  - serializedVersion: 3
+    buildTarget: Standalone
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 5e97eb03825dee720800000000000000
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

BIN
Editor/Icons/icon-achievement.png


+ 108 - 0
Editor/Icons/icon-achievement.png.meta

@@ -0,0 +1,108 @@
+fileFormatVersion: 2
+guid: bdd99bac9095e2644bba1dfb95178ce2
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 11
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 0
+    sRGBTexture: 1
+    linearTexture: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapsPreserveCoverage: 0
+    alphaTestReferenceValue: 0.5
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: 0.25
+    normalMapFilter: 0
+  isReadable: 0
+  streamingMipmaps: 0
+  streamingMipmapsPriority: 0
+  vTOnly: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 6
+  cubemapConvolution: 0
+  seamlessCubemap: 0
+  textureFormat: 1
+  maxTextureSize: 2048
+  textureSettings:
+    serializedVersion: 2
+    filterMode: 1
+    aniso: 1
+    mipBias: 0
+    wrapU: 1
+    wrapV: 1
+    wrapW: 0
+  nPOTScale: 0
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 1
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: 0.5, y: 0.5}
+  spritePixelsToUnits: 100
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spriteGenerateFallbackPhysicsShape: 1
+  alphaUsage: 1
+  alphaIsTransparency: 1
+  spriteTessellationDetail: -1
+  textureType: 8
+  textureShape: 1
+  singleChannelComponent: 0
+  flipbookRows: 1
+  flipbookColumns: 1
+  maxTextureSizeSet: 0
+  compressionQualitySet: 0
+  textureFormatSet: 0
+  ignorePngGamma: 0
+  applyGammaDecoding: 0
+  platformSettings:
+  - serializedVersion: 3
+    buildTarget: DefaultTexturePlatform
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  - serializedVersion: 3
+    buildTarget: Standalone
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 5e97eb03825dee720800000000000000
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Runtime.meta

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

+ 86 - 0
Runtime/AchievementBase.cs

@@ -0,0 +1,86 @@
+using System.Collections;
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+using Sirenix.OdinInspector;
+using KairoEngine.Utilities.Statistics;
+
+namespace KairoEngine.Achievements
+{
+    [CreateAssetMenu(fileName = "Achievement", menuName = "KairoEngine/Achievements/Achievement", order = 10), HideMonoScript]
+    public class AchievementBase : ScriptableObject
+    {
+        
+        [BoxGroup("Achievement")] public string title;
+        [BoxGroup("Achievement")] public string identifier;
+        [BoxGroup("Achievement")] public Sprite unlockedIcon;
+        [BoxGroup("Achievement")] public Sprite lockedIcon;
+        [BoxGroup("Achievement"), HideLabel, TextArea(minLines:2 ,maxLines:2)] public string description;
+
+        [BoxGroup("Statistic")] public string statisticTitle;
+        [BoxGroup("Statistic")] public ComparisionOperator comparasion;
+
+        [BoxGroup("Statistic")] public StatisticType statisticType = StatisticType.integer;
+        [BoxGroup("Statistic"), ShowIf("@statisticType == StatisticType.integer")] public int intValue;
+        [BoxGroup("Statistic") , ShowIf("@statisticType == StatisticType.time")] public float floatValue;
+        [BoxGroup("Statistic"), ShowIf("@statisticType == StatisticType.text")] public string stringValue;
+
+        public bool HasAchieved()
+        {
+            var stat = Statistics.GetData(statisticTitle);
+            if(stat == null) return false;
+            switch (statisticType)
+            {
+                case StatisticType.integer:
+                    int currentInt = stat.GetInteger();
+                    return Compare<int>(currentInt, intValue);
+                case StatisticType.time:
+                    float currentTime = stat.GetTime();
+                    return Compare<float>(currentTime, floatValue);
+                case StatisticType.text:
+                    string currentText = stat.GetText();
+                    return Compare<string>(currentText, stringValue);
+                default:
+                    return false;
+            }
+        } 
+
+        public bool Compare<T>(T value1, T value2)
+        {
+            switch (comparasion)
+            {
+                default:
+                case ComparisionOperator.EqualTo:
+                    return EqualityComparer<T>.Default.Equals(value1 , value2);
+                case ComparisionOperator.NotEqualTo:
+                    return !EqualityComparer<T>.Default.Equals(value1 , value2);
+                case ComparisionOperator.GreaterThan:
+                    if(typeof(T) == typeof(int)) return Convert.ToInt32(value1) > Convert.ToInt32(value2);
+                    else if(typeof(T) == typeof(float)) return Convert.ToDecimal(value1) > Convert.ToDecimal(value2);
+                    else if(typeof(T) == typeof(string)) return Convert.ToString(value1).Length > Convert.ToString(value2).Length;
+                    else return false;
+                case ComparisionOperator.GreaterThanOrEqualTo:
+                    if(typeof(T) == typeof(int)) return Convert.ToInt32(value1) >= Convert.ToInt32(value2);
+                    else if(typeof(T) == typeof(float)) return Convert.ToDecimal(value1) >= Convert.ToDecimal(value2);
+                    else if(typeof(T) == typeof(string)) return Convert.ToString(value1).Length >= Convert.ToString(value2).Length;
+                    else return false;
+                case ComparisionOperator.LessThan:
+                    if(typeof(T) == typeof(int)) return Convert.ToInt32(value1) < Convert.ToInt32(value2);
+                    else if(typeof(T) == typeof(float)) return Convert.ToDecimal(value1) < Convert.ToDecimal(value2);
+                    else if(typeof(T) == typeof(string)) return Convert.ToString(value1).Length < Convert.ToString(value2).Length;
+                    else return false;
+                case ComparisionOperator.LessOrEqualTo:
+                    if(typeof(T) == typeof(int)) return Convert.ToInt32(value1) <= Convert.ToInt32(value2);
+                    else if(typeof(T) == typeof(float)) return Convert.ToDecimal(value1) <= Convert.ToDecimal(value2);
+                    else if(typeof(T) == typeof(string)) return Convert.ToString(value1).Length <= Convert.ToString(value2).Length;
+                    else return false;
+            }
+        }
+    }
+
+    public enum ComparisionOperator
+    {
+        EqualTo, NotEqualTo, GreaterThan, GreaterThanOrEqualTo, LessThan, LessOrEqualTo
+    }
+
+}

+ 11 - 0
Runtime/AchievementBase.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f580df0f812fdd642858c0e5eca040bb
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {fileID: 2800000, guid: bdd99bac9095e2644bba1dfb95178ce2, type: 3}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 21 - 0
Runtime/AchievementStatus.cs

@@ -0,0 +1,21 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using Sirenix.OdinInspector;
+
+namespace KairoEngine.Achievements
+{
+    [System.Serializable]
+    public class AchievementStatus
+    {
+        [HorizontalGroup("data", 0.015f), HideLabel, ReadOnly] public bool unlocked = false;
+        [HorizontalGroup("data", 0.985f), HideLabel, ReadOnly] public AchievementBase achievement;
+        
+
+        public AchievementStatus(AchievementBase achievement, bool unlocked)
+        {
+            this.achievement = achievement;
+            this.unlocked = unlocked;
+        }
+    }
+}

+ 11 - 0
Runtime/AchievementStatus.cs.meta

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

+ 87 - 0
Runtime/AchievementsController.cs

@@ -0,0 +1,87 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using Sirenix.OdinInspector;
+using KairoEngine.Utilities.Statistics;
+using KairoEngine.Core;
+using UniRx;
+
+namespace KairoEngine.Achievements
+{
+    [HideMonoScript]
+    public class AchievementsController : SerializedMonoBehaviour
+    {
+        public string achievementCompletedEvent = "AchievementCompletedEvent";
+       
+        public bool CheckOnStart = true;
+        public bool checkOnInterval = true;
+        [ShowIf("@checkOnInterval"), SuffixLabel("ms")] public int checkInterval = 1000;
+        [SuffixLabel("ms")] public int startDelay = 0;
+        public bool debug = false;
+        [ShowIf("@!initialized")] public AchievementsLibrary library;
+
+        [ShowIf("@initialized"), System.NonSerialized, ShowInInspector, HideReferenceObjectPicker]
+        [ListDrawerSettings(IsReadOnly = true, DraggableItems = false, Expanded = true, ShowIndexLabels = false, ShowPaging = false, ShowItemCount = true, HideRemoveButton = true)]
+        public List<AchievementStatus> achievementsStatus;
+        private bool initialized = false;
+        private CompositeDisposable timerComposite;
+
+        private void Start()
+        {
+            if(debug) Debug.Log("Initializing AchievementsController");
+            if(Statistics.instance == null) Debug.LogError("Missing Statistics component");
+            if(library == null) 
+            {
+                Debug.LogError("Missing Achievements Library on AchievementsController.\nPlease configure the Achievements module in the GameConfig file.");
+                return;
+            }
+            achievementsStatus = new List<AchievementStatus>();
+            for (int i = 0; i < library.achievements.Count; i++) 
+            {
+                int value = PlayerPrefs.GetInt($"ACHIEVEMENT_{library.achievements[i].identifier}", 0);
+                achievementsStatus.Add(new AchievementStatus(library.achievements[i], value == 0 ? false : true));
+                PlayerPrefs.SetInt($"ACHIEVEMENT_{library.achievements[i].identifier}", value);
+            }
+            initialized = true;
+            Timer.ExecuteRealTime(startDelay, () => {
+                if(CheckOnStart) CheckAchievements();
+                if(checkOnInterval) StartCheckTimer();
+            });
+            
+        }
+
+        private void OnDestroy() 
+        {
+            if (timerComposite != null) timerComposite.Dispose();
+        } 
+
+        public void CheckAchievements()
+        {
+            if(debug) Debug.Log($"Checking achievements ({achievementsStatus.Count})");
+            if(library == null) return;
+            for (int i = 0; i < achievementsStatus.Count; i++)
+            {
+                if(achievementsStatus[i].unlocked == true) continue;
+                if(achievementsStatus[i].achievement.HasAchieved())
+                {
+                    Debug.Log($"Achievement Unlocked: {achievementsStatus[i].achievement.title}");
+                    GenericEvents.Trigger(achievementCompletedEvent, achievementsStatus[i].achievement.identifier);
+                    achievementsStatus[i].unlocked = true;
+                    PlayerPrefs.SetInt($"ACHIEVEMENT_{achievementsStatus[i].achievement.identifier}", 1);
+                }
+            }
+        }
+
+        public void StartCheckTimer()
+        {
+            timerComposite = Timer.ExecuteRealTime(checkInterval, () => {
+                if(checkOnInterval)
+                {
+                    CheckAchievements();
+                    StartCheckTimer();
+                }
+            });
+            
+        }
+    }
+}

+ 11 - 0
Runtime/AchievementsController.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f2ecd7adbe569984ab9fa1795d90cdd1
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {fileID: 2800000, guid: 474bff1a86879204da0166ec12e79c56, type: 3}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 13 - 0
Runtime/AchievementsLibrary.cs

@@ -0,0 +1,13 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using Sirenix.OdinInspector;
+
+namespace KairoEngine.Achievements
+{
+    [CreateAssetMenu(fileName = "Achievements Library", menuName = "KairoEngine/Achievements/Library"), HideMonoScript]
+    public class AchievementsLibrary : ScriptableObject
+    {
+        public List<AchievementBase> achievements = new List<AchievementBase>();
+    }
+}

+ 11 - 0
Runtime/AchievementsLibrary.cs.meta

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

+ 67 - 0
Runtime/AchievementsModule.cs

@@ -0,0 +1,67 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using KairoEngine.Core;
+using KairoEngine.Core.ModuleSystem;
+using Sirenix.OdinInspector;
+
+namespace KairoEngine.Achievements
+{
+    [Serializable, HideReferenceObjectPicker]
+    public class AchievementsModule : GameModuleBase
+    {
+        public override string name => "Achievements Module";
+        [FoldoutGroup("@name"), NonSerialized, ShowInInspector, InlineEditor(InlineEditorObjectFieldModes.Boxed)] public AchievementsLibrary library;
+
+        public AchievementsModule(GameConfig config) : base(config)
+        {
+            this.gameConfig = config;
+            this.className = this.GetType().AssemblyQualifiedName;
+            this.typeName = "AchievementsModule";
+        }
+
+        public override void Load(Transform parent)
+        {
+            if(library == null)
+            {
+                Debug.LogError("Missing Achievements Library.\nPlease configure the Achievements module in the Game config file.");
+                return;
+            }
+            var obj = new GameObject();
+            obj.transform.parent = parent;
+            obj.name = "Achievements";
+            var comp = obj.AddComponent<AchievementsController>();
+            comp.library = library;
+        }
+
+        public override void Reset()
+        {
+            
+        }
+
+        public override void Destroy() { }
+
+        public static AchievementsModule JSONToAchievementsModule(string data)
+        {
+            try
+            {
+                return JsonUtility.FromJson<AchievementsModule>(data);
+            }
+            catch (System.Exception e)
+            {
+                Debug.LogError($"Could not deserialize AchievementsModule: \n{e}");
+                return new AchievementsModule(null);
+            }
+        }
+
+        public override void OnBeforeSerialize(ObjectSerializer serializer) 
+        {
+            if(library != null) serializer.AddScriptableObject("Achievements_Library", library);
+        }
+        public override void OnBeforeDeserialize(ObjectSerializer serializer)
+        { 
+            library = (AchievementsLibrary)serializer.GetScriptableObject("Achievements_Library");
+        }
+    }
+}

+ 11 - 0
Runtime/AchievementsModule.cs.meta

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

+ 18 - 0
Runtime/KairoEngine.Achievements.asmdef

@@ -0,0 +1,18 @@
+{
+    "name": "KairoEngine.Achievements",
+    "rootNamespace": "",
+    "references": [
+        "GUID:7e5ae6a38d1532248b4c890eca668b06",
+        "GUID:165d83fc3bb2a4144925c85421871d8e",
+        "GUID:560b04d1a97f54a4e82edc0cbbb69285"
+    ],
+    "includePlatforms": [],
+    "excludePlatforms": [],
+    "allowUnsafeCode": false,
+    "overrideReferences": false,
+    "precompiledReferences": [],
+    "autoReferenced": true,
+    "defineConstraints": [],
+    "versionDefines": [],
+    "noEngineReferences": false
+}

+ 7 - 0
Runtime/KairoEngine.Achievements.asmdef.meta

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