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