Skip to content

Commit cfac43e

Browse files
v.0.1.0 (#2)
* user verification tracking * Refactor flow * Update readme * Missing file * Correct AnalyticConst namespace --------- Co-authored-by: bac.tran <[email protected]>
1 parent 7a8f2d2 commit cfac43e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+393
-219
lines changed

Assets/Scenes.meta Assets/AxieInfinity.meta

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/Scripts.meta Assets/AxieInfinity/Analytic.meta

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
File renamed without changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using System.Collections;
2+
using System.Collections.Generic;
3+
using UnityEngine;
4+
5+
namespace Analytic
6+
{
7+
public class AnalyticBehavior : MonoBehaviour
8+
{
9+
private void Awake()
10+
{
11+
DontDestroyOnLoad(this);
12+
}
13+
}
14+
}

Assets/Scripts/Analytic/AnalyticManager.Heartbeat.cs Assets/AxieInfinity/Analytic/Core/AnalyticManager.Heartbeat.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ static void OnCheckInput()
1919
#endif
2020
if (isPressed)
2121
{
22-
heartbeatStats.OnNewPressed();
22+
_heartbeatStats.OnNewPressed();
2323
}
2424
}
2525
}

Assets/Scripts/Analytic/AnalyticManager.Schedule.cs Assets/AxieInfinity/Analytic/Core/AnalyticManager.Schedule.cs

+26-16
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,18 @@ public partial class AnalyticManager
1515
public const int REQUEST_INTERVAL = 10;
1616
public const int RETRY_NUMBER = 3;
1717
public const int EVENT_PER_REQUEST = 300;
18-
public static string endPoint = "https://x.skymavis.com/track";
19-
public static string apiKey;
20-
public static HeartbeatStats heartbeatStats;
18+
public static readonly string EN_POINT = "https://x.skymavis.com/track";
19+
public static string API_KEY;
20+
private static HeartbeatStats _heartbeatStats;
21+
private static string _currentName = "";
2122

2223
private static readonly Dictionary<AnalyticRequest, int> dictRetryRequests = new Dictionary<AnalyticRequest, int>();
2324

