Decompiled source of DiscordBot v1.2.5

DiscordBot.dll

Decompiled 2 days ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net.WebSockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using DiscordBot.Notices;
using HarmonyLib;
using JetBrains.Annotations;
using LocalizationManager;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using ServerSync;
using TMPro;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
using uGIF;

[assembly: ComVisible(false)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyTrademark("")]
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("DiscordBot")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyFileVersion("1.2.5")]
[assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")]
[assembly: AssemblyCompany("RustyMods")]
[assembly: AssemblyProduct("DiscordBot")]
[assembly: AssemblyCopyright("Copyright ©  2021")]
[assembly: AssemblyConfiguration("")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.5.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[<96ea2e4e-1d9f-4d65-9323-a43f017d41b6>Embedded]
	internal sealed class <96ea2e4e-1d9f-4d65-9323-a43f017d41b6>EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[<96ea2e4e-1d9f-4d65-9323-a43f017d41b6>Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class <239e2483-84fb-4479-8c52-efd07452cd88>NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public <239e2483-84fb-4479-8c52-efd07452cd88>NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public <239e2483-84fb-4479-8c52-efd07452cd88>NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[<96ea2e4e-1d9f-4d65-9323-a43f017d41b6>Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class <8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public <8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace uGIF
{
	[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
	[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(1)]
	public class GIFEncoder
	{
		public bool useGlobalColorTable = false;

		public Color32? transparent = null;

		public int repeat = -1;

		public int dispose = -1;

		public int quality = 10;

		private int delay = 0;

		private int width;

		private int height;

		private int transIndex;

		private bool started = false;

		private MemoryStream ms;

		private Color32[] pixels;

		private byte[] indexedPixels;

		private byte[] prevIndexedPixels;

		private int colorDepth;

		private byte[] colorTab;

		private bool[] usedEntry = new bool[256];

		private int palSize = 7;

		private bool firstFrame = true;

		private NeuQuant nq;

		public float FPS
		{
			set
			{
				delay = Mathf.RoundToInt(100f / value);
			}
		}

		public void AddFrame(Image im)
		{
			if (im == null)
			{
				throw new ArgumentNullException("im");
			}
			if (!started)
			{
				throw new InvalidOperationException("Start() must be called before AddFrame()");
			}
			if (firstFrame)
			{
				width = im.width;
				height = im.height;
			}
			pixels = im.pixels;
			RemapPixels();
			pixels = null;
			if (firstFrame)
			{
				WriteLSD();
				WritePalette();
				if (repeat >= 0)
				{
					WriteNetscapeExt();
				}
			}
			WriteGraphicCtrlExt();
			WriteImageDesc();
			if (!firstFrame && !useGlobalColorTable)
			{
				WritePalette();
			}
			WritePixels();
			firstFrame = false;
		}

		public void Finish()
		{
			if (!started)
			{
				throw new InvalidOperationException("Start() must be called before Finish()");
			}
			started = false;
			ms.WriteByte(59);
			ms.Flush();
			transIndex = 0;
			pixels = null;
			indexedPixels = null;
			prevIndexedPixels = null;
			colorTab = null;
			firstFrame = true;
			nq = null;
		}

		public void Start(MemoryStream os)
		{
			if (os == null)
			{
				throw new ArgumentNullException("os");
			}
			ms = os;
			started = true;
			WriteString("GIF89a");
		}

		private void RemapPixels()
		{
			//IL_0151: Unknown result type (might be due to invalid IL or missing references)
			//IL_0156: Unknown result type (might be due to invalid IL or missing references)
			//IL_015f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			int num = pixels.Length;
			indexedPixels = new byte[num];
			if (firstFrame || !useGlobalColorTable)
			{
				nq = new NeuQuant(pixels, num, quality);
				colorTab = nq.Process();
			}
			for (int i = 0; i < num; i++)
			{
				int num2 = nq.Map(pixels[i].r & 0xFF, pixels[i].g & 0xFF, pixels[i].b & 0xFF);
				usedEntry[num2] = true;
				indexedPixels[i] = (byte)num2;
				if (dispose == 1 && prevIndexedPixels != null)
				{
					if (indexedPixels[i] == prevIndexedPixels[i])
					{
						indexedPixels[i] = (byte)transIndex;
					}
					else
					{
						prevIndexedPixels[i] = (byte)num2;
					}
				}
			}
			colorDepth = 8;
			palSize = 7;
			if (transparent.HasValue)
			{
				Color32 value = transparent.Value;
				transIndex = nq.Map(value.b, value.g, value.r);
			}
			if (dispose == 1 && prevIndexedPixels == null)
			{
				prevIndexedPixels = indexedPixels.Clone() as byte[];
			}
		}

		private int FindClosest(Color32 c)
		{
			//IL_0018: 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_0026: Unknown result type (might be due to invalid IL or missing references)
			if (colorTab == null)
			{
				return -1;
			}
			int r = c.r;
			int g = c.g;
			int b = c.b;
			int result = 0;
			int num = 16777216;
			int num2 = colorTab.Length;
			for (int i = 0; i < num2; i++)
			{
				int num3 = r - (colorTab[i++] & 0xFF);
				int num4 = g - (colorTab[i++] & 0xFF);
				int num5 = b - (colorTab[i] & 0xFF);
				int num6 = num3 * num3 + num4 * num4 + num5 * num5;
				int num7 = i / 3;
				if (usedEntry[num7] && num6 < num)
				{
					num = num6;
					result = num7;
				}
			}
			return result;
		}

		private void WriteGraphicCtrlExt()
		{
			ms.WriteByte(33);
			ms.WriteByte(249);
			ms.WriteByte(4);
			int num;
			int num2;
			if (!transparent.HasValue)
			{
				num = 0;
				num2 = 0;
			}
			else
			{
				num = 1;
				num2 = 2;
			}
			if (dispose >= 0)
			{
				num2 = dispose & 7;
			}
			num2 <<= 2;
			ms.WriteByte(Convert.ToByte(0 | num2 | 0 | num));
			WriteShort(delay);
			ms.WriteByte(Convert.ToByte(transIndex));
			ms.WriteByte(0);
		}

		private void WriteImageDesc()
		{
			ms.WriteByte(44);
			WriteShort(0);
			WriteShort(0);
			WriteShort(width);
			WriteShort(height);
			ms.WriteByte(0);
		}

		private void WriteLSD()
		{
			WriteShort(width);
			WriteShort(height);
			ms.WriteByte(Convert.ToByte(0xF0 | palSize));
			ms.WriteByte(0);
			ms.WriteByte(0);
		}

		private void WriteNetscapeExt()
		{
			ms.WriteByte(33);
			ms.WriteByte(byte.MaxValue);
			ms.WriteByte(11);
			WriteString("NETSCAPE2.0");
			ms.WriteByte(3);
			ms.WriteByte(1);
			WriteShort(repeat);
			ms.WriteByte(0);
		}

		private void WritePalette()
		{
			ms.Write(colorTab, 0, colorTab.Length);
			int num = 768 - colorTab.Length;
			for (int i = 0; i < num; i++)
			{
				ms.WriteByte(0);
			}
		}

		private void WritePixels()
		{
			LZWEncoder lZWEncoder = new LZWEncoder(width, height, indexedPixels, colorDepth);
			lZWEncoder.Encode(ms);
		}

		private void WriteShort(int value)
		{
			ms.WriteByte(Convert.ToByte(value & 0xFF));
			ms.WriteByte(Convert.ToByte((value >> 8) & 0xFF));
		}

		private void WriteString(string s)
		{
			char[] array = s.ToCharArray();
			for (int i = 0; i < array.Length; i++)
			{
				ms.WriteByte((byte)array[i]);
			}
		}
	}
	[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(1)]
	[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
	public class Image
	{
		public int width;

		public int height;

		public Color32[] pixels;

		public Image(Texture2D f)
		{
			pixels = f.GetPixels32();
			width = ((Texture)f).width;
			height = ((Texture)f).height;
		}

		public Image(Color32[] pixels, int width, int height)
		{
			this.pixels = pixels;
			this.width = width;
			this.height = height;
		}

		public Image(int width, int height)
		{
			this.width = width;
			this.height = height;
			pixels = (Color32[])(object)new Color32[width * height];
		}

		public void DrawImage(Image image, int i, int i2)
		{
			throw new NotImplementedException();
		}

		public Color32 GetPixel(int tw, int th)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			int num = th * width + tw;
			return pixels[num];
		}

		public void Flip()
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			for (int i = 0; i < height / 2; i++)
			{
				for (int j = 0; j < width; j++)
				{
					int num = i * width + j;
					int num2 = (height - i - 1) * width + j;
					Color32 val = pixels[num];
					pixels[num] = pixels[num2];
					pixels[num2] = val;
				}
			}
		}

		public void Resize(int scale)
		{
			//IL_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			if (scale <= 1)
			{
				return;
			}
			int num = width / scale;
			int num2 = height / scale;
			Color32[] array = (Color32[])(object)new Color32[num * num2];
			for (int i = 0; i < num2; i++)
			{
				for (int j = 0; j < num; j++)
				{
					array[i * num + j] = pixels[i * scale * width + j * scale];
				}
			}
			pixels = array;
			height = num2;
			width = num;
		}

		public void ResizeBilinear(int newWidth, int newHeight)
		{
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: 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)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_010a: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			if (newWidth == width && newHeight == height)
			{
				return;
			}
			Color32[] array = pixels;
			Color32[] array2 = (Color32[])(object)new Color32[newWidth * newHeight];
			float num = 1f / ((float)newWidth / (float)(width - 1));
			float num2 = 1f / ((float)newHeight / (float)(height - 1));
			int num3 = width;
			for (int i = 0; i < newHeight; i++)
			{
				int num4 = Mathf.FloorToInt((float)i * num2);
				int num5 = num4 * num3;
				int num6 = (num4 + 1) * num3;
				int num7 = i * newWidth;
				for (int j = 0; j < newWidth; j++)
				{
					int num8 = (int)Mathf.Floor((float)j * num);
					float p = (float)j * num - (float)num8;
					array2[num7 + j] = ColorLerpUnclamped(Color32.op_Implicit(ColorLerpUnclamped(Color32.op_Implicit(array[num5 + num8]), Color32.op_Implicit(array[num5 + num8 + 1]), p)), Color32.op_Implicit(ColorLerpUnclamped(Color32.op_Implicit(array[num6 + num8]), Color32.op_Implicit(array[num6 + num8 + 1]), p)), (float)i * num2 - (float)num4);
				}
			}
			pixels = array2;
			height = newHeight;
			width = newWidth;
		}

		private Color32 ColorLerpUnclamped(Color A, Color B, float P)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			return Color32.op_Implicit(new Color(A.r + (B.r - A.r) * P, A.g + (B.g - A.g) * P, A.b + (B.b - A.b) * P, A.a + (B.a - A.a) * P));
		}
	}
	[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
	[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(1)]
	public class LZWEncoder
	{
		private static readonly int EOF = -1;

		private byte[] pixAry;

		private int initCodeSize;

		private int curPixel;

		private static readonly int BITS = 12;

		private static readonly int HSIZE = 5003;

		private int n_bits;

		private int maxbits = BITS;

		private int maxcode;

		private int maxmaxcode = 1 << BITS;

		private int[] htab = new int[HSIZE];

		private int[] codetab = new int[HSIZE];

		private int hsize = HSIZE;

		private int free_ent = 0;

		private bool clear_flg = false;

		private int g_init_bits;

		private int ClearCode;

		private int EOFCode;

		private int cur_accum = 0;

		private int cur_bits = 0;

		private int[] masks = new int[17]
		{
			0, 1, 3, 7, 15, 31, 63, 127, 255, 511,
			1023, 2047, 4095, 8191, 16383, 32767, 65535
		};

		private int a_count;

		private byte[] accum = new byte[256];

		public LZWEncoder(int width, int height, byte[] pixels, int color_depth)
		{
			pixAry = pixels;
			initCodeSize = Math.Max(2, color_depth);
		}

		private void Add(byte c, Stream outs)
		{
			accum[a_count++] = c;
			if (a_count >= 254)
			{
				Flush(outs);
			}
		}

		private void ClearTable(Stream outs)
		{
			ResetCodeTable(hsize);
			free_ent = ClearCode + 2;
			clear_flg = true;
			Output(ClearCode, outs);
		}

		private void ResetCodeTable(int hsize)
		{
			for (int i = 0; i < hsize; i++)
			{
				htab[i] = -1;
			}
		}

		private void Compress(int init_bits, Stream outs)
		{
			g_init_bits = init_bits;
			clear_flg = false;
			n_bits = g_init_bits;
			maxcode = MaxCode(n_bits);
			ClearCode = 1 << init_bits - 1;
			EOFCode = ClearCode + 1;
			free_ent = ClearCode + 2;
			a_count = 0;
			int num = NextPixel();
			int num2 = 0;
			for (int num3 = hsize; num3 < 65536; num3 *= 2)
			{
				num2++;
			}
			num2 = 8 - num2;
			int num4 = hsize;
			ResetCodeTable(num4);
			Output(ClearCode, outs);
			int num5;
			while ((num5 = NextPixel()) != EOF)
			{
				int num3 = (num5 << maxbits) + num;
				int num6 = (num5 << num2) ^ num;
				if (htab[num6] == num3)
				{
					num = codetab[num6];
					continue;
				}
				if (htab[num6] >= 0)
				{
					int num7 = num4 - num6;
					if (num6 == 0)
					{
						num7 = 1;
					}
					while (true)
					{
						if ((num6 -= num7) < 0)
						{
							num6 += num4;
						}
						if (htab[num6] == num3)
						{
							break;
						}
						if (htab[num6] >= 0)
						{
							continue;
						}
						goto IL_0160;
					}
					num = codetab[num6];
					continue;
				}
				goto IL_0160;
				IL_0160:
				Output(num, outs);
				num = num5;
				if (free_ent < maxmaxcode)
				{
					codetab[num6] = free_ent++;
					htab[num6] = num3;
				}
				else
				{
					ClearTable(outs);
				}
			}
			Output(num, outs);
			Output(EOFCode, outs);
		}

		public void Encode(Stream os)
		{
			os.WriteByte(Convert.ToByte(initCodeSize));
			curPixel = 0;
			Compress(initCodeSize + 1, os);
			os.WriteByte(0);
		}

		private void Flush(Stream outs)
		{
			if (a_count > 0)
			{
				outs.WriteByte(Convert.ToByte(a_count));
				outs.Write(accum, 0, a_count);
				a_count = 0;
			}
		}

		private int MaxCode(int n_bits)
		{
			return (1 << n_bits) - 1;
		}

		private int NextPixel()
		{
			if (curPixel == pixAry.Length)
			{
				return EOF;
			}
			curPixel++;
			return pixAry[curPixel - 1] & 0xFF;
		}

		private void Output(int code, Stream outs)
		{
			cur_accum &= masks[cur_bits];
			if (cur_bits > 0)
			{
				cur_accum |= code << cur_bits;
			}
			else
			{
				cur_accum = code;
			}
			cur_bits += n_bits;
			while (cur_bits >= 8)
			{
				Add((byte)((uint)cur_accum & 0xFFu), outs);
				cur_accum >>= 8;
				cur_bits -= 8;
			}
			if (free_ent > maxcode || clear_flg)
			{
				if (clear_flg)
				{
					maxcode = MaxCode(n_bits = g_init_bits);
					clear_flg = false;
				}
				else
				{
					n_bits++;
					if (n_bits == maxbits)
					{
						maxcode = maxmaxcode;
					}
					else
					{
						maxcode = MaxCode(n_bits);
					}
				}
			}
			if (code == EOFCode)
			{
				while (cur_bits > 0)
				{
					Add((byte)((uint)cur_accum & 0xFFu), outs);
					cur_accum >>= 8;
					cur_bits -= 8;
				}
				Flush(outs);
			}
		}
	}
	[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
	[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(1)]
	public class NeuQuant
	{
		private static readonly int netsize = 256;

		private static readonly int prime1 = 499;

		private static readonly int prime2 = 491;

		private static readonly int prime3 = 487;

		private static readonly int prime4 = 503;

		private static readonly int minpicturebytes = 3 * prime4;

		private static readonly int maxnetpos = netsize - 1;

		private static readonly int netbiasshift = 4;

		private static readonly int ncycles = 100;

		private static readonly int intbiasshift = 16;

		private static readonly int intbias = 1 << intbiasshift;

		private static readonly int gammashift = 10;

		private static readonly int gamma = 1 << gammashift;

		private static readonly int betashift = 10;

		private static readonly int beta = intbias >> betashift;

		private static readonly int betagamma = intbias << gammashift - betashift;

		private static readonly int initrad = netsize >> 3;

		private static readonly int radiusbiasshift = 6;

		private static readonly int radiusbias = 1 << radiusbiasshift;

		private static readonly int initradius = initrad * radiusbias;

		private static readonly int radiusdec = 30;

		private static readonly int alphabiasshift = 10;

		private static readonly int initalpha = 1 << alphabiasshift;

		private int alphadec;

		private static readonly int radbiasshift = 8;

		private static readonly int radbias = 1 << radbiasshift;

		private static readonly int alpharadbshift = alphabiasshift + radbiasshift;

		private static readonly int alpharadbias = 1 << alpharadbshift;

		private Color32[] thepicture;

		private int lengthcount;

		private int samplefac;

		private int[][] network;

		private int[] netindex = new int[256];

		private int[] bias = new int[netsize];

		private int[] freq = new int[netsize];

		private int[] radpower = new int[initrad];

		public NeuQuant(Color32[] thepic, int len, int sample)
		{
			thepicture = thepic;
			lengthcount = len;
			samplefac = sample;
			network = new int[netsize][];
			for (int i = 0; i < netsize; i++)
			{
				network[i] = new int[4];
				int[] array = network[i];
				array[0] = (array[1] = (array[2] = (i << netbiasshift + 8) / netsize));
				freq[i] = intbias / netsize;
				bias[i] = 0;
			}
		}

		private byte[] ColorMap()
		{
			byte[] array = new byte[3 * netsize];
			int[] array2 = new int[netsize];
			for (int i = 0; i < netsize; i++)
			{
				array2[network[i][3]] = i;
			}
			int num = 0;
			for (int j = 0; j < netsize; j++)
			{
				int num2 = array2[j];
				array[num++] = (byte)network[num2][0];
				array[num++] = (byte)network[num2][1];
				array[num++] = (byte)network[num2][2];
			}
			return array;
		}

		private void Inxbuild()
		{
			int num = 0;
			int num2 = 0;
			for (int i = 0; i < netsize; i++)
			{
				int[] array = network[i];
				int num3 = i;
				int num4 = array[1];
				int[] array2;
				for (int j = i + 1; j < netsize; j++)
				{
					array2 = network[j];
					if (array2[1] < num4)
					{
						num3 = j;
						num4 = array2[1];
					}
				}
				array2 = network[num3];
				if (i != num3)
				{
					int j = array2[0];
					array2[0] = array[0];
					array[0] = j;
					j = array2[1];
					array2[1] = array[1];
					array[1] = j;
					j = array2[2];
					array2[2] = array[2];
					array[2] = j;
					j = array2[3];
					array2[3] = array[3];
					array[3] = j;
				}
				if (num4 != num)
				{
					netindex[num] = num2 + i >> 1;
					for (int j = num + 1; j < num4; j++)
					{
						netindex[j] = i;
					}
					num = num4;
					num2 = i;
				}
			}
			netindex[num] = num2 + maxnetpos >> 1;
			for (int j = num + 1; j < 256; j++)
			{
				netindex[j] = maxnetpos;
			}
		}

		private void Learn()
		{
			if (lengthcount < minpicturebytes)
			{
				samplefac = 1;
			}
			alphadec = 30 + (samplefac - 1) / 3;
			Color32[] array = thepicture;
			int num = 0;
			int num2 = lengthcount;
			int num3 = lengthcount / (3 * samplefac);
			int num4 = num3 / ncycles;
			int num5 = initalpha;
			int num6 = initradius;
			int num7 = num6 >> radiusbiasshift;
			if (num7 <= 1)
			{
				num7 = 0;
			}
			int i;
			for (i = 0; i < num7; i++)
			{
				radpower[i] = num5 * ((num7 * num7 - i * i) * radbias / (num7 * num7));
			}
			int num8 = ((lengthcount < minpicturebytes) ? 3 : ((lengthcount % prime1 != 0) ? (3 * prime1) : ((lengthcount % prime2 != 0) ? (3 * prime2) : ((lengthcount % prime3 == 0) ? (3 * prime4) : (3 * prime3)))));
			i = 0;
			while (i < num3)
			{
				int b = (array[num].r & 0xFF) << netbiasshift;
				int g = (array[num].g & 0xFF) << netbiasshift;
				int r = (array[num].b & 0xFF) << netbiasshift;
				int i2 = Contest(b, g, r);
				Altersingle(num5, i2, b, g, r);
				if (num7 != 0)
				{
					Alterneigh(num7, i2, b, g, r);
				}
				num += num8;
				if (num >= num2)
				{
					num -= lengthcount;
				}
				i++;
				if (num4 == 0)
				{
					num4 = 1;
				}
				if (i % num4 == 0)
				{
					num5 -= num5 / alphadec;
					num6 -= num6 / radiusdec;
					num7 = num6 >> radiusbiasshift;
					if (num7 <= 1)
					{
						num7 = 0;
					}
					for (i2 = 0; i2 < num7; i2++)
					{
						radpower[i2] = num5 * ((num7 * num7 - i2 * i2) * radbias / (num7 * num7));
					}
				}
			}
		}

		public int Map(int b, int g, int r)
		{
			int num = 1000;
			int result = -1;
			int num2 = netindex[g];
			int num3 = num2 - 1;
			while (num2 < netsize || num3 >= 0)
			{
				int[] array;
				int num5;
				int num4;
				if (num2 < netsize)
				{
					array = network[num2];
					num4 = array[1] - g;
					if (num4 >= num)
					{
						num2 = netsize;
					}
					else
					{
						num2++;
						if (num4 < 0)
						{
							num4 = -num4;
						}
						num5 = array[0] - b;
						if (num5 < 0)
						{
							num5 = -num5;
						}
						num4 += num5;
						if (num4 < num)
						{
							num5 = array[2] - r;
							if (num5 < 0)
							{
								num5 = -num5;
							}
							num4 += num5;
							if (num4 < num)
							{
								num = num4;
								result = array[3];
							}
						}
					}
				}
				if (num3 < 0)
				{
					continue;
				}
				array = network[num3];
				num4 = g - array[1];
				if (num4 >= num)
				{
					num3 = -1;
					continue;
				}
				num3--;
				if (num4 < 0)
				{
					num4 = -num4;
				}
				num5 = array[0] - b;
				if (num5 < 0)
				{
					num5 = -num5;
				}
				num4 += num5;
				if (num4 < num)
				{
					num5 = array[2] - r;
					if (num5 < 0)
					{
						num5 = -num5;
					}
					num4 += num5;
					if (num4 < num)
					{
						num = num4;
						result = array[3];
					}
				}
			}
			return result;
		}

		public byte[] Process()
		{
			Learn();
			Unbiasnet();
			Inxbuild();
			return ColorMap();
		}

		private void Unbiasnet()
		{
			for (int i = 0; i < netsize; i++)
			{
				network[i][0] >>= netbiasshift;
				network[i][1] >>= netbiasshift;
				network[i][2] >>= netbiasshift;
				network[i][3] = i;
			}
		}

		private void Alterneigh(int rad, int i, int b, int g, int r)
		{
			int num = i - rad;
			if (num < -1)
			{
				num = -1;
			}
			int num2 = i + rad;
			if (num2 > netsize)
			{
				num2 = netsize;
			}
			int num3 = i + 1;
			int num4 = i - 1;
			int num5 = 1;
			while (num3 < num2 || num4 > num)
			{
				int num6 = radpower[num5++];
				if (num3 < num2)
				{
					int[] array = network[num3++];
					array[0] -= num6 * (array[0] - b) / alpharadbias;
					array[1] -= num6 * (array[1] - g) / alpharadbias;
					array[2] -= num6 * (array[2] - r) / alpharadbias;
				}
				if (num4 > num)
				{
					int[] array = network[num4--];
					array[0] -= num6 * (array[0] - b) / alpharadbias;
					array[1] -= num6 * (array[1] - g) / alpharadbias;
					array[2] -= num6 * (array[2] - r) / alpharadbias;
				}
			}
		}

		private void Altersingle(int alpha, int i, int b, int g, int r)
		{
			int[] array = network[i];
			array[0] -= alpha * (array[0] - b) / initalpha;
			array[1] -= alpha * (array[1] - g) / initalpha;
			array[2] -= alpha * (array[2] - r) / initalpha;
		}

		private int Contest(int b, int g, int r)
		{
			int num = int.MaxValue;
			int num2 = num;
			int num3 = -1;
			int result = num3;
			for (int i = 0; i < netsize; i++)
			{
				int[] array = network[i];
				int num4 = array[0] - b;
				if (num4 < 0)
				{
					num4 = -num4;
				}
				int num5 = array[1] - g;
				if (num5 < 0)
				{
					num5 = -num5;
				}
				num4 += num5;
				num5 = array[2] - r;
				if (num5 < 0)
				{
					num5 = -num5;
				}
				num4 += num5;
				if (num4 < num)
				{
					num = num4;
					num3 = i;
				}
				int num6 = num4 - (bias[i] >> intbiasshift - netbiasshift);
				if (num6 < num2)
				{
					num2 = num6;
					result = i;
				}
				int num7 = freq[i] >> betashift;
				freq[i] -= num7;
				bias[i] += num7 << gammashift;
			}
			freq[num3] += beta;
			bias[num3] -= betagamma;
			return result;
		}
	}
}
namespace LocalizationManager
{
	[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
	[PublicAPI]
	[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(1)]
	public class Localizer
	{
		private static readonly Dictionary<string, Dictionary<string, Func<string>>> PlaceholderProcessors;

		private static readonly Dictionary<string, Dictionary<string, string>> loadedTexts;

		private static readonly ConditionalWeakTable<Localization, string> localizationLanguage;

		private static readonly List<WeakReference<Localization>> localizationObjects;

		[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(2)]
		private static BaseUnityPlugin _plugin;

		private static readonly List<string> fileExtensions;

		private static BaseUnityPlugin plugin
		{
			get
			{
				//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00b2: Expected O, but got Unknown
				if (_plugin == null)
				{
					IEnumerable<TypeInfo> source;
					try
					{
						source = Assembly.GetExecutingAssembly().DefinedTypes.ToList();
					}
					catch (ReflectionTypeLoadException ex)
					{
						source = from t in ex.Types
							where t != null
							select t.GetTypeInfo();
					}
					_plugin = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)source.First([<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)] (TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t)));
				}
				return _plugin;
			}
		}

		private static void UpdatePlaceholderText(Localization localization, string key)
		{
			localizationLanguage.TryGetValue(localization, out var value);
			string text = loadedTexts[value][key];
			if (PlaceholderProcessors.TryGetValue(key, out var value2))
			{
				text = value2.Aggregate(text, [<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)] (string current, KeyValuePair<string, Func<string>> kv) => current.Replace("{" + kv.Key + "}", kv.Value()));
			}
			localization.AddWord(key, text);
		}

		public static void AddPlaceholder<T>(string key, string placeholder, ConfigEntry<T> config, [<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(new byte[] { 2, 1, 1 })] Func<T, string> convertConfigValue = null)
		{
			if (convertConfigValue == null)
			{
				convertConfigValue = [<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)] [return: <239e2483-84fb-4479-8c52-efd07452cd88>Nullable(1)] (T val) => val.ToString();
			}
			if (!PlaceholderProcessors.ContainsKey(key))
			{
				PlaceholderProcessors[key] = new Dictionary<string, Func<string>>();
			}
			config.SettingChanged += [<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)] (object _, EventArgs _) =>
			{
				UpdatePlaceholder();
			};
			if (loadedTexts.ContainsKey(Localization.instance.GetSelectedLanguage()))
			{
				UpdatePlaceholder();
			}
			void UpdatePlaceholder()
			{
				PlaceholderProcessors[key][placeholder] = () => convertConfigValue(config.Value);
				UpdatePlaceholderText(Localization.instance, key);
			}
		}

		public static void AddText(string key, string text)
		{
			List<WeakReference<Localization>> list = new List<WeakReference<Localization>>();
			foreach (WeakReference<Localization> localizationObject in localizationObjects)
			{
				if (localizationObject.TryGetTarget(out var target))
				{
					Dictionary<string, string> dictionary = loadedTexts[localizationLanguage.GetOrCreateValue(target)];
					if (!target.m_translations.ContainsKey(key))
					{
						dictionary[key] = text;
						target.AddWord(key, text);
					}
				}
				else
				{
					list.Add(localizationObject);
				}
			}
			foreach (WeakReference<Localization> item in list)
			{
				localizationObjects.Remove(item);
			}
		}

		public static void Load()
		{
			LoadLocalization(Localization.instance, Localization.instance.GetSelectedLanguage());
		}

		private static void LoadLocalization(Localization __instance, string language)
		{
			if (!localizationLanguage.Remove(__instance))
			{
				localizationObjects.Add(new WeakReference<Localization>(__instance));
			}
			localizationLanguage.Add(__instance, language);
			Dictionary<string, string> dictionary = new Dictionary<string, string>();
			foreach (string item in from f in Directory.GetFiles(Path.GetDirectoryName(Paths.PluginPath), plugin.Info.Metadata.Name + ".*", SearchOption.AllDirectories)
				where fileExtensions.IndexOf(Path.GetExtension(f)) >= 0
				select f)
			{
				string text = Path.GetFileNameWithoutExtension(item).Split(new char[1] { '.' })[1];
				if (dictionary.ContainsKey(text))
				{
					Debug.LogWarning((object)("Duplicate key " + text + " found for " + plugin.Info.Metadata.Name + ". The duplicate file found at " + item + " will be skipped."));
				}
				else
				{
					dictionary[text] = item;
				}
			}
			if (!dictionary.TryGetValue("English", out var value))
			{
				throw new Exception("Found no English localizations in mod " + plugin.Info.Metadata.Name + ". Expected a file like " + plugin.Info.Metadata.Name + ".English.json or .yml.");
			}
			Dictionary<string, string> dictionary2 = JsonConvert.DeserializeObject<Dictionary<string, string>>(File.ReadAllText(value));
			if (dictionary2 == null)
			{
				throw new Exception("Localization for mod " + plugin.Info.Metadata.Name + " failed: English localization file was empty.");
			}
			string text2 = null;
			if (language != "English" && dictionary.TryGetValue(language, out var value2))
			{
				text2 = File.ReadAllText(value2);
			}
			if (text2 != null)
			{
				foreach (KeyValuePair<string, string> item2 in JsonConvert.DeserializeObject<Dictionary<string, string>>(text2) ?? new Dictionary<string, string>())
				{
					dictionary2[item2.Key] = item2.Value;
				}
			}
			loadedTexts[language] = dictionary2;
			foreach (KeyValuePair<string, string> item3 in dictionary2)
			{
				UpdatePlaceholderText(__instance, item3.Key);
			}
		}

		static Localizer()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Expected O, but got Unknown
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Expected O, but got Unknown
			PlaceholderProcessors = new Dictionary<string, Dictionary<string, Func<string>>>();
			loadedTexts = new Dictionary<string, Dictionary<string, string>>();
			localizationLanguage = new ConditionalWeakTable<Localization, string>();
			localizationObjects = new List<WeakReference<Localization>>();
			fileExtensions = new List<string> { ".json" };
			Harmony val = new Harmony("org.bepinex.helpers.LocalizationManager");
			val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "LoadCSV", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Localizer), "LoadLocalization", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
		}

		[return: <239e2483-84fb-4479-8c52-efd07452cd88>Nullable(2)]
		private static byte[] LoadTranslationFromAssembly(string language)
		{
			foreach (string fileExtension in fileExtensions)
			{
				byte[] array = ReadEmbeddedFileBytes("translations." + language + fileExtension);
				if (array != null)
				{
					return array;
				}
			}
			return null;
		}

		[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(2)]
		public static byte[] ReadEmbeddedFileBytes([<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(1)] string resourceFileName, Assembly containingAssembly = null)
		{
			using MemoryStream memoryStream = new MemoryStream();
			if ((object)containingAssembly == null)
			{
				containingAssembly = Assembly.GetCallingAssembly();
			}
			string text = containingAssembly.GetManifestResourceNames().FirstOrDefault([<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)] (string str) => str.EndsWith(resourceFileName, StringComparison.Ordinal));
			if (text != null)
			{
				containingAssembly.GetManifestResourceStream(text)?.CopyTo(memoryStream);
			}
			return (memoryStream.Length == 0L) ? null : memoryStream.ToArray();
		}
	}
}
namespace DiscordBot
{
	[PublicAPI]
	[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(1)]
	[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
	public static class API
	{
		public static List<Action> m_queue = new List<Action>();

		public static void RegisterCommand(string command, string description, [<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(new byte[] { 2, 1, 1 })] Action<string[]> action, [<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(new byte[] { 2, 1 })] Action<ZPackage> reaction, bool adminOnly, bool isSecret, string emoji)
		{
			if (DiscordCommands.loaded)
			{
				if (!DiscordCommands.m_commands.ContainsKey(command))
				{
					new DiscordCommands.DiscordCommand(command, description, action, reaction, adminOnly, isSecret, emoji);
				}
				return;
			}
			m_queue.Add(delegate
			{
				if (!DiscordCommands.m_commands.ContainsKey(command))
				{
					new DiscordCommands.DiscordCommand(command, description, action, reaction, adminOnly, isSecret, emoji);
				}
			});
		}

		public static void SendNotification(string message)
		{
			Discord.instance?.SendMessage(Webhook.Notifications, message);
		}

		public static void SendChat(string message)
		{
			Discord.instance?.SendMessage(Webhook.Chat, message);
		}
	}
	[PublicAPI]
	[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
	[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(1)]
	public static class DiscordBot_API
	{
		[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
		internal class Method
		{
			private const string Namespace = "DiscordBot";

			private const string ClassName = "API";

			private const string Assembly = "DiscordBot";

			private const string API_LOCATION = "DiscordBot.API, DiscordBot";

			private static readonly Dictionary<string, Type> CachedTypes = new Dictionary<string, Type>();

			[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(2)]
			private readonly MethodInfo info;

			[return: <239e2483-84fb-4479-8c52-efd07452cd88>Nullable(new byte[] { 1, 2 })]
			public object[] Invoke([<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(new byte[] { 1, 2 })] params object[] args)
			{
				object obj = info?.Invoke(null, args);
				object[] array = new object[args.Length + 1];
				array[0] = obj;
				Array.Copy(args, 0, array, 1, args.Length);
				return array;
			}

			public Method(string typeNameWithAssembly, string methodName, BindingFlags bindingFlags = BindingFlags.Static | BindingFlags.Public)
			{
				if (!TryGetType(typeNameWithAssembly, out var type))
				{
					return;
				}
				if (type == null)
				{
					Debug.LogWarning((object)("Type resolution returned null for: '" + typeNameWithAssembly + "'"));
					return;
				}
				info = type.GetMethod(methodName, bindingFlags);
				if (info == null)
				{
					Debug.LogWarning((object)("Failed to find public static method '" + methodName + "' in type '" + type.FullName + "'. Verify the method name is correct, the method exists, and it is marked as public static. "));
				}
			}

			public Method(string methodName, BindingFlags bindingFlags = BindingFlags.Static | BindingFlags.Public)
				: this("DiscordBot.API, DiscordBot", methodName, bindingFlags)
			{
			}

			private static bool TryGetType(string typeNameWithAssembly, [<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(2)] out Type type)
			{
				if (CachedTypes.TryGetValue(typeNameWithAssembly, out type))
				{
					return true;
				}
				Type type2 = Type.GetType(typeNameWithAssembly);
				if ((object)type2 == null)
				{
					Debug.LogWarning((object)("Failed to resolve type: '" + typeNameWithAssembly + "'. Verify the namespace, class name, and assembly name are correct. Ensure the assembly is loaded and accessible."));
					return false;
				}
				type = type2;
				CachedTypes[typeNameWithAssembly] = type2;
				return true;
			}

			public Method(string typeNameWithAssembly, string methodName, params Type[] types)
			{
				if (!TryGetType(typeNameWithAssembly, out var type))
				{
					return;
				}
				if (type == null)
				{
					Debug.LogWarning((object)("Type resolution returned null for: '" + typeNameWithAssembly + "'"));
					return;
				}
				info = type.GetMethod(methodName, types);
				if (info == null)
				{
					Debug.LogWarning((object)("Failed to find public static method '" + methodName + "' in type '" + type.FullName + "'. Verify the method name is correct, the method exists, and it is marked as public static. "));
				}
			}

			public Method(string methodName, params Type[] types)
				: this("DiscordBot.API, DiscordBot", methodName, types)
			{
			}

			[PublicAPI]
			public ParameterInfo[] GetParameters()
			{
				return info?.GetParameters() ?? Array.Empty<ParameterInfo>();
			}

			[PublicAPI]
			public static void ClearCache()
			{
				CachedTypes.Clear();
			}
		}

		private static bool _isLoaded;

		private static readonly Method _RegisterCommand = new Method("RegisterCommand");

		private static readonly Method _SendNotification = new Method("SendNotification");

		private static readonly Method _SendChat = new Method("SendChat");

		private static readonly Dictionary<string, string> Emojis = new Dictionary<string, string>
		{
			{ "smile", "\ud83d\ude0a" },
			{ "grin", "\ud83d\ude01" },
			{ "laugh", "\ud83d\ude02" },
			{ "wink", "\ud83d\ude09" },
			{ "wave", "\ud83d\udc4b" },
			{ "clap", "\ud83d\udc4f" },
			{ "thumbsup", "\ud83d\udc4d" },
			{ "thumbsdown", "\ud83d\udc4e" },
			{ "ok", "\ud83d\udc4c" },
			{ "pray", "\ud83d\ude4f" },
			{ "muscle", "\ud83d\udcaa" },
			{ "facepalm", "\ud83e\udd26" },
			{ "dog", "\ud83d\udc36" },
			{ "cat", "\ud83d\udc31" },
			{ "mouse", "\ud83d\udc2d" },
			{ "fox", "\ud83e\udd8a" },
			{ "bear", "\ud83d\udc3b" },
			{ "panda", "\ud83d\udc3c" },
			{ "koala", "\ud83d\udc28" },
			{ "lion", "\ud83e\udd81" },
			{ "tiger", "\ud83d\udc2f" },
			{ "monkey", "\ud83d\udc35" },
			{ "unicorn", "\ud83e\udd84" },
			{ "dragon", "\ud83d\udc09" },
			{ "tree", "\ud83c\udf33" },
			{ "palm", "\ud83c\udf34" },
			{ "flower", "\ud83c\udf38" },
			{ "rose", "\ud83c\udf39" },
			{ "sun", "☀\ufe0f" },
			{ "moon", "\ud83c\udf19" },
			{ "star", "⭐" },
			{ "rain", "\ud83c\udf27\ufe0f" },
			{ "snow", "❄\ufe0f" },
			{ "fire", "\ud83d\udd25" },
			{ "lightning", "⚡" },
			{ "pizza", "\ud83c\udf55" },
			{ "burger", "\ud83c\udf54" },
			{ "fries", "\ud83c\udf5f" },
			{ "taco", "\ud83c\udf2e" },
			{ "cake", "\ud83c\udf70" },
			{ "donut", "\ud83c\udf69" },
			{ "coffee", "☕" },
			{ "tea", "\ud83c\udf75" },
			{ "beer", "\ud83c\udf7a" },
			{ "wine", "\ud83c\udf77" },
			{ "rocket", "\ud83d\ude80" },
			{ "car", "\ud83d\ude97" },
			{ "bike", "\ud83d\udeb2" },
			{ "airplane", "✈\ufe0f" },
			{ "train", "\ud83d\ude86" },
			{ "bus", "\ud83d\ude8c" },
			{ "ship", "\ud83d\udea2" },
			{ "book", "\ud83d\udcd6" },
			{ "pencil", "✏\ufe0f" },
			{ "pen", "\ud83d\udd8a\ufe0f" },
			{ "paint", "\ud83c\udfa8" },
			{ "camera", "\ud83d\udcf7" },
			{ "phone", "\ud83d\udcf1" },
			{ "computer", "\ud83d\udcbb" },
			{ "gift", "\ud83c\udf81" },
			{ "balloon", "\ud83c\udf88" },
			{ "key", "\ud83d\udd11" },
			{ "lock", "\ud83d\udd12" },
			{ "soccer", "⚽" },
			{ "basketball", "\ud83c\udfc0" },
			{ "football", "\ud83c\udfc8" },
			{ "tennis", "\ud83c\udfbe" },
			{ "golf", "⛳" },
			{ "run", "\ud83c\udfc3" },
			{ "swim", "\ud83c\udfca" },
			{ "ski", "⛷\ufe0f" },
			{ "game", "\ud83c\udfae" },
			{ "music", "\ud83c\udfb5" },
			{ "guitar", "\ud83c\udfb8" },
			{ "drum", "\ud83e\udd41" },
			{ "check", "✅" },
			{ "x", "❌" },
			{ "warning", "⚠\ufe0f" },
			{ "question", "❓" },
			{ "exclamation", "❗" },
			{ "infinity", "♾\ufe0f" },
			{ "heart", "❤\ufe0f" },
			{ "brokenheart", "\ud83d\udc94" },
			{ "sparkle", "✨" },
			{ "starstruck", "\ud83e\udd29" },
			{ "plus", "✚" },
			{ "minus", "━" },
			{ "tornado", "\ud83c\udf2a\ufe0f" },
			{ "storm", "⛈\ufe0f" },
			{ "save", "\ud83d\udcbe" },
			{ "stop", "\ud83d\udd34" }
		};

		private static bool isLoaded
		{
			get
			{
				if (_isLoaded)
				{
					return true;
				}
				_isLoaded = Type.GetType("DiscordBot.API, DiscordBot") != null;
				return _isLoaded;
			}
		}

		public static bool IsLoaded()
		{
			return isLoaded;
		}

		public static void SendNotification(string message)
		{
			_SendNotification.Invoke(message);
		}

		public static void SendChat(string message)
		{
			_SendChat.Invoke(message);
		}

		public static void RegisterCommand(string command, string description, Action<string[]> action, [<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(new byte[] { 2, 1 })] Action<ZPackage> reaction = null, bool adminOnly = false, bool isSecret = false, string emoji = "")
		{
			_RegisterCommand.Invoke(command, description, action, reaction, adminOnly, isSecret, emoji);
		}
	}
	[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
	[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(1)]
	public static class Extensions
	{
		public static string ToURL(this Webhook type)
		{
			if (1 == 0)
			{
			}
			string result = type switch
			{
				Webhook.Chat => DiscordBotPlugin.ChatWebhookURL, 
				Webhook.Notifications => DiscordBotPlugin.NoticeWebhookURL, 
				Webhook.Commands => DiscordBotPlugin.CommandWebhookURL, 
				Webhook.DeathFeed => DiscordBotPlugin.DeathFeedWebhookURL, 
				_ => DiscordBotPlugin.ChatWebhookURL, 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		public static string ToID(this Channel type)
		{
			if (1 == 0)
			{
			}
			string result = type switch
			{
				Channel.Chat => DiscordBotPlugin.ChatChannelID, 
				Channel.Commands => DiscordBotPlugin.CommandChannelID, 
				_ => DiscordBotPlugin.ChatChannelID, 
			};
			if (1 == 0)
			{
			}
			return result;
		}
	}
	public enum Toggle
	{
		On = 1,
		Off = 0
	}
	public enum Webhook
	{
		Notifications,
		Chat,
		Commands,
		DeathFeed
	}
	public enum Channel
	{
		Chat,
		Commands
	}
	public enum ChatDisplay
	{
		Player,
		Bot
	}
	[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(1)]
	[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
	[BepInPlugin("RustyMods.DiscordBot", "DiscordBot", "1.2.5")]
	public class DiscordBotPlugin : BaseUnityPlugin
	{
		[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
		public class StringListConfig
		{
			public readonly List<string> list;

			public StringListConfig(List<string> items)
			{
				list = items;
			}

			public StringListConfig(string items)
			{
				list = items.Split(new char[1] { ',' }).ToList();
			}

			public static void Draw(ConfigEntryBase cfg)
			{
				//IL_00e8: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ed: Unknown result type (might be due to invalid IL or missing references)
				//IL_0103: Expected O, but got Unknown
				//IL_0132: Unknown result type (might be due to invalid IL or missing references)
				//IL_0137: Unknown result type (might be due to invalid IL or missing references)
				//IL_014d: Expected O, but got Unknown
				bool valueOrDefault = cfg.Description.Tags.Select([<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)] (object a) => (a.GetType().Name == "ConfigurationManagerAttributes") ? ((bool?)a.GetType().GetField("ReadOnly")?.GetValue(a)) : null).FirstOrDefault((bool? v) => v.HasValue).GetValueOrDefault();
				bool flag = false;
				List<string> list = new List<string>();
				GUILayout.BeginVertical(Array.Empty<GUILayoutOption>());
				foreach (string item2 in new StringListConfig((string)cfg.BoxedValue).list)
				{
					GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>());
					string item = item2;
					string text = GUILayout.TextField(item2, Array.Empty<GUILayoutOption>());
					if (text != item2 && !valueOrDefault)
					{
						flag = true;
						item = text;
					}
					if (GUILayout.Button("x", new GUIStyle(GUI.skin.button)
					{
						fixedWidth = 21f
					}, Array.Empty<GUILayoutOption>()) && !valueOrDefault)
					{
						flag = true;
					}
					else
					{
						list.Add(item);
					}
					if (GUILayout.Button("+", new GUIStyle(GUI.skin.button)
					{
						fixedWidth = 21f
					}, Array.Empty<GUILayoutOption>()) && !valueOrDefault)
					{
						list.Add("");
						flag = true;
					}
					GUILayout.EndHorizontal();
				}
				GUILayout.EndVertical();
				if (flag)
				{
					cfg.BoxedValue = new StringListConfig(list).ToString();
				}
			}

			public override string ToString()
			{
				return string.Join(",", list);
			}
		}

		[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)]
		public class Resolution
		{
			public readonly int width;

			public readonly int height;

			public Resolution(int width, int height)
			{
				this.width = width;
				this.height = height;
				resolutions[ToString()] = this;
			}

			[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(1)]
			public sealed override string ToString()
			{
				return $"{width}x{height}";
			}
		}

		[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)]
		public class ConfigurationManagerAttributes
		{
			[UsedImplicitly]
			public int? Order = null;

			[UsedImplicitly]
			public bool? Browsable = null;

			[UsedImplicitly]
			[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(2)]
			public string Category = null;

			[UsedImplicitly]
			[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(new byte[] { 2, 1 })]
			public Action<ConfigEntryBase> CustomDrawer = null;
		}

		internal const string ModName = "DiscordBot";

		internal const string ModVersion = "1.2.5";

		internal const string Author = "RustyMods";

		private const string ModGUID = "RustyMods.DiscordBot";

		private static readonly string ConfigFileName = "RustyMods.DiscordBot.cfg";

		private static readonly string ConfigFileFullPath;

		internal static string ConnectionError;

		private readonly Harmony _harmony = new Harmony("RustyMods.DiscordBot");

		public static readonly ManualLogSource DiscordBotLogger;

		private static readonly ConfigSync ConfigSync;

		public static readonly Dir directory;

		public static DiscordBotPlugin m_instance;

		private static ConfigEntry<Toggle> _serverConfigLocked;

		private static ConfigEntry<string> m_startWorldHook;

		private static ConfigEntry<string> m_saveWebhook;

		private static ConfigEntry<string> m_shutdownWebhook;

		private static ConfigEntry<string> m_loginWebhook;

		private static ConfigEntry<string> m_logoutWebhook;

		private static ConfigEntry<string> m_eventWebhook;

		private static ConfigEntry<string> m_newDayWebhook;

		private static ConfigEntry<string> m_notificationWebhookURL;

		private static ConfigEntry<Toggle> m_serverStartNotice;

		private static ConfigEntry<Toggle> m_serverStopNotice;

		private static ConfigEntry<Toggle> m_serverSaveNotice;

		private static ConfigEntry<Toggle> m_deathNotice;

		private static ConfigEntry<Toggle> m_loginNotice;

		private static ConfigEntry<Toggle> m_logoutNotice;

		private static ConfigEntry<Toggle> m_eventNotice;

		private static ConfigEntry<Toggle> m_newDayNotice;

		private static ConfigEntry<Toggle> m_coordinateDetails;

		private static ConfigEntry<string> m_chatWebhookURL;

		private static ConfigEntry<string> m_chatChannelID;

		private static ConfigEntry<Toggle> m_chatEnabled;

		private static ConfigEntry<ChatDisplay> m_chatType;

		private static ConfigEntry<string> m_commandWebhookURL;

		private static ConfigEntry<string> m_commandChannelID;

		private static ConfigEntry<string> m_deathFeedURL;

		private static ConfigEntry<string> m_discordAdmins;

		private static ConfigEntry<Toggle> m_logErrors;

		private static ConfigEntry<string> m_botToken;

		private static ConfigEntry<Toggle> m_screenshotDeath;

		private static ConfigEntry<float> m_screenshotDelay;

		private static ConfigEntry<string> m_screenshotResolution;

		private static ConfigEntry<Toggle> m_screenshotGif;

		private static ConfigEntry<int> m_gifFPS;

		private static ConfigEntry<float> m_gifDuration;

		private static ConfigEntry<string> m_gifResolution;

		private static ConfigEntry<KeyCode> m_selfieKey;

		private static ConfigEntry<AIService> m_aiService;

		private static ConfigEntry<string> m_chatGPTAPIKEY;

		private static ConfigEntry<string> m_geminiAPIKEY;

		private static ConfigEntry<string> m_deepSeekAPIKEY;

		private static ConfigEntry<string> m_openRouterAPIKEY;

		private static ConfigEntry<OpenRouterModel> m_openRouterModel;

		private static ConfigEntry<Toggle> m_enableJobs;

		private static readonly Dictionary<string, Resolution> resolutions;

		public static bool ShowServerStart => m_serverStartNotice.Value == Toggle.On;

		public static bool ShowChat => m_chatEnabled.Value == Toggle.On;

		public static bool LogErrors => m_logErrors.Value == Toggle.On;

		public static bool ShowServerStop => m_serverStopNotice.Value == Toggle.On;

		public static bool ShowServerSave => m_serverSaveNotice.Value == Toggle.On;

		public static bool ShowOnDeath => m_deathNotice.Value == Toggle.On;

		public static bool ShowOnLogin => m_loginNotice.Value == Toggle.On;

		public static bool ShowOnLogout => m_logoutNotice.Value == Toggle.On;

		public static bool ShowEvent => m_eventNotice.Value == Toggle.On;

		public static bool ShowNewDay => m_newDayNotice.Value == Toggle.On;

		public static bool ShowCoordinates => m_coordinateDetails.Value == Toggle.On;

		public static ChatDisplay ChatType => m_chatType.Value;

		public static string DiscordAdmins => m_discordAdmins.Value;

		public static string BOT_TOKEN => m_botToken.Value;

		public static string ChatChannelID => m_chatChannelID.Value;

		public static string CommandChannelID => m_commandChannelID.Value;

		public static string ChatWebhookURL => m_chatWebhookURL.Value;

		public static string CommandWebhookURL => m_commandWebhookURL.Value;

		public static string NoticeWebhookURL => m_notificationWebhookURL.Value;

		public static string DeathFeedWebhookURL => m_deathFeedURL.Value;

		public static bool ScreenshotDeath => m_screenshotDeath.Value == Toggle.On;

		public static bool ScreenshotGif => m_screenshotGif.Value == Toggle.On;

		public static float ScreenshotDelay => m_screenshotDelay.Value;

		public static int GIF_FPS => m_gifFPS.Value;

		public static float GIF_DURATION => m_gifDuration.Value;

		public static Resolution ScreenshotResolution => resolutions[m_screenshotResolution.Value];

		public static Resolution GifResolution => resolutions[m_gifResolution.Value];

		public static KeyCode SelfieKey => m_selfieKey.Value;

		public static AIService AIService => m_aiService.Value;

		public static string ChatGPT_KEY => m_chatGPTAPIKEY.Value;

		public static string Gemini_KEY => m_geminiAPIKEY.Value;

		public static string DeepSeek_KEY => m_deepSeekAPIKEY.Value;

		public static string OpenRouter_KEY => m_openRouterAPIKEY.Value;

		public static OpenRouterModel OpenRouterModel => m_openRouterModel.Value;

		public static List<string> OnWorldStartHooks => Utility.IsNullOrWhiteSpace(m_startWorldHook.Value) ? new List<string>() : new StringListConfig(m_startWorldHook.Value).list;

		public static List<string> OnWorldSaveHooks => Utility.IsNullOrWhiteSpace(m_saveWebhook.Value) ? new List<string>() : new StringListConfig(m_saveWebhook.Value).list;

		public static List<string> OnWorldShutdownHooks => Utility.IsNullOrWhiteSpace(m_shutdownWebhook.Value) ? new List<string>() : new StringListConfig(m_shutdownWebhook.Value).list;

		public static List<string> OnLoginHooks => Utility.IsNullOrWhiteSpace(m_loginWebhook.Value) ? new List<string>() : new StringListConfig(m_loginWebhook.Value).list;

		public static List<string> OnLogoutHooks => Utility.IsNullOrWhiteSpace(m_logoutWebhook.Value) ? new List<string>() : new StringListConfig(m_logoutWebhook.Value).list;

		public static List<string> OnEventHooks => Utility.IsNullOrWhiteSpace(m_eventWebhook.Value) ? new List<string>() : new StringListConfig(m_eventWebhook.Value).list;

		public static List<string> OnNewDayHooks => Utility.IsNullOrWhiteSpace(m_newDayWebhook.Value) ? new List<string>() : new StringListConfig(m_newDayWebhook.Value).list;

		public static bool JobsEnabled => m_enableJobs.Value == Toggle.On;

		public static void SetDiscordAdmins(string value)
		{
			m_discordAdmins.Value = value;
		}

		public static void LogWarning(string message)
		{
			DiscordBotLogger.LogWarning((object)message);
		}

		public static void LogDebug(string message)
		{
			DiscordBotLogger.LogDebug((object)message);
		}

		public static void LogError(string message)
		{
			DiscordBotLogger.LogError((object)message);
		}

		public void Awake()
		{
			//IL_024e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0259: Expected O, but got Unknown
			//IL_031b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0326: Expected O, but got Unknown
			//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c0: Expected O, but got Unknown
			//IL_0400: Unknown result type (might be due to invalid IL or missing references)
			//IL_040b: Expected O, but got Unknown
			//IL_0439: Unknown result type (might be due to invalid IL or missing references)
			//IL_0444: Expected O, but got Unknown
			//IL_04dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_04e7: Expected O, but got Unknown
			//IL_0543: Unknown result type (might be due to invalid IL or missing references)
			//IL_054e: Expected O, but got Unknown
			//IL_058e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0599: Expected O, but got Unknown
			//IL_05d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_05e4: Expected O, but got Unknown
			//IL_0624: Unknown result type (might be due to invalid IL or missing references)
			//IL_062f: Expected O, but got Unknown
			//IL_066f: Unknown result type (might be due to invalid IL or missing references)
			//IL_067a: Expected O, but got Unknown
			//IL_06ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_06c5: Expected O, but got Unknown
			//IL_0705: Unknown result type (might be due to invalid IL or missing references)
			//IL_0710: Expected O, but got Unknown
			Keys.Write();
			Localizer.Load();
			m_instance = this;
			_serverConfigLocked = config("1 - General", "Lock Configuration", Toggle.On, "If on, the configuration is locked and can be changed by server admins only.");
			ConfigSync.AddLockingConfigEntry<Toggle>(_serverConfigLocked);
			m_logErrors = config("1 - General", "Log Errors", Toggle.Off, "If on, caught errors will log to console");
			m_notificationWebhookURL = config("2 - Notifications", "Webhook URL", "", "Set webhook to receive notifications, like server start, stop, save etc...");
			m_serverStartNotice = config("2 - Notifications", "Startup", Toggle.On, "If on, bot will send message when server is starting");
			m_serverStopNotice = config("2 - Notifications", "Shutdown", Toggle.On, "If on, bot will send message when server is shutting down");
			m_serverSaveNotice = config("2 - Notifications", "Saving", Toggle.On, "If on, bot will send message when server is saving");
			m_loginNotice = config("2 - Notifications", "Login", Toggle.On, "If on, bot will send message when player logs in");
			m_logoutNotice = config("2 - Notifications", "Logout", Toggle.On, "If on, bot will send message when player logs out");
			m_eventNotice = config("2 - Notifications", "Random Events", Toggle.On, "If on, bot will send message when random event starts");
			m_newDayNotice = config("2 - Notifications", "New Day", Toggle.Off, "If on, bot will send message when a new day begins");
			m_coordinateDetails = config("2 - Notifications", "Show Coordinates", Toggle.On, "If on, coordinates will be added to login/logout notifications");
			m_chatWebhookURL = config("3 - Chat", "Webhook URL", "", "Set discord webhook to display chat messages");
			m_chatChannelID = config("3 - Chat", "Channel ID", "", "Set channel ID to monitor for messages");
			m_chatEnabled = config("3 - Chat", "Enabled", Toggle.On, "If on, bot will send message when player shouts and monitor discord for messages");
			m_chatType = config("3 - Chat", "Display As", ChatDisplay.Player, "Set how chat messages appear, if Player, message sent by player, else sent by bot with a prefix that player is saying");
			m_commandWebhookURL = config("4 - Commands", "Webhook URL", "", "Set discord webhook to display feedback messages from commands");
			m_commandChannelID = config("4 - Commands", "Channel ID", "", "Set channel ID to monitor for input commands");
			m_discordAdmins = config("4 - Commands", "Discord Admin", "", new ConfigDescription("List of discord admins, who can run commands", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					CustomDrawer = StringListConfig.Draw
				}
			}));
			m_enableJobs = config("4 - Commands", "Jobs", Toggle.On, "If on, jobs are enabled");
			m_botToken = config("5 - Setup", "BOT TOKEN", "", "Add bot token here, server only", synchronizedSetting: false);
			m_deathNotice = config("6 - Death Feed", "Enabled", Toggle.On, "If on, bot will send message when player dies");
			m_deathFeedURL = config("6 - Death Feed", "Webhook URL", "", "Set webhook to receive death feed messages");
			m_screenshotDeath = config("6 - Death Feed", "Screenshot", Toggle.On, "If on, bot will post screenshot of death", synchronizedSetting: false);
			m_screenshotDelay = config("6 - Death Feed", "Screenshot Delay", 0.3f, new ConfigDescription("Set delay", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()), synchronizedSetting: false);
			Resolution resolution = new Resolution(800, 600);
			Resolution resolution2 = new Resolution(960, 540);
			Resolution resolution3 = new Resolution(1280, 720);
			Resolution resolution4 = new Resolution(1920, 1080);
			m_screenshotResolution = config("6 - Death Feed", "Screenshot Resolution", resolution2.ToString(), new ConfigDescription("Set resolution", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[4]
			{
				resolution.ToString(),
				resolution2.ToString(),
				resolution3.ToString(),
				resolution4.ToString()
			}), Array.Empty<object>()), synchronizedSetting: false);
			m_screenshotGif = config("6 - Death Feed", "Screenshot GIF", Toggle.On, "If on, bot will post gif of death", synchronizedSetting: false);
			m_gifFPS = config("6 - Death Feed", "GIF FPS", 30, new ConfigDescription("Set frames per second", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 30), Array.Empty<object>()), synchronizedSetting: false);
			m_gifDuration = config("6 - Death Feed", "GIF Record Duration", 3f, new ConfigDescription("Set recording duration for gif, in seconds", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 3f), Array.Empty<object>()), synchronizedSetting: false);
			Resolution resolution5 = new Resolution(256, 144);
			Resolution resolution6 = new Resolution(320, 180);
			Resolution resolution7 = new Resolution(480, 270);
			Resolution resolution8 = new Resolution(640, 360);
			m_gifResolution = config("6 - Death Feed", "GIF Resolution", resolution7.ToString(), new ConfigDescription("Set resolution", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[4]
			{
				resolution5.ToString(),
				resolution6.ToString(),
				resolution7.ToString(),
				resolution8.ToString()
			}), Array.Empty<object>()), synchronizedSetting: false);
			m_selfieKey = config<KeyCode>("1 - General", "Selfie", (KeyCode)0, "Hotkey to take selfie and send to discord", synchronizedSetting: false);
			m_startWorldHook = config("7 - Webhooks", "On World Start", "", new ConfigDescription("If empty, will use default notification webhook", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					CustomDrawer = StringListConfig.Draw
				}
			}));
			m_saveWebhook = config("7 - Webhooks", "On World Save", "", new ConfigDescription("If empty, will use default notification webhook", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					CustomDrawer = StringListConfig.Draw
				}
			}));
			m_shutdownWebhook = config("7 - Webhooks", "On World Shutdown", "", new ConfigDescription("If empty, will use default notification webhook", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					CustomDrawer = StringListConfig.Draw
				}
			}));
			m_loginWebhook = config("7 - Webhooks", "On Login", "", new ConfigDescription("If empty, will use default notification webhook", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					CustomDrawer = StringListConfig.Draw
				}
			}));
			m_logoutWebhook = config("7 - Webhooks", "On Logout", "", new ConfigDescription("If empty, will use default notification webhook", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					CustomDrawer = StringListConfig.Draw
				}
			}));
			m_eventWebhook = config("7 - Webhooks", "On Event", "", new ConfigDescription("If empty, will use default notification webhook", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					CustomDrawer = StringListConfig.Draw
				}
			}));
			m_newDayWebhook = config("7 - Webhooks", "On New Day", "", new ConfigDescription("If empty, will use default notification webhook", (AcceptableValueBase)null, new object[1]
			{
				new ConfigurationManagerAttributes
				{
					CustomDrawer = StringListConfig.Draw
				}
			}));
			m_aiService = config("8 - AI", "Provider", AIService.Gemini, "Set which Artificial Intelligence API to use", synchronizedSetting: false);
			m_chatGPTAPIKEY = config("8 - AI", "ChatGPT", "", "Set ChatGPT key", synchronizedSetting: false);
			m_geminiAPIKEY = config("8 - AI", "Gemini", "", "Set Gemini key", synchronizedSetting: false);
			m_deepSeekAPIKEY = config("8 - AI", "DeepSeek", "", "Set DeepSeek key", synchronizedSetting: false);
			m_openRouterAPIKEY = config("8 - AI", "OpenRouter", "", "Set OpenRouter key", synchronizedSetting: false);
			m_openRouterModel = config("8 - AI", "OpenRouter Model", OpenRouterModel.Claude3_5Sonnet, "Set OpenRouter Model", synchronizedSetting: false);
			DiscordCommands.Setup();
			DeathQuips.Setup();
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			_harmony.PatchAll(executingAssembly);
			SetupWatcher();
		}

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

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

		private void ReadConfigValues(object sender, FileSystemEventArgs e)
		{
			if (!File.Exists(ConfigFileFullPath))
			{
				return;
			}
			try
			{
				DiscordBotLogger.LogDebug((object)"ReadConfigValues called");
				((BaseUnityPlugin)this).Config.Reload();
			}
			catch
			{
				DiscordBotLogger.LogError((object)("There was an issue loading your " + ConfigFileName));
				DiscordBotLogger.LogError((object)"Please check your config entries for spelling and format!");
			}
		}

		private ConfigEntry<T> config<[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(2)] T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Expected O, but got Unknown
			ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags);
			ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(group, name, value, val);
			SyncedConfigEntry<T> syncedConfigEntry = ConfigSync.AddConfigEntry<T>(val2);
			syncedConfigEntry.SynchronizedConfig = synchronizedSetting;
			return val2;
		}

		public ConfigEntry<T> config<[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(2)] T>(string group, string name, T value, string description, bool synchronizedSetting = true)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Expected O, but got Unknown
			return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting);
		}

		static DiscordBotPlugin()
		{
			string configPath = Paths.ConfigPath;
			char directorySeparatorChar = Path.DirectorySeparatorChar;
			ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName;
			ConnectionError = "";
			DiscordBotLogger = Logger.CreateLogSource("DiscordBot");
			ConfigSync = new ConfigSync("RustyMods.DiscordBot")
			{
				DisplayName = "DiscordBot",
				CurrentVersion = "1.2.5",
				MinimumRequiredVersion = "1.2.5"
			};
			directory = new Dir(Paths.ConfigPath, "DiscordBot");
			m_instance = null;
			_serverConfigLocked = null;
			m_startWorldHook = null;
			m_saveWebhook = null;
			m_shutdownWebhook = null;
			m_loginWebhook = null;
			m_logoutWebhook = null;
			m_eventWebhook = null;
			m_newDayWebhook = null;
			m_notificationWebhookURL = null;
			m_serverStartNotice = null;
			m_serverStopNotice = null;
			m_serverSaveNotice = null;
			m_deathNotice = null;
			m_loginNotice = null;
			m_logoutNotice = null;
			m_eventNotice = null;
			m_newDayNotice = null;
			m_coordinateDetails = null;
			m_chatWebhookURL = null;
			m_chatChannelID = null;
			m_chatEnabled = null;
			m_chatType = null;
			m_commandWebhookURL = null;
			m_commandChannelID = null;
			m_deathFeedURL = null;
			m_discordAdmins = null;
			m_logErrors = null;
			m_botToken = null;
			m_screenshotDeath = null;
			m_screenshotDelay = null;
			m_screenshotResolution = null;
			m_screenshotGif = null;
			m_gifFPS = null;
			m_gifDuration = null;
			m_gifResolution = null;
			m_selfieKey = null;
			m_aiService = null;
			m_chatGPTAPIKEY = null;
			m_geminiAPIKEY = null;
			m_deepSeekAPIKEY = null;
			m_openRouterAPIKEY = null;
			m_openRouterModel = null;
			m_enableJobs = null;
			resolutions = new Dictionary<string, Resolution>();
		}
	}
	public enum AIService
	{
		ChatGPT,
		Gemini,
		DeepSeek,
		OpenRouter
	}
	[PublicAPI]
	public enum GPTModel
	{
		[InternalName("gpt-3.5-turbo")]
		Turbo,
		[InternalName("gpt-4o")]
		GPT4o,
		[InternalName("gpt-4o-mini")]
		GPT4oMini,
		[InternalName("gpt-4.1")]
		GPT4_1
	}
	[PublicAPI]
	public enum GeminiModel
	{
		[InternalName("gemini-2.0-flash")]
		Flash2_0,
		[InternalName("gemini-2.5-flash")]
		Flash2_5,
		[InternalName("gemini-2.5-pro")]
		Pro2_5
	}
	[PublicAPI]
	public enum DeepSeekModel
	{
		[InternalName("deepseek-chat")]
		Chat,
		[InternalName("deepseek-reasoner")]
		Reasoner
	}
	[PublicAPI]
	public enum OpenRouterModel
	{
		[InternalName("anthropic/claude-3.5-sonnet")]
		Claude3_5Sonnet,
		[InternalName("google/gemini-2.0-flash-exp:free")]
		GeminiFlashFree,
		[InternalName("meta-llama/llama-4-maverick:free")]
		Llama4_Maverick,
		[InternalName("microsoft/wizardlm-2-8x22b")]
		WizardLM8x22B,
		[InternalName("openai/gpt-4o-mini")]
		GPT4oMini,
		[InternalName("deepseek/deepseek-chat")]
		DeepSeekChat,
		[InternalName("nousresearch/hermes-3-llama-3.1-405b:free")]
		Hermes3_Llama31_405b
	}
	[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(1)]
	[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
	public class InternalName : Attribute
	{
		public readonly string internalName;

		public InternalName(string internalName)
		{
			this.internalName = internalName;
		}
	}
	[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(1)]
	[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
	public class ChatAI : MonoBehaviour
	{
		[HarmonyPatch(typeof(Terminal), "UpdateChat")]
		[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)]
		private static class Terminal_UpdateChat_Patch
		{
			[UsedImplicitly]
			[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(1)]
			private static void Postfix(Terminal __instance)
			{
				if (!((Object)(object)__instance != (Object)(object)Chat.instance) && Object.op_Implicit((Object)(object)instance))
				{
					instance.tempChat = ((TMP_Text)__instance.m_output).text;
				}
			}
		}

		[HarmonyPatch(typeof(ZNet), "OnNewConnection")]
		[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)]
		private static class ZNet_OnNewConnection_Patch
		{
			[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(1)]
			[UsedImplicitly]
			private static void Postfix(ZNetPeer peer)
			{
				peer.m_rpc.Register<string, string>("RPC_ChatAIMessage", (Action<ZRpc, string, string>)RPC_ChatAIMessage);
			}
		}

		[Serializable]
		[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
		public class GPTRequest
		{
			public string model = "gpt-4o-mini";

			public List<GPTMessage> messages = new List<GPTMessage>();
		}

		[Serializable]
		[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)]
		public class GPTResponse
		{
			[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(1)]
			public GPTChoice[] choices;
		}

		[Serializable]
		[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)]
		public class GPTChoice
		{
			[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(1)]
			public GPTMessage message;
		}

		[Serializable]
		[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
		public class GPTMessage
		{
			public string role;

			public string content;

			public GPTMessage()
			{
			}

			public GPTMessage(string role, string content)
			{
				this.role = role;
				this.content = content;
			}
		}

		[Serializable]
		[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)]
		public class GeminiRequest
		{
			[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(1)]
			public List<GeminiContent> contents = new List<GeminiContent>();
		}

		[Serializable]
		[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)]
		public class GeminiContent
		{
			[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(1)]
			public List<GeminiPart> parts;
		}

		[Serializable]
		[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)]
		public class GeminiPart
		{
			[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(1)]
			public string text;
		}

		[Serializable]
		[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)]
		public class GeminiResponse
		{
			[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(1)]
			public GeminiCandidate[] candidates;

			[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(2)]
			public GeminiUsageMetadata UsageMetadata;
		}

		[Serializable]
		[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)]
		public class GeminiUsageMetadata
		{
			public int promptTokenCount;

			public int candidatesTokenCount;

			public int totalTokenCount;
		}

		[Serializable]
		[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)]
		public class GeminiCandidate
		{
			[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(1)]
			public GeminiContent content;
		}

		[Serializable]
		[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
		public class DeepSeekRequest
		{
			public string model = "deepseek-chat";

			public List<DeepSeekMessage> messages = new List<DeepSeekMessage>();

			public bool stream = false;
		}

		[Serializable]
		[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)]
		public class DeepSeekResponse
		{
			[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(1)]
			public DeepSeekChoice[] choices;
		}

		[Serializable]
		[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)]
		public class DeepSeekChoice
		{
			[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(1)]
			public DeepSeekMessage message;
		}

		[Serializable]
		[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
		public class DeepSeekMessage
		{
			public string role;

			public string content;

			public DeepSeekMessage()
			{
			}

			public DeepSeekMessage(string role, string content)
			{
				this.role = role;
				this.content = content;
			}
		}

		[Serializable]
		[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
		public class OpenRouterRequest
		{
			public string model = "anthropic/claude-3.5-sonnet";

			public List<OpenRouterMessage> messages = new List<OpenRouterMessage>();

			public bool stream = false;
		}

		[Serializable]
		[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)]
		public class OpenRouterResponse
		{
			[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(1)]
			public OpenRouterChoice[] choices;
		}

		[Serializable]
		[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)]
		public class OpenRouterChoice
		{
			[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(1)]
			public OpenRouterMessage message;
		}

		[Serializable]
		[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
		public class OpenRouterMessage
		{
			public string role;

			public string content;

			public OpenRouterMessage()
			{
			}

			public OpenRouterMessage(string role, string content)
			{
				this.role = role;
				this.content = content;
			}
		}

		[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(2)]
		public static ChatAI instance;

		public bool isThinking;

		public int ellipsesCount;

		public float ellipsesTimer;

		public string tempChat = "";

		[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(new byte[] { 2, 1 })]
		[method: <239e2483-84fb-4479-8c52-efd07452cd88>Nullable(new byte[] { 2, 1 })]
		[field: <239e2483-84fb-4479-8c52-efd07452cd88>Nullable(new byte[] { 2, 1 })]
		public event Action<string> OnResponse;

		[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(2)]
		[method: <8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(2)]
		[field: <239e2483-84fb-4479-8c52-efd07452cd88>Nullable(2)]
		public event Action<int, int, int> OnMetadata;

		[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(new byte[] { 2, 1 })]
		[method: <239e2483-84fb-4479-8c52-efd07452cd88>Nullable(new byte[] { 2, 1 })]
		[field: <239e2483-84fb-4479-8c52-efd07452cd88>Nullable(new byte[] { 2, 1 })]
		public event Action<string> OnError;

		[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(new byte[] { 2, 1 })]
		[method: <239e2483-84fb-4479-8c52-efd07452cd88>Nullable(new byte[] { 2, 1 })]
		[field: <239e2483-84fb-4479-8c52-efd07452cd88>Nullable(new byte[] { 2, 1 })]
		public event Action<string> OnDeathQuip;

		public void BroadcastMessage(string username, string message)
		{
			if (!Object.op_Implicit((Object)(object)ZNet.instance))
			{
				return;
			}
			foreach (ZNetPeer peer in ZNet.instance.GetPeers())
			{
				peer.m_rpc.Invoke("RPC_ChatAIMessage", new object[2] { username, message });
			}
		}

		public static void RPC_ChatAIMessage(ZRpc rpc, string username, string message)
		{
			DisplayChatMessage(username, message);
		}

		private static void DisplayChatMessage(string username, string message)
		{
			string text = "</color><color=orange>" + username + "</color>: " + message;
			((Terminal)Chat.instance).AddString(text);
			Chat.instance.Show();
		}

		public void Awake()
		{
			instance = this;
			OnResponse += HandleResponse;
			OnError += HandleError;
			OnDeathQuip += HandleDeathQuip;
			OnMetadata += HandleMetadata;
		}

		public void Update()
		{
			if (!Object.op_Implicit((Object)(object)Chat.instance) || !isThinking)
			{
				return;
			}
			ellipsesTimer += Time.deltaTime;
			if (!(ellipsesTimer < 0.5f))
			{
				ellipsesTimer = 0f;
				if (ellipsesCount > 3)
				{
					ellipsesCount = 0;
				}
				ellipsesCount++;
				((TMP_Text)((Terminal)Chat.instance).m_output).text = tempChat + new string('.', ellipsesCount);
			}
		}

		public void OnDestroy()
		{
			instance = null;
		}

		public void HandleResponse(string response)
		{
			((Terminal)Chat.instance).AddString($"<color=orange>[{DiscordBotPlugin.AIService}]</color>: {response}");
			Chat.instance.Show();
			BroadcastMessage($"[{DiscordBotPlugin.AIService}]", response);
			Discord.instance?.SendMessage(Webhook.Chat, DiscordBotPlugin.AIService.ToString(), response);
		}

		public void HandleMetadata(int promptTokenCount, int candidatesTokenCount, int totalTokenCount)
		{
			string message = $"Prompt Token Count: {promptTokenCount}; Candidates Token Count: {candidatesTokenCount}; Total Token Count: {totalTokenCount}";
			DiscordBotPlugin.LogDebug(message);
		}

		public void HandleError(string error)
		{
			DiscordBotPlugin.LogError(error);
		}

		public void HandleDeathQuip(string quip)
		{
			if (Object.op_Implicit((Object)(object)Screenshot.instance))
			{
				Screenshot.instance.message = quip;
			}
			if (Object.op_Implicit((Object)(object)Recorder.instance))
			{
				Recorder.instance.message = quip;
			}
		}

		public void Ask(string prompt, bool deathQuip = false)
		{
			switch (DiscordBotPlugin.AIService)
			{
			case AIService.ChatGPT:
				AskOpenAI(prompt, deathQuip);
				break;
			case AIService.Gemini:
				AskGemini(prompt, deathQuip);
				break;
			case AIService.DeepSeek:
				AskDeepSeek(prompt, deathQuip);
				break;
			case AIService.OpenRouter:
				AskOpenRouter(prompt, deathQuip);
				break;
			}
		}

		public static bool HasKey()
		{
			AIService aIService = DiscordBotPlugin.AIService;
			if (1 == 0)
			{
			}
			bool result = aIService switch
			{
				AIService.ChatGPT => !string.IsNullOrEmpty(DiscordBotPlugin.ChatGPT_KEY), 
				AIService.Gemini => !string.IsNullOrEmpty(DiscordBotPlugin.Gemini_KEY), 
				AIService.DeepSeek => !string.IsNullOrEmpty(DiscordBotPlugin.DeepSeek_KEY), 
				AIService.OpenRouter => !string.IsNullOrEmpty(DiscordBotPlugin.OpenRouter_KEY), 
				_ => false, 
			};
			if (1 == 0)
			{
			}
			return result;
		}

		public void AskOpenAI(string prompt, bool deathQuip = false)
		{
			if (string.IsNullOrEmpty(DiscordBotPlugin.ChatGPT_KEY))
			{
				this.OnError?.Invoke("OpenAI API token not set");
			}
			else
			{
				((MonoBehaviour)this).StartCoroutine(PromptOpenAI(DiscordBotPlugin.ChatGPT_KEY, prompt, deathQuip));
			}
		}

		public void AskGemini(string prompt, bool deathQuip = false)
		{
			if (string.IsNullOrEmpty(DiscordBotPlugin.Gemini_KEY))
			{
				this.OnError?.Invoke("Gemini API token not set");
			}
			else
			{
				((MonoBehaviour)this).StartCoroutine(PromptGemini(DiscordBotPlugin.Gemini_KEY, prompt, deathQuip));
			}
		}

		public void AskDeepSeek(string prompt, bool deathQuip = false)
		{
			if (string.IsNullOrEmpty(DiscordBotPlugin.DeepSeek_KEY))
			{
				this.OnError?.Invoke("DeepSeek API token not set");
			}
			else
			{
				((MonoBehaviour)this).StartCoroutine(PromptDeepSeek(DiscordBotPlugin.DeepSeek_KEY, prompt, deathQuip));
			}
		}

		public void AskOpenRouter(string prompt, bool deathQuip = false)
		{
			if (string.IsNullOrEmpty(DiscordBotPlugin.OpenRouter_KEY))
			{
				this.OnError?.Invoke("OpenRouter API token not set");
			}
			else
			{
				((MonoBehaviour)this).StartCoroutine(PromptOpenRouter(DiscordBotPlugin.OpenRouter_KEY, prompt, deathQuip));
			}
		}

		private IEnumerator PromptOpenAI(string apiKey, string prompt, bool deathQuip)
		{
			isThinking = true;
			string json = JsonConvert.SerializeObject((object)new GPTRequest
			{
				model = Utils.GetAttributeOfType<InternalName>((Enum)GPTModel.Turbo).internalName,
				messages = 
				{
					new GPTMessage("user", prompt)
				}
			});
			byte[] body = Encoding.UTF8.GetBytes(json);
			UnityWebRequest request = new UnityWebRequest("https://api.openai.com/v1/chat/completions", "POST");
			try
			{
				request.uploadHandler = (UploadHandler)new UploadHandlerRaw(body);
				request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
				request.SetRequestHeader("Content-Type", "application/json");
				request.SetRequestHeader("Authorization", "Bearer " + apiKey);
				yield return request.SendWebRequest();
				isThinking = false;
				if ((int)request.result != 1)
				{
					this.OnError?.Invoke("Failed to prompt gpt: " + request.error);
				}
				else
				{
					ParseGPTResponse(request.downloadHandler.text, deathQuip);
				}
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		public void ParseGPTResponse(string json, bool deathQuip)
		{
			GPTResponse gPTResponse = JsonConvert.DeserializeObject<GPTResponse>(json);
			if (gPTResponse == null)
			{
				this.OnError?.Invoke("Failed to parse response");
				return;
			}
			string obj = gPTResponse.choices[0].message.content.Trim();
			if (!deathQuip)
			{
				this.OnResponse?.Invoke(obj);
			}
			else
			{
				this.OnDeathQuip?.Invoke(obj);
			}
		}

		private IEnumerator PromptGemini(string apiKey, string prompt, bool deathQuip)
		{
			isThinking = true;
			string model = Utils.GetAttributeOfType<InternalName>((Enum)GeminiModel.Flash2_0).internalName;
			string url = "https://generativelanguage.googleapis.com/v1beta/models/" + model + ":generateContent?key=" + apiKey;
			string json = JsonConvert.SerializeObject((object)new GeminiRequest
			{
				contents = 
				{
					new GeminiContent
					{
						parts = new List<GeminiPart>
						{
							new GeminiPart
							{
								text = prompt
							}
						}
					}
				}
			});
			byte[] body = Encoding.UTF8.GetBytes(json);
			UnityWebRequest request = new UnityWebRequest(url, "POST");
			try
			{
				request.uploadHandler = (UploadHandler)new UploadHandlerRaw(body);
				request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
				request.SetRequestHeader("Content-Type", "application/json");
				yield return request.SendWebRequest();
				isThinking = false;
				if ((int)request.result != 1)
				{
					this.OnError?.Invoke("Failed to prompt Gemini: " + request.error);
					this.OnError?.Invoke("Response: " + request.downloadHandler.text);
				}
				else
				{
					ParseGeminiResponse(request.downloadHandler.text, deathQuip);
				}
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		public void ParseGeminiResponse(string json, bool deathQuip)
		{
			GeminiResponse geminiResponse = JsonConvert.DeserializeObject<GeminiResponse>(json);
			if (geminiResponse?.candidates == null || geminiResponse.candidates.Length == 0)
			{
				this.OnError?.Invoke("Failed to parse gemini response");
				return;
			}
			string obj = geminiResponse.candidates[0].content.parts[0].text.Trim();
			if (geminiResponse.UsageMetadata != null)
			{
				this.OnMetadata?.Invoke(geminiResponse.UsageMetadata.promptTokenCount, geminiResponse.UsageMetadata.candidatesTokenCount, geminiResponse.UsageMetadata.totalTokenCount);
			}
			if (deathQuip)
			{
				this.OnDeathQuip?.Invoke(obj);
			}
			else
			{
				this.OnResponse?.Invoke(obj);
			}
		}

		private IEnumerator PromptDeepSeek(string apiKey, string prompt, bool deathQuip)
		{
			isThinking = true;
			string json = JsonConvert.SerializeObject((object)new DeepSeekRequest
			{
				model = Utils.GetAttributeOfType<InternalName>((Enum)DeepSeekModel.Chat).internalName,
				messages = 
				{
					new DeepSeekMessage("user", prompt)
				}
			});
			byte[] body = Encoding.UTF8.GetBytes(json);
			UnityWebRequest request = new UnityWebRequest("https://api.deepseek.com/chat/completions", "POST");
			try
			{
				request.uploadHandler = (UploadHandler)new UploadHandlerRaw(body);
				request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
				request.SetRequestHeader("Content-Type", "application/json");
				request.SetRequestHeader("Authorization", "Bearer " + apiKey);
				yield return request.SendWebRequest();
				isThinking = false;
				if ((int)request.result != 1)
				{
					this.OnError?.Invoke("Failed to prompt DeepSeek: " + request.error);
					this.OnError?.Invoke("Response: " + request.downloadHandler.text);
				}
				else
				{
					ParseDeepSeekResponse(request.downloadHandler.text, deathQuip);
				}
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		public void ParseDeepSeekResponse(string json, bool deathQuip)
		{
			DeepSeekResponse deepSeekResponse = JsonConvert.DeserializeObject<DeepSeekResponse>(json);
			if (deepSeekResponse?.choices == null || deepSeekResponse.choices.Length == 0)
			{
				this.OnError?.Invoke("Failed to parse DeepSeek response");
				return;
			}
			string obj = deepSeekResponse.choices[0].message.content.Trim();
			if (deathQuip)
			{
				this.OnDeathQuip?.Invoke(obj);
			}
			else
			{
				this.OnResponse?.Invoke(obj);
			}
		}

		private IEnumerator PromptOpenRouter(string apiKey, string prompt, bool deathQuip)
		{
			isThinking = true;
			string json = JsonConvert.SerializeObject((object)new OpenRouterRequest
			{
				model = Utils.GetAttributeOfType<InternalName>((Enum)DiscordBotPlugin.OpenRouterModel).internalName,
				messages = 
				{
					new OpenRouterMessage("user", prompt)
				}
			});
			byte[] body = Encoding.UTF8.GetBytes(json);
			UnityWebRequest request = new UnityWebRequest("https://openrouter.ai/api/v1/chat/completions", "POST");
			try
			{
				request.uploadHandler = (UploadHandler)new UploadHandlerRaw(body);
				request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
				request.SetRequestHeader("Content-Type", "application/json");
				request.SetRequestHeader("Authorization", "Bearer " + apiKey);
				request.SetRequestHeader("HTTP-Referer", "https://github.com/RustyMods/DiscordBot");
				request.SetRequestHeader("X-Title", "DiscordBot");
				yield return request.SendWebRequest();
				isThinking = false;
				if ((int)request.result != 1)
				{
					this.OnError?.Invoke("Failed to prompt OpenRouter: " + request.error);
					this.OnError?.Invoke("Response: " + request.downloadHandler.text);
				}
				else
				{
					ParseOpenRouterResponse(request.downloadHandler.text, deathQuip);
				}
			}
			finally
			{
				((IDisposable)request)?.Dispose();
			}
		}

		public void ParseOpenRouterResponse(string json, bool deathQuip)
		{
			OpenRouterResponse openRouterResponse = JsonConvert.DeserializeObject<OpenRouterResponse>(json);
			if (openRouterResponse?.choices == null || openRouterResponse.choices.Length == 0)
			{
				this.OnError?.Invoke("Failed to parse OpenRouter response");
				return;
			}
			string obj = openRouterResponse.choices[0].message.content.Trim();
			if (deathQuip)
			{
				this.OnDeathQuip?.Invoke(obj);
			}
			else
			{
				this.OnResponse?.Invoke(obj);
			}
		}
	}
	public static class ColorExtensions
	{
		public static Color Blurple => new Color(0.36f, 0.47f, 1f);

		public static Color SoftBlue => new Color(0.25f, 0.55f, 0.95f);

		public static Color MutedBlue => new Color(0.32f, 0.78f, 0.85f);

		public static Color Purple => new Color(0.64f, 0.43f, 0.95f);

		public static Color SlateGray => new Color(0.22f, 0.25f, 0.3f);

		public static Color VibrantOrange => new Color(1f, 0.55f, 0.25f);

		public static Color CoolGray => new Color(0.45f, 0.52f, 0.6f);
	}
	[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
	[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(1)]
	public class Recorder : MonoBehaviour
	{
		[Header("Discord message")]
		private string playerName = string.Empty;

		public string message = string.Empty;

		private string thumbnail = string.Empty;

		[Header("GIF Settings")]
		private readonly List<Image> recordedImages = new List<Image>();

		private bool isRecording;

		private float recordStartTime;

		[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(2)]
		private Coroutine recordingCoroutine;

		[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(2)]
		private byte[] gifBytes;

		[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(2)]
		public static Recorder instance;

		private static Camera camera => Utils.GetMainCamera();

		private static int gifHeight => DiscordBotPlugin.GifResolution.height;

		private static int gifWidth => DiscordBotPlugin.GifResolution.width;

		private static int fps => DiscordBotPlugin.GIF_FPS;

		private static float recordDuration => DiscordBotPlugin.GIF_DURATION;

		public void Awake()
		{
			instance = this;
		}

		public void OnDestroy()
		{
			instance = null;
		}

		public void StartRecording(string player, string quip, string avatar)
		{
			if (!isRecording)
			{
				playerName = player;
				message = quip;
				thumbnail = avatar;
				isRecording = true;
				recordStartTime = Time.time;
				if (recordingCoroutine != null)
				{
					((MonoBehaviour)this).StopCoroutine(recordingCoroutine);
				}
				recordingCoroutine = ((MonoBehaviour)this).StartCoroutine(Record());
			}
		}

		private IEnumerator Record()
		{
			Screenshot.instance?.HideHud();
			float interval = 1f / (float)fps;
			while (isRecording && Time.time - recordStartTime < recordDuration)
			{
				yield return (object)new WaitForEndOfFrame();
				Image img = new Image(ScreenCapture.CaptureScreenshotAsTexture());
				recordedImages.Add(img);
				yield return (object)new WaitForSeconds(interval);
			}
			isRecording = false;
			Screenshot.instance?.ShowHud();
			Thread thread = new Thread(CreateGif);
			thread.Start();
			((MonoBehaviour)this).StartCoroutine(WaitForBytes());
		}

		private IEnumerator WaitForBytes()
		{
			while (gifBytes == null)
			{
				yield return null;
			}
			SendGif(gifBytes);
			Cleanup();
		}

		public void Cleanup()
		{
			recordedImages.Clear();
			gifBytes = null;
		}

		private void CreateGif()
		{
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			GIFEncoder gIFEncoder = new GIFEncoder
			{
				useGlobalColorTable = true,
				repeat = 0,
				FPS = fps,
				transparent = new Color32(byte.MaxValue, (byte)0, byte.MaxValue, byte.MaxValue),
				dispose = 1
			};
			MemoryStream memoryStream = new MemoryStream();
			gIFEncoder.Start(memoryStream);
			foreach (Image recordedImage in recordedImages)
			{
				recordedImage.ResizeBilinear(gifWidth, gifHeight);
				recordedImage.Flip();
				gIFEncoder.AddFrame(recordedImage);
			}
			gIFEncoder.Finish();
			gifBytes = memoryStream.ToArray();
			memoryStream.Close();
		}

		[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(2)]
		private void SendGif(byte[] bytes)
		{
			if (bytes == null || bytes.Length == 0)
			{
				DiscordBotPlugin.LogWarning("GIF bytes are null or empty");
			}
			else
			{
				Discord.instance?.SendGifMessage(Webhook.DeathFeed, playerName, message, bytes, $"{DateTime.UtcNow:yyyyMMdd_HHmmss}.gif", "", thumbnail);
			}
		}
	}
	[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(1)]
	[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
	public class Screenshot : MonoBehaviour
	{
		[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(2)]
		public static Screenshot instance;

		private Texture2D recordedFrame = null;

		private bool isCapturing;

		[Header("Discord message")]
		private string playerName = string.Empty;

		public string message = string.Empty;

		private string thumbnail = string.Empty;

		private GameObject m_chatWindow = null;

		[Header("Screenshot Settings")]
		private static int width => DiscordBotPlugin.ScreenshotResolution.width;

		private static int height => DiscordBotPlugin.ScreenshotResolution.height;

		public void Awake()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Expected O, but got Unknown
			instance = this;
			recordedFrame = new Texture2D(width, height, (TextureFormat)3, false);
		}

		public void Start()
		{
			m_chatWindow = ((Component)((Transform)((Terminal)Chat.instance).m_chatWindow).Find("root")).gameObject;
		}

		public void Update()
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if ((int)DiscordBotPlugin.SelfieKey != 0 && Input.GetKey(DiscordBotPlugin.SelfieKey) && !isCapturing)
			{
				StartSelfie();
			}
		}

		public void OnDestroy()
		{
			instance = null;
		}

		private IEnumerator DelayedCaptureFrame()
		{
			HideHud();
			yield return (object)new WaitForSeconds(DiscordBotPlugin.ScreenshotDelay);
			yield return (object)new WaitForEndOfFrame();
			Texture2D frame = ScreenCapture.CaptureScreenshotAsTexture();
			ShowHud();
			try
			{
				Image img = new Image(frame);
				img.ResizeBilinear(width, height);
				recordedFrame.Reinitialize(width, height);
				recordedFrame.SetPixels32(img.pixels);
				recordedFrame.Apply();
			}
			catch (Exception ex)
			{
				DiscordBotPlugin.LogWarning("Failed to resize recorded frame: " + ex.Message);
				isCapturing = false;
				yield break;
			}
			byte[] bytes = ImageConversion.EncodeToPNG(recordedFrame);
			if (bytes == null || bytes.Length == 0)
			{
				DiscordBotPlugin.LogWarning("Failed to encode recorded frame");
				isCapturing = false;
			}
			else
			{
				SendToDiscord(bytes);
				isCapturing = false;
			}
		}

		public void StartCapture(string player, string quip, string avatar)
		{
			if (!isCapturing)
			{
				playerName = player;
				message = quip;
				thumbnail = avatar;
				isCapturing = true;
				((MonoBehaviour)this).StartCoroutine(DelayedCaptureFrame());
			}
		}

		public void HideHud()
		{
			Hud.instance.m_userHidden = true;
			Hud.instance.m_hudPressed = 0f;
			m_chatWindow.SetActive(false);
			((Component)Console.instance).gameObject.SetActive(false);
		}

		public void ShowHud()
		{
			Hud.instance.m_userHidden = false;
			Hud.instance.m_hudPressed = 0f;
			m_chatWindow.SetActive(true);
			((Component)Console.instance).gameObject.SetActive(true);
		}

		private IEnumerator DelayedSelfie()
		{
			HideHud();
			yield return (object)new WaitForSeconds(DiscordBotPlugin.ScreenshotDelay);
			yield return (object)new WaitForEndOfFrame();
			Texture2D frame = ScreenCapture.CaptureScreenshotAsTexture();
			ShowHud();
			try
			{
				Image img = new Image(frame);
				img.ResizeBilinear(width, height);
				recordedFrame.Reinitialize(width, height);
				recordedFrame.SetPixels32(img.pixels);
				recordedFrame.Apply();
			}
			catch (Exception ex)
			{
				DiscordBotPlugin.LogWarning("Failed to resize recorded frame: " + ex.Message);
				isCapturing = false;
				yield break;
			}
			byte[] bytes = ImageConversion.EncodeToPNG(recordedFrame);
			if (bytes == null || bytes.Length == 0)
			{
				DiscordBotPlugin.LogWarning("Failed to encode recorded frame");
				isCapturing = false;
			}
			else
			{
				SendSelfieToDiscord(bytes);
				isCapturing = false;
			}
		}

		public void StartSelfie()
		{
			isCapturing = true;
			((MonoBehaviour)this).StartCoroutine(DelayedSelfie());
		}

		public void SendToDiscord(byte[] data)
		{
			Discord.instance?.SendImageMessage(Webhook.DeathFeed, playerName, message, data, $"{DateTime.UtcNow:yyyyMMdd_HHmmss}.png", "", thumbnail);
		}

		public void SendSelfieToDiscord(byte[] bytes)
		{
			Discord.instance?.SendImageMessage(Webhook.Chat, Player.m_localPlayer.GetPlayerName(), "Selfie!", bytes, $"{DateTime.UtcNow:yyyyMMdd_HHmmss}.png");
		}
	}
	[<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(1)]
	[<239e2483-84fb-4479-8c52-efd07452cd88>Nullable(0)]
	public class Dir
	{
		public readonly string Path;

		public bool Exists => Directory.Exists(Path);

		public Dir(string dir, string name)
		{
			Path = System.IO.Path.Combine(dir, name);
			EnsureDirectoryExists();
		}

		private void EnsureDirectoryExists()
		{
			if (!Directory.Exists(Path))
			{
				Directory.CreateDirectory(Path);
			}
		}

		public string[] GetFiles(string searchPattern = "*", bool includeSubDirs = false)
		{
			SearchOption searchOption = (includeSubDirs ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
			return ExecuteWithRetry([<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)] () => Directory.GetFiles(Path, searchPattern, searchOption));
		}

		public string[] GetDirectories(string searchPattern = "*")
		{
			return ExecuteWithRetry([<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)] () => Directory.GetDirectories(Path, searchPattern));
		}

		public string CreateDir(string dirName)
		{
			string text = System.IO.Path.Combine(Path, dirName);
			if (Directory.Exists(text))
			{
				return text;
			}
			Directory.CreateDirectory(text);
			return text;
		}

		public string WriteFile(string fileName, string content)
		{
			string fullPath = System.IO.Path.Combine(Path, fileName);
			ExecuteWithRetry(delegate
			{
				File.WriteAllText(fullPath, content);
			});
			return fullPath;
		}

		public string WriteAllLines(string fileName, List<string> lines)
		{
			string fullPath = System.IO.Path.Combine(Path, fileName);
			ExecuteWithRetry(delegate
			{
				File.WriteAllLines(fullPath, lines);
			});
			return fullPath;
		}

		public void WriteAllBytes(string fileName, byte[] content)
		{
			string fullPath = System.IO.Path.Combine(Path, fileName);
			ExecuteWithRetry(delegate
			{
				File.WriteAllBytes(fullPath, content);
			});
		}

		public string ReadFile(string fileName)
		{
			string fullPath = System.IO.Path.Combine(Path, fileName);
			return ExecuteWithRetry([<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)] () => File.ReadAllText(fullPath));
		}

		public IEnumerable<string> ReadAllLines(string fileName)
		{
			string fullPath = System.IO.Path.Combine(Path, fileName);
			return ExecuteWithRetry([<8463bf94-2e6d-4e2f-af82-7033db72bcef>NullableContext(0)] () => File.ReadAllLines(fullPath));
		}

		public bool FileExists(string fileName)
		{
			string fullPath = System.IO.Path.Combine(Path, fileName);
			return ExecuteWithRetry(() => File.Exists(f