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 LethalSkins v1.0.3
LethalSkins.dll
Decompiled 2 years agousing 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(); } } } }