Decompiled source of LethalAnalytics v1.0.1

LethalAnalytics.dll

Decompiled 6 months ago
using 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>());
	}
}