Decompiled source of LethalSkins v1.0.3

LethalSkins.dll

Decompiled 10 months ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using LC_API.ClientAPI;
using LC_API.GameInterfaceAPI;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("LethalSkins")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("My first plugin")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("LethalSkins")]
[assembly: AssemblyTitle("LethalSkins")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace LethalSkins
{
	[BepInPlugin("io.patrickdundas.LethalSkins", "LethalSkins", "1.0.2")]
	public class Plugin : BaseUnityPlugin
	{
		private const string modGUID = "io.patrickdundas.LethalSkins";

		private const string modName = "LethalSkins";

		private const string modVersion = "1.0.2";

		private const string baseURL = "https://main-gkvbkt6upa-uc.a.run.app";

		public static ConfigEntry<string> skinPartyCode;

		private string skinDir;

		private void Awake()
		{
			((BaseUnityPlugin)this).Config.SaveOnConfigSet = true;
			CommandHandler.RegisterCommand("syncskins", (Action<string[]>)SyncCommandHandler);
			CommandHandler.RegisterCommand("pluginlist", (Action<string[]>)PluginCommandHandler);
			skinDir = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) + "\\moresuits";
			skinPartyCode = ((BaseUnityPlugin)this).Config.Bind<string>("SkinPartyCode", "Skin Party Code to Sync Skins", "xxxxxx", (ConfigDescription)null);
			((BaseUnityPlugin)this).Logger.LogInfo((object)("Plugin LethalSkins is loaded with SkinPartyCode " + skinPartyCode.Value));
			DetectOrCreateSkinDir();
			SyncSkins(skinPartyCode.Value, inGame: false);
			foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
			{
				string key = pluginInfo.Key;
				string name = pluginInfo.Value.Metadata.Name;
				Console.WriteLine("Plugin GUID: " + key + ", Name: " + name);
			}
		}

		private void PluginCommandHandler(string[] args)
		{
			foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos)
			{
				string key = pluginInfo.Key;
				string name = pluginInfo.Value.Metadata.Name;
				Console.WriteLine("Plugin GUID: " + key + ", Name: " + name);
			}
		}

		private void SyncCommandHandler(string[] args)
		{
			if (args.Length == 0)
			{
				Console.WriteLine("Re-syncing with saved party code " + skinPartyCode.Value);
				SyncSkins(skinPartyCode.Value, inGame: true);
			}
			else
			{
				Console.WriteLine("Setting new party code: " + args[0]);
				((ConfigEntryBase)skinPartyCode).SetSerializedValue(args[0]);
				SyncSkins(args[0], inGame: true);
			}
		}

		public static async Task<string[]> GetPartyManifest(string skinPartyCode)
		{
			string url = "https://main-gkvbkt6upa-uc.a.run.app/steam-api/party/" + skinPartyCode + "/skins/list";
			HttpClient client = new HttpClient();
			try
			{
				((HttpHeaders)client.DefaultRequestHeaders).Add("User-Agent", "LethalSkins/1.0.2");
				HttpResponseMessage response = await client.GetAsync(url);
				if (response.IsSuccessStatusCode)
				{
					return JsonConvert.DeserializeObject<List<string>>(await response.Content.ReadAsStringAsync()).ToArray();
				}
				Console.WriteLine($"GetPartyManifest Error HTTP {response.StatusCode}");
				throw new HttpRequestException($"Error: {response.StatusCode}");
			}
			finally
			{
				((IDisposable)client)?.Dispose();
			}
		}

		public static async Task<string[]> GetDownloadUrls(string skinPartyCode, string[] skins)
		{
			string url = "https://main-gkvbkt6upa-uc.a.run.app/steam-api/party/" + skinPartyCode + "/skins/getDownloadUrls?skins=" + string.Join(",", skins);
			HttpClient client = new HttpClient();
			try
			{
				((HttpHeaders)client.DefaultRequestHeaders).Add("User-Agent", "LethalSkins/1.0.2");
				HttpResponseMessage response = await client.GetAsync(url);
				if (response.IsSuccessStatusCode)
				{
					return JsonConvert.DeserializeObject<List<string>>(await response.Content.ReadAsStringAsync()).ToArray();
				}
				Console.WriteLine($"GetDownloadUrls Error HTTP {response.StatusCode}");
				throw new HttpRequestException($"Error: {response.StatusCode}");
			}
			finally
			{
				((IDisposable)client)?.Dispose();
			}
		}

		private async void SyncSkins(string skinPartyCode, bool inGame)
		{
			string[] manifest = await GetPartyManifest(skinPartyCode);
			Console.WriteLine("Got Manifest: " + string.Join(",", manifest));
			if (manifest.Length != 0)
			{
				string[] existing = GetExistingSkins(skinDir);
				Console.WriteLine("Current Files: " + string.Join(",", existing));
				string[] toDownload = manifest.Except(existing).ToArray();
				string[] toDelete = existing.Except(manifest).ToArray();
				Console.WriteLine("Deleting: " + string.Join(",", toDelete));
				Console.WriteLine("Downloading: " + string.Join(",", toDownload));
				if (toDownload.Length != 0)
				{
					if (inGame)
					{
						GameTips.ShowTip("Syncing", $"Downloading {toDownload.Length} Skins, Please Wait.");
					}
					string[] array = await GetDownloadUrls(skinPartyCode, toDownload);
					foreach (string url in array)
					{
						Console.WriteLine("Downloading skin");
						await DownloadFile(url, string.Concat(str2: ExtractFilename(url), str0: skinDir, str1: "\\", str3: ".png"));
					}
					if (inGame)
					{
						GameTips.ShowTip("Skins Synced", "Restart your game now to see the new skins");
					}
				}
				else if (inGame)
				{
					GameTips.ShowTip("Already Synced", "No skins to download");
				}
				string[] array2 = toDelete;
				for (int j = 0; j < array2.Length; j++)
				{
					string filePath = string.Concat(str2: array2[j], str0: skinDir, str1: "\\", str3: ".png");
					Console.WriteLine("Processing delete: " + filePath);
					try
					{
						if (File.Exists(filePath))
						{
							File.Delete(filePath);
						}
					}
					catch (IOException ioExp)
					{
						Console.WriteLine("An IO exception occurred: " + ioExp.Message);
					}
					catch (Exception exp)
					{
						Console.WriteLine("An exception occurred: " + exp.Message);
					}
				}
			}
			else
			{
				Console.WriteLine("Empty Manifest! Party empty or doesnt exist");
				if (inGame)
				{
					GameTips.ShowTip("Sync Error", "The party doesn't exist or has no uploaded skins");
				}
			}
		}

		private static string ExtractFilename(string input)
		{
			string pattern = "/(?<name>[^/]+)\\.png";
			foreach (Match item in Regex.Matches(input, pattern, RegexOptions.IgnoreCase))
			{
				if (item.Success)
				{
					return item.Groups["name"].Value;
				}
			}
			return "";
		}

		private static string[] GetExistingSkins(string directoryPath)
		{
			if (Directory.Exists(directoryPath))
			{
				string[] files = Directory.GetFiles(directoryPath);
				string[] array = files.Select((string path) => Path.GetFileName(path)).ToArray();
				List<string> list = new List<string>();
				string[] array2 = array;
				foreach (string text in array2)
				{
					if (text.Contains(".png") || text.Contains(".PNG"))
					{
						Console.WriteLine("Found file " + text);
						list.Add(text.Replace(".PNG", "").Replace(".png", ""));
					}
				}
				return list.ToArray();
			}
			return new string[1] { "Directory does not exist." };
		}

		private void DetectOrCreateSkinDir()
		{
			if (!Directory.Exists(skinDir))
			{
				Directory.CreateDirectory(skinDir);
				Console.WriteLine("Skin Directory created: " + skinDir);
			}
			else
			{
				Console.WriteLine("Skin Directory found: " + skinDir);
			}
			FileStream fileStream = File.Create(skinDir + "\\!less-suits.txt");
		}

		public static async Task DownloadFile(string fileUrl, string localPath)
		{
			HttpClient client = new HttpClient();
			try
			{
				HttpResponseMessage response = await client.GetAsync(fileUrl, (HttpCompletionOption)1);
				try
				{
					response.EnsureSuccessStatusCode();
					using Stream contentStream = await response.Content.ReadAsStreamAsync();
					using Stream fileStream = new FileStream(localPath, FileMode.Create, FileAccess.Write, FileShare.None);
					await contentStream.CopyToAsync(fileStream);
				}
				finally
				{
					((IDisposable)response)?.Dispose();
				}
				Console.WriteLine("File downloaded successfully to " + localPath);
			}
			catch (Exception ex)
			{
				Exception e = ex;
				Console.WriteLine("Error occurred while downloading the file: " + e.Message);
			}
			finally
			{
				((IDisposable)client)?.Dispose();
			}
		}
	}
}