James Peret 3 anni fa
commit
cd026d53cb

+ 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
Runtime.meta

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

+ 20 - 0
Runtime/KairoEngine.SteamIntegration.asmdef

@@ -0,0 +1,20 @@
+{
+    "name": "KairoEngine.SteamIntegration",
+    "rootNamespace": "",
+    "references": [
+        "GUID:e048eeec9bdb9d30448017b829deb3f6",
+        "GUID:7e5ae6a38d1532248b4c890eca668b06"
+    ],
+    "includePlatforms": [],
+    "excludePlatforms": [],
+    "allowUnsafeCode": false,
+    "overrideReferences": true,
+    "precompiledReferences": [
+        "Facepunch.Steamworks.Win64.dll",
+        "Sirenix.OdinInspector.Attributes.dll"
+    ],
+    "autoReferenced": true,
+    "defineConstraints": [],
+    "versionDefines": [],
+    "noEngineReferences": false
+}

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

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

+ 57 - 0
Runtime/SteamModule.cs

@@ -0,0 +1,57 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using KairoEngine.Core;
+using KairoEngine.Core.ModuleSystem;
+using Sirenix.OdinInspector;
+
+namespace KairoEngine.SteamIntegration
+{
+    public class SteamModule : GameModuleBase
+    {
+        public override string name => "Steam Module";
+
+        [LabelText("Steamworks App ID")] public uint appId = 0000000;
+        public bool showDebug = false;
+
+        public SteamModule(GameConfig config) : base(config)
+        {
+            this.gameConfig = config;
+            this.className = this.GetType().AssemblyQualifiedName;
+            this.typeName = "SteamModule";
+        }
+
+        public override void Load(Transform parent)
+        {
+            GameObject obj = GameObject.Instantiate(new GameObject(), parent);
+            obj.name = "SteamIntegration";
+            SteamworksManager steamworksManager = obj.AddComponent<SteamworksManager>();
+            steamworksManager.appId = appId;
+            steamworksManager.ShowDebug(showDebug);
+        }
+
+        public override void Start() { }
+
+        public override void Reset() { }
+
+        public override void Destroy() { }
+
+        public static SteamModule JSONToSteamModule(string data)
+        {
+            try
+            {
+                return JsonUtility.FromJson<SteamModule>(data);
+            }
+            catch (System.Exception e)
+            {
+                Debug.LogError($"Could not deserialize SteamModule: \n{e}");
+                return new SteamModule(null);
+            }
+        }
+
+        public override void OnBeforeSerialize(ObjectSerializer serializer) { }
+
+        public override void OnBeforeDeserialize(ObjectSerializer serializer) { }
+    }
+}

+ 11 - 0
Runtime/SteamModule.cs.meta

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

+ 74 - 0
Runtime/SteamworksAchievements.cs

@@ -0,0 +1,74 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using Sirenix.OdinInspector;
+using KairoEngine.Core;
+
+namespace KairoEngine.SteamIntegration
+{
+
+    [System.Serializable]
+    public class SteamworksAchievements
+    {
+        [Tooltip("Listen for internal game events for when an achievement is unlocked")]
+        public bool listenForUnlockEvents = true;
+        [ShowIf("@listenForUnlockEvents")] public string listenEventName = "AchievementUnlockedEvent";
+
+        [Tooltip("Fire an event when an achievement is unlocked in the Steam backend")]
+        public bool broadcastEventOnUnlock = true;
+        [ShowIf("@broadcastEventOnUnlock")] public string broadcastEventName = "SteamAchievementUnlocked";
+
+        public void Start()
+        {
+            if(listenForUnlockEvents) GenericEvents.StartListening(listenEventName, UnlockAchievement);
+            if(broadcastEventOnUnlock) Steamworks.SteamUserStats.OnAchievementProgress += AchievementChanged;
+        }
+
+        public void Stop()
+        {
+            if(listenForUnlockEvents) GenericEvents.StopListening(listenEventName, UnlockAchievement);
+            if(broadcastEventOnUnlock) Steamworks.SteamUserStats.OnAchievementProgress -= AchievementChanged;
+        }
+
+        private void AchievementChanged( Steamworks.Data.Achievement ach, int currentProgress, int progress )
+        {
+            if ( ach.State )
+            {
+                Debug.Log( $"{ach.Name} WAS UNLOCKED!" );
+                GenericEvents.Trigger(broadcastEventName, ach.Identifier);
+            }
+        }
+
+        [Button("Unlock Achievement")]
+        public void UnlockAchievement(string achievementId)
+        {
+            if(!SteamworksManager.HasInitialized()) return;
+            var achievements = Steamworks.SteamUserStats.Achievements;
+            foreach (var achievement in achievements)
+            {
+                if(achievement.Identifier == achievementId)
+                {
+                    if(achievement.State == false) 
+                    {
+                        achievement.Trigger();
+                        Steamworks.SteamUserStats.StoreStats();
+                        Debug.Log($"UNLOCKED achievement {achievementId} on Steam");
+                    }
+                    else Debug.Log($"Achievement {achievementId} already UNLOCKED on Steam");
+                    return;
+                }
+            }
+        }        
+
+        [ButtonGroup("Buttons"),Button("Print Achievements")]
+        public void PrintAchievementStatus()
+        {
+            if(!SteamworksManager.HasInitialized()) return;
+            var achievements = Steamworks.SteamUserStats.Achievements;
+            foreach (var achievement in achievements)
+            {
+                Debug.Log($"{achievement.Name} ({(achievement.State ? "UNLOCKED" : "LOCKED")} - {achievement.Identifier})");
+            }
+        }
+    }
+}

