Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of LethalAnalytics v1.0.1
LethalAnalytics.dll
Decompiled 2 years agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Net; using System.Net.Http; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text.RegularExpressions; using System.Threading; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using LethalConfig; using LethalConfig.ConfigItems; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("LethalAnalytics")] [assembly: AssemblyDescription("Allows mod creators to see how their mods are used, easily catch errors, and learn about their audience.")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("LethalAnalytics")] [assembly: AssemblyCopyright("Copyright © RoosterBooster007 2024")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("34f2d91f-5d5e-4278-bc2d-b5f62637a5d1")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("1.0.0.0")] namespace LethalAnalytics; public static class AnalyticsManager { public static bool telemetricsEnabled => (bool)((ConfigEntryBase)LethalAnalytics.enableTele).BoxedValue; public static GASession registerGASession(string modId, string modName, string modVersion, string modDesc, string measurementId, string screenTitle = "MainMenu", string renewScreenTitle = "InGame", bool sendSystemInfo = true, int sessionLengthMins = 30) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown modName = Regex.Replace(modName, "[^A-Za-z0-9 ]", ""); modName = modName.Trim(); ConfigEntry<bool> val = LethalAnalytics.configFile.Bind<bool>("Mods", modName, true, modDesc + "\n\n[Important: This entry indicates whether a mod receives analytics updates. Consult the description above.]"); BoolCheckBoxConfigItem val2 = new BoolCheckBoxConfigItem(val, false); LethalConfigManager.AddConfigItem((BaseConfigItem)(object)val2); GASession result = new GASession(modId, modName, modVersion, measurementId, screenTitle, renewScreenTitle, sendSystemInfo, val, sessionLengthMins); LethalAnalytics.mls.LogInfo((object)(modName + " v" + modVersion + " successfully registered a GA property!")); return result; } } public class GASession { private string modId; private string modName; private string modVersion; private string measurementId; private string screenTitle; private string renewScreenTitle; private bool sendSystemInfo; private ConfigEntry<bool> enableTele; private int sessionLengthMins; private HttpClient HTTPclient = new HttpClient(); private DateTimeOffset sessionStartTime = DateTimeOffset.UtcNow; private DateTimeOffset lastEng = DateTimeOffset.UtcNow; private int GAHitCount = 1; private int GASessionCount = 1; private string GASessionID = Regex.Replace(Guid.NewGuid().ToString(), "[^\\d]", "").Substring(0, 10); public bool telemetricsEnabled => (bool)((ConfigEntryBase)enableTele).BoxedValue; internal GASession(string modId, string modName, string modVersion, string measurementId, string screenTitle, string renewScreenTitle, bool sendSystemInfo, ConfigEntry<bool> enableTele, int sessionLengthMins) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown this.modId = modId; this.modName = modName; this.modVersion = modVersion; this.measurementId = measurementId; this.screenTitle = screenTitle; this.renewScreenTitle = renewScreenTitle; this.sendSystemInfo = sendSystemInfo; this.enableTele = enableTele; this.sessionLengthMins = sessionLengthMins; Patches.mainMenuLaunched += OnMenuLaunch; Patches.userClosingLC += OnLCClosing; if (isFirstRun()) { SendUserGA("page_view", startingSession: true, "&_fv=1"); } else { SendUserGA("page_view", startingSession: true, ""); } } private void OnLCClosing(object sender, EventArgs e) { sendGAEvent("state", "session_end", new Dictionary<string, string> { ["closed"] = "true" }); } private void OnMenuLaunch(object sender, EventArgs e) { if (recentlyUpdated()) { sendGAEvent("state", "update", new Dictionary<string, string> { ["version"] = modVersion }); } } private static string getSystemArch() { if (Environment.Is64BitProcess) { return "x86_64"; } return "x86"; } private static string getSystemBits() { if (Environment.Is64BitProcess) { return "64"; } return "32"; } private bool isFirstRun() { if (!PlayerPrefs.HasKey(modId + ".newUser")) { PlayerPrefs.SetInt(modId + ".newUser", 1); PlayerPrefs.Save(); return true; } return false; } private bool recentlyUpdated() { if (PlayerPrefs.GetString(modId + ".v") != modVersion) { PlayerPrefs.SetString(modId + ".v", modVersion); PlayerPrefs.Save(); return true; } return false; } private void startNewGASession() { GASessionCount++; GASessionID = Regex.Replace(Guid.NewGuid().ToString(), "[^\\d]", "").Substring(0, 10); sessionStartTime = DateTimeOffset.UtcNow; lastEng = DateTime.UtcNow; GAHitCount = 1; SendUserGA("page_view", startingSession: false, ""); } public void sendGAEvent(string event_category, string event_name, Dictionary<string, string> event_params, bool isEngaged = true) { //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0220: Unknown result type (might be due to invalid IL or missing references) if (!(bool)((ConfigEntryBase)LethalAnalytics.enableTele).BoxedValue || !(bool)((ConfigEntryBase)enableTele).BoxedValue) { return; } if ((DateTime.UtcNow - lastEng).TotalMinutes >= (double)sessionLengthMins) { startNewGASession(); } event_name = WebUtility.UrlEncode(event_name); event_category = WebUtility.UrlEncode(event_category); string text = ""; foreach (KeyValuePair<string, string> event_param in event_params) { text = ((!int.TryParse(event_param.Value, out var result)) ? (text + "&ep." + WebUtility.UrlEncode(event_param.Key) + "=" + WebUtility.UrlEncode(event_param.Value)) : (text + "&epn." + WebUtility.UrlEncode(event_param.Key) + "=" + result)); } string text2 = ""; if (isEngaged) { text2 = text2 + "&_et = " + (long)Math.Floor((DateTime.UtcNow - lastEng).TotalMilliseconds); } GAHitCount++; HttpClient hTTPclient = HTTPclient; string[] obj = new string[31] { "https://www.google-analytics.com/g/collect?v=2&tid=", measurementId, "&cid=", SystemInfo.deviceUniqueIdentifier, "&sid=", GASessionID, "&ul=", CultureInfo.CurrentCulture.Name, "&sr=", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null }; Resolution currentResolution = Screen.currentResolution; obj[9] = ((Resolution)(ref currentResolution)).width.ToString(); obj[10] = "x"; currentResolution = Screen.currentResolution; obj[11] = ((Resolution)(ref currentResolution)).height.ToString(); obj[12] = "&uap="; obj[13] = WebUtility.UrlEncode(Environment.OSVersion.Platform.ToString()); obj[14] = "&uam="; obj[15] = WebUtility.UrlEncode(Application.version); obj[16] = "&uapv="; obj[17] = WebUtility.UrlEncode(modVersion); obj[18] = "&en="; obj[19] = event_name; obj[20] = "&ep.category="; obj[21] = event_category; obj[22] = text; obj[23] = text2; obj[24] = "&tfd="; obj[25] = ((long)Math.Floor((DateTime.UtcNow - sessionStartTime).TotalMilliseconds)).ToString(); obj[26] = "&uamb=0&uaw=0&pscdl=noapi&_s="; obj[27] = GAHitCount.ToString(); obj[28] = "&sct="; obj[29] = GASessionCount.ToString(); obj[30] = "&seg=1&_ee=1&npa=0&dma=0&frm=0&are=1"; hTTPclient.GetAsync(string.Concat(obj)); if (!LethalAnalytics.recentModList.Contains(modName)) { LethalAnalytics.recentModList.Add(modName); } LethalAnalytics.totalEventsSent++; if (isEngaged) { lastEng = DateTime.UtcNow; } } private void SendUserGA(string e, bool startingSession, string args) { //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) if ((bool)((ConfigEntryBase)LethalAnalytics.enableTele).BoxedValue && (bool)((ConfigEntryBase)enableTele).BoxedValue) { string text = ""; string text2 = ""; if (sendSystemInfo) { text = text + "&ep.cpu=" + SystemInfo.processorType + "&ep.gpu=" + SystemInfo.graphicsDeviceName; } text2 = ((!startingSession) ? renewScreenTitle : screenTitle); HttpClient hTTPclient = HTTPclient; string[] obj = new string[33] { "https://www.google-analytics.com/g/collect?v=2&tid=", measurementId, "&cid=", SystemInfo.deviceUniqueIdentifier, "&sid=", GASessionID, "&ul=", CultureInfo.CurrentCulture.Name, "&sr=", null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null }; Resolution currentResolution = Screen.currentResolution; obj[9] = ((Resolution)(ref currentResolution)).width.ToString(); obj[10] = "x"; currentResolution = Screen.currentResolution; obj[11] = ((Resolution)(ref currentResolution)).height.ToString(); obj[12] = "&uap="; obj[13] = WebUtility.UrlEncode(Environment.OSVersion.Platform.ToString()); obj[14] = "&uam="; obj[15] = WebUtility.UrlEncode(Application.version); obj[16] = "&uapv="; obj[17] = WebUtility.UrlEncode(modVersion); obj[18] = "&en="; obj[19] = e; obj[20] = text; obj[21] = "&tfd="; obj[22] = ((long)Math.Floor((DateTime.UtcNow - sessionStartTime).TotalMilliseconds)).ToString(); obj[23] = "&uaa="; obj[24] = getSystemArch(); obj[25] = "&uab="; obj[26] = getSystemBits(); obj[27] = "&uamb=0&uaw=0&dt="; obj[28] = WebUtility.UrlEncode(text2 + " (v" + modVersion + ")"); obj[29] = "&are=1&frm=0&pscdl=noapi&seg=1&npa=0&_s=1&sct="; obj[30] = GASessionCount.ToString(); obj[31] = "&dma=0&_ss=1&_nsi=1&_ee=1"; obj[32] = args; hTTPclient.GetAsync(string.Concat(obj)); if (!LethalAnalytics.recentModList.Contains(modName)) { LethalAnalytics.recentModList.Add(modName); } LethalAnalytics.totalEventsSent++; } } } internal class Patches { [HarmonyPatch(typeof(MenuManager))] internal class MenuPatch { [HarmonyPatch("Awake")] [HarmonyPostfix] public static void patchUpdateEvent() { Patches.mainMenuLaunched?.Invoke(null, EventArgs.Empty); } } [HarmonyPatch(typeof(QuickMenuManager))] public class QMenuPatch { [HarmonyPatch("OpenQuickMenu")] [HarmonyPostfix] public static void patchOpen() { Patches.quickMenuOpened?.Invoke(null, EventArgs.Empty); } } [HarmonyPatch(typeof(GameNetworkManager))] public class LeavePatch { [HarmonyPatch("OnDisable")] [HarmonyPrefix] public static void patchQuit() { Patches.userClosingLC?.Invoke(null, EventArgs.Empty); } } internal static event EventHandler mainMenuLaunched; internal static event EventHandler quickMenuOpened; internal static event EventHandler userClosingLC; } [BepInPlugin("net.RB007.LethalAnalytics", "LethalAnalytics", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class LethalAnalytics : BaseUnityPlugin { private const string modGUID = "net.RB007.LethalAnalytics"; private const string modName = "LethalAnalytics"; private const string modVersion = "1.0.0"; private readonly Harmony harmony = new Harmony("net.RB007.LethalAnalytics"); internal static ManualLogSource mls; internal static int totalEventsSent = 0; internal static int prevTotalEventsSent = 0; internal static List<string> recentModList = new List<string>(); internal Timer _timer; internal static ConfigEntry<bool> enableTele; internal static ConfigEntry<int> eventsSent; internal static ConfigFile configFile; internal static GASession gaSession; private void Awake() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Expected O, but got Unknown mls = Logger.CreateLogSource("net.RB007.LethalAnalytics"); mls.LogInfo((object)"LethalAnalytics is enabling..."); mls.LogInfo((object)"Reading config..."); enableTele = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable telemetry", true, "When enabled, some anonymous user data/input actions may be uploaded to various analytics sites. This helps mod creators understand what features are used the most and what they can improve. :) \n\nCheck each mod listed below to see what data is collected.\n\nSupported analytics sites:\n - Google Analytics"); BoolCheckBoxConfigItem val = new BoolCheckBoxConfigItem(enableTele, false); LethalConfigManager.AddConfigItem((BaseConfigItem)(object)val); eventsSent = ((BaseUnityPlugin)this).Config.Bind<int>("Info", "Events sent this session", totalEventsSent, "[Read-only] This shows how many total analytics events have been sent, via the plugins listed below, while you've been online."); IntInputFieldConfigItem val2 = new IntInputFieldConfigItem(eventsSent, false); LethalConfigManager.AddConfigItem((BaseConfigItem)(object)val2); configFile = ((BaseUnityPlugin)this).Config; mls.LogInfo((object)"Config loaded!"); mls.LogInfo((object)"Patching game..."); harmony.PatchAll(); mls.LogInfo((object)"Patched all!"); Patches.quickMenuOpened += OnQMenuOpen; gaSession = new GASession("net.RB007.LethalAnalytics", "LethalAnalytics", "1.0.0", "G-KQFXJ36ZK6", "MainMenu", "InGame", sendSystemInfo: true, enableTele, 30); _timer = new Timer(SentEventsInfo, null, TimeSpan.FromMinutes(3.0), TimeSpan.FromMinutes(3.0)); mls.LogInfo((object)("LethalAnalytics started! CID: " + SystemInfo.deviceUniqueIdentifier)); } private void SentEventsInfo(object state) { string text = ""; foreach (string recentMod in recentModList) { text = text + recentMod + ","; } gaSession.sendGAEvent("event", "sent_events", new Dictionary<string, string> { ["events_count"] = (totalEventsSent - prevTotalEventsSent).ToString(), ["mods_count"] = recentModList.Count.ToString(), ["mods_list"] = text }); prevTotalEventsSent = totalEventsSent; } private void OnQMenuOpen(object sender, EventArgs e) { ((ConfigEntryBase)eventsSent).BoxedValue = totalEventsSent; gaSession.sendGAEvent("event", "menu_open", new Dictionary<string, string>()); } }