Browse Source

Initial commit

jamesperet 2 years ago
commit
3ed48675b6

+ 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/*

+ 110 - 0
Readme.md

@@ -0,0 +1,110 @@
+# KairoEngine.Analytics.v0.1.2
+
+The Analytics package uses the [Mixpanel](https://mixpanel.com) service to store analytics. It can be easly changed to use another service without having to change the actual event tracking inside the game.
+
+### Required packages
+
+- `Mixpanel.Unity` ([github](https://github.com/mixpanel/mixpanel-unity))
+- ``KairoEngine.Core``
+
+### Namespaces
+
+- `KairoEngine.Analytics`
+
+### Modules
+
+### Components
+
+- `Analytics` �? The analytics system component that needs to be filled out with the mixpanel Key.
+
+### Getting Started
+
+Create a new class called ``GameAnalytics`` or use the name of the current game and add the following libraries:
+
+```csharp
+using KairoEngine.Core;
+using KairoEngine.Utilities;
+using KairoEngine.Analytics;
+
+/// <summary>Listen to game events and emmit analytic events.</summary>
+public class GameAnalytics : MonoBehaviour
+{
+
+}
+```
+
+Then to start tracking a player, use these snippets:
+
+```csharp
+// Get or create a Player ID
+var randomID = KairoEngine.Core.Utilities.RandomString(12);
+var playerID = PlayerPrefs.GetString("PlayerID", randomID);
+PlayerPrefs.SetString("PlayerID", playerID);
+// Set the ID for all tracking done from now on
+Analytics.Identify(playerID);
+// Set App Version
+Analytics.Register("App Version", Application.version);
+// Send data to the server in 2 seconds
+StartCoroutine(Timer.Start(2f, false, () => { Analytics.Flush(); }));
+```
+
+To track stuff:
+
+```csharp
+// Simple event
+Analytics.Track("Game Initialized");
+// Event with payload
+var data = new Dictionary<string, System.Object>();
+data.Add("Level", level);
+Analytics.Track("Level Started", data);
+// Timed event
+Analytics.StartTimedEvent("Level Finished");
+StartCoroutine(Timer.Start(10f, false, () => { 
+    Analytics.Track("Level Finished", data); 
+}));
+```
+
+To send analytics before quitting the application:
+
+```csharp
+// On game init, run this function that adds an 
+// event listener for when the game wants to quit
+[RuntimeInitializeOnLoadMethod] 
+static void RunOnStart() => Application.wantsToQuit += OnApplicationQuit;
+
+// Singleton for this component so that it can be 
+// referenced in a Lambda function
+public static GameAnalytics instance;
+
+// When quitting the application:
+// Cancel quitting, send quit event, flush analytics, 
+// wait 2 seconds and finally quit the application.
+static bool OnApplicationQuit() 
+{
+    // Finished the Timed event
+    Analytics.Track("Quit");
+    // Send data to the Analytics server
+    // This takes about one second to happen
+    // If the app quits now data might not be sent
+    Analytics.Flush();
+    if(instance != null) 
+    {
+        instance.StartCoroutine(Timer.Start(2f, false, () => { 
+            // Actualy close the application
+            Application.Quit(); 
+        }));
+        // Remove the event listener so no bugs pop up
+        Application.wantsToQuit -= OnApplicationQuit;
+        // Return false so that the app doesn't quit
+        return false;
+    }
+    // If there is no instance return true so that the app can quit
+    return true;
+}
+```
+
+### Functions
+
+### Back Log
+
+- [ ] Create a module that loads the analytics component on init and holds its data

+ 7 - 0
Readme.md.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 9ab60c6f6576b834e8b251999912a53f
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Runtime.meta

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

+ 64 - 0
Runtime/Analytics.cs

@@ -0,0 +1,64 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using Sirenix.OdinInspector;
+using mixpanel;
+
+namespace KairoEngine.Analytics
+{
+    /// <summary>Send analytics events to Mixpanel</summary>
+    [HideMonoScript] public class Analytics : MonoBehaviour
+    {
+        public static Analytics instance;
+
+        public bool trackEvents = true;
+        public bool debugEvents = true;
+        public bool clearEventsOnStart = false;
+
+        void OnApplicationQuit() => Mixpanel.Disable();      
+
+        void Awake()
+        {
+            if(instance == null) instance = this;
+            else Destroy(this);
+            if(clearEventsOnStart) Mixpanel.ClearTimedEvents();
+            Mixpanel.Init();
+        }
+
+        public static bool IsTracking() => instance != null ? instance.trackEvents : false;
+        public static bool ShowDebug() => instance != null ? instance.debugEvents : false;
+        public static void Identify(string playerID) => Mixpanel.Identify(playerID);
+        public static void Register(string propertieTitle, int propertyValue) => Mixpanel.Register(propertieTitle, propertyValue);
+        public static void Register(string propertieTitle, float propertyValue) => Mixpanel.Register(propertieTitle, propertyValue);
+        public static void Register(string propertieTitle, string propertyValue) => Mixpanel.Register(propertieTitle, propertyValue);
+        public static void StartTimedEvent(string title) =>  Mixpanel.StartTimedEvent(title);
+        public static void Flush() => Mixpanel.Flush();
+
+        public static void Track(string eventTitle)
+        {
+            if(IsTracking()) Mixpanel.Track(eventTitle);
+            if(ShowDebug()) Debug.Log($"Tracking event \'{eventTitle}\'");
+        }
+
+        public static void Track(string eventTitle, Value props)
+        {
+            if(IsTracking()) Mixpanel.Track(eventTitle, props);
+            if(ShowDebug()) Debug.Log($"Tracking event \'{eventTitle}\', {props.ToString()}");
+        }
+
+        public static void Track(string eventTitle, Dictionary<string, System.Object> dictionary)
+        {
+            if(!IsTracking()) return;
+            var props = new Value();
+            foreach (var item in dictionary)
+            {
+                if(item.Value.GetType() == typeof(int)) props[item.Key] = (int)item.Value;
+                else if(item.Value.GetType() == typeof(string)) props[item.Key] = (string)item.Value;
+                else if(item.Value.GetType() == typeof(float)) props[item.Key] = (float)item.Value;
+            }
+            Mixpanel.Track(eventTitle, props);
+            if(ShowDebug()) Debug.Log($"Tracking event \'{eventTitle}\', {props.ToString()}");
+        }
+
+    }
+}

+ 11 - 0
Runtime/Analytics.cs.meta

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

+ 16 - 0
Runtime/KairoEngine.Analytics.asmdef

@@ -0,0 +1,16 @@
+{
+    "name": "KairoEngine.Analytics",
+    "rootNamespace": "",
+    "references": [
+        "GUID:21462402cefc5dd4ba284fb769521eff"
+    ],
+    "includePlatforms": [],
+    "excludePlatforms": [],
+    "allowUnsafeCode": false,
+    "overrideReferences": false,
+    "precompiledReferences": [],
+    "autoReferenced": true,
+    "defineConstraints": [],
+    "versionDefines": [],
+    "noEngineReferences": false
+}

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

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

+ 15 - 0
package.json

@@ -0,0 +1,15 @@
+{
+    "name": "at.kairoscope.kairoengine.analytics",
+    "displayName": "KairoEngine Analytics",
+    "version": "0.1.2",
+    "unity": "2020.3",
+    "description": "Kairoengine analytics library. Sends data to the Mixpanel service.",
+    "dependencies": {
+      "at.kairoscope.thirdparty.mixpanel":"2.2.2"
+    },
+    "repository": {
+      "type": "git",
+      "url": "https://git.kairoscope.net/kairoengine/analytics.git"
+    },
+    "author": "Kairoscope"
+  }