2425
private static IEnumerator CheckingTimer()
2526
{
2627
while (true)
2728
{
28-
if (initialized)
29+
if (initialized && !string.IsNullOrEmpty(userId) && !string.IsNullOrEmpty(API_KEY))
2930
{
3031
if (Time.realtimeSinceStartup - lastRequestTime > REQUEST_INTERVAL)
3132
{
@@ -44,15 +45,25 @@ private static void CheckSendAnalyticRequest()
4445
if (analyticListData == null) return;
4546
if(analyticListData.listEventDatas.Count == 0)
4647
{
47-
string heartbeatData = JsonConvert.SerializeObject(heartbeatStats);
48+
//string heartbeatData = JsonConvert.SerializeObject(_heartbeatStats);
4849

49-
var jObject = new JObject();
50-
var jHeartbeatData = JObject.Parse(heartbeatData);
51-
jObject.Add("action_properties", jHeartbeatData);
52-
jObject.Add(new JProperty("event", "heartbeat"));
53-
AddEvent(EventTypes.Track, jObject);
50+
//var jObject = new JObject();
51+
//var jHeartbeatData = JObject.Parse(heartbeatData);
52+
//jObject.Add("action_properties", jHeartbeatData);
53+
//jObject.Add(new JProperty("event", "heartbeat"));
54+
AddEvent(EventTypes.Track, new
55+
{
56+
@event = "heartbeat",
57+
action_properties = _heartbeatStats
58+
});
59+
_heartbeatStats.EndBeat();
60+
}
5461

55-
heartbeatStats.EndBeat();
62+
var activeScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
63+
if (activeScene != null && activeScene.name != _currentName)
64+
{
65+
_currentName = activeScene.name;
66+
AnalyticManager.AddEvent(EventTypes.Screen, new { @event = "s_" + _currentName });
5667
}
5768

5869
//Create new request
@@ -61,15 +72,15 @@ private static void CheckSendAnalyticRequest()
6172

6273
private static void Submit(AnalyticRequest data, Action<AsyncOperation> cb)
6374
{
64-
var request = new UnityWebRequest(endPoint, "POST"); // start as POST, then change later
75+
var request = new UnityWebRequest(EN_POINT, "POST"); // start as POST, then change later
6576
request.SetRequestHeader("Content-Type", "application/json");
6677

67-
var apiBytes = Encoding.UTF8.GetBytes($"{apiKey}:");
78+
var apiBytes = Encoding.UTF8.GetBytes($"{API_KEY}:");
6879
string encodedText = Convert.ToBase64String(apiBytes, Base64FormattingOptions.None);
6980
request.SetRequestHeader("Authorization", "Basic " + encodedText);
7081
request.downloadHandler = new DownloadHandlerBuffer();
7182
var json = JsonConvert.SerializeObject(data, AnalyticListData.SerializerSettings);
72-
Debug.Log($"[Analytic]: {json}");
83+
Debug.Log(json);
7384
var jsonBytes = new UTF8Encoding().GetBytes(json);
7485
request.uploadHandler = new UploadHandlerRaw(jsonBytes);
7586

@@ -95,7 +106,6 @@ private static void Submit(AnalyticRequest data, Action<AsyncOperation> cb)
95106

96107
private static IEnumerator RequestAfter(AnalyticRequest analyticRequest, float seconds)
97108
{
98-
99109
yield return new WaitForSeconds(seconds);
100110
DoRequest(analyticRequest);
101111
}
@@ -165,7 +175,7 @@ static void Finish(AnalyticRequest request)
165175
}
166176

167177
analyticListData.SaveToDevice();
168-
Debug.Log($"[Analytic] Request Finish: {request.events.Count}");
178+
//Debug.Log($"[Analytic] Request Finish: {request.events.Count}");
169179
}
170180
}
171181
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
using System;
2+
using Newtonsoft.Json.Linq;
3+
using UnityEngine;
4+
5+
namespace Analytic
6+
{
7+
public partial class AnalyticManager
8+
{
9+
public static string buildVersion => $"{Application.version}";
10+
11+
public static string sessionId { get; private set; }
12+
public static long sessionOffset { get; private set; }
13+
public static bool initialized { get; private set; }
14+
public static string userId;
15+
public static string env;
16+
17+
private static float lastRequestTime;
18+
19+
private static AnalyticListData analyticListData = new AnalyticListData(AnalyticListData.analyticListData);
20+
public static AnalyticBehavior analyticBehavior;
21+
22+
public static void IdentifyLocalUser()
23+
{
24+
JObject jObject = LoadLocalProfile();
25+
26+
UserVertification.GetArgVertification(out var signature, out var message);
27+
var userData = UserVertification.Vertification(signature, message);
28+
if(userData != null)
29+
{
30+
string roninAddress = (string)userData["roninAddress"];
31+
if (string.IsNullOrEmpty(roninAddress))
32+
{
33+
jObject.Add(new JProperty("ronin_address", roninAddress));
34+
}
35+
}
36+
AnalyticManager.AddEvent(EventTypes.Identify, jObject);
37+
}
38+
39+
public static void IdentifyCustomUser(JObject userProperties)
40+
{
41+
JObject jObject = LoadLocalProfile();
42+
43+
UserVertification.GetArgVertification(out var signature, out var message);
44+
var userData = UserVertification.Vertification(signature, message);
45+
if (userData != null)
46+
{
47+
string roninAddress = (string)userData["roninAddress"];
48+
if (string.IsNullOrEmpty(roninAddress))
49+
{
50+
jObject.Add(new JProperty("ronin_address", roninAddress));
51+
}
52+
}
53+
54+
if(userProperties != null)
55+
{
56+
string roninAddress = (string)userData["ronin_address"];
57+
if (!string.IsNullOrEmpty(roninAddress))
58+
{
59+
jObject["ronin_address"] = roninAddress;
60+
}
61+
string userId = (string)userProperties["user_id"];
62+
if (!string.IsNullOrEmpty(userId))
63+
{
64+
AnalyticManager.userId = userId;
65+
}
66+
jObject.Add(new JProperty("user_properties", userProperties));
67+
}
68+
69+
StartNewSession(AnalyticManager.userId);
70+
AnalyticManager.AddEvent(EventTypes.Identify, jObject);
71+
}
72+
73+
private static JObject LoadLocalProfile()
74+
{
75+
string userId = PlayerPrefs.GetString("userId");
76+
if (string.IsNullOrEmpty(userId))
77+
{
78+
userId = System.Guid.NewGuid().ToString();
79+
PlayerPrefs.SetString("userId", userId);
80+
}
81+
AnalyticManager.userId = userId;
82+
#if UNITY_EDITOR
83+
AnalyticManager.env = "dev";
84+
#else
85+
AnalyticManager.env = "staging";
86+
#endif
87+
88+
var jObject = new JObject();
89+
jObject.Add(new JProperty("device_name", SystemInfo.deviceModel));
90+
jObject.Add(new JProperty("device_id", SystemInfo.deviceUniqueIdentifier));
91+
jObject.Add(new JProperty("platform_name", Application.platform.ToString()));
92+
jObject.Add(new JProperty("platform_version", SystemInfo.operatingSystem));
93+
94+
jObject.Add(new JProperty("system_memory_size", SystemInfo.systemMemorySize));
95+
jObject.Add(new JProperty("processor_count", SystemInfo.processorCount));
96+
jObject.Add(new JProperty("graphics_device", SystemInfo.graphicsDeviceName));
97+
jObject.Add(new JProperty("graphics_memory_size", SystemInfo.graphicsMemorySize));
98+
return jObject;
99+
}
100+
101+
public static void InitManager(string apiKey)
102+
{
103+
AnalyticManager.API_KEY = apiKey;
104+
if (initialized) return;
105+
if (string.IsNullOrEmpty(EN_POINT) || string.IsNullOrEmpty(apiKey))
106+
{
107+
Debug.LogError("AnalyticManager invalid endpoint");
108+
return;
109+
}
110+
analyticListData = AnalyticListData.LoadFromDevice();
111+
sessionId = Guid.NewGuid().ToString();
112+
sessionOffset = 1;
113+
114+
AnalyticManager._heartbeatStats = new HeartbeatStats();
115+
AnalyticManager._heartbeatStats.Init();
116+
117+
lastRequestTime = float.MinValue;
118+
initialized = true;
119+
120+
var behavior = new GameObject();
121+
behavior.name = "AnalyticBehavior";
122+
analyticBehavior = behavior.AddComponent<AnalyticBehavior>();
123+
UnityEngine.GameObject.DontDestroyOnLoad(behavior);
124+
125+
analyticBehavior.StartCoroutine(CheckingTimer());
126+
Debug.Log("AnalyticManager StartSession");
127+
}
128+
129+
private static void StartNewSession(string userId)
130+
{
131+
if (userId != PlayerPrefs.GetString("userId"))
132+
{
133+
PlayerPrefs.SetString("userId", userId);
134+
sessionId = Guid.NewGuid().ToString();
135+
sessionOffset = 1;
136+
137+
AnalyticManager._heartbeatStats = new HeartbeatStats();
138+
AnalyticManager._heartbeatStats.Init();
139+
}
140+
}
141+
142+
public static void AddEvent(EventTypes type, object data)
143+
{
144+
var analyticEvent = new AnalyticEvent(type, data);
145+
AddEvent(analyticEvent);
146+
}
147+
148+
private static void AddEvent(AnalyticEvent analyticEvent)
149+
{
150+
if (!initialized) return;
151+
analyticEvent.MergeData(GetCommonFields());
152+
analyticListData.listEventDatas.Add(analyticEvent);
153+
analyticListData.SaveToDevice();
154+
}
155+
156+
private static object GetCommonFields()
157+
{
158+
var internetType = "unknown";
159+
if (Application.internetReachability == NetworkReachability.ReachableViaLocalAreaNetwork)
160+
{
161+
internetType = "wifi_or_cable";
162+
}
163+
else if (Application.internetReachability == NetworkReachability.ReachableViaCarrierDataNetwork)
164+
{
165+
internetType = "data_network";
166+
}
167+
168+
return new
169+
{
170+
171+
uuid = Guid.NewGuid().ToString(),
172+
timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss"),
173+
session_id = sessionId,
174+
offset = sessionOffset++,
175+
user_id = userId,
176+
build_version = env + ":" + buildVersion,
177+
internet_type = internetType,
178+
};
179+
}
180+
}
181+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using System;
2+
using System.Linq;
3+
using Newtonsoft.Json.Linq;
4+
5+
namespace Analytic
6+
{
7+
public class UserVertification
8+
{
9+
public static string GetArg(string name)
10+
{
11+
var args = System.Environment.GetCommandLineArgs();
12+
for (int i = 0; i < args.Length; i++)
13+
{
14+
if (args[i] == name && args.Length > i + 1)
15+
{
16+
return args[i + 1];
17+
}
18+
}
19+
return string.Empty;
20+
}
21+
22+
public static void GetArgVertification(out string signature, out string message)
23+
{
24+
signature = GetArg("-signature");
25+
message = GetArg("-message");
26+
}
27+
28+
private static byte[] StringToByteArray(string hex)
29+
{
30+
return Enumerable.Range(0, hex.Length)
31+
.Where(x => x % 2 == 0)
32+
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
33+
.ToArray();
34+
}
35+
36+
public static JObject Vertification(string signature, string message)
37+
{
38+
if (string.IsNullOrEmpty(message)) return null;
39+
40+
var messageData = StringToByteArray(message);
41+
var messageStr = System.Text.Encoding.UTF8.GetString(messageData);
42+
//var signatureData = StringToByteArray(signature);
43+
try
44+
{
45+
//This not support on dotnet20, so just skip verify at client side
46+
// var rsa = RSA.Create();
47+
// rsa.ImportRSAPublicKey(DecodeOpenSSLPublicKey(rsaPub), out var bytesRead);
48+
// UnityEngine.Debug.Log($"bytesRead: ${bytesRead}");
49+
50+
JObject userData = (JObject)Newtonsoft.Json.JsonConvert.DeserializeObject(messageStr);
51+
if (userData != null)
52+
{
53+
UnityEngine.Debug.Log($"MH user data: {Newtonsoft.Json.JsonConvert.SerializeObject(userData)}");
54+
return userData;
55+
}
56+
else
57+
{
58+
return null;
59+
}
60+
}
61+
catch (System.Exception ex)
62+
{
63+
UnityEngine.Debug.LogError(ex);
64+
return null;
65+
}
66+
}
67+
}
68+
}

Assets/AxieInfinity/Analytic/Core/UserVerification.cs.meta

+11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
File renamed without changes.

0 commit comments

Comments
 (0)