Decompiled source of DiscordBot v1.1.2
DiscordBot.dll
Decompiled 3 days ago
The result has been truncated due to the large size, download it to view full contents!
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 HarmonyLib; using JetBrains.Annotations; using LocalizationManager; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; using ServerSync; using Splatform; using TMPro; using UnityEngine; using UnityEngine.Networking; using UnityEngine.UI; using uGIF; [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")] [assembly: AssemblyFileVersion("1.1.2")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyDescription("")] [assembly: AssemblyTitle("DiscordBot")] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyCompany("RustyMods")] [assembly: AssemblyProduct("DiscordBot")] [assembly: CompilationRelaxations(8)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.1.2.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [<fb7af288-4992-4af4-b6b5-9c6416ee3ff2>Embedded] internal sealed class <fb7af288-4992-4af4-b6b5-9c6416ee3ff2>EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [<fb7af288-4992-4af4-b6b5-9c6416ee3ff2>Embedded] [CompilerGenerated] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class <79c465b9-e19a-45b2-b8d4-89f0bda71d86>NullableAttribute : Attribute { public readonly byte[] NullableFlags; public <79c465b9-e19a-45b2-b8d4-89f0bda71d86>NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public <79c465b9-e19a-45b2-b8d4-89f0bda71d86>NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] [CompilerGenerated] [<fb7af288-4992-4af4-b6b5-9c6416ee3ff2>Embedded] internal sealed class <a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContextAttribute : Attribute { public readonly byte Flag; public <a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace uGIF { [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(1)] [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(0)] 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]); } } } [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(0)] [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(1)] 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(Image image) { pixels = image.pixels.Clone() as Color32[]; width = image.width; height = image.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)); } } [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(0)] [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>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); } } } [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(1)] [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(0)] 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 { [PublicAPI] [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(0)] [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>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; [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>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([<a3c84666-66ef-4ed1-accf-6c30be1c4e69>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, [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>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, [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(new byte[] { 2, 1, 1 })] Func<T, string> convertConfigValue = null) { if (convertConfigValue == null) { convertConfigValue = [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(0)] [return: <79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(1)] (T val) => val.ToString(); } if (!PlaceholderProcessors.ContainsKey(key)) { PlaceholderProcessors[key] = new Dictionary<string, Func<string>>(); } config.SettingChanged += [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>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: <79c465b9-e19a-45b2-b8d4-89f0bda71d86>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; } [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(2)] public static byte[] ReadEmbeddedFileBytes([<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(1)] string resourceFileName, Assembly containingAssembly = null) { using MemoryStream memoryStream = new MemoryStream(); if ((object)containingAssembly == null) { containingAssembly = Assembly.GetCallingAssembly(); } string text = containingAssembly.GetManifestResourceNames().FirstOrDefault([<a3c84666-66ef-4ed1-accf-6c30be1c4e69>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 { [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(0)] [PublicAPI] [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(1)] public static class API { public static List<Action> m_queue = new List<Action>(); public static void RegisterCommand(string command, string description, [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(new byte[] { 2, 1, 1 })] Action<string[]> action, [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>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); if (!isSecret) { new DiscordCommands.CommandTooltip(command, description, adminOnly, emoji); } } return; } m_queue.Add(delegate { if (!DiscordCommands.m_commands.ContainsKey(command)) { new DiscordCommands.DiscordCommand(command, description, action, reaction, adminOnly, isSecret, emoji); if (!isSecret) { new DiscordCommands.CommandTooltip(command, description, adminOnly, 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); } } [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(0)] [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(1)] [PublicAPI] public static class DiscordBot_API { [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>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>(); [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(2)] private readonly MethodInfo info; [return: <79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(new byte[] { 1, 2 })] public object[] Invoke([<79c465b9-e19a-45b2-b8d4-89f0bda71d86>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, [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>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, [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>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); } } [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(1)] [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(0)] 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 } [BepInPlugin("RustyMods.DiscordBot", "DiscordBot", "1.1.2")] [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(0)] [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(1)] public class DiscordBotPlugin : BaseUnityPlugin { [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>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([<a3c84666-66ef-4ed1-accf-6c30be1c4e69>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); } } [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>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; } [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(1)] public sealed override string ToString() { return $"{width}x{height}"; } } [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(0)] public class ConfigurationManagerAttributes { [UsedImplicitly] public int? Order = null; [UsedImplicitly] public bool? Browsable = null; [UsedImplicitly] [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(2)] public string Category = null; [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(new byte[] { 2, 1 })] [UsedImplicitly] public Action<ConfigEntryBase> CustomDrawer = null; } internal const string ModName = "DiscordBot"; internal const string ModVersion = "1.1.2"; 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; private static ConfigEntry<Toggle> _serverConfigLocked; public static readonly Dir directory; public static DiscordBotPlugin m_instance; 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<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<int> m_screenshotDepth; 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 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 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 int ScreenshotDepth => m_screenshotDepth.Value; 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 void Awake() { //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0205: Expected O, but got Unknown //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: Expected O, but got Unknown //IL_0360: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Expected O, but got Unknown //IL_039d: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: Expected O, but got Unknown //IL_043c: Unknown result type (might be due to invalid IL or missing references) //IL_0447: Expected O, but got Unknown //IL_0475: Unknown result type (might be due to invalid IL or missing references) //IL_0480: Expected O, but got Unknown //IL_0518: Unknown result type (might be due to invalid IL or missing references) //IL_0523: 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, errors will log to console as warnings"); 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_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_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(960, 540); Resolution resolution2 = new Resolution(800, 600); Resolution resolution3 = new Resolution(960, 540); Resolution resolution4 = new Resolution(1280, 720); Resolution resolution5 = new Resolution(1920, 1080); m_screenshotResolution = config("6 - Death Feed", "Screenshot Resolution", resolution.ToString(), new ConfigDescription("Set resolution", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[5] { resolution2.ToString(), resolution.ToString(), resolution3.ToString(), resolution4.ToString(), resolution5.ToString() }), Array.Empty<object>()), synchronizedSetting: false); m_screenshotDepth = config("6 - Death Feed", "Screenshot Depth", 32, new ConfigDescription("Set depth", (AcceptableValueBase)(object)new AcceptableValueList<int>(new int[4] { 0, 16, 24, 32 }), Array.Empty<object>()), synchronizedSetting: false); m_screenshotResolution.SettingChanged += [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(0)] (object _, EventArgs _) => { Screenshot.instance?.OnResolutionChange(); }; m_screenshotDepth.SettingChanged += [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(0)] (object _, EventArgs _) => { Screenshot.instance?.OnResolutionChange(); }; 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 resolution6 = new Resolution(256, 144); Resolution resolution7 = new Resolution(320, 180); Resolution resolution8 = new Resolution(480, 270); Resolution resolution9 = new Resolution(640, 360); m_gifResolution = config("6 - Death Feed", "GIF Resolution", resolution8.ToString(), new ConfigDescription("Set resolution", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[4] { resolution6.ToString(), resolution7.ToString(), resolution8.ToString(), resolution9.ToString() }), Array.Empty<object>()), synchronizedSetting: false); m_gifResolution.SettingChanged += [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(0)] (object _, EventArgs _) => { Screenshot.instance?.OnGifResolutionChange(); }; 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<[<79c465b9-e19a-45b2-b8d4-89f0bda71d86>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<[<79c465b9-e19a-45b2-b8d4-89f0bda71d86>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.1.2", MinimumRequiredVersion = "1.1.2" }; _serverConfigLocked = null; directory = new Dir(Paths.ConfigPath, "DiscordBot"); m_instance = null; m_notificationWebhookURL = null; m_serverStartNotice = null; m_serverStopNotice = null; m_serverSaveNotice = null; m_deathNotice = null; m_loginNotice = null; m_logoutNotice = 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_screenshotDepth = null; m_screenshotGif = null; m_gifFPS = null; m_gifDuration = null; m_gifResolution = null; resolutions = new Dictionary<string, Resolution>(); } } [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(1)] [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(0)] public class Screenshot : MonoBehaviour { [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(2)] public static Screenshot instance; [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(2)] private Texture2D recordedFrame; [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(2)] private RenderTexture renderTexture; private bool isCapturing; [Header("Discord message")] private string playerName = string.Empty; private string message = string.Empty; private string thumbnail = string.Empty; [Header("GIF Settings")] private readonly List<Texture2D> recordedFrames = new List<Texture2D>(); private bool isRecording; private float recordStartTime; [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(2)] private Coroutine recordingCoroutine; [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(2)] private RenderTexture gifTexture; [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(2)] private byte[] gifBytes; private static Camera camera => Utils.GetMainCamera(); [Header("Screenshot Settings")] private static int width => DiscordBotPlugin.ScreenshotResolution.width; private static int height => DiscordBotPlugin.ScreenshotResolution.height; private static int depth => DiscordBotPlugin.ScreenshotDepth; 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() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown instance = this; renderTexture = new RenderTexture(width, height, depth); renderTexture.Create(); gifTexture = new RenderTexture(gifWidth, gifHeight, 24); gifTexture.Create(); } public void OnResolutionChange() { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown if (isCapturing) { DiscordBotPlugin.LogWarning("Bot is capturing screenshot, cannot change settings"); return; } if ((Object)(object)renderTexture != (Object)null) { renderTexture.Release(); Object.DestroyImmediate((Object)(object)renderTexture); renderTexture = null; } renderTexture = new RenderTexture(width, height, depth); renderTexture.Create(); } public void OnGifResolutionChange() { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Expected O, but got Unknown if (isRecording) { DiscordBotPlugin.LogWarning("Bot is recording GIF, cannot change settings"); return; } if ((Object)(object)gifTexture != (Object)null) { gifTexture.Release(); Object.DestroyImmediate((Object)(object)gifTexture); gifTexture = null; } gifTexture = new RenderTexture(gifWidth, gifHeight, 24); gifTexture.Create(); } public void OnDestroy() { instance = null; } private IEnumerator DelayedCaptureFrame() { yield return (object)new WaitForSeconds(DiscordBotPlugin.ScreenshotDelay); recordedFrame = Capture(); if (recordedFrame == null) { isCapturing = false; yield break; } SendToDiscord(ImageConversion.EncodeToPNG(recordedFrame)); isCapturing = false; } private Texture2D Capture() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_005d: Unknown result type (might be due to invalid IL or missing references) RenderTexture targetTexture = camera.targetTexture; camera.targetTexture = renderTexture; camera.Render(); RenderTexture.active = renderTexture; Texture2D val = new Texture2D(width, height, (TextureFormat)3, false); val.ReadPixels(new Rect(0f, 0f, (float)width, (float)height), 0, 0, false); val.Apply(); RenderTexture.active = null; camera.targetTexture = targetTexture; return val; } 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 SendToDiscord(byte[] data) { Discord.instance?.SendImageMessage(Webhook.DeathFeed, playerName, message, data, $"{DateTime.UtcNow:yyyyMMdd_HHmmss}.png", "", thumbnail); Object.DestroyImmediate((Object)(object)recordedFrame); recordedFrame = null; } private IEnumerator DelayedSelfie() { yield return (object)new WaitForSeconds(DiscordBotPlugin.ScreenshotDelay); recordedFrame = Capture(); if (recordedFrame == null) { isCapturing = false; yield break; } SendSelfieToDiscord(); isCapturing = false; } public void StartSelfie() { isCapturing = true; ((MonoBehaviour)this).StartCoroutine(DelayedSelfie()); } public void SendSelfieToDiscord() { Discord.instance?.SendImageMessage(Webhook.Chat, Player.m_localPlayer.GetPlayerName(), "Selfie!", ImageConversion.EncodeToPNG(recordedFrame), $"{DateTime.UtcNow:yyyyMMdd_HHmmss}.png"); Object.DestroyImmediate((Object)(object)recordedFrame); recordedFrame = 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 Texture2D CaptureFrame() { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_005d: Unknown result type (might be due to invalid IL or missing references) RenderTexture targetTexture = camera.targetTexture; camera.targetTexture = gifTexture; camera.Render(); RenderTexture.active = gifTexture; Texture2D val = new Texture2D(gifWidth, gifHeight, (TextureFormat)3, false); val.ReadPixels(new Rect(0f, 0f, (float)gifWidth, (float)gifHeight), 0, 0, false); val.Apply(); RenderTexture.active = null; camera.targetTexture = targetTexture; return val; } private IEnumerator Record() { float interval = 1f / (float)fps; while (isRecording && Time.time - recordStartTime < recordDuration) { recordedFrames.Add(CaptureFrame()); yield return (object)new WaitForSeconds(interval); } isRecording = false; Thread thread = new Thread(CreateGif); thread.Start(); ((MonoBehaviour)this).StartCoroutine(WaitForBytes()); } private IEnumerator WaitForBytes() { while (gifBytes == null) { yield return null; } SendGif(gifBytes); 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 (Texture2D recordedFrame in recordedFrames) { Image image = new Image(recordedFrame); image.Flip(); gIFEncoder.AddFrame(image); } gIFEncoder.Finish(); gifBytes = memoryStream.ToArray(); memoryStream.Close(); recordedFrames.Clear(); } private void SendGif(byte[] bytes) { Discord.instance?.SendGifMessage(Webhook.DeathFeed, playerName, message, bytes, $"{DateTime.UtcNow:yyyyMMdd_HHmmss}.gif", "", thumbnail); } } [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(1)] [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>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([<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(0)] () => Directory.GetFiles(Path, searchPattern, searchOption)); } public string[] GetDirectories(string searchPattern = "*") { return ExecuteWithRetry([<a3c84666-66ef-4ed1-accf-6c30be1c4e69>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([<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(0)] () => File.ReadAllText(fullPath)); } public IEnumerable<string> ReadAllLines(string fileName) { string fullPath = System.IO.Path.Combine(Path, fileName); return ExecuteWithRetry([<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(0)] () => File.ReadAllLines(fullPath)); } public bool FileExists(string fileName) { string fullPath = System.IO.Path.Combine(Path, fileName); return ExecuteWithRetry(() => File.Exists(fullPath)); } public void DeleteFile(string fileName) { string fullPath = System.IO.Path.Combine(Path, fileName); ExecuteWithRetry(delegate { if (File.Exists(fullPath)) { File.Delete(fullPath); } }); } private T ExecuteWithRetry<[<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(2)] T>(Func<T> operation) { try { return operation(); } catch (DirectoryNotFoundException) { EnsureDirectoryExists(); return operation(); } } private void ExecuteWithRetry(Action operation) { try { operation(); } catch (DirectoryNotFoundException) { EnsureDirectoryExists(); operation(); } } } [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(1)] [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(0)] public static class DeathQuips { private static readonly Dir QuipsDir = new Dir(DiscordBotPlugin.directory.Path, "Quips"); private static readonly Random random = new Random(); private static string[] Templates = new string[15] { "{player} thought they could take on {creature}{level}. They were wrong. So very wrong.", "Breaking news: {creature}{level} just turned {player} into yesterday's lunch!", "{player} has been graciously donated to the {creature}{level} retirement fund.", "RIP {player} - defeated by a {creature}{level}. We'll tell your story... if we remember it.", "{player} tried to negotiate with {creature}{level}. Negotiations failed spectacularly.", "{creature}{level} just taught {player} a valuable lesson about mortality.", "{player} is now experiencing the afterlife, courtesy of {creature}{level}.", "Darwin Award goes to {player} for challenging a {creature}{level} to single combat!", "{creature} {level} has added {player} to their collection. How thoughtful!", "{player} became {creature}'s{level} afternoon snack. Crunchy on the outside, chewy on the inside.", "Weather update: It's raining {player}, thanks to {creature}{level}!", "{player} just discovered what a {creature}{level} tastes like. Spoiler: They taste like {player}.", "{creature} {level} sends their regards to {player}'s next of kin.", "{player} has been permanently relocated by {creature}{level}. New address: The Great Beyond.", "Medical examiner's report: {player} suffered from acute {creature}{level} syndrome." }; private static string[] LowLevelInsults = new string[4] { "Imagine dying to a {creature}{level}. We're not angry, just disappointed.", "{player} was bested by a baby {creature}{level}. Let that sink in.", "A {creature}{level} just ended {player}'s whole career. Yikes.", "{player} got schooled by {creature}{level}. Time to go back to training wheels!" }; private static string[] HighLevelRespect = new string[4] { "{player} faced a legendary {creature}{level} and... well, at least they tried!", "{creature}{level} shows no mercy, not even for {player}. Respect the boss fight!", "{player} challenged a god-tier {creature}{level}. Bold strategy, poor execution.", "That {creature}{level} just reminded everyone why they're the apex predator. Sorry {player}." }; private static string[] BossDeaths = new string[3] { "{player} has been obliterated by {creature}{level}. Boss fight = Boss loss!", "{creature}{level} just demonstrated why they're called a 'boss.' {player} learned this the hard way.", "{player} thought they were ready for {creature}{level}. {creature} disagreed... violently." }; private static readonly Dictionary<HitType, string[]> deathQuips = new Dictionary<HitType, string[]> { [(HitType)3] = new string[7] { "{player} discovered gravity works. Physics: 1, {player}: 0.", "{player} tried to fly without wings. Spoiler alert: it didn't work.", "{player} has been forcibly introduced to the ground. They're getting very acquainted.", "{player} took the express route down. No stops, no survivors.", "Gravity called, {player} answered. Permanently.", "{player} forgot the first rule of holes: stop digging... or falling.", "{player} just learned why birds have wings. Too late, unfortunately." }, [(HitType)4] = new string[7] { "{player} tried to breathe water. Fish: 1, {player}: 0.", "{player} has become one with the ocean. How poetic. How dead.", "{player} discovered they're not actually part mermaid.", "{player} took 'sleeping with the fishes' a bit too literally.", "{player} forgot to bring their floaties. Critical error.", "{player} just proved that humans are terrible at being fish.", "{player} went for a swim and stayed for eternity." }, [(HitType)5] = new string[7] { "{player} was cremated without prior consent.", "{player} thought they were fire-proof. They were fire-food.", "{player} is now extra crispy. Would you like fries with that?", "{player} discovered that 'stop, drop, and roll' has a time limit.", "{player} became a human torch. Not the superhero kind.", "{player} just learned why fire safety exists.", "{player} is now well-done. Chef's kiss! \ud83d\udc80" }, [(HitType)6] = new string[7] { "{player} has been turned into a {player}-sicle.", "{player} got the ultimate brain freeze.", "{player} discovered that hypothermia isn't just a suggestion.", "{player} is now permanently chilled. Ice to meet you!", "{player} became a statue. Very artistic. Very dead.", "{player} learned that winter clothing isn't optional.", "{player} is experiencing an ice age... of one." }, [(HitType)7] = new string[7] { "{player} failed the poison taste test. Final score: Poison wins.", "{player} discovered that not all berries are friends.", "{player} has been chemically decommissioned.", "{player} took a sip from the wrong cup. Choose wisely next time!", "{player} learned why warning labels exist the hard way.", "{player} became a cautionary tale about mysterious substances.", "{player} is now immune to everything. Because they're dead." }, [(HitType)10] = new string[7] { "{player} found the edge of the world. It found them back.", "{player} tried to go where no one has gone before. There's a reason for that.", "{player} discovered that maps have boundaries for a reason.", "{player} took 'pushing the envelope' to the extreme.", "{player} has left the building... and the world... and existence.", "{player} went beyond the point of no return. Literally.", "{player} boldly went where they shouldn't have gone." }, [(HitType)11] = new string[7] { "{player} had a high-velocity meeting with something solid.", "{player} discovered the true meaning of 'sudden stop.'", "{player} became a pancake. Not the breakfast kind.", "{player} experienced physics at its most brutal.", "{player} collided with reality. Reality won.", "{player} learned that momentum isn't always your friend.", "{player} just had their final impact statement." }, [(HitType)12] = new string[7] { "{player} was run over by a cart. Talk about slow and steady losing the race.", "{player} discovered that carts have right of way. Aggressively.", "{player} became a speed bump. Permanently.", "{player} was cart-wheeled into the afterlife.", "{player} learned that carts don't brake for pedestrians.", "{player} got rolled over by the least threatening vehicle possible.", "{player} was defeated by medieval transportation. How embarrassing." }, [(HitType)13] = new string[7] { "{player} hugged a tree. The tree hugged back... harder.", "{player} became one with nature. Very one. Very nature.", "{player} discovered that trees don't move. They don't have to.", "{player} was branched out of existence.", "{player} learned that bark is worse than bite.", "{player} got rooted. Permanently.", "{player} tried to become a lumberjack. The tree disagreed." }, [(HitType)14] = new string[7] { "{player} was their own worst enemy. Literally.", "{player} achieved the ultimate self-own.", "{player} discovered friendly fire isn't very friendly.", "{player} was defeated by their greatest foe: themselves.", "{player} just pulled off the world's most elaborate suicide.", "{player} proved that sometimes you are your own problem.", "{player} achieved peak self-sabotage." }, [(HitType)15] = new string[7] { "{player} was structurally readjusted. Permanently.", "{player} discovered that buildings fight back.", "{player} became part of the architecture. Very integrated.", "{player} was demolished by demolition.", "{player} learned that load-bearing walls are serious business.", "{player} got constructed into the afterlife.", "{player} experienced aggressive urban planning." }, [(HitType)16] = new string[7] { "{player} was auto-targeted and auto-eliminated.", "{player} discovered that turrets have excellent aim.", "{player} became target practice. Final score: Turret wins.", "{player} was precision-eliminated by automated defense.", "{player} learned that turrets don't take breaks.", "{player} got schooled by a machine with no emotions.", "{player} was mechanically removed from existence." }, [(HitType)17] = new string[7] { "{player} was hit by a boat. On land. Somehow.", "{player} discovered that boats have right of way everywhere.", "{player} was sailed into the afterlife.", "{player} got boated. That's apparently a thing now.", "{player} learned that boats don't brake for pedestrians either.", "{player} was run down by the nautical express.", "{player} experienced aggressive maritime law." }, [(HitType)18] = new string[7] { "{player} was stabbed by the ceiling. Caves are rude.", "{player} discovered that nature has pointy bits.", "{player} was cave-shanked by limestone.", "{player} learned to look up the hard way.", "{player} became a geological casualty.", "{player} was speared by a very patient rock.", "{player} got the point. Literally." }, [(HitType)19] = new string[7] { "{player} was launched into the stratosphere. One-way ticket.", "{player} discovered medieval ballistics the hard way.", "{player} was trebucheted out of existence.", "{player} experienced the superior siege weapon personally.", "{player} got yeeted by ancient engineering.", "{player} was catapulted into legend. And death.", "{player} learned why catapults were weapons of war." }, [(HitType)9] = new string[7] { "{player} couldn't see through the smoke screen. Permanently.", "{player} was smoked out of existence.", "{player} discovered that smoke inhalation isn't a joke.", "{player} got lost in the smoke and never found their way back.", "{player} was fog-banked into the afterlife.", "{player} couldn't clear the air in time.", "{player} became a smokehouse casualty." }, [(HitType)8] = new string[7] { "{player} was hydro-pressured into submission.", "{player} discovered that water can be violent.", "{player} was liquidated. Literally.", "{player} learned that H2O can be H2-NO.", "{player} was swept away by aquatic aggression.", "{player} experienced water pressure personally.", "{player} got tide-rolled into oblivion." }, [(HitType)20] = new string[7] { "{player} was cinder-blocked from life.", "{player} discovered that cinder fire burns differently. Deadlier.", "{player} was ash-ified by superior flames.", "{player} learned about advanced pyrotechnics the hard way.", "{player} was upgraded from regular fire to premium fire.", "{player} experienced fire 2.0. It's an improvement. For the fire.", "{player} was incinerated by artisanal flames." }, [(HitType)21] = new string[7] { "{player} discovered that Ashlands water isn't refreshing.", "{player} went for a swim in liquid doom.", "{player} learned that not all oceans are created equal.", "{player} was dissolved by the most unfriendly sea.", "{player} took a bath in liquid nightmares.", "{player} discovered the ocean of nope.", "{player} went swimming and became soup." }, [(HitType)0] = new string[7] { "{player} died to... something. We're not quite sure what.", "{player} was eliminated by mysterious circumstances.", "{player} discovered an unknown way to die. Congratulations?", "{player} was removed from existence by undefined means.", "{player} achieved death through unknown methods. Innovative!", "{player} died in a way that defies classification.", "{player} was killed by the universe's debugging process." } }; public static string GenerateDeathQuip(string playerName, string creatureName, int creatureLevel, bool isBoss = false) { string[] array = (isBoss ? BossDeaths : ((creatureLevel <= 5) ? LowLevelInsults : ((creatureLevel < 50) ? Templates : HighLevelRespect))); string text = array[random.Next(array.Length)]; string newValue = ((creatureLevel > 1) ? (" " + new string('★', creatureLevel - 1)) : ""); return text.Replace("{player}", playerName).Replace("{creature}", creatureName).Replace("{level}", newValue); } public static string GenerateContextualQuip(string playerName, string creatureName, int creatureLevel, string prefabID = "") { string text = GenerateDeathQuip(playerName, creatureName, creatureLevel); if (1 == 0) { } string text2 = prefabID switch { "Blob" => " At least it was squishy!", "Dragon" => " Well, that escalated quickly.", "Skeleton" => " Bone-chilling performance!", "Draugr" => " Braaaaains... or lack thereof.", "Wolf" => " Should've brought a bigger stick.", "Bjorn" => " Hibernation is over, apparently.", "Goblin" => " Size doesn't matter, apparently.", _ => "", }; if (1 == 0) { } string text3 = text2; return text + text3; } public static string GenerateEnvironmentalQuip(string playerName, HitType hitType) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (!deathQuips.TryGetValue(hitType, out var value)) { return playerName + " died in a way that words cannot describe. How mysterious..."; } string text = value[random.Next(value.Length)]; return text.Replace("{player}", playerName); } public static void Setup() { //IL_00cb: Unknown result type (might be due to invalid IL or missing references) string[] files = QuipsDir.GetFiles(".txt", includeSubDirs: true); if (files.Length == 0) { Write(); } else { string[] array = files; foreach (string path in array) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path); string[] array2 = File.ReadAllLines(path); switch (fileNameWithoutExtension) { case "Templates": Templates = array2; continue; case "LowLevelInsults": LowLevelInsults = array2; continue; case "HighLevelRespect": HighLevelRespect = array2; continue; case "BossDeaths": BossDeaths = array2; continue; } if (Enum.TryParse<HitType>(fileNameWithoutExtension, ignoreCase: true, out HitType result)) { deathQuips[result] = array2; } } } FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(QuipsDir.Path, "*.txt"); fileSystemWatcher.EnableRaisingEvents = true; fileSystemWatcher.IncludeSubdirectories = true; fileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite; fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; fileSystemWatcher.Changed += OnChanged; fileSystemWatcher.Created += OnChanged; } private static void OnChanged(object sender, FileSystemEventArgs e) { //IL_008e: Unknown result type (might be due to invalid IL or missing references) string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(e.FullPath); string[] array = File.ReadAllLines(e.FullPath); switch (fileNameWithoutExtension) { case "Templates": Templates = array; return; case "LowLevelInsults": LowLevelInsults = array; return; case "HighLevelRespect": HighLevelRespect = array; return; case "BossDeaths": BossDeaths = array; return; } if (Enum.TryParse<HitType>(fileNameWithoutExtension, ignoreCase: true, out HitType result)) { deathQuips[result] = array; } } private static void Write() { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) QuipsDir.WriteAllLines("Templates.txt", Templates.ToList()); QuipsDir.WriteAllLines("LowLevelInsults.txt", LowLevelInsults.ToList()); QuipsDir.WriteAllLines("HighLevelRespect.txt", HighLevelRespect.ToList()); QuipsDir.WriteAllLines("BossDeaths.txt", BossDeaths.ToList()); foreach (KeyValuePair<HitType, string[]> deathQuip in deathQuips) { Dir quipsDir = QuipsDir; HitType key = deathQuip.Key; quipsDir.WriteAllLines(((object)(HitType)(ref key)).ToString() + ".txt", deathQuip.Value.ToList()); } } } [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(0)] [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(2)] public class DiscordGatewayClient : MonoBehaviour { [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(0)] [HarmonyPatch(typeof(ZNet), "Awake")] private static class ZNet_Awake_Patch { [UsedImplicitly] [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(1)] private static void Postfix(ZNet __instance) { if (__instance.IsServer()) { ((Component)DiscordBotPlugin.m_instance).gameObject.AddComponent<DiscordGatewayClient>(); } } } [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(1)] [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(0)] private class PriorityQueue<[<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(2)] T> { private readonly Queue<T> highPriority = new Queue<T>(); private readonly Queue<T> normalPriority = new Queue<T>(); public int Count => highPriority.Count + normalPriority.Count; public void Enqueue(T item, bool priority = false) { DiscordGatewayClient instance = DiscordGatewayClient.instance; if (instance == null || instance.isConnected) { if (priority) { highPriority.Enqueue(item); } else { normalPriority.Enqueue(item); } DiscordGatewayClient.instance?.TriggerProcessing(); } } public T Dequeue() { return (highPriority.Count > 0) ? highPriority.Dequeue() : normalPriority.Dequeue(); } public void Clear() { highPriority.Clear(); normalPriority.Clear(); } } [Serializable] [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(0)] public class GatewayEvent { public int op; public JObject d; public int? s; public string t; } [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(0)] [UsedImplicitly] public enum Opcodes { Dispatch = 0, Heartbeat = 1, Identify = 2, PresenceUpdate = 3, VoiceStateUpdate = 4, Resume = 6, Reconnect = 7, RequestGuildMembers = 8, InvalidSession = 9, Hello = 10, HeartbeatOK = 11, RequestSoundboardSounds = 31 } [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(0)] [UsedImplicitly] public enum Intent { Guilds = 1, GuildMessages = 0x200, MessageContent = 0x8000 } [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(1)] private static readonly JsonSerializerSettings settings = new JsonSerializerSettings { MissingMemberHandling = (MissingMemberHandling)0, NullValueHandling = (NullValueHandling)1, Error = [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(0)] (object _, [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(1)] ErrorEventArgs args) => { args.ErrorContext.Handled = true; } }; public static DiscordGatewayClient instance; private const int BUFFER_SIZE = 16384; private ClientWebSocket websocket; private CancellationTokenSource cancellationTokenSource; private string gatewayUrl; private int sequenceNumber; private string sessionId; private bool heartbeatAcknowledged = true; private Coroutine heartbeatCoroutine; private bool isConnecting; private bool isConnected; private bool shouldReconnect = true; [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(1)] private readonly PriorityQueue<object> messageQueue = new PriorityQueue<object>(); private bool isSending; [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(1)] private static readonly WaitForSeconds processMessageRate = new WaitForSeconds(0.1f); [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(1)] private static readonly WaitForSeconds retryConnectionDelay = new WaitForSeconds(5f); [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(new byte[] { 2, 1 })] [method: <79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(new byte[] { 2, 1 })] [field: <79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(new byte[] { 2, 1 })] public event Action<Message> OnChatReceived; [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(new byte[] { 2, 1 })] [method: <79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(new byte[] { 2, 1 })] [field: <79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(new byte[] { 2, 1 })] public event Action<Message> OnCommandReceived; [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(new byte[] { 2, 1 })] [method: <79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(new byte[] { 2, 1 })] [field: <79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(new byte[] { 2, 1 })] public event Action<string> OnError; public event Action OnConnected; public event Action OnDisconnected; [<79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(new byte[] { 2, 1 })] [method: <79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(new byte[] { 2, 1 })] [field: <79c465b9-e19a-45b2-b8d4-89f0bda71d86>Nullable(new byte[] { 2, 1 })] public event Action<string> OnClosed; public void Awake() { instance = this; OnChatReceived += HandleChatMessage; OnCommandReceived += HandleCommands; OnError += HandleError; OnClosed += DiscordBotPlugin.LogDebug; OnConnected += delegate { DiscordBotPlugin.LogDebug("Connected to discord gateway"); }; OnDisconnected += delegate { DiscordBotPlugin.LogDebug("Disconnected from discord gateway"); }; } [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(1)] private static void HandleError(string message) { if (DiscordBotPlugin.LogErrors) { DiscordBotPlugin.LogWarning(message); } } [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(1)] private static void HandleChatMessage(Message message) { Discord.instance?.BroadcastMessage(message.author?.GetDisplayName() ?? "", message.content ?? ""); if (Object.op_Implicit((Object)(object)Player.m_localPlayer)) { Discord.DisplayChatMessage(message.author?.GetDisplayName() ?? "", message?.content ?? ""); } } [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(1)] private static void HandleCommands(Message message) { if (message.content != null) { string[] array = message.content.Split(new char[1] { ' ' }); string text = array[0].Trim(); if (!DiscordCommands.m_commands.TryGetValue(text, out var value)) { Discord.instance?.SendMessage(Webhook.Commands, ZNet.instance.GetWorldName(), "Failed to find command: " + text); } else if (!value.IsAllowed(message.author?.GetFullUsername() ?? "")) { Discord.instance?.SendMessage(Webhook.Commands, ZNet.instance.GetWorldName(), message.author?.GetFullUsername() + " not allowed to use command: " + text); } else { value.Run(array); } } } public void TriggerProcessing() { if (!isSending && messageQueue.Count > 0) { isSending = true; ((MonoBehaviour)this).StartCoroutine(ProcessMessageQueue()); } } [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(1)] private IEnumerator ProcessMessageQueue() { while (messageQueue.Count > 0 && isConnected) { object message = messageQueue.Dequeue(); yield return SendGatewayMessage(message); yield return processMessageRate; } isSending = false; } private void Start() { if (string.IsNullOrEmpty(DiscordBotPlugin.BOT_TOKEN)) { DiscordBotPlugin.LogWarning("Bot token not set"); } else { ((MonoBehaviour)this).StartCoroutine(InitializeGateway()); } } private void OnDestroy() { shouldReconnect = false; DisconnectWebSocket(); instance = null; } [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(1)] private IEnumerator InitializeGateway() { if (isConnecting || isConnected) { yield break; } isConnecting = true; UnityWebRequest request = UnityWebRequest.Get("https://discord.com/api/v10/gateway/bot"); try { request.SetRequestHeader("Authorization", "Bot " + DiscordBotPlugin.BOT_TOKEN); request.SetRequestHeader("Content-Type", "application/json"); yield return request.SendWebRequest(); if ((int)request.result == 1) { JObject response = JObject.Parse(request.downloadHandler.text); gatewayUrl = ((object)response["url"])?.ToString() ?? string.Empty; if (!string.IsNullOrEmpty(gatewayUrl)) { gatewayUrl += "/?v=10&encoding=json"; yield return ((MonoBehaviour)this).StartCoroutine(ConnectToGateway()); } else { this.OnError?.Invoke("Failed to get gateway URL"); isConnecting = false; } } else { this.OnError?.Invoke("Failed to get gateway URL: " + request.error); isConnecting = false; yield return retryConnectionDelay; if (shouldReconnect) { ((MonoBehaviour)this).StartCoroutine(InitializeGateway()); } } } finally { ((IDisposable)request)?.Dispose(); } } [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(1)] private IEnumerator ConnectToGateway() { websocket = new ClientWebSocket(); cancellationTokenSource = new CancellationTokenSource(); Task connectTask = websocket.ConnectAsync(new Uri(gatewayUrl ?? ""), cancellationTokenSource.Token); yield return (object)new WaitUntil((Func<bool>)(() => connectTask.IsCompleted)); if (connectTask.Status == TaskStatus.RanToCompletion) { isConnected = true; isConnecting = false; ((MonoBehaviour)this).StartCoroutine(ListenForMessages()); } else if (connectTask.Status == TaskStatus.Canceled) { this.OnClosed?.Invoke("Connection task canceled"); isConnecting = false; } else if (connectTask.Status == TaskStatus.Faulted) { this.OnError?.Invoke("Failed to connect: " + connectTask.Exception?.GetBaseException().Message); isConnecting = false; if (shouldReconnect) { ((MonoBehaviour)this).StartCoroutine(ReconnectAfterDelay()); } } else { this.OnError?.Invoke("Failed to connect: " + connectTask.Exception?.GetBaseException().Message); isConnecting = false; } } [<a3c84666-66ef-4ed1-accf-6c30be1c4e69>NullableContext(1)] private IEnumerator ListenForMessages() { byte[] buffer =