Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of DiscordBot AWL v1.4.0
DiscordBot.dll
Decompiled 2 hours 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 DiscordBot.Jobs; using DiscordBot.Notices; using HarmonyLib; using JetBrains.Annotations; using LocalizationManager; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; using ServerSync; using TMPro; using UnityEngine; using UnityEngine.Networking; using UnityEngine.UI; using uGIF; [assembly: AssemblyTrademark("")] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("DiscordBot")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("RustyMods")] [assembly: AssemblyProduct("DiscordBot")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: ComVisible(false)] [assembly: Guid("4358610B-F3F4-4843-B7AF-98B7BC60DCDE")] [assembly: AssemblyFileVersion("1.4.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: CompilationRelaxations(8)] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.4.0.0")] [module: UnverifiableCode] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [<d7a5d9a4-7ca2-47a3-9182-b7be8e207ba6>Embedded] internal sealed class <d7a5d9a4-7ca2-47a3-9182-b7be8e207ba6>EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] [<d7a5d9a4-7ca2-47a3-9182-b7be8e207ba6>Embedded] internal sealed class <5cd3367d-3f18-4efd-8d81-d072213732ed>NullableAttribute : Attribute { public readonly byte[] NullableFlags; public <5cd3367d-3f18-4efd-8d81-d072213732ed>NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public <5cd3367d-3f18-4efd-8d81-d072213732ed>NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [<d7a5d9a4-7ca2-47a3-9182-b7be8e207ba6>Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] [CompilerGenerated] internal sealed class <226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContextAttribute : Attribute { public readonly byte Flag; public <226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace uGIF { [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(1)] [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(0)] public class GIFEncoder { public bool useGlobalColorTable; public Color32? transparent; public int repeat = -1; public int dispose = -1; public int quality = 10; private int delay; private int width; private int height; private int transIndex; private bool started; 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_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013c: 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_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0011: 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) 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() { new LZWEncoder(width, height, indexedPixels, colorDepth).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]); } } } [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(0)] [<226ca976-6ae0-4386-814c-a218f6c5d69a>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(Color32[] pixels, int width, int height) { this.pixels = pixels; this.width = width; this.height = height; } public Image(int width, int height) { this.width = width; this.height = height; pixels = (Color32[])(object)new Color32[width * height]; } public void DrawImage(Image image, int i, int i2) { throw new NotImplementedException(); } public Color32 GetPixel(int tw, int th) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) int num = th * width + tw; return pixels[num]; } public void Flip() { //IL_002e: 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0056: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: 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_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: 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)); } } [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(1)] [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(0)] 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; private bool clear_flg; private int g_init_bits; private int ClearCode; private int EOFCode; private int cur_accum; private int cur_bits; 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_0121; } num = codetab[num6]; continue; } goto IL_0121; IL_0121: 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)(cur_accum & 0xFF), 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)(cur_accum & 0xFF), outs); cur_accum >>= 8; cur_bits -= 8; } Flush(outs); } } } [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(1)] [<5cd3367d-3f18-4efd-8d81-d072213732ed>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[] obj = network[i]; int num4 = obj[0] - b; if (num4 < 0) { num4 = -num4; } int num5 = obj[1] - g; if (num5 < 0) { num5 = -num5; } num4 += num5; num5 = obj[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 { [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(1)] [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(0)] [PublicAPI] 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; [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(2)] private static BaseUnityPlugin _plugin; private static readonly List<string> fileExtensions; private static BaseUnityPlugin plugin { get { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: 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([<226ca976-6ae0-4386-814c-a218f6c5d69a>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, [<226ca976-6ae0-4386-814c-a218f6c5d69a>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, [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(new byte[] { 2, 1, 1 })] Func<T, string> convertConfigValue = null) { if (convertConfigValue == null) { convertConfigValue = (T val) => val.ToString(); } if (!PlaceholderProcessors.ContainsKey(key)) { PlaceholderProcessors[key] = new Dictionary<string, Func<string>>(); } config.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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" }; new Harmony("org.bepinex.helpers.LocalizationManager").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: <5cd3367d-3f18-4efd-8d81-d072213732ed>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; } [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(2)] public static byte[] ReadEmbeddedFileBytes([<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(1)] string resourceFileName, Assembly containingAssembly = null) { using MemoryStream memoryStream = new MemoryStream(); if ((object)containingAssembly == null) { containingAssembly = Assembly.GetCallingAssembly(); } string text = containingAssembly.GetManifestResourceNames().FirstOrDefault([<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (string str) => str.EndsWith(resourceFileName, StringComparison.Ordinal)); if (text != null) { containingAssembly.GetManifestResourceStream(text)?.CopyTo(memoryStream); } return (memoryStream.Length == 0L) ? null : memoryStream.ToArray(); } } } namespace DiscordBot { [PublicAPI] [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(0)] [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(1)] public static class API { public static List<Action> m_queue = new List<Action>(); public static void RegisterCommand(string command, string description, [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(new byte[] { 2, 1, 1 })] Action<string[]> action, [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(new byte[] { 2, 1 })] Action<ZPackage> reaction, bool adminOnly, bool isSecret, string emoji) { if (DiscordCommands.loaded) { if (!DiscordCommands.m_commands.ContainsKey(command)) { new DiscordCommands.DiscordCommand(command, description, action, reaction, adminOnly, isSecret, emoji); } return; } m_queue.Add(delegate { if (!DiscordCommands.m_commands.ContainsKey(command)) { new DiscordCommands.DiscordCommand(command, description, action, reaction, adminOnly, isSecret, emoji); } }); } public static void SendWebhookMessage(string channel, string message) { switch (channel.ToLower()) { case "notifications": Discord.instance?.SendMessage(Webhook.Notifications, "", message); break; case "chat": Discord.instance?.SendMessage(Webhook.Chat, "", message); break; case "commands": Discord.instance?.SendMessage(Webhook.Commands, "", message); break; } } public static void SendWebhookTable(string channel, string title, Dictionary<string, string> tableData) { switch (channel.ToLower()) { case "notifications": Discord.instance?.SendTableEmbed(Webhook.Notifications, title, tableData); break; case "chat": Discord.instance?.SendTableEmbed(Webhook.Chat, title, tableData); break; case "commands": Discord.instance?.SendTableEmbed(Webhook.Commands, title, tableData); break; } } public static void SendNotification(string message) { Discord.instance?.SendMessage(Webhook.Notifications, message); } public static void SendChat(string message) { Discord.instance?.SendMessage(Webhook.Chat, message); } public static void SendCommandMessage(string message) { Discord.instance?.SendMessage(Webhook.Commands, message); } } [PublicAPI] [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(0)] [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(1)] public static class DiscordBot_API { [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] [PublicAPI] public enum Channel { Notifications, Chat, Commands } [<5cd3367d-3f18-4efd-8d81-d072213732ed>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>(); [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(2)] private readonly MethodInfo info; [return: <5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(new byte[] { 1, 2 })] public object[] Invoke([<5cd3367d-3f18-4efd-8d81-d072213732ed>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, [<5cd3367d-3f18-4efd-8d81-d072213732ed>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(); } } [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(2)] private static readonly Method _RegisterCommand; [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(2)] private static readonly Method _SendWebhookMessage; [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(2)] private static readonly Method _SendWebhookTable; private static readonly Dictionary<string, string> Emojis; public static bool IsLoaded() { return Type.GetType("DiscordBot.API, DiscordBot") != null; } static DiscordBot_API() { 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" } }; if (IsLoaded()) { _RegisterCommand = new Method("RegisterCommand"); _SendWebhookMessage = new Method("SendWebhookMessage"); _SendWebhookTable = new Method("SendWebhookTable"); } } public static void SendWebhookMessage(Channel channel, string message) { _SendWebhookMessage?.Invoke(channel.ToString(), message); } public static void SendWebhookTable(Channel channel, string title, Dictionary<string, string> tableData) { _SendWebhookTable?.Invoke(channel.ToString(), title, tableData); } public static void RegisterCommand(string command, string description, Action<string[]> action, [<5cd3367d-3f18-4efd-8d81-d072213732ed>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); } } [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(0)] [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(1)] public static class Extensions { public static string ToURL(this Webhook type) { return type switch { Webhook.Chat => DiscordBotPlugin.ChatWebhookURL, Webhook.Notifications => DiscordBotPlugin.NoticeWebhookURL, Webhook.Commands => DiscordBotPlugin.CommandWebhookURL, Webhook.DeathFeed => DiscordBotPlugin.DeathFeedWebhookURL, _ => DiscordBotPlugin.ChatWebhookURL, }; } public static string ToID(this Channel type) { return type switch { Channel.Chat => DiscordBotPlugin.ChatChannelID, Channel.Commands => DiscordBotPlugin.CommandChannelID, _ => DiscordBotPlugin.ChatChannelID, }; } public static T GetOrAddComponent<[<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(0)] T>(this GameObject obj) where T : Component { T result = default(T); if (!obj.TryGetComponent<T>(ref result)) { return obj.AddComponent<T>(); } 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 } [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(0)] [BepInPlugin("RustyMods.DiscordBot", "DiscordBot", "1.4.0")] [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(1)] public class DiscordBotPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(ZNet), "Awake")] [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] private static class ZNet_Awake_Patch { [UsedImplicitly] [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(1)] private static void Postfix(ZNet __instance) { ((Component)m_instance).gameObject.GetOrAddComponent<Discord>(); ((Component)m_instance).gameObject.GetOrAddComponent<Screenshot>(); ((Component)m_instance).gameObject.GetOrAddComponent<Recorder>(); ((Component)m_instance).gameObject.GetOrAddComponent<ChatAI>(); if (__instance.IsServer()) { ((Component)m_instance).gameObject.GetOrAddComponent<DiscordGatewayClient>(); ((Component)m_instance).gameObject.GetOrAddComponent<JobManager>(); UpdateServerAIKeys(); UpdateServerAIOption(); UpdateServerWebhooks(); } } } [<5cd3367d-3f18-4efd-8d81-d072213732ed>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_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Expected O, but got Unknown //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Expected O, but got Unknown bool valueOrDefault = cfg.Description.Tags.Select([<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object a) => (!(a.GetType().Name == "ConfigurationManagerAttributes")) ? ((bool?)null) : ((bool?)a.GetType().GetField("ReadOnly")?.GetValue(a))).FirstOrDefault((bool? v) => v.HasValue) == true; 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); } } [<226ca976-6ae0-4386-814c-a218f6c5d69a>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; } [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(1)] public sealed override string ToString() { return $"{width}x{height}"; } } [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] public class ConfigurationManagerAttributes { [UsedImplicitly] public int? Order; [UsedImplicitly] public bool? Browsable; [UsedImplicitly] [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(2)] public string Category; [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(new byte[] { 2, 1 })] [UsedImplicitly] public Action<ConfigEntryBase> CustomDrawer; } [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(0)] public class ServerWebhooks { public readonly string notifications = ""; public readonly string commands = ""; public readonly string chat = ""; public readonly string death = ""; public readonly string start = ""; public readonly string save = ""; public readonly string shutdown = ""; public readonly string login = ""; public readonly string logout = ""; public readonly string events = ""; public readonly string newDay = ""; public readonly string useCommands = ""; public readonly string boss = ""; public ServerWebhooks() { } public ServerWebhooks(string notifications, string commands, string chat, string death, string start, string save, string shutdown, string login, string logout, string events, string newDay, string useCommands, string boss) { this.notifications = notifications; this.commands = commands; this.chat = chat; this.death = death; this.start = start; this.save = save; this.shutdown = shutdown; this.login = login; this.logout = logout; this.events = events; this.newDay = newDay; this.useCommands = useCommands; this.boss = boss; } public ServerWebhooks(string configs) { string[] array = configs.Split(new char[1] { ';' }); if (array.Length >= 13) { notifications = array[0]; commands = array[1]; chat = array[2]; death = array[3]; start = array[4]; save = array[5]; shutdown = array[6]; login = array[7]; logout = array[8]; events = array[9]; newDay = array[10]; useCommands = array[11]; boss = array[12]; } } public override string ToString() { return notifications + ";" + commands + ";" + chat + ";" + death + ";" + start + ";" + save + ";" + shutdown + ";" + login + ";" + logout + ";" + events + ";" + newDay + ";" + useCommands + ";" + boss; } } [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(0)] public class ServerKeys { public readonly string ChatGPT = ""; public readonly string Gemini = ""; public readonly string DeepSeek = ""; public readonly string OpenRouter = ""; public ServerKeys() { } public ServerKeys(string ChatGPT, string Gemini, string DeepSeek, string OpenRouter) { this.ChatGPT = ChatGPT; this.Gemini = Gemini; this.DeepSeek = DeepSeek; this.OpenRouter = OpenRouter; } public ServerKeys(string keys) { string[] array = keys.Split(new char[1] { ';' }); if (array.Length >= 4) { ChatGPT = array[0]; Gemini = array[1]; DeepSeek = array[2]; OpenRouter = array[3]; } } public override string ToString() { return ChatGPT + ";" + Gemini + ";" + DeepSeek + ";" + OpenRouter; } } [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(0)] public class ServerAIOption { public readonly AIService service = AIService.Gemini; public readonly OpenRouterModel openRouterModel; public readonly GeminiModel geminiModel = GeminiModel.Flash3_6; public readonly bool serverAIAvailable; public ServerAIOption() { } public ServerAIOption(string config) { string[] array = config.Split(new char[1] { ';' }); if (array.Length >= 3) { Enum.TryParse<AIService>(array[0], ignoreCase: true, out service); Enum.TryParse<OpenRouterModel>(array[1], ignoreCase: true, out openRouterModel); Enum.TryParse<GeminiModel>(array[2], ignoreCase: true, out geminiModel); if (array.Length >= 4) { bool.TryParse(array[3], out serverAIAvailable); } } } public ServerAIOption(AIService service, OpenRouterModel openRouterModel, GeminiModel geminiModel, bool serverAIAvailable) { this.service = service; this.openRouterModel = openRouterModel; this.geminiModel = geminiModel; this.serverAIAvailable = serverAIAvailable; } public override string ToString() { return $"{service};{openRouterModel};{geminiModel};{serverAIAvailable}"; } } [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(0)] public class Record { private readonly List<string> logs = new List<string>(); public void Log(LogLevel level, string log) { //IL_0015: 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) //IL_0028: Invalid comparison between Unknown and I4 //IL_004a: 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) logs.Add($"[{DateTime.Now:HH:mm:ss}][{level}]: {log}"); if ((int)level == 2) { if (LogErrors) { DiscordBotLogger.Log(level, (object)log); } } else if (ShowDetailedLogs) { DiscordBotLogger.Log(level, (object)log); } } public void Write() { directory.WriteAllLines("RustyMods.DiscordBot.log", logs); } } internal const string ModName = "DiscordBot"; internal const string ModVersion = "1.4.0"; internal const string Author = "RustyMods"; private const string ModGUID = "RustyMods.DiscordBot"; private const string ConfigFileName = "RustyMods.DiscordBot.cfg"; private static readonly string ConfigFileFullPath; internal static string ConnectionError; private readonly Harmony _harmony = new Harmony("RustyMods.DiscordBot"); public static readonly ManualLogSource DiscordBotLogger; private static readonly ConfigSync ConfigSync; public static readonly Dir directory; public static DiscordBotPlugin m_instance; private static ConfigEntry<Toggle> _serverConfigLocked; private static ConfigEntry<string> m_startWorldHook; private static ConfigEntry<string> m_saveWebhook; private static ConfigEntry<string> m_shutdownWebhook; private static ConfigEntry<string> m_loginWebhook; private static ConfigEntry<string> m_logoutWebhook; private static ConfigEntry<string> m_eventWebhook; private static ConfigEntry<string> m_newDayWebhook; private static ConfigEntry<string> m_useCommandWebhook; private static ConfigEntry<string> m_bossWebhook; private static ConfigEntry<string> m_notificationWebhookURL; private static ConfigEntry<Toggle> m_serverStartNotice; private static ConfigEntry<Toggle> m_serverStopNotice; private static ConfigEntry<Toggle> m_serverSaveNotice; private static ConfigEntry<Toggle> m_deathNotice; private static ConfigEntry<Toggle> m_loginNotice; private static ConfigEntry<Toggle> m_logoutNotice; private static ConfigEntry<Toggle> m_eventNotice; private static ConfigEntry<Toggle> m_newDayNotice; private static ConfigEntry<Toggle> m_coordinateDetails; private static ConfigEntry<Toggle> m_commandNotice; private static ConfigEntry<Toggle> m_showServerDetails; private static ConfigEntry<Toggle> m_showBossDeath; 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_showDetailedLogs; private static ConfigEntry<Toggle> m_screenshotDeath; private static ConfigEntry<float> m_screenshotDelay; private static ConfigEntry<string> m_screenshotResolution; private static ConfigEntry<Toggle> m_screenshotGif; private static ConfigEntry<int> m_gifFPS; private static ConfigEntry<float> m_gifDuration; private static ConfigEntry<string> m_gifResolution; private static ConfigEntry<KeyCode> m_selfieKey; private static ConfigEntry<AIService> m_aiService; private static ConfigEntry<string> m_chatGPTAPIKEY; private static ConfigEntry<string> m_geminiAPIKEY; private static ConfigEntry<GeminiModel> m_geminiModel; private static ConfigEntry<string> m_deepSeekAPIKEY; private static ConfigEntry<string> m_openRouterAPIKEY; private static ConfigEntry<OpenRouterModel> m_openRouterModel; private static ConfigEntry<Toggle> m_useServerKeys; private static readonly CustomSyncedValue<string> m_serverKeys; private static readonly CustomSyncedValue<string> m_serverOptions; private static ConfigEntry<Toggle> m_allowDiscordPrompt; private static ConfigEntry<Toggle> m_improveDeathQuips; private static ConfigEntry<Toggle> m_improveDayQuips; private static ConfigEntry<string> m_aiProviderOrder; private static ConfigEntry<string> m_geminiModels; private static ConfigEntry<Toggle> m_geminiAutoDiscover; private static ConfigEntry<string> m_openRouterModels; private static ConfigEntry<Toggle> m_openRouterAutoDiscover; private static ConfigEntry<Toggle> m_openRouterFreeOnly; private static ConfigEntry<string> m_openAIModels; private static ConfigEntry<string> m_deepSeekModels; private static ConfigEntry<int> m_aiMaxAttempts; private static ConfigEntry<int> m_aiModelsPerProvider; private static ConfigEntry<int> m_aiRequestTimeoutSeconds; private static ConfigEntry<int> m_aiCatalogCacheMinutes; private static ConfigEntry<int> m_aiMaxOutputTokens; private static ConfigEntry<int> m_aiMaxPromptCharacters; private static ConfigEntry<float> m_aiRemoteRequestCooldown; private static ConfigEntry<int> m_aiRemoteResponseTimeoutSeconds; private static ConfigEntry<Toggle> m_serverAIBroker; private static ConfigEntry<Toggle> m_allowPlayerAIPrompts; private static ConfigEntry<Toggle> m_enableJobs; private static readonly Dictionary<string, Resolution> resolutions; private static readonly CustomSyncedValue<string> ServerSyncedWebhooks; private static ServerKeys SyncedAIKeys; private static ServerAIOption SyncedAIOption; private static ServerWebhooks SyncedWebhooks; public static readonly Record records; public static bool ShowServerStart => m_serverStartNotice.Value == Toggle.On; public static bool ShowBossDeath => m_showBossDeath.Value == Toggle.On; public static bool ShowServerDetails => m_showServerDetails.Value == Toggle.On; public static bool ShowChat => m_chatEnabled.Value == Toggle.On; private static bool LogErrors => m_logErrors.Value == Toggle.On; public static bool ShowServerStop => m_serverStopNotice.Value == Toggle.On; public static bool ShowServerSave => m_serverSaveNotice.Value == Toggle.On; public static bool ShowOnDeath => m_deathNotice.Value == Toggle.On; public static bool ShowOnLogin => m_loginNotice.Value == Toggle.On; public static bool ShowOnLogout => m_logoutNotice.Value == Toggle.On; public static bool ShowEvent => m_eventNotice.Value == Toggle.On; public static bool ShowNewDay => m_newDayNotice.Value == Toggle.On; public static bool ShowCoordinates => m_coordinateDetails.Value == Toggle.On; private static bool ShowDetailedLogs => m_showDetailedLogs.Value == Toggle.On; public static bool ShowCommandUse => m_commandNotice.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 => SyncedWebhooks.chat; public static string CommandWebhookURL => SyncedWebhooks.commands; public static string NoticeWebhookURL => SyncedWebhooks.notifications; public static string DeathFeedWebhookURL => SyncedWebhooks.death; public static bool ScreenshotDeath => m_screenshotDeath.Value == Toggle.On; public static bool ScreenshotGif => m_screenshotGif.Value == Toggle.On; public static float ScreenshotDelay => m_screenshotDelay.Value; public static int GIF_FPS => m_gifFPS.Value; public static float GIF_DURATION => m_gifDuration.Value; public static Resolution ScreenshotResolution => resolutions[m_screenshotResolution.Value]; public static Resolution GifResolution => resolutions[m_gifResolution.Value]; public static KeyCode SelfieKey => m_selfieKey.Value; public static AIService AIService => m_aiService.Value; private static string ChatGPT_KEY => m_chatGPTAPIKEY.Value; private static string Gemini_KEY => m_geminiAPIKEY.Value; private static string DeepSeek_KEY => m_deepSeekAPIKEY.Value; private static string OpenRouter_KEY => m_openRouterAPIKEY.Value; private static bool UseServerKeys => m_useServerKeys.Value == Toggle.On; private static OpenRouterModel OpenRouterModel => m_openRouterModel.Value; private static GeminiModel GeminiModel => m_geminiModel.Value; public static bool AllowDiscordPrompt => m_allowDiscordPrompt.Value == Toggle.On; public static bool ImproveDeathQuips => m_improveDeathQuips.Value == Toggle.On; public static bool ImproveDayQuips => m_improveDayQuips.Value == Toggle.On; public static bool GeminiAutoDiscover => m_geminiAutoDiscover.Value == Toggle.On; public static bool OpenRouterAutoDiscover => m_openRouterAutoDiscover.Value == Toggle.On; public static bool OpenRouterFreeOnly => m_openRouterFreeOnly.Value == Toggle.On; public static bool ServerAIBrokerEnabled => m_serverAIBroker.Value == Toggle.On; public static bool AllowPlayerAIPrompts => m_allowPlayerAIPrompts.Value == Toggle.On; public static int AIMaxAttempts => Math.Max(1, m_aiMaxAttempts.Value); public static int AIModelsPerProvider => Math.Max(1, m_aiModelsPerProvider.Value); public static int AIRequestTimeoutSeconds => Math.Max(1, m_aiRequestTimeoutSeconds.Value); public static int AICatalogCacheMinutes => Math.Max(1, m_aiCatalogCacheMinutes.Value); public static int AIMaxOutputTokens => Math.Max(8, m_aiMaxOutputTokens.Value); public static int AIMaxPromptCharacters => Math.Max(128, m_aiMaxPromptCharacters.Value); public static float AIRemoteRequestCooldown => Math.Max(0f, m_aiRemoteRequestCooldown.Value); public static int AIRemoteResponseTimeoutSeconds => Math.Max(10, m_aiRemoteResponseTimeoutSeconds.Value); public static List<string> OnWorldStartHooks { get { if (!Utility.IsNullOrWhiteSpace(SyncedWebhooks.start)) { return new StringListConfig(SyncedWebhooks.start).list; } return new List<string>(); } } public static List<string> OnWorldSaveHooks { get { if (!Utility.IsNullOrWhiteSpace(SyncedWebhooks.save)) { return new StringListConfig(SyncedWebhooks.save).list; } return new List<string>(); } } public static List<string> OnWorldShutdownHooks { get { if (!Utility.IsNullOrWhiteSpace(SyncedWebhooks.shutdown)) { return new StringListConfig(SyncedWebhooks.shutdown).list; } return new List<string>(); } } public static List<string> OnLoginHooks { get { if (!Utility.IsNullOrWhiteSpace(SyncedWebhooks.login)) { return new StringListConfig(SyncedWebhooks.login).list; } return new List<string>(); } } public static List<string> OnLogoutHooks { get { if (!Utility.IsNullOrWhiteSpace(SyncedWebhooks.logout)) { return new StringListConfig(SyncedWebhooks.logout).list; } return new List<string>(); } } public static List<string> OnEventHooks { get { if (!Utility.IsNullOrWhiteSpace(SyncedWebhooks.events)) { return new StringListConfig(SyncedWebhooks.events).list; } return new List<string>(); } } public static List<string> OnNewDayHooks { get { if (!Utility.IsNullOrWhiteSpace(SyncedWebhooks.newDay)) { return new StringListConfig(SyncedWebhooks.newDay).list; } return new List<string>(); } } public static List<string> OnUseCommandHooks { get { if (!Utility.IsNullOrWhiteSpace(SyncedWebhooks.useCommands)) { return new StringListConfig(SyncedWebhooks.useCommands).list; } return new List<string>(); } } public static List<string> OnBossDeathHooks { get { if (!Utility.IsNullOrWhiteSpace(SyncedWebhooks.boss)) { return new StringListConfig(SyncedWebhooks.boss).list; } return new List<string>(); } } public static bool JobsEnabled => m_enableJobs.Value == Toggle.On; public static void SetDiscordAdmins(string value) { m_discordAdmins.Value = value; } public static void LogWarning(string message) { records.Log((LogLevel)4, message); } public static void LogDebug(string message) { records.Log((LogLevel)32, message); } public static void LogError(string message) { records.Log((LogLevel)2, message); } public static AIService GetAIServiceOption() { return AIService; } public static OpenRouterModel GetOpenRouterOption() { return OpenRouterModel; } public static GeminiModel GetGeminiOption() { return GeminiModel; } public static string GetChatGPTKey() { return ChatGPT_KEY; } public static string GetGeminiKey() { return Gemini_KEY; } public static string GetDeepSeekKey() { return DeepSeek_KEY; } public static string GetOpenRouterKey() { return OpenRouter_KEY; } public static bool HasAnyLocalAIKey() { if (string.IsNullOrWhiteSpace(ChatGPT_KEY) && string.IsNullOrWhiteSpace(Gemini_KEY) && string.IsNullOrWhiteSpace(DeepSeek_KEY)) { return !string.IsNullOrWhiteSpace(OpenRouter_KEY); } return true; } public static bool CanUseServerAI() { if (!UseServerKeys || !ServerAIBrokerEnabled) { return false; } ZNet instance = ZNet.instance; if (instance != null && instance.IsServer()) { return HasAnyLocalAIKey(); } return SyncedAIOption.serverAIAvailable; } public static List<AIService> GetAIProviderOrder() { List<AIService> list = ParseEnumList<AIService>(m_aiProviderOrder.Value); if (AIService != AIService.None) { list.Insert(0, AIService); } return list.Where((AIService provider) => provider != AIService.None).Distinct().ToList(); } public static List<string> GetGeminiModels() { return PrependModel(Utils.GetAttributeOfType<InternalName>((Enum)GeminiModel).internalName, ParseStringList(m_geminiModels.Value)); } public static List<string> GetOpenRouterModels() { return PrependModel(Utils.GetAttributeOfType<InternalName>((Enum)OpenRouterModel).internalName, ParseStringList(m_openRouterModels.Value)); } public static List<string> GetOpenAIModels() { return ParseStringList(m_openAIModels.Value); } public static List<string> GetDeepSeekModels() { return ParseStringList(m_deepSeekModels.Value); } private static List<string> ParseStringList(string value) { return (from item in value.Split(new char[4] { ',', ';', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) select item.Trim() into item where item.Length > 0 select item).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToList(); } [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] [return: <5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(new byte[] { 1, 0 })] private static List<T> ParseEnumList<T>([<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(1)] string value) where T : struct { List<T> list = new List<T>(); foreach (string item in ParseStringList(value)) { if (Enum.TryParse<T>(item, ignoreCase: true, out var result)) { list.Add(result); } } return list; } private static List<string> PrependModel(string primary, List<string> models) { models.Insert(0, primary); return models.Distinct<string>(StringComparer.OrdinalIgnoreCase).ToList(); } public void Awake() { //IL_0331: Unknown result type (might be due to invalid IL or missing references) //IL_033c: Expected O, but got Unknown //IL_0427: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Expected O, but got Unknown //IL_04c1: Unknown result type (might be due to invalid IL or missing references) //IL_04cc: Expected O, but got Unknown //IL_050c: Unknown result type (might be due to invalid IL or missing references) //IL_0517: Expected O, but got Unknown //IL_0545: Unknown result type (might be due to invalid IL or missing references) //IL_0550: Expected O, but got Unknown //IL_05e8: Unknown result type (might be due to invalid IL or missing references) //IL_05f3: Expected O, but got Unknown //IL_064a: Unknown result type (might be due to invalid IL or missing references) //IL_0655: Expected O, but got Unknown //IL_0690: Unknown result type (might be due to invalid IL or missing references) //IL_069b: Expected O, but got Unknown //IL_06d6: Unknown result type (might be due to invalid IL or missing references) //IL_06e1: Expected O, but got Unknown //IL_071c: Unknown result type (might be due to invalid IL or missing references) //IL_0727: Expected O, but got Unknown //IL_0762: Unknown result type (might be due to invalid IL or missing references) //IL_076d: Expected O, but got Unknown //IL_07a8: Unknown result type (might be due to invalid IL or missing references) //IL_07b3: Expected O, but got Unknown //IL_07ee: Unknown result type (might be due to invalid IL or missing references) //IL_07f9: Expected O, but got Unknown //IL_0834: Unknown result type (might be due to invalid IL or missing references) //IL_083f: Expected O, but got Unknown //IL_087a: Unknown result type (might be due to invalid IL or missing references) //IL_0885: Expected O, but got Unknown Keys.Write(); Localizer.Load(); m_instance = this; _serverConfigLocked = config("1 - General", "Lock Configuration", Toggle.On, "If on, the configuration is locked and can be changed by server admins only."); ConfigSync.AddLockingConfigEntry<Toggle>(_serverConfigLocked); m_logErrors = config("1 - General", "Log Errors", Toggle.Off, "If on, caught errors will log to console"); m_showDetailedLogs = config("1 - General", "Detailed Logs", Toggle.Off, "Show detailed logs"); m_notificationWebhookURL = config("2 - Notifications", "Webhook URL", "", "Set webhook to receive notifications, like server start, stop, save etc... [Server Only]", synchronizedSetting: false); m_notificationWebhookURL.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerWebhooks(); }; m_serverStartNotice = config("2 - Notifications", "Startup", Toggle.On, "If on, bot will send message when server is starting"); m_showServerDetails = config("2 - Notifications", "Server Details", Toggle.Off, "If on, bot will send server details when starting"); m_serverStopNotice = config("2 - Notifications", "Shutdown", Toggle.On, "If on, bot will send message when server is shutting down"); m_serverSaveNotice = config("2 - Notifications", "Saving", Toggle.On, "If on, bot will send message when server is saving"); m_loginNotice = config("2 - Notifications", "Login", Toggle.On, "If on, bot will send message when player logs in"); m_logoutNotice = config("2 - Notifications", "Logout", Toggle.On, "If on, bot will send message when player logs out"); m_eventNotice = config("2 - Notifications", "Random Events", Toggle.On, "If on, bot will send message when random event starts"); m_newDayNotice = config("2 - Notifications", "New Day", Toggle.Off, "If on, bot will send message when a new day begins"); m_coordinateDetails = config("2 - Notifications", "Show Coordinates", Toggle.On, "If on, coordinates will be added to login/logout notifications"); m_showBossDeath = config("2 - Notifications", "Show Boss Death", Toggle.Off, "If on, bot will send boss death notifications"); m_commandNotice = config("2 - Notifications", "Show Command Use", Toggle.Off, "If on, bot will send message when a player uses a cheat terminal command"); m_chatWebhookURL = config("3 - Chat", "Webhook URL", "", "Set discord webhook to display chat messages [Server Only]", synchronizedSetting: false); m_chatWebhookURL.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerWebhooks(); }; 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 [Server Only]", synchronizedSetting: false); m_commandWebhookURL.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerWebhooks(); }; m_commandChannelID = config("4 - Commands", "Channel ID", "", "Set channel ID to monitor for input commands"); m_discordAdmins = config("4 - Commands", "Discord Admin", "", new ConfigDescription("List of discord admins, who can run commands", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { CustomDrawer = StringListConfig.Draw } })); m_enableJobs = config("4 - Commands", "Jobs", Toggle.On, "If on, jobs are enabled"); m_botToken = config("5 - Setup", "BOT TOKEN", "", "Add bot token here, server only", synchronizedSetting: false); m_deathNotice = config("6 - Death Feed", "Enabled", Toggle.On, "If on, bot will send message when player dies"); m_deathFeedURL = config("6 - Death Feed", "Webhook URL", "", "Set webhook to receive death feed messages [Server Only]", synchronizedSetting: false); m_deathFeedURL.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerWebhooks(); }; m_screenshotDeath = config("6 - Death Feed", "Screenshot", Toggle.On, "If on, bot will post screenshot of death", synchronizedSetting: false); m_screenshotDelay = config("6 - Death Feed", "Screenshot Delay", 0.3f, new ConfigDescription("Set delay", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()), synchronizedSetting: false); Resolution resolution = new Resolution(800, 600); Resolution resolution2 = new Resolution(960, 540); Resolution resolution3 = new Resolution(1280, 720); Resolution resolution4 = new Resolution(1920, 1080); m_screenshotResolution = config("6 - Death Feed", "Screenshot Resolution", resolution2.ToString(), new ConfigDescription("Set resolution", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[4] { resolution.ToString(), resolution2.ToString(), resolution3.ToString(), resolution4.ToString() }), Array.Empty<object>()), synchronizedSetting: false); m_screenshotGif = config("6 - Death Feed", "Screenshot GIF", Toggle.On, "If on, bot will post gif of death", synchronizedSetting: false); m_gifFPS = config("6 - Death Feed", "GIF FPS", 30, new ConfigDescription("Set frames per second", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 30), Array.Empty<object>()), synchronizedSetting: false); m_gifDuration = config("6 - Death Feed", "GIF Record Duration", 3f, new ConfigDescription("Set recording duration for gif, in seconds", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 3f), Array.Empty<object>()), synchronizedSetting: false); Resolution resolution5 = new Resolution(256, 144); Resolution resolution6 = new Resolution(320, 180); Resolution resolution7 = new Resolution(480, 270); Resolution resolution8 = new Resolution(640, 360); m_gifResolution = config("6 - Death Feed", "GIF Resolution", resolution7.ToString(), new ConfigDescription("Set resolution", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[4] { resolution5.ToString(), resolution6.ToString(), resolution7.ToString(), resolution8.ToString() }), Array.Empty<object>()), synchronizedSetting: false); m_selfieKey = config<KeyCode>("1 - General", "Selfie", (KeyCode)0, "Hotkey to take selfie and send to discord", synchronizedSetting: false); m_startWorldHook = config("7 - Webhooks", "On World Start", "", new ConfigDescription("If empty, will use default notification webhook [Server Only]", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { CustomDrawer = StringListConfig.Draw } }), synchronizedSetting: false); m_saveWebhook = config("7 - Webhooks", "On World Save", "", new ConfigDescription("If empty, will use default notification webhook [Server Only]", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { CustomDrawer = StringListConfig.Draw } }), synchronizedSetting: false); m_shutdownWebhook = config("7 - Webhooks", "On World Shutdown", "", new ConfigDescription("If empty, will use default notification webhook [Server Only]", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { CustomDrawer = StringListConfig.Draw } }), synchronizedSetting: false); m_loginWebhook = config("7 - Webhooks", "On Login", "", new ConfigDescription("If empty, will use default notification webhook [Server Only]", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { CustomDrawer = StringListConfig.Draw } }), synchronizedSetting: false); m_logoutWebhook = config("7 - Webhooks", "On Logout", "", new ConfigDescription("If empty, will use default notification webhook [Server Only]", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { CustomDrawer = StringListConfig.Draw } }), synchronizedSetting: false); m_eventWebhook = config("7 - Webhooks", "On Event", "", new ConfigDescription("If empty, will use default notification webhook [Server Only]", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { CustomDrawer = StringListConfig.Draw } }), synchronizedSetting: false); m_newDayWebhook = config("7 - Webhooks", "On New Day", "", new ConfigDescription("If empty, will use default notification webhook [Server Only]", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { CustomDrawer = StringListConfig.Draw } }), synchronizedSetting: false); m_useCommandWebhook = config("7 - Webhooks", "On Use Command", "", new ConfigDescription("If empty, will use default notification webhook [Server Only]", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { CustomDrawer = StringListConfig.Draw } }), synchronizedSetting: false); m_bossWebhook = config("7 - Webhooks", "On Boss Death", "", new ConfigDescription("If empty, will use default notification webhook [Server Only]", (AcceptableValueBase)null, new object[1] { new ConfigurationManagerAttributes { CustomDrawer = StringListConfig.Draw } }), synchronizedSetting: false); m_startWorldHook.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerWebhooks(); }; m_saveWebhook.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerWebhooks(); }; m_shutdownWebhook.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerWebhooks(); }; m_loginWebhook.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerWebhooks(); }; m_logoutWebhook.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerWebhooks(); }; m_eventWebhook.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerWebhooks(); }; m_newDayWebhook.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerWebhooks(); }; m_useCommandWebhook.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerWebhooks(); }; m_bossWebhook.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerWebhooks(); }; m_aiService = config("8 - AI", "Provider", AIService.Gemini, "Set which Artificial Intelligence API to use", synchronizedSetting: false); m_chatGPTAPIKEY = config("8 - AI", "ChatGPT", "", "Set ChatGPT key", synchronizedSetting: false); m_geminiAPIKEY = config("8 - AI", "Gemini", "", "Set Gemini key", synchronizedSetting: false); m_deepSeekAPIKEY = config("8 - AI", "DeepSeek", "", "Set DeepSeek key", synchronizedSetting: false); m_openRouterAPIKEY = config("8 - AI", "OpenRouter", "", "Set OpenRouter key", synchronizedSetting: false); m_openRouterModel = config("8 - AI", "OpenRouter Model", OpenRouterModel.AutoFree, "Legacy primary OpenRouter model. Prefer OpenRouter Models for ordered failover.", synchronizedSetting: false); m_useServerKeys = config("8 - AI", "Use Server Keys", Toggle.On, "If enabled, clients without local keys send AI requests to the server broker. API keys are never synchronized to clients."); m_geminiModel = config("8 - AI", "Gemini Model", GeminiModel.Flash3_6, "Legacy primary Gemini model. Prefer Gemini Models for ordered failover.", synchronizedSetting: false); m_allowDiscordPrompt = config("8 - AI", "Discord Prompt", Toggle.Off, "If on, Discord users can prompt the server AI using !prompt"); m_aiProviderOrder = config("8 - AI", "Provider Order", "Gemini, OpenRouter, ChatGPT, DeepSeek", "Ordered provider failover. The Provider setting is tried first when enabled.", synchronizedSetting: false); m_geminiModels = config("8 - AI", "Gemini Models", "gemini-3.6-flash, gemini-3.5-flash-lite, gemini-3.5-flash, gemini-3.1-flash-lite, gemini-flash-latest, gemini-flash-lite-latest, gemini-3.1-pro-preview, gemini-3-flash-preview, gemini-pro-latest, gemini-2.5-flash-lite, gemini-2.5-flash, gemini-2.5-pro", "Ordered Gemini model failover list.", synchronizedSetting: false); m_geminiAutoDiscover = config("8 - AI", "Gemini Auto Discover", Toggle.On, "Discover text-generation models available to the configured Gemini key.", synchronizedSetting: false); m_openRouterModels = config("8 - AI", "OpenRouter Models", "openrouter/free", "Ordered OpenRouter model failover list. Discovered models are appended when enabled.", synchronizedSetting: false); m_openRouterAutoDiscover = config("8 - AI", "OpenRouter Auto Discover", Toggle.On, "Discover models usable by the configured OpenRouter key and account preferences.", synchronizedSetting: false); m_openRouterFreeOnly = config("8 - AI", "OpenRouter Free Only", Toggle.On, "Only auto-discover OpenRouter models with zero prompt, completion, and request price.", synchronizedSetting: false); m_openAIModels = config("8 - AI", "OpenAI Models", "gpt-5.6-luna, gpt-5.6-terra, gpt-5.6-sol, gpt-5.6, gpt-5.5, gpt-5.4-mini, gpt-5.4-nano, gpt-4.1-mini", "Ordered OpenAI model failover list. Cost-efficient models are tried before frontier models by default.", synchronizedSetting: false); m_deepSeekModels = config("8 - AI", "DeepSeek Models", "deepseek-chat, deepseek-reasoner", "Ordered DeepSeek model failover list.", synchronizedSetting: false); m_aiMaxAttempts = config("8 - AI", "Max Attempts", 12, "Maximum provider/model attempts per AI request.", synchronizedSetting: false); m_aiModelsPerProvider = config("8 - AI", "Models Per Provider", 3, "Maximum model attempts before failing over to the next configured provider.", synchronizedSetting: false); m_aiRequestTimeoutSeconds = config("8 - AI", "Request Timeout Seconds", 30, "Timeout for each AI API request.", synchronizedSetting: false); m_aiCatalogCacheMinutes = config("8 - AI", "Model Catalog Cache Minutes", 60, "How long discovered model catalogs are cached.", synchronizedSetting: false); m_aiMaxOutputTokens = config("8 - AI", "Max Output Tokens", 160, "Maximum output tokens requested for a response.", synchronizedSetting: false); m_aiMaxPromptCharacters = config("8 - AI", "Max Prompt Characters", 4000, "Maximum client prompt length accepted by the server AI broker.", synchronizedSetting: false); m_aiRemoteRequestCooldown = config("8 - AI", "Remote Request Cooldown Seconds", 2f, "Minimum delay between AI broker requests from the same client.", synchronizedSetting: false); m_aiRemoteResponseTimeoutSeconds = config("8 - AI", "Remote Response Timeout Seconds", 120, "Maximum time a client waits for a server AI broker response.", synchronizedSetting: false); m_serverAIBroker = config("8 - AI", "Server AI Broker", Toggle.On, "Execute client death/day quip AI requests on the server without exposing API keys.", synchronizedSetting: false); m_allowPlayerAIPrompts = config("8 - AI", "Allow Player AI Prompts", Toggle.Off, "Allow manual in-game player prompts through the server AI broker. Automatic death/day quips remain allowed.", synchronizedSetting: false); m_chatGPTAPIKEY.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerAIKeys(); }; m_geminiAPIKEY.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerAIKeys(); }; m_deepSeekAPIKEY.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerAIKeys(); }; m_openRouterAPIKEY.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerAIKeys(); }; m_aiService.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerAIOption(); }; m_openRouterModel.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerAIOption(); }; m_geminiModel.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerAIOption(); }; m_aiProviderOrder.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerAIOption(); }; m_serverAIBroker.SettingChanged += [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] (object _, EventArgs _) => { UpdateServerAIOption(); }; m_serverKeys.ValueChanged += delegate { ZNet instance = ZNet.instance; if (instance == null || !instance.IsServer()) { SyncedAIKeys = new ServerKeys(); } }; m_serverOptions.ValueChanged += delegate { if (!string.IsNullOrWhiteSpace(m_serverOptions.Value)) { ZNet instance = ZNet.instance; if (instance == null || !instance.IsServer()) { SyncedAIOption = new ServerAIOption(m_serverOptions.Value); LogDebug("Received server AI options"); } } }; ServerSyncedWebhooks.ValueChanged += delegate { if (!string.IsNullOrWhiteSpace(ServerSyncedWebhooks.Value)) { ZNet instance = ZNet.instance; if (instance == null || !instance.IsServer()) { SyncedWebhooks = new ServerWebhooks(ServerSyncedWebhooks.Value); LogDebug("Received server webhooks"); } } }; m_improveDeathQuips = config("8 - AI", "Death Quips", Toggle.On, "If on and AI is setup, will prompt to improve quip"); m_improveDayQuips = config("8 - AI", "Day Quips", Toggle.On, "If on, and AI is setup, will prompt to improve quip"); DiscordCommands.Setup(); DeathQuips.Setup(); DayQuips.Setup(); Assembly executingAssembly = Assembly.GetExecutingAssembly(); _harmony.PatchAll(executingAssembly); SetupWatcher(); } private static void UpdateServerWebhooks() { ZNet instance = ZNet.instance; if (instance != null && instance.IsServer()) { SyncedWebhooks = new ServerWebhooks(m_notificationWebhookURL.Value, m_commandWebhookURL.Value, m_chatWebhookURL.Value, m_deathFeedURL.Value, m_startWorldHook.Value, m_saveWebhook.Value, m_shutdownWebhook.Value, m_loginWebhook.Value, m_logoutWebhook.Value, m_eventWebhook.Value, m_newDayWebhook.Value, m_useCommandWebhook.Value, m_bossWebhook.Value); ServerSyncedWebhooks.Value = SyncedWebhooks.ToString(); records.Log((LogLevel)16, "Updating server webhooks"); } } private static void UpdateServerAIKeys() { ZNet instance = ZNet.instance; if (instance != null && instance.IsServer()) { m_serverKeys.Value = string.Empty; UpdateServerAIOption(); records.Log((LogLevel)16, "Updated server AI credential availability without synchronizing API keys"); } } private static void UpdateServerAIOption() { ZNet instance = ZNet.instance; if (instance != null && instance.IsServer()) { ServerAIOption serverAIOption = new ServerAIOption(AIService, OpenRouterModel, GeminiModel, ServerAIBrokerEnabled && HasAnyLocalAIKey()); m_serverOptions.Value = serverAIOption.ToString(); records.Log((LogLevel)16, "Updating server AI options"); } } private void OnDestroy() { ((BaseUnityPlugin)this).Config.Save(); records.Write(); } private void SetupWatcher() { FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, "RustyMods.DiscordBot.cfg"); 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 RustyMods.DiscordBot.cfg"); DiscordBotLogger.LogError((object)"Please check your config entries for spelling and format!"); } } private ConfigEntry<T> config<[<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(2)] T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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); ConfigSync.AddConfigEntry<T>(val2).SynchronizedConfig = synchronizedSetting; return val2; } public ConfigEntry<T> config<[<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(2)] T>(string group, string name, T value, string description, bool synchronizedSetting = true) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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 + "RustyMods.DiscordBot.cfg"; ConnectionError = ""; DiscordBotLogger = Logger.CreateLogSource("DiscordBot"); ConfigSync = new ConfigSync("RustyMods.DiscordBot") { DisplayName = "DiscordBot", CurrentVersion = "1.4.0", MinimumRequiredVersion = "1.4.0" }; directory = new Dir(Paths.ConfigPath, "DiscordBot"); m_instance = null; _serverConfigLocked = null; m_startWorldHook = null; m_saveWebhook = null; m_shutdownWebhook = null; m_loginWebhook = null; m_logoutWebhook = null; m_eventWebhook = null; m_newDayWebhook = null; m_useCommandWebhook = null; m_bossWebhook = null; m_notificationWebhookURL = null; m_serverStartNotice = null; m_serverStopNotice = null; m_serverSaveNotice = null; m_deathNotice = null; m_loginNotice = null; m_logoutNotice = null; m_eventNotice = null; m_newDayNotice = null; m_coordinateDetails = null; m_commandNotice = null; m_showServerDetails = null; m_showBossDeath = 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_showDetailedLogs = null; m_screenshotDeath = null; m_screenshotDelay = null; m_screenshotResolution = null; m_screenshotGif = null; m_gifFPS = null; m_gifDuration = null; m_gifResolution = null; m_selfieKey = null; m_aiService = null; m_chatGPTAPIKEY = null; m_geminiAPIKEY = null; m_geminiModel = null; m_deepSeekAPIKEY = null; m_openRouterAPIKEY = null; m_openRouterModel = null; m_useServerKeys = null; m_serverKeys = new CustomSyncedValue<string>(ConfigSync, "RustyMods.DiscordBot.ServerKeys", ""); m_serverOptions = new CustomSyncedValue<string>(ConfigSync, "RustyMods.DiscordBot.ServerOptions", ""); m_allowDiscordPrompt = null; m_improveDeathQuips = null; m_improveDayQuips = null; m_aiProviderOrder = null; m_geminiModels = null; m_geminiAutoDiscover = null; m_openRouterModels = null; m_openRouterAutoDiscover = null; m_openRouterFreeOnly = null; m_openAIModels = null; m_deepSeekModels = null; m_aiMaxAttempts = null; m_aiModelsPerProvider = null; m_aiRequestTimeoutSeconds = null; m_aiCatalogCacheMinutes = null; m_aiMaxOutputTokens = null; m_aiMaxPromptCharacters = null; m_aiRemoteRequestCooldown = null; m_aiRemoteResponseTimeoutSeconds = null; m_serverAIBroker = null; m_allowPlayerAIPrompts = null; m_enableJobs = null; resolutions = new Dictionary<string, Resolution>(); ServerSyncedWebhooks = new CustomSyncedValue<string>(ConfigSync, "RustyMods.DiscordBot.SyncedWebhooks", ""); SyncedAIKeys = new ServerKeys(); SyncedAIOption = new ServerAIOption(); SyncedWebhooks = new ServerWebhooks(); records = new Record(); } } public enum AIService { None, ChatGPT, Gemini, DeepSeek, OpenRouter } [PublicAPI] public enum GPTModel { [InternalName("gpt-5.6-luna")] GPT5_6Luna, [InternalName("gpt-5.6-terra")] GPT5_6Terra, [InternalName("gpt-5.6-sol")] GPT5_6Sol, [InternalName("gpt-5.6")] GPT5_6, [InternalName("gpt-3.5-turbo")] Turbo, [InternalName("gpt-4o")] GPT4o, [InternalName("gpt-4o-mini")] GPT4oMini, [InternalName("gpt-4.1")] GPT4_1 } [PublicAPI] public enum GeminiModel { [InternalName("gemini-2.0-flash")] Flash2_0, [InternalName("gemini-2.5-flash")] Flash2_5, [InternalName("gemini-2.0-pro")] Pro2_0, [InternalName("gemini-2.5-pro")] Pro2_5, [InternalName("gemini-3.1-flash-lite")] Flash3_1Lite, [InternalName("gemini-3.5-flash-lite")] Flash3_5Lite, [InternalName("gemini-3.5-flash")] Flash3_5, [InternalName("gemini-3.6-flash")] Flash3_6 } [PublicAPI] public enum DeepSeekModel { [InternalName("deepseek-chat")] Chat, [InternalName("deepseek-reasoner")] Reasoner } [PublicAPI] public enum OpenRouterModel { [InternalName("anthropic/claude-3.5-sonnet")] Claude3_5Sonnet, [InternalName("google/gemini-2.0-flash-exp:free")] GeminiFlashFree, [InternalName("meta-llama/llama-4-maverick:free")] Llama4_Maverick, [InternalName("microsoft/wizardlm-2-8x22b")] WizardLM8x22B, [InternalName("openai/gpt-4o-mini")] GPT4oMini, [InternalName("deepseek/deepseek-chat")] DeepSeekChat, [InternalName("nousresearch/hermes-3-llama-3.1-405b:free")] Hermes3_Llama31_405b, [InternalName("openrouter/free")] AutoFree } [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(0)] [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(1)] public class InternalName : Attribute { public readonly string internalName; public InternalName(string internalName) { this.internalName = internalName; } } [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(1)] [<5cd3367d-3f18-4efd-8d81-d072213732ed>Nullable(0)] public class ChatAI : MonoBehaviour { [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] [HarmonyPatch(typeof(ZNet), "Disconnect")] private static class ZNet_Disconnect_Patch { [UsedImplicitly] [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(1)] private static void Prefix(ZNetPeer peer) { if (peer?.m_rpc != null) { RemoteRequestTimes.Remove(peer.m_rpc); ConsumedDeathCharacters.Remove(peer.m_rpc); } } } [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(0)] [HarmonyPatch(typeof(Terminal), "UpdateChat")] private static class Terminal_UpdateChat_Patch { [<226ca976-6ae0-4386-814c-a218f6c5d69a>NullableContext(1)] [UsedImplicitly] private static void Postfix(Terminal __instance) { if (!((Object)(object)__instance != (Object)(object)Chat.instance) && Object.op_Implicit((Object)(object)instance)) { instance.tempChat = ((TMP_Text)__instance.m_output).text; } } } [<226ca976-6ae0-4386-814c-a218f6