Decompiled source of StockPlus v1.0.0

StockPlus.dll

Decompiled 11 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
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 BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using HutongGames.PlayMaker.Actions;
using Mirror;
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("StockPlus")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("StockPlus")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("d42b6645-fb2e-40d8-a560-df5c5a8d2ccd")]
[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 StockPlus;

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 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);

	internal GASession(string modId, string modName, string modVersion, string measurementId, string screenTitle, string renewScreenTitle, bool sendSystemInfo, 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.sessionLengthMins = sessionLengthMins;
		if (isFirstRun())
		{
			SendUserGA("page_view", startingSession: true, "&_fv=1");
		}
		else
		{
			SendUserGA("page_view", startingSession: true, "");
		}
	}

	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_01dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_0201: Unknown result type (might be due to invalid IL or missing references)
		//IL_0206: Unknown result type (might be due to invalid IL or missing references)
		if (!StockPlusPlugin.telemetryEnabled.Value)
		{
			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 (isEngaged)
		{
			lastEng = DateTime.UtcNow;
		}
	}

	private void SendUserGA(string e, bool startingSession, string args)
	{
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00da: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
		if (StockPlusPlugin.telemetryEnabled.Value)
		{
			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));
		}
	}
}
[BepInPlugin("RB007.plugins.StockPlus", "StockPlus", "1.0.0")]
public class StockPlusPlugin : BaseUnityPlugin
{
	[HarmonyPatch(typeof(NetworkManager), "OnStartHost")]
	public static class OnHost
	{
		[HarmonyPostfix]
		public static void Postfix(NetworkManager __instance)
		{
			isHost = true;
			((MonoBehaviour)__instance).StartCoroutine(CheckStock());
		}

		private static IEnumerator CheckStock()
		{
			while (true)
			{
				yield return (object)new WaitForSeconds(checkInterval);
				if (isStocking.Value)
				{
					AddLowStock(buyToo: true);
				}
			}
		}
	}

	[HarmonyPatch(typeof(NetworkManager), "OnStartClient")]
	public static class OnClient
	{
		[HarmonyPostfix]
		public static void Postfix(NetworkManager __instance)
		{
		}
	}

	[HarmonyPatch(typeof(PlayerNetwork), "OnStartClient")]
	public static class CreateUI
	{
		[HarmonyPostfix]
		public static void Postfix(PlayerNetwork __instance)
		{
			ManagerBlackboard val = Object.FindFirstObjectByType<ManagerBlackboard>();
			if ((Object)(object)val == (Object)null)
			{
				Debug.LogWarning((object)"Failed to create StockPlus UI!");
			}
		}
	}

	[HarmonyPatch(typeof(ApplicationQuit), "OnEnter")]
	public static class QuitEvent
	{
		[HarmonyPostfix]
		public static void Prefix(ApplicationQuit __instance)
		{
			gaSession.sendGAEvent("state", "session_end", new Dictionary<string, string> { ["closed"] = "true" });
		}
	}

	private const string GUID = "RB007.plugins.StockPlus";

	private const string PluginName = "StockPlus";

	private const string VersionString = "1.0.0";

	internal static Harmony Harmony;

	internal static bool isHost = false;

	public static ConfigEntry<bool> isStocking;

	public static ConfigEntry<int> minStockThreshold;

	public static ConfigEntry<bool> telemetryEnabled;

	internal static float checkInterval = 20f;

	internal static GASession gaSession;

	private void Awake()
	{
		//IL_0067: Unknown result type (might be due to invalid IL or missing references)
		//IL_0071: Expected O, but got Unknown
		isStocking = ((BaseUnityPlugin)this).Config.Bind<bool>("Settings", "Auto Stocking Enabled", true, "Any available items (when they are fewer than the threshold below) will be purchased automatically.");
		minStockThreshold = ((BaseUnityPlugin)this).Config.Bind<int>("Settings", "Minimum Stock Threshold", 16, "When there are fewer of each item (than this value) available, they will be added to the shopping list (and purchased).");
		telemetryEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Misc", "Enable Telemetry", true, "Help me improve this mod by sending logs of small mod/game events.");
		Harmony = new Harmony("RB007.plugins.StockPlus");
		Harmony.PatchAll();
		gaSession = new GASession("RB007.plugins.StockPlus", "StockPlus", "1.0.0", "G-0BREKNCPF9", "MainMenu", "InGame", sendSystemInfo: true, 30);
		Debug.Log((object)"Loaded StockPlus successfully!");
	}

	public static void AddLowStock(bool buyToo)
	{
		ManagerBlackboard val = Object.FindFirstObjectByType<ManagerBlackboard>();
		ProductListing val2 = Object.FindFirstObjectByType<ProductListing>();
		if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
		{
			Debug.LogWarning((object)"Failed to add low stock to shopping list!");
			return;
		}
		FieldInfo field = typeof(ManagerBlackboard).GetField("isSpawning", BindingFlags.Instance | BindingFlags.NonPublic);
		if (field != null)
		{
			bool flag = (bool)field.GetValue(val);
			if (flag && buyToo)
			{
				return;
			}
		}
		int num = 0;
		int num2 = 0;
		float num3 = 0f;
		foreach (int availableProduct in val2.availableProducts)
		{
			Data_Product component = val2.productPrefabs[availableProduct].GetComponent<Data_Product>();
			if ((Object)(object)component == (Object)null || !val2.unlockedProductTiers[component.productTier])
			{
				return;
			}
			MethodInfo method = typeof(ManagerBlackboard).GetMethod("GetProductsExistences", BindingFlags.Instance | BindingFlags.NonPublic);
			if (method != null)
			{
				int[] source = (int[])method.Invoke(val, new object[1] { availableProduct });
				if (source.Sum() < minStockThreshold.Value)
				{
					float num4 = component.basePricePerUnit * val2.tierInflation[component.productTier];
					num4 *= (float)component.maxItemsPerBox;
					num4 = Mathf.Round(num4 * 100f) / 100f;
					val.AddShoppingListProduct(availableProduct, num4);
					num++;
					num2 += component.maxItemsPerBox;
					num3 += num4;
				}
			}
		}
		if (buyToo && val.shoppingTotalCharge > 0f)
		{
			BuyStock();
		}
		if (num > 0)
		{
			gaSession.sendGAEvent("game", "restock", new Dictionary<string, string>
			{
				["boxes"] = num.ToString(),
				["items"] = num2.ToString(),
				["cost"] = num3.ToString(),
				["buy"] = buyToo.ToString()
			});
		}
		else
		{
			gaSession.sendGAEvent("game", "scan", new Dictionary<string, string>
			{
				["threshold"] = minStockThreshold.Value.ToString(),
				["buy"] = buyToo.ToString()
			});
		}
	}

	public static void BuyStock()
	{
		ManagerBlackboard val = Object.FindFirstObjectByType<ManagerBlackboard>();
		if ((Object)(object)val == (Object)null)
		{
			Debug.LogWarning((object)"Failed to buy shopping list!");
		}
		else
		{
			val.BuyCargo();
		}
	}
}