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 MemeBanner v1.0.1
MemeBanner.dll
Decompiled 8 minutes agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Microsoft.CodeAnalysis; using RiskOfOptions; using RiskOfOptions.Options; using RoR2; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("MemeBanner")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.1.0")] [assembly: AssemblyInformationalVersion("1.0.1+e978bd25aa951e3bbc9ee26b71fc6d8a1a3ec81e")] [assembly: AssemblyProduct("MemeBanner")] [assembly: AssemblyTitle("MemeBanner")] [assembly: AssemblyVersion("1.0.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } internal static class ApngDecoder { private sealed class FrameInfo { internal int Width; internal int Height; internal int X; internal int Y; internal float Delay; internal byte Dispose; internal byte Blend; internal readonly List<byte[]> Parts = new List<byte[]>(); } private const byte DISPOSE_BACKGROUND = 1; private const byte DISPOSE_PREVIOUS = 2; private const byte BLEND_OVER = 1; private const int FCTL_LENGTH = 26; private const int CHUNK_OVERHEAD = 12; private static readonly uint[] CrcTable = BuildCrcTable(); internal static bool TryDecode(byte[] data, out Color32[][] frames, out float[] delays, out int width, out int height) { //IL_03c9: Unknown result type (might be due to invalid IL or missing references) //IL_03d0: Expected O, but got Unknown //IL_04ba: Unknown result type (might be due to invalid IL or missing references) //IL_04bf: Unknown result type (might be due to invalid IL or missing references) //IL_04dd: Unknown result type (might be due to invalid IL or missing references) //IL_04e3: Unknown result type (might be due to invalid IL or missing references) //IL_04e8: Unknown result type (might be due to invalid IL or missing references) //IL_04d9: Unknown result type (might be due to invalid IL or missing references) //IL_04ed: Unknown result type (might be due to invalid IL or missing references) frames = null; delays = null; width = 0; height = 0; if (data.Length < 8 || data[0] != 137 || data[1] != 80 || data[2] != 78 || data[3] != 71) { return false; } byte[] array = null; List<byte[]> list = new List<byte[]>(); List<FrameInfo> list2 = new List<FrameInfo>(); bool flag = false; int num = 8; while (num + 8 <= data.Length) { int num2 = ReadInt(data, num); if (num2 < 0 || num + 12 + num2 > data.Length) { break; } string text = Encoding.ASCII.GetString(data, num + 4, 4); int num3 = num + 8; switch (text) { case "IHDR": array = Slice(data, num3, num2); width = ReadInt(data, num3); height = ReadInt(data, num3 + 4); break; case "acTL": flag = true; break; case "fcTL": if (num2 >= 26) { int num4 = (data[num3 + 22] << 8) | data[num3 + 23]; list2.Add(new FrameInfo { Width = ReadInt(data, num3 + 4), Height = ReadInt(data, num3 + 8), X = ReadInt(data, num3 + 12), Y = ReadInt(data, num3 + 16), Delay = (float)((data[num3 + 20] << 8) | data[num3 + 21]) / ((num4 == 0) ? 100f : ((float)num4)), Dispose = data[num3 + 24], Blend = data[num3 + 25] }); } break; case "IDAT": if (list2.Count == 1) { list2[0].Parts.Add(Slice(data, num3, num2)); } break; case "fdAT": if (list2.Count > 0 && num2 > 4) { list2[list2.Count - 1].Parts.Add(Slice(data, num3 + 4, num2 - 4)); } break; case "PLTE": case "tRNS": case "gAMA": case "cHRM": case "sRGB": case "iCCP": case "sBIT": case "pHYs": list.Add(Slice(data, num, num2 + 12)); break; } num += 12 + num2; if (text == "IEND") { break; } } if (!flag || array == null || width <= 0 || height <= 0 || list2.Count == 0) { return false; } List<Color32[]> list3 = new List<Color32[]>(); List<float> list4 = new List<float>(); Color32[] array2 = (Color32[])(object)new Color32[width * height]; Color32[] array3 = null; Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); foreach (FrameInfo item in list2) { if (item.Parts.Count == 0 || item.Width <= 0 || item.Height <= 0 || !ImageConversion.LoadImage(val, BuildPng(array, list, item))) { continue; } Color32[] pixels = val.GetPixels32(); if (pixels.Length < item.Width * item.Height) { continue; } if (item.Dispose == 2) { array3 = (Color32[])array2.Clone(); } int num5 = height - item.Y - item.Height; for (int i = 0; i < item.Height; i++) { int num6 = num5 + i; if (num6 < 0 || num6 >= height) { continue; } for (int j = 0; j < item.Width; j++) { int num7 = item.X + j; if (num7 >= 0 && num7 < width) { Color32 val2 = pixels[i * item.Width + j]; int num8 = num6 * width + num7; array2[num8] = ((item.Blend == 1) ? Over(val2, array2[num8]) : val2); } } } list3.Add((Color32[])array2.Clone()); list4.Add(Mathf.Max(item.Delay, 0.01f)); if (item.Dispose == 1) { PixelCanvas.ClearRect(array2, width, height, item.X, num5, item.Width, item.Height); } else if (item.Dispose == 2 && array3 != null) { array2 = array3; } } Object.Destroy((Object)(object)val); if (list3.Count == 0) { return false; } frames = list3.ToArray(); delays = list4.ToArray(); return true; } private static Color32 Over(Color32 source, Color32 under) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) if (source.a == byte.MaxValue || under.a == 0) { return source; } if (source.a == 0) { return under; } float num = (float)(int)source.a / 255f; float num2 = (float)(int)under.a / 255f; float num3 = num + num2 * (1f - num); if (num3 <= 0f) { return new Color32((byte)0, (byte)0, (byte)0, (byte)0); } return new Color32(Mix(source.r, under.r, num, num2, num3), Mix(source.g, under.g, num, num2, num3), Mix(source.b, under.b, num, num2, num3), (byte)Mathf.RoundToInt(num3 * 255f)); } private static byte Mix(byte source, byte under, float sa, float ua, float outA) { return (byte)Mathf.Clamp(Mathf.RoundToInt(((float)(int)source / 255f * sa + (float)(int)under / 255f * ua * (1f - sa)) / outA * 255f), 0, 255); } private static byte[] BuildPng(byte[] header, List<byte[]> carried, FrameInfo info) { byte[] array = (byte[])header.Clone(); WriteInt(array, 0, info.Width); WriteInt(array, 4, info.Height); int num = 0; foreach (byte[] part in info.Parts) { num += part.Length; } byte[] array2 = new byte[num]; int num2 = 0; foreach (byte[] part2 in info.Parts) { Buffer.BlockCopy(part2, 0, array2, num2, part2.Length); num2 += part2.Length; } List<byte> list = new List<byte>(num + 256); list.AddRange(new byte[8] { 137, 80, 78, 71, 13, 10, 26, 10 }); AppendChunk(list, "IHDR", array); foreach (byte[] item in carried) { list.AddRange(item); } AppendChunk(list, "IDAT", array2); AppendChunk(list, "IEND", new byte[0]); return list.ToArray(); } private static void AppendChunk(List<byte> png, string type, byte[] body) { byte[] array = new byte[4]; WriteInt(array, 0, body.Length); png.AddRange(array); byte[] array2 = new byte[4 + body.Length]; for (int i = 0; i < 4; i++) { array2[i] = (byte)type[i]; } Buffer.BlockCopy(body, 0, array2, 4, body.Length); png.AddRange(array2); byte[] array3 = new byte[4]; WriteInt(array3, 0, (int)Crc32(array2)); png.AddRange(array3); } private static uint[] BuildCrcTable() { uint[] array = new uint[256]; for (uint num = 0u; num < 256; num++) { uint num2 = num; for (int i = 0; i < 8; i++) { num2 = (((num2 & 1) != 0) ? (0xEDB88320u ^ (num2 >> 1)) : (num2 >> 1)); } array[num] = num2; } return array; } private static uint Crc32(byte[] bytes) { uint num = uint.MaxValue; foreach (byte b in bytes) { num = CrcTable[(num ^ b) & 0xFF] ^ (num >> 8); } return num ^ 0xFFFFFFFFu; } private static byte[] Slice(byte[] data, int offset, int length) { byte[] array = new byte[length]; Buffer.BlockCopy(data, offset, array, 0, length); return array; } private static int ReadInt(byte[] data, int offset) { return (data[offset] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | data[offset + 3]; } private static void WriteInt(byte[] data, int offset, int value) { data[offset] = (byte)(value >> 24); data[offset + 1] = (byte)(value >> 16); data[offset + 2] = (byte)(value >> 8); data[offset + 3] = (byte)value; } } internal static class GifDecoder { private enum BlockResult { Ok, Skip, Fatal } private struct GraphicControl { internal int DelayHundredths; internal int Disposal; internal int TransparentIndex; internal static GraphicControl Default() { return new GraphicControl { DelayHundredths = 10, Disposal = 0, TransparentIndex = -1 }; } internal float Delay() { if (DelayHundredths > 1) { return (float)DelayHundredths / 100f; } return 0.1f; } } private struct ImageBlock { internal int Left; internal int Top; internal int Width; internal int Height; internal bool Interlaced; internal Color32[] Table; internal byte[] Indices; } private const byte BLOCK_EXTENSION = 33; private const byte BLOCK_IMAGE = 44; private const byte BLOCK_TRAILER = 59; private const byte EXTENSION_GRAPHIC_CONTROL = 249; private const int COLOR_TABLE_FLAG = 128; private const int INTERLACE_FLAG = 64; private const int DISPOSE_BACKGROUND = 2; private const int DISPOSE_PREVIOUS = 3; private const int MAX_CODES = 4096; internal static bool TryDecode(byte[] data, out Color32[][] frames, out float[] delays, out int width, out int height) { frames = null; delays = null; width = 0; height = 0; if (data.Length < 14 || data[0] != 71 || data[1] != 73 || data[2] != 70) { return false; } int num = 6; width = data[num] | (data[num + 1] << 8); height = data[num + 2] | (data[num + 3] << 8); int num2 = data[num + 4]; num += 7; if (width <= 0 || height <= 0) { return false; } Color32[] table = null; if ((num2 & 0x80) != 0 && !TryReadTable(data, ref num, 2 << (num2 & 7), out table)) { return false; } List<Color32[]> list = new List<Color32[]>(); List<float> list2 = new List<float>(); Color32[] array = (Color32[])(object)new Color32[width * height]; Color32[] array2 = null; GraphicControl control = GraphicControl.Default(); while (num < data.Length) { switch (data[num++]) { case 33: if (ReadExtension(data, ref num, ref control)) { continue; } break; case 44: { ImageBlock image; switch (ReadImageBlock(data, ref num, table, out image)) { default: if (control.Disposal == 3) { array2 = (Color32[])array.Clone(); } Composite(array, width, height, image, control.TransparentIndex); list.Add((Color32[])array.Clone()); list2.Add(control.Delay()); if (control.Disposal == 2) { PixelCanvas.ClearRect(array, width, height, image.Left, height - image.Top - image.Height, image.Width, image.Height); } else if (control.Disposal == 3 && array2 != null) { array = array2; } continue; case BlockResult.Skip: continue; case BlockResult.Fatal: break; } break; } } break; } if (list.Count == 0) { return false; } frames = list.ToArray(); delays = list2.ToArray(); return true; } private static bool ReadExtension(byte[] data, ref int pos, ref GraphicControl control) { if (pos >= data.Length) { return false; } if (data[pos++] == 249 && pos + 5 <= data.Length) { int num = data[pos++]; int num2 = data[pos]; control.DelayHundredths = data[pos + 1] | (data[pos + 2] << 8); control.TransparentIndex = (((num2 & 1) != 0) ? data[pos + 3] : (-1)); control.Disposal = (num2 >> 2) & 7; pos += num; } SkipBlocks(data, ref pos); return true; } private static BlockResult ReadImageBlock(byte[] data, ref int pos, Color32[] globalTable, out ImageBlock image) { image = default(ImageBlock); if (pos + 9 > data.Length) { return BlockResult.Fatal; } image.Left = data[pos] | (data[pos + 1] << 8); image.Top = data[pos + 2] | (data[pos + 3] << 8); image.Width = data[pos + 4] | (data[pos + 5] << 8); image.Height = data[pos + 6] | (data[pos + 7] << 8); int num = data[pos + 8]; pos += 9; Color32[] table = null; if ((num & 0x80) != 0 && !TryReadTable(data, ref pos, 2 << (num & 7), out table)) { return BlockResult.Fatal; } image.Table = table ?? globalTable; image.Interlaced = (num & 0x40) != 0; if (pos >= data.Length) { return BlockResult.Fatal; } int num2 = data[pos++]; byte[] input = ReadBlocks(data, ref pos); if (image.Table == null || image.Width <= 0 || image.Height <= 0 || num2 < 1 || num2 > 11) { return BlockResult.Skip; } image.Indices = Decompress(input, num2, image.Width * image.Height); return BlockResult.Ok; } private static void Composite(Color32[] canvas, int width, int height, ImageBlock image, int transparentIndex) { //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < image.Height; i++) { int num = (image.Interlaced ? InterlacedRow(i, image.Height) : i); int num2 = height - 1 - (image.Top + num); if (num2 < 0 || num2 >= height) { continue; } for (int j = 0; j < image.Width; j++) { int num3 = image.Left + j; if (num3 >= 0 && num3 < width) { int num4 = image.Indices[i * image.Width + j]; if (num4 != transparentIndex && num4 < image.Table.Length) { canvas[num2 * width + num3] = image.Table[num4]; } } } } } private static int InterlacedRow(int decodedRow, int height) { int num = (height + 7) / 8; int num2 = (height + 3) / 8; int num3 = (height + 1) / 4; if (decodedRow < num) { return decodedRow * 8; } decodedRow -= num; if (decodedRow < num2) { return decodedRow * 8 + 4; } decodedRow -= num2; if (decodedRow < num3) { return decodedRow * 4 + 2; } return (decodedRow - num3) * 2 + 1; } private static bool TryReadTable(byte[] data, ref int pos, int count, out Color32[] table) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) table = null; if (pos + count * 3 > data.Length) { return false; } table = (Color32[])(object)new Color32[count]; for (int i = 0; i < count; i++) { table[i] = new Color32(data[pos], data[pos + 1], data[pos + 2], byte.MaxValue); pos += 3; } return true; } private static void SkipBlocks(byte[] data, ref int pos) { while (pos < data.Length) { int num = data[pos++]; if (num == 0) { break; } pos += num; } } private static byte[] ReadBlocks(byte[] data, ref int pos) { List<byte> list = new List<byte>(); while (pos < data.Length) { int num = data[pos++]; if (num == 0) { break; } for (int i = 0; i < num; i++) { if (pos >= data.Length) { break; } list.Add(data[pos++]); } } return list.ToArray(); } private static byte[] Decompress(byte[] input, int minCodeSize, int pixelCount) { short[] array = new short[4096]; byte[] array2 = new byte[4096]; byte[] array3 = new byte[4097]; byte[] array4 = new byte[pixelCount]; int num = 1 << minCodeSize; int num2 = num + 1; int num3 = minCodeSize + 1; int num4 = num2 + 1; int num5 = -1; int num6 = 0; int num7 = 0; int num8 = 0; int num9 = input.Length * 8; for (int i = 0; i < num; i++) { array2[i] = (byte)i; } while (num8 < pixelCount && num7 + num3 <= num9) { int num10 = ReadBits(input, num7, num3); num7 += num3; if (num10 == num) { num3 = minCodeSize + 1; num4 = num2 + 1; num5 = -1; continue; } if (num10 == num2) { break; } int num11 = num10; int num12 = 0; if (num10 >= num4) { if (num5 < 0) { break; } array3[num12++] = (byte)num6; num10 = num5; } while (num10 >= num && num12 < 4096) { array3[num12++] = array2[num10]; num10 = array[num10]; } num6 = array2[num10]; array3[num12++] = (byte)num6; while (num12 > 0 && num8 < pixelCount) { array4[num8++] = array3[--num12]; } if (num5 >= 0 && num4 < 4096) { array[num4] = (short)num5; array2[num4] = (byte)num6; num4++; if (num4 == 1 << num3 && num3 < 12) { num3++; } } num5 = num11; } return array4; } private static int ReadBits(byte[] data, int bitPos, int count) { int num = 0; for (int i = 0; i < count; i++) { int num2 = bitPos + i; num |= ((data[num2 >> 3] >> (num2 & 7)) & 1) << i; } return num; } } internal static class PixelCanvas { internal static void ClearRect(Color32[] canvas, int width, int height, int left, int bottom, int w, int h) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < h; i++) { int num = bottom + i; if (num < 0 || num >= height) { continue; } for (int j = 0; j < w; j++) { int num2 = left + j; if (num2 >= 0 && num2 < width) { canvas[num * width + num2] = new Color32((byte)0, (byte)0, (byte)0, (byte)0); } } } } } internal sealed class BannerImage { internal readonly Texture2D[] Frames; internal readonly float[] Delays; internal BannerImage(Texture2D[] frames, float[] delays) { Frames = frames; Delays = delays; } } [BepInPlugin("com.hibiscus.memebanner", "MemeBanner", "1.0.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class MemeBannerPlugin : BaseUnityPlugin { public const string PluginGuid = "com.hibiscus.memebanner"; public const string PluginName = "MemeBanner"; public const string PluginVersion = "1.0.1"; internal const string FLAG_MATERIAL = "matWarbannerFlag"; private const string RISK_OF_OPTIONS_GUID = "com.rune580.riskofoptions"; private const int ANIMATED_SIZE = 256; private const int MAX_FRAMES = 200; private static readonly string[] _extensions = new string[4] { ".png", ".jpg", ".jpeg", ".gif" }; private static readonly Dictionary<string, BannerImage> _cache = new Dictionary<string, BannerImage>(); private static Rect _clothWindow; private static Color32[] _clothPixels; private static int _clothWidth; private static int _clothHeight; private static string[] _images = Array.Empty<string>(); private static int _next; private static string _lastShown; private static ConfigEntry<bool> _useStockAlpha; private static ConfigEntry<bool> _randomBanner; internal static ManualLogSource Log; private static string _pluginDir; public void Awake() { Log = ((BaseUnityPlugin)this).Logger; _useStockAlpha = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "UseStockAlphaMask", false, "Off: your image covers the whole cloth as a rectangle.\nOn: an image that has no transparency of its own borrows the stock banner's alpha, so it keeps the torn-cloth silhouette. An image that already has transparency always keeps its own, either way."); _randomBanner = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RandomBanner", false, "Off: a queue of all your images is generated, so nothing repeats until every image has been shown once.\nOn: every banner picks an image at random, which can repeat."); _pluginDir = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location); string text = Path.Combine(_pluginDir, "Banners"); Directory.CreateDirectory(text); _images = (from f in Directory.GetFiles(text, "*", SearchOption.AllDirectories) where _extensions.Contains(Path.GetExtension(f).ToLowerInvariant()) select f).ToArray(); _next = _images.Length; ((BaseUnityPlugin)this).Logger.LogInfo((object)$"{_images.Length} banner image(s) found in {text}"); if (Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions")) { SetupRiskOfOptions(); } RoR2Application.onLoadFinished = (Action)Delegate.Combine(RoR2Application.onLoadFinished, new Action(PatchWardPrefab)); } private void SetupRiskOfOptions() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown ModSettingsManager.SetModDescription("Every Warbanner you drop gets a random image from the mod's Banners folder."); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(_useStockAlpha, true)); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(_randomBanner)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"registered in-game settings via Risk of Options"); } private static void PatchWardPrefab() { GameObject val = LegacyResourcesAPI.Load<GameObject>("Prefabs/NetworkedObjects/WarbannerWard"); if (!Object.op_Implicit((Object)(object)val)) { Log.LogError((object)"WarbannerWard prefab not found - banners will look normal."); return; } MeasureCloth(val); if (!Object.op_Implicit((Object)(object)val.GetComponent<RandomBannerTexture>())) { val.AddComponent<RandomBannerTexture>(); } } private static void MeasureCloth(GameObject prefab) { //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_01a0: Unknown result type (might be due to invalid IL or missing references) Renderer[] componentsInChildren = prefab.GetComponentsInChildren<Renderer>(true); foreach (Renderer val in componentsInChildren) { Material sharedMaterial = val.sharedMaterial; if (!Object.op_Implicit((Object)(object)sharedMaterial) || !((Object)sharedMaterial).name.StartsWith("matWarbannerFlag", StringComparison.Ordinal)) { continue; } MeshFilter component = ((Component)val).GetComponent<MeshFilter>(); Mesh val2 = (Object.op_Implicit((Object)(object)component) ? component.sharedMesh : null); if (!Object.op_Implicit((Object)(object)val2)) { SkinnedMeshRenderer val3 = (SkinnedMeshRenderer)(object)((val is SkinnedMeshRenderer) ? val : null); val2 = (Object.op_Implicit((Object)(object)val3) ? val3.sharedMesh : null); } Texture texture = sharedMaterial.GetTexture("_MainTex"); if (!Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)texture)) { Log.LogWarning((object)"banner cloth has no mesh or texture - images will be used unscaled"); break; } float num = float.MaxValue; float num2 = float.MinValue; float num3 = float.MaxValue; float num4 = float.MinValue; Vector2[] uv = val2.uv; foreach (Vector2 val4 in uv) { num = Mathf.Min(num, val4.x); num2 = Mathf.Max(num2, val4.x); num3 = Mathf.Min(num3, val4.y); num4 = Mathf.Max(num4, val4.y); } if (num2 <= num || num4 <= num3) { Log.LogWarning((object)"banner cloth has a degenerate UV window - images will be used unscaled"); break; } _clothWindow = Rect.MinMaxRect(num, num3, num2, num4); _clothWidth = texture.width; _clothHeight = texture.height; _clothPixels = ReadBack(texture); Log.LogInfo((object)$"banner cloth: {_clothWidth}x{_clothHeight}, uv window {_clothWindow}"); break; } } private static Color32[] ReadBack(Texture source) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown RenderTexture temporary = RenderTexture.GetTemporary(source.width, source.height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2); Graphics.Blit(source, temporary); RenderTexture active = RenderTexture.active; RenderTexture.active = temporary; Texture2D val = new Texture2D(source.width, source.height, (TextureFormat)4, false); val.ReadPixels(new Rect(0f, 0f, (float)source.width, (float)source.height), 0, 0); val.Apply(); RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); Color32[] pixels = val.GetPixels32(); Object.Destroy((Object)val); return pixels; } internal static BannerImage RandomImage() { if (_images.Length == 0) { return null; } string text = NextPath(); if (_cache.TryGetValue(text, out var value)) { return value; } BannerImage bannerImage = null; try { bannerImage = Load(text); } catch (Exception ex) { Log.LogWarning((object)("could not read " + Path.GetFileName(text) + ": " + ex.Message)); } _cache[text] = bannerImage; return bannerImage; } private static string NextPath() { if (_randomBanner.Value) { return _images[Random.Range(0, _images.Length)]; } if (_next >= _images.Length) { for (int num = _images.Length - 1; num > 0; num--) { int num2 = Random.Range(0, num + 1); string text = _images[num]; _images[num] = _images[num2]; _images[num2] = text; } if (_images.Length > 1 && _images[0] == _lastShown) { int num3 = Random.Range(1, _images.Length); string text2 = _images[0]; _images[0] = _images[num3]; _images[num3] = text2; } _next = 0; } _lastShown = _images[_next++]; return _lastShown; } private static BannerImage Load(string path) { //IL_006f: 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_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown byte[] array = File.ReadAllBytes(path); string text = Path.GetExtension(path).ToLowerInvariant(); Color32[][] frames = null; float[] delays = null; int width = 0; int height = 0; if (text == ".gif") { GifDecoder.TryDecode(array, out frames, out delays, out width, out height); } else if (text == ".png") { ApngDecoder.TryDecode(array, out frames, out delays, out width, out height); } if (frames != null && frames.Length != 0) { return BuildAnimation(path, frames, delays, width, height); } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false) { name = Path.GetFileName(path), wrapMode = (TextureWrapMode)1 }; if (!ImageConversion.LoadImage(val, array)) { Log.LogWarning((object)("could not decode " + Path.GetFileName(path))); Object.Destroy((Object)(object)val); return null; } Color32[] pixels = val.GetPixels32(); int width2 = ((Texture)val).width; int height2 = ((Texture)val).height; string name = ((Object)val).name; Object.Destroy((Object)(object)val); bool useMask = _useStockAlpha.Value && IsFullyOpaque(pixels); Texture2D val2 = FitToCloth(pixels, width2, height2, name, useMask, _clothWidth); return new BannerImage((Texture2D[])(object)new Texture2D[1] { val2 }, new float[1]); } private static BannerImage BuildAnimation(string path, Color32[][] rawFrames, float[] rawDelays, int w, int h) { int num = Mathf.Min(rawFrames.Length, 200); if (num < rawFrames.Length) { Log.LogWarning((object)$"{Path.GetFileName(path)} has {rawFrames.Length} frames, using the first {num}"); } bool flag = _useStockAlpha.Value; int num2 = 0; while (flag && num2 < num) { flag = IsFullyOpaque(rawFrames[num2]); num2++; } int size = ((num > 1) ? Mathf.Min(256, _clothWidth) : _clothWidth); string fileName = Path.GetFileName(path); Texture2D[] array = (Texture2D[])(object)new Texture2D[num]; float[] array2 = new float[num]; for (int i = 0; i < num; i++) { array[i] = FitToCloth(rawFrames[i], w, h, fileName, flag, size); array2[i] = Mathf.Max(rawDelays[i], 0.01f); } Log.LogInfo((object)$"{Path.GetFileName(path)}: {num} frame(s), {w}x{h}"); return new BannerImage(array, array2); } private static bool IsFullyOpaque(Color32[] pixels) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < pixels.Length; i++) { if (pixels[i].a < byte.MaxValue) { return false; } } return true; } private static Texture2D FitToCloth(Color32[] source, int sourceWidth, int sourceHeight, string name, bool useMask, int size) { //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0139: 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) if (_clothPixels == null) { return MakeTexture(source, sourceWidth, sourceHeight, name, mipChain: false); } float num = ((Rect)(ref _clothWindow)).xMin * (float)size; float num2 = ((Rect)(ref _clothWindow)).xMax * (float)size; float num3 = ((Rect)(ref _clothWindow)).yMin * (float)size; float num4 = ((Rect)(ref _clothWindow)).yMax * (float)size; int num5 = Mathf.Max(0, Mathf.FloorToInt(num)); int num6 = Mathf.Min(size, Mathf.CeilToInt(num2)); int num7 = Mathf.Max(0, Mathf.FloorToInt(num3)); int num8 = Mathf.Min(size, Mathf.CeilToInt(num4)); Color32[] array = (Color32[])(object)new Color32[size * size]; for (int i = num7; i < num8; i++) { float num9 = ((float)i + 0.5f - num3) / (num4 - num3); int num10 = i * size; int num11 = i * _clothHeight / size * _clothWidth; for (int j = num5; j < num6; j++) { float num12 = 1f - ((float)j + 0.5f - num) / (num2 - num); Color32 val = Sample(source, sourceWidth, sourceHeight, Mathf.Clamp01(num12), Mathf.Clamp01(num9)); if (useMask) { val.a = (byte)(val.a * _clothPixels[num11 + j * _clothWidth / size].a / 255); } array[num10 + j] = val; } } return MakeTexture(array, size, size, name, mipChain: true); } private static Texture2D MakeTexture(Color32[] pixels, int width, int height, string name, bool mipChain) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //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) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown Texture2D val = new Texture2D(width, height, (TextureFormat)4, mipChain) { name = name, wrapMode = (TextureWrapMode)1 }; val.SetPixels32(pixels); val.Apply(); return val; } private static Color32 Sample(Color32[] pixels, int width, int height, float u, float v) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: 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_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: 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_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) float num = u * (float)width; float num2 = v * (float)height; int num3 = Mathf.FloorToInt(num); int num4 = Mathf.FloorToInt(num2); float tx = num - (float)num3; float ty = num2 - (float)num4; int num5 = Mathf.Clamp(num3, 0, width - 1); int num6 = Mathf.Clamp(num3 + 1, 0, width - 1); int num7 = Mathf.Clamp(num4, 0, height - 1) * width; int num8 = Mathf.Clamp(num4 + 1, 0, height - 1) * width; Color32 val = pixels[num7 + num5]; Color32 val2 = pixels[num7 + num6]; Color32 val3 = pixels[num8 + num5]; Color32 val4 = pixels[num8 + num6]; return new Color32(Blend(val.r, val2.r, val3.r, val4.r, tx, ty), Blend(val.g, val2.g, val3.g, val4.g, tx, ty), Blend(val.b, val2.b, val3.b, val4.b, tx, ty), Blend(val.a, val2.a, val3.a, val4.a, tx, ty)); } private static byte Blend(byte c00, byte c10, byte c01, byte c11, float tx, float ty) { float num = (float)(int)c00 + (float)(c10 - c00) * tx; float num2 = (float)(int)c01 + (float)(c11 - c01) * tx; return (byte)(num + (num2 - num) * ty + 0.5f); } } public class RandomBannerTexture : MonoBehaviour { private static bool _warned; private readonly List<Material> _cloth = new List<Material>(); private BannerImage _image; private int _frame; private float _timer; private void OnEnable() { //IL_0078: Unknown result type (might be due to invalid IL or missing references) _cloth.Clear(); _frame = 0; _timer = 0f; _image = MemeBannerPlugin.RandomImage(); if (_image == null || _image.Frames.Length == 0) { return; } Renderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<Renderer>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Material[] materials = componentsInChildren[i].materials; foreach (Material val in materials) { if (((Object)val).name.StartsWith("matWarbannerFlag", StringComparison.Ordinal)) { val.SetColor("_Color", Color.white); _cloth.Add(val); } } } if (_cloth.Count == 0) { if (!_warned) { _warned = true; MemeBannerPlugin.Log.LogWarning((object)"no 'matWarbannerFlag' material on the banner - the game model changed, banners stay vanilla"); } } else { Apply(); } } private void Update() { if (_image == null || _image.Frames.Length < 2 || _cloth.Count == 0) { return; } _timer += Time.deltaTime; bool flag = false; for (int i = 0; i < _image.Frames.Length; i++) { if (!(_timer >= _image.Delays[_frame])) { break; } _timer -= _image.Delays[_frame]; _frame = (_frame + 1) % _image.Frames.Length; flag = true; } if (flag) { Apply(); } } private void Apply() { Texture2D val = _image.Frames[_frame]; foreach (Material item in _cloth) { item.SetTexture("_MainTex", (Texture)(object)val); } } }