Decompiled source of Discord Screenshots v1.4.0

discordScreenshots.1.4.0.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Extensions;
using Jotunn.Utils;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
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("discordScreenshots")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("discordScreenshots")]
[assembly: AssemblyCopyright("Copyright ©  2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("CA695DDD-2CE8-407B-B7A2-9FB6D3783286")]
[assembly: AssemblyFileVersion("0.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = "")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
[HarmonyPatch(typeof(Player), "OnDamaged")]
public static class RemoveDamageFlashOnDeath
{
	[HarmonyPostfix]
	private static bool Prefix(Player __instance, HitData hit)
	{
		if (hit.GetTotalDamage() >= ((Character)__instance).GetHealth())
		{
			return false;
		}
		return true;
	}
}
namespace discordScreenshots
{
	public class BepinexConfiguration
	{
		public static ConfigFile Config;

		public static ConfigEntry<string> WebhookURL;

		public static ConfigEntry<string> WebhookUsername;

		public static ConfigEntry<string> WebhookAvatarURL;

		public static ConfigEntry<string> DeathMessage;

		public static ConfigEntry<KeyCode> ScreenshotHotkey;

		public static void GenerateConfigs(ConfigFile configFile)
		{
			Config = configFile;
			ScreenshotHotkey = ConfigFileExtensions.BindConfig<KeyCode>(Config, "Screenshot", "Hotkey", (KeyCode)293, "The hotkey to take a screenshot and send to Discord.", false, (int?)1, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			WebhookURL = ConfigFileExtensions.BindConfig<string>(Config, "Webhook", "URL", "", "The URL of the Discord webhook to send messages to.", true, (int?)2, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			WebhookUsername = ConfigFileExtensions.BindConfig<string>(Config, "Webhook", "Username", "Valheim Death Bot", "The username of the Discord webhook to send messages to.", true, (int?)3, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			WebhookAvatarURL = ConfigFileExtensions.BindConfig<string>(Config, "Webhook", "AvatarURL", "", "The avatar URL of the Discord webhook to send messages to.", true, (int?)4, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
			DeathMessage = ConfigFileExtensions.BindConfig<string>(Config, "Death Screenshot", "Message", "met their demise! Final moments captured...", "The message to send with death screenshots (player name will be prepended automatically).", true, (int?)5, (AcceptableValueBase)null, (Action<ConfigEntryBase>)null, (ConfigurationManagerAttributes)null);
		}
	}
	public class SimpleDiscordWebhook
	{
		private readonly string _webhookUrl;

		private readonly string? _username;

		private readonly string? _avatarUrl;

		public SimpleDiscordWebhook(string webhookUrl, string? username = null, string? avatarUrl = null)
		{
			if (string.IsNullOrEmpty(webhookUrl))
			{
				throw new ArgumentException("Webhook URL cannot be null or empty", "webhookUrl");
			}
			_webhookUrl = webhookUrl;
			_username = username;
			_avatarUrl = avatarUrl;
		}

		public async Task SendMessageAsync(string message)
		{
			if (string.IsNullOrEmpty(message))
			{
				throw new ArgumentException("Message cannot be null or empty", "message");
			}
			SimpleWebhookPayload payload = new SimpleWebhookPayload
			{
				content = message,
				username = _username,
				avatar_url = _avatarUrl
			};
			string jsonPayload = JsonConvert.SerializeObject((object)payload);
			await SendPayloadAsync(jsonPayload);
		}

		public void SendMessage(string message)
		{
			SendMessageAsync(message).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult();
		}

		public async Task SendScreenshotAsync(string? message = null, string? filename = null)
		{
			string filename2 = filename;
			string message2 = message;
			try
			{
				if (string.IsNullOrEmpty(filename2))
				{
					filename2 = $"valheim_screenshot_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.png";
				}
				else if (!filename2.EndsWith(".png"))
				{
					filename2 += ".png";
				}
				Texture2D screenshot = ScreenCapture.CaptureScreenshotAsTexture();
				if ((Object)(object)screenshot == (Object)null)
				{
					throw new Exception("Failed to capture screenshot - returned null texture");
				}
				byte[] pngData = ImageConversion.EncodeToPNG(screenshot);
				Object.DestroyImmediate((Object)(object)screenshot);
				if (pngData == null || pngData.Length == 0)
				{
					throw new Exception("Failed to encode screenshot to PNG");
				}
				Debug.Log((object)$"Screenshot captured and encoded - {pngData.Length} bytes, uploading...");
				await Task.Run(async delegate
				{
					await SendFileAsync(pngData, filename2, message2);
				});
			}
			catch (Exception ex2)
			{
				Exception ex = ex2;
				throw new Exception("Error capturing and sending screenshot: " + ex.Message, ex);
			}
		}

		public Texture2D CaptureScreenshot()
		{
			Texture2D val = ScreenCapture.CaptureScreenshotAsTexture();
			if ((Object)(object)val == (Object)null)
			{
				throw new Exception("Failed to capture screenshot - returned null texture");
			}
			return val;
		}

		public byte[] ProcessScreenshot(Texture2D screenshot)
		{
			byte[] result = ImageConversion.EncodeToPNG(screenshot);
			Object.DestroyImmediate((Object)(object)screenshot);
			return result;
		}

		public async Task SendFileAsync(byte[] fileData, string filename, string? message = null)
		{
			if (fileData == null || fileData.Length == 0)
			{
				throw new ArgumentException("File data cannot be null or empty", "fileData");
			}
			if (string.IsNullOrEmpty(filename))
			{
				throw new ArgumentException("Filename cannot be null or empty", "filename");
			}
			string boundary = "----formdata-discord-" + DateTime.Now.Ticks.ToString("x");
			using MemoryStream memoryStream = new MemoryStream();
			await WriteMultipartFormDataAsync(memoryStream, boundary, fileData, filename, message);
			byte[] formData = memoryStream.ToArray();
			await SendMultipartPayloadAsync(formData, boundary);
		}

		private async Task SendPayloadAsync(string jsonPayload)
		{
			try
			{
				byte[] byteArray = Encoding.UTF8.GetBytes(jsonPayload);
				WebRequest request = WebRequest.Create(_webhookUrl);
				request.Method = "POST";
				request.ContentType = "application/json";
				request.ContentLength = byteArray.Length;
				using (Stream dataStream = request.GetRequestStream())
				{
					await dataStream.WriteAsync(byteArray, 0, byteArray.Length);
				}
				using WebResponse response = request.GetResponse();
				if (response is HttpWebResponse httpResponse && httpResponse.StatusCode != HttpStatusCode.NoContent && httpResponse.StatusCode != HttpStatusCode.OK)
				{
					throw new Exception($"Discord webhook returned status: {httpResponse.StatusCode}");
				}
				using Stream responseStream = response.GetResponseStream();
				if (responseStream == null)
				{
					return;
				}
				using StreamReader streamReader = new StreamReader(responseStream);
				string responseText = await streamReader.ReadToEndAsync();
				if (!string.IsNullOrEmpty(responseText))
				{
					Debug.Log((object)("Discord response: " + responseText));
				}
			}
			catch (WebException ex2)
			{
				string errorMessage = "Failed to send webhook message";
				WebResponse response2 = ex2.Response;
				if (response2 is HttpWebResponse errorResponse)
				{
					using Stream errorStream = errorResponse.GetResponseStream();
					if (errorStream != null)
					{
						using StreamReader reader = new StreamReader(errorStream);
						errorMessage += string.Format(arg1: await reader.ReadToEndAsync(), format: ": {0} - {1}", arg0: errorResponse.StatusCode);
					}
				}
				throw new Exception(errorMessage, ex2);
			}
			catch (Exception ex3)
			{
				Exception ex = ex3;
				throw new Exception("Error sending Discord webhook: " + ex.Message, ex);
			}
		}

		private async Task SendMultipartPayloadAsync(byte[] formData, string boundary)
		{
			try
			{
				WebRequest request = WebRequest.Create(_webhookUrl);
				request.Method = "POST";
				request.ContentType = "multipart/form-data; boundary=" + boundary;
				request.ContentLength = formData.Length;
				using (Stream dataStream = request.GetRequestStream())
				{
					await dataStream.WriteAsync(formData, 0, formData.Length);
				}
				using WebResponse response = request.GetResponse();
				if (response is HttpWebResponse httpResponse && httpResponse.StatusCode != HttpStatusCode.NoContent && httpResponse.StatusCode != HttpStatusCode.OK)
				{
					throw new Exception($"Discord webhook returned status: {httpResponse.StatusCode}");
				}
				using Stream responseStream = response.GetResponseStream();
				if (responseStream == null)
				{
					return;
				}
				using StreamReader streamReader = new StreamReader(responseStream);
				string responseText = await streamReader.ReadToEndAsync();
				if (!string.IsNullOrEmpty(responseText))
				{
					Debug.Log((object)("Discord file upload response: " + responseText));
				}
			}
			catch (WebException ex2)
			{
				string errorMessage = "Failed to send webhook file";
				WebResponse response2 = ex2.Response;
				if (response2 is HttpWebResponse errorResponse)
				{
					using Stream errorStream = errorResponse.GetResponseStream();
					if (errorStream != null)
					{
						using StreamReader reader = new StreamReader(errorStream);
						errorMessage += string.Format(arg1: await reader.ReadToEndAsync(), format: ": {0} - {1}", arg0: errorResponse.StatusCode);
					}
				}
				throw new Exception(errorMessage, ex2);
			}
			catch (Exception ex3)
			{
				Exception ex = ex3;
				throw new Exception("Error sending Discord webhook file: " + ex.Message, ex);
			}
		}

		private async Task WriteMultipartFormDataAsync(Stream stream, string boundary, byte[] fileData, string filename, string? message)
		{
			string newLine = "\r\n";
			byte[] boundaryBytes = Encoding.UTF8.GetBytes("--" + boundary + newLine);
			await stream.WriteAsync(boundaryBytes, 0, boundaryBytes.Length);
			string fileHeader = "Content-Disposition: form-data; name=\"files[0]\"; filename=\"" + filename + "\"" + newLine + "Content-Type: image/png" + newLine + newLine;
			byte[] fileHeaderBytes = Encoding.UTF8.GetBytes(fileHeader);
			await stream.WriteAsync(fileHeaderBytes, 0, fileHeaderBytes.Length);
			await stream.WriteAsync(fileData, 0, fileData.Length);
			byte[] newLineBytes = Encoding.UTF8.GetBytes(newLine);
			await stream.WriteAsync(newLineBytes, 0, newLineBytes.Length);
			if (!string.IsNullOrEmpty(message))
			{
				await stream.WriteAsync(boundaryBytes, 0, boundaryBytes.Length);
				SimpleWebhookPayload payload = new SimpleWebhookPayload
				{
					content = message,
					username = _username,
					avatar_url = _avatarUrl
				};
				string jsonPayload = JsonConvert.SerializeObject((object)payload);
				string jsonHeader = "Content-Disposition: form-data; name=\"payload_json\"" + newLine + "Content-Type: application/json" + newLine + newLine;
				byte[] jsonHeaderBytes = Encoding.UTF8.GetBytes(jsonHeader);
				await stream.WriteAsync(jsonHeaderBytes, 0, jsonHeaderBytes.Length);
				byte[] jsonBytes = Encoding.UTF8.GetBytes(jsonPayload);
				await stream.WriteAsync(jsonBytes, 0, jsonBytes.Length);
				await stream.WriteAsync(newLineBytes, 0, newLineBytes.Length);
			}
			byte[] closingBoundary = Encoding.UTF8.GetBytes("--" + boundary + "--" + newLine);
			await stream.WriteAsync(closingBoundary, 0, closingBoundary.Length);
		}

		public static async Task SendQuickMessageAsync(string webhookUrl, string message, string? username = null, string? avatarUrl = null)
		{
			SimpleDiscordWebhook webhook = new SimpleDiscordWebhook(webhookUrl, username, avatarUrl);
			await webhook.SendMessageAsync(message);
		}

		public static void SendQuickMessage(string webhookUrl, string message, string? username = null, string? avatarUrl = null)
		{
			SendQuickMessageAsync(webhookUrl, message, username, avatarUrl).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult();
		}

		public static async Task SendQuickScreenshotAsync(string webhookUrl, string? message = null, string? username = null, string? avatarUrl = null, string? filename = null)
		{
			SimpleDiscordWebhook webhook = new SimpleDiscordWebhook(webhookUrl, username, avatarUrl);
			await webhook.SendScreenshotAsync(message, filename);
		}

		public static void SendQuickScreenshot(string webhookUrl, string? message = null, string? username = null, string? avatarUrl = null, string? filename = null)
		{
			SendQuickScreenshotAsync(webhookUrl, message, username, avatarUrl, filename).ConfigureAwait(continueOnCapturedContext: false).GetAwaiter().GetResult();
		}
	}
	internal class SimpleWebhookPayload
	{
		public string? content { get; set; }

		public string? username { get; set; }

		public string? avatar_url { get; set; }
	}
	[BepInPlugin("warpalicious.discordScreenshots", "discordScreenshots", "1.4.0")]
	public class discordScreenshotsPlugin : BaseUnityPlugin
	{
		private const string ModName = "discordScreenshots";

		private const string ModVersion = "1.4.0";

		private const string Author = "warpalicious";

		private const string ModGUID = "warpalicious.discordScreenshots";

		private static string ConfigFileName = "warpalicious.discordScreenshots.cfg";

		private static string ConfigFileFullPath;

		private readonly Harmony HarmonyInstance = new Harmony("warpalicious.discordScreenshots");

		public static readonly ManualLogSource TemplateLogger;

		public static AssetBundle assetBundle;

		private DateTime _lastReloadTime;

		private const long RELOAD_DELAY = 10000000L;

		public void Awake()
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			HarmonyInstance.PatchAll(executingAssembly);
			SetupWatcher();
			BepinexConfiguration.GenerateConfigs(((BaseUnityPlugin)this).Config);
		}

		public static void LoadAssetBundle()
		{
			assetBundle = AssetUtils.LoadAssetBundleFromResources("discordscreenshots", Assembly.GetExecutingAssembly());
		}

		private void OnDestroy()
		{
			((BaseUnityPlugin)this).Config.Save();
		}

		private void SetupWatcher()
		{
			_lastReloadTime = DateTime.Now;
			FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName);
			fileSystemWatcher.Changed += ReadConfigValues;
			fileSystemWatcher.Created += ReadConfigValues;
			fileSystemWatcher.Renamed += ReadConfigValues;
			fileSystemWatcher.IncludeSubdirectories = true;
			fileSystemWatcher.EnableRaisingEvents = true;
		}

		private void ReadConfigValues(object sender, FileSystemEventArgs e)
		{
			DateTime now = DateTime.Now;
			long num = now.Ticks - _lastReloadTime.Ticks;
			if (File.Exists(ConfigFileFullPath) && num >= 10000000)
			{
				try
				{
					TemplateLogger.LogInfo((object)"Attempting to reload configuration...");
					((BaseUnityPlugin)this).Config.Reload();
					TemplateLogger.LogInfo((object)"Configuration reloaded successfully!");
				}
				catch
				{
					TemplateLogger.LogError((object)("There was an issue loading " + ConfigFileName));
					return;
				}
				_lastReloadTime = now;
				if ((Object)(object)ZNet.instance != (Object)null && !ZNet.instance.IsDedicated())
				{
					TemplateLogger.LogInfo((object)"Updating runtime configurations...");
				}
			}
		}

		static discordScreenshotsPlugin()
		{
			string configPath = Paths.ConfigPath;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName;
			TemplateLogger = Logger.CreateLogSource("discordScreenshots");
		}
	}
}
namespace discordScreenshots.Patches
{
	[HarmonyPatch(typeof(Terminal), "InitTerminal")]
	public static class DiscordConsoleCommandPatch
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__0_0;

			public static ConsoleEvent <>9__0_1;

			public static ConsoleEvent <>9__0_2;

			internal void <Postfix>b__0_0(ConsoleEventArgs args)
			{
				<>c__DisplayClass0_0 CS$<>8__locals0 = new <>c__DisplayClass0_0();
				if (args.Length < 2)
				{
					Terminal context = args.Context;
					if (context != null)
					{
						context.AddString("Usage: discord <message>");
					}
					Terminal context2 = args.Context;
					if (context2 != null)
					{
						context2.AddString("Example: discord Hello from Valheim!");
					}
					return;
				}
				CS$<>8__locals0.message = string.Join(" ", args.Args, 1, args.Args.Length - 1);
				if (string.IsNullOrWhiteSpace(CS$<>8__locals0.message))
				{
					Terminal context3 = args.Context;
					if (context3 != null)
					{
						context3.AddString("Message cannot be empty");
					}
					return;
				}
				CS$<>8__locals0.playerName = "Server";
				if ((Object)(object)Player.m_localPlayer != (Object)null && !string.IsNullOrEmpty(Player.m_localPlayer.GetPlayerName()))
				{
					CS$<>8__locals0.playerName = Player.m_localPlayer.GetPlayerName();
				}
				Terminal context4 = args.Context;
				if (context4 != null)
				{
					context4.AddString("Sending message to Discord...");
				}
				Task.Run(async delegate
				{
					try
					{
						string formattedMessage = "\ud83d\udcac **" + CS$<>8__locals0.playerName + "**: " + CS$<>8__locals0.message;
						await SimpleDiscordWebhook.SendQuickMessageAsync(BepinexConfiguration.WebhookURL.Value, formattedMessage, "Valheim Console");
						Debug.Log((object)("Discord message sent successfully: " + formattedMessage));
					}
					catch (Exception ex2)
					{
						Exception ex = ex2;
						Debug.LogError((object)("Failed to send Discord message: " + ex.Message));
					}
				});
			}

			internal void <Postfix>b__0_1(ConsoleEventArgs args)
			{
				<>c__DisplayClass0_1 CS$<>8__locals0 = new <>c__DisplayClass0_1();
				Terminal context = args.Context;
				if (context != null)
				{
					context.AddString("Testing Discord webhook connection...");
				}
				CS$<>8__locals0.playerName = "Server";
				if ((Object)(object)Player.m_localPlayer != (Object)null && !string.IsNullOrEmpty(Player.m_localPlayer.GetPlayerName()))
				{
					CS$<>8__locals0.playerName = Player.m_localPlayer.GetPlayerName();
				}
				Task.Run(async delegate
				{
					try
					{
						await SimpleDiscordWebhook.SendQuickMessageAsync(BepinexConfiguration.WebhookURL.Value, "\ud83e\uddea Discord webhook test from **" + CS$<>8__locals0.playerName + "** - Connection working!", "Valheim Test Bot");
						Debug.Log((object)"Discord webhook test message sent successfully!");
					}
					catch (Exception ex2)
					{
						Exception ex = ex2;
						Debug.LogError((object)("Discord webhook test failed: " + ex.Message));
					}
				});
			}

			internal void <Postfix>b__0_2(ConsoleEventArgs args)
			{
				<>c__DisplayClass0_2 <>c__DisplayClass0_ = new <>c__DisplayClass0_2
				{
					playerName = "Unknown Player"
				};
				if ((Object)(object)Player.m_localPlayer != (Object)null && !string.IsNullOrEmpty(Player.m_localPlayer.GetPlayerName()))
				{
					<>c__DisplayClass0_.playerName = Player.m_localPlayer.GetPlayerName();
				}
				<>c__DisplayClass0_.message = null;
				if (args.Length > 1)
				{
					<>c__DisplayClass0_.message = string.Join(" ", args.Args, 1, args.Args.Length - 1);
				}
				if (string.IsNullOrEmpty(<>c__DisplayClass0_.message))
				{
					<>c__DisplayClass0_.message = "\ud83d\udcf8 **" + <>c__DisplayClass0_.playerName + "** took a screenshot!";
				}
				Terminal context = args.Context;
				if (context != null)
				{
					context.AddString("Capturing screenshot...");
				}
				try
				{
					<>c__DisplayClass0_3 CS$<>8__locals0 = new <>c__DisplayClass0_3();
					CS$<>8__locals0.CS$<>8__locals1 = <>c__DisplayClass0_;
					CS$<>8__locals0.webhook = new SimpleDiscordWebhook(BepinexConfiguration.WebhookURL.Value, "Valheim Screenshots");
					CS$<>8__locals0.filename = $"{CS$<>8__locals0.CS$<>8__locals1.playerName}_screenshot_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.png";
					Texture2D val = ScreenCapture.CaptureScreenshotAsTexture();
					if ((Object)(object)val == (Object)null)
					{
						throw new Exception("Failed to capture screenshot");
					}
					CS$<>8__locals0.pngData = ImageConversion.EncodeToPNG(val);
					Object.DestroyImmediate((Object)(object)val);
					if (CS$<>8__locals0.pngData == null || CS$<>8__locals0.pngData.Length == 0)
					{
						throw new Exception("Failed to encode screenshot to PNG");
					}
					Terminal context2 = args.Context;
					if (context2 != null)
					{
						context2.AddString("Screenshot captured, uploading to Discord...");
					}
					Task.Run(async delegate
					{
						try
						{
							await CS$<>8__locals0.webhook.SendFileAsync(CS$<>8__locals0.pngData, CS$<>8__locals0.filename, CS$<>8__locals0.CS$<>8__locals1.message);
							Debug.Log((object)("Screenshot uploaded to Discord for " + CS$<>8__locals0.CS$<>8__locals1.playerName));
						}
						catch (Exception ex3)
						{
							Exception ex2 = ex3;
							Debug.LogError((object)("Failed to upload screenshot: " + ex2.Message));
						}
					});
				}
				catch (Exception ex)
				{
					Terminal context3 = args.Context;
					if (context3 != null)
					{
						context3.AddString("Error: " + ex.Message);
					}
					Debug.LogError((object)("Failed to capture screenshot: " + ex.Message));
				}
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass0_0
		{
			public string playerName;

			public string message;

			internal async Task <Postfix>b__3()
			{
				try
				{
					string formattedMessage = "\ud83d\udcac **" + playerName + "**: " + message;
					await SimpleDiscordWebhook.SendQuickMessageAsync(BepinexConfiguration.WebhookURL.Value, formattedMessage, "Valheim Console");
					Debug.Log((object)("Discord message sent successfully: " + formattedMessage));
				}
				catch (Exception ex2)
				{
					Exception ex = ex2;
					Debug.LogError((object)("Failed to send Discord message: " + ex.Message));
				}
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass0_1
		{
			public string playerName;

			internal async Task <Postfix>b__4()
			{
				try
				{
					await SimpleDiscordWebhook.SendQuickMessageAsync(BepinexConfiguration.WebhookURL.Value, "\ud83e\uddea Discord webhook test from **" + playerName + "** - Connection working!", "Valheim Test Bot");
					Debug.Log((object)"Discord webhook test message sent successfully!");
				}
				catch (Exception ex2)
				{
					Exception ex = ex2;
					Debug.LogError((object)("Discord webhook test failed: " + ex.Message));
				}
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass0_2
		{
			public string message;

			public string playerName;
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass0_3
		{
			public SimpleDiscordWebhook webhook;

			public byte[] pngData;

			public string filename;

			public <>c__DisplayClass0_2 CS$<>8__locals1;

			internal async Task <Postfix>b__5()
			{
				try
				{
					await webhook.SendFileAsync(pngData, filename, CS$<>8__locals1.message);
					Debug.Log((object)("Screenshot uploaded to Discord for " + CS$<>8__locals1.playerName));
				}
				catch (Exception ex2)
				{
					Exception ex = ex2;
					Debug.LogError((object)("Failed to upload screenshot: " + ex.Message));
				}
			}
		}

		[HarmonyPostfix]
		private static void Postfix()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Unknown result type (might be due to invalid IL or missing references)
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Expected O, but got Unknown
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Expected O, but got Unknown
			object obj = <>c.<>9__0_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					if (args.Length < 2)
					{
						Terminal context5 = args.Context;
						if (context5 != null)
						{
							context5.AddString("Usage: discord <message>");
						}
						Terminal context6 = args.Context;
						if (context6 != null)
						{
							context6.AddString("Example: discord Hello from Valheim!");
						}
					}
					else
					{
						string message2 = string.Join(" ", args.Args, 1, args.Args.Length - 1);
						if (string.IsNullOrWhiteSpace(message2))
						{
							Terminal context7 = args.Context;
							if (context7 != null)
							{
								context7.AddString("Message cannot be empty");
							}
						}
						else
						{
							string playerName3 = "Server";
							if ((Object)(object)Player.m_localPlayer != (Object)null && !string.IsNullOrEmpty(Player.m_localPlayer.GetPlayerName()))
							{
								playerName3 = Player.m_localPlayer.GetPlayerName();
							}
							Terminal context8 = args.Context;
							if (context8 != null)
							{
								context8.AddString("Sending message to Discord...");
							}
							Task.Run(async delegate
							{
								try
								{
									string formattedMessage = "\ud83d\udcac **" + playerName3 + "**: " + message2;
									await SimpleDiscordWebhook.SendQuickMessageAsync(BepinexConfiguration.WebhookURL.Value, formattedMessage, "Valheim Console");
									Debug.Log((object)("Discord message sent successfully: " + formattedMessage));
								}
								catch (Exception ex7)
								{
									Exception ex6 = ex7;
									Debug.LogError((object)("Failed to send Discord message: " + ex6.Message));
								}
							});
						}
					}
				};
				<>c.<>9__0_0 = val;
				obj = (object)val;
			}
			new ConsoleCommand("discord", "sends a message to Discord webhook. Usage: discord <message>", (ConsoleEvent)obj, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj2 = <>c.<>9__0_1;
			if (obj2 == null)
			{
				ConsoleEvent val2 = delegate(ConsoleEventArgs args)
				{
					Terminal context4 = args.Context;
					if (context4 != null)
					{
						context4.AddString("Testing Discord webhook connection...");
					}
					string playerName2 = "Server";
					if ((Object)(object)Player.m_localPlayer != (Object)null && !string.IsNullOrEmpty(Player.m_localPlayer.GetPlayerName()))
					{
						playerName2 = Player.m_localPlayer.GetPlayerName();
					}
					Task.Run(async delegate
					{
						try
						{
							await SimpleDiscordWebhook.SendQuickMessageAsync(BepinexConfiguration.WebhookURL.Value, "\ud83e\uddea Discord webhook test from **" + playerName2 + "** - Connection working!", "Valheim Test Bot");
							Debug.Log((object)"Discord webhook test message sent successfully!");
						}
						catch (Exception ex5)
						{
							Exception ex4 = ex5;
							Debug.LogError((object)("Discord webhook test failed: " + ex4.Message));
						}
					});
				};
				<>c.<>9__0_1 = val2;
				obj2 = (object)val2;
			}
			new ConsoleCommand("discordtest", "tests the Discord webhook connection", (ConsoleEvent)obj2, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
			object obj3 = <>c.<>9__0_2;
			if (obj3 == null)
			{
				ConsoleEvent val3 = delegate(ConsoleEventArgs args)
				{
					string playerName = "Unknown Player";
					if ((Object)(object)Player.m_localPlayer != (Object)null && !string.IsNullOrEmpty(Player.m_localPlayer.GetPlayerName()))
					{
						playerName = Player.m_localPlayer.GetPlayerName();
					}
					string message = null;
					if (args.Length > 1)
					{
						message = string.Join(" ", args.Args, 1, args.Args.Length - 1);
					}
					if (string.IsNullOrEmpty(message))
					{
						message = "\ud83d\udcf8 **" + playerName + "** took a screenshot!";
					}
					Terminal context = args.Context;
					if (context != null)
					{
						context.AddString("Capturing screenshot...");
					}
					try
					{
						SimpleDiscordWebhook webhook = new SimpleDiscordWebhook(BepinexConfiguration.WebhookURL.Value, "Valheim Screenshots");
						string filename = $"{playerName}_screenshot_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.png";
						Texture2D val4 = ScreenCapture.CaptureScreenshotAsTexture();
						if ((Object)(object)val4 == (Object)null)
						{
							throw new Exception("Failed to capture screenshot");
						}
						byte[] pngData = ImageConversion.EncodeToPNG(val4);
						Object.DestroyImmediate((Object)(object)val4);
						if (pngData == null || pngData.Length == 0)
						{
							throw new Exception("Failed to encode screenshot to PNG");
						}
						Terminal context2 = args.Context;
						if (context2 != null)
						{
							context2.AddString("Screenshot captured, uploading to Discord...");
						}
						Task.Run(async delegate
						{
							try
							{
								await webhook.SendFileAsync(pngData, filename, message);
								Debug.Log((object)("Screenshot uploaded to Discord for " + playerName));
							}
							catch (Exception ex3)
							{
								Exception ex2 = ex3;
								Debug.LogError((object)("Failed to upload screenshot: " + ex2.Message));
							}
						});
					}
					catch (Exception ex)
					{
						Terminal context3 = args.Context;
						if (context3 != null)
						{
							context3.AddString("Error: " + ex.Message);
						}
						Debug.LogError((object)("Failed to capture screenshot: " + ex.Message));
					}
				};
				<>c.<>9__0_2 = val3;
				obj3 = (object)val3;
			}
			new ConsoleCommand("discordscreenshot", "captures and sends a screenshot to Discord", (ConsoleEvent)obj3, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}
	}
	[HarmonyPatch(typeof(Player), "Update")]
	public static class HotkeyScreenshotPatch
	{
		[HarmonyPostfix]
		private static void Postfix(Player __instance)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && Input.GetKeyDown(BepinexConfiguration.ScreenshotHotkey.Value))
				{
					string text = __instance.GetPlayerName();
					if (string.IsNullOrEmpty(text))
					{
						text = "Unknown Player";
					}
					Debug.Log((object)("HotkeyScreenshotPatch: " + text + " pressed screenshot hotkey"));
					string message = "\ud83d\udcf8 **" + text + "** captured this screenshot!";
					string filename = $"{text}_screenshot_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.png";
					SimpleDiscordWebhook.SendQuickScreenshotAsync(BepinexConfiguration.WebhookURL.Value, message, BepinexConfiguration.WebhookUsername.Value, BepinexConfiguration.WebhookAvatarURL.Value, filename);
				}
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("HotkeyScreenshotPatch: Error: " + ex.Message));
			}
		}
	}
	public static class PlayerDeathScreenshotPatch
	{
		internal static Texture2D storedDeathScreenshot;

		internal static string storedPlayerName;

		internal static DateTime storedDeathTime;

		internal static IEnumerator CaptureDeathScreenshotCoroutine(string playerName)
		{
			yield return (object)new WaitForSeconds(0.1f);
			SimpleDiscordWebhook webhook = new SimpleDiscordWebhook(BepinexConfiguration.WebhookURL.Value);
			storedDeathScreenshot = webhook.CaptureScreenshot();
			storedPlayerName = playerName;
			storedDeathTime = DateTime.Now;
			Debug.Log((object)("Death screenshot captured and stored for " + playerName));
		}
	}
	[HarmonyPatch(typeof(Humanoid), "OnRagdollCreated")]
	public static class PlayerRagdollScreenshotPatch
	{
		[HarmonyPostfix]
		private static void Postfix(Humanoid __instance)
		{
			try
			{
				Player val = (Player)(object)((__instance is Player) ? __instance : null);
				if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer))
				{
					string text = val.GetPlayerName();
					if (string.IsNullOrEmpty(text))
					{
						text = "Unknown Player";
					}
					Debug.Log((object)("PlayerRagdollScreenshotPatch: " + text + " died - capturing screenshot"));
					((MonoBehaviour)val).StartCoroutine(PlayerDeathScreenshotPatch.CaptureDeathScreenshotCoroutine(text));
				}
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("PlayerRagdollScreenshotPatch: Error: " + ex.Message));
			}
		}
	}
	[HarmonyPatch(typeof(Player), "Awake")]
	public static class PlayerRespawnScreenshotPatch
	{
		[HarmonyPostfix]
		private static void Postfix(Player __instance)
		{
			try
			{
				Debug.Log((object)"PlayerRespawnScreenshotPatch: Awake");
				Debug.Log((object)"PlayerRespawnScreenshotPatch: Local player confirmed");
				if ((Object)(object)PlayerDeathScreenshotPatch.storedDeathScreenshot != (Object)null)
				{
					Debug.Log((object)("PlayerRespawnScreenshotPatch: Processing stored death screenshot for " + PlayerDeathScreenshotPatch.storedPlayerName));
					ProcessStoredDeathScreenshot();
				}
				else
				{
					Debug.Log((object)"PlayerRespawnScreenshotPatch: No stored death screenshot found");
				}
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("PlayerRespawnScreenshotPatch: Error: " + ex.Message));
			}
		}

		private static void ProcessStoredDeathScreenshot()
		{
			try
			{
				SimpleDiscordWebhook webhook = new SimpleDiscordWebhook(BepinexConfiguration.WebhookURL.Value, BepinexConfiguration.WebhookUsername.Value, BepinexConfiguration.WebhookAvatarURL.Value);
				byte[] pngData = webhook.ProcessScreenshot(PlayerDeathScreenshotPatch.storedDeathScreenshot);
				string deathMessage = "**" + PlayerDeathScreenshotPatch.storedPlayerName + "** " + BepinexConfiguration.DeathMessage.Value;
				string filename = $"{PlayerDeathScreenshotPatch.storedPlayerName}_death_{PlayerDeathScreenshotPatch.storedDeathTime:yyyy-MM-dd_HH-mm-ss}.png";
				Task.Run(async delegate
				{
					try
					{
						await webhook.SendFileAsync(pngData, filename, deathMessage);
						Debug.Log((object)("Death screenshot uploaded successfully for " + PlayerDeathScreenshotPatch.storedPlayerName));
					}
					catch (Exception ex3)
					{
						Exception ex2 = ex3;
						Debug.LogError((object)("Error uploading death screenshot: " + ex2.Message));
					}
				});
				PlayerDeathScreenshotPatch.storedDeathScreenshot = null;
				PlayerDeathScreenshotPatch.storedPlayerName = null;
			}
			catch (Exception ex)
			{
				Debug.LogError((object)("Error processing stored death screenshot: " + ex.Message));
				if ((Object)(object)PlayerDeathScreenshotPatch.storedDeathScreenshot != (Object)null)
				{
					Object.DestroyImmediate((Object)(object)PlayerDeathScreenshotPatch.storedDeathScreenshot);
					PlayerDeathScreenshotPatch.storedDeathScreenshot = null;
					PlayerDeathScreenshotPatch.storedPlayerName = null;
				}
			}
		}
	}
}