+ 11 - 0
Runtime/SteamworksAchievements.cs.meta

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

+ 122 - 0
Runtime/SteamworksManager.cs

@@ -0,0 +1,122 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using Sirenix.OdinInspector;
+
+namespace KairoEngine.SteamIntegration
+{
+    // Todo: Separete concerns into different scripts - manager, stats, achievements, friends, screenshoots...
+    // Todo: Update stats
+    // Todo: Sync stats with KairoEngine Statistics
+    // Todo: Steam screenshoot
+    // Todo: Send user data to Analytics system 
+
+    [HideMonoScript]
+    public class SteamworksManager : MonoBehaviour
+    {
+        [BoxGroup("Configurations"), LabelText("Steamworks App ID")] public uint appId = 0;
+        [BoxGroup("Configurations"), LabelText("Use Stats")] public bool useStats = true;
+        [BoxGroup("Configurations"), LabelText("Use Achievements"), ShowIf("@useStats")] public bool useAchievements = true;
+        [BoxGroup("Configurations"), ShowInInspector] public static bool showDebug = false;
+
+        [FoldoutGroup("Stats"), InlineProperty, HideLabel, ShowIf("@useStats")] 
+        public SteamworksStats stats = new SteamworksStats();
+
+        [FoldoutGroup("Achievements"), InlineProperty, HideLabel, ShowIf("@useAchievements && useStats")] 
+        public SteamworksAchievements achievements = new SteamworksAchievements();
+
+        public static bool hasInitialized = false;
+        private string playerName;
+
+        private void OnDestroy() 
+        {
+            stats.Stop();
+            achievements.Stop();
+            Steamworks.SteamClient.Shutdown();
+            hasInitialized = false;
+        }
+        
+
+        private void Start()
+        {
+            if(appId == 0) 
+            {
+                if(showDebug) Debug.LogWarning("Missing AppId for Steamworks manager. Please configure Steam Module in GameConfig.");
+                return;
+            }
+            try
+            {
+                Steamworks.SteamClient.Init( appId, true );
+                hasInitialized = true;
+                playerName = Steamworks.SteamClient.Name;
+                var playerSteamId = Steamworks.SteamClient.SteamId;
+                if(showDebug)  Debug.Log($"{playerName} ({playerSteamId})");
+                if(useStats) stats.Start();
+                if(useAchievements) achievements.Start();
+                RefreshStats();
+                //PrintFriendsList();
+            }
+            catch ( System.Exception e )
+            {
+                Debug.LogError(e.ToString());
+            }
+        }
+
+        public static bool HasInitialized()
+        {
+            if(hasInitialized == false)
+            {
+                Debug.LogWarning("Not connected to Steam");
+                return false;
+            }
+            return true;
+        }
+
+        public static void RefreshStats()
+        {
+            if(!HasInitialized()) return;
+            bool received = Steamworks.SteamUserStats.RequestCurrentStats();
+            if(showDebug) 
+            {
+                if(received) Debug.Log("Received current stats from Steam");
+                else Debug.LogWarning("Error requesting current Steam stats");
+            }
+            
+        }
+
+        // [ButtonGroup("Buttons"), Button("Print Friends List")]
+        // public void PrintFriendsList()
+        // {
+        //     if(!HasInitialized()) return;
+        //     List<string> friends = new List<string>();
+        //     string friendsText = "";
+        //     foreach ( var player in Steamworks.SteamFriends.GetFriends() )
+        //     {
+        //         friends.Add(player.Name);
+        //     }
+        //     for (int i = 0; i < friends.Count; i++)
+        //     {
+        //         if(i < friends.Count - 1) friendsText += $"{friends[i]}, ";
+        //         else friendsText += $"{friends[i]}";
+        //     }
+        //     Debug.Log($"Friends of {playerName}: {friendsText}");
+        // }
+
+        [Button("Reset Player Stats & Achievements"), GUIColor("@Color.red"), PropertyTooltip("The password is RESETDATA")]
+        public void ResetSteamStats(string password, bool resetAchievements = true)
+        {
+            if(password != "RESETDATA")
+            {
+                Debug.LogWarning("Incorrect password");
+                return;
+            }
+            if(!SteamworksManager.HasInitialized()) return;
+            Steamworks.SteamUserStats.ResetAll( resetAchievements ); // true = wipe achivements too
+            Steamworks.SteamUserStats.StoreStats();
+            SteamworksManager.RefreshStats();
+            Debug.Log($"Steamworks data for player {playerName} has been reset!");
+        }
+
+        public void ShowDebug(bool debug) => showDebug = debug;
+    }
+}

+ 11 - 0
Runtime/SteamworksManager.cs.meta

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

+ 15 - 0
Runtime/SteamworksStats.cs

@@ -0,0 +1,15 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using Sirenix.OdinInspector;
+
+namespace KairoEngine.SteamIntegration
+{
+    [System.Serializable]
+    public class SteamworksStats
+    {
+        public void Start() { }
+        public void Stop() { }
+        
+    }
+}

+ 11 - 0
Runtime/SteamworksStats.cs.meta

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