using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BarrkUI.ChatOverhaul; using BarrkUI.Compat; using BarrkUI.Configuration; using BarrkUI.Layout; using BarrkUI.Trading; using BarrkUI.UI; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using ServerSync; using SharedMedia; using SharedNet; using SharedUI; using Splatform; using TMPro; using UnityEngine; using UnityEngine.TextCore; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: IgnoresAccessChecksTo("assembly_guiutils")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: AssemblyCompany("VikingOS")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("VikingOS - rebuild Valheim's interface. Move, resize and rotate any UI element, plus chat fixes and item sharing.")] [assembly: AssemblyFileVersion("0.9.2.0")] [assembly: AssemblyInformationalVersion("0.9.2+5d942492f9f4a27b0ed403480e9fc3d59ea8eb7d")] [assembly: AssemblyProduct("VikingOS")] [assembly: AssemblyTitle("VikingOS")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.9.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [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; } } } namespace SharedMedia { public static class GifDecoder { public sealed class Frame { public Color32[] Pixels; public float DelaySeconds; } private sealed class Canvas { public int Width; public int Height; public Color32[] Pixels; } public const int MaxDimension = 512; public const int MaxFrames = 64; public static bool TryDecode(byte[] bytes, out int width, out int height, out List frames) { width = 0; height = 0; frames = null; try { return Decode(bytes, 64, out width, out height, out frames); } catch { frames = null; return false; } } private static bool Decode(byte[] b, int maxFrames, out int width, out int height, out List frames) { width = 0; height = 0; frames = null; if (b == null || b.Length < 13) { return false; } if (b[0] != 71 || b[1] != 73 || b[2] != 70 || b[3] != 56) { return false; } if ((b[4] != 55 && b[4] != 57) || b[5] != 97) { return false; } int num = 6; width = b[num] | (b[num + 1] << 8); height = b[num + 2] | (b[num + 3] << 8); byte b2 = b[num + 4]; num += 7; if (width <= 0 || height <= 0 || width > 512 || height > 512) { return false; } Color32[] array = null; if ((b2 & 0x80) != 0) { int size = 2 << (b2 & 7); array = ReadColourTable(b, ref num, size); if (array == null) { return false; } } Canvas canvas = new Canvas { Width = width, Height = height, Pixels = (Color32[])(object)new Color32[width * height] }; frames = new List(); float delaySeconds = 0.1f; int transparentIndex = -1; int num2 = 0; Color32[] array2 = null; while (num < b.Length) { switch (b[num++]) { case 33: if (num >= b.Length) { return false; } if (b[num++] == 249) { if (num + 5 >= b.Length) { return false; } int num7 = b[num++]; if (num7 >= 4) { byte num8 = b[num]; num2 = (num8 >> 2) & 7; int num9 = b[num + 1] | (b[num + 2] << 8); delaySeconds = ((num9 <= 1) ? 0.1f : ((float)num9 / 100f)); transparentIndex = (((num8 & 1) != 0) ? b[num + 3] : (-1)); } num += num7; if (!SkipSubBlocks(b, ref num)) { return false; } } else if (!SkipSubBlocks(b, ref num)) { return false; } continue; default: return false; case 44: { if (num + 9 > b.Length) { return false; } int num3 = b[num] | (b[num + 1] << 8); int num4 = b[num + 2] | (b[num + 3] << 8); int num5 = b[num + 4] | (b[num + 5] << 8); int num6 = b[num + 6] | (b[num + 7] << 8); byte b3 = b[num + 8]; num += 9; if (num5 <= 0 || num6 <= 0 || num3 < 0 || num4 < 0) { return false; } if (num3 + num5 > width || num4 + num6 > height) { return false; } bool interlaced = (b3 & 0x40) != 0; Color32[] array3 = array; if ((b3 & 0x80) != 0) { int size2 = 2 << (b3 & 7); array3 = ReadColourTable(b, ref num, size2); } if (array3 == null) { return false; } if (num2 == 3) { array2 = CopyRegion(canvas, num3, num4, num5, num6); } byte[] array4 = DecodeLzwImage(b, ref num, num5, num6); if (array4 == null) { return false; } DrawIndices(canvas, array4, array3, transparentIndex, num3, num4, num5, num6, interlaced); frames.Add(new Frame { Pixels = (Color32[])canvas.Pixels.Clone(), DelaySeconds = delaySeconds }); if (frames.Count >= maxFrames) { break; } switch (num2) { case 2: ClearRegion(canvas, num3, num4, num5, num6); break; case 3: if (array2 != null) { PasteRegion(canvas, array2, num3, num4, num5, num6); } break; } delaySeconds = 0.1f; transparentIndex = -1; num2 = 0; continue; } case 59: break; } break; } return frames.Count > 0; } private static Color32[] ReadColourTable(byte[] b, ref int pos, int size) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) if (pos + size * 3 > b.Length) { return null; } Color32[] array = (Color32[])(object)new Color32[size]; for (int i = 0; i < size; i++) { array[i] = new Color32(b[pos], b[pos + 1], b[pos + 2], byte.MaxValue); pos += 3; } return array; } private static bool SkipSubBlocks(byte[] b, ref int pos) { while (pos < b.Length) { int num = b[pos++]; if (num == 0) { return true; } pos += num; } return false; } private static byte[] DecodeLzwImage(byte[] b, ref int pos, int fw, int fh) { if (pos >= b.Length) { return null; } int num = b[pos++]; if (num < 2 || num > 11) { return null; } List list = new List(1024); while (pos < b.Length) { int num2 = b[pos++]; if (num2 == 0) { break; } if (pos + num2 > b.Length) { return null; } for (int i = 0; i < num2; i++) { list.Add(b[pos + i]); } pos += num2; } int num3 = 1 << num; int num4 = num3 + 1; int[] array = new int[4096]; byte[] array2 = new byte[4096]; byte[] array3 = new byte[4097]; int num5 = num + 1; int num6 = num4 + 1; int num7 = -1; byte[] array4 = new byte[fw * fh]; int num8 = 0; int num9 = 0; int j = 0; int num10 = 0; while (num8 < array4.Length) { for (; j < num5; j += 8) { if (num10 >= list.Count) { if (num8 <= 0) { return null; } return array4; } num9 |= list[num10++] << j; } int num11 = num9 & ((1 << num5) - 1); num9 >>= num5; j -= num5; if (num11 == num3) { num5 = num + 1; num6 = num4 + 1; num7 = -1; continue; } if (num11 == num4) { break; } int num12 = 0; int num13 = num11; if (num13 == num6 && num7 >= 0) { array3[num12++] = FirstByteOf(array, array2, num7, num3); num13 = num7; } else if (num13 > num6) { return null; } while (num13 >= num3 + 2) { if (num12 >= array3.Length) { return null; } array3[num12++] = array2[num13]; num13 = array[num13]; } if (num12 >= array3.Length) { return null; } array3[num12++] = (byte)num13; while (num12 > 0 && num8 < array4.Length) { array4[num8++] = array3[--num12]; } if (num7 >= 0 && num6 < 4096) { array[num6] = num7; array2[num6] = FirstByteOf(array, array2, (num11 == num6) ? num7 : num11, num3); num6++; if (num6 == 1 << num5 && num5 < 12) { num5++; } } num7 = num11; } return array4; } private static byte FirstByteOf(int[] prefix, byte[] suffix, int code, int clearCode) { int num = 0; while (code >= clearCode + 2) { code = prefix[code]; if (++num > 4096) { return 0; } } return (byte)code; } private static void DrawIndices(Canvas canvas, byte[] indices, Color32[] table, int transparentIndex, int left, int top, int fw, int fh, bool interlaced) { //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) int num = 0; for (int i = 0; i < ((!interlaced) ? 1 : 4); i++) { int num2 = (interlaced ? (new int[4] { 0, 4, 2, 1 })[i] : 0); int num3 = ((!interlaced) ? 1 : (new int[4] { 8, 8, 4, 2 })[i]); for (int j = num2; j < fh; j += num3) { int num4 = num * fw; num++; int num5 = (top + j) * canvas.Width + left; for (int k = 0; k < fw; k++) { int num6 = indices[num4 + k]; if (num6 != transparentIndex && num6 < table.Length) { canvas.Pixels[num5 + k] = table[num6]; } } } } } private static Color32[] CopyRegion(Canvas canvas, int left, int top, int fw, int fh) { Color32[] array = (Color32[])(object)new Color32[fw * fh]; for (int i = 0; i < fh; i++) { Array.Copy(canvas.Pixels, (top + i) * canvas.Width + left, array, i * fw, fw); } return array; } private static void PasteRegion(Canvas canvas, Color32[] region, int left, int top, int fw, int fh) { for (int i = 0; i < fh; i++) { Array.Copy(region, i * fw, canvas.Pixels, (top + i) * canvas.Width + left, fw); } } private static void ClearRegion(Canvas canvas, int left, int top, int fw, int fh) { //IL_0002: 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_0027: Unknown result type (might be due to invalid IL or missing references) Color32 val = default(Color32); for (int i = 0; i < fh; i++) { int num = (top + i) * canvas.Width + left; for (int j = 0; j < fw; j++) { canvas.Pixels[num + j] = val; } } } } public static class GifEncoder { public sealed class Frame { public Color32[] Pixels; public float DelaySeconds; } private sealed class SubBlockWriter { private readonly MemoryStream _out; private readonly byte[] _buffer = new byte[255]; private int _bufferAt; private int _bitBuffer; private int _bitCount; public SubBlockWriter(MemoryStream output) { _out = output; } public void WriteBits(int value, int bits) { _bitBuffer |= value << _bitCount; _bitCount += bits; while (_bitCount >= 8) { WriteByte((byte)(_bitBuffer & 0xFF)); _bitBuffer >>= 8; _bitCount -= 8; } } private void WriteByte(byte b) { _buffer[_bufferAt++] = b; if (_bufferAt >= 255) { _out.WriteByte(byte.MaxValue); _out.Write(_buffer, 0, 255); _bufferAt = 0; } } public void Flush() { if (_bitCount > 0) { WriteByte((byte)(_bitBuffer & 0xFF)); } if (_bufferAt > 0) { _out.WriteByte((byte)_bufferAt); _out.Write(_buffer, 0, _bufferAt); _bufferAt = 0; } _out.WriteByte(0); _bitBuffer = 0; _bitCount = 0; } } private const int PaletteSize = 256; private const int TransparentIndex = 252; public static byte[] Encode(int width, int height, List frames) { if (width <= 0 || height <= 0 || frames == null || frames.Count == 0) { return null; } using MemoryStream memoryStream = new MemoryStream(); Write(memoryStream, 71, 73, 70, 56, 57, 97); WriteU16(memoryStream, width); WriteU16(memoryStream, height); memoryStream.WriteByte(247); memoryStream.WriteByte(0); memoryStream.WriteByte(0); WritePalette(memoryStream); Write(memoryStream, 33, 255, 11); string text = "NETSCAPE2.0"; foreach (char c in text) { memoryStream.WriteByte((byte)c); } Write(memoryStream, 3, 1, 0, 0, 0); byte[] indices = new byte[width * height]; foreach (Frame frame in frames) { if (frame?.Pixels == null || frame.Pixels.Length < width * height) { return null; } int v = Mathf.Clamp(Mathf.RoundToInt(frame.DelaySeconds * 100f), 2, 65535); Write(memoryStream, 33, 249, 4, 9); WriteU16(memoryStream, v); memoryStream.WriteByte(252); memoryStream.WriteByte(0); memoryStream.WriteByte(44); WriteU16(memoryStream, 0); WriteU16(memoryStream, 0); WriteU16(memoryStream, width); WriteU16(memoryStream, height); memoryStream.WriteByte(0); Quantise(frame.Pixels, indices); WriteLzw(memoryStream, indices); } memoryStream.WriteByte(59); return memoryStream.ToArray(); } private static void WritePalette(MemoryStream ms) { for (int i = 0; i < 6; i++) { for (int j = 0; j < 7; j++) { for (int k = 0; k < 6; k++) { ms.WriteByte((byte)(i * 255 / 5)); ms.WriteByte((byte)(j * 255 / 6)); ms.WriteByte((byte)(k * 255 / 5)); } } } for (int l = 252; l < 256; l++) { ms.WriteByte(0); ms.WriteByte(0); ms.WriteByte(0); } } private static void Quantise(Color32[] pixels, byte[] indices) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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_0023: 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_0041: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < indices.Length; i++) { Color32 val = pixels[i]; if (val.a < 128) { indices[i] = 252; continue; } int num = val.r * 6 / 256; int num2 = val.g * 7 / 256; int num3 = val.b * 6 / 256; indices[i] = (byte)((num * 7 + num2) * 6 + num3); } } private static void WriteLzw(MemoryStream ms, byte[] indices) { ms.WriteByte(8); SubBlockWriter subBlockWriter = new SubBlockWriter(ms); Dictionary dictionary = new Dictionary(4096); int num = 9; int num2 = 258; subBlockWriter.WriteBits(256, num); int num3 = indices[0]; for (int i = 1; i < indices.Length; i++) { int num4 = indices[i]; int key = (num3 << 8) | num4; if (dictionary.TryGetValue(key, out var value)) { num3 = value; continue; } subBlockWriter.WriteBits(num3, num); dictionary[key] = num2; if (num2 == 1 << num && num < 12) { num++; } num2++; if (num2 >= 4096) { subBlockWriter.WriteBits(256, num); dictionary.Clear(); num = 9; num2 = 258; } num3 = num4; } subBlockWriter.WriteBits(num3, num); subBlockWriter.WriteBits(257, num); subBlockWriter.Flush(); } private static void Write(MemoryStream ms, params int[] bytes) { foreach (int num in bytes) { ms.WriteByte((byte)num); } } private static void WriteU16(MemoryStream ms, int v) { ms.WriteByte((byte)(v & 0xFF)); ms.WriteByte((byte)((v >> 8) & 0xFF)); } public static Color32[] Resize(Color32[] src, int srcW, int srcH, int dstW, int dstH) { //IL_00b4: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) Color32[] array = (Color32[])(object)new Color32[dstW * dstH]; if (srcW <= 0 || srcH <= 0 || dstW <= 0 || dstH <= 0) { return array; } for (int i = 0; i < dstH; i++) { float num = ((float)i + 0.5f) / (float)dstH * (float)srcH - 0.5f; int num2 = Mathf.Clamp(Mathf.FloorToInt(num), 0, srcH - 1); int num3 = Mathf.Min(num2 + 1, srcH - 1); float t = Mathf.Clamp01(num - (float)num2); for (int j = 0; j < dstW; j++) { float num4 = ((float)j + 0.5f) / (float)dstW * (float)srcW - 0.5f; int num5 = Mathf.Clamp(Mathf.FloorToInt(num4), 0, srcW - 1); int num6 = Mathf.Min(num5 + 1, srcW - 1); float t2 = Mathf.Clamp01(num4 - (float)num5); array[i * dstW + j] = Lerp(Lerp(src[num2 * srcW + num5], src[num2 * srcW + num6], t2), Lerp(src[num3 * srcW + num5], src[num3 * srcW + num6], t2), t); } } return array; } private static Color32 Lerp(Color32 a, Color32 b, float t) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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_0064: Unknown result type (might be due to invalid IL or missing references) return new Color32((byte)((float)(int)a.r + (float)(b.r - a.r) * t), (byte)((float)(int)a.g + (float)(b.g - a.g) * t), (byte)((float)(int)a.b + (float)(b.b - a.b) * t), (byte)((float)(int)a.a + (float)(b.a - a.a) * t)); } } } namespace SharedNet { public sealed class BlobLibrary { public enum BlobKind : byte { Png, Gif } public sealed class Entry { public string Name; public string Hash; public BlobKind Kind; public int Width; public int Height; public int Length; } public sealed class Limits { public int MaxBytes = 98304; public int MaxWidth = 256; public int MaxHeight = 256; public int MaxCount = 64; public bool AcceptGif; public Func OversizeRewriter; } private sealed class Incoming { public byte[][] Chunks; public int Received; public int Total; public float LastChunkAt; } private const byte CatalogueVersion = 1; private const int ChunkBytes = 32768; private const float TransferTimeoutSeconds = 15f; private readonly string _name; private readonly string _fetchRpc; private readonly string _chunkRpc; private readonly string _reloadRpc; private readonly string _reloadReplyRpc; private readonly CustomSyncedValue _catalogue; private readonly Func _packFolder; private readonly string _cacheDir; private readonly Limits _limits; private readonly Func _sharingEnabled; private readonly Func _host; private readonly Action _logInfo; private readonly Action _logWarning; private readonly Action _logError; private readonly Dictionary _decoded = new Dictionary(StringComparer.OrdinalIgnoreCase); private string _decodedFrom; private readonly List _packEntries = new List(); private readonly Dictionary _serverBlobs = new Dictionary(StringComparer.OrdinalIgnoreCase); private bool _serverScanned; private readonly HashSet _have = new HashSet(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _requested = new Dictionary(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _transfers = new Dictionary(StringComparer.OrdinalIgnoreCase); private Coroutine _pump; private Action _reloadReply; public int Revision { get; private set; } public event Action Changed; public BlobLibrary(string name, string rpcPrefix, CustomSyncedValue catalogue, Func packFolder, string cacheDir, Limits limits, Func sharingEnabled, Func coroutineHost, Action logInfo, Action logWarning, Action logError) { _name = name; _fetchRpc = rpcPrefix + "_Fetch"; _chunkRpc = rpcPrefix + "_Chunk"; _reloadRpc = rpcPrefix + "_Reload"; _reloadReplyRpc = rpcPrefix + "_Reloaded"; _catalogue = catalogue; _packFolder = packFolder; _cacheDir = cacheDir; _limits = limits ?? new Limits(); _sharingEnabled = sharingEnabled ?? ((Func)(() => true)); _host = coroutineHost; _logInfo = logInfo ?? ((Action)delegate { }); _logWarning = logWarning ?? ((Action)delegate { }); _logError = logError ?? ((Action)delegate { }); } public void OnSessionStart() { try { if (ZRoutedRpc.instance == null) { return; } ZRoutedRpc.instance.Register(_fetchRpc, (Action)RPC_Fetch); ZRoutedRpc.instance.Register(_chunkRpc, (Action)RPC_Chunk); ZRoutedRpc.instance.Register(_reloadRpc, (Action)RPC_Reload); ZRoutedRpc.instance.Register(_reloadReplyRpc, (Action)RPC_Reloaded); if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { ScanServerPack(); Publish(); } MonoBehaviour val = _host?.Invoke(); if ((Object)(object)val != (Object)null) { if (_pump != null) { val.StopCoroutine(_pump); } _pump = val.StartCoroutine(ClientPump()); } } catch (Exception arg) { _logError($"could not start the {_name} library (non-fatal, the feature idles this session). Reason: {arg}"); } } public void OnSessionEnd() { try { MonoBehaviour val = _host?.Invoke(); if (_pump != null && (Object)(object)val != (Object)null) { val.StopCoroutine(_pump); } _pump = null; _decoded.Clear(); _decodedFrom = null; _packEntries.Clear(); _serverBlobs.Clear(); _serverScanned = false; _have.Clear(); _requested.Clear(); _transfers.Clear(); Bump(); } catch (Exception arg) { _logError($"tearing down the {_name} library failed (non-fatal). Reason: {arg}"); } } private void Bump() { Revision++; try { this.Changed?.Invoke(); } catch (Exception arg) { _logError($"a {_name} change handler threw (non-fatal). Reason: {arg}"); } } public Entry Find(string name) { if (string.IsNullOrEmpty(name)) { return null; } EnsureDecoded(); if (!_decoded.TryGetValue(name, out var value)) { return null; } return value; } public List Entries() { EnsureDecoded(); return new List(_decoded.Values); } public bool HasBlob(string hash) { if (!string.IsNullOrEmpty(hash)) { return File.Exists(CachePath(hash)); } return false; } public byte[] TryReadBytes(Entry entry) { if (entry == null) { return null; } try { string path = CachePath(entry.Hash); if (File.Exists(path)) { return File.ReadAllBytes(path); } if (_serverBlobs.TryGetValue(entry.Hash, out var value) && File.Exists(value)) { return File.ReadAllBytes(value); } } catch (Exception arg) { _logError($"reading a cached {_name} failed (non-fatal). Reason: {arg}"); } return null; } private string CachePath(string hash) { return Path.Combine(_cacheDir, hash + ".bin"); } private void EnsureDecoded() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown string text = _catalogue.Value ?? ""; if (text == _decodedFrom) { return; } _decodedFrom = text; _decoded.Clear(); try { if (string.IsNullOrEmpty(text)) { Bump(); return; } ZPackage val = new ZPackage(text); byte b = val.ReadByte(); if (b != 1) { _logWarning($"the server's {_name} catalogue is format {b}, not {(byte)1} - ignoring it."); Bump(); return; } int num = val.ReadInt(); for (int i = 0; i < num; i++) { Entry entry = new Entry { Name = val.ReadString(), Hash = val.ReadString(), Kind = (BlobKind)val.ReadByte(), Width = val.ReadInt(), Height = val.ReadInt(), Length = val.ReadInt() }; if (!string.IsNullOrEmpty(entry.Name) && !string.IsNullOrEmpty(entry.Hash)) { _decoded[entry.Name] = entry; } } Bump(); } catch (Exception arg) { _decoded.Clear(); _logError($"the server's {_name} catalogue could not be read (non-fatal). Reason: {arg}"); } } public int ScanServerPack() { _serverBlobs.Clear(); _serverScanned = true; try { string text = _packFolder(); List list = new List(); if (Directory.Exists(text)) { list.AddRange(Directory.GetFiles(text, "*.png", SearchOption.TopDirectoryOnly)); if (_limits.AcceptGif) { list.AddRange(Directory.GetFiles(text, "*.gif", SearchOption.TopDirectoryOnly)); } } list.Sort(StringComparer.OrdinalIgnoreCase); int num = 0; foreach (string item in list) { if (num >= _limits.MaxCount) { _logWarning($"the {_name} pack holds more than {_limits.MaxCount} files - the rest are not offered to clients."); break; } if (RegisterPackFile(item)) { num++; } } _logInfo($"offering {num} {_name}(s) to clients from {text}."); return num; } catch (Exception arg) { _logError($"could not scan the {_name} pack (non-fatal). Reason: {arg}"); return 0; } } private bool RegisterPackFile(string path) { try { string name = Path.GetFileNameWithoutExtension(path); byte[] array = File.ReadAllBytes(path); if (!Identify(array, out var kind, out var w, out var h)) { _logWarning("not offering '" + Path.GetFileName(path) + "' - it is not a readable PNG" + (_limits.AcceptGif ? " or GIF" : "") + "."); return false; } if (array.Length > _limits.MaxBytes || w > _limits.MaxWidth || h > _limits.MaxHeight) { byte[] array2 = _limits.OversizeRewriter?.Invoke(path, array); if (array2 == null || array2.Length > _limits.MaxBytes || !Identify(array2, out kind, out w, out h) || w > _limits.MaxWidth || h > _limits.MaxHeight) { _logWarning("not offering '" + Path.GetFileName(path) + "' - over the limits " + $"({_limits.MaxBytes / 1024} KB, {_limits.MaxWidth}x{_limits.MaxHeight}) and it could not be shrunk to fit."); return false; } Directory.CreateDirectory(_cacheDir); string text = Path.Combine(_cacheDir, "pack-" + HashOf(array2) + ".bin"); File.WriteAllBytes(text, array2); _logInfo($"'{Path.GetFileName(path)}' was over the limits and has been shrunk to {array2.Length / 1024} KB ({w}x{h}) for transfer."); array = array2; path = text; } string text2 = HashOf(array); _serverBlobs[text2] = path; _packEntries.RemoveAll((Entry e) => string.Equals(e.Name, name, StringComparison.OrdinalIgnoreCase)); _packEntries.Add(new Entry { Name = name, Hash = text2, Kind = kind, Width = w, Height = h, Length = array.Length }); return true; } catch (Exception arg) { _logError($"could not read '{path}' (non-fatal, it is skipped). Reason: {arg}"); return false; } } private bool Identify(byte[] bytes, out BlobKind kind, out int w, out int h) { if (ReadPngHeader(bytes, out w, out h)) { kind = BlobKind.Png; return true; } if (_limits.AcceptGif && ReadGifHeader(bytes, out w, out h)) { kind = BlobKind.Gif; return true; } kind = BlobKind.Png; return false; } public void Publish() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Expected O, but got Unknown try { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } if (!_sharingEnabled()) { _catalogue.Value = ""; return; } if (!_serverScanned) { ScanServerPack(); } ZPackage val = new ZPackage(); val.Write((byte)1); val.Write(_packEntries.Count); foreach (Entry packEntry in _packEntries) { val.Write(packEntry.Name); val.Write(packEntry.Hash); val.Write((byte)packEntry.Kind); val.Write(packEntry.Width); val.Write(packEntry.Height); val.Write(packEntry.Length); } _catalogue.Value = val.GetBase64(); } catch (Exception arg) { _logError($"publishing the {_name} catalogue failed (non-fatal, clients keep the previous one). Reason: {arg}"); } } public int Reload() { _packEntries.Clear(); int result = ScanServerPack(); Publish(); return result; } public void RequestReload(Action reply) { _reloadReply = reply; if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { int num = Reload(); reply?.Invoke($"now offering {num} {_name}(s)."); return; } ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC(_reloadRpc, Array.Empty()); } reply?.Invoke("asked the server to rescan its " + _name + " folder..."); } private IEnumerator ClientPump() { while ((Object)(object)ZNet.instance == (Object)null) { yield return null; } if (ZNet.instance.IsServer()) { foreach (string key in _serverBlobs.Keys) { _have.Add(key); } } else { while ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.GetPeers().Count == 0) { yield return null; } yield return (object)new WaitForSeconds(2f); } while (true) { yield return (object)new WaitForSeconds(1f); PumpOnce(); } } private void PumpOnce() { try { EnsureDecoded(); if (_decoded.Count == 0) { return; } if (_requested.Count > 0) { List list = null; foreach (KeyValuePair item in _requested) { Incoming value; float num = (_transfers.TryGetValue(item.Key, out value) ? value.LastChunkAt : item.Value); if (!(Time.realtimeSinceStartup - num <= 15f)) { (list ?? (list = new List())).Add(item.Key); } } if (list != null) { foreach (string item2 in list) { _transfers.Remove(item2); _requested.Remove(item2); } _logWarning("a " + _name + " download stalled or went unanswered - it will be asked for again."); } } if (_transfers.Count > 0) { return; } foreach (Entry value2 in _decoded.Values) { if (!_have.Contains(value2.Hash) && !_requested.ContainsKey(value2.Hash)) { if (!HasBlob(value2.Hash)) { Request(value2); break; } _have.Add(value2.Hash); Bump(); } } } catch (Exception arg) { _logError($"the {_name} download pump failed (non-fatal). Reason: {arg}"); } } private void Request(Entry e) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown try { if (e.Length > _limits.MaxBytes) { _logWarning($"not fetching '{e.Name}' - the server says it is {e.Length / 1024} KB, over the {_limits.MaxBytes / 1024} KB limit."); _have.Add(e.Hash); return; } _requested[e.Hash] = Time.realtimeSinceStartup; ZPackage val = new ZPackage(); val.Write(e.Hash); ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC(_fetchRpc, new object[1] { val }); } } catch (Exception arg) { _requested.Remove(e.Hash); _logError($"asking for the {_name} '{e.Name}' failed (non-fatal). Reason: {arg}"); } } private void RPC_Fetch(long sender, ZPackage pkg) { try { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || pkg == null || !_sharingEnabled()) { return; } string text = pkg.ReadString(); if (!string.IsNullOrEmpty(text) && _serverBlobs.TryGetValue(text, out var value) && File.Exists(value)) { MonoBehaviour val = _host?.Invoke(); if ((Object)(object)val != (Object)null) { val.StartCoroutine(SendBlob(sender, text, value)); } } } catch (Exception arg) { _logError($"{_name} fetch handler failed (non-fatal). Reason: {arg}"); } } private IEnumerator SendBlob(long target, string hash, string path) { byte[] bytes = null; try { bytes = File.ReadAllBytes(path); } catch (Exception arg) { _logError($"could not read '{path}' to send it (non-fatal). Reason: {arg}"); } if (bytes == null || bytes.Length == 0) { yield break; } int total = Mathf.Max(1, Mathf.CeilToInt((float)bytes.Length / 32768f)); for (int i = 0; i < total; i++) { int num = i * 32768; int num2 = Mathf.Min(32768, bytes.Length - num); byte[] array = new byte[num2]; Buffer.BlockCopy(bytes, num, array, 0, num2); try { ZPackage val = new ZPackage(); val.Write(hash); val.Write(i); val.Write(total); val.Write(array); ZRoutedRpc instance = ZRoutedRpc.instance; if (instance != null) { instance.InvokeRoutedRPC(target, _chunkRpc, new object[1] { val }); } } catch (Exception arg2) { _logError($"sending a {_name} chunk failed (non-fatal, the client will retry). Reason: {arg2}"); break; } yield return null; } } private void RPC_Chunk(long sender, ZPackage pkg) { try { if (pkg == null || ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer())) { return; } string text = pkg.ReadString(); int num = pkg.ReadInt(); int num2 = pkg.ReadInt(); byte[] array = pkg.ReadByteArray(); if (string.IsNullOrEmpty(text) || array == null || num2 <= 0 || num < 0 || num >= num2 || num2 > _limits.MaxBytes / 32768 + 1 || array.Length > 32768 || !_requested.ContainsKey(text)) { return; } if (!_transfers.TryGetValue(text, out var value)) { value = new Incoming { Chunks = new byte[num2][], Total = num2 }; _transfers[text] = value; } if (value.Total == num2 && value.Chunks[num] == null) { value.Chunks[num] = array; value.Received++; value.LastChunkAt = Time.realtimeSinceStartup; if (value.Received >= value.Total) { _transfers.Remove(text); _requested.Remove(text); Complete(text, value); } } } catch (Exception arg) { _logError($"{_name} chunk handler failed (non-fatal). Reason: {arg}"); } } private void Complete(string hash, Incoming t) { try { int num = 0; byte[][] chunks = t.Chunks; foreach (byte[] array in chunks) { num += array.Length; } if (num <= _limits.MaxBytes) { byte[] array2 = new byte[num]; int num2 = 0; chunks = t.Chunks; foreach (byte[] array3 in chunks) { Buffer.BlockCopy(array3, 0, array2, num2, array3.Length); num2 += array3.Length; } if (!string.Equals(HashOf(array2), hash, StringComparison.OrdinalIgnoreCase)) { _logWarning("a downloaded " + _name + " did not match its hash and was discarded."); return; } if ((!ReadPngHeader(array2, out var width, out var height) && (!_limits.AcceptGif || !ReadGifHeader(array2, out width, out height))) || width > _limits.MaxWidth || height > _limits.MaxHeight) { _logWarning("a downloaded " + _name + " was not an image of a sensible size and was discarded."); return; } Directory.CreateDirectory(_cacheDir); File.WriteAllBytes(CachePath(hash), array2); _have.Add(hash); Bump(); } } catch (Exception arg) { _logError($"storing a downloaded {_name} failed (non-fatal). Reason: {arg}"); } } private void RPC_Reload(long sender) { try { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { ZNetPeer peer = ZNet.instance.GetPeer(sender); string text = ((peer != null && peer.m_socket != null) ? peer.m_socket.GetHostName() : ""); if (!ZNet.instance.ListContainsId(ZNet.instance.m_adminList, text)) { _logWarning("refused a " + _name + " reload from " + text + " - not on the adminlist."); ZRoutedRpc.instance.InvokeRoutedRPC(sender, _reloadReplyRpc, new object[1] { -1 }); } else { int num = Reload(); _logInfo($"{_name} reload (via {text}): now offering {num} file(s)."); ZRoutedRpc.instance.InvokeRoutedRPC(sender, _reloadReplyRpc, new object[1] { num }); } } } catch (Exception arg) { _logError($"{_name} reload handler failed (non-fatal). Reason: {arg}"); } } private void RPC_Reloaded(long sender, int count) { try { string obj = ((count < 0) ? ("the server refused the " + _name + " reload - you are not on its adminlist.") : $"the server is now offering {count} {_name}(s). Players receive any they are missing shortly."); _reloadReply?.Invoke(obj); _reloadReply = null; _logInfo(obj); } catch (Exception arg) { _logError($"{_name} reload reply handler failed (non-fatal). Reason: {arg}"); } } public static string HashOf(byte[] bytes) { using SHA1 sHA = SHA1.Create(); byte[] array = sHA.ComputeHash(bytes); StringBuilder stringBuilder = new StringBuilder(16); for (int i = 0; i < 8; i++) { stringBuilder.Append(array[i].ToString("x2")); } return stringBuilder.ToString(); } public static bool ReadPngHeader(byte[] b, out int width, out int height) { width = 0; height = 0; if (b == null || b.Length < 24) { return false; } if (b[0] != 137 || b[1] != 80 || b[2] != 78 || b[3] != 71 || b[4] != 13 || b[5] != 10 || b[6] != 26 || b[7] != 10) { return false; } if (b[12] != 73 || b[13] != 72 || b[14] != 68 || b[15] != 82) { return false; } width = (b[16] << 24) | (b[17] << 16) | (b[18] << 8) | b[19]; height = (b[20] << 24) | (b[21] << 16) | (b[22] << 8) | b[23]; if (width > 0 && height > 0 && width <= 16384) { return height <= 16384; } return false; } public static bool ReadGifHeader(byte[] b, out int width, out int height) { width = 0; height = 0; if (b == null || b.Length < 13) { return false; } if (b[0] != 71 || b[1] != 73 || b[2] != 70 || b[3] != 56) { return false; } if (b[4] != 55 && b[4] != 57) { return false; } if (b[5] != 97) { return false; } width = b[6] | (b[7] << 8); height = b[8] | (b[9] << 8); if (width > 0) { return height > 0; } return false; } } } namespace SharedUI { internal enum FrameStyle { Gilt, Runic, Serpent, Ironbound } internal struct ThemeOptions { public Color Metal; public bool DeriveTones; public Color Deep; public Color Bright; public Color Panel; public float PanelOpacity; public Color Text; public Color MutedText; public float Scale; public int BodyDelta; public int TitleDelta; public int SubTitleDelta; public int HeaderDelta; public int ButtonDelta; public int RowDelta; public int FooterDelta; public int FieldDelta; public FrameStyle Frame; public static ThemeOptions Default => new ThemeOptions { Metal = new Color(0.8f, 0.62f, 0.26f, 1f), DeriveTones = true, Deep = new Color(0.26f, 0.17f, 0.05f, 1f), Bright = new Color(1f, 0.94f, 0.72f, 1f), Panel = new Color(0.075f, 0.065f, 0.051f, 1f), PanelOpacity = 0.955f, Text = new Color(0.9f, 0.86f, 0.75f, 1f), MutedText = new Color(0.6f, 0.56f, 0.48f, 1f), Scale = 1f, BodyDelta = 0, TitleDelta = 0, SubTitleDelta = 0, HeaderDelta = 0, ButtonDelta = 0, RowDelta = 0, FooterDelta = 0, FieldDelta = 0, Frame = FrameStyle.Gilt }; } internal static class GiltFrameTheme { private enum Edge { Top, Bottom, Left, Right } private sealed class Painter { public bool MirrorX; public bool MirrorY; public bool Transpose; private readonly int _w; private readonly int _h; private readonly float[] _a; private readonly float[] _z; public Painter(int w, int h) { _w = w; _h = h; _a = new float[w * h]; _z = new float[w * h]; } private void Put(float fx, float fy, float a, float z) { if (a <= 0f) { return; } if (Transpose) { float num = fx; fx = fy; fy = num; } int num2 = Mathf.RoundToInt(fx); int num3 = Mathf.RoundToInt(fy); if (MirrorX) { num2 = _w - 1 - num2; } if (MirrorY) { num3 = _h - 1 - num3; } if (num2 >= 0 && num3 >= 0 && num2 < _w && num3 < _h) { int num4 = num3 * _w + num2; if (a > _a[num4]) { _a[num4] = a; } if (z > _z[num4]) { _z[num4] = z; } } } public void Disc(float cx, float cy, float r) { if (r <= 0f) { return; } int num = Mathf.FloorToInt(cx - r - 1f); int num2 = Mathf.CeilToInt(cx + r + 1f); int num3 = Mathf.FloorToInt(cy - r - 1f); int num4 = Mathf.CeilToInt(cy + r + 1f); for (int i = num3; i <= num4; i++) { for (int j = num; j <= num2; j++) { float num5 = (float)j - cx; float num6 = (float)i - cy; float num7 = Mathf.Sqrt(num5 * num5 + num6 * num6); float num8 = Mathf.Clamp01(r + 0.5f - num7); if (!(num8 <= 0f)) { Put(j, i, num8, Mathf.Sqrt(Mathf.Max(0f, 1f - num7 / r * (num7 / r)))); } } } } public void Lozenge(float cx, float cy, float r) { int num = Mathf.FloorToInt(cx - r - 1f); int num2 = Mathf.CeilToInt(cx + r + 1f); int num3 = Mathf.FloorToInt(cy - r - 1f); int num4 = Mathf.CeilToInt(cy + r + 1f); for (int i = num3; i <= num4; i++) { for (int j = num; j <= num2; j++) { float num5 = Mathf.Abs((float)j - cx) + Mathf.Abs((float)i - cy); float num6 = Mathf.Clamp01(r + 0.5f - num5); if (!(num6 <= 0f)) { Put(j, i, num6, Mathf.Sqrt(Mathf.Max(0f, 1f - num5 / r * (num5 / r)))); } } } } public void Taper(Vector2 a, Vector2 b, float w0, float w1) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.Max(8, Mathf.CeilToInt(Vector2.Distance(a, b) * 3f)); for (int i = 0; i <= num; i++) { float num2 = (float)i / (float)num; Vector2 val = Vector2.Lerp(a, b, num2); Disc(val.x, val.y, Mathf.Lerp(w0, w1, num2)); } } public void Bezier(Vector2 a, Vector2 b, Vector2 c, float w0, float w1) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: 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_0037: 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.Max(16, Mathf.CeilToInt((Vector2.Distance(a, b) + Vector2.Distance(b, c)) * 3f)); for (int i = 0; i <= num; i++) { float num2 = (float)i / (float)num; float num3 = 1f - num2; Vector2 val = num3 * num3 * a + 2f * num3 * num2 * b + num2 * num2 * c; Disc(val.x, val.y, Mathf.Lerp(w0, w1, num2)); } } public void Spiral(Vector2 eye, float r0, float growth, float t0, float t1, float phase, float w0, float w1, bool mirror = false) { //IL_005c: 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) int num = Mathf.Max(48, Mathf.CeilToInt((t1 - t0) * 40f)); for (int i = 0; i <= num; i++) { float num2 = (float)i / (float)num; float num3 = Mathf.Lerp(t0, t1, num2); float num4 = r0 * Mathf.Exp(growth * num3); float num5 = num3 + phase; float num6 = Mathf.Cos(num5) * num4; float num7 = Mathf.Sin(num5) * num4; if (mirror) { num6 = 0f - num6; } Disc(eye.x + num6, eye.y + num7, Mathf.Lerp(w0, w1, num2)); } } public void RailPixel(int x, int y, float d, float half) { float num = Mathf.Clamp01(half + 0.5f - d); if (!(num <= 0f)) { Put(x, y, num, Mathf.Sqrt(Mathf.Max(0f, 1f - d / half * (d / half)))); } } public void SquareElbow(float mid, float half, float centre) { for (int i = 0; i < _h; i++) { for (int j = 0; j < _w; j++) { float d = Mathf.Min(Mathf.Abs((float)j - mid), Mathf.Abs((float)i - mid)); if (!((float)j > centre) || !((float)i > centre)) { RailPixel(j, i, d, half); } } } } public void RailElbow(float mid, float half, float centre) { float num = centre - mid; for (int i = 0; i < _h; i++) { for (int j = 0; j < _w; j++) { float d; if (!((float)j <= centre) || !((float)i <= centre)) { d = ((!((float)i <= centre)) ? ((!((float)j <= centre)) ? Mathf.Min(Mathf.Abs((float)i - mid), Mathf.Abs((float)j - mid)) : Mathf.Abs((float)j - mid)) : Mathf.Abs((float)i - mid)); } else { float num2 = (float)j - centre; float num3 = (float)i - centre; d = Mathf.Abs(Mathf.Sqrt(num2 * num2 + num3 * num3) - num); } RailPixel(j, i, d, half); } } } public Texture2D Bake() { //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_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: 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_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_00ef: 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) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) Texture2D val = New(_w, _h, (TextureWrapMode)1, (FilterMode)1); Color[] array = (Color[])(object)new Color[_w * _h]; for (int i = 0; i < _h; i++) { for (int j = 0; j < _w; j++) { int num = i * _w + j; float num2 = _a[num]; int num3 = (_h - 1 - i) * _w + j; if (num2 <= 0f) { array[num3] = Color.clear; continue; } float num4 = Z(j - 1, i) - Z(j + 1, i) + (Z(j, i - 1) - Z(j, i + 1)); float num5 = Mathf.Clamp01(0.42f + 0.5f * num4 + 0.18f * _z[num]); Color val2 = ((num5 < 0.5f) ? Color.Lerp(GoldDeep, Gold, num5 * 2f) : Color.Lerp(Gold, GoldBright, (num5 - 0.5f) * 2f)); array[num3] = new Color(val2.r, val2.g, val2.b, num2); } } val.SetPixels(array); val.Apply(false); return val; } private float Z(int x, int y) { return _z[Mathf.Clamp(y, 0, _h - 1) * _w + Mathf.Clamp(x, 0, _w - 1)]; } } public static Color GoldDeep = new Color(0.26f, 0.17f, 0.05f, 1f); public static Color Gold = new Color(0.8f, 0.62f, 0.26f, 1f); public static Color GoldBright = new Color(1f, 0.94f, 0.72f, 1f); public static Color Parchment = new Color(0.9f, 0.86f, 0.75f, 1f); public static Color Muted = new Color(0.6f, 0.56f, 0.48f, 1f); private static ThemeOptions _bakedFrom = ThemeOptions.Default; private static bool _everBaked; private static int _appliedFrame = -1; private static bool _conflictLogged; private static readonly ManualLogSource Log = Logger.CreateLogSource("SharedUI.GiltFrameTheme"); public const string HexMuted = "#9A9182"; public const string HexLocked = "#E0736B"; public const string HexOpen = "#87D278"; public const float Band = 18f; public const float Pad = 22f; public static float TitleHeight = 54f; public static float FooterHeight = 30f; private static int _fontDelta; private static ThemeOptions _styledFrom = ThemeOptions.Default; private static bool _everStyled; private const int CornerTile = 84; private const float Overhang = 10f; private const float CornerExtent = 74f; private const int CrestW = 56; private const int CrestH = 34; private const float CrestOverhang = 8f; private const float OuterMid = 4.4f; private const float OuterHalf = 2.7f; private const float InnerMid = 12.4f; private const float InnerHalf = 1.6f; private const float BendCentre = 32f; public static GUIStyle Title; public static GUIStyle SubTitle; public static GUIStyle Header; public static GUIStyle Key; public static GUIStyle Value; public static GUIStyle Note; public static GUIStyle Footer; public static GUIStyle Button; public static GUIStyle Primary; public static GUIStyle Row; public static GUIStyle Field; public static GUIStyle ImageButton; private static Texture2D _railTop; private static Texture2D _railBottom; private static Texture2D _railLeft; private static Texture2D _railRight; private static Texture2D _cornerTL; private static Texture2D _cornerTR; private static Texture2D _cornerBL; private static Texture2D _cornerBR; private static Texture2D _crestTop; private static Texture2D _crestBottom; private static Texture2D _diamond; private static Texture2D _heart; private static Texture2D _dot; private static Texture2D _panel; private static Texture2D _white; private static Texture2D _btnNormal; private static Texture2D _btnHover; private static Texture2D _btnActive; private static Texture2D _rowNormal; private static Texture2D _rowHover; private static Texture2D _rowActive; private static Texture2D _selection; private static Texture2D _fieldTex; private static bool _railRepeats; private static float _railTileLength = 4f; public static float TextScale { get; private set; } = 1f; public static Color Metal(float alpha) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) return new Color(Gold.r, Gold.g, Gold.b, alpha); } public static Color MetalBright(float alpha) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) return new Color(GoldBright.r, GoldBright.g, GoldBright.b, alpha); } public static Color MetalDeep(float alpha) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) return new Color(GoldDeep.r, GoldDeep.g, GoldDeep.b, alpha); } private static bool BakeInputsMatch(ThemeOptions o) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_0068: 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) if (_everBaked && o.Frame == _bakedFrom.Frame && o.Metal == _bakedFrom.Metal && o.DeriveTones == _bakedFrom.DeriveTones && (o.DeriveTones || (o.Deep == _bakedFrom.Deep && o.Bright == _bakedFrom.Bright)) && o.Panel == _bakedFrom.Panel) { return Mathf.Approximately(o.PanelOpacity, _bakedFrom.PanelOpacity); } return false; } private static bool StyleInputsMatch(ThemeOptions o) { //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) if (_everStyled && Title != null && Mathf.Approximately(o.Scale, _styledFrom.Scale) && o.BodyDelta == _styledFrom.BodyDelta && o.TitleDelta == _styledFrom.TitleDelta && o.SubTitleDelta == _styledFrom.SubTitleDelta && o.HeaderDelta == _styledFrom.HeaderDelta && o.ButtonDelta == _styledFrom.ButtonDelta && o.RowDelta == _styledFrom.RowDelta && o.FooterDelta == _styledFrom.FooterDelta && o.FieldDelta == _styledFrom.FieldDelta && o.Text == _styledFrom.Text) { return o.MutedText == _styledFrom.MutedText; } return false; } public static float S(float v) { return Mathf.Round(v * TextScale); } public static void EnsureBuilt(Color goldColour, float textScale = 1f, int fontSizeDelta = 0, int headingDelta = 0) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) ThemeOptions o = ThemeOptions.Default; o.Metal = goldColour; o.Scale = textScale; o.BodyDelta = fontSizeDelta; o.TitleDelta = headingDelta; o.SubTitleDelta = headingDelta; o.HeaderDelta = headingDelta; EnsureBuilt(o); } public static void EnsureBuilt(ThemeOptions o) { //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Unknown result type (might be due to invalid IL or missing references) //IL_0283: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_0297: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_03ca: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Unknown result type (might be due to invalid IL or missing references) //IL_03f9: Unknown result type (might be due to invalid IL or missing references) //IL_03fe: Unknown result type (might be due to invalid IL or missing references) //IL_0418: Unknown result type (might be due to invalid IL or missing references) //IL_041d: Unknown result type (might be due to invalid IL or missing references) //IL_0437: Unknown result type (might be due to invalid IL or missing references) //IL_043c: Unknown result type (might be due to invalid IL or missing references) //IL_044b: Unknown result type (might be due to invalid IL or missing references) //IL_0450: Unknown result type (might be due to invalid IL or missing references) //IL_0482: Unknown result type (might be due to invalid IL or missing references) //IL_04aa: Unknown result type (might be due to invalid IL or missing references) //IL_04dc: Unknown result type (might be due to invalid IL or missing references) //IL_04e1: Unknown result type (might be due to invalid IL or missing references) //IL_0513: Unknown result type (might be due to invalid IL or missing references) //IL_052d: Unknown result type (might be due to invalid IL or missing references) //IL_0532: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_railTop != (Object)null && BakeInputsMatch(o) && StyleInputsMatch(o)) { _appliedFrame = Time.frameCount; return; } if ((Object)(object)_railTop != (Object)null && _appliedFrame == Time.frameCount) { if (!_conflictLogged) { _conflictLogged = true; Log.LogWarning((object)("Two consumers of SharedUI.GiltFrameTheme asked for different values in the same " + $"frame (live: metal={_bakedFrom.Metal}, frame={_bakedFrom.Frame}, scale={TextScale}, " + $"delta={_fontDelta}; requested: metal={o.Metal}, frame={o.Frame}, scale={o.Scale}, " + $"delta={o.BodyDelta}). The theme is a single shared bake, so the first caller each " + "frame wins. Set the same UI theme values in every mod that uses this theme to resolve it.")); } return; } if ((Object)(object)_railTop != (Object)null && !BakeInputsMatch(o)) { DestroyTextures(); } if ((Object)(object)_railTop != (Object)null) { if (!StyleInputsMatch(o)) { BuildStyles(o); } _appliedFrame = Time.frameCount; return; } _bakedFrom = o; _everBaked = true; Gold = new Color(o.Metal.r, o.Metal.g, o.Metal.b, 1f); Parchment = o.Text; Muted = o.MutedText; if (!o.DeriveTones) { GoldDeep = o.Deep; GoldBright = o.Bright; } else if (Mathf.Approximately(Gold.r, 0.8f) && Mathf.Approximately(Gold.g, 0.62f) && Mathf.Approximately(Gold.b, 0.26f)) { GoldDeep = new Color(0.26f, 0.17f, 0.05f, 1f); GoldBright = new Color(1f, 0.94f, 0.72f, 1f); } else { GoldDeep = new Color(Gold.r * 0.325f, Gold.g * 0.274f, Gold.b * 0.192f, 1f); GoldBright = Color.Lerp(Gold, Color.white, 0.72f); } _railTop = BuildRail(o.Frame, Edge.Top); _railBottom = BuildRail(o.Frame, Edge.Bottom); _railLeft = BuildRail(o.Frame, Edge.Left); _railRight = BuildRail(o.Frame, Edge.Right); _railRepeats = RailRepeats(o.Frame); _railTileLength = RailTile(o.Frame); if (_railRepeats) { ((Texture)_railTop).wrapMode = (TextureWrapMode)0; ((Texture)_railBottom).wrapMode = (TextureWrapMode)0; ((Texture)_railLeft).wrapMode = (TextureWrapMode)0; ((Texture)_railRight).wrapMode = (TextureWrapMode)0; } _cornerTL = BuildCorner(o.Frame, mirrorX: false, mirrorY: false); _cornerTR = BuildCorner(o.Frame, mirrorX: true, mirrorY: false); _cornerBL = BuildCorner(o.Frame, mirrorX: false, mirrorY: true); _cornerBR = BuildCorner(o.Frame, mirrorX: true, mirrorY: true); _crestTop = BuildCrest(o.Frame, flip: false); _crestBottom = BuildCrest(o.Frame, flip: true); _diamond = BuildDiamond(14); _heart = BuildHeart(28); _dot = BuildDot(24); _panel = BuildPanel(64, o.Panel, o.PanelOpacity); _white = BuildSolid(Color.white); _btnNormal = BuildPatch(Surface(o, 0.35f, 0.95f), GoldDeep); _btnHover = BuildPatch(Surface(o, 1.3f, 0.97f), Gold); _btnActive = BuildPatch(Surface(o, 2.6f, 0.98f), GoldBright); _rowNormal = BuildPatch(Color.clear, Color.clear); _rowHover = BuildPatch(new Color(Gold.r, Gold.g, Gold.b, 0.1f), new Color(Gold.r, Gold.g, Gold.b, 0.45f)); _rowActive = BuildPatch(new Color(Gold.r, Gold.g, Gold.b, 0.2f), Gold); _selection = BuildSolid(new Color(Gold.r, Gold.g, Gold.b, 0.15f)); _fieldTex = BuildPatch(Surface(o, -0.45f, 0.95f), GoldDeep); BuildStyles(o); _appliedFrame = Time.frameCount; } private static Color Surface(ThemeOptions o, float lift, float alpha) { //IL_0001: 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_003e: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_002a: 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) //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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) Color panel = o.Panel; if (lift >= 0f) { float num = Mathf.Clamp01(lift * 0.25f); panel = Color.Lerp(panel * (1f + lift * 0.55f), o.Metal, num); } else { panel *= Mathf.Clamp01(1f + lift); } return new Color(Mathf.Clamp01(panel.r), Mathf.Clamp01(panel.g), Mathf.Clamp01(panel.b), alpha); } private static void DestroyTextures() { Texture2D[] array = (Texture2D[])(object)new Texture2D[23] { _railTop, _railBottom, _railLeft, _railRight, _cornerTL, _cornerTR, _cornerBL, _cornerBR, _crestTop, _crestBottom, _diamond, _heart, _panel, _white, _dot, _btnNormal, _btnHover, _btnActive, _rowNormal, _rowHover, _rowActive, _selection, _fieldTex }; foreach (Texture2D val in array) { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } } _railTop = (_railBottom = (_railLeft = (_railRight = null))); _cornerTL = (_cornerTR = (_cornerBL = (_cornerBR = null))); _crestTop = (_crestBottom = (_diamond = (_heart = (_dot = null)))); _panel = (_white = null); _btnNormal = (_btnHover = (_btnActive = null)); _rowNormal = (_rowHover = (_rowActive = (_selection = null))); _fieldTex = null; Title = null; } public static void DrawWindow(Rect win, string title) { //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_0044: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) DrawPanelFill(win); DrawFrame(win); DrawShadowed(new Rect(((Rect)(ref win)).x + 74f, ((Rect)(ref win)).y + 18f + 8f, ((Rect)(ref win)).width - 148f, TitleHeight - 20f), (title ?? string.Empty).ToUpperInvariant(), Title); DrawRule(new Rect(((Rect)(ref win)).x + 18f + 22f, ((Rect)(ref win)).y + 18f + TitleHeight - 12f, ((Rect)(ref win)).width - 80f, 1f)); } public static void DrawPanelFill(Rect win) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) GUI.DrawTexture(new Rect(((Rect)(ref win)).x + 1f, ((Rect)(ref win)).y + 1f, ((Rect)(ref win)).width - 2f, ((Rect)(ref win)).height - 2f), (Texture)(object)_panel, (ScaleMode)0); } public static Rect Body(Rect win) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) return new Rect(((Rect)(ref win)).x + 18f + 22f, ((Rect)(ref win)).y + 18f + TitleHeight, ((Rect)(ref win)).width - 80f, ((Rect)(ref win)).height - 36f - TitleHeight - FooterHeight); } public static Rect FooterLine(Rect win) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) return new Rect(((Rect)(ref win)).x + 18f + 22f, ((Rect)(ref win)).yMax - 18f - FooterHeight, ((Rect)(ref win)).width - 80f, S(18f)); } public static void DrawFrame(Rect r) { //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0221: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02bb: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) //IL_0352: Unknown result type (might be due to invalid IL or missing references) //IL_037a: Unknown result type (might be due to invalid IL or missing references) float num = ((Rect)(ref r)).width - 148f; float num2 = ((Rect)(ref r)).height - 148f; if (_railRepeats) { float num3 = Mathf.Max(1f, _railTileLength); GUI.DrawTextureWithTexCoords(new Rect(((Rect)(ref r)).x + 74f, ((Rect)(ref r)).y, num, 18f), (Texture)(object)_railTop, new Rect(0f, 0f, num / num3, 1f)); GUI.DrawTextureWithTexCoords(new Rect(((Rect)(ref r)).x + 74f, ((Rect)(ref r)).yMax - 18f, num, 18f), (Texture)(object)_railBottom, new Rect(0f, 0f, num / num3, 1f)); GUI.DrawTextureWithTexCoords(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y + 74f, 18f, num2), (Texture)(object)_railLeft, new Rect(0f, 0f, 1f, num2 / num3)); GUI.DrawTextureWithTexCoords(new Rect(((Rect)(ref r)).xMax - 18f, ((Rect)(ref r)).y + 74f, 18f, num2), (Texture)(object)_railRight, new Rect(0f, 0f, 1f, num2 / num3)); } else { GUI.DrawTexture(new Rect(((Rect)(ref r)).x + 74f, ((Rect)(ref r)).y, num, 18f), (Texture)(object)_railTop); GUI.DrawTexture(new Rect(((Rect)(ref r)).x + 74f, ((Rect)(ref r)).yMax - 18f, num, 18f), (Texture)(object)_railBottom); GUI.DrawTexture(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y + 74f, 18f, num2), (Texture)(object)_railLeft); GUI.DrawTexture(new Rect(((Rect)(ref r)).xMax - 18f, ((Rect)(ref r)).y + 74f, 18f, num2), (Texture)(object)_railRight); } float num4 = 74f; GUI.DrawTexture(new Rect(((Rect)(ref r)).x - 10f, ((Rect)(ref r)).y - 10f, 84f, 84f), (Texture)(object)_cornerTL); GUI.DrawTexture(new Rect(((Rect)(ref r)).xMax - num4, ((Rect)(ref r)).y - 10f, 84f, 84f), (Texture)(object)_cornerTR); GUI.DrawTexture(new Rect(((Rect)(ref r)).x - 10f, ((Rect)(ref r)).yMax - num4, 84f, 84f), (Texture)(object)_cornerBL); GUI.DrawTexture(new Rect(((Rect)(ref r)).xMax - num4, ((Rect)(ref r)).yMax - num4, 84f, 84f), (Texture)(object)_cornerBR); float num5 = ((Rect)(ref r)).center.x - 28f; GUI.DrawTexture(new Rect(num5, ((Rect)(ref r)).y - 8f, 56f, 34f), (Texture)(object)_crestTop); GUI.DrawTexture(new Rect(num5, ((Rect)(ref r)).yMax + 8f - 34f, 56f, 34f), (Texture)(object)_crestBottom); DrawOutline(new Rect(((Rect)(ref r)).x + 18f, ((Rect)(ref r)).y + 18f, ((Rect)(ref r)).width - 36f, ((Rect)(ref r)).height - 36f), new Color(Gold.r, Gold.g, Gold.b, 0.45f), 1f); } public static void DrawOutline(Rect r, Color c, float t) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_0048: 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_0094: Unknown result type (might be due to invalid IL or missing references) Color color = GUI.color; GUI.color = c; GUI.DrawTexture(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y, ((Rect)(ref r)).width, t), (Texture)(object)_white); GUI.DrawTexture(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).yMax - t, ((Rect)(ref r)).width, t), (Texture)(object)_white); GUI.DrawTexture(new Rect(((Rect)(ref r)).x, ((Rect)(ref r)).y, t, ((Rect)(ref r)).height), (Texture)(object)_white); GUI.DrawTexture(new Rect(((Rect)(ref r)).xMax - t, ((Rect)(ref r)).y, t, ((Rect)(ref r)).height), (Texture)(object)_white); GUI.color = color; } public static void DrawFill(Rect r, Color c) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) Color color = GUI.color; GUI.color = c; GUI.DrawTexture(r, (Texture)(object)_white); GUI.color = color; } public static void DrawInset(Rect r) { //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_001f: 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) DrawFill(r, new Color(0f, 0f, 0f, 0.45f)); DrawOutline(r, new Color(Gold.r, Gold.g, Gold.b, 0.32f), 1f); } public static void DrawSelection(Rect r) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) GUI.DrawTexture(r, (Texture)(object)_selection); } public static void DrawDot(Rect r, Color c) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) Color color = GUI.color; GUI.color = c; GUI.DrawTexture(r, (Texture)(object)_dot, (ScaleMode)2); GUI.color = color; } public static void DrawHeartMark(Rect r, bool lit) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) Color color = GUI.color; GUI.color = (Color)(lit ? Gold : new Color(0.75f, 0.75f, 0.75f, 0.28f)); GUI.DrawTexture(r, (Texture)(object)_heart, (ScaleMode)2); GUI.color = color; } public static void DrawRule(Rect r) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0030: 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) DrawFill(r, new Color(Gold.r, Gold.g, Gold.b, 0.4f)); GUI.DrawTexture(new Rect(((Rect)(ref r)).center.x - 7f, ((Rect)(ref r)).y - 7f + 0.5f, 14f, 14f), (Texture)(object)_diamond); } public static void DrawShadowed(Rect r, string text, GUIStyle style) { //IL_0012: 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) if (style != null && !string.IsNullOrEmpty(text)) { Color textColor = style.normal.textColor; style.normal.textColor = new Color(0f, 0f, 0f, 0.7f); GUI.Label(new Rect(((Rect)(ref r)).x + 1.5f, ((Rect)(ref r)).y + 1.5f, ((Rect)(ref r)).width, ((Rect)(ref r)).height), text, style); style.normal.textColor = textColor; GUI.Label(r, text, style); } } private static void BuildStyles(ThemeOptions o) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Expected O, but got Unknown //IL_0280: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Expected O, but got Unknown //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Expected O, but got Unknown //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_0313: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_0320: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Unknown result type (might be due to invalid IL or missing references) //IL_0345: Expected O, but got Unknown //IL_0345: Unknown result type (might be due to invalid IL or missing references) //IL_034a: Unknown result type (might be due to invalid IL or missing references) //IL_0354: Expected O, but got Unknown //IL_0354: Unknown result type (might be due to invalid IL or missing references) //IL_0360: Expected O, but got Unknown //IL_03ba: Unknown result type (might be due to invalid IL or missing references) //IL_03ce: Unknown result type (might be due to invalid IL or missing references) //IL_03e2: Unknown result type (might be due to invalid IL or missing references) //IL_03f6: Unknown result type (might be due to invalid IL or missing references) _styledFrom = o; _everStyled = true; TextScale = Mathf.Clamp(o.Scale, 0.6f, 3f); _fontDelta = Mathf.Clamp(o.BodyDelta, -6, 24); Parchment = o.Text; Muted = o.MutedText; int num = Mathf.Clamp(o.TitleDelta, -16, 32); int styleDelta = Mathf.Clamp(o.SubTitleDelta, -16, 32); int styleDelta2 = Mathf.Clamp(o.HeaderDelta, -16, 32); int styleDelta3 = Mathf.Clamp(o.ButtonDelta, -16, 32); int styleDelta4 = Mathf.Clamp(o.RowDelta, -16, 32); int num2 = Mathf.Clamp(o.FooterDelta, -16, 32); int styleDelta5 = Mathf.Clamp(o.FieldDelta, -16, 32); float num3 = Mathf.Max(0, _fontDelta); float num4 = Mathf.Max(num3, (float)Mathf.Max(0, _fontDelta + num)); float num5 = Mathf.Max(num3, (float)Mathf.Max(0, _fontDelta + num2)); TitleHeight = 26f + Mathf.Round(28f * TextScale) + Mathf.Round(num4 * 1.5f); FooterHeight = Mathf.Max(30f, Mathf.Round(30f * TextScale) + num5); Font font = FindFont(); Title = Text(font, Pt(25, num), (FontStyle)1, GoldBright, (TextAnchor)4); SubTitle = Text(font, Pt(18, styleDelta), (FontStyle)1, Gold, (TextAnchor)3); Header = Text(font, Pt(13, styleDelta2), (FontStyle)1, Gold, (TextAnchor)3); Key = Text(font, Pt(13), (FontStyle)0, Muted, (TextAnchor)3); Value = Text(font, Pt(13), (FontStyle)1, Parchment, (TextAnchor)3); Note = Text(font, Pt(13), (FontStyle)2, Muted, (TextAnchor)4); Note.wordWrap = true; Footer = Text(font, Pt(11, num2), (FontStyle)0, Muted, (TextAnchor)4); Button = Patch(font, Pt(13, styleDelta3), (FontStyle)1, (TextAnchor)4, _btnNormal, _btnHover, _btnActive); Button.padding = new RectOffset(12, 12, 6, 6); Primary = Patch(font, Pt(16, styleDelta3), (FontStyle)1, (TextAnchor)4, _btnNormal, _btnHover, _btnActive); Primary.padding = new RectOffset(12, 12, 8, 8); Primary.normal.textColor = Gold; Row = Patch(font, Pt(14, styleDelta4), (FontStyle)0, (TextAnchor)3, _rowNormal, _rowHover, _rowActive); Row.padding = new RectOffset(12, 12, 4, 4); Row.normal.textColor = Parchment; ImageButton = Patch(font, Pt(11, styleDelta4), (FontStyle)0, (TextAnchor)7, _rowNormal, _rowHover, _rowActive); Field = new GUIStyle { font = font, fontSize = Pt(13, styleDelta5), alignment = (TextAnchor)3, padding = new RectOffset(8, 8, 4, 4), border = new RectOffset(3, 3, 3, 3), clipping = (TextClipping)1 }; Field.normal.background = _fieldTex; Field.focused.background = _fieldTex; Field.hover.background = _fieldTex; Field.active.background = _fieldTex; Field.normal.textColor = Parchment; Field.focused.textColor = GoldBright; Field.hover.textColor = Parchment; Field.active.textColor = Parchment; } private static int Pt(int designSize, int styleDelta = 0) { return Mathf.Max(8, Mathf.RoundToInt((float)designSize * TextScale) + _fontDelta + styleDelta); } private static GUIStyle Text(Font font, int size, FontStyle fs, Color colour, TextAnchor anchor) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Expected O, but got Unknown GUIStyle val = new GUIStyle { font = font, fontSize = size, fontStyle = fs, alignment = anchor, richText = true, wordWrap = false, clipping = (TextClipping)1 }; val.normal.textColor = colour; return val; } private static GUIStyle Patch(Font font, int size, FontStyle fs, TextAnchor anchor, Texture2D normal, Texture2D hover, Texture2D active) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown GUIStyle val = new GUIStyle { font = font, fontSize = size, fontStyle = fs, alignment = anchor, richText = true, wordWrap = false, border = new RectOffset(3, 3, 3, 3), clipping = (TextClipping)1 }; val.normal.background = normal; val.hover.background = hover; val.active.background = active; val.focused.background = normal; val.normal.textColor = Parchment; val.hover.textColor = GoldBright; val.active.textColor = GoldBright; val.focused.textColor = Parchment; return val; } private static Font FindFont() { Font[] array = Resources.FindObjectsOfTypeAll(); string[] array2 = new string[3] { "AveriaSerifLibre", "Norsebold", "Norse" }; foreach (string value in array2) { Font[] array3 = array; foreach (Font val in array3) { if ((Object)(object)val != (Object)null && ((Object)val).name.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) { return val; } } } return null; } private static int RailTile(FrameStyle style) { return style switch { FrameStyle.Serpent => 48, FrameStyle.Ironbound => 40, _ => 4, }; } private static bool RailRepeats(FrameStyle style) { return RailTile(style) > 4; } private static Texture2D BuildRail(FrameStyle style, Edge edge) { bool horizontal = edge == Edge.Top || edge == Edge.Bottom; int num = RailTile(style); int num2 = 18; int w = (horizontal ? num : num2); int h = (horizontal ? num2 : num); Painter p = new Painter(w, h) { MirrorY = (edge == Edge.Bottom), MirrorX = (edge == Edge.Right) }; Action action = delegate(float a, float ac, float r) { if (horizontal) { p.Disc(a, ac, r); } else { p.Disc(ac, a, r); } }; switch (style) { case FrameStyle.Runic: RailProfile(p, horizontal, num, num2, 2f, 0.9f); RailProfile(p, horizontal, num, num2, 6.6f, 2.3f); RailProfile(p, horizontal, num, num2, 12.8f, 2.3f); break; case FrameStyle.Serpent: { for (int num3 = 0; num3 <= num * 3; num3++) { float num4 = (float)num3 / (float)(num * 3); float arg = num4 * (float)num; float num5 = Mathf.Sin(num4 * (float)Math.PI * 2f) * 3.6f; action(arg, 9f + num5, 2.3f); action(arg, 9f - num5, 2.3f); } break; } case FrameStyle.Ironbound: RailProfile(p, horizontal, num, num2, 2.4f, 1.3f); RailProfile(p, horizontal, num, num2, 9f, 5.2f); RailProfile(p, horizontal, num, num2, 15.6f, 1.3f); action((float)num * 0.5f, 9f, 3.1f); break; default: RailProfile(p, horizontal, num, num2, 4.4f, 2.7f); RailProfile(p, horizontal, num, num2, 12.4f, 1.6f); break; } return p.Bake(); } private static void RailProfile(Painter p, bool horizontal, int along, int band, float mid, float half) { for (int i = 0; i < along; i++) { for (int j = 0; j < band; j++) { float d = Mathf.Abs((float)j - mid); if (horizontal) { p.RailPixel(i, j, d, half); } else { p.RailPixel(j, i, d, half); } } } } private static Texture2D BuildCorner(FrameStyle style, bool mirrorX, bool mirrorY) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) if (style != FrameStyle.Gilt) { return BuildCornerAlt(style, mirrorX, mirrorY); } Painter painter = new Painter(84, 84) { MirrorX = mirrorX, MirrorY = mirrorY }; painter.RailElbow(14.4f, 2.7f, 32f); painter.RailElbow(22.4f, 1.6f, 32f); painter.Lozenge(11f, 11f, 4.5f); painter.Taper(new Vector2(13.5f, 13.5f), new Vector2(19.3f, 19.3f), 1.2f, 2.2f); painter.Lozenge(36f, 36f, 3.4f); for (int i = 0; i < 2; i++) { painter.Transpose = i == 1; painter.Taper(new Vector2(38.5f, 35f), new Vector2(47f, 32f), 1.4f, 0.45f); painter.Spiral(new Vector2(50f, 31f), 1.3f, 0.33f, 0f, 6.8f, 5.371f, 0.55f, 2.4f); painter.Bezier(new Vector2(56f, 36f), new Vector2(68f, 41f), new Vector2(78f, 30f), 2.2f, 0.35f); painter.Spiral(new Vector2(76f, 32f), 0.9f, 0.32f, 0f, 4.6f, 1f, 1.1f, 0.3f); painter.Disc(58f, 34f, 1.8f); } painter.Transpose = false; return painter.Bake(); } private static Texture2D BuildCornerAlt(FrameStyle style, bool mirrorX, bool mirrorY) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_02a3: Unknown result type (might be due to invalid IL or missing references) //IL_02c2: Unknown result type (might be due to invalid IL or missing references) Painter painter = new Painter(84, 84) { MirrorX = mirrorX, MirrorY = mirrorY }; switch (style) { case FrameStyle.Runic: { painter.SquareElbow(12f, 0.9f, 32f); painter.SquareElbow(16.6f, 2.3f, 32f); painter.SquareElbow(22.8f, 2.3f, 32f); painter.Taper(new Vector2(26f, 54f), new Vector2(54f, 26f), 1.9f, 1.9f); painter.Taper(new Vector2(30f, 30f), new Vector2(50f, 50f), 1.5f, 1.5f); painter.Lozenge(40f, 40f, 4.2f); for (int k = 0; k < 2; k++) { painter.Transpose = k == 1; painter.Disc(52f, 9.7f, 1.9f); painter.Disc(66f, 9.7f, 1.9f); painter.Disc(80f, 9.7f, 1.9f); } painter.Transpose = false; break; } case FrameStyle.Serpent: { painter.RailElbow(15.4f, 2.3f, 32f); painter.RailElbow(22.6f, 2.3f, 32f); painter.Lozenge(19f, 19f, 7.2f); painter.Taper(new Vector2(15f, 15f), new Vector2(6f, 6f), 3.4f, 1.1f); painter.Taper(new Vector2(23f, 14f), new Vector2(12f, 8f), 1.6f, 0.5f); painter.Taper(new Vector2(14f, 23f), new Vector2(8f, 12f), 1.6f, 0.5f); painter.Disc(24f, 16f, 1.7f); painter.Disc(16f, 24f, 1.7f); painter.Bezier(new Vector2(28f, 20f), new Vector2(24f, 24f), new Vector2(20f, 28f), 1.5f, 1.5f); for (int j = 0; j < 2; j++) { painter.Transpose = j == 1; painter.Bezier(new Vector2(34f, 30f), new Vector2(50f, 24f), new Vector2(64f, 33f), 2.3f, 2.3f); painter.Spiral(new Vector2(74f, 26f), 1.1f, 0.3f, 0f, 5f, 2.2f, 2.1f, 0.9f); } painter.Transpose = false; break; } default: { painter.SquareElbow(12.4f, 1.3f, 32f); painter.SquareElbow(19f, 5.2f, 32f); painter.SquareElbow(25.6f, 1.3f, 32f); painter.Disc(19f, 19f, 4.6f); painter.Disc(19f, 19f, 2f); for (int i = 0; i < 2; i++) { painter.Transpose = i == 1; painter.Disc(44f, 19f, 3.1f); painter.Disc(70f, 19f, 3.1f); } painter.Transpose = false; break; } } return painter.Bake(); } private static Texture2D BuildCrest(FrameStyle style, bool flip) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: 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_010e: Unknown result type (might be due to invalid IL or missing references) //IL_012d: 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) //IL_014b: Unknown result type (might be due to invalid IL or missing references) if (style != FrameStyle.Gilt) { return BuildCrestAlt(style, flip); } Painter painter = new Painter(56, 34); painter.MirrorY = flip; painter.Disc(28f, 2.5f, 1.8f); painter.Lozenge(28f, 9f, 6.5f); painter.Taper(new Vector2(28f, 14f), new Vector2(28f, 24f), 2.2f, 1.2f); painter.Spiral(new Vector2(17f, 25f), 1.2f, 0.33f, 0f, 5.4f, 2.6f, 2f, 0.35f); painter.Spiral(new Vector2(39f, 25f), 1.2f, 0.33f, 0f, 5.4f, 2.6f, 2f, 0.35f, mirror: true); painter.Bezier(new Vector2(23f, 19f), new Vector2(13f, 24f), new Vector2(4f, 16f), 1.6f, 0.3f); painter.Bezier(new Vector2(33f, 19f), new Vector2(43f, 24f), new Vector2(52f, 16f), 1.6f, 0.3f); painter.Disc(3f, 14f, 1.5f); painter.Disc(53f, 14f, 1.5f); return painter.Bake(); } private static Texture2D BuildCrestAlt(FrameStyle style, bool flip) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_007e: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_0200: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) Painter painter = new Painter(56, 34) { MirrorY = flip }; switch (style) { case FrameStyle.Runic: painter.Lozenge(28f, 8f, 6f); painter.Taper(new Vector2(28f, 13f), new Vector2(28f, 27f), 2f, 2f); painter.Taper(new Vector2(28f, 16f), new Vector2(17f, 25f), 1.7f, 1.1f); painter.Taper(new Vector2(28f, 16f), new Vector2(39f, 25f), 1.7f, 1.1f); painter.Disc(7f, 10f, 1.9f); painter.Disc(49f, 10f, 1.9f); break; case FrameStyle.Serpent: painter.Lozenge(28f, 11f, 5.2f); painter.Spiral(new Vector2(19f, 17f), 1.2f, 0.32f, 0f, 5.6f, 2.4f, 2.1f, 0.5f); painter.Spiral(new Vector2(37f, 17f), 1.2f, 0.32f, 0f, 5.6f, 2.4f, 2.1f, 0.5f, mirror: true); painter.Bezier(new Vector2(24f, 20f), new Vector2(12f, 26f), new Vector2(2f, 15f), 2f, 1f); painter.Bezier(new Vector2(32f, 20f), new Vector2(44f, 26f), new Vector2(54f, 15f), 2f, 1f); break; default: painter.Taper(new Vector2(3f, 12f), new Vector2(53f, 12f), 4.4f, 4.4f); painter.Disc(28f, 12f, 8.2f); painter.Disc(28f, 12f, 4.4f); painter.Disc(11f, 12f, 2.4f); painter.Disc(45f, 12f, 2.4f); painter.Disc(28f, 25f, 2.4f); break; } return painter.Bake(); } private static Texture2D BuildDot(int size) { //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) Texture2D val = New(size, size, (TextureWrapMode)1, (FilterMode)1); Color[] array = (Color[])(object)new Color[size * size]; float num = (float)(size - 1) * 0.5f; float num2 = (float)size * 0.42f; for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { float num3 = 0f; for (int k = 0; k < 2; k++) { for (int l = 0; l < 2; l++) { float num4 = (float)j + ((float)l + 0.5f) * 0.5f - 0.5f - num; float num5 = (float)i + ((float)k + 0.5f) * 0.5f - 0.5f - num; if (Mathf.Sqrt(num4 * num4 + num5 * num5) <= num2) { num3 += 0.25f; } } } array[i * size + j] = new Color(1f, 1f, 1f, num3); } } val.SetPixels(array); val.Apply(false); return val; } private static Texture2D BuildDiamond(int size) { Painter painter = new Painter(size, size); float num = (float)(size - 1) * 0.5f; painter.Lozenge(num, num, (float)size * 0.36f); return painter.Bake(); } private static Texture2D BuildHeart(int size) { //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) Texture2D val = New(size, size, (TextureWrapMode)1, (FilterMode)1); Color[] array = (Color[])(object)new Color[size * size]; for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { float num = 0f; for (int k = 0; k < 2; k++) { for (int l = 0; l < 2; l++) { float num2 = (((float)j + ((float)l + 0.5f) * 0.5f) / (float)size - 0.5f) * 2.6f; float num3 = (((float)i + ((float)k + 0.5f) * 0.5f) / (float)size - 0.42f) * 2.9f; float num4 = num2 * num2 + num3 * num3 - 1f; if (num4 * num4 * num4 - num2 * num2 * num3 * num3 * num3 <= 0f) { num += 0.25f; } } } array[i * size + j] = new Color(1f, 1f, 1f, num); } } val.SetPixels(array); val.Apply(false); return val; } private static Texture2D BuildPanel(int size, Color colour, float opacity) { //IL_0085: 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_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) Texture2D val = New(size, size, (TextureWrapMode)1, (FilterMode)1); Color[] array = (Color[])(object)new Color[size * size]; float num = (float)(size - 1) * 0.5f; float num2 = Mathf.Clamp01(opacity); for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { float num3 = ((float)j - num) / num; float num4 = ((float)i - num) / num; float num5 = Mathf.Clamp01(1f - 0.55f * Mathf.Sqrt(0.6f * (num3 * num3 + num4 * num4))); float num6 = 0.73f + 0.27f * num5; array[i * size + j] = new Color(colour.r * num6, colour.g * num6, colour.b * num6, num2); } } val.SetPixels(array); val.Apply(false); return val; } private static Texture2D BuildPatch(Color fill, Color border) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) Texture2D val = New(12, 12, (TextureWrapMode)1, (FilterMode)0); Color[] array = (Color[])(object)new Color[144]; for (int i = 0; i < 12; i++) { for (int j = 0; j < 12; j++) { int num = Mathf.Min(Mathf.Min(j, i), Mathf.Min(11 - j, 11 - i)); array[i * 12 + j] = ((num == 0) ? border : fill); } } val.SetPixels(array); val.Apply(false); return val; } private static Texture2D BuildSolid(Color c) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) Texture2D obj = New(1, 1, (TextureWrapMode)1, (FilterMode)0); obj.SetPixel(0, 0, c); obj.Apply(false); return obj; } private static Texture2D New(int w, int h, TextureWrapMode wrap, FilterMode filter) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: 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_0010: 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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown return new Texture2D(w, h, (TextureFormat)4, false) { wrapMode = wrap, filterMode = filter, hideFlags = (HideFlags)61 }; } } internal static class UIFocus { [HarmonyPatch] internal static class UIFocusPatch { private static readonly ManualLogSource Log = Logger.CreateLogSource("SharedUI.UIFocus"); [HarmonyPatch(typeof(Chat), "HasFocus")] [HarmonyPostfix] private static void Chat_HasFocus_Postfix(ref bool __result) { try { if (HasTextFocus || BlocksGameInput) { __result = true; } } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed (non-fatal, keyboard may leak into gameplay while a window is focused). Reason: {1}", "Chat_HasFocus_Postfix", arg)); } } [HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")] [HarmonyPrefix] private static bool GameCamera_UpdateMouseCapture_Prefix() { try { if (!WantsCursor) { return true; } Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; return false; } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed (non-fatal, falling back to vanilla cursor handling). Reason: {1}", "GameCamera_UpdateMouseCapture_Prefix", arg)); return true; } } [HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")] [HarmonyPostfix] [HarmonyPriority(800)] private static void GameCamera_UpdateMouseCapture_Postfix() { try { if (WantsCursor) { Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; } } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed (non-fatal, another mod's cursor handling may win this frame). Reason: {1}", "GameCamera_UpdateMouseCapture_Postfix", arg)); } } } private static readonly HashSet _cursorWindows = new HashSet(); private static readonly HashSet _textFocusWindows = new HashSet(); private static readonly HashSet _inputBlockWindows = new HashSet(); public static bool WantsCursor => _cursorWindows.Count > 0; public static bool HasTextFocus => _textFocusWindows.Count > 0; public static bool BlocksGameInput => _inputBlockWindows.Count > 0; public static void SetWantsCursor(string windowId, bool active) { if (active) { _cursorWindows.Add(windowId); } else { _cursorWindows.Remove(windowId); } } public static void SetHasTextFocus(string windowId, bool active) { if (active) { _textFocusWindows.Add(windowId); } else { _textFocusWindows.Remove(windowId); } } public static void SetBlocksGameInput(string windowId, bool active) { if (active) { _inputBlockWindows.Add(windowId); } else { _inputBlockWindows.Remove(windowId); } } } internal class ConfigManagerAttributes { public bool? Browsable; public bool? ReadOnly; public bool? IsAdvanced; public int? Order; public string Category; } } namespace ServerSync { [PublicAPI] public abstract class OwnConfigEntryBase { public object? LocalBaseValue; public bool SynchronizedConfig = true; public abstract ConfigEntryBase BaseConfig { get; } } [PublicAPI] public class SyncedConfigEntry(ConfigEntry sourceConfig) : OwnConfigEntryBase() { public readonly ConfigEntry SourceConfig = sourceConfig; public override ConfigEntryBase BaseConfig => (ConfigEntryBase)(object)SourceConfig; public T Value { get { return SourceConfig.Value; } set { SourceConfig.Value = value; } } public void AssignLocalValue(T value) { if (LocalBaseValue == null) { Value = value; } else { LocalBaseValue = value; } } } public abstract class CustomSyncedValueBase { public object? LocalBaseValue; public readonly string Identifier; public readonly Type Type; private object? boxedValue; protected bool localIsOwner; public readonly int Priority; public object? BoxedValue { get { return boxedValue; } set { boxedValue = value; this.ValueChanged?.Invoke(); } } public event Action? ValueChanged; protected CustomSyncedValueBase(ConfigSync configSync, string identifier, Type type, int priority) { Priority = priority; Identifier = identifier; Type = type; configSync.AddCustomValue(this); localIsOwner = configSync.IsSourceOfTruth; configSync.SourceOfTruthChanged += delegate(bool truth) { localIsOwner = truth; }; } } [PublicAPI] public sealed class CustomSyncedValue : CustomSyncedValueBase { public T Value { get { return (T)base.BoxedValue; } set { base.BoxedValue = value; } } public CustomSyncedValue(ConfigSync configSync, string identifier, T value = default(T), int priority = 0) : base(configSync, identifier, typeof(T), priority) { Value = value; } public void AssignLocalValue(T value) { if (localIsOwner) { Value = value; } else { LocalBaseValue = value; } } } internal class ConfigurationManagerAttributes { [UsedImplicitly] public bool? ReadOnly = false; } [PublicAPI] public class ConfigSync { [HarmonyPatch(typeof(ZRpc), "HandlePackage")] private static class SnatchCurrentlyHandlingRPC { public static ZRpc? currentRpc; [HarmonyPrefix] private static void Prefix(ZRpc __instance) { currentRpc = __instance; } } [HarmonyPatch(typeof(ZNet), "Awake")] internal static class RegisterRPCPatch { [HarmonyPostfix] private static void Postfix(ZNet __instance) { isServer = __instance.IsServer(); foreach (ConfigSync configSync2 in configSyncs) { ZRoutedRpc.instance.Register(configSync2.Name + " ConfigSync", (Action)configSync2.RPC_FromOtherClientConfigSync); if (isServer) { configSync2.InitialSyncDone = true; Debug.Log((object)("Registered '" + configSync2.Name + " ConfigSync' RPC - waiting for incoming connections")); } } if (isServer) { ((MonoBehaviour)__instance).StartCoroutine(WatchAdminListChanges()); } static void SendAdmin(List peers, bool isAdmin) { ZPackage package = ConfigsToPackage(null, null, new PackageEntry[1] { new PackageEntry { section = "Internal", key = "lockexempt", type = typeof(bool), value = isAdmin } }); ConfigSync configSync = configSyncs.First(); if (configSync != null) { ((MonoBehaviour)ZNet.instance).StartCoroutine(configSync.sendZPackage(peers, package)); } } static IEnumerator WatchAdminListChanges() { MethodInfo listContainsId = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList adminList = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); List CurrentList = new List(adminList.GetList()); while (true) { yield return (object)new WaitForSeconds(30f); if (!adminList.GetList().SequenceEqual(CurrentList)) { CurrentList = new List(adminList.GetList()); List list = ZNet.instance.GetPeers().Where(delegate(ZNetPeer p) { string hostName = p.m_rpc.GetSocket().GetHostName(); return ((object)listContainsId != null) ? ((bool)listContainsId.Invoke(ZNet.instance, new object[2] { adminList, hostName })) : adminList.Contains(hostName); }).ToList(); SendAdmin(ZNet.instance.GetPeers().Except(list).ToList(), isAdmin: false); SendAdmin(list, isAdmin: true); } } } } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] private static class RegisterClientRPCPatch { [HarmonyPostfix] private static void Postfix(ZNet __instance, ZNetPeer peer) { if (__instance.IsServer()) { return; } foreach (ConfigSync configSync in configSyncs) { peer.m_rpc.Register(configSync.Name + " ConfigSync", (Action)configSync.RPC_FromServerConfigSync); } } } private class ParsedConfigs { public readonly Dictionary configValues = new Dictionary(); public readonly Dictionary customValues = new Dictionary(); } [HarmonyPatch(typeof(ZNet), "Shutdown")] private class ResetConfigsOnShutdown { [HarmonyPostfix] private static void Postfix() { ProcessingServerUpdate = true; foreach (ConfigSync configSync in configSyncs) { configSync.resetConfigsFromServer(); configSync.IsSourceOfTruth = true; configSync.InitialSyncDone = false; } ProcessingServerUpdate = false; } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] private class SendConfigsAfterLogin { private class BufferingSocket : ZPlayFabSocket, ISocket { public volatile bool finished; public volatile int versionMatchQueued = -1; public readonly List Package = new List(); public readonly ISocket Original; public BufferingSocket(ISocket original) { Original = original; ((ZPlayFabSocket)this)..ctor(); } public bool IsConnected() { return Original.IsConnected(); } public ZPackage Recv() { return Original.Recv(); } public int GetSendQueueSize() { return Original.GetSendQueueSize(); } public int GetCurrentSendRate() { return Original.GetCurrentSendRate(); } public bool IsHost() { return Original.IsHost(); } public void Dispose() { Original.Dispose(); } public bool GotNewData() { return Original.GotNewData(); } public void Close() { Original.Close(); } public string GetEndPointString() { return Original.GetEndPointString(); } public void GetAndResetStats(out int totalSent, out int totalRecv) { Original.GetAndResetStats(ref totalSent, ref totalRecv); } public void GetConnectionQuality(out float localQuality, out float remoteQuality, out int ping, out float outByteSec, out float inByteSec) { Original.GetConnectionQuality(ref localQuality, ref remoteQuality, ref ping, ref outByteSec, ref inByteSec); } public ISocket Accept() { return Original.Accept(); } public int GetHostPort() { return Original.GetHostPort(); } public bool Flush() { return Original.Flush(); } public string GetHostName() { return Original.GetHostName(); } public void VersionMatch() { if (finished) { Original.VersionMatch(); } else { versionMatchQueued = Package.Count; } } public void Send(ZPackage pkg) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown int pos = pkg.GetPos(); pkg.SetPos(0); int num = pkg.ReadInt(); if ((num == StringExtensionMethods.GetStableHashCode("PeerInfo") || num == StringExtensionMethods.GetStableHashCode("RoutedRPC") || num == StringExtensionMethods.GetStableHashCode("ZDOData")) && !finished) { ZPackage val = new ZPackage(pkg.GetArray()); val.SetPos(pos); Package.Add(val); } else { pkg.SetPos(pos); Original.Send(pkg); } } } [HarmonyPriority(800)] [HarmonyPrefix] private static void Prefix(ref Dictionary? __state, ZNet __instance, ZRpc rpc) { //IL_0073: Unknown result type (might be due to invalid IL or missing references) if (!__instance.IsServer()) { return; } BufferingSocket bufferingSocket = new BufferingSocket(rpc.GetSocket()); AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, bufferingSocket); object? obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc }); ZNetPeer val = (ZNetPeer)((obj is ZNetPeer) ? obj : null); if (val != null && (int)ZNet.m_onlineBackend != 0) { FieldInfo fieldInfo = AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket"); object? value = fieldInfo.GetValue(val); ZPlayFabSocket val2 = (ZPlayFabSocket)((value is ZPlayFabSocket) ? value : null); if (val2 != null) { typeof(ZPlayFabSocket).GetField("m_remotePlayerId").SetValue(bufferingSocket, val2.m_remotePlayerId); } fieldInfo.SetValue(val, bufferingSocket); } if (__state == null) { __state = new Dictionary(); } __state[Assembly.GetExecutingAssembly()] = bufferingSocket; } [HarmonyPostfix] private static void Postfix(Dictionary __state, ZNet __instance, ZRpc rpc) { ZNetPeer peer; if (__instance.IsServer()) { object obj = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc }); peer = (ZNetPeer)((obj is ZNetPeer) ? obj : null); if (peer == null) { SendBufferedData(); } else { ((MonoBehaviour)__instance).StartCoroutine(sendAsync()); } } void SendBufferedData() { if (rpc.GetSocket() is BufferingSocket bufferingSocket) { AccessTools.DeclaredField(typeof(ZRpc), "m_socket").SetValue(rpc, bufferingSocket.Original); object? obj2 = AccessTools.DeclaredMethod(typeof(ZNet), "GetPeer", new Type[1] { typeof(ZRpc) }, (Type[])null).Invoke(__instance, new object[1] { rpc }); ZNetPeer val = (ZNetPeer)((obj2 is ZNetPeer) ? obj2 : null); if (val != null) { AccessTools.DeclaredField(typeof(ZNetPeer), "m_socket").SetValue(val, bufferingSocket.Original); } } BufferingSocket bufferingSocket2 = __state[Assembly.GetExecutingAssembly()]; bufferingSocket2.finished = true; for (int i = 0; i < bufferingSocket2.Package.Count; i++) { if (i == bufferingSocket2.versionMatchQueued) { bufferingSocket2.Original.VersionMatch(); } bufferingSocket2.Original.Send(bufferingSocket2.Package[i]); } if (bufferingSocket2.Package.Count == bufferingSocket2.versionMatchQueued) { bufferingSocket2.Original.VersionMatch(); } } IEnumerator sendAsync() { foreach (ConfigSync configSync in configSyncs) { List list = new List(); if (configSync.CurrentVersion != null) { list.Add(new PackageEntry { section = "Internal", key = "serverversion", type = typeof(string), value = configSync.CurrentVersion }); } MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList val = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); list.Add(new PackageEntry { section = "Internal", key = "lockexempt", type = typeof(bool), value = (((object)methodInfo == null) ? ((object)val.Contains(rpc.GetSocket().GetHostName())) : methodInfo.Invoke(ZNet.instance, new object[2] { val, rpc.GetSocket().GetHostName() })) }); ZPackage package = ConfigsToPackage(configSync.allConfigs.Select((OwnConfigEntryBase c) => c.BaseConfig), configSync.allCustomValues, list, partial: false); yield return ((MonoBehaviour)__instance).StartCoroutine(configSync.sendZPackage(new List { peer }, package)); } SendBufferedData(); } } } private class PackageEntry { public string section; public string key; public Type type; public object? value; } [HarmonyPatch(typeof(ConfigEntryBase), "GetSerializedValue")] private static class PreventSavingServerInfo { [HarmonyPrefix] private static bool Prefix(ConfigEntryBase __instance, ref string __result) { OwnConfigEntryBase ownConfigEntryBase = configData(__instance); if (ownConfigEntryBase == null || isWritableConfig(ownConfigEntryBase)) { return true; } __result = TomlTypeConverter.ConvertToString(ownConfigEntryBase.LocalBaseValue, __instance.SettingType); return false; } } [HarmonyPatch(typeof(ConfigEntryBase), "SetSerializedValue")] private static class PreventConfigRereadChangingValues { [HarmonyPrefix] private static bool Prefix(ConfigEntryBase __instance, string value) { OwnConfigEntryBase ownConfigEntryBase = configData(__instance); if (ownConfigEntryBase == null || ownConfigEntryBase.LocalBaseValue == null) { return true; } try { ownConfigEntryBase.LocalBaseValue = TomlTypeConverter.ConvertToValue(value, __instance.SettingType); } catch (Exception ex) { Debug.LogWarning((object)$"Config value of setting \"{__instance.Definition}\" could not be parsed and will be ignored. Reason: {ex.Message}; Value: {value}"); } return false; } } private class InvalidDeserializationTypeException : Exception { public string expected; public string received; public string field = ""; } public static bool ProcessingServerUpdate; public readonly string Name; public string? DisplayName; public string? CurrentVersion; public string? MinimumRequiredVersion; public bool ModRequired; private bool? forceConfigLocking; private bool isSourceOfTruth = true; private static readonly HashSet configSyncs; private readonly HashSet allConfigs = new HashSet(); private HashSet allCustomValues = new HashSet(); private static bool isServer; private static bool lockExempt; private OwnConfigEntryBase? lockedConfig; private const byte PARTIAL_CONFIGS = 1; private const byte FRAGMENTED_CONFIG = 2; private const byte COMPRESSED_CONFIG = 4; private readonly Dictionary> configValueCache = new Dictionary>(); private readonly List> cacheExpirations = new List>(); private static long packageCounter; public bool IsLocked { get { bool? flag = forceConfigLocking; bool num; if (!flag.HasValue) { if (lockedConfig == null) { goto IL_0051; } num = ((IConvertible)lockedConfig.BaseConfig.BoxedValue).ToInt32(CultureInfo.InvariantCulture) != 0; } else { num = flag == true; } if (num) { return !lockExempt; } goto IL_0051; IL_0051: return false; } set { forceConfigLocking = value; } } public bool IsAdmin { get { if (!lockExempt) { return isSourceOfTruth; } return true; } } public bool IsSourceOfTruth { get { return isSourceOfTruth; } private set { if (value != isSourceOfTruth) { isSourceOfTruth = value; this.SourceOfTruthChanged?.Invoke(value); } } } public bool InitialSyncDone { get; private set; } public event Action? SourceOfTruthChanged; private event Action? lockedConfigChanged; static ConfigSync() { ProcessingServerUpdate = false; configSyncs = new HashSet(); lockExempt = false; packageCounter = 0L; RuntimeHelpers.RunClassConstructor(typeof(VersionCheck).TypeHandle); } public ConfigSync(string name) { Name = name; configSyncs.Add(this); new VersionCheck(this); } public SyncedConfigEntry AddConfigEntry(ConfigEntry configEntry) { OwnConfigEntryBase ownConfigEntryBase = configData((ConfigEntryBase)(object)configEntry); SyncedConfigEntry syncedEntry = ownConfigEntryBase as SyncedConfigEntry; if (syncedEntry == null) { syncedEntry = new SyncedConfigEntry(configEntry); AccessTools.DeclaredField(typeof(ConfigDescription), "k__BackingField").SetValue(((ConfigEntryBase)configEntry).Description, new object[1] { new ConfigurationManagerAttributes() }.Concat(((ConfigEntryBase)configEntry).Description.Tags ?? Array.Empty()).Concat(new SyncedConfigEntry[1] { syncedEntry }).ToArray()); configEntry.SettingChanged += delegate { if (!ProcessingServerUpdate && syncedEntry.SynchronizedConfig) { Broadcast(ZRoutedRpc.Everybody, (ConfigEntryBase)configEntry); } }; allConfigs.Add(syncedEntry); } return syncedEntry; } public SyncedConfigEntry AddLockingConfigEntry(ConfigEntry lockingConfig) where T : IConvertible { if (lockedConfig != null) { throw new Exception("Cannot initialize locking ConfigEntry twice"); } lockedConfig = AddConfigEntry(lockingConfig); lockingConfig.SettingChanged += delegate { this.lockedConfigChanged?.Invoke(); }; return (SyncedConfigEntry)lockedConfig; } internal void AddCustomValue(CustomSyncedValueBase customValue) { if (allCustomValues.Select((CustomSyncedValueBase v) => v.Identifier).Concat(new string[1] { "serverversion" }).Contains(customValue.Identifier)) { throw new Exception("Cannot have multiple settings with the same name or with a reserved name (serverversion)"); } allCustomValues.Add(customValue); allCustomValues = new HashSet(allCustomValues.OrderByDescending((CustomSyncedValueBase v) => v.Priority)); customValue.ValueChanged += delegate { if (!ProcessingServerUpdate) { Broadcast(ZRoutedRpc.Everybody, customValue); } }; } private void RPC_FromServerConfigSync(ZRpc rpc, ZPackage package) { lockedConfigChanged += serverLockedSettingChanged; IsSourceOfTruth = false; if (HandleConfigSyncRPC(0L, package, clientUpdate: false)) { InitialSyncDone = true; } } private void RPC_FromOtherClientConfigSync(long sender, ZPackage package) { HandleConfigSyncRPC(sender, package, clientUpdate: true); } private bool HandleConfigSyncRPC(long sender, ZPackage package, bool clientUpdate) { //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Expected O, but got Unknown //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Expected O, but got Unknown //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown try { if (isServer && IsLocked) { ZRpc? currentRpc = SnatchCurrentlyHandlingRPC.currentRpc; object obj; if (currentRpc == null) { obj = null; } else { ISocket socket = currentRpc.GetSocket(); obj = ((socket != null) ? socket.GetHostName() : null); } string text = (string)obj; if (text != null) { MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(ZNet), "ListContainsId", (Type[])null, (Type[])null); SyncedList val = (SyncedList)AccessTools.DeclaredField(typeof(ZNet), "m_adminList").GetValue(ZNet.instance); if (!(((object)methodInfo == null) ? val.Contains(text) : ((bool)methodInfo.Invoke(ZNet.instance, new object[2] { val, text })))) { return false; } } } cacheExpirations.RemoveAll(delegate(KeyValuePair kv) { if (kv.Key < DateTimeOffset.Now.Ticks) { configValueCache.Remove(kv.Value); return true; } return false; }); byte b = package.ReadByte(); if ((b & 2) != 0) { long num = package.ReadLong(); string text2 = sender.ToString() + num; if (!configValueCache.TryGetValue(text2, out var value)) { value = new SortedDictionary(); configValueCache[text2] = value; cacheExpirations.Add(new KeyValuePair(DateTimeOffset.Now.AddSeconds(60.0).Ticks, text2)); } int key = package.ReadInt(); int num2 = package.ReadInt(); value.Add(key, package.ReadByteArray()); if (value.Count < num2) { return false; } configValueCache.Remove(text2); package = new ZPackage(value.Values.SelectMany((byte[] a) => a).ToArray()); b = package.ReadByte(); } ProcessingServerUpdate = true; if ((b & 4) != 0) { MemoryStream stream = new MemoryStream(package.ReadByteArray()); MemoryStream memoryStream = new MemoryStream(); using (DeflateStream deflateStream = new DeflateStream(stream, CompressionMode.Decompress)) { deflateStream.CopyTo(memoryStream); } package = new ZPackage(memoryStream.ToArray()); b = package.ReadByte(); } if ((b & 1) == 0) { resetConfigsFromServer(); } ParsedConfigs parsedConfigs = ReadConfigsFromPackage(package); ConfigFile val2 = null; bool saveOnConfigSet = false; foreach (KeyValuePair configValue in parsedConfigs.configValues) { if (!isServer && configValue.Key.LocalBaseValue == null) { configValue.Key.LocalBaseValue = configValue.Key.BaseConfig.BoxedValue; } if (val2 == null) { val2 = configValue.Key.BaseConfig.ConfigFile; saveOnConfigSet = val2.SaveOnConfigSet; val2.SaveOnConfigSet = false; } configValue.Key.BaseConfig.BoxedValue = configValue.Value; } if (val2 != null) { val2.SaveOnConfigSet = saveOnConfigSet; val2.Save(); } foreach (KeyValuePair customValue in parsedConfigs.customValues) { if (!isServer) { CustomSyncedValueBase key2 = customValue.Key; if (key2.LocalBaseValue == null) { key2.LocalBaseValue = customValue.Key.BoxedValue; } } customValue.Key.BoxedValue = customValue.Value; } Debug.Log((object)string.Format("Received {0} configs and {1} custom values from {2} for mod {3}", parsedConfigs.configValues.Count, parsedConfigs.customValues.Count, (isServer || clientUpdate) ? $"client {sender}" : "the server", DisplayName ?? Name)); if (!isServer) { serverLockedSettingChanged(); } return true; } finally { ProcessingServerUpdate = false; } } private ParsedConfigs ReadConfigsFromPackage(ZPackage package) { ParsedConfigs parsedConfigs = new ParsedConfigs(); Dictionary dictionary = allConfigs.Where((OwnConfigEntryBase c) => c.SynchronizedConfig).ToDictionary((OwnConfigEntryBase c) => c.BaseConfig.Definition.Section + "_" + c.BaseConfig.Definition.Key, (OwnConfigEntryBase c) => c); Dictionary dictionary2 = allCustomValues.ToDictionary((CustomSyncedValueBase c) => c.Identifier, (CustomSyncedValueBase c) => c); int num = package.ReadInt(); for (int num2 = 0; num2 < num; num2++) { string text = package.ReadString(); string text2 = package.ReadString(); string text3 = package.ReadString(); Type type = Type.GetType(text3); if (text3 == "" || type != null) { object obj; try { obj = ((text3 == "") ? null : ReadValueWithTypeFromZPackage(package, type)); } catch (InvalidDeserializationTypeException ex) { Debug.LogWarning((object)("Got unexpected struct internal type " + ex.received + " for field " + ex.field + " struct " + text3 + " for " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + ex.expected)); continue; } OwnConfigEntryBase value2; if (text == "Internal") { CustomSyncedValueBase value; if (text2 == "serverversion") { if (obj?.ToString() != CurrentVersion) { Debug.LogWarning((object)("Received server version is not equal: server version = " + (obj?.ToString() ?? "null") + "; local version = " + (CurrentVersion ?? "unknown"))); } } else if (text2 == "lockexempt") { if (obj is bool flag) { lockExempt = flag; } } else if (dictionary2.TryGetValue(text2, out value)) { if ((text3 == "" && (!value.Type.IsValueType || Nullable.GetUnderlyingType(value.Type) != null)) || GetZPackageTypeString(value.Type) == text3) { parsedConfigs.customValues[value] = obj; continue; } Debug.LogWarning((object)("Got unexpected type " + text3 + " for internal value " + text2 + " for mod " + (DisplayName ?? Name) + ", expecting " + value.Type.AssemblyQualifiedName)); } } else if (dictionary.TryGetValue(text + "_" + text2, out value2)) { Type type2 = configType(value2.BaseConfig); if ((text3 == "" && (!type2.IsValueType || Nullable.GetUnderlyingType(type2) != null)) || GetZPackageTypeString(type2) == text3) { parsedConfigs.configValues[value2] = obj; continue; } Debug.LogWarning((object)("Got unexpected type " + text3 + " for " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ", expecting " + type2.AssemblyQualifiedName)); } else { Debug.LogWarning((object)("Received unknown config entry " + text2 + " in section " + text + " for mod " + (DisplayName ?? Name) + ". This may happen if client and server versions of the mod do not match.")); } continue; } Debug.LogWarning((object)("Got invalid type " + text3 + ", abort reading of received configs")); return new ParsedConfigs(); } return parsedConfigs; } private static bool isWritableConfig(OwnConfigEntryBase config) { ConfigSync configSync = configSyncs.FirstOrDefault((ConfigSync cs) => cs.allConfigs.Contains(config)); if (configSync == null) { return true; } if (!configSync.IsSourceOfTruth && config.SynchronizedConfig && config.LocalBaseValue != null) { if (!configSync.IsLocked) { if (config == configSync.lockedConfig) { return lockExempt; } return true; } return false; } return true; } private void serverLockedSettingChanged() { foreach (OwnConfigEntryBase allConfig in allConfigs) { configAttribute(allConfig.BaseConfig).ReadOnly = !isWritableConfig(allConfig); } } private void resetConfigsFromServer() { ConfigFile val = null; bool saveOnConfigSet = false; foreach (OwnConfigEntryBase item in allConfigs.Where((OwnConfigEntryBase config) => config.LocalBaseValue != null)) { if (val == null) { val = item.BaseConfig.ConfigFile; saveOnConfigSet = val.SaveOnConfigSet; val.SaveOnConfigSet = false; } item.BaseConfig.BoxedValue = item.LocalBaseValue; item.LocalBaseValue = null; } if (val != null) { val.SaveOnConfigSet = saveOnConfigSet; } foreach (CustomSyncedValueBase item2 in allCustomValues.Where((CustomSyncedValueBase config) => config.LocalBaseValue != null)) { item2.BoxedValue = item2.LocalBaseValue; item2.LocalBaseValue = null; } lockedConfigChanged -= serverLockedSettingChanged; serverLockedSettingChanged(); } private IEnumerator distributeConfigToPeers(ZNetPeer peer, ZPackage package) { ZRoutedRpc rpc = ZRoutedRpc.instance; if (rpc == null) { yield break; } byte[] data = package.GetArray(); if (data != null && data.LongLength > 250000) { int fragments = (int)(1 + (data.LongLength - 1) / 250000); long packageIdentifier = ++packageCounter; int fragment = 0; while (fragment < fragments) { foreach (bool item in waitForQueue()) { yield return item; } if (peer.m_socket.IsConnected()) { ZPackage val = new ZPackage(); val.Write((byte)2); val.Write(packageIdentifier); val.Write(fragment); val.Write(fragments); val.Write(data.Skip(250000 * fragment).Take(250000).ToArray()); SendPackage(val); if (fragment != fragments - 1) { yield return true; } int num = fragment + 1; fragment = num; continue; } break; } yield break; } foreach (bool item2 in waitForQueue()) { yield return item2; } SendPackage(package); void SendPackage(ZPackage pkg) { string text = Name + " ConfigSync"; if (isServer) { peer.m_rpc.Invoke(text, new object[1] { pkg }); } else { rpc.InvokeRoutedRPC(peer.m_server ? 0 : peer.m_uid, text, new object[1] { pkg }); } } IEnumerable waitForQueue() { float timeout = Time.time + 30f; while (peer.m_socket.GetSendQueueSize() > 20000) { if (Time.time > timeout) { Debug.Log((object)$"Disconnecting {peer.m_uid} after 30 seconds config sending timeout"); peer.m_rpc.Invoke("Error", new object[1] { (object)(ConnectionStatus)5 }); ZNet.instance.Disconnect(peer); break; } yield return false; } } } private IEnumerator sendZPackage(long target, ZPackage package) { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { return Enumerable.Empty().GetEnumerator(); } List list = (List)AccessTools.DeclaredField(typeof(ZRoutedRpc), "m_peers").GetValue(ZRoutedRpc.instance); if (target != ZRoutedRpc.Everybody) { list = list.Where((ZNetPeer p) => p.m_uid == target).ToList(); } return sendZPackage(list, package); } private IEnumerator sendZPackage(List peers, ZPackage package) { if (!Object.op_Implicit((Object)(object)ZNet.instance)) { yield break; } byte[] array = package.GetArray(); if (array != null && array.LongLength > 10000) { ZPackage val = new ZPackage(); val.Write((byte)4); MemoryStream memoryStream = new MemoryStream(); using (DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionLevel.Optimal)) { deflateStream.Write(array, 0, array.Length); } val.Write(memoryStream.ToArray()); package = val; } List> writers = (from p in peers where p.IsReady() select distributeConfigToPeers(p, package)).ToList(); writers.RemoveAll((IEnumerator writer) => !writer.MoveNext()); while (writers.Count > 0) { yield return null; writers.RemoveAll((IEnumerator writer) => !writer.MoveNext()); } } private void Broadcast(long target, params ConfigEntryBase[] configs) { if (!IsLocked || isServer) { ZPackage package = ConfigsToPackage(configs); ZNet instance = ZNet.instance; if (instance != null) { ((MonoBehaviour)instance).StartCoroutine(sendZPackage(target, package)); } } } private void Broadcast(long target, params CustomSyncedValueBase[] customValues) { if (!IsLocked || isServer) { ZPackage package = ConfigsToPackage(null, customValues); ZNet instance = ZNet.instance; if (instance != null) { ((MonoBehaviour)instance).StartCoroutine(sendZPackage(target, package)); } } } private static OwnConfigEntryBase? configData(ConfigEntryBase config) { return config.Description.Tags?.OfType().SingleOrDefault(); } public static SyncedConfigEntry? ConfigData(ConfigEntry config) { return ((ConfigEntryBase)config).Description.Tags?.OfType>().SingleOrDefault(); } private static T configAttribute(ConfigEntryBase config) { return config.Description.Tags.OfType().First(); } private static Type configType(ConfigEntryBase config) { return configType(config.SettingType); } private static Type configType(Type type) { if (!type.IsEnum) { return type; } return Enum.GetUnderlyingType(type); } private static ZPackage ConfigsToPackage(IEnumerable? configs = null, IEnumerable? customValues = null, IEnumerable? packageEntries = null, bool partial = true) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Expected O, but got Unknown List list = configs?.Where((ConfigEntryBase config) => configData(config).SynchronizedConfig).ToList() ?? new List(); List list2 = customValues?.ToList() ?? new List(); ZPackage val = new ZPackage(); val.Write(partial ? ((byte)1) : ((byte)0)); val.Write(list.Count + list2.Count + (packageEntries?.Count() ?? 0)); foreach (PackageEntry item in packageEntries ?? Array.Empty()) { AddEntryToPackage(val, item); } foreach (CustomSyncedValueBase item2 in list2) { AddEntryToPackage(val, new PackageEntry { section = "Internal", key = item2.Identifier, type = item2.Type, value = item2.BoxedValue }); } foreach (ConfigEntryBase item3 in list) { AddEntryToPackage(val, new PackageEntry { section = item3.Definition.Section, key = item3.Definition.Key, type = configType(item3), value = item3.BoxedValue }); } return val; } private static void AddEntryToPackage(ZPackage package, PackageEntry entry) { package.Write(entry.section); package.Write(entry.key); package.Write((entry.value == null) ? "" : GetZPackageTypeString(entry.type)); AddValueToZPackage(package, entry.value); } private static string GetZPackageTypeString(Type type) { return type.AssemblyQualifiedName; } private static void AddValueToZPackage(ZPackage package, object? value) { Type type = value?.GetType(); if (value is Enum) { value = ((IConvertible)value).ToType(Enum.GetUnderlyingType(value.GetType()), CultureInfo.InvariantCulture); } else { if (value is ICollection collection) { package.Write(collection.Count); { foreach (object item in collection) { AddValueToZPackage(package, item); } return; } } if ((object)type != null && type.IsValueType && !type.IsPrimitive) { FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); package.Write(fields.Length); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { package.Write(GetZPackageTypeString(fieldInfo.FieldType)); AddValueToZPackage(package, fieldInfo.GetValue(value)); } return; } } ZRpc.Serialize(new object[1] { value }, ref package); } private static object ReadValueWithTypeFromZPackage(ZPackage package, Type type) { if ((object)type != null && type.IsValueType && !type.IsPrimitive && !type.IsEnum) { FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); int num = package.ReadInt(); if (num != fields.Length) { throw new InvalidDeserializationTypeException { received = $"(field count: {num})", expected = $"(field count: {fields.Length})" }; } object uninitializedObject = FormatterServices.GetUninitializedObject(type); FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { string text = package.ReadString(); if (text != GetZPackageTypeString(fieldInfo.FieldType)) { throw new InvalidDeserializationTypeException { received = text, expected = GetZPackageTypeString(fieldInfo.FieldType), field = fieldInfo.Name }; } fieldInfo.SetValue(uninitializedObject, ReadValueWithTypeFromZPackage(package, fieldInfo.FieldType)); } return uninitializedObject; } if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<, >)) { int num2 = package.ReadInt(); IDictionary dictionary = (IDictionary)Activator.CreateInstance(type); Type type2 = typeof(KeyValuePair<, >).MakeGenericType(type.GenericTypeArguments); FieldInfo field = type2.GetField("key", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo field2 = type2.GetField("value", BindingFlags.Instance | BindingFlags.NonPublic); for (int j = 0; j < num2; j++) { object obj = ReadValueWithTypeFromZPackage(package, type2); dictionary.Add(field.GetValue(obj), field2.GetValue(obj)); } return dictionary; } if (type != typeof(List) && type.IsGenericType) { Type type3 = typeof(ICollection<>).MakeGenericType(type.GenericTypeArguments[0]); if ((object)type3 != null && type3.IsAssignableFrom(type)) { int num3 = package.ReadInt(); object obj2 = Activator.CreateInstance(type); MethodInfo method = type3.GetMethod("Add"); for (int k = 0; k < num3; k++) { method.Invoke(obj2, new object[1] { ReadValueWithTypeFromZPackage(package, type.GenericTypeArguments[0]) }); } return obj2; } } ParameterInfo parameterInfo = (ParameterInfo)FormatterServices.GetUninitializedObject(typeof(ParameterInfo)); AccessTools.DeclaredField(typeof(ParameterInfo), "ClassImpl").SetValue(parameterInfo, type); List source = new List(); ZRpc.Deserialize(new ParameterInfo[2] { null, parameterInfo }, package, ref source); return source.First(); } } [PublicAPI] [HarmonyPatch] public class VersionCheck { private static readonly HashSet versionChecks; private static readonly Dictionary notProcessedNames; public string Name; private string? displayName; private string? currentVersion; private string? minimumRequiredVersion; public bool ModRequired = true; private string? ReceivedCurrentVersion; private string? ReceivedMinimumRequiredVersion; private readonly List ValidatedClients = new List(); private ConfigSync? ConfigSync; public string DisplayName { get { return displayName ?? Name; } set { displayName = value; } } public string CurrentVersion { get { return currentVersion ?? "0.0.0"; } set { currentVersion = value; } } public string MinimumRequiredVersion { get { string text = minimumRequiredVersion; if (text == null) { if (!ModRequired) { return "0.0.0"; } text = CurrentVersion; } return text; } set { minimumRequiredVersion = value; } } private static void PatchServerSync() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Expected O, but got Unknown Patches patchInfo = PatchProcessor.GetPatchInfo((MethodBase)AccessTools.DeclaredMethod(typeof(ZNet), "Awake", (Type[])null, (Type[])null)); if (patchInfo != null && patchInfo.Postfixes.Count((Patch p) => p.PatchMethod.DeclaringType == typeof(ConfigSync.RegisterRPCPatch)) > 0) { return; } Harmony val = new Harmony("org.bepinex.helpers.ServerSync"); foreach (Type item in from t in typeof(ConfigSync).GetNestedTypes(BindingFlags.NonPublic).Concat(new Type[1] { typeof(VersionCheck) }) where t.IsClass select t) { val.PatchAll(item); } } static VersionCheck() { versionChecks = new HashSet(); notProcessedNames = new Dictionary(); typeof(ThreadingHelper).GetMethod("StartSyncInvoke").Invoke(ThreadingHelper.Instance, new object[1] { new Action(PatchServerSync) }); } public VersionCheck(string name) { Name = name; ModRequired = true; versionChecks.Add(this); } public VersionCheck(ConfigSync configSync) { ConfigSync = configSync; Name = ConfigSync.Name; versionChecks.Add(this); } public void Initialize() { ReceivedCurrentVersion = null; ReceivedMinimumRequiredVersion = null; if (ConfigSync != null) { Name = ConfigSync.Name; DisplayName = ConfigSync.DisplayName; CurrentVersion = ConfigSync.CurrentVersion; MinimumRequiredVersion = ConfigSync.MinimumRequiredVersion; ModRequired = ConfigSync.ModRequired; } } private bool IsVersionOk() { if (ReceivedMinimumRequiredVersion == null || ReceivedCurrentVersion == null) { return !ModRequired; } bool num = new Version(CurrentVersion) >= new Version(ReceivedMinimumRequiredVersion); bool flag = new Version(ReceivedCurrentVersion) >= new Version(MinimumRequiredVersion); return num && flag; } private string ErrorClient() { if (ReceivedMinimumRequiredVersion == null) { return DisplayName + " is not installed on the server."; } if (!(new Version(CurrentVersion) >= new Version(ReceivedMinimumRequiredVersion))) { return DisplayName + " needs to be at least version " + ReceivedMinimumRequiredVersion + ". You have version " + CurrentVersion + "."; } return DisplayName + " may not be higher than version " + ReceivedCurrentVersion + ". You have version " + CurrentVersion + "."; } private string ErrorServer(ZRpc rpc) { return "Disconnect: The client (" + rpc.GetSocket().GetHostName() + ") doesn't have the correct " + DisplayName + " version " + MinimumRequiredVersion; } private string Error(ZRpc? rpc = null) { if (rpc != null) { return ErrorServer(rpc); } return ErrorClient(); } private static VersionCheck[] GetFailedClient() { return versionChecks.Where((VersionCheck check) => !check.IsVersionOk()).ToArray(); } private static VersionCheck[] GetFailedServer(ZRpc rpc) { return versionChecks.Where((VersionCheck check) => check.ModRequired && !check.ValidatedClients.Contains(rpc)).ToArray(); } private static void Logout() { Game.instance.Logout(true, true); AccessTools.DeclaredField(typeof(ZNet), "m_connectionStatus").SetValue(null, (object)(ConnectionStatus)3); } private static void DisconnectClient(ZRpc rpc) { rpc.Invoke("Error", new object[1] { 3 }); } private static void CheckVersion(ZRpc rpc, ZPackage pkg) { CheckVersion(rpc, pkg, null); } private static void CheckVersion(ZRpc rpc, ZPackage pkg, Action? original) { string text = pkg.ReadString(); string text2 = pkg.ReadString(); string text3 = pkg.ReadString(); bool flag = false; foreach (VersionCheck versionCheck in versionChecks) { if (!(text != versionCheck.Name)) { Debug.Log((object)("Received " + versionCheck.DisplayName + " version " + text3 + " and minimum version " + text2 + " from the " + (ZNet.instance.IsServer() ? "client" : "server") + ".")); versionCheck.ReceivedMinimumRequiredVersion = text2; versionCheck.ReceivedCurrentVersion = text3; if (ZNet.instance.IsServer() && versionCheck.IsVersionOk()) { versionCheck.ValidatedClients.Add(rpc); } flag = true; } } if (flag) { return; } pkg.SetPos(0); if (original != null) { original(rpc, pkg); if (pkg.GetPos() == 0) { notProcessedNames.Add(text, text3); } } } [HarmonyPatch(typeof(ZNet), "RPC_PeerInfo")] [HarmonyPrefix] private static bool RPC_PeerInfo(ZRpc rpc, ZNet __instance) { VersionCheck[] array = (__instance.IsServer() ? GetFailedServer(rpc) : GetFailedClient()); if (array.Length == 0) { return true; } VersionCheck[] array2 = array; for (int i = 0; i < array2.Length; i++) { Debug.LogWarning((object)array2[i].Error(rpc)); } if (__instance.IsServer()) { DisconnectClient(rpc); } else { Logout(); } return false; } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] [HarmonyPrefix] private static void RegisterAndCheckVersion(ZNetPeer peer, ZNet __instance) { //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Expected O, but got Unknown notProcessedNames.Clear(); IDictionary dictionary = (IDictionary)typeof(ZRpc).GetField("m_functions", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(peer.m_rpc); if (dictionary.Contains(StringExtensionMethods.GetStableHashCode("ServerSync VersionCheck"))) { object obj = dictionary[StringExtensionMethods.GetStableHashCode("ServerSync VersionCheck")]; Action action = (Action)obj.GetType().GetField("m_action", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(obj); peer.m_rpc.Register("ServerSync VersionCheck", (Action)delegate(ZRpc rpc, ZPackage pkg) { CheckVersion(rpc, pkg, action); }); } else { peer.m_rpc.Register("ServerSync VersionCheck", (Action)CheckVersion); } foreach (VersionCheck versionCheck in versionChecks) { versionCheck.Initialize(); if (versionCheck.ModRequired || __instance.IsServer()) { Debug.Log((object)("Sending " + versionCheck.DisplayName + " version " + versionCheck.CurrentVersion + " and minimum version " + versionCheck.MinimumRequiredVersion + " to the " + (__instance.IsServer() ? "client" : "server") + ".")); ZPackage val = new ZPackage(); val.Write(versionCheck.Name); val.Write(versionCheck.MinimumRequiredVersion); val.Write(versionCheck.CurrentVersion); peer.m_rpc.Invoke("ServerSync VersionCheck", new object[1] { val }); } } } [HarmonyPatch(typeof(ZNet), "Disconnect")] [HarmonyPrefix] private static void RemoveDisconnected(ZNetPeer peer, ZNet __instance) { if (!__instance.IsServer()) { return; } foreach (VersionCheck versionCheck in versionChecks) { versionCheck.ValidatedClients.Remove(peer.m_rpc); } } [HarmonyPatch(typeof(FejdStartup), "ShowConnectError")] [HarmonyPostfix] private static void ShowConnectionError(FejdStartup __instance) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) if (!__instance.m_connectionFailedPanel.activeSelf || (int)ZNet.GetConnectionStatus() != 3) { return; } bool flag = false; VersionCheck[] failedClient = GetFailedClient(); if (failedClient.Length != 0) { string text = string.Join("\n", failedClient.Select((VersionCheck check) => check.Error())); TMP_Text connectionFailedError = __instance.m_connectionFailedError; connectionFailedError.text = connectionFailedError.text + "\n" + text; flag = true; } foreach (KeyValuePair item in notProcessedNames.OrderBy((KeyValuePair kv) => kv.Key)) { if (!__instance.m_connectionFailedError.text.Contains(item.Key)) { TMP_Text connectionFailedError2 = __instance.m_connectionFailedError; connectionFailedError2.text = connectionFailedError2.text + "\nServer expects you to have " + item.Key + " (Version: " + item.Value + ") installed."; flag = true; } } if (flag) { RectTransform component = ((Component)__instance.m_connectionFailedPanel.transform.Find("Image")).GetComponent(); Vector2 sizeDelta = component.sizeDelta; sizeDelta.x = 675f; component.sizeDelta = sizeDelta; __instance.m_connectionFailedError.ForceMeshUpdate(false, false); float num = __instance.m_connectionFailedError.renderedHeight + 105f; RectTransform component2 = ((Component)((Component)component).transform.Find("ButtonOk")).GetComponent(); component2.anchoredPosition = new Vector2(component2.anchoredPosition.x, component2.anchoredPosition.y - (num - component.sizeDelta.y) / 2f); sizeDelta = component.sizeDelta; sizeDelta.y = num; component.sizeDelta = sizeDelta; } } } } namespace BarrkUI { internal static class Diagnostics { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__12_0; public static ConsoleEvent <>9__12_1; public static ConsoleEvent <>9__12_2; public static ConsoleEvent <>9__12_3; public static ConsoleEvent <>9__12_4; internal void b__12_0(ConsoleEventArgs args) { if (args.Args.Length > 1) { switch (args.Args[1].ToLowerInvariant()) { case "on": case "1": case "true": ConfigManager.debugLogging.Value = true; break; case "off": case "0": case "false": ConfigManager.debugLogging.Value = false; break; default: args.Context.AddString("vikingos_debug: expected 'on' or 'off'."); return; } } foreach (string item in StatusLines()) { args.Context.AddString(item); } args.Context.AddString(" session : " + SessionState.Describe()); args.Context.AddString(" chat : " + ChatFeatures.Describe()); args.Context.AddString($" shares : {ItemShareCache.Count} cached this session"); args.Context.AddString(" whisper : " + (WhisperRpc.CanReply ? ("/r replies to " + WhisperRpc.LastFromName) : "nobody has whispered you yet")); args.Context.AddString($" trade : {TradeRpc.State}" + (TradeRpc.Busy ? (" with " + TradeRpc.PartnerName) : string.Empty) + $" escrow held here: {TradeEscrow.Count}"); } internal void b__12_1(ConsoleEventArgs args) { if (args.Args.Length > 1 && args.Args[1].ToLowerInvariant() == "edit") { if (!SessionState.PlayerReady) { args.Context.AddString("vikingos_layout: not in a world yet (" + SessionState.Describe() + ")."); return; } LayoutEditor.Toggle(); args.Context.AddString("vikingos_layout: edit mode " + (LayoutEditor.Active ? "on" : "off") + "."); } else if (args.Args.Length > 1 && args.Args[1].ToLowerInvariant() == "reset") { if (args.Args.Length > 2) { string text = string.Join(" ", args.Args, 2, args.Args.Length - 2); LayoutTarget layoutTarget = FindTarget(text); if (layoutTarget == null) { args.Context.AddString("vikingos_layout: no element matching '" + text + "'. Run 'vikingos_layout' for the list."); return; } LayoutEngine.Reset(layoutTarget); args.Context.AddString("vikingos_layout: " + layoutTarget.Label + " reset to where the game left it."); } else { LayoutEngine.ResetAll(); args.Context.AddString("vikingos_layout: every element reset."); } } else { string[] array = LayoutEngine.Describe().Split(new char[1] { '\n' }); foreach (string text2 in array) { args.Context.AddString(text2.TrimEnd(new char[1] { '\r' })); } } } internal void b__12_2(ConsoleEventArgs args) { if (!SessionState.IsLive) { args.Context.AddString("vikingos_dumpui: not in a world yet (" + SessionState.Describe() + ")."); return; } try { args.Context.AddString("vikingos_dumpui: wrote " + UiDump.Write()); } catch (Exception ex) { args.Context.AddString("vikingos_dumpui failed: " + ex.Message); Log.LogError((object)ex.ToString()); } } internal void b__12_3(ConsoleEventArgs args) { try { TradeTest.Run(args); } catch (Exception ex) { args.Context.AddString("vikingos_tradetest failed: " + ex.Message); Log.LogError((object)ex.ToString()); } } internal void b__12_4(ConsoleEventArgs args) { try { WhisperTest.Run(args); } catch (Exception ex) { args.Context.AddString("vikingos_whispertest failed: " + ex.Message); Log.LogError((object)ex.ToString()); } } } private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.Debug"); private static readonly List _healthOrder = new List(); private static readonly Dictionary _health = new Dictionary(); private static bool _commandRegistered; public static bool Enabled { get { if (ConfigManager.debugLogging != null) { return ConfigManager.debugLogging.Value; } return false; } } public static bool OverlayEnabled { get { if (ConfigManager.debugOverlay != null) { return ConfigManager.debugOverlay.Value; } return false; } } public static void Trace(Func message) { if (!Enabled) { return; } try { Log.LogInfo((object)message()); } catch (Exception ex) { Log.LogWarning((object)("A trace message threw while being built (the traced operation itself is unaffected): " + ex.Message)); } } public static void Health(string feature, bool ok, string detail) { string line = (ok ? "OK " : "DEGRADED") + " " + feature + " - " + detail; if (!_health.ContainsKey(feature)) { _healthOrder.Add(feature); } _health[feature] = line; if (ok) { Trace(() => "health: " + line); } else { Log.LogWarning((object)(feature + " is not working: " + detail)); } } public static void HealthUnknown(string feature, string detail) { string value = "UNKNOWN " + feature + " - " + detail; if (!_health.ContainsKey(feature)) { _healthOrder.Add(feature); } _health[feature] = value; Log.LogInfo((object)(feature + ": " + detail)); } public static IEnumerable StatusLines() { yield return "VikingOS v0.9.2 - debug logging " + (Enabled ? "ON" : "off") + ", overlay " + (OverlayEnabled ? "ON" : "off"); if (_healthOrder.Count == 0) { yield return " (nothing has reported in yet - patches attach on load, RPCs on entering a world)"; yield break; } foreach (string item in _healthOrder) { yield return " " + _health[item]; } } public static void RegisterConsoleCommand() { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0027: 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: Expected O, but got Unknown //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_0097: 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_00a2: Expected O, but got Unknown //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Expected O, but got Unknown //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Expected O, but got Unknown if (_commandRegistered) { return; } try { object obj = <>c.<>9__12_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { if (args.Args.Length > 1) { switch (args.Args[1].ToLowerInvariant()) { case "on": case "1": case "true": ConfigManager.debugLogging.Value = true; break; case "off": case "0": case "false": ConfigManager.debugLogging.Value = false; break; default: args.Context.AddString("vikingos_debug: expected 'on' or 'off'."); return; } } foreach (string item in StatusLines()) { args.Context.AddString(item); } args.Context.AddString(" session : " + SessionState.Describe()); args.Context.AddString(" chat : " + ChatFeatures.Describe()); args.Context.AddString($" shares : {ItemShareCache.Count} cached this session"); args.Context.AddString(" whisper : " + (WhisperRpc.CanReply ? ("/r replies to " + WhisperRpc.LastFromName) : "nobody has whispered you yet")); args.Context.AddString($" trade : {TradeRpc.State}" + (TradeRpc.Busy ? (" with " + TradeRpc.PartnerName) : string.Empty) + $" escrow held here: {TradeEscrow.Count}"); }; <>c.<>9__12_0 = val; obj = (object)val; } new ConsoleCommand("vikingos_debug", "[on|off] - VikingOS:print feature status, and optionally turn debug logging on or off", (ConsoleEvent)obj, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj2 = <>c.<>9__12_1; if (obj2 == null) { ConsoleEvent val2 = delegate(ConsoleEventArgs args) { if (args.Args.Length > 1 && args.Args[1].ToLowerInvariant() == "edit") { if (!SessionState.PlayerReady) { args.Context.AddString("vikingos_layout: not in a world yet (" + SessionState.Describe() + ")."); } else { LayoutEditor.Toggle(); args.Context.AddString("vikingos_layout: edit mode " + (LayoutEditor.Active ? "on" : "off") + "."); } } else if (args.Args.Length > 1 && args.Args[1].ToLowerInvariant() == "reset") { if (args.Args.Length > 2) { string text = string.Join(" ", args.Args, 2, args.Args.Length - 2); LayoutTarget layoutTarget = FindTarget(text); if (layoutTarget == null) { args.Context.AddString("vikingos_layout: no element matching '" + text + "'. Run 'vikingos_layout' for the list."); } else { LayoutEngine.Reset(layoutTarget); args.Context.AddString("vikingos_layout: " + layoutTarget.Label + " reset to where the game left it."); } } else { LayoutEngine.ResetAll(); args.Context.AddString("vikingos_layout: every element reset."); } } else { string[] array = LayoutEngine.Describe().Split(new char[1] { '\n' }); foreach (string text2 in array) { args.Context.AddString(text2.TrimEnd(new char[1] { '\r' })); } } }; <>c.<>9__12_1 = val2; obj2 = (object)val2; } new ConsoleCommand("vikingos_layout", "[edit|reset|reset ] - VikingOS:show every movable UI element and its current offset", (ConsoleEvent)obj2, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj3 = <>c.<>9__12_2; if (obj3 == null) { ConsoleEvent val3 = delegate(ConsoleEventArgs args) { if (!SessionState.IsLive) { args.Context.AddString("vikingos_dumpui: not in a world yet (" + SessionState.Describe() + ")."); return; } try { args.Context.AddString("vikingos_dumpui: wrote " + UiDump.Write()); } catch (Exception ex2) { args.Context.AddString("vikingos_dumpui failed: " + ex2.Message); Log.LogError((object)ex2.ToString()); } }; <>c.<>9__12_2 = val3; obj3 = (object)val3; } new ConsoleCommand("vikingos_dumpui", "VikingOS: write the live UI tree (canvases, scalers, every RectTransform) to a file", (ConsoleEvent)obj3, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj4 = <>c.<>9__12_3; if (obj4 == null) { ConsoleEvent val4 = delegate(ConsoleEventArgs args) { try { TradeTest.Run(args); } catch (Exception ex2) { args.Context.AddString("vikingos_tradetest failed: " + ex2.Message); Log.LogError((object)ex2.ToString()); } }; <>c.<>9__12_3 = val4; obj4 = (object)val4; } new ConsoleCommand("vikingos_tradetest", "[roundtrip|swap|dupe|refund|status|claim] - VikingOS:drive the real trade settlement path solo", (ConsoleEvent)obj4, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj5 = <>c.<>9__12_4; if (obj5 == null) { ConsoleEvent val5 = delegate(ConsoleEventArgs args) { try { WhisperTest.Run(args); } catch (Exception ex2) { args.Context.AddString("vikingos_whispertest failed: " + ex2.Message); Log.LogError((object)ex2.ToString()); } }; <>c.<>9__12_4 = val5; obj5 = (object)val5; } new ConsoleCommand("vikingos_whispertest", "VikingOS: whisper yourself and check the whole path - sanitiser, reply target, privacy", (ConsoleEvent)obj5, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); _commandRegistered = true; Health("Console command", ok: true, "'vikingos_debug', 'vikingos_dumpui', 'vikingos_layout', 'vikingos_tradetest' and 'vikingos_whispertest' registered"); } catch (Exception ex) { Health("Console command", ok: false, "'vikingos_debug' could not be registered. Reason: " + ex.Message); Log.LogError((object)ex.ToString()); } } private static LayoutTarget FindTarget(string wanted) { foreach (LayoutTarget target in LayoutEngine.Targets) { if (string.Equals(target.Id, wanted, StringComparison.OrdinalIgnoreCase)) { return target; } if (string.Equals(target.Label, wanted, StringComparison.OrdinalIgnoreCase)) { return target; } } return null; } } internal static class ModPaths { private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.Paths"); public const string FolderName = "VikingOS"; private const string LegacyFolderName = "BarrkUI"; private const string LegacyConfigFile = "wubarrk.BarrkUI.cfg"; private const string CurrentConfigFile = "wubarrk.VikingOS.cfg"; public static string ConfigDir => Path.Combine(Paths.ConfigPath, "VikingOS"); public static string InConfigDir(string leaf) { return Path.Combine(ConfigDir, leaf); } public static bool MigrateLegacyNames() { bool result = false; try { result = MoveFile(Path.Combine(Paths.ConfigPath, "wubarrk.BarrkUI.cfg"), Path.Combine(Paths.ConfigPath, "wubarrk.VikingOS.cfg")); MoveDirectory(Path.Combine(Paths.ConfigPath, "BarrkUI"), ConfigDir); } catch (Exception ex) { Log.LogWarning((object)("could not migrate the old BarrkUI-named configuration (non-fatal, VikingOS starts on its defaults and your old files are untouched). Reason: " + ex.Message)); } return result; } private static bool MoveFile(string from, string to) { if (!File.Exists(from) || File.Exists(to)) { return false; } File.Move(from, to); Log.LogInfo((object)("migrated configuration: " + Path.GetFileName(from) + " -> " + Path.GetFileName(to))); return true; } private static void MoveDirectory(string from, string to) { if (!Directory.Exists(from)) { return; } if (!Directory.Exists(to)) { Directory.Move(from, to); Log.LogInfo((object)"migrated configuration folder: BarrkUI/ -> VikingOS/"); return; } int num = 0; string[] files = Directory.GetFiles(from, "*", SearchOption.AllDirectories); foreach (string text in files) { string path = text.Substring(from.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); string text2 = Path.Combine(to, path); if (!File.Exists(text2)) { Directory.CreateDirectory(Path.GetDirectoryName(text2)); File.Move(text, text2); num++; } } if (num > 0) { Log.LogInfo((object)(string.Format("migrated {0} file(s) from {1}/ into {2}/. ", num, "BarrkUI", "VikingOS") + "The old folder is left in place - delete it once you are happy.")); } } } [BepInPlugin("wubarrk.VikingOS", "VikingOS", "0.9.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string PluginGUID = "wubarrk.VikingOS"; public const string PluginName = "VikingOS"; public const string PluginVersion = "0.9.2"; private readonly Harmony _harmony = new Harmony("wubarrk.VikingOS"); private static readonly Type[] PatchTypes = new Type[8] { typeof(SessionState.LifecyclePatch), typeof(UIFocus.UIFocusPatch), typeof(ChatMessagePatch), typeof(AlwaysShoutPatch), typeof(ItemShareRpc.RegisterPatch), typeof(TradeRpc.RegisterPatch), typeof(ChatRelay.RoutedRpcPatch), typeof(EmoteLibrary.SessionPatch) }; private static readonly Type[] UiPatchTypes = new Type[7] { typeof(LayoutBars), typeof(EmoteRenderer.ChatHookPatch), typeof(ChatWindowFix), typeof(ChatOverhaulWindow.DropOutsidePatch), typeof(WhisperRpc.RegisterPatch), typeof(ChatCommands.InputTextPatch), typeof(PanelTheme) }; public static Plugin Instance; public static ManualLogSource Log; private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; if (ModPaths.MigrateLegacyNames()) { ((BaseUnityPlugin)this).Config.Reload(); } ConfigManager.Init(((BaseUnityPlugin)this).Config); Log.LogInfo((object)("Running as " + RunMode.Describe() + ".")); if (!RunMode.HasUI) { ChatFeatures.LatchForSession(); } if (RunMode.HasUI) { LayoutEngine.Init(); } Diagnostics.RegisterConsoleCommand(); EmoteLibrary.Init(); ChatRelay.Init(); ApplyPatches(); KgChatOverride.Apply(_harmony); Log.LogInfo((object)"VikingOS v0.9.2 loaded successfully."); } private void Update() { ChatRelay.Pump(); TradeRpc.Tick(); if (RunMode.HasUI) { EmojiPicker.Watchdog(); if (ChatFeatures.Enabled) { ChatOverhaulWindow.Tick(); } LayoutEditor.Tick(); } } private void LateUpdate() { if (RunMode.HasUI) { LayoutEngine.LateUpdate(); } } private void OnGUI() { if (RunMode.HasUI) { PanelFrame.Draw(); HudWidgets.Draw(); if (ChatFeatures.Enabled) { ChatOverhaulWindow.Draw(); } TradeWindow.Draw(); LayoutEditor.Draw(); } } private void ApplyPatches() { Type[] array = (RunMode.HasUI ? PatchTypes.Concat(UiPatchTypes).ToArray() : PatchTypes); foreach (Type type in array) { try { _harmony.PatchAll(type); if (type != typeof(ChatMessagePatch)) { Diagnostics.Health(type.Name, ok: true, "patched"); } } catch (Exception ex) { Diagnostics.Health(type.Name, ok: false, "failed to patch, related features are disabled. Reason: " + ex.Message); Log.LogError((object)ex.ToString()); } } } } internal static class RunMode { private static readonly bool _isDedicatedServer = (int)SystemInfo.graphicsDeviceType == 4; public static bool IsDedicatedServer => _isDedicatedServer; public static bool HasUI => !_isDedicatedServer; public static string Describe() { if (!_isDedicatedServer) { return "client (full UI)"; } return "dedicated server (no UI; chat policy and item-link routing only)"; } } internal static class SessionState { [HarmonyPatch] internal static class LifecyclePatch { [HarmonyPatch(typeof(Player), "SetLocalPlayer")] [HarmonyPostfix] private static void Player_SetLocalPlayer_Postfix() { try { Diagnostics.Trace(() => "local player is live; session state: " + Describe() + "."); ChatFeatures.LatchForSession(); KgChatOverride.VerifyOutcome(); TradeRpc.ClaimPending(); } catch (Exception arg) { Log.LogError((object)$"SetLocalPlayer postfix failed (non-fatal). Reason: {arg}"); } } [HarmonyPatch(typeof(Game), "Logout")] [HarmonyPrefix] private static void Game_Logout_Prefix() { Reset("logout"); } [HarmonyPatch(typeof(ZNet), "Shutdown")] [HarmonyPrefix] private static void ZNet_Shutdown_Prefix() { Reset("network shutdown"); } } private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.Session"); public static bool NetworkReady { get { if ((Object)(object)ZNet.instance != (Object)null) { return ZRoutedRpc.instance != null; } return false; } } public static bool PlayerReady { get { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (NetworkReady && (Object)(object)Player.m_localPlayer != (Object)null) { return ZNet.instance.LocalPlayerCharacterID != ZDOID.None; } return false; } } public static bool ContentReady { get { if ((Object)(object)ObjectDB.instance != (Object)null && ObjectDB.instance.m_items != null) { return ObjectDB.instance.m_items.Count > 0; } return false; } } public static bool IsLive { get { if (PlayerReady) { return ContentReady; } return false; } } public static int SessionId { get; private set; } public static string Describe() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null) { return "no ZNet (main menu / not connected)"; } if (ZRoutedRpc.instance == null) { return "no ZRoutedRpc"; } if ((Object)(object)Player.m_localPlayer == (Object)null) { return "no local player yet (still loading in)"; } if (ZNet.instance.LocalPlayerCharacterID == ZDOID.None) { return "local player has no character id yet"; } if (!ContentReady) { return "ObjectDB not populated yet"; } return "live"; } public static void Reset(string reason) { try { SessionId++; int cached = ItemShareCache.Count; ItemShareCache.Clear(); ItemIconSprites.Clear(); ChatOverhaulWindow.ResetSession(); PanelFrame.ResetSession(); ChatFeatures.ResetSession(); WhisperRpc.ResetSession(); TradeRpc.ResetSession(); TradeWindow.ResetSession(); UIFocus.SetWantsCursor("VikingOS_ChatOverhaulWindow", active: false); UIFocus.SetHasTextFocus("VikingOS_ChatOverhaulWindow", active: false); Diagnostics.Trace(() => $"session reset ({reason}); dropped {cached} cached item share(s)."); } catch (Exception arg) { Log.LogError((object)$"Session reset failed after {reason} - state may leak into the next world. Reason: {arg}"); } } } internal sealed class TestReport { private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.SelfTest"); private readonly Terminal _terminal; public int Failures { get; private set; } public int Passes { get; private set; } public TestReport(Terminal terminal) { _terminal = terminal; } public void Line(string text) { Terminal terminal = _terminal; if (terminal != null) { terminal.AddString(text); } Log.LogInfo((object)text); } public void Check(bool ok, string what) { if (ok) { Passes++; Line(" PASS " + what); } else { Failures++; Line(" FAIL " + what); } } public void Fail(string what) { Failures++; Line(" FAIL " + what); } public void Summary() { if (Passes != 0 || Failures != 0) { Line((Failures == 0) ? $" ---- {Passes} check(s) passed, none failed." : $" ---- {Passes} passed, {Failures} FAILED. Do not ship this until they are understood."); } } } internal static class UiDump { private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.UiDump"); private const int MaxDepth = 12; private static readonly Type[] UiRootTypes = new Type[4] { typeof(Hud), typeof(InventoryGui), typeof(Minimap), typeof(Chat) }; private static readonly Vector3[] _corners = (Vector3[])(object)new Vector3[4]; public static string Write() { //IL_007b: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("VikingOS live UI dump"); stringBuilder.AppendLine($"generated : {DateTime.Now:yyyy-MM-dd HH:mm:ss}"); stringBuilder.AppendLine("VikingOS : v0.9.2"); stringBuilder.AppendLine($"screen : {Screen.width}x{Screen.height} dpi={Screen.dpi} fullscreen={Screen.fullScreen} ({Screen.fullScreenMode})"); stringBuilder.AppendLine("session : " + SessionState.Describe()); stringBuilder.AppendLine(); AppendKnownRoots(stringBuilder); Canvas[] array = Object.FindObjectsByType((FindObjectsInactive)1, (FindObjectsSortMode)0); stringBuilder.AppendLine($"=== {array.Length} Canvas(es) ==="); stringBuilder.AppendLine(); Canvas[] array2 = array; foreach (Canvas canvas in array2) { AppendCanvas(stringBuilder, canvas); } string configDir = ModPaths.ConfigDir; Directory.CreateDirectory(configDir); string text = Path.Combine(configDir, $"ui-dump-{DateTime.Now:yyyyMMdd-HHmmss}.txt"); File.WriteAllText(text, stringBuilder.ToString()); Log.LogInfo((object)("UI dump written to " + text)); return text; } private static void AppendKnownRoots(StringBuilder sb) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) sb.AppendLine("=== Vanilla UI handles (reflected - every UI-typed field on each singleton) ==="); sb.AppendLine(); Type[] uiRootTypes = UiRootTypes; foreach (Type type in uiRootTypes) { object singleton = GetSingleton(type); sb.AppendLine("--- " + type.Name + " ---"); if (singleton == null) { sb.AppendLine(" (no live instance right now)"); sb.AppendLine(); continue; } AppendHandle(sb, " (root)", ((Component)singleton).gameObject); FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { if (!IsUiType(fieldInfo.FieldType)) { continue; } object value; try { value = fieldInfo.GetValue(singleton); } catch { continue; } if (value is Array array) { for (int k = 0; k < array.Length; k++) { AppendHandle(sb, $" {fieldInfo.Name}[{k}]", ResolveGameObject(array.GetValue(k))); } } else { AppendHandle(sb, " " + fieldInfo.Name, ResolveGameObject(value)); } } sb.AppendLine(); } } private static object GetSingleton(Type type) { PropertyInfo property = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public); if (property != null) { object value = property.GetValue(null); Object val = (Object)((value is Object) ? value : null); if (val != null && val != (Object)null) { return value; } } FieldInfo field = type.GetField("m_instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { object value2 = field.GetValue(null); Object val2 = (Object)((value2 is Object) ? value2 : null); if (val2 != null && val2 != (Object)null) { return value2; } } return null; } private static bool IsUiType(Type t) { if (t.IsArray) { t = t.GetElementType(); } if (t == null) { return false; } if (!typeof(GameObject).IsAssignableFrom(t) && !typeof(Transform).IsAssignableFrom(t) && !typeof(Graphic).IsAssignableFrom(t) && !typeof(Canvas).IsAssignableFrom(t) && !typeof(Selectable).IsAssignableFrom(t)) { return typeof(TMP_Text).IsAssignableFrom(t); } return true; } private static void AppendAnimator(StringBuilder sb, GameObject go, int pad) { Animator component = go.GetComponent(); if ((Object)(object)component == (Object)null) { return; } string text = "(no controller)"; if ((Object)(object)component.runtimeAnimatorController != (Object)null) { List list = new List(); AnimationClip[] animationClips = component.runtimeAnimatorController.animationClips; foreach (AnimationClip val in animationClips) { if ((Object)(object)val != (Object)null) { list.Add(((Object)val).name); } } text = ((list.Count > 0) ? string.Join(",", list.ToArray()) : "(no clips)"); } sb.AppendLine(string.Format("{0,-1}{1} ** ANIMATOR ** enabled={2} clips=[{3}] <- re-apply must run in LateUpdate", "", new string(' ', pad - 1), ((Behaviour)component).enabled, text)); } private static GameObject ResolveGameObject(object value) { if (value == null) { return null; } GameObject val = (GameObject)((value is GameObject) ? value : null); if (val != null) { if (!((Object)(object)val != (Object)null)) { return null; } return val; } Component val2 = (Component)((value is Component) ? value : null); if (val2 != null) { if (!((Object)(object)val2 != (Object)null)) { return null; } return val2.gameObject; } return null; } private static void AppendHandle(StringBuilder sb, string label, GameObject go) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)go == (Object)null) { sb.AppendLine($"{label,-36} : (null)"); return; } Transform transform = go.transform; RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null); string text = (((Object)(object)val != (Object)null) ? (" a[" + F(val.anchorMin) + ".." + F(val.anchorMax) + "] p" + F(val.pivot) + " pos" + F(val.anchoredPosition) + " size" + F(val.sizeDelta) + " scale" + F(((Transform)val).localScale)) : ""); sb.AppendLine($"{label,-36} : {HierarchyPath(go.transform)} active={go.activeInHierarchy}{text}"); if ((Object)(object)val != (Object)null) { val.GetWorldCorners(_corners); sb.AppendLine(string.Format("{0,-36} worldCorners BL{1} TL{2} TR{3} BR{4} lossyScale={5:0.###}", "", F(_corners[0]), F(_corners[1]), F(_corners[2]), F(_corners[3]), ((Transform)val).lossyScale.x)); } Graphic component = go.GetComponent(); if ((Object)(object)component != (Object)null) { sb.AppendLine(string.Format("{0,-36} graphic={1} raycastTarget={2}", "", ((object)component).GetType().Name, component.raycastTarget)); } Component[] components = go.GetComponents(); foreach (Component val2 in components) { if (!((Object)(object)val2 == (Object)null)) { string text2 = SafeAppearance(val2); if (text2 != null) { sb.AppendLine(string.Format("{0,-36} +{1}: {2}", "", ((object)val2).GetType().Name, text2)); } } } AppendAnimator(sb, go, 36); } private static void AppendCanvas(StringBuilder sb, Canvas canvas) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) if (canvas.isRootCanvas) { sb.AppendLine("--- Canvas: " + HierarchyPath(((Component)canvas).transform) + " ---"); sb.AppendLine($" renderMode : {canvas.renderMode}"); sb.AppendLine(" worldCamera : " + (((Object)(object)canvas.worldCamera != (Object)null) ? ((Object)canvas.worldCamera).name : "(none)")); sb.AppendLine($" sortingOrder : {canvas.sortingOrder} sortingLayer={canvas.sortingLayerName}"); sb.AppendLine($" scaleFactor : {canvas.scaleFactor}"); sb.AppendLine($" referencePixels : {canvas.referencePixelsPerUnit}"); sb.AppendLine($" pixelPerfect : {canvas.pixelPerfect}"); CanvasScaler component = ((Component)canvas).GetComponent(); if ((Object)(object)component == (Object)null) { sb.AppendLine(" CanvasScaler : (none)"); } else { sb.AppendLine($" CanvasScaler.mode : {component.uiScaleMode}"); sb.AppendLine($" referenceRes : {component.referenceResolution}"); sb.AppendLine($" screenMatch : {component.screenMatchMode} match={component.matchWidthOrHeight}"); sb.AppendLine($" scaleFactor : {component.scaleFactor}"); sb.AppendLine($" refPixelsPerUnit: {component.referencePixelsPerUnit}"); } GraphicRaycaster component2 = ((Component)canvas).GetComponent(); sb.AppendLine(" GraphicRaycaster : " + (((Object)(object)component2 != (Object)null) ? $"present (blockingObjects={component2.blockingObjects}, ignoreReversed={component2.ignoreReversedGraphics})" : "ABSENT")); if ((Object)(object)((Component)canvas).GetComponent() != (Object)null && (Object)(object)component != (Object)null) { float num = Mathf.Min((float)Screen.width / 1920f, (float)Screen.height / 1080f); float num2 = ((num > 0f) ? (component.scaleFactor / num) : float.NaN); sb.AppendLine($" GuiScaler : present geometricFactor={num:0.####} impliedGuiScale={num2:0.####}"); sb.AppendLine($" canvas rect in canvas units = {(float)Screen.width / component.scaleFactor:0.#} x {(float)Screen.height / component.scaleFactor:0.#}"); } sb.AppendLine(); sb.AppendLine(" tree (name | components | anchorMin/Max | pivot | anchoredPos | sizeDelta | scale)"); sb.AppendLine(" followed by one '+Component: key=value ...' line per component with appearance or layout data:"); AppendTree(sb, ((Component)canvas).transform, 0); sb.AppendLine(); } } private static void AppendTree(StringBuilder sb, Transform t, int depth) { //IL_003f: 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) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) if (depth > 12) { return; } string text = new string(' ', 4 + depth * 2); RectTransform val = (RectTransform)(object)((t is RectTransform) ? t : null); string text2 = (((Object)(object)val != (Object)null) ? ("a[" + F(val.anchorMin) + ".." + F(val.anchorMax) + "] p" + F(val.pivot) + " pos" + F(val.anchoredPosition) + " size" + F(val.sizeDelta) + " scale" + F(((Transform)val).localScale)) : "(not a RectTransform)"); sb.AppendLine(text + ((Object)t).name + (((Component)t).gameObject.activeSelf ? "" : " [inactive]") + " | " + Components(t) + " | " + text2); Component[] components = ((Component)t).GetComponents(); foreach (Component val2 in components) { if (!((Object)(object)val2 == (Object)null)) { string text3 = SafeAppearance(val2); if (text3 != null) { sb.AppendLine(text + " +" + ((object)val2).GetType().Name + ": " + text3); } } } for (int j = 0; j < t.childCount; j++) { AppendTree(sb, t.GetChild(j), depth + 1); } } private static string Components(Transform t) { List list = new List(); Component[] components = ((Component)t).GetComponents(); foreach (Component val in components) { if ((Object)(object)val == (Object)null) { list.Add(""); continue; } string name = ((object)val).GetType().Name; if (!(name == "RectTransform") && !(name == "Transform")) { list.Add(name); } } if (list.Count != 0) { return string.Join(",", list.ToArray()); } return "-"; } private static string SafeAppearance(Component component) { try { return Appearance(component); } catch (Exception ex) { return "** reading this component threw " + ex.GetType().Name + ": " + ex.Message + " **"; } } private static string Appearance(Component component) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_03ec: Unknown result type (might be due to invalid IL or missing references) //IL_0408: Unknown result type (might be due to invalid IL or missing references) //IL_03af: Unknown result type (might be due to invalid IL or missing references) //IL_0429: Unknown result type (might be due to invalid IL or missing references) //IL_0445: Unknown result type (might be due to invalid IL or missing references) //IL_02ec: Unknown result type (might be due to invalid IL or missing references) //IL_0308: Unknown result type (might be due to invalid IL or missing references) //IL_0324: Unknown result type (might be due to invalid IL or missing references) //IL_04cc: 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_05ad: Unknown result type (might be due to invalid IL or missing references) //IL_05f5: Unknown result type (might be due to invalid IL or missing references) //IL_0627: Unknown result type (might be due to invalid IL or missing references) //IL_062d: Invalid comparison between Unknown and I4 //IL_06af: Unknown result type (might be due to invalid IL or missing references) //IL_06b5: Invalid comparison between Unknown and I4 //IL_0631: Unknown result type (might be due to invalid IL or missing references) //IL_0636: Unknown result type (might be due to invalid IL or missing references) //IL_0640: Unknown result type (might be due to invalid IL or missing references) //IL_065c: Unknown result type (might be due to invalid IL or missing references) //IL_0678: Unknown result type (might be due to invalid IL or missing references) //IL_0694: Unknown result type (might be due to invalid IL or missing references) //IL_0724: Unknown result type (might be due to invalid IL or missing references) //IL_06bc: Unknown result type (might be due to invalid IL or missing references) //IL_06c1: Unknown result type (might be due to invalid IL or missing references) //IL_077c: Unknown result type (might be due to invalid IL or missing references) if (component is TMP_SubMeshUI || component is TMP_SubMesh) { return null; } List list = new List(); Graphic val = (Graphic)(object)((component is Graphic) ? component : null); if (val != null) { list.Add("color=" + Hex(val.color)); try { Material material = val.material; if ((Object)(object)material != (Object)null && ((Object)material).name != "Default UI Material") { list.Add("material=" + ((Object)material).name); } } catch (Exception ex) { list.Add("material=** threw " + ex.GetType().Name + " **"); } } Image val2 = (Image)(object)((component is Image) ? component : null); if (val2 == null) { RawImage val3 = (RawImage)(object)((component is RawImage) ? component : null); if (val3 == null) { TMP_Text val4 = (TMP_Text)(object)((component is TMP_Text) ? component : null); if (val4 == null) { Text val5 = (Text)(object)((component is Text) ? component : null); if (val5 == null) { Outline val6 = (Outline)(object)((component is Outline) ? component : null); if (val6 == null) { Shadow val7 = (Shadow)(object)((component is Shadow) ? component : null); if (val7 == null) { CanvasGroup val8 = (CanvasGroup)(object)((component is CanvasGroup) ? component : null); if (val8 == null) { LayoutGroup val9 = (LayoutGroup)(object)((component is LayoutGroup) ? component : null); if (val9 == null) { ContentSizeFitter val10 = (ContentSizeFitter)(object)((component is ContentSizeFitter) ? component : null); if (val10 == null) { LayoutElement val11 = (LayoutElement)(object)((component is LayoutElement) ? component : null); if (val11 == null) { AspectRatioFitter val12 = (AspectRatioFitter)(object)((component is AspectRatioFitter) ? component : null); if (val12 == null) { Selectable val13 = (Selectable)(object)((component is Selectable) ? component : null); if (val13 == null) { RectMask2D val14 = (RectMask2D)(object)((component is RectMask2D) ? component : null); if (val14 == null) { Mask val15 = (Mask)(object)((component is Mask) ? component : null); if (val15 == null) { GuiBar val16 = (GuiBar)(object)((component is GuiBar) ? component : null); if (val16 != null) { list.Add($"m_width={val16.m_width:0.#}"); list.Add("m_originalColor=" + Hex(val16.m_originalColor)); list.Add("m_bar=" + Name((Object)(object)val16.m_bar)); list.Add("** writes its bar's sizeDelta.x every frame, and ResetColor() restores m_originalColor - DO NOT THEME **"); } } else { list.Add($"showMaskGraphic={val15.showMaskGraphic}"); } } else { list.Add($"padding={val14.padding}"); } } else { list.Add($"transition={val13.transition}"); list.Add($"interactable={val13.interactable}"); if ((int)val13.transition == 1) { ColorBlock colors = val13.colors; list.Add("normal=" + Hex(((ColorBlock)(ref colors)).normalColor)); list.Add("highlighted=" + Hex(((ColorBlock)(ref colors)).highlightedColor)); list.Add("pressed=" + Hex(((ColorBlock)(ref colors)).pressedColor)); list.Add("disabled=" + Hex(((ColorBlock)(ref colors)).disabledColor)); } else if ((int)val13.transition == 2) { SpriteState spriteState = val13.spriteState; list.Add("highlightedSprite=" + Name((Object)(object)((SpriteState)(ref spriteState)).highlightedSprite)); list.Add("pressedSprite=" + Name((Object)(object)((SpriteState)(ref spriteState)).pressedSprite)); list.Add("disabledSprite=" + Name((Object)(object)((SpriteState)(ref spriteState)).disabledSprite)); } } } else { list.Add($"aspectMode={val12.aspectMode}"); list.Add($"aspectRatio={val12.aspectRatio:0.###}"); list.Add("** DRIVES rect **"); } } else { list.Add($"min=({val11.minWidth:0.#},{val11.minHeight:0.#})"); list.Add($"preferred=({val11.preferredWidth:0.#},{val11.preferredHeight:0.#})"); list.Add($"flexible=({val11.flexibleWidth:0.#},{val11.flexibleHeight:0.#})"); list.Add($"ignoreLayout={val11.ignoreLayout}"); } } else { list.Add($"horizontalFit={val10.horizontalFit}"); list.Add($"verticalFit={val10.verticalFit}"); list.Add("** DRIVES sizeDelta **"); } } else { AppendLayoutGroup(list, val9); } } else { list.Add($"alpha={val8.alpha:0.##}"); list.Add($"interactable={val8.interactable}"); list.Add($"blocksRaycasts={val8.blocksRaycasts}"); } } else { list.Add("effectColor=" + Hex(val7.effectColor)); list.Add("effectDistance=" + F(val7.effectDistance)); } } else { list.Add("effectColor=" + Hex(((Shadow)val6).effectColor)); list.Add("effectDistance=" + F(((Shadow)val6).effectDistance)); } } else { list.Add("font=" + (((Object)(object)val5.font != (Object)null) ? ((Object)val5.font).name : "(none)")); list.Add($"fontSize={val5.fontSize}"); list.Add($"style={val5.fontStyle}"); list.Add("text=" + Sample(val5.text)); } } else { list.Add("font=" + (((Object)(object)val4.font != (Object)null) ? ((Object)val4.font).name : "(none)")); if ((Object)(object)val4.fontSharedMaterial != (Object)null) { list.Add("fontMaterial=" + ((Object)val4.fontSharedMaterial).name); } list.Add($"fontSize={val4.fontSize:0.#}"); if (val4.enableAutoSizing) { list.Add($"autoSize={val4.fontSizeMin:0.#}-{val4.fontSizeMax:0.#}"); } list.Add($"style={val4.fontStyle}"); list.Add($"align={val4.alignment}"); list.Add($"overflow={val4.overflowMode}"); list.Add("text=" + Sample(val4.text)); } } else { list.Add("texture=" + (((Object)(object)val3.texture != (Object)null) ? ((Object)val3.texture).name : "(none)")); object[] array = new object[4]; Rect uvRect = val3.uvRect; array[0] = ((Rect)(ref uvRect)).x; uvRect = val3.uvRect; array[1] = ((Rect)(ref uvRect)).y; uvRect = val3.uvRect; array[2] = ((Rect)(ref uvRect)).width; uvRect = val3.uvRect; array[3] = ((Rect)(ref uvRect)).height; list.Add(string.Format("uvRect=({0:0.##},{1:0.##},{2:0.##},{3:0.##})", array)); } } else { AppendImage(list, val2); } if (list.Count != 0) { return string.Join(" ", list.ToArray()); } return null; } private static void AppendImage(List parts, Image image) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Invalid comparison between Unknown and I4 //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //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_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Invalid comparison between Unknown and I4 //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Invalid comparison between Unknown and I4 //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ad: Invalid comparison between Unknown and I4 //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Invalid comparison between Unknown and I4 //IL_01b6: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) Sprite sprite = image.sprite; parts.Add("sprite=" + Name((Object)(object)sprite)); if ((Object)(object)image.overrideSprite != (Object)null && (Object)(object)image.overrideSprite != (Object)(object)sprite) { parts.Add("overrideSprite=" + Name((Object)(object)image.overrideSprite)); } parts.Add($"type={image.type}"); if ((Object)(object)sprite != (Object)null) { Vector4 border = sprite.border; parts.Add($"border=({border.x:0.#},{border.y:0.#},{border.z:0.#},{border.w:0.#})"); parts.Add($"ppu={sprite.pixelsPerUnit:0.#}"); Rect rect = sprite.rect; object arg = ((Rect)(ref rect)).width; rect = sprite.rect; parts.Add($"spriteRect=({arg:0.#}x{((Rect)(ref rect)).height:0.#})"); if ((Object)(object)sprite.texture != (Object)null) { parts.Add("atlas=" + ((Object)sprite.texture).name); } if (((int)image.type == 1 || (int)image.type == 2) && border == Vector4.zero) { parts.Add("** type wants a border but the sprite has none - draws as Simple **"); } } if ((int)image.type == 1 || (int)image.type == 2) { parts.Add($"fillCenter={image.fillCenter}"); } if ((int)image.type == 3) { parts.Add($"fillMethod={image.fillMethod} fillAmount={image.fillAmount:0.##}"); } if (image.preserveAspect) { parts.Add("preserveAspect=true"); } } private static void AppendLayoutGroup(List parts, LayoutGroup group) { //IL_0069: 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_011c: 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) parts.Add($"padding={group.padding.left},{group.padding.bottom},{group.padding.right},{group.padding.top}"); parts.Add($"childAlignment={group.childAlignment}"); HorizontalOrVerticalLayoutGroup val = (HorizontalOrVerticalLayoutGroup)(object)((group is HorizontalOrVerticalLayoutGroup) ? group : null); if (val != null) { parts.Add($"spacing={val.spacing:0.#}"); parts.Add($"childForceExpand=({val.childForceExpandWidth},{val.childForceExpandHeight})"); parts.Add($"childControlSize=({val.childControlWidth},{val.childControlHeight})"); } else { GridLayoutGroup val2 = (GridLayoutGroup)(object)((group is GridLayoutGroup) ? group : null); if (val2 != null) { parts.Add("cellSize=" + F(val2.cellSize)); parts.Add("spacing=" + F(val2.spacing)); parts.Add($"constraint={val2.constraint}/{val2.constraintCount}"); } } parts.Add("** DRIVES its children's anchoredPosition **"); } private static string Hex(Color c) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: 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_0014: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) Color32 val = Color32.op_Implicit(c); return $"#{val.r:X2}{val.g:X2}{val.b:X2}{val.a:X2}"; } private static string Name(Object o) { if (!(o != (Object)null)) { return "(none)"; } return o.name; } private static string Sample(string s) { if (string.IsNullOrEmpty(s)) { return "\"\""; } s = s.Replace("\n", "\\n").Replace("\r", ""); if (s.Length > 48) { s = s.Substring(0, 48) + "..."; } return "\"" + s + "\""; } private static string F(Vector2 v) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) return $"({v.x:0.##},{v.y:0.##})"; } private static string F(Vector3 v) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) return $"({v.x:0.##},{v.y:0.##},{v.z:0.##})"; } private static string HierarchyPath(Transform t) { List list = new List(); while ((Object)(object)t != (Object)null) { list.Insert(0, ((Object)t).name); t = t.parent; } return string.Join("/", list.ToArray()); } } } namespace BarrkUI.UI { internal static class CompassPins { internal struct Mark { public float Bearing; public float Distance; public Sprite Icon; public string Label; public Color Tint; public bool Player; } private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.CompassPins"); private static readonly List _marks = new List(); private static readonly List _scratch = new List(); private static readonly Comparison ByDistance = (Mark a, Mark b) => a.Distance.CompareTo(b.Distance); private const float RefreshInterval = 0.1f; private static float _nextRefresh; private static FieldInfo _pinsField; private static FieldInfo _visibleField; private static FieldInfo _sharedFadeField; private static bool _resolved; private static bool _broken; private const float CheckedFade = 0.45f; private const float MinDistance = 0.5f; public static IList Marks => _marks; public static void Refresh(Vector3 origin) { //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Invalid comparison between Unknown and I4 //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Expected I4, but got Unknown //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_022b: Unknown result type (might be due to invalid IL or missing references) //IL_0224: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) if (Time.unscaledTime < _nextRefresh) { return; } _nextRefresh = Time.unscaledTime + 0.1f; _marks.Clear(); if (_broken) { return; } bool flag = ConfigManager.hudCompassPins != null && ConfigManager.hudCompassPins.Value; bool flag2 = ConfigManager.hudCompassPlayers != null && ConfigManager.hudCompassPlayers.Value; if (!flag && !flag2) { return; } Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null) { return; } Resolve(); if (_broken || !(_pinsField.GetValue(instance) is List list)) { return; } bool[] array = ((_visibleField != null) ? (_visibleField.GetValue(instance) as bool[]) : null); float num = ((_sharedFadeField != null) ? ((float)_sharedFadeField.GetValue(instance)) : 0f); Color val = default(Color); ((Color)(ref val))..ctor(0.7f, 0.7f, 0.7f, 0.8f * num); float num2 = ((ConfigManager.hudCompassPinRange != null) ? ConfigManager.hudCompassPinRange.Value : 0f); _scratch.Clear(); for (int i = 0; i < list.Count; i++) { PinData val2 = list[i]; if (val2 == null || val2.m_shouldDelete) { continue; } bool flag3 = (int)val2.m_type == 10; if (flag3 ? (!flag2) : (!flag)) { continue; } int num3 = (int)val2.m_type; if (array != null && num3 >= 0 && num3 < array.Length && !array[num3]) { continue; } bool flag4 = val2.m_ownerID != 0; if (flag4 && num <= 0f) { continue; } float num4 = val2.m_pos.x - origin.x; float num5 = val2.m_pos.z - origin.z; float num6 = Mathf.Sqrt(num4 * num4 + num5 * num5); if (!(num6 < 0.5f) && (!(num2 > 0f) || !(num6 > num2))) { float num7 = Mathf.Atan2(num4, num5) * 57.29578f; if (num7 < 0f) { num7 += 360f; } Color tint = (flag4 ? val : Color.white); if (val2.m_checked) { tint.a *= 0.45f; } _scratch.Add(new Mark { Bearing = num7, Distance = num6, Icon = val2.m_icon, Label = LabelFor(val2), Tint = tint, Player = flag3 }); } } _scratch.Sort(ByDistance); for (int num8 = Mathf.Min((ConfigManager.hudCompassPinLimit != null) ? ConfigManager.hudCompassPinLimit.Value : 24, _scratch.Count) - 1; num8 >= 0; num8--) { _marks.Add(_scratch[num8]); } } private static void Resolve() { if (_resolved) { return; } _resolved = true; _pinsField = AccessTools.Field(typeof(Minimap), "m_pins"); _visibleField = AccessTools.Field(typeof(Minimap), "m_visibleIconTypes"); _sharedFadeField = AccessTools.Field(typeof(Minimap), "m_sharedMapDataFade"); if (_pinsField == null) { _broken = true; Log.LogWarning((object)"FEATURE-HEALTH: Minimap.m_pins was not found, so map pins and players cannot be read. The compass still works; the pin marks are off for this session."); return; } if (_visibleField == null) { Log.LogWarning((object)"Minimap.m_visibleIconTypes was not found - the map's pin-type filters will not be mirrored on the compass, so a type hidden on the map still shows here."); } if (_sharedFadeField != null && _sharedFadeField.FieldType != typeof(float)) { _sharedFadeField = null; } } private static string LabelFor(PinData p) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected I4, but got Unknown if (!string.IsNullOrEmpty(p.m_name)) { return p.m_name; } PinType type = p.m_type; return (type - 4) switch { 0 => "Death", 1 => "Home", 5 => "Boss", 3 => "Shout", 8 => "Ping", 7 => "Event", 6 => "Player", _ => "Pin", }; } public static string DistanceText(float metres) { if (metres < 1000f) { return Mathf.RoundToInt(metres) + "m"; } return (metres / 1000f).ToString("0.0") + "km"; } } internal static class HudWidgets { private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.HudWidgets"); private const int ClockId = 1; private const int WeightId = 2; private const int CompassId = 3; public const float MinScale = 0.5f; public const float MaxScale = 3f; private static int _dragging; private static int _resizing; private static Vector2 _dragOffset; private static Vector2 _dragPos; private static float _liveScale = 1f; private static float _resizeStartScale; private static float _resizeStartX; private static float _resizeNaturalWidth; private static TimeZoneInfo _eastern; private static bool _easternLookedUp; private static readonly string[] ClockLabels = new string[3] { "Local", "Server", "Game" }; private static readonly string[] ClockValues = new string[3]; private static readonly string[] CardinalNames = new string[8] { "N", "NE", "E", "SE", "S", "SW", "W", "NW" }; private const float CompassHalfSweep = 90f; private const float LabelWindow = 12f; private static GUIStyle _centred; private static GUIStyle _centredSource; private static GUIStyle _centredKey; private static GUIStyle _centredKeySource; private static GUIStyle _key; private static GUIStyle _keySource; private static GUIStyle _value; private static GUIStyle _valueSource; private static float _keyScale = float.NaN; private static float _valueScale = float.NaN; private static float PinIconScale { get { if (ConfigManager.hudCompassPinSize == null) { return 1f; } return Mathf.Clamp(ConfigManager.hudCompassPinSize.Value, 0.4f, 2f); } } private static bool MarksWanted { get { if (ConfigManager.hudCompassPins == null || !ConfigManager.hudCompassPins.Value) { if (ConfigManager.hudCompassPlayers != null) { return ConfigManager.hudCompassPlayers.Value; } return false; } return true; } } public static void Draw() { try { LayoutSnap.BeginWidgetRects(); if (!SessionState.PlayerReady || (Object)(object)Hud.instance == (Object)null || Hud.IsUserHidden()) { return; } bool flag = ConfigManager.hudClock != null && ConfigManager.hudClock.Value; bool flag2 = ConfigManager.hudWeight != null && ConfigManager.hudWeight.Value; bool flag3 = ConfigManager.hudCompass != null && ConfigManager.hudCompass.Value; if (flag || flag2 || flag3) { ConfigManager.ApplyTheme(); if (flag) { DrawClock(); } if (flag2) { DrawWeight(); } if (flag3) { DrawCompass(); } if (_dragging != 0) { LayoutSnap.DrawGuides(); } } } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed (non-fatal, HUD widgets hidden this frame). Reason: {1}", "Draw", arg)); } } private static void DrawClock() { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) float num = ScaleOf(1, ConfigManager.hudClockScale); GUIStyle val = KeyStyle(num); GUIStyle val2 = ValueStyle(num); ClockValues[0] = DateTime.Now.ToShortTimeString(); ClockValues[1] = EasternNow().ToString("HH:mm") + " EST"; ClockValues[2] = GameTimeText(); float num2 = Px(8f, num); float num3 = Px(10f, num); float num4 = 0f; float num5 = 0f; float num6 = 0f; for (int i = 0; i < 3; i++) { Vector2 val3 = val.CalcSize(new GUIContent(ClockLabels[i])); Vector2 val4 = val2.CalcSize(new GUIContent(ClockValues[i])); num4 = Mathf.Max(num4, val3.x); num5 = Mathf.Max(num5, val4.x); num6 = Mathf.Max(num6, Mathf.Max(val3.y, val4.y)); } num6 += Px(3f, num); float num7 = num2 * 2f + num4 + num3 + num5; float h = num2 * 2f + num6 * 3f; Rect r = WidgetRect(ConfigManager.hudClockX, ConfigManager.hudClockY, num7, h); HandleInput(1, ref r, ConfigManager.hudClockX, ConfigManager.hudClockY, ConfigManager.hudClockScale, num7 / Mathf.Max(0.01f, num)); DrawShell(r, num); float num8 = ((Rect)(ref r)).x + num2; float num9 = ((Rect)(ref r)).y + num2; for (int j = 0; j < 3; j++) { GUI.Label(new Rect(num8, num9, num4, num6), ClockLabels[j], val); GUI.Label(new Rect(num8 + num4 + num3, num9, num5, num6), ClockValues[j], val2); num9 += num6; } } private static string GameTimeText() { if ((Object)(object)EnvMan.instance == (Object)null) { return "-"; } int num = Mathf.FloorToInt(Mathf.Clamp01(EnvMan.instance.GetDayFraction()) * 24f * 60f); return $"Day {EnvMan.instance.GetDay()} · {num / 60:00}:{num % 60:00}"; } private static DateTime EasternNow() { if (!_easternLookedUp) { _easternLookedUp = true; try { _eastern = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"); } catch { try { _eastern = TimeZoneInfo.FindSystemTimeZoneById("America/New_York"); } catch { _eastern = null; } } } if (_eastern == null) { return DateTime.UtcNow.AddHours(-5.0); } return TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, _eastern); } private static void DrawWeight() { //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Expected O, but got Unknown //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: 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_00db: 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_0114: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { float num = ScaleOf(2, ConfigManager.hudWeightScale); GUIStyle val = KeyStyle(num); GUIStyle val2 = ValueStyle(num); int num2 = Mathf.CeilToInt(((Humanoid)localPlayer).GetInventory().GetTotalWeight()); int num3 = Mathf.CeilToInt(localPlayer.GetMaxCarryWeight()); bool flag = num2 > num3; string text = $"{num2}/{num3}"; float num4 = Px(8f, num); float num5 = Px(10f, num); float num6 = Px(7f, num); Vector2 val3 = val.CalcSize(new GUIContent("Weight")); Vector2 val4 = val2.CalcSize(new GUIContent(text)); float num7 = Mathf.Max(val3.y, val4.y); float num8 = num4 * 2f + val3.x + num5 + val4.x; float h = num4 * 2f + num7 + num6 + Px(3f, num); Rect r = WidgetRect(ConfigManager.hudWeightX, ConfigManager.hudWeightY, num8, h); HandleInput(2, ref r, ConfigManager.hudWeightX, ConfigManager.hudWeightY, ConfigManager.hudWeightScale, num8 / Mathf.Max(0.01f, num)); DrawShell(r, num); float num9 = ((Rect)(ref r)).x + num4; float num10 = ((Rect)(ref r)).y + num4; float num11 = ((Rect)(ref r)).width - num4 * 2f; GUI.Label(new Rect(num9, num10, val3.x, num7), "Weight", val); string text2 = ((flag && Mathf.Sin(Time.time * 10f) > 0f) ? $"{num2}/{num3}" : text); GUI.Label(new Rect(num9 + val3.x + num5, num10, ((Rect)(ref r)).width - num4 - (num9 + val3.x + num5 - ((Rect)(ref r)).x), num7), text2, val2); num10 += num7 + Px(3f, num); Rect r2 = default(Rect); ((Rect)(ref r2))..ctor(num9, num10, num11, num6); GiltFrameTheme.DrawInset(r2); float num12 = ((num3 > 0) ? Mathf.Clamp01((float)num2 / (float)num3) : 0f); if (num12 > 0f) { Color c = (Color)(flag ? new Color(0.85f, 0.25f, 0.2f, 0.95f) : GiltFrameTheme.Gold); GiltFrameTheme.DrawFill(new Rect(((Rect)(ref r2)).x + 1f, ((Rect)(ref r2)).y + 1f, (((Rect)(ref r2)).width - 2f) * num12, ((Rect)(ref r2)).height - 2f), c); } } } private static void DrawCompass() { //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Expected O, but got Unknown //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Expected O, but got Unknown //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_023d: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_027a: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Unknown result type (might be due to invalid IL or missing references) //IL_02b3: Unknown result type (might be due to invalid IL or missing references) //IL_0233: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) float num = ScaleOf(3, ConfigManager.hudCompassScale); GUIStyle val = KeyStyle(num); GUIStyle obj = ValueStyle(num); float num2 = CurrentHeading(); string text = $"{Mathf.RoundToInt(num2) % 360:000}° {NearestCardinal(num2)}"; bool marksWanted = MarksWanted; bool flag = marksWanted && ConfigManager.hudCompassPinLabel != null && ConfigManager.hudCompassPinLabel.Value; float num3 = Px(8f, num); float num4 = Px(230f, num); float num5 = (marksWanted ? Px(18f * PinIconScale, num) : 0f); float num6 = Px(22f, num) + num5; Vector2 val2 = obj.CalcSize(new GUIContent(text)); float y = val2.y; float num7 = (flag ? val.CalcSize(new GUIContent("Ag")).y : 0f); float num8 = (flag ? Px(3f, num) : 0f); float num9 = num3 * 2f + Mathf.Max(num4, val2.x); Rect r = WidgetRect(h: num3 * 2f + y + Px(4f, num) + num6 + num8 + num7, cx: ConfigManager.hudCompassX, cy: ConfigManager.hudCompassY, w: num9); HandleInput(3, ref r, ConfigManager.hudCompassX, ConfigManager.hudCompassY, ConfigManager.hudCompassScale, num9 / Mathf.Max(0.01f, num)); DrawShell(r, num); Rect val3 = default(Rect); ((Rect)(ref val3))..ctor(((Rect)(ref r)).x + num3, ((Rect)(ref r)).y + num3, ((Rect)(ref r)).width - num3 * 2f, y); GUIStyle val4 = CentredValue(obj); GUI.Label(val3, text, val4); Rect val5 = default(Rect); ((Rect)(ref val5))..ctor(((Rect)(ref r)).x + num3, ((Rect)(ref val3)).yMax + Px(4f, num), ((Rect)(ref r)).width - num3 * 2f, num6); GiltFrameTheme.DrawInset(val5); if (marksWanted) { CompassPins.Refresh(((Object)(object)Player.m_localPlayer != (Object)null) ? ((Component)Player.m_localPlayer).transform.position : (((Object)(object)GameCamera.instance != (Object)null) ? ((Component)GameCamera.instance).transform.position : Vector3.zero)); } DrawCompassTape(val5, num2, num, val, num5); GiltFrameTheme.DrawFill(new Rect(((Rect)(ref val5)).center.x - 1f, ((Rect)(ref val5)).y + 1f, 2f, ((Rect)(ref val5)).height - 2f), GiltFrameTheme.GoldBright); if (flag) { DrawCentreLabel(new Rect(((Rect)(ref r)).x + num3, ((Rect)(ref val5)).yMax + num8, ((Rect)(ref r)).width - num3 * 2f, num7), num2, val); } } private static void DrawCentreLabel(Rect where, float heading, GUIStyle key) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) IList marks = CompassPins.Marks; int num = -1; float num2 = 12f; for (int i = 0; i < marks.Count; i++) { float num3 = Mathf.Abs(Mathf.DeltaAngle(heading, marks[i].Bearing)); if (num3 <= num2) { num2 = num3; num = i; } } if (num >= 0) { CompassPins.Mark mark = marks[num]; GUI.Label(where, mark.Label + " " + CompassPins.DistanceText(mark.Distance), CentredKey(key)); } } private static void DrawCompassTape(Rect tape, float heading, float scale, GUIStyle key, float pinBand) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: 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_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: 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_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) GUI.BeginGroup(tape); try { float num = ((Rect)(ref tape)).width / 180f; float num2 = ((Rect)(ref tape)).width * 0.5f; float num3 = ((Rect)(ref tape)).height - pinBand; int num4 = Mathf.CeilToInt((heading - 90f) / 15f); int num5 = Mathf.FloorToInt((heading + 90f) / 15f); for (int i = num4; i <= num5; i++) { float num6 = (float)i * 15f; float num7 = num2 + (num6 - heading) * num; if ((i % 3 + 3) % 3 == 0) { int num8 = (i / 3 % 8 + 8) % 8; string text = CardinalNames[num8]; Vector2 val = key.CalcSize(new GUIContent(text)); Rect val2 = new Rect(num7 - val.x * 0.5f, pinBand + (num3 - val.y) * 0.5f, val.x, val.y); Color textColor = key.normal.textColor; key.normal.textColor = ((num8 == 0) ? GiltFrameTheme.GoldBright : GiltFrameTheme.Parchment); GUI.Label(val2, text, key); key.normal.textColor = textColor; } else { float num9 = Mathf.Max(2f, num3 * 0.28f); GiltFrameTheme.DrawFill(new Rect(num7 - 0.5f, ((Rect)(ref tape)).height - num9 - 2f, 1f, num9), new Color(GiltFrameTheme.Gold.r, GiltFrameTheme.Gold.g, GiltFrameTheme.Gold.b, 0.55f)); } } if (pinBand > 0f) { DrawPinMarks(heading, num, num2, pinBand); } } finally { GUI.EndGroup(); } } private static void DrawPinMarks(float heading, float pxPerDegree, float half, float pinBand) { //IL_0148: 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_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0092: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00da: 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_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: 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_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) IList marks = CompassPins.Marks; if (marks.Count == 0) { return; } float num = Mathf.Max(6f, pinBand - 2f); Color color = GUI.color; try { Rect r = default(Rect); for (int i = 0; i < marks.Count; i++) { CompassPins.Mark mark = marks[i]; float num2 = Mathf.DeltaAngle(heading, mark.Bearing); if (!(Mathf.Abs(num2) > 95f)) { float num3 = half + num2 * pxPerDegree; ((Rect)(ref r))..ctor(num3 - num * 0.5f, (pinBand - num) * 0.5f + 1f, num, num); if ((Object)(object)mark.Icon != (Object)null) { GUI.color = mark.Tint; DrawSprite(r, mark.Icon); } else { Color val = (Color)(mark.Player ? new Color(0.85f, 0.25f, 0.2f, 0.95f) : GiltFrameTheme.Gold); GiltFrameTheme.DrawDot(r, new Color(val.r * mark.Tint.r, val.g * mark.Tint.g, val.b * mark.Tint.b, val.a * mark.Tint.a)); } } } } finally { GUI.color = color; } } private static void DrawSprite(Rect r, Sprite sprite) { //IL_0012: 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_0018: 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) Texture2D texture = sprite.texture; if (!((Object)(object)texture == (Object)null)) { Rect textureRect = sprite.textureRect; GUI.DrawTextureWithTexCoords(r, (Texture)(object)texture, new Rect(((Rect)(ref textureRect)).x / (float)((Texture)texture).width, ((Rect)(ref textureRect)).y / (float)((Texture)texture).height, ((Rect)(ref textureRect)).width / (float)((Texture)texture).width, ((Rect)(ref textureRect)).height / (float)((Texture)texture).height)); } } private static float CurrentHeading() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) Transform val = (((Object)(object)GameCamera.instance != (Object)null) ? ((Component)GameCamera.instance).transform : (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Component)Player.m_localPlayer).transform : null)); if ((Object)(object)val == (Object)null) { return 0f; } Vector3 forward = val.forward; float num = Mathf.Atan2(forward.x, forward.z) * 57.29578f; if (!(num < 0f)) { return num; } return num + 360f; } private static string NearestCardinal(float heading) { int num = Mathf.RoundToInt(heading / 45f) % 8; return CardinalNames[(num + 8) % 8]; } private static GUIStyle CentredValue(GUIStyle source) { //IL_001c: 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_002d: Expected O, but got Unknown if (_centred != null && _centredSource == source) { return _centred; } _centredSource = source; _centred = new GUIStyle(source) { alignment = (TextAnchor)4 }; return _centred; } private static GUIStyle CentredKey(GUIStyle source) { //IL_001c: 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_0028: 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_003b: Expected O, but got Unknown if (_centredKey != null && _centredKeySource == source) { return _centredKey; } _centredKeySource = source; _centredKey = new GUIStyle(source) { alignment = (TextAnchor)4, richText = false, clipping = (TextClipping)1 }; return _centredKey; } private static GUIStyle KeyStyle(float scale) { if (_key != null && _keySource == GiltFrameTheme.Key && Mathf.Approximately(_keyScale, scale)) { return _key; } _keySource = GiltFrameTheme.Key; _keyScale = scale; _key = Scaled(GiltFrameTheme.Key, scale); return _key; } private static GUIStyle ValueStyle(float scale) { if (_value != null && _valueSource == GiltFrameTheme.Value && Mathf.Approximately(_valueScale, scale)) { return _value; } _valueSource = GiltFrameTheme.Value; _valueScale = scale; _value = Scaled(GiltFrameTheme.Value, scale); return _value; } private static GUIStyle Scaled(GUIStyle source, float scale) { //IL_0001: 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_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Expected O, but got Unknown return new GUIStyle(source) { fontSize = Mathf.Max(8, Mathf.RoundToInt((float)source.fontSize * scale)), wordWrap = false, clipping = (TextClipping)0 }; } private static float Px(float v, float scale) { return Mathf.Round(GiltFrameTheme.S(v) * scale); } private static void DrawShell(Rect r, float scale) { //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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: 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_0063: Unknown result type (might be due to invalid IL or missing references) LayoutSnap.RegisterWidgetRect(r); GiltFrameTheme.DrawPanelFill(r); GiltFrameTheme.DrawOutline(r, new Color(GiltFrameTheme.Gold.r, GiltFrameTheme.Gold.g, GiltFrameTheme.Gold.b, 0.55f), 1f); if (Cursor.visible) { Rect r2 = GripRect(r, scale); GiltFrameTheme.DrawFill(r2, GiltFrameTheme.Metal(0.45f)); GiltFrameTheme.DrawOutline(r2, GiltFrameTheme.MetalDeep(0.9f), 1f); } } private static Rect GripRect(Rect r, float scale) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Max(10f, Px(11f, scale)); return new Rect(((Rect)(ref r)).xMax - num - 2f, ((Rect)(ref r)).yMax - num - 2f, num, num); } private static float ScaleOf(int id, ConfigEntry entry) { if (_resizing == id) { return _liveScale; } if (entry != null) { return Mathf.Clamp(entry.Value, 0.5f, 3f); } return 1f; } private static Rect WidgetRect(ConfigEntry cx, ConfigEntry cy, float w, float h) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp01(cx.Value) * (float)Screen.width; float num2 = Mathf.Clamp01(cy.Value) * (float)Screen.height; float num3 = Mathf.Clamp(num, 0f, Mathf.Max(0f, (float)Screen.width - w)); num2 = Mathf.Clamp(num2, 0f, Mathf.Max(0f, (float)Screen.height - h)); return new Rect(num3, num2, w, h); } private static void HandleInput(int id, ref Rect r, ConfigEntry cx, ConfigEntry cy, ConfigEntry scaleEntry, float naturalWidth) { //IL_0033: 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_0039: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected I4, but got Unknown //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_019b: 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) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: 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) Event current = Event.current; if (current == null) { return; } if (_dragging == id) { ((Rect)(ref r)).x = _dragPos.x; ((Rect)(ref r)).y = _dragPos.y; } EventType type = current.type; switch ((int)type) { case 0: if (current.button != 0 || _dragging != 0 || _resizing != 0 || !Cursor.visible || !((Rect)(ref r)).Contains(current.mousePosition)) { break; } if (scaleEntry != null) { Rect val = GripRect(r, ScaleOf(id, scaleEntry)); if (((Rect)(ref val)).Contains(current.mousePosition)) { _resizing = id; _liveScale = Mathf.Clamp(scaleEntry.Value, 0.5f, 3f); _resizeStartScale = _liveScale; _resizeStartX = current.mousePosition.x; _resizeNaturalWidth = Mathf.Max(1f, naturalWidth); goto IL_014d; } } _dragging = id; _dragOffset = current.mousePosition - new Vector2(((Rect)(ref r)).x, ((Rect)(ref r)).y); _dragPos = new Vector2(((Rect)(ref r)).x, ((Rect)(ref r)).y); LayoutSnap.Build(null, r); goto IL_014d; case 3: if (_dragging == id) { Vector2 val2 = current.mousePosition - _dragOffset; LayoutSnap.Clear(); if (LayoutSnap.Wanted(current)) { val2 += LayoutSnap.ForBox(new Rect(val2.x, val2.y, ((Rect)(ref r)).width, ((Rect)(ref r)).height)); } _dragPos.x = Mathf.Clamp(val2.x, 0f, Mathf.Max(0f, (float)Screen.width - ((Rect)(ref r)).width)); _dragPos.y = Mathf.Clamp(val2.y, 0f, Mathf.Max(0f, (float)Screen.height - ((Rect)(ref r)).height)); ((Rect)(ref r)).x = _dragPos.x; ((Rect)(ref r)).y = _dragPos.y; current.Use(); } else if (_resizing == id) { _liveScale = Mathf.Clamp(_resizeStartScale + (current.mousePosition.x - _resizeStartX) / _resizeNaturalWidth, 0.5f, 3f); current.Use(); } break; case 1: if (_dragging == id) { _dragging = 0; LayoutSnap.Clear(); cx.Value = Mathf.Clamp01(_dragPos.x / (float)Screen.width); cy.Value = Mathf.Clamp01(_dragPos.y / (float)Screen.height); current.Use(); } else if (_resizing == id) { _resizing = 0; if (scaleEntry != null) { scaleEntry.Value = _liveScale; } current.Use(); } break; case 2: break; IL_014d: current.Use(); break; } } } internal static class PanelFrame { private struct Cluster { public Rect Bounds; public float Filled; } private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.PanelFrame"); private const float MinFrameSide = 170f; private const float MinCoverage = 0.72f; private const float RescanSeconds = 0.25f; private static readonly List _backgrounds = new List(); private static float _nextRescan; private static readonly List _clusters = new List(); private static readonly List _frames = new List(); private static int _builtOnFrame = -1; private static Rect _playerFrame; private static bool _playerFrameKnown; private static int _tracedFrameCount = -1; private static RectTransform _scannedOverlay; private static readonly Vector3[] _corners = (Vector3[])(object)new Vector3[4]; private static float Pad => 18f; private static float Reach => Pad + 9f; public static IReadOnlyList Frames { get { Rebuild(); return _frames; } } public static bool TryGetPlayerFrame(out Rect frame) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) Rebuild(); frame = _playerFrame; return _playerFrameKnown; } public static void ResetSession() { _backgrounds.Clear(); _nextRescan = 0f; _builtOnFrame = -1; _tracedFrameCount = -1; _scannedOverlay = null; } public static void Draw() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) try { if (!SessionState.IsLive || (ConfigManager.goldTheme != null && !ConfigManager.goldTheme.Value) || (ConfigManager.giltFrames != null && !ConfigManager.giltFrames.Value)) { return; } Rebuild(); if (_frames.Count != 0) { ConfigManager.ApplyTheme(); for (int i = 0; i < _frames.Count; i++) { GiltFrameTheme.DrawFrame(_frames[i]); } } } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed (non-fatal, inventory frame hidden this frame). Reason: {1}", "Draw", arg)); } } private static void Rebuild() { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_01d7: Unknown result type (might be due to invalid IL or missing references) //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Unknown result type (might be due to invalid IL or missing references) if (_builtOnFrame == Time.frameCount) { return; } _builtOnFrame = Time.frameCount; _clusters.Clear(); _frames.Clear(); _playerFrameKnown = false; InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance == (Object)null || !InventoryGui.IsVisible()) { _backgrounds.Clear(); _nextRescan = 0f; _tracedFrameCount = -1; _scannedOverlay = null; return; } RescanIfDue(instance); bool flag = (Object)(object)PanelTheme.ActiveOverlay(instance) != (Object)null; Rect gui = default(Rect); bool flag2 = !flag && TryGuiRect(instance.m_player, out gui); for (int i = 0; i < _backgrounds.Count; i++) { if (TryGuiRect(_backgrounds[i], out var gui2) && !(((Rect)(ref gui2)).width < 170f) && !(((Rect)(ref gui2)).height < 170f)) { AddCluster(gui2); } } if (_clusters.Count == 0 && !flag) { if (TryGuiRect(instance.m_player, out var gui3)) { AddCluster(gui3); } if (TryGuiRect(instance.m_container, out var gui4)) { AddCluster(gui4); } if (TryGuiRect(instance.m_info, out var gui5)) { AddCluster(gui5); } if (TryGuiRect(instance.m_crafting, out var gui6)) { AddCluster(gui6); } } MergeClusters(); Rect val = default(Rect); for (int j = 0; j < _clusters.Count; j++) { Rect bounds = _clusters[j].Bounds; ((Rect)(ref val))..ctor(((Rect)(ref bounds)).x - Pad, ((Rect)(ref bounds)).y - Pad, ((Rect)(ref bounds)).width + Pad * 2f, ((Rect)(ref bounds)).height + Pad * 2f); if (!(((Rect)(ref val)).width < 170f) && !(((Rect)(ref val)).height < 170f)) { _frames.Add(val); if (flag2 && !_playerFrameKnown && ((Rect)(ref bounds)).Overlaps(gui)) { _playerFrame = val; _playerFrameKnown = true; } } } if (!_playerFrameKnown && _frames.Count > 0) { _playerFrame = _frames[0]; for (int k = 1; k < _frames.Count; k++) { Rect val2 = _frames[k]; if (((Rect)(ref val2)).x < ((Rect)(ref _playerFrame)).x) { _playerFrame = _frames[k]; } } _playerFrameKnown = true; } TraceIfChanged(); } private static void AddCluster(Rect r) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) _clusters.Add(new Cluster { Bounds = r, Filled = ((Rect)(ref r)).width * ((Rect)(ref r)).height }); } private static void RescanIfDue(InventoryGui gui) { RectTransform val = PanelTheme.ActiveOverlay(gui); bool flag = (Object)(object)_scannedOverlay != (Object)(object)val || _backgrounds.Count == 0 || Time.unscaledTime >= _nextRescan; if (!flag) { for (int i = 0; i < _backgrounds.Count; i++) { if ((Object)(object)_backgrounds[i] == (Object)null) { flag = true; break; } } } if (flag) { _nextRescan = Time.unscaledTime + 0.25f; _scannedOverlay = val; PanelTheme.CollectBackgrounds(gui, _backgrounds); } } private static bool TryGuiRect(RectTransform rt, out Rect gui) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) gui = default(Rect); if ((Object)(object)rt == (Object)null || !((Component)rt).gameObject.activeInHierarchy) { return false; } rt.GetWorldCorners(_corners); gui = new Rect(_corners[0].x, (float)Screen.height - _corners[2].y, _corners[2].x - _corners[0].x, _corners[2].y - _corners[0].y); if (((Rect)(ref gui)).width <= 1f || ((Rect)(ref gui)).height <= 1f) { return false; } if (!(((Rect)(ref gui)).width < (float)Screen.width * 0.95f)) { return ((Rect)(ref gui)).height < (float)Screen.height * 0.95f; } return true; } private static void MergeClusters() { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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_007a: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) while (true) { int num = -1; int index = -1; float num2 = -1f; Cluster value = default(Cluster); for (int i = 0; i < _clusters.Count; i++) { for (int j = i + 1; j < _clusters.Count; j++) { Rect bounds = _clusters[i].Bounds; Rect bounds2 = _clusters[j].Bounds; Rect val = Inflate(bounds, Reach); if (!((Rect)(ref val)).Overlaps(Inflate(bounds2, Reach))) { continue; } Rect bounds3 = Union(bounds, bounds2); float num3 = Mathf.Max(1f, ((Rect)(ref bounds3)).width * ((Rect)(ref bounds3)).height); float num4 = Mathf.Min(_clusters[i].Filled + _clusters[j].Filled, num3); bool flag = ((Rect)(ref bounds)).Overlaps(bounds2); float num5 = num4 / num3; if (flag || !(num5 < 0.72f)) { float num6 = (flag ? 2f : num5); if (!(num6 <= num2)) { num = i; index = j; num2 = num6; value = new Cluster { Bounds = bounds3, Filled = num4 }; } } } } if (num < 0) { break; } _clusters[num] = value; _clusters.RemoveAt(index); } } private static Rect Inflate(Rect r, float by) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) return new Rect(((Rect)(ref r)).x - by, ((Rect)(ref r)).y - by, ((Rect)(ref r)).width + by * 2f, ((Rect)(ref r)).height + by * 2f); } private static Rect Union(Rect a, Rect b) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Min(((Rect)(ref a)).xMin, ((Rect)(ref b)).xMin); float num2 = Mathf.Min(((Rect)(ref a)).yMin, ((Rect)(ref b)).yMin); float num3 = Mathf.Max(((Rect)(ref a)).xMax, ((Rect)(ref b)).xMax); float num4 = Mathf.Max(((Rect)(ref a)).yMax, ((Rect)(ref b)).yMax); return new Rect(num, num2, num3 - num, num4 - num2); } private static void TraceIfChanged() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) int num = (_frames.Count * 397) ^ _backgrounds.Count; for (int i = 0; i < _frames.Count; i++) { Rect val = _frames[i]; num = (num * 31) ^ (Mathf.RoundToInt(((Rect)(ref val)).x) * 7) ^ (Mathf.RoundToInt(((Rect)(ref val)).y) * 13) ^ (Mathf.RoundToInt(((Rect)(ref val)).width) * 17) ^ (Mathf.RoundToInt(((Rect)(ref val)).height) * 23); } if (num == _tracedFrameCount) { return; } _tracedFrameCount = num; InventoryGui gui = InventoryGui.instance; Diagnostics.Trace(delegate { //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_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append($"panel frame: {_backgrounds.Count} background(s) -> {_clusters.Count} cluster(s) -> {_frames.Count} frame(s)"); stringBuilder.Append(PanelTheme.DescribeBackgrounds(gui)); for (int j = 0; j < _frames.Count; j++) { Rect val2 = _frames[j]; stringBuilder.Append($"\n frame {j}: x{((Rect)(ref val2)).x:0} y{((Rect)(ref val2)).y:0} w{((Rect)(ref val2)).width:0} h{((Rect)(ref val2)).height:0}"); } for (int k = 0; k < _clusters.Count; k++) { Rect bounds = _clusters[k].Bounds; float num2 = Mathf.Max(1f, ((Rect)(ref bounds)).width * ((Rect)(ref bounds)).height); stringBuilder.Append($"\n cluster {k}: x{((Rect)(ref bounds)).x:0} y{((Rect)(ref bounds)).y:0} w{((Rect)(ref bounds)).width:0} h{((Rect)(ref bounds)).height:0} coverage {_clusters[k].Filled / num2:0.00}"); } return stringBuilder.ToString(); }); } } [HarmonyPatch] internal static class PanelTheme { private sealed class Original { public Sprite Sprite; public Material Material; public Color Color; public Type Type; } private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.PanelTheme"); private static readonly Dictionary _swapped = new Dictionary(); private static Original _vanillaPanel; private static Original _vanillaBadge; private static Sprite _panelSprite; private static Texture2D _panelTexture; private static Sprite _badgeSprite; private static Texture2D _badgeTexture; private static Color _builtFor; private static Color _badgeBuiltFor; private static Color _panelFillBuiltFor; private static Color _badgeFillBuiltFor; private static bool Wanted { get { if (ConfigManager.goldTheme == null || ConfigManager.goldTheme.Value) { if (ConfigManager.themePanels != null) { return ConfigManager.themePanels.Value; } return true; } return false; } } [HarmonyPatch(typeof(InventoryGui), "Awake")] [HarmonyPostfix] private static void InventoryGui_Awake_Postfix(InventoryGui __instance) { try { _swapped.Clear(); if (Wanted) { Apply(__instance); } } catch (Exception ex) { Diagnostics.Health("Panel theme", ok: false, "could not theme the inventory panels. Reason: " + ex.Message); Log.LogError((object)ex.ToString()); } } public static void OnToggled() { try { if (Wanted) { InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance != (Object)null) { Apply(instance); } } else { Restore(); } } catch (Exception arg) { Log.LogError((object)$"toggling the panel theme failed (non-fatal). Reason: {arg}"); } } public static void OnColourChanged() { try { if (Wanted) { InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance != (Object)null) { Apply(instance); return; } PanelSprite(); BadgeSprite(); } } catch (Exception arg) { Log.LogError((object)$"re-colouring the panel theme failed (non-fatal). Reason: {arg}"); } } private static void Apply(InventoryGui gui) { //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: 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_0106: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) int num = 0; int num2 = 0; PanelSprite(); BadgeSprite(); foreach (RectTransform item in Roots(gui)) { if ((Object)(object)item == (Object)null) { continue; } Image[] componentsInChildren = ((Component)item).GetComponentsInChildren(true); Original original = null; float num3 = 0f; Image[] array = componentsInChildren; foreach (Image val in array) { if ((Object)(object)val == (Object)null) { continue; } bool flag = _swapped.ContainsKey(val); bool flag2 = (Object)(object)val.sprite != (Object)null && ((Object)val.sprite).name.StartsWith("woodpanel", StringComparison.Ordinal) && !((Object)val.sprite).name.EndsWith("_mask", StringComparison.Ordinal); if (flag || flag2) { if (!flag) { _swapped[val] = new Original { Sprite = val.sprite, Material = ((Graphic)val).material, Color = ((Graphic)val).color, Type = val.type }; } RememberVanilla(val, _swapped[val]); float num4 = Area(val); if (num4 > num3) { num3 = num4; original = _swapped[val]; } Swap(val); num++; } } array = componentsInChildren; foreach (Image val2 in array) { if (IsOurSprite(val2) && !_swapped.ContainsKey(val2)) { Original original2 = original ?? VanillaFor(val2); if (original2 != null) { _swapped[val2] = new Original { Sprite = original2.Sprite, Material = original2.Material, Color = original2.Color, Type = original2.Type }; Swap(val2); num2++; } } } } Diagnostics.Health("Panel theme", ok: true, (num2 == 0) ? $"{num} panel background(s) re-skinned black and gold" : $"{num} panel background(s) re-skinned black and gold, {num2} adopted from another mod"); } private static void Swap(Image image) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) Rect rect = ((Graphic)image).rectTransform.rect; bool flag = Mathf.Min(((Rect)(ref rect)).width, ((Rect)(ref rect)).height) < 120f; image.sprite = (flag ? BadgeSprite() : PanelSprite()); ((Graphic)image).material = null; ((Graphic)image).color = Color.white; image.type = (Type)1; } private static void RememberVanilla(Image image, Original original) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)image == (Object)null || (Object)(object)original?.Sprite == (Object)null) { return; } Rect rect = ((Graphic)image).rectTransform.rect; if (Mathf.Min(((Rect)(ref rect)).width, ((Rect)(ref rect)).height) < 120f) { if (_vanillaBadge == null) { _vanillaBadge = original; } } else if (_vanillaPanel == null) { _vanillaPanel = original; } } private static Original VanillaFor(Image image) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)image == (Object)null) { return _vanillaPanel; } Rect rect = ((Graphic)image).rectTransform.rect; return ((Mathf.Min(((Rect)(ref rect)).width, ((Rect)(ref rect)).height) < 120f) ? _vanillaBadge : _vanillaPanel) ?? _vanillaPanel ?? _vanillaBadge; } private static void PutBack(Image image, Original original) { //IL_001a: 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) image.sprite = original.Sprite; ((Graphic)image).material = original.Material; ((Graphic)image).color = original.Color; image.type = original.Type; } private static void Restore() { foreach (KeyValuePair item in _swapped) { if (!((Object)(object)item.Key == (Object)null)) { PutBack(item.Key, item.Value); } } _swapped.Clear(); int num = SweepStrays(); Diagnostics.Health("Panel theme", ok: true, (num == 0) ? "restored - no panel is still wearing a VikingOS sprite" : $"restored, and {num} stray copy/copies of our sprite were swept back to vanilla"); } private static int SweepStrays() { InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance == (Object)null) { return 0; } int num = 0; foreach (RectTransform item in Roots(instance)) { if ((Object)(object)item == (Object)null) { continue; } Image[] componentsInChildren = ((Component)item).GetComponentsInChildren(true); foreach (Image val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && IsOurSprite(val)) { Original original = VanillaFor(val); if (original == null) { Diagnostics.Health("Panel theme", ok: false, "\"" + ((Object)val).name + "\" is still wearing a VikingOS sprite and no vanilla original was ever recorded for it this session, so it cannot be put back. Reload the world to clear it."); continue; } PutBack(val, original); num++; } } } return num; } private static IEnumerable Roots(InventoryGui gui) { yield return gui.m_player; yield return gui.m_crafting; yield return gui.m_info; yield return gui.m_container; foreach (RectTransform item in Overlays(gui)) { yield return item; } } private static IEnumerable Overlays(InventoryGui gui) { yield return AsRect((Component)(object)gui.m_textsDialog); yield return AsRect((Component)(object)gui.m_skillsDialog); yield return AsRect((Component)(object)gui.m_variantDialog); yield return (RectTransform)(((Object)(object)gui.m_trophiesPanel != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); } private static RectTransform AsRect(Component component) { if (!((Object)(object)component != (Object)null)) { return null; } Transform transform = component.transform; return (RectTransform)(object)((transform is RectTransform) ? transform : null); } private static IEnumerable PanelRoots(InventoryGui gui) { yield return gui.m_player; yield return gui.m_crafting; yield return gui.m_info; yield return gui.m_container; } public static RectTransform ActiveOverlay(InventoryGui gui) { if ((Object)(object)gui == (Object)null) { return null; } foreach (RectTransform item in Overlays(gui)) { if ((Object)(object)item != (Object)null && ((Component)item).gameObject.activeInHierarchy) { return item; } } return null; } public static void CollectBackgrounds(InventoryGui gui, List into) { into.Clear(); if ((Object)(object)gui == (Object)null) { return; } RectTransform val = ActiveOverlay(gui); if ((Object)(object)val != (Object)null) { Collect(val, into); return; } foreach (RectTransform item in PanelRoots(gui)) { Collect(item, into); } } private static void Collect(RectTransform root, List into) { if ((Object)(object)root == (Object)null || !((Component)root).gameObject.activeInHierarchy) { return; } Image[] componentsInChildren = ((Component)root).GetComponentsInChildren(false); foreach (Image val in componentsInChildren) { if (IsPanelBackground(val)) { into.Add(((Graphic)val).rectTransform); } } } public static string DescribeBackgrounds(InventoryGui gui) { //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)gui == (Object)null) { return "no InventoryGui"; } StringBuilder stringBuilder = new StringBuilder(); foreach (RectTransform item in Roots(gui)) { if ((Object)(object)item == (Object)null) { stringBuilder.Append("\n "); continue; } if (!((Component)item).gameObject.activeInHierarchy) { stringBuilder.Append("\n " + ((Object)item).name + ": INACTIVE root - contributes nothing"); continue; } int num = 0; List list = new List(); Image[] componentsInChildren = ((Component)item).GetComponentsInChildren(false); foreach (Image val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { if (IsPanelBackground(val)) { num++; } list.Add(val); } } stringBuilder.Append($"\n {((Object)item).name}: {num} accepted, {list.Count} active Image(s)"); list.Sort((Image a, Image b) => Area(b).CompareTo(Area(a))); for (int num2 = 0; num2 < list.Count && num2 < 4; num2++) { Image val2 = list[num2]; Rect rect = ((Graphic)val2).rectTransform.rect; stringBuilder.Append("\n " + (IsPanelBackground(val2) ? "USED" : "skip") + " " + ((Object)val2).name + " sprite=" + (((Object)(object)val2.sprite == (Object)null) ? "" : ((Object)val2.sprite).name) + " " + $"{((Rect)(ref rect)).width:0}x{((Rect)(ref rect)).height:0} enabled={((Behaviour)val2).enabled} alpha={((Graphic)val2).color.a:0.00}"); } } return stringBuilder.ToString(); } private static float Area(Image image) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)image == (Object)null) { return 0f; } Rect rect = ((Graphic)image).rectTransform.rect; return Mathf.Abs(((Rect)(ref rect)).width * ((Rect)(ref rect)).height); } public static bool IsPanelBackground(Image image) { if ((Object)(object)image == (Object)null || !((Behaviour)image).enabled || (Object)(object)image.sprite == (Object)null) { return false; } if (_swapped.ContainsKey(image)) { return true; } if (IsOurSprite(image)) { return true; } string name = ((Object)image.sprite).name; if (name.StartsWith("woodpanel", StringComparison.Ordinal)) { return !name.EndsWith("_mask", StringComparison.Ordinal); } return false; } private static bool IsOurSprite(Image image) { if ((Object)(object)image == (Object)null || (Object)(object)image.sprite == (Object)null) { return false; } if ((Object)(object)image.sprite == (Object)(object)_panelSprite || (Object)(object)image.sprite == (Object)(object)_badgeSprite) { return true; } string name = ((Object)image.sprite).name; if (!(name == "VikingOS_Panel")) { return name == "VikingOS_Badge"; } return true; } private static Sprite PanelSprite() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_007d: 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_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: 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) //IL_0068: 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_007b: Expected O, but got Unknown //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: 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_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) Color val = ThemeGold(); Color val2 = ThemeFill(); if ((Object)(object)_panelSprite != (Object)null && _builtFor == val && _panelFillBuiltFor == val2) { return _panelSprite; } _builtFor = val; _panelFillBuiltFor = val2; if ((Object)(object)_panelTexture == (Object)null) { _panelTexture = new Texture2D(96, 96, (TextureFormat)4, false) { name = "VikingOS_Panel", filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; } Color val3 = default(Color); ((Color)(ref val3))..ctor(val.r * 0.45f, val.g * 0.45f, val.b * 0.45f, 1f); Color val4 = EdgeSeam(val2); Color[] array = (Color[])(object)new Color[9216]; for (int i = 0; i < 96; i++) { for (int j = 0; j < 96; j++) { int num = Mathf.Min(Mathf.Min(j, 95 - j), Mathf.Min(i, 95 - i)); Color val5 = ((num >= 1) ? ((num >= 4) ? ((num >= 5) ? ((num >= 7) ? ((num >= 16) ? val2 : Color.Lerp(new Color(val2.r * 1.6f, val2.g * 1.6f, val2.b * 1.5f, val2.a), val2, (float)(num - 7) / 9f)) : val4) : val3) : val) : val4); array[i * 96 + j] = val5; } } _panelTexture.SetPixels(array); _panelTexture.Apply(false); if ((Object)(object)_panelSprite == (Object)null) { _panelSprite = Sprite.Create(_panelTexture, new Rect(0f, 0f, 96f, 96f), new Vector2(0.5f, 0.5f), 50f, 0u, (SpriteMeshType)0, new Vector4(16f, 16f, 16f, 16f)); ((Object)_panelSprite).name = "VikingOS_Panel"; } return _panelSprite; } private static Sprite BadgeSprite() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: 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) //IL_0068: 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_007b: Expected O, but got Unknown //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: 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_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) Color val = ThemeGold(); Color val2 = ThemeFill(); if ((Object)(object)_badgeSprite != (Object)null && _badgeBuiltFor == val && _badgeFillBuiltFor == val2) { return _badgeSprite; } _badgeBuiltFor = val; _badgeFillBuiltFor = val2; if ((Object)(object)_badgeTexture == (Object)null) { _badgeTexture = new Texture2D(32, 32, (TextureFormat)4, false) { name = "VikingOS_Badge", filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; } Color val3 = EdgeSeam(val2); Color[] array = (Color[])(object)new Color[1024]; for (int i = 0; i < 32; i++) { for (int j = 0; j < 32; j++) { int num = Mathf.Min(Mathf.Min(j, 31 - j), Mathf.Min(i, 31 - i)); Color val4 = ((num >= 1) ? ((num >= 3) ? ((num >= 4) ? val2 : val3) : val) : val3); array[i * 32 + j] = val4; } } _badgeTexture.SetPixels(array); _badgeTexture.Apply(false); if ((Object)(object)_badgeSprite == (Object)null) { _badgeSprite = Sprite.Create(_badgeTexture, new Rect(0f, 0f, 32f, 32f), new Vector2(0.5f, 0.5f), 50f, 0u, (SpriteMeshType)0, new Vector4(6f, 6f, 6f, 6f)); ((Object)_badgeSprite).name = "VikingOS_Badge"; } return _badgeSprite; } private static Color ThemeGold() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (ConfigManager.uiGoldColour == null) { return new Color(0.8f, 0.62f, 0.26f, 1f); } return ConfigManager.uiGoldColour.Value; } private static Color ThemeFill() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) Color val = (Color)((ConfigManager.uiPanelColour != null) ? ConfigManager.uiPanelColour.Value : new Color(0.075f, 0.065f, 0.051f, 1f)); float num = ((ConfigManager.uiPanelOpacity != null) ? ConfigManager.uiPanelOpacity.Value : 0.955f); return new Color(val.r, val.g, val.b, Mathf.Clamp01(num * 0.984f)); } private static Color EdgeSeam(Color fill) { //IL_0000: 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_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) return new Color(fill.r * 0.45f, fill.g * 0.45f, fill.b * 0.45f, 1f); } } } namespace BarrkUI.Trading { internal static class TradeEscrow { [Serializable] internal sealed class Deposit { [JsonProperty("id")] public string Id = string.Empty; [JsonProperty("party")] public long Party; [JsonProperty("partner")] public long Partner; [JsonProperty("partyName")] public string PartyName = string.Empty; [JsonProperty("items")] public List Items = new List(); [JsonProperty("at")] public long DepositedAtUtcTicks; [JsonProperty("collected")] public bool Collected; [JsonProperty("sent")] public bool Sent; } [Serializable] private sealed class EscrowFile { [JsonProperty("version")] public int Version = 1; [JsonProperty("sequence")] public long Sequence; [JsonProperty("deposits")] public List Deposits = new List(); } internal static class ForTesting { public static double UnmatchedTimeout => 90.0; public static Deposit Find(long party) { EnsureLoaded(); if (!_deposits.TryGetValue(party, out var value)) { return null; } return value; } public static List All() { EnsureLoaded(); return new List(_deposits.Values); } public static bool IsCollected(Deposit deposit) { return deposit?.Collected ?? false; } public static bool IsSent(Deposit deposit) { return deposit?.Sent ?? false; } public static long PartnerOf(Deposit deposit) { return deposit?.Partner ?? 0; } public static int ItemCountOf(Deposit deposit) { return (deposit?.Items?.Count).GetValueOrDefault(); } public static double AgeSeconds(Deposit deposit) { if (deposit != null) { return (DateTime.UtcNow - new DateTime(deposit.DepositedAtUtcTicks)).TotalSeconds; } return 0.0; } public static void Backdate(Deposit deposit, double seconds) { if (deposit != null) { deposit.DepositedAtUtcTicks = DateTime.UtcNow.AddSeconds(0.0 - seconds).Ticks; Save(); } } public static void Uncollect(Deposit deposit) { if (deposit != null) { deposit.Collected = false; deposit.Sent = false; Save(); } } public static void ForceTick() { _nextTick = 0f; Tick(); } } private const double UnmatchedTimeoutSeconds = 90.0; private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.TradeEscrow"); private static long _sequence; private static readonly Dictionary _deposits = new Dictionary(); private static bool _loaded; private static float _nextTick; public static string FilePath => ModPaths.InConfigDir("trades.json"); public static int Count => _deposits.Count; public static bool Accept(long party, long partner, string partyName, List items) { EnsureLoaded(); if (party == 0L || partner == 0L || party == partner) { return false; } if (items == null) { return false; } if (_deposits.ContainsKey(party)) { Log.LogWarning((object)$"trade: refused a second deposit from {party:x} - one is already open. The client will be refunded."); return false; } long ticks = DateTime.UtcNow.Ticks; _deposits[party] = new Deposit { Id = $"{party:x}-{++_sequence:x}-{ticks:x}", Party = party, Partner = partner, PartyName = (partyName ?? string.Empty), Items = items, DepositedAtUtcTicks = ticks }; Save(); Log.LogInfo((object)$"trade: holding {items.Count} item(s) from {partyName} ({party:x}) for {partner:x}."); return true; } public static bool TryMatch(long party, out Deposit forParty, out Deposit forPartner) { forParty = null; forPartner = null; if (!_deposits.TryGetValue(party, out var value)) { return false; } if (!_deposits.TryGetValue(value.Partner, out var value2)) { return false; } if (value2.Partner != party) { return false; } forParty = value2; forPartner = value; return true; } public static List PendingFor(long party) { EnsureLoaded(); List list = new List(); foreach (Deposit value in _deposits.Values) { if (value.Partner == party && !value.Collected && _deposits.ContainsKey(value.Partner)) { list.Add(value); } } return list; } public static void MarkSent(Deposit deposit) { if (deposit != null) { deposit.Sent = true; Save(); } } public static void Collect(long party, long partner) { EnsureLoaded(); if (_deposits.TryGetValue(partner, out var value) && value.Partner == party) { value.Collected = true; if (_deposits.TryGetValue(party, out var value2) && value2.Collected && value2.Partner == partner) { _deposits.Remove(party); _deposits.Remove(partner); Log.LogInfo((object)$"trade: completed between {party:x} and {partner:x}; escrow released."); } Save(); } } public static List Withdraw(long party) { EnsureLoaded(); if (!_deposits.TryGetValue(party, out var value)) { return null; } _deposits.Remove(party); Save(); return value.Items; } public static void Tick() { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer() || Time.unscaledTime < _nextTick) { return; } _nextTick = Time.unscaledTime + 5f; EnsureLoaded(); if (_deposits.Count == 0) { return; } DateTime utcNow = DateTime.UtcNow; List list = null; foreach (KeyValuePair deposit2 in _deposits) { Deposit value = deposit2.Value; if (!_deposits.ContainsKey(value.Partner) && !((utcNow - new DateTime(value.DepositedAtUtcTicks)).TotalSeconds < 90.0)) { (list ?? (list = new List())).Add(deposit2.Key); } } if (list == null) { return; } foreach (long item in list) { Deposit deposit = _deposits[item]; deposit.Partner = item; deposit.Sent = false; deposit.DepositedAtUtcTicks = DateTime.UtcNow.Ticks; Log.LogInfo((object)($"trade: {deposit.PartyName} ({item:x}) waited {90.0:F0}s with no " + $"counter-deposit. {deposit.Items.Count} item(s) are being returned - held here until they claim them.")); } Save(); } public static bool IsRefund(Deposit deposit) { if (deposit != null) { return deposit.Party == deposit.Partner; } return false; } private static void EnsureLoaded() { if (_loaded) { return; } _loaded = true; try { if (!File.Exists(FilePath)) { return; } EscrowFile escrowFile = JsonConvert.DeserializeObject(File.ReadAllText(FilePath)); if (escrowFile?.Deposits == null) { return; } _sequence = escrowFile.Sequence; foreach (Deposit deposit in escrowFile.Deposits) { if (deposit != null && deposit.Party != 0L) { if (string.IsNullOrEmpty(deposit.Id)) { deposit.Id = $"{deposit.Party:x}-legacy-{deposit.DepositedAtUtcTicks:x}"; } if (_sequence < 1) { _sequence = 1L; } _deposits[deposit.Party] = deposit; } } if (_deposits.Count > 0) { Log.LogInfo((object)$"trade: recovered {_deposits.Count} deposit(s) still in escrow from a previous session."); } } catch (Exception ex) { _loaded = false; Diagnostics.Health("Trade escrow", ok: false, "trades.json could not be read, so items held in escrow are NOT recoverable this session and the file has been left untouched for manual recovery. Reason: " + ex.Message); Log.LogError((object)ex.ToString()); } } private static void Save() { try { EscrowFile escrowFile = new EscrowFile { Sequence = _sequence }; escrowFile.Deposits.AddRange(_deposits.Values); Directory.CreateDirectory(Path.GetDirectoryName(FilePath)); File.WriteAllText(FilePath, JsonConvert.SerializeObject((object)escrowFile, (Formatting)1)); } catch (Exception arg) { Log.LogError((object)("trade: COULD NOT WRITE " + FilePath + ". Items currently in escrow will be LOST if this " + $"server restarts before the trades complete. Reason: {arg}")); } } public static string IdOf(Deposit deposit) { return deposit?.Id ?? string.Empty; } public static List ItemsOf(Deposit deposit) { return deposit?.Items; } public static string NameOf(Deposit deposit) { return deposit?.PartyName ?? string.Empty; } public static long PartyOf(Deposit deposit) { return deposit?.Party ?? 0; } } internal static class TradeInbox { [Serializable] private sealed class InboxFile { [JsonProperty("version")] public int Version = 1; [JsonProperty("applied")] public List Applied = new List(); } private const int MaxRemembered = 500; private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.TradeInbox"); private static readonly List _applied = new List(); private static readonly HashSet _index = new HashSet(StringComparer.Ordinal); private static bool _loaded; public static string FilePath => ModPaths.InConfigDir("trade-inbox.json"); public static bool AlreadyApplied(string deliveryId) { if (string.IsNullOrEmpty(deliveryId)) { return false; } EnsureLoaded(); return _index.Contains(deliveryId); } public static void MarkApplied(string deliveryId) { if (string.IsNullOrEmpty(deliveryId)) { return; } EnsureLoaded(); if (_index.Add(deliveryId)) { _applied.Add(deliveryId); while (_applied.Count > 500) { _index.Remove(_applied[0]); _applied.RemoveAt(0); } Save(); } } private static void EnsureLoaded() { if (_loaded) { return; } _loaded = true; try { if (!File.Exists(FilePath)) { return; } InboxFile inboxFile = JsonConvert.DeserializeObject(File.ReadAllText(FilePath)); if (inboxFile?.Applied == null) { return; } foreach (string item in inboxFile.Applied) { if (!string.IsNullOrEmpty(item) && _index.Add(item)) { _applied.Add(item); } } Diagnostics.Trace(() => $"trade inbox: {_applied.Count} past delivery(ies) remembered."); } catch (Exception ex) { _loaded = false; Diagnostics.Health("Trade inbox", ok: false, "trade-inbox.json could not be read. Until it can, a redelivered trade could be applied twice - the file has been left untouched. Reason: " + ex.Message); Log.LogError((object)ex.ToString()); } } private static void Save() { try { InboxFile inboxFile = new InboxFile(); inboxFile.Applied.AddRange(_applied); Directory.CreateDirectory(Path.GetDirectoryName(FilePath)); File.WriteAllText(FilePath, JsonConvert.SerializeObject((object)inboxFile, (Formatting)1)); } catch (Exception arg) { Log.LogError((object)$"COULD NOT WRITE {FilePath}. If this trade is redelivered it may be applied twice. Reason: {arg}"); } } } [Serializable] internal sealed class TradeItem { [JsonProperty("prefab")] public string PrefabName = string.Empty; [JsonProperty("stack")] public int Stack = 1; [JsonProperty("quality")] public int Quality = 1; [JsonProperty("variant")] public int Variant; [JsonProperty("durability")] public float Durability; [JsonProperty("crafterId")] public long CrafterID; [JsonProperty("crafterName")] public string CrafterName = string.Empty; [JsonProperty("worldLevel")] public int WorldLevel; [JsonProperty("pickedUp")] public bool PickedUp; [JsonProperty("custom")] public Dictionary CustomData = new Dictionary(); private const int PayloadVersion = 1; public static TradeItem From(ItemData item, int stack) { TradeItem tradeItem = new TradeItem { PrefabName = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : string.Empty), Stack = Mathf.Max(1, stack), Quality = item.m_quality, Variant = item.m_variant, Durability = item.m_durability, CrafterID = item.m_crafterID, CrafterName = (item.m_crafterName ?? string.Empty), WorldLevel = item.m_worldLevel, PickedUp = item.m_pickedUp }; if (item.m_customData != null) { foreach (KeyValuePair customDatum in item.m_customData) { tradeItem.CustomData[customDatum.Key] = customDatum.Value; } } return tradeItem; } public ItemData Rebuild() { if (string.IsNullOrEmpty(PrefabName) || (Object)(object)ObjectDB.instance == (Object)null) { return null; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(PrefabName); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent() : null); if ((Object)(object)val == (Object)null || val.m_itemData?.m_shared == null) { return null; } ItemData val2 = val.m_itemData.Clone(); val2.m_stack = Mathf.Max(1, Stack); val2.m_quality = Mathf.Max(1, Quality); val2.m_variant = ClampVariant(Variant, val2.m_shared); val2.m_durability = Durability; val2.m_crafterID = CrafterID; val2.m_crafterName = CrafterName ?? string.Empty; val2.m_pickedUp = PickedUp; val2.m_dropPrefab = itemPrefab; val2.m_worldLevel = WorldLevel; if (val2.m_customData == null) { val2.m_customData = new Dictionary(); } val2.m_customData.Clear(); if (CustomData != null) { foreach (KeyValuePair customDatum in CustomData) { val2.m_customData[customDatum.Key] = customDatum.Value; } } return val2; } private static int ClampVariant(int variant, SharedData shared) { Sprite[] icons = shared.m_icons; int num = ((icons != null) ? icons.Length : 0); if (num != 0) { return Mathf.Clamp(variant, 0, num - 1); } return 0; } public string DisplayName() { ItemData val = Rebuild(); if (val?.m_shared == null) { return PrefabName + " (unknown here)"; } string obj = ((Localization.instance != null) ? Localization.instance.Localize(val.m_shared.m_name) : val.m_shared.m_name); string text = ((Quality > 1) ? $" ★{Quality}" : string.Empty); string text2 = ((Stack > 1) ? $" ×{Stack}" : string.Empty); return obj + text + text2; } public Sprite Icon() { ItemData obj = Rebuild(); if (obj == null) { return null; } return obj.GetIcon(); } public static ZPackage Write(List items) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(1); val.Write(items?.Count ?? 0); if (items == null) { return val; } foreach (TradeItem item in items) { val.Write(item.PrefabName ?? string.Empty); val.Write(item.Stack); val.Write(item.Quality); val.Write(item.Variant); val.Write(item.Durability); val.Write(item.CrafterID); val.Write(item.CrafterName ?? string.Empty); val.Write(item.WorldLevel); val.Write(item.PickedUp); val.Write(item.CustomData?.Count ?? 0); if (item.CustomData == null) { continue; } foreach (KeyValuePair customDatum in item.CustomData) { val.Write(customDatum.Key ?? string.Empty); val.Write(customDatum.Value ?? string.Empty); } } val.SetPos(0); return val; } public static List Read(ZPackage pkg) { if (pkg == null) { return null; } try { if (pkg.ReadInt() != 1) { return null; } int num = pkg.ReadInt(); if (num < 0 || num > 64) { return null; } List list = new List(num); for (int i = 0; i < num; i++) { TradeItem tradeItem = new TradeItem { PrefabName = pkg.ReadString(), Stack = pkg.ReadInt(), Quality = pkg.ReadInt(), Variant = pkg.ReadInt(), Durability = pkg.ReadSingle(), CrafterID = pkg.ReadLong(), CrafterName = pkg.ReadString(), WorldLevel = pkg.ReadInt(), PickedUp = pkg.ReadBool() }; int num2 = pkg.ReadInt(); if (num2 < 0 || num2 > 256) { return null; } for (int j = 0; j < num2; j++) { string text = pkg.ReadString(); string value = pkg.ReadString(); if (!string.IsNullOrEmpty(text)) { tradeItem.CustomData[text] = value; } } tradeItem.Stack = Mathf.Clamp(tradeItem.Stack, 1, 9999); tradeItem.Quality = Mathf.Clamp(tradeItem.Quality, 1, 100); list.Add(tradeItem); } return list; } catch (Exception) { return null; } } } internal static class TradeRpc { internal enum Phase { Idle, Inviting, Invited, Open, Settling } [HarmonyPatch] internal static class RegisterPatch { [HarmonyPatch(typeof(ZNet), "Awake")] [HarmonyPostfix] private static void ZNet_Awake_Postfix() { try { if (ZRoutedRpc.instance == null) { Diagnostics.Health("Trading", ok: false, "ZNet.Awake ran with no ZRoutedRpc, so trade RPCs could not be registered. Trading is disabled for this session."); return; } ZRoutedRpc.instance.Register("VikingOS_TradeInvite", (Action)RPC_Invite); ZRoutedRpc.instance.Register("VikingOS_TradeReply", (Action)RPC_Reply); ZRoutedRpc.instance.Register("VikingOS_TradeOffer", (Action)RPC_Offer); ZRoutedRpc.instance.Register("VikingOS_TradeCancel", (Action)RPC_Cancel); ZRoutedRpc.instance.Register("VikingOS_TradeDeposit", (Action)RPC_Deposit); ZRoutedRpc.instance.Register("VikingOS_TradeDeliver", (Method)RPC_Deliver); ZRoutedRpc.instance.Register("VikingOS_TradeAck", (Action)RPC_Ack); ZRoutedRpc.instance.Register("VikingOS_TradeClaim", (Action)RPC_Claim); ZRoutedRpc.instance.Register("VikingOS_TradePing", (Action)RPC_Ping); Diagnostics.Health("Trading", ok: true, "trade RPCs registered for this session"); } catch (Exception ex) { Diagnostics.Health("Trading", ok: false, "registering the trade RPCs threw, so trading is disabled for this session. Reason: " + ex.Message); Log.LogError((object)ex.ToString()); } } } internal static class ForTesting { public static void SendDeposit(long partner, string partyName, List items) { ZRoutedRpc.instance.InvokeRoutedRPC("VikingOS_TradeDeposit", new object[3] { partner, partyName, TradeItem.Write(items) }); } } private const string RpcInvite = "VikingOS_TradeInvite"; private const string RpcReply = "VikingOS_TradeReply"; private const string RpcOffer = "VikingOS_TradeOffer"; private const string RpcCancel = "VikingOS_TradeCancel"; private const string RpcDeposit = "VikingOS_TradeDeposit"; private const string RpcDeliver = "VikingOS_TradeDeliver"; private const string RpcAck = "VikingOS_TradeAck"; private const string RpcClaim = "VikingOS_TradeClaim"; private const string RpcPing = "VikingOS_TradePing"; private const float PingInterval = 2f; private const float PingTimeout = 6f; private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.Trade"); internal static readonly List MyOffer = new List(); internal static readonly List MyOfferSources = new List(); internal static readonly List TheirOffer = new List(); private static bool _settled; private static string _theirSignature = string.Empty; private static float _lastHeard; private static float _nextPing; public static Phase State { get; private set; } = Phase.Idle; public static long PartnerId { get; private set; } public static string PartnerName { get; private set; } = string.Empty; public static bool MyReady { get; private set; } public static bool TheirReady { get; private set; } public static string Status { get; private set; } = string.Empty; public static bool Busy => State != Phase.Idle; public static void ResetSession() { Reset("left the world"); } private static void Reset(string reason) { State = Phase.Idle; PartnerId = 0L; PartnerName = string.Empty; MyOffer.Clear(); MyOfferSources.Clear(); TheirOffer.Clear(); MyReady = false; TheirReady = false; _settled = false; _theirSignature = string.Empty; _lastHeard = 0f; _nextPing = 0f; if (!string.IsNullOrEmpty(reason)) { Status = reason; } } private static void HeardFromPartner() { _lastHeard = Time.unscaledTime; } public static void ClaimPending() { try { if (ZRoutedRpc.instance != null && !((Object)(object)ZNet.instance == (Object)null)) { ZRoutedRpc.instance.InvokeRoutedRPC("VikingOS_TradeClaim", Array.Empty()); Diagnostics.Trace(() => "trade: asked the server for anything held in escrow for us."); } } catch (Exception arg) { Log.LogError((object)$"could not ask the server for pending trade items. Reason: {arg}"); } } public static void Invite(string name, long uid) { if (Busy) { Say("You are already in a trade."); } else if (uid != 0L && ZRoutedRpc.instance != null && !((Object)(object)Player.m_localPlayer == (Object)null)) { Reset(null); State = Phase.Inviting; PartnerId = uid; PartnerName = name ?? string.Empty; HeardFromPartner(); ZRoutedRpc.instance.InvokeRoutedRPC(uid, "VikingOS_TradeInvite", new object[1] { Player.m_localPlayer.GetPlayerName() }); Say("Asked " + PartnerName + " to trade..."); } } public static void AcceptInvite() { if (State == Phase.Invited) { State = Phase.Open; ZRoutedRpc.instance.InvokeRoutedRPC(PartnerId, "VikingOS_TradeReply", new object[2] { Player.m_localPlayer.GetPlayerName(), 1 }); Say("Trading with " + PartnerName + "."); SendMyState(); } } public static void DeclineInvite() { if (State == Phase.Invited) { ZRoutedRpc.instance.InvokeRoutedRPC(PartnerId, "VikingOS_TradeReply", new object[2] { Player.m_localPlayer.GetPlayerName(), 0 }); Reset("Declined."); } } public static void Cancel(string reason) { if (State == Phase.Idle) { return; } if (State == Phase.Settling) { Say("Too late to cancel - the server has both sides and is completing the swap."); return; } if (PartnerId != 0L && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(PartnerId, "VikingOS_TradeCancel", new object[1] { reason ?? "cancelled" }); } Reset(string.IsNullOrEmpty(reason) ? "Trade cancelled." : ("Trade cancelled: " + reason)); } public static void AddToOffer(ItemData item) { if (State == Phase.Open && item?.m_shared != null) { if ((Object)(object)item.m_dropPrefab == (Object)null) { Say("That item cannot be traded - it has no prefab to identify it by."); return; } if (MyOffer.Count >= 16) { Say("That is as much as one trade will carry."); return; } if (MyOfferSources.Contains(item)) { Say("That one is already on the table."); return; } MyOffer.Add(TradeItem.From(item, item.m_stack)); MyOfferSources.Add(item); MyReady = false; TheirReady = false; SendMyState(); } } public static void RemoveFromOffer(int index) { if (State == Phase.Open && index >= 0 && index < MyOffer.Count) { MyOffer.RemoveAt(index); MyOfferSources.RemoveAt(index); MyReady = false; TheirReady = false; SendMyState(); } } public static void SetReady(bool ready) { if (State == Phase.Open) { MyReady = ready; SendMyState(); } } private static void SendMyState() { if (PartnerId != 0L && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(PartnerId, "VikingOS_TradeOffer", new object[2] { TradeItem.Write(MyOffer), MyReady ? 1 : 0 }); } } public static void Tick() { TradeEscrow.Tick(); if (State != Phase.Idle) { PumpHeartbeat(); if (State == Phase.Open && !_settled && MyReady && TheirReady) { Settle(); } } } private static void PumpHeartbeat() { float unscaledTime = Time.unscaledTime; if (unscaledTime >= _nextPing) { _nextPing = unscaledTime + 2f; if (PartnerId != 0L && ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(PartnerId, "VikingOS_TradePing", Array.Empty()); } } if (!PartnerIsLive() && State != Phase.Settling) { Reset(PartnerName + " disconnected - the trade was called off. Nothing left your inventory."); Diagnostics.Trace(() => "trade: partner went quiet before settlement; cancelled with nothing moved."); } } private static bool PartnerIsLive() { if (PartnerId == 0L) { return false; } if (_lastHeard > 0f && Time.unscaledTime - _lastHeard > 6f) { return false; } return PartnerInPeerList(); } private static bool PartnerInPeerList() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ZNet.instance == (Object)null) { return false; } foreach (PlayerInfo player in ZNet.instance.GetPlayerList()) { if (player.m_characterID != ZDOID.None) { ZDOID characterID = player.m_characterID; if (((ZDOID)(ref characterID)).UserID == PartnerId) { return true; } } } return false; } private static void RPC_Ping(long sender) { if (State != Phase.Idle && sender == PartnerId) { HeardFromPartner(); } } private static void Settle() { _settled = true; if (!PartnerIsLive()) { _settled = false; Reset(PartnerName + " dropped just before the swap. Nothing left your inventory."); return; } Player localPlayer = Player.m_localPlayer; Inventory val = (((Object)(object)localPlayer != (Object)null) ? ((Humanoid)localPlayer).GetInventory() : null); if (val == null) { Cancel("no inventory"); return; } foreach (ItemData myOfferSource in MyOfferSources) { if (!val.ContainsItem(myOfferSource)) { _settled = false; Cancel("one of your items is no longer in your inventory"); return; } } List list = new List(TheirOffer.Count); foreach (TradeItem item in TheirOffer) { ItemData val2 = item.Rebuild(); if (val2 == null) { _settled = false; Cancel("\"" + item.PrefabName + "\" does not exist on your client - you may be missing a mod they have"); return; } list.Add(val2); } if (!HasRoomFor(val, list, MyOfferSources.Count)) { _settled = false; Cancel("your inventory has no room for what they are offering"); return; } foreach (ItemData myOfferSource2 in MyOfferSources) { ((Humanoid)localPlayer).RemoveEquipAction(myOfferSource2); ((Humanoid)localPlayer).UnequipItem(myOfferSource2, false); val.RemoveItem(myOfferSource2); } State = Phase.Settling; Say("Both confirmed - the server is completing the swap."); ZRoutedRpc.instance.InvokeRoutedRPC("VikingOS_TradeDeposit", new object[3] { PartnerId, localPlayer.GetPlayerName(), TradeItem.Write(MyOffer) }); } private static bool HasRoomFor(Inventory inventory, List incoming, int slotsBeingFreed) { int num = inventory.GetEmptySlots() + slotsBeingFreed; foreach (ItemData item in incoming) { int num2 = Mathf.Max(1, item.m_shared.m_maxStackSize); num -= Mathf.CeilToInt((float)item.m_stack / (float)num2); } return num >= 0; } private static void RPC_Invite(long sender, string fromName) { try { if (!((Object)(object)Player.m_localPlayer == (Object)null)) { string text = Sanitise(fromName); if (Busy) { ZRoutedRpc.instance.InvokeRoutedRPC(sender, "VikingOS_TradeReply", new object[2] { Player.m_localPlayer.GetPlayerName(), 0 }); return; } Reset(null); State = Phase.Invited; PartnerId = sender; PartnerName = text; HeardFromPartner(); Say(text + " wants to trade."); } } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed. Reason: {1}", "RPC_Invite", arg)); } } private static void RPC_Reply(long sender, string fromName, int accepted) { try { if (State == Phase.Inviting && sender == PartnerId) { HeardFromPartner(); if (accepted == 0) { Reset(Sanitise(fromName) + " declined."); return; } State = Phase.Open; Say("Trading with " + PartnerName + "."); SendMyState(); } } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed. Reason: {1}", "RPC_Reply", arg)); } } private static void RPC_Offer(long sender, ZPackage payload, int ready) { try { if (State != Phase.Open || sender != PartnerId) { return; } HeardFromPartner(); List list = TradeItem.Read(payload); if (list == null) { Cancel("their offer could not be read"); return; } string text = Signature(list); bool flag = text != _theirSignature; _theirSignature = text; TheirOffer.Clear(); TheirOffer.AddRange(list); TheirReady = ready != 0; if (flag && MyReady) { MyReady = false; Say("They changed their offer - confirm again."); SendMyState(); } } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed. Reason: {1}", "RPC_Offer", arg)); } } private static void RPC_Cancel(long sender, string reason) { try { if (State != Phase.Idle && sender == PartnerId && State != Phase.Settling) { Reset(PartnerName + " cancelled: " + Sanitise(reason)); } } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed. Reason: {1}", "RPC_Cancel", arg)); } } private static void RPC_Deliver(long sender, string deliveryId, long fromUid, string fromName, ZPackage payload) { //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) try { Player localPlayer = Player.m_localPlayer; Inventory val = (((Object)(object)localPlayer != (Object)null) ? ((Humanoid)localPlayer).GetInventory() : null); if (val == null) { return; } if (TradeInbox.AlreadyApplied(deliveryId)) { Diagnostics.Trace(() => "trade: delivery \"" + deliveryId + "\" was already applied; re-acknowledging without adding anything."); ZRoutedRpc.instance.InvokeRoutedRPC("VikingOS_TradeAck", new object[1] { fromUid }); if (State == Phase.Settling) { Reset("Trade complete."); } return; } List list = TradeItem.Read(payload); if (list == null) { Log.LogError((object)"trade: a delivery from the server could not be read. It has NOT been acknowledged and remains in escrow."); Say("A trade delivery arrived damaged and was left with the server. Report this."); return; } List list2 = new List(list.Count); foreach (TradeItem item in list) { ItemData val2 = item.Rebuild(); if (val2 != null) { list2.Add(val2); continue; } Log.LogError((object)("trade: cannot rebuild \"" + item.PrefabName + "\" on this client, so the whole delivery is left in escrow.")); Say("A trade contained \"" + item.PrefabName + "\", which does not exist on your client. It is still held by the server."); return; } foreach (ItemData item2 in list2) { if (!val.AddItem(item2)) { ItemDrop.DropItem(item2, item2.m_stack, ((Component)localPlayer).transform.position + ((Component)localPlayer).transform.forward, Quaternion.identity); } } TradeInbox.MarkApplied(deliveryId); long num; if (!((Object)(object)ZNet.instance != (Object)null)) { num = 0L; } else { ZDOID localPlayerCharacterID = ZNet.instance.LocalPlayerCharacterID; num = ((ZDOID)(ref localPlayerCharacterID)).UserID; } long num2 = num; Say((fromUid == num2) ? $"Returned to you: {list2.Count} item(s) from a trade that did not complete." : $"Received {list2.Count} item(s) from {Sanitise(fromName)}."); ZRoutedRpc.instance.InvokeRoutedRPC("VikingOS_TradeAck", new object[1] { fromUid }); if (State == Phase.Settling) { Reset("Trade complete."); } } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed - the delivery was NOT acknowledged and stays in escrow. Reason: {1}", "RPC_Deliver", arg)); } } private static void RPC_Deposit(long sender, long partner, string partyName, ZPackage payload) { try { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { List list = TradeItem.Read(payload); if (list == null || !TradeEscrow.Accept(sender, partner, partyName, list)) { Log.LogWarning((object)$"trade: refusing a deposit from {sender:x}; echoing it back untouched."); payload.SetPos(0); ZRoutedRpc.instance.InvokeRoutedRPC(sender, "VikingOS_TradeDeliver", new object[4] { string.Empty, sender, partyName ?? string.Empty, payload }); } else { DeliverIfMatched(sender); } } } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed for sender={1}. Reason: {2}", "RPC_Deposit", sender, arg)); } } private static void DeliverIfMatched(long party) { if (TradeEscrow.TryMatch(party, out var forParty, out var forPartner)) { long to = TradeEscrow.PartyOf(forParty); Send(party, forParty); Send(to, forPartner); } } private static void Send(long to, TradeEscrow.Deposit deposit) { if (deposit != null && to != 0L) { ZRoutedRpc.instance.InvokeRoutedRPC(to, "VikingOS_TradeDeliver", new object[4] { TradeEscrow.IdOf(deposit), TradeEscrow.PartyOf(deposit), TradeEscrow.NameOf(deposit), TradeItem.Write(TradeEscrow.ItemsOf(deposit)) }); TradeEscrow.MarkSent(deposit); Log.LogInfo((object)$"trade: sent {TradeEscrow.ItemsOf(deposit).Count} item(s) from {TradeEscrow.NameOf(deposit)} to {to:x}."); } } private static void RPC_Ack(long sender, long partner) { try { if (!((Object)(object)ZNet.instance == (Object)null) && ZNet.instance.IsServer()) { TradeEscrow.Collect(sender, partner); } } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed for sender={1}. Reason: {2}", "RPC_Ack", sender, arg)); } } private static void RPC_Claim(long sender) { try { if ((Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsServer()) { return; } List list = TradeEscrow.PendingFor(sender); if (list.Count == 0) { return; } Log.LogInfo((object)$"trade: {sender:x} reconnected with {list.Count} delivery(ies) waiting."); foreach (TradeEscrow.Deposit item in list) { Send(sender, item); } } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed for sender={1}. Reason: {2}", "RPC_Claim", sender, arg)); } } private static string Signature(List items) { if (items == null || items.Count == 0) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(); foreach (TradeItem item in items) { stringBuilder.Append(item.PrefabName).Append('|').Append(item.Stack) .Append('|') .Append(item.Quality) .Append('|') .Append(item.Variant) .Append('|') .Append(item.Durability.ToString("0.##")) .Append(';'); } return stringBuilder.ToString(); } private static string Sanitise(string value) { if (string.IsNullOrEmpty(value)) { return "someone"; } string text = value.Replace('<', ' ').Replace('>', ' ').Trim(); if (text.Length > 40) { text = text.Substring(0, 40); } if (text.Length != 0) { return text; } return "someone"; } private static void Say(string text) { Status = text ?? string.Empty; Diagnostics.Trace(() => "trade: " + Status); } } internal static class TradeTest { private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.TradeTest"); private const long PartnerUid = 6217583538779652097L; private const string PartnerName = "Test Partner"; private const int MaxItemsPerPayload = 64; public static void Run(ConsoleEventArgs args) { TestReport testReport = new TestReport(args.Context); string text = ((args.Args.Length > 1) ? args.Args[1].ToLowerInvariant() : string.Empty); int count = ParseCount(args, 2); if (text.Length != 0) { int needsEmptyEscrow; string reason; switch (text) { case "help": case "?": break; case "status": Status(testReport); return; default: needsEmptyEscrow = ((text == "refund") ? 1 : 0); goto IL_0099; case "swap": case "dupe": { needsEmptyEscrow = 1; goto IL_0099; } IL_0099: if (!Ready((byte)needsEmptyEscrow != 0, out reason)) { testReport.Line("vikingos_tradetest: " + reason); return; } try { switch (text) { case "roundtrip": RoundTrip(testReport); break; case "swap": Swap(testReport, count, alsoTestDupe: false); break; case "dupe": Swap(testReport, count, alsoTestDupe: true); break; case "refund": Refund(testReport, count); break; case "claim": Claim(testReport); break; default: testReport.Line("vikingos_tradetest: no such test '" + text + "'."); Usage(testReport); return; } } catch (Exception ex) { testReport.Fail("the test threw: " + ex.Message); testReport.Line(" Nothing is lost. Run 'vikingos_tradetest status' to see what escrow is holding,"); testReport.Line(" then 'vikingos_tradetest claim' (or just relog) to bring it home."); Log.LogError((object)ex.ToString()); } testReport.Summary(); return; } } Usage(testReport); } private static void Usage(TestReport report) { report.Line("vikingos_tradetest - drives the REAL trade settlement path against a synthetic partner."); report.Line(" roundtrip every item you are carrying through capture -> wire -> read -> rebuild."); report.Line(" Moves nothing. Catches lossy serialisation eating another mod's data."); report.Line(" swap [n] a whole trade: deposit both sides, match, deliver, acknowledge."); report.Line(" Your n items come back to you, so your pack is the expected result."); report.Line(" dupe [n] a swap, then the same delivery re-sent. Nothing may arrive twice."); report.Line(" refund [n] a deposit nobody counters, aged past the timeout, swept and claimed."); report.Line(" status what escrow and the delivery ledger currently hold."); report.Line(" claim ask the server for anything it is holding for you (recovery)."); report.Line("Single player / listen server only - it must be able to be both halves at once."); } private static int ParseCount(ConsoleEventArgs args, int index) { if (args.Args.Length <= index || !int.TryParse(args.Args[index], out var result)) { return 1; } return Mathf.Clamp(result, 1, 16); } private static bool Ready(bool needsEmptyEscrow, out string reason) { reason = string.Empty; if (!SessionState.IsLive || (Object)(object)Player.m_localPlayer == (Object)null) { reason = "not in a world yet (" + SessionState.Describe() + ")."; return false; } if ((Object)(object)ZNet.instance == (Object)null || ZRoutedRpc.instance == null) { reason = "there is no network session, so there is no server half to talk to."; return false; } if (!ZNet.instance.IsServer()) { reason = "this is a client on somebody else's server. The self-test has to BE the server (single player, or your own listen server) because it plays both halves."; return false; } if (TradeRpc.Busy) { reason = $"you are in a real trade right now ({TradeRpc.State}). Finish or cancel it first."; return false; } int count = TradeEscrow.ForTesting.All().Count; if (needsEmptyEscrow && count > 0) { reason = $"escrow is already holding {count} deposit(s). Run 'vikingos_tradetest status' to see " + "what, and 'vikingos_tradetest claim' to bring anything owed to you home first."; return false; } return true; } private static void RoundTrip(TestReport report) { List list = new List(((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems()); report.Line($"roundtrip: {list.Count} item(s) in your inventory."); int num = 0; int num2 = 0; foreach (ItemData item2 in list) { if (item2?.m_shared == null) { continue; } if ((Object)(object)item2.m_dropPrefab == (Object)null) { report.Line(" skip " + Describe(item2) + " - no drop prefab, so a trade could not identify it."); num2++; continue; } num++; try { TradeItem item = TradeItem.From(item2, item2.m_stack); List list2 = TradeItem.Read(TradeItem.Write(new List { item })); if (list2 == null || list2.Count != 1) { report.Fail(Describe(item2) + " - the payload could not be read back off the wire."); continue; } ItemData val = list2[0].Rebuild(); if (val == null) { report.Fail(Describe(item2) + " - Rebuild returned nothing, so this item could not be received."); continue; } List list3 = new List(); CompareFields(item2, val, list3); if (list3.Count == 0) { continue; } report.Fail(Describe(item2) + " does not survive the round trip:"); foreach (string item3 in list3) { report.Line(" " + item3); } } catch (Exception ex) { report.Fail(Describe(item2) + " threw on the way round: " + ex.Message); Log.LogError((object)ex.ToString()); } } report.Line($" {num} item(s) checked, {num2} skipped."); List list4 = new List(); foreach (ItemData item4 in list) { if (item4?.m_shared != null && !((Object)(object)item4.m_dropPrefab == (Object)null)) { if (list4.Count >= 64) { break; } list4.Add(TradeItem.From(item4, item4.m_stack)); } } if (list4.Count == 0) { report.Line(" nothing tradeable to test the multi-item framing with."); return; } if (num > 64) { report.Line($" framing pass covers the first {64} - TradeItem.Read refuses more, " + "deliberately, and an offer is capped at 16 anyway."); } List list5 = TradeItem.Read(TradeItem.Write(list4)); if (list5 == null) { report.Fail($"a {list4.Count}-item payload could not be read back at all."); return; } report.Check(list5.Count == list4.Count, $"a {list4.Count}-item payload comes back with {list5.Count} item(s)"); int num3 = 0; for (int i = 0; i < Math.Min(list5.Count, list4.Count); i++) { string text = KeyOf(list4[i]); string text2 = KeyOf(list5[i]); if (!(text == text2)) { num3++; report.Line($" item {i} changed in a multi-item payload:"); report.Line(" sent " + text); report.Line(" got " + text2); } } report.Check(num3 == 0, "every item survives being sent alongside the others"); } private static void Swap(TestReport report, int count, bool alsoTestDupe) { try { RunSwap(report, count, alsoTestDupe); } finally { if (TradeEscrow.ForTesting.Find(6217583538779652097L) != null) { TradeEscrow.Withdraw(6217583538779652097L); report.Line(" the harness's synthetic deposit was still in escrow and has been discarded (its items were copies - nothing real was in it)."); } } } private static void RunSwap(TestReport report, int count, bool alsoTestDupe) { Player localPlayer = Player.m_localPlayer; Inventory inventory = ((Humanoid)localPlayer).GetInventory(); long uID = ZNet.GetUID(); if (uID == 6217583538779652097L) { report.Fail("your session uid collided with the harness's synthetic partner. Rejoin the world."); return; } string note; List list = Pick(inventory, count, out note); if (list.Count == 0) { report.Line("swap: nothing in your inventory can be traded (everything is equipped, or has no drop prefab)."); return; } if (note.Length > 0) { report.Line(" " + note); } if (list.Count < count) { report.Line($" asked for {count}, only {list.Count} could be traded."); } report.Line($"swap: putting up {list.Count} item(s):"); foreach (ItemData item in list) { report.Line(" " + Describe(item)); } Dictionary before = Signature(inventory); List list2 = new List(); foreach (ItemData item2 in list) { list2.Add(TradeItem.From(item2, item2.m_stack)); } List list3 = TradeItem.Read(TradeItem.Write(list2)); if (list3 == null) { report.Fail("the partner's offer could not be read off the wire, so the swap was not started. Nothing moved."); return; } if (!TradeEscrow.Accept(6217583538779652097L, uID, "Test Partner", list3)) { report.Fail("escrow refused the partner's deposit, so the swap was not started. Nothing moved."); return; } TradeEscrow.Deposit deposit = TradeEscrow.ForTesting.Find(6217583538779652097L); string text = TradeEscrow.IdOf(deposit); report.Check(!string.IsNullOrEmpty(text), "the partner's deposit was minted an id (" + text + ")"); report.Check(!TradeInbox.AlreadyApplied(text), "that id is one your ledger has never seen"); foreach (ItemData item3 in list) { inventory.RemoveItem(item3); } TradeRpc.ForTesting.SendDeposit(6217583538779652097L, localPlayer.GetPlayerName(), list2); TradeEscrow.Deposit deposit2 = TradeEscrow.ForTesting.Find(uID); if (deposit2 == null) { report.Fail("escrow never took our deposit in - RPC_Deposit refused it."); RestoreIfMissing(report, inventory, before, list2); } else { report.Check(TradeEscrow.ForTesting.IsSent(deposit2), "our goods were handed on to the partner"); report.Check(!TradeEscrow.ForTesting.IsCollected(deposit2), "our deposit is still held, because the synthetic partner has not acknowledged yet"); } report.Check(TradeEscrow.ForTesting.IsCollected(deposit), "the partner's deposit was acknowledged by us and escrow closed it"); report.Check(TradeInbox.AlreadyApplied(text), "the delivery ledger now remembers " + text); report.Check(FileMentions(TradeInbox.FilePath, text), "trade-inbox.json on disk holds that id - it survived, which is the whole point of it"); if (alsoTestDupe) { Dictionary before2 = Signature(inventory); report.Line("dupe: reopening the delivery you were already paid, and asking for it again."); report.Line(" (the same edit the multiplayer sheet describes: set 'collected' back to false)"); TradeEscrow.ForTesting.Uncollect(deposit); report.Check(!TradeEscrow.ForTesting.IsCollected(deposit), "the record is open again"); TradeRpc.ClaimPending(); Dictionary after = Signature(inventory); List list4 = Diff(before2, after); report.Check(list4.Count == 0, "NOTHING ARRIVED A SECOND TIME"); foreach (string item4 in list4) { report.Line(" " + item4); } report.Check(TradeEscrow.ForTesting.IsCollected(deposit), "the redelivery was acknowledged without adding anything, so escrow closed it again"); report.Line(" (with 'vikingos_debug on' the log also says: was already applied)"); } TradeEscrow.Collect(6217583538779652097L, uID); report.Check(TradeEscrow.Count == 0, "escrow is empty"); report.Check(EscrowFileIsEmpty(), "trades.json on disk holds no deposits"); Dictionary after2 = Signature(inventory); List list5 = Diff(before, after2); report.Check(list5.Count == 0, "your inventory is EXACTLY as it was - every field survived capture, wire, disk, rebuild and add"); foreach (string item5 in list5) { report.Line(" " + item5); } } private static void Refund(TestReport report, int count) { Player localPlayer = Player.m_localPlayer; Inventory inventory = ((Humanoid)localPlayer).GetInventory(); long uID = ZNet.GetUID(); string note; List list = Pick(inventory, count, out note); if (list.Count == 0) { report.Line("refund: nothing in your inventory can be traded."); return; } if (note.Length > 0) { report.Line(" " + note); } if (list.Count < count) { report.Line($" asked for {count}, only {list.Count} could be traded."); } report.Line($"refund: depositing {list.Count} item(s) that nobody will counter:"); foreach (ItemData item in list) { report.Line(" " + Describe(item)); } Dictionary before = Signature(inventory); List list2 = new List(); foreach (ItemData item2 in list) { list2.Add(TradeItem.From(item2, item2.m_stack)); } foreach (ItemData item3 in list) { inventory.RemoveItem(item3); } TradeRpc.ForTesting.SendDeposit(6217583538779652097L, localPlayer.GetPlayerName(), list2); TradeEscrow.Deposit deposit = TradeEscrow.ForTesting.Find(uID); if (deposit == null) { report.Fail("escrow never took the deposit in - RPC_Deposit refused it."); RestoreIfMissing(report, inventory, before, list2); return; } string text = TradeEscrow.IdOf(deposit); report.Check(Diff(before, Signature(inventory)).Count > 0, "the items have left your inventory"); report.Check(!TradeEscrow.ForTesting.IsSent(deposit), "nothing was delivered - there is no counterpart to match"); double unmatchedTimeout = TradeEscrow.ForTesting.UnmatchedTimeout; report.Line($" ageing the record past the {unmatchedTimeout:F0}s unmatched timeout and running the sweep."); TradeEscrow.ForTesting.Backdate(deposit, unmatchedTimeout + 5.0); TradeEscrow.ForTesting.ForceTick(); report.Check(TradeEscrow.ForTesting.PartnerOf(deposit) == uID, "the sweep re-addressed the deposit to you, so it is now a normal pending delivery"); TradeRpc.ClaimPending(); report.Check(TradeInbox.AlreadyApplied(text), "the delivery ledger remembers " + text); report.Check(TradeEscrow.Count == 0, "escrow is empty"); report.Check(EscrowFileIsEmpty(), "trades.json on disk holds no deposits"); List list3 = Diff(before, Signature(inventory)); report.Check(list3.Count == 0, "your inventory is EXACTLY as it was before the deposit"); foreach (string item4 in list3) { report.Line(" " + item4); } } private static void Claim(TestReport report) { Inventory inventory = ((Humanoid)Player.m_localPlayer).GetInventory(); Dictionary before = Signature(inventory); report.Line($"claim: escrow is holding {TradeEscrow.Count} deposit(s) before the ask."); TradeRpc.ClaimPending(); List list = Diff(before, Signature(inventory)); if (list.Count == 0) { report.Line(" nothing arrived. Either escrow held nothing for you, or your ledger says you have already been paid for what it holds."); } else { foreach (string item in list) { report.Line(" " + item); } } report.Line($" escrow is holding {TradeEscrow.Count} deposit(s) now."); } private static void Status(TestReport report) { long num = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.GetUID() : 0); report.Line(string.Format("you are {0:x}; the harness's synthetic partner is {1:x} ({2}).", num, 6217583538779652097L, "Test Partner")); report.Line("escrow : " + TradeEscrow.FilePath); List list = TradeEscrow.ForTesting.All(); if (list.Count == 0) { report.Line(" holding nothing."); } foreach (TradeEscrow.Deposit item in list) { report.Line(" " + TradeEscrow.IdOf(item)); report.Line($" from {TradeEscrow.PartyOf(item):x} ({TradeEscrow.NameOf(item)}) " + $"to {TradeEscrow.ForTesting.PartnerOf(item):x}" + (TradeEscrow.IsRefund(item) ? " [refund, on its way home]" : string.Empty)); report.Line($" {TradeEscrow.ForTesting.ItemCountOf(item)} item(s), " + (TradeEscrow.ForTesting.IsSent(item) ? "sent" : "not sent") + ", " + (TradeEscrow.ForTesting.IsCollected(item) ? "acknowledged" : "NOT acknowledged") + ", " + $"age {TradeEscrow.ForTesting.AgeSeconds(item):F0}s"); List list2 = TradeEscrow.ItemsOf(item); if (list2 == null) { continue; } foreach (TradeItem item2 in list2) { report.Line(" " + item2.DisplayName()); } } report.Line("ledger : " + TradeInbox.FilePath); report.Line($" {CountLedgerEntries()} delivery(ies) remembered on disk."); } private static List Pick(Inventory inventory, int count, out string note) { note = string.Empty; List list = new List(); List list2 = new List(); foreach (ItemData item in new List(inventory.GetAllItems())) { if (item?.m_shared != null && !((Object)(object)item.m_dropPrefab == (Object)null) && !item.m_equipped) { if (item.m_shared.m_maxStackSize <= 1) { list.Add(item); } else { list2.Add(item); } } } List list3 = new List(); foreach (ItemData item2 in list) { if (list3.Count >= count) { break; } list3.Add(item2); } if (list3.Count < count && list2.Count > 0) { foreach (ItemData item3 in list2) { if (list3.Count >= count) { break; } list3.Add(item3); } note = "using stackable items - if one of them merges into a stack you already hold, vanilla's AddItem keeps the stack it merged INTO, and a difference below may be that rather than the trade. Carry a few pieces of gear to test cleanly."; } return list3; } private static void RestoreIfMissing(TestReport report, Inventory inventory, Dictionary before, List payload) { bool flag = false; foreach (string item in Diff(before, Signature(inventory))) { if (item.StartsWith("LOST", StringComparison.Ordinal)) { flag = true; } } if (!flag) { report.Line(" your items are back in your inventory - the refused deposit was echoed straight back."); return; } int num = 0; foreach (TradeItem item2 in payload) { ItemData val = item2.Rebuild(); if (val != null && inventory.AddItem(val)) { num++; } } report.Line($" the harness has put {num} of {payload.Count} item(s) back into your inventory by " + "hand. Check them over before trading anything for real."); } private static Dictionary Signature(Inventory inventory) { Dictionary dictionary = new Dictionary(StringComparer.Ordinal); foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem?.m_shared != null) { string key = KeyOf(allItem); dictionary.TryGetValue(key, out var value); dictionary[key] = value + Mathf.Max(1, allItem.m_stack); } } return dictionary; } private static List Diff(Dictionary before, Dictionary after) { List list = new List(); foreach (KeyValuePair item in before) { after.TryGetValue(item.Key, out var value); if (value != item.Value) { list.Add((value < item.Value) ? $"LOST {item.Value - value} of {item.Key}" : $"GAINED {value - item.Value} of {item.Key}"); } } foreach (KeyValuePair item2 in after) { if (!before.ContainsKey(item2.Key)) { list.Add($"APPEARED {item2.Value} of {item2.Key}"); } } return list; } private static string KeyOf(ItemData item) { return Key(((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : "(no prefab)", item.m_quality, item.m_variant, item.m_durability, item.m_crafterID, item.m_crafterName, item.m_worldLevel, item.m_pickedUp, item.m_customData); } private static string KeyOf(TradeItem item) { return Key(item.PrefabName, item.Quality, item.Variant, item.Durability, item.CrafterID, item.CrafterName, item.WorldLevel, item.PickedUp, item.CustomData) + $" x{item.Stack}"; } private static string Key(string prefab, int quality, int variant, float durability, long crafterId, string crafterName, int worldLevel, bool pickedUp, Dictionary custom) { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(prefab).Append(" q").Append(quality) .Append(" v") .Append(variant) .Append(" d") .Append(durability.ToString("R", CultureInfo.InvariantCulture)) .Append(" by") .Append(crafterId) .Append(':') .Append(crafterName ?? string.Empty) .Append(" w") .Append(worldLevel) .Append(pickedUp ? " picked" : string.Empty); if (custom == null || custom.Count == 0) { return stringBuilder.ToString(); } List list = new List(custom.Keys); list.Sort(StringComparer.Ordinal); stringBuilder.Append(" {"); foreach (string item in list) { stringBuilder.Append(item).Append('=').Append(custom[item]) .Append(';'); } stringBuilder.Append('}'); return stringBuilder.ToString(); } private static void CompareFields(ItemData original, ItemData rebuilt, List problems) { string text = (((Object)(object)original.m_dropPrefab != (Object)null) ? ((Object)original.m_dropPrefab).name : string.Empty); string text2 = (((Object)(object)rebuilt.m_dropPrefab != (Object)null) ? ((Object)rebuilt.m_dropPrefab).name : string.Empty); if (text != text2) { problems.Add("prefab: " + text + " -> " + text2); } if (original.m_stack != rebuilt.m_stack) { problems.Add($"stack: {original.m_stack} -> {rebuilt.m_stack}"); } if (original.m_quality != rebuilt.m_quality) { problems.Add($"quality: {original.m_quality} -> {rebuilt.m_quality}"); } if (original.m_durability != rebuilt.m_durability) { problems.Add($"durability: {original.m_durability:R} -> {rebuilt.m_durability:R}"); } if (original.m_crafterID != rebuilt.m_crafterID) { problems.Add($"crafter id: {original.m_crafterID} -> {rebuilt.m_crafterID}"); } if ((original.m_crafterName ?? string.Empty) != (rebuilt.m_crafterName ?? string.Empty)) { problems.Add("crafter name: \"" + original.m_crafterName + "\" -> \"" + rebuilt.m_crafterName + "\""); } if (original.m_worldLevel != rebuilt.m_worldLevel) { problems.Add($"world level: {original.m_worldLevel} -> {rebuilt.m_worldLevel}"); } if (original.m_pickedUp != rebuilt.m_pickedUp) { problems.Add($"picked up: {original.m_pickedUp} -> {rebuilt.m_pickedUp}"); } if (original.m_variant != rebuilt.m_variant) { int valueOrDefault = (rebuilt.m_shared?.m_icons?.Length).GetValueOrDefault(); problems.Add($"variant: {original.m_variant} -> {rebuilt.m_variant} " + $"(Rebuild clamps to the prefab's {valueOrDefault} icon(s) - a difference here means this " + "item's variant is outside that range and would change appearance on arrival)"); } CompareCustomData(original.m_customData, rebuilt.m_customData, problems); } private static void CompareCustomData(Dictionary sent, Dictionary got, List problems) { if (sent == null || sent.Count == 0) { if (got != null && got.Count > 0) { problems.Add($"custom data: nothing sent, {got.Count} key(s) arrived"); } return; } if (got == null) { problems.Add($"custom data: {sent.Count} key(s) sent, the dictionary itself is missing"); return; } foreach (KeyValuePair item in sent) { if (!got.TryGetValue(item.Key, out var value)) { problems.Add("custom data: \"" + item.Key + "\" was LOST - another mod's per-item state would be destroyed by a trade"); } else if (value != item.Value) { problems.Add("custom data: \"" + item.Key + "\" changed, \"" + item.Value + "\" -> \"" + value + "\""); } } foreach (KeyValuePair item2 in got) { if (!sent.ContainsKey(item2.Key)) { problems.Add("custom data: \"" + item2.Key + "\" appeared from nowhere"); } } } private static bool FileMentions(string path, string needle) { try { return File.Exists(path) && !string.IsNullOrEmpty(needle) && File.ReadAllText(path).Contains(needle); } catch (Exception ex) { Log.LogWarning((object)("could not read " + path + ": " + ex.Message)); return false; } } private static bool EscrowFileIsEmpty() { try { if (!File.Exists(TradeEscrow.FilePath)) { return true; } string text = File.ReadAllText(TradeEscrow.FilePath); int num = text.IndexOf("\"deposits\"", StringComparison.OrdinalIgnoreCase); return num < 0 || text.IndexOf("\"id\"", num, StringComparison.OrdinalIgnoreCase) < 0; } catch (Exception ex) { Log.LogWarning((object)("could not read " + TradeEscrow.FilePath + ": " + ex.Message)); return false; } } private static int CountLedgerEntries() { try { if (!File.Exists(TradeInbox.FilePath)) { return 0; } JToken obj = JObject.Parse(File.ReadAllText(TradeInbox.FilePath))["applied"]; JToken obj2 = ((obj is JArray) ? obj : null); return (obj2 != null) ? ((JContainer)obj2).Count : 0; } catch (Exception ex) { Log.LogWarning((object)("could not read " + TradeInbox.FilePath + ": " + ex.Message)); return -1; } } private static string Describe(ItemData item) { string obj = ((item.m_shared != null && Localization.instance != null) ? Localization.instance.Localize(item.m_shared.m_name) : (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : "?")); string text = ((item.m_quality > 1) ? $" *{item.m_quality}" : string.Empty); string text2 = ((item.m_stack > 1) ? $" x{item.m_stack}" : string.Empty); return obj + text + text2; } } internal static class TradeWindow { [CompilerGenerated] private static class <>O { public static WindowFunction <0>__DrawWindow; } public const string WindowId = "VikingOS_TradeWindow"; private static readonly int GuiWindowId = StringExtensionMethods.GetStableHashCode("VikingOS_TradeWindow"); private static Rect _rect; private static bool _rectInitialised; private static Vector2 _committedPos = new Vector2(float.NaN, float.NaN); private static Rect _dropZone; public static bool IsOpen => TradeRpc.Busy; public static Rect DropZone => _dropZone; public static bool DropZoneKnown { get; private set; } public static Rect PanelRect { get { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (!IsOpen) { return new Rect(0f, 0f, 0f, 0f); } return _rect; } } public static void ResetSession() { //IL_001a: 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) DropZoneKnown = false; _dropZone = new Rect(0f, 0f, 0f, 0f); } public static void BringToFront() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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_003e: 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) Vector2 val = Size(); _rectInitialised = true; _rect = new Rect(((float)Screen.width - val.x) * 0.5f, ((float)Screen.height - val.y) * 0.5f, val.x, val.y); ClampToScreen(); } public static void Draw() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Expected O, but got Unknown if (!SessionState.IsLive || !IsOpen) { DropZoneKnown = false; UIFocus.SetWantsCursor("VikingOS_TradeWindow", active: false); return; } ConfigManager.ApplyTheme(); UIFocus.SetWantsCursor("VikingOS_TradeWindow", active: true); Vector2 val = Size(); if (!_rectInitialised) { _rectInitialised = true; _rect = new Rect(ConfigManager.tradeWindowX.Value, ConfigManager.tradeWindowY.Value, val.x, val.y); } ((Rect)(ref _rect)).width = val.x; ((Rect)(ref _rect)).height = val.y; int guiWindowId = GuiWindowId; Rect rect = _rect; object obj = <>O.<0>__DrawWindow; if (obj == null) { WindowFunction val2 = DrawWindow; <>O.<0>__DrawWindow = val2; obj = (object)val2; } _rect = GUI.Window(guiWindowId, rect, (WindowFunction)obj, GUIContent.none, GUIStyle.none); ClampToScreen(); CommitPositionIfSettled(); } private static Vector2 Size() { //IL_0036: Unknown result type (might be due to invalid IL or missing references) return new Vector2(Mathf.Min(GiltFrameTheme.S(620f), (float)Screen.width * 0.6f), Mathf.Min(GiltFrameTheme.S(480f), (float)Screen.height * 0.7f)); } private static void ClampToScreen() { float num = GiltFrameTheme.S(28f); ((Rect)(ref _rect)).x = Mathf.Clamp(((Rect)(ref _rect)).x, 0f - ((Rect)(ref _rect)).width + num, (float)Screen.width - num); ((Rect)(ref _rect)).y = Mathf.Clamp(((Rect)(ref _rect)).y, 0f, (float)Screen.height - num); } private static void CommitPositionIfSettled() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) if (!Input.GetMouseButton(0) && (_committedPos.x != ((Rect)(ref _rect)).x || _committedPos.y != ((Rect)(ref _rect)).y)) { _committedPos = new Vector2(((Rect)(ref _rect)).x, ((Rect)(ref _rect)).y); ConfigManager.tradeWindowX.Value = ((Rect)(ref _rect)).x; ConfigManager.tradeWindowY.Value = ((Rect)(ref _rect)).y; } } private static void DrawWindow(int id) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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_00af: 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_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_011a: 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) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0144: 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_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) DropZoneKnown = false; Rect val = default(Rect); ((Rect)(ref val))..ctor(0f, 0f, ((Rect)(ref _rect)).width, ((Rect)(ref _rect)).height); GiltFrameTheme.DrawPanelFill(val); GiltFrameTheme.DrawFrame(val); string text = ((TradeRpc.State == TradeRpc.Phase.Invited) ? "TRADE REQUEST" : ("TRADE — " + TradeRpc.PartnerName.ToUpperInvariant())); GiltFrameTheme.DrawShadowed(new Rect(32f, 26f, ((Rect)(ref val)).width - 36f - 28f, GiltFrameTheme.TitleHeight - 20f), text, GiltFrameTheme.Title); GUI.DragWindow(new Rect(0f, 0f, ((Rect)(ref val)).width, 18f + GiltFrameTheme.TitleHeight)); GiltFrameTheme.DrawRule(new Rect(40f, 18f + GiltFrameTheme.TitleHeight - 12f, ((Rect)(ref val)).width - 80f, 1f)); Rect body = GiltFrameTheme.Body(val); switch (TradeRpc.State) { case TradeRpc.Phase.Invited: DrawInvitePrompt(body); break; case TradeRpc.Phase.Inviting: DrawWaiting(body, "Waiting for " + TradeRpc.PartnerName + " to answer..."); break; case TradeRpc.Phase.Settling: DrawWaiting(body, "Both sides confirmed. The server is holding the goods and completing the swap."); break; default: DrawTable(body, val); break; } GiltFrameTheme.DrawShadowed(GiltFrameTheme.FooterLine(val), TradeRpc.Status, GiltFrameTheme.Footer); } private static void DrawInvitePrompt(Rect body) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) float num = GiltFrameTheme.S(30f); float num2 = GiltFrameTheme.S(10f); GUI.Label(new Rect(((Rect)(ref body)).x, ((Rect)(ref body)).y, ((Rect)(ref body)).width, num * 2f), TradeRpc.PartnerName + " wants to trade with you.", GiltFrameTheme.Header); float num3 = (((Rect)(ref body)).width - num2) * 0.5f; float num4 = ((Rect)(ref body)).y + num * 2f + num2; if (GUI.Button(new Rect(((Rect)(ref body)).x, num4, num3, num), "Accept", GiltFrameTheme.Primary)) { TradeRpc.AcceptInvite(); } if (GUI.Button(new Rect(((Rect)(ref body)).x + num3 + num2, num4, num3, num), "Decline", GiltFrameTheme.Button)) { TradeRpc.DeclineInvite(); } } private static void DrawWaiting(Rect body, string message) { //IL_002f: 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) float num = GiltFrameTheme.S(30f); GUI.Label(new Rect(((Rect)(ref body)).x, ((Rect)(ref body)).y, ((Rect)(ref body)).width, ((Rect)(ref body)).height - num * 2f), message, GiltFrameTheme.Note); if (TradeRpc.State == TradeRpc.Phase.Inviting && GUI.Button(new Rect(((Rect)(ref body)).x, ((Rect)(ref body)).yMax - num, ((Rect)(ref body)).width, num), "Cancel", GiltFrameTheme.Button)) { TradeRpc.Cancel("changed their mind"); } } private static void DrawTable(Rect body, Rect win) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) float rowH = GiltFrameTheme.S(26f); float num = GiltFrameTheme.S(10f); float num2 = GiltFrameTheme.S(22f); float num3 = GiltFrameTheme.S(30f); float num4 = (((Rect)(ref body)).width - num) * 0.5f; float num5 = ((Rect)(ref body)).y + num2 + GiltFrameTheme.S(4f); float num6 = ((Rect)(ref body)).height - num2 - num3 * 2f - num * 3f; GiltFrameTheme.DrawShadowed(new Rect(((Rect)(ref body)).x, ((Rect)(ref body)).y, num4, num2), MyReadyMark() + "YOU OFFER", GiltFrameTheme.Header); Rect val = new Rect(((Rect)(ref body)).x, num5, num4, num6); GiltFrameTheme.DrawInset(val); DrawMyOffer(val, rowH); _dropZone = GUIUtility.GUIToScreenRect(val); DropZoneKnown = true; GiltFrameTheme.DrawShadowed(new Rect(((Rect)(ref body)).x + num4 + num, ((Rect)(ref body)).y, num4, num2), TheirReadyMark() + TradeRpc.PartnerName.ToUpperInvariant() + " OFFERS", GiltFrameTheme.Header); Rect val2 = new Rect(((Rect)(ref body)).x + num4 + num, num5, num4, num6); GiltFrameTheme.DrawInset(val2); DrawTheirOffer(val2, rowH); float num7 = num5 + num6 + num; string text = (TradeRpc.MyReady ? "✔ Confirmed — click to withdraw" : "Confirm this trade"); GUIStyle val3 = (TradeRpc.MyReady ? GiltFrameTheme.Primary : GiltFrameTheme.Button); if (GUI.Button(new Rect(((Rect)(ref body)).x, num7, ((Rect)(ref body)).width, num3), text, val3)) { TradeRpc.SetReady(!TradeRpc.MyReady); } num7 += num3 + num; if (GUI.Button(new Rect(((Rect)(ref body)).x, num7, ((Rect)(ref body)).width, num3), "Cancel trade", GiltFrameTheme.Button)) { TradeRpc.Cancel("cancelled"); } } private static string MyReadyMark() { if (!TradeRpc.MyReady) { return ""; } return "✔ "; } private static string TheirReadyMark() { if (!TradeRpc.TheirReady) { return ""; } return "✔ "; } private static void DrawMyOffer(Rect area, float rowH) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginArea(new Rect(((Rect)(ref area)).x + 4f, ((Rect)(ref area)).y + 4f, ((Rect)(ref area)).width - 8f, ((Rect)(ref area)).height - 8f)); if (TradeRpc.MyOffer.Count == 0) { GUILayout.Label(CarryingItem() ? "Release here to offer it" : "Drag items here from your inventory", GiltFrameTheme.Note, Array.Empty()); } for (int i = 0; i < TradeRpc.MyOffer.Count; i++) { GUILayout.BeginHorizontal(Array.Empty()); GUILayout.Label(TradeRpc.MyOffer[i].DisplayName(), GiltFrameTheme.Value, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(rowH) }); GUI.enabled = !TradeRpc.MyReady; if (GUILayout.Button("×", GiltFrameTheme.Button, (GUILayoutOption[])(object)new GUILayoutOption[2] { GUILayout.Width(GiltFrameTheme.S(26f)), GUILayout.Height(rowH) })) { TradeRpc.RemoveFromOffer(i); GUI.enabled = true; GUILayout.EndHorizontal(); break; } GUI.enabled = true; GUILayout.EndHorizontal(); } GUILayout.EndArea(); if (CarryingItem() && ((Rect)(ref area)).Contains(GuiMouse())) { GiltFrameTheme.DrawSelection(area); } } private static void DrawTheirOffer(Rect area, float rowH) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginArea(new Rect(((Rect)(ref area)).x + 4f, ((Rect)(ref area)).y + 4f, ((Rect)(ref area)).width - 8f, ((Rect)(ref area)).height - 8f)); List theirOffer = TradeRpc.TheirOffer; if (theirOffer.Count == 0) { GUILayout.Label("Nothing offered yet.", GiltFrameTheme.Note, Array.Empty()); } for (int i = 0; i < theirOffer.Count; i++) { GUILayout.Label(theirOffer[i].DisplayName(), GiltFrameTheme.Value, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(rowH) }); } GUILayout.EndArea(); } private static bool CarryingItem() { InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance != (Object)null) { return (Object)(object)instance.m_dragGo != (Object)null; } return false; } private static Vector2 GuiMouse() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) return new Vector2(Input.mousePosition.x, (float)Screen.height - Input.mousePosition.y); } } } namespace BarrkUI.Layout { [HarmonyPatch] internal static class LayoutBars { private const float MinBarWidth = 8f; private static readonly HashSet _widthDriven = new HashSet(); private static int _knownHud; public static void Forget() { _widthDriven.Clear(); _knownHud = 0; } public static bool IsWidthDriven(RectTransform rt) { if ((Object)(object)rt != (Object)null && _widthDriven.Count > 0) { return _widthDriven.Contains(((Object)rt).GetInstanceID()); } return false; } private static void Track(Hud hud) { if (!((Object)(object)hud == (Object)null)) { int instanceID = ((Object)hud).GetInstanceID(); if (_knownHud != instanceID) { _knownHud = instanceID; _widthDriven.Clear(); Add(hud.m_healthBarRoot); Add(hud.m_staminaBar2Root); Add(hud.m_eitrBarRoot); Add(hud.m_adrenalineBarRoot); } } } private static void Add(RectTransform rt) { if ((Object)(object)rt != (Object)null) { _widthDriven.Add(((Object)rt).GetInstanceID()); } } private static float WidthDelta(RectTransform root) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)root == (Object)null)) { return LayoutEngine.GetSizeFor(root).x; } return 0f; } [HarmonyPatch(typeof(Hud), "SetHealthBarSize")] [HarmonyPrefix] private static void HealthBarSize(Hud __instance, ref float size) { Track(__instance); size = Adjust(size, WidthDelta(__instance.m_healthBarRoot)); } [HarmonyPatch(typeof(Hud), "SetStaminaBarSize")] [HarmonyPrefix] private static void StaminaBarSize(Hud __instance, ref float size) { Track(__instance); size = Adjust(size, WidthDelta(__instance.m_staminaBar2Root)); } [HarmonyPatch(typeof(Hud), "SetEitrBarSize")] [HarmonyPrefix] private static void EitrBarSize(Hud __instance, ref float size) { Track(__instance); size = Adjust(size, WidthDelta(__instance.m_eitrBarRoot)); } [HarmonyPatch(typeof(Hud), "SetAdrenalineBarSize")] [HarmonyPrefix] private static void AdrenalineBarSize(Hud __instance, ref float size) { Track(__instance); size = Adjust(size, WidthDelta(__instance.m_adrenalineBarRoot)); } private static float Adjust(float size, float delta) { if (float.IsNaN(delta) || float.IsInfinity(delta)) { return size; } if (delta == 0f) { return size; } float num = size + delta; if (!float.IsNaN(num) && !float.IsInfinity(num)) { return Mathf.Max(8f, num); } return size; } } internal static class LayoutEditor { private struct Handle { public LayoutTarget Target; public Rect GuiRect; public Vector2 UnitsPerPixel; } public const string WindowId = "VikingOS_LayoutEditor"; private const float HandleMinSize = 24f; private const float ScrollScaleStep = 0.05f; private const float KeyNudgeUnits = 1f; private const float QuarterTurn = 90f; private const float FineRotationStep = 15f; private const float GroupGrabBand = 10f; private static bool _active; private const float GripSize = 14f; private static bool _hoveredIsGroupGrab; private static bool _draggingIsGroupGrab; private static LayoutTarget _hovered; private static LayoutTarget _resizing; private static int _resizeH; private static int _resizeV; private static LayoutTarget _dragging; private static LayoutTarget _lastTouched; private static bool _pendingCommit; private static Rect _menuRect; private static Vector2 _dragStartMouse; private static Vector2 _dragStartOffset; private static Rect _dragStartRect; private static Vector2 _resizeStartMouse; private static Rect _resizeStartRect; private static Vector2 _resizeApplied; private static readonly List _handles = new List(); private static int _handlesBuiltOnFrame = -1; private static LayoutTarget _pinned; private static float _pinnedFlashUntil; private const float MenuFlashSeconds = 4f; public static bool Active => _active; public static bool HasMenuSelection => _pinned != null; public static void OnMenuSelected(LayoutTarget target) { if (target != null) { _lastTouched = target; _pinned = target; _pinnedFlashUntil = Time.unscaledTime + 4f; } } public static void ClearMenuSelection() { _pinned = null; _pinnedFlashUntil = 0f; } public static void Toggle() { SetActive(!_active); } public static void SetActive(bool active) { if (_active != active) { _active = active; _dragging = null; _hovered = null; ClearMenuSelection(); UIFocus.SetWantsCursor("VikingOS_LayoutEditor", active); UIFocus.SetBlocksGameInput("VikingOS_LayoutEditor", active); if (!active) { LayoutMenu.ForgetTextFocus(); UIFocus.SetHasTextFocus("VikingOS_LayoutEditor", active: false); Commit(); } Diagnostics.Trace(() => "layout editor " + (active ? "opened" : "closed")); } } public static void Tick() { //IL_001a: 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_0022: Unknown result type (might be due to invalid IL or missing references) if (_active && !SessionState.PlayerReady) { SetActive(active: false); return; } KeyboardShortcut value = ConfigManager.layoutEditorKey.Value; if ((int)((KeyboardShortcut)(ref value)).MainKey != 0 && ((KeyboardShortcut)(ref value)).IsDown() && !TypingSomewhere()) { Toggle(); } else if (_active) { if (LayoutMenu.HasTextFocus) { UIFocus.SetHasTextFocus("VikingOS_LayoutEditor", active: true); return; } UIFocus.SetHasTextFocus("VikingOS_LayoutEditor", active: false); HandlePanelKeys(); HandleScroll(); HandleKeys(); } } private static void HandlePanelKeys() { //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Invalid comparison between Unknown and I4 if (ChatInputFocused() || Console.IsVisible() || TextInput.IsVisible() || Minimap.InTextInput() || Menu.IsVisible()) { return; } if (ZInput.GetButtonDown("Inventory")) { ZInput.ResetButtonStatus("Inventory"); InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance != (Object)null) { if (InventoryGui.IsVisible()) { instance.Hide(); } else { instance.Show((Container)null, 1); } } } if (ZInput.GetButtonDown("Map") && (Object)(object)Minimap.instance != (Object)null) { ZInput.ResetButtonStatus("Map"); Minimap.instance.SetMapMode((MapMode)(((int)Minimap.instance.m_mode == 2) ? 1 : 2)); } } private static bool TypingSomewhere() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: 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) if (LayoutMenu.HasTextFocus) { return false; } KeyboardShortcut value = ConfigManager.layoutEditorKey.Value; if (!ProducesNoCharacter(((KeyboardShortcut)(ref value)).MainKey)) { if (UIFocus.HasTextFocus) { return true; } if (ChatInputFocused()) { return true; } if (Console.IsVisible()) { return true; } if (TextInput.IsVisible()) { return true; } if (Minimap.InTextInput()) { return true; } } return false; } private static bool ChatInputFocused() { Chat instance = Chat.instance; if ((Object)(object)instance != (Object)null && (Object)(object)((Terminal)instance).m_chatWindow != (Object)null && ((Component)((Terminal)instance).m_chatWindow).gameObject.activeInHierarchy && (Object)(object)((Terminal)instance).m_input != (Object)null) { return ((TMP_InputField)((Terminal)instance).m_input).isFocused; } return false; } private static bool ProducesNoCharacter(KeyCode key) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Invalid comparison between Unknown and I4 if ((int)key >= 282) { return (int)key <= 296; } return false; } private static void HandleScroll() { LayoutTarget layoutTarget = _hovered ?? _pinned; if (layoutTarget != null && layoutTarget.CanScale) { float mouseScrollWheel = ZInput.GetMouseScrollWheel(); if (!Mathf.Approximately(mouseScrollWheel, 0f)) { Resize(layoutTarget, Mathf.Sign(mouseScrollWheel) * 0.05f); } } } private static void HandleKeys() { //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_0127: 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_0136: Unknown result type (might be due to invalid IL or missing references) LayoutTarget layoutTarget = _pinned ?? _hovered ?? _lastTouched; if (layoutTarget != null) { if (ZInput.GetKeyDown((KeyCode)61, true) || ZInput.GetKeyDown((KeyCode)270, true)) { Resize(layoutTarget, 0.05f); } if (ZInput.GetKeyDown((KeyCode)45, true) || ZInput.GetKeyDown((KeyCode)269, true)) { Resize(layoutTarget, -0.05f); } float num = ((ZInput.GetKey((KeyCode)304, true) || ZInput.GetKey((KeyCode)303, true)) ? 15f : 90f); if (ZInput.GetKeyDown((KeyCode)91, true)) { Rotate(layoutTarget, 0f - num); } if (ZInput.GetKeyDown((KeyCode)93, true)) { Rotate(layoutTarget, num); } Vector2 zero = Vector2.zero; if (ZInput.GetKeyDown((KeyCode)276, true)) { zero.x -= 1f; } if (ZInput.GetKeyDown((KeyCode)275, true)) { zero.x += 1f; } if (ZInput.GetKeyDown((KeyCode)273, true)) { zero.y += 1f; } if (ZInput.GetKeyDown((KeyCode)274, true)) { zero.y -= 1f; } if (!(zero == Vector2.zero)) { LayoutEngine.Nudge(layoutTarget, zero); _lastTouched = layoutTarget; Touch(layoutTarget); } } } private static void Resize(LayoutTarget target, float delta) { LayoutEngine.SetScale(target, LayoutEngine.GetScale(target) + delta); _lastTouched = target; Touch(target); } private static void Rotate(LayoutTarget target, float degrees) { LayoutEngine.SetRotation(target, LayoutEngine.GetRotation(target) + degrees); _lastTouched = target; Touch(target); } private static void Touch(LayoutTarget target) { LayoutEngine.ClampToScreen(target); _pendingCommit = true; } private static void Commit() { if (_pendingCommit) { _pendingCommit = false; LayoutEngine.Commit(); } } public static void Draw() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (_active && SessionState.PlayerReady) { ConfigManager.ApplyTheme(); if (_handlesBuiltOnFrame != Time.frameCount) { RebuildHandles(); } _menuRect = LayoutMenu.CurrentRect; HandleMouse(); DrawHandles(); LayoutMenu.Draw(); } } private static void RebuildHandles() { //IL_00f1: 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_00fb: Unknown result type (might be due to invalid IL or missing references) _handlesBuiltOnFrame = Time.frameCount; _handles.Clear(); Rect guiRect = default(Rect); foreach (LayoutTarget target in LayoutEngine.Targets) { if (LayoutEngine.TryGetScreenRect(target, out var screenRect, out var unitsPerPixel)) { ((Rect)(ref guiRect))..ctor(((Rect)(ref screenRect)).x, (float)Screen.height - ((Rect)(ref screenRect)).yMax, ((Rect)(ref screenRect)).width, ((Rect)(ref screenRect)).height); if (((Rect)(ref guiRect)).width < 24f) { ((Rect)(ref guiRect)).x = ((Rect)(ref guiRect)).x - (24f - ((Rect)(ref guiRect)).width) * 0.5f; ((Rect)(ref guiRect)).width = 24f; } if (((Rect)(ref guiRect)).height < 24f) { ((Rect)(ref guiRect)).y = ((Rect)(ref guiRect)).y - (24f - ((Rect)(ref guiRect)).height) * 0.5f; ((Rect)(ref guiRect)).height = 24f; } _handles.Add(new Handle { Target = target, GuiRect = guiRect, UnitsPerPixel = unitsPerPixel }); } } } private static void HandleMouse() { //IL_0007: 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_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0019: 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) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0271: Unknown result type (might be due to invalid IL or missing references) //IL_0288: Expected I4, but got Unknown //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_038a: Unknown result type (might be due to invalid IL or missing references) //IL_038b: Unknown result type (might be due to invalid IL or missing references) //IL_0390: Unknown result type (might be due to invalid IL or missing references) //IL_0395: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_03ff: Unknown result type (might be due to invalid IL or missing references) //IL_0404: Unknown result type (might be due to invalid IL or missing references) //IL_040d: Unknown result type (might be due to invalid IL or missing references) //IL_0418: Unknown result type (might be due to invalid IL or missing references) //IL_0422: Unknown result type (might be due to invalid IL or missing references) //IL_042d: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Unknown result type (might be due to invalid IL or missing references) //IL_0437: Unknown result type (might be due to invalid IL or missing references) //IL_043e: Unknown result type (might be due to invalid IL or missing references) //IL_0445: Unknown result type (might be due to invalid IL or missing references) //IL_044a: Unknown result type (might be due to invalid IL or missing references) //IL_03b0: Unknown result type (might be due to invalid IL or missing references) //IL_03c2: Unknown result type (might be due to invalid IL or missing references) //IL_03e3: Unknown result type (might be due to invalid IL or missing references) //IL_03e5: Unknown result type (might be due to invalid IL or missing references) //IL_03e7: Unknown result type (might be due to invalid IL or missing references) //IL_03ec: Unknown result type (might be due to invalid IL or missing references) //IL_03f1: Unknown result type (might be due to invalid IL or missing references) //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02e5: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: 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) Event current = Event.current; Vector2 mousePosition = current.mousePosition; if (_dragging == null && ((Rect)(ref _menuRect)).Contains(mousePosition)) { _hovered = null; return; } if ((int)current.type == 0 && LayoutMenu.HasTextFocus) { GUI.FocusControl((string)null); LayoutMenu.ForgetTextFocus(); } if (_resizing != null) { HandleResizeDrag(current, mousePosition); return; } if (_dragging == null) { if ((int)current.type == 0 && current.button == 0 && TryStartResize(mousePosition)) { current.Use(); return; } _hovered = null; _hoveredIsGroupGrab = false; bool flag = SectionModeWanted(current); float num = float.MaxValue; Handle handle; if (!flag) { float band = GiltFrameTheme.S(10f); for (int i = 0; i < _handles.Count; i++) { if (_handles[i].Target.IsGroup && OnBorder(_handles[i].GuiRect, mousePosition, band)) { handle = _handles[i]; float width = ((Rect)(ref handle.GuiRect)).width; handle = _handles[i]; float num2 = width * ((Rect)(ref handle.GuiRect)).height; if (!(num2 >= num)) { num = num2; _hovered = _handles[i].Target; _hoveredIsGroupGrab = true; } } } } if (_hovered == null) { num = float.MaxValue; for (int j = 0; j < _handles.Count; j++) { handle = _handles[j]; if (((Rect)(ref handle.GuiRect)).Contains(mousePosition)) { handle = _handles[j]; float width2 = ((Rect)(ref handle.GuiRect)).width; handle = _handles[j]; float num3 = width2 * ((Rect)(ref handle.GuiRect)).height; if (!(num3 >= num)) { num = num3; _hovered = _handles[j].Target; } } } if (flag) { _hovered = SectionOf(_hovered); } _hoveredIsGroupGrab = _hovered != null && _hovered.IsGroup; } if (_pinned != null) { Handle handle2 = HandleFor(_pinned); if (((Rect)(ref handle2.GuiRect)).width > 0f && ((Rect)(ref handle2.GuiRect)).Contains(mousePosition)) { _hovered = _pinned; _hoveredIsGroupGrab = _pinned.IsGroup; } } } EventType type = current.type; switch ((int)type) { case 0: if (_hovered != null && current.button == 0) { if (_hovered != _pinned) { _pinned = null; } _dragging = _hovered; _draggingIsGroupGrab = _hoveredIsGroupGrab; _lastTouched = _hovered; LayoutMenu.Select(_hovered); _dragStartMouse = mousePosition; _dragStartOffset = LayoutEngine.GetOffset(_hovered); _dragStartRect = HandleFor(_hovered).GuiRect; LayoutSnap.Build(_hovered, null); current.Use(); } else if (_hovered == null && current.button == 0 && (_pinned != null || _lastTouched != null)) { ClearMenuSelection(); _lastTouched = null; LayoutMenu.Select(null); current.Use(); } else if (_hovered != null && current.button == 1) { LayoutEngine.Reset(_hovered); _pendingCommit = true; Commit(); current.Use(); } break; case 3: if (_dragging != null) { Vector2 val = mousePosition - _dragStartMouse; LayoutSnap.Clear(); if (LayoutSnap.Wanted(current)) { Rect wouldBe = default(Rect); ((Rect)(ref wouldBe))..ctor(((Rect)(ref _dragStartRect)).x + val.x, ((Rect)(ref _dragStartRect)).y + val.y, ((Rect)(ref _dragStartRect)).width, ((Rect)(ref _dragStartRect)).height); val += LayoutSnap.ForBox(wouldBe); } Handle handle3 = HandleFor(_dragging); Vector2 val2 = _dragStartOffset + new Vector2(val.x * handle3.UnitsPerPixel.x, (0f - val.y) * handle3.UnitsPerPixel.y); LayoutEngine.Nudge(_dragging, val2 - LayoutEngine.GetOffset(_dragging)); _pendingCommit = true; current.Use(); } break; case 1: if (_dragging != null) { Diagnostics.Trace(() => $"layout editor: moved {_dragging.Label} to offset {LayoutEngine.GetOffset(_dragging)}"); Touch(_dragging); _dragging = null; LayoutSnap.Clear(); Commit(); current.Use(); } break; case 2: break; } } private static LayoutTarget GripOwner() { return _resizing ?? _dragging ?? _hovered ?? _pinned ?? _lastTouched; } private static Rect GripRect(Rect box, int h, int v) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) float num = GiltFrameTheme.S(14f); float num2 = ((h == 1) ? (((Rect)(ref box)).xMax - num) : ((Rect)(ref box)).xMin); float num3 = ((v == 1) ? ((Rect)(ref box)).yMin : (((Rect)(ref box)).yMax - num)); return new Rect(num2, num3, num, num); } private static bool TryStartResize(Vector2 mouse) { //IL_0025: 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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) LayoutTarget layoutTarget = GripOwner(); if (layoutTarget == null) { return false; } Handle handle = HandleFor(layoutTarget); if (handle.Target == null) { return false; } for (int i = 0; i <= 1; i++) { for (int j = 0; j <= 1; j++) { Rect val = GripRect(handle.GuiRect, i, j); if (((Rect)(ref val)).Contains(mouse)) { _resizing = layoutTarget; _resizeH = i; _resizeV = j; _lastTouched = layoutTarget; _resizeStartMouse = mouse; _resizeStartRect = handle.GuiRect; _resizeApplied = Vector2.zero; LayoutSnap.Build(layoutTarget, null); return true; } } } return false; } private static void HandleResizeDrag(Event e, Vector2 mouse) { //IL_0001: 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_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: 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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: 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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: 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_00e9: 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_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) EventType type = e.type; if ((int)type != 1) { if ((int)type == 3) { Vector2 val = mouse - _resizeStartMouse; LayoutSnap.Clear(); if (LayoutSnap.Wanted(e)) { float x = ((_resizeH == 1) ? ((Rect)(ref _resizeStartRect)).xMax : ((Rect)(ref _resizeStartRect)).xMin) + val.x; float y = ((_resizeV == 1) ? ((Rect)(ref _resizeStartRect)).yMin : ((Rect)(ref _resizeStartRect)).yMax) + val.y; val += LayoutSnap.ForEdges(x, y); } Handle handle = HandleFor(_resizing); float num = val.x * handle.UnitsPerPixel.x; float num2 = (0f - val.y) * handle.UnitsPerPixel.y; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor((_resizeH == 1) ? num : (0f - num), (_resizeV == 1) ? num2 : (0f - num2)); Vector2 val3 = val2 - _resizeApplied; Vector2 pivot; Vector2 size; if (val3 == Vector2.zero) { e.Use(); } else if (LayoutEngine.TryGetRectInfo(_resizing, out pivot, out size)) { _resizeApplied = val2; Vector2 anchorCompensation = default(Vector2); ((Vector2)(ref anchorCompensation))..ctor(val3.x * ((_resizeH == 1) ? pivot.x : (0f - (1f - pivot.x))), val3.y * ((_resizeV == 1) ? pivot.y : (0f - (1f - pivot.y)))); LayoutEngine.Resize(_resizing, val3, anchorCompensation); _pendingCommit = true; e.Use(); } } } else { Diagnostics.Trace(() => $"layout editor: resized {_resizing.Label} to {LayoutEngine.GetSize(_resizing)}"); Touch(_resizing); _resizing = null; _resizeApplied = Vector2.zero; LayoutSnap.Clear(); Commit(); e.Use(); } } private static bool SectionModeWanted(Event e) { bool num = ConfigManager.layoutSectionMode == null || ConfigManager.layoutSectionMode.Value; bool flag = e != null && e.control; return num != flag; } public static LayoutTarget SectionOf(LayoutTarget target) { if (target == null) { return null; } LayoutTarget layoutTarget = (target.IsGroup ? target : null); for (int i = 0; i < _handles.Count; i++) { LayoutTarget target2 = _handles[i].Target; if (target2 != target && target2.IsGroup && target.Id.StartsWith(target2.Id + "/", StringComparison.Ordinal) && (layoutTarget == null || target2.Depth < layoutTarget.Depth)) { layoutTarget = target2; } } return layoutTarget ?? target; } private static bool OnBorder(Rect r, Vector2 p, float band) { //IL_0002: 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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) if (!((Rect)(ref r)).Contains(p)) { return false; } if (!(p.x - ((Rect)(ref r)).xMin <= band) && !(((Rect)(ref r)).xMax - p.x <= band) && !(p.y - ((Rect)(ref r)).yMin <= band)) { return ((Rect)(ref r)).yMax - p.y <= band; } return true; } private static Handle HandleFor(LayoutTarget target) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < _handles.Count; i++) { if (_handles[i].Target == target) { return _handles[i]; } } return new Handle { Target = target, UnitsPerPixel = Vector2.one }; } private static void DrawGrips() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: 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) //IL_0071: Unknown result type (might be due to invalid IL or missing references) LayoutTarget layoutTarget = GripOwner(); if (layoutTarget == null) { return; } Handle handle = HandleFor(layoutTarget); if (handle.Target == null) { return; } for (int i = 0; i <= 1; i++) { for (int j = 0; j <= 1; j++) { Rect r = GripRect(handle.GuiRect, i, j); bool flag = _resizing == layoutTarget && _resizeH == i && _resizeV == j; GiltFrameTheme.DrawFill(r, flag ? GiltFrameTheme.MetalBright(0.95f) : GiltFrameTheme.Metal(0.55f)); GiltFrameTheme.DrawOutline(r, GiltFrameTheme.MetalDeep(0.9f), 1f); } } } private static void DrawHandles() { //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: 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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01ff: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: 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_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_036a: Unknown result type (might be due to invalid IL or missing references) //IL_036f: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Unknown result type (might be due to invalid IL or missing references) //IL_0373: Unknown result type (might be due to invalid IL or missing references) //IL_03df: Unknown result type (might be due to invalid IL or missing references) //IL_0385: Unknown result type (might be due to invalid IL or missing references) //IL_0391: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) foreach (Handle handle3 in _handles) { bool flag = handle3.Target == _dragging; bool flag2 = handle3.Target == _hovered; bool flag3 = LayoutEngine.IsCustomised(handle3.Target); Color c = (Color)(flag ? GiltFrameTheme.Metal(0.3f) : (flag2 ? GiltFrameTheme.Metal(0.18f) : (flag3 ? new Color(0.4f, 0.9f, 0.5f, 0.08f) : new Color(1f, 1f, 1f, 0.02f)))); Color c2 = (Color)((flag || flag2) ? GiltFrameTheme.Metal(0.95f) : (flag3 ? new Color(0.4f, 0.9f, 0.5f, 0.45f) : new Color(1f, 1f, 1f, 0.14f))); GiltFrameTheme.DrawFill(handle3.GuiRect, c); if (handle3.Target.IsGroup) { bool flag4 = flag && _draggingIsGroupGrab; bool flag5 = flag2 && _hoveredIsGroupGrab; Color c3 = ((flag4 || flag5) ? new Color(1f, 0.35f, 0.3f, 1f) : new Color(0.85f, 0.2f, 0.18f, 0.7f)); GiltFrameTheme.DrawOutline(handle3.GuiRect, c3, (flag4 || flag5) ? 3f : 2f); } else { GiltFrameTheme.DrawOutline(handle3.GuiRect, c2, 1f); } } LayoutSnap.DrawGuides(); if (_pinned != null) { Handle handle = HandleFor(_pinned); if (((Rect)(ref handle.GuiRect)).width > 0f) { GiltFrameTheme.DrawFill(handle.GuiRect, GiltFrameTheme.Metal(0.18f)); GiltFrameTheme.DrawOutline(handle.GuiRect, GiltFrameTheme.MetalBright(1f), 4f); if (Time.unscaledTime < _pinnedFlashUntil) { float alpha = 0.55f + 0.45f * Mathf.Sin(Time.unscaledTime * 8f); GiltFrameTheme.DrawOutline(new Rect(((Rect)(ref handle.GuiRect)).x - 9f, ((Rect)(ref handle.GuiRect)).y - 9f, ((Rect)(ref handle.GuiRect)).width + 18f, ((Rect)(ref handle.GuiRect)).height + 18f), GiltFrameTheme.Metal(alpha), 3f); } GiltFrameTheme.DrawShadowed(new Rect(((Rect)(ref handle.GuiRect)).x, ((Rect)(ref handle.GuiRect)).yMax + 2f, GiltFrameTheme.S(620f), GiltFrameTheme.S(20f)), "SELECTED · " + _pinned.Label + " · drag it here, nudge it with the arrow keys, or click empty space to let go", GiltFrameTheme.Value); } } DrawGrips(); LayoutTarget layoutTarget = _resizing ?? _dragging ?? _hovered; if (layoutTarget != null) { Handle handle2 = HandleFor(layoutTarget); string text = $"{layoutTarget.Label} x{LayoutEngine.GetScale(layoutTarget):0.##}"; float rotation = LayoutEngine.GetRotation(layoutTarget); if (!Mathf.Approximately(rotation, 0f)) { text += $" {rotation:0}°"; } Vector2 offset = LayoutEngine.GetOffset(layoutTarget); if (offset != Vector2.zero) { text += $" ({offset.x:0.#}, {offset.y:0.#})"; } GiltFrameTheme.DrawShadowed(new Rect(((Rect)(ref handle2.GuiRect)).x, ((Rect)(ref handle2.GuiRect)).y - GiltFrameTheme.S(20f), GiltFrameTheme.S(560f), GiltFrameTheme.S(20f)), text, GiltFrameTheme.Value); } } } internal static class LayoutEngine { private sealed class Baseline { public int InstanceId; public Vector2 AnchoredPosition; public Vector3 LocalScale; public Quaternion LocalRotation; public Vector2 SizeDelta; } private sealed class Entry { public LayoutTarget Target; public Vector2 Offset; public float Scale = 1f; public float Rotation; public Vector2 Size; public Baseline Baseline; public RectTransform Cached; public bool Warned; public bool AppliedPosition; public bool AppliedScale; public bool AppliedRotation; public bool AppliedSize; public Vector2 PendingPosition; public int PendingStreak; public int PendingTotal; } private const float MinVisiblePixels = 32f; private const float MaxOffset = 4000f; private const float MinScale = 0.2f; private const float MaxScale = 5f; private const int StableCaptureFrames = 3; private const int MaxCaptureWait = 60; private const float StableEpsilon = 0.01f; private const float MinSize = 12f; private static readonly List _entries = new List(); private static readonly Dictionary _byId = new Dictionary(); private static int _discoveredForScene = -1; private static readonly Vector3[] _corners = (Vector3[])(object)new Vector3[4]; public static IReadOnlyList Targets => LayoutDiscovery.All; public static int ElementCount => _entries.Count; public static int CustomisedCount { get { int num = 0; foreach (Entry entry in _entries) { if (IsCustomised(entry)) { num++; } } return num; } } public static void Init() { LayoutStore.Load(); } public static void RediscoverSoon() { _discoveredForScene = -1; } private static void EnsureDiscovered() { //IL_008b: 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_0091: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) if (_discoveredForScene == SessionState.SessionId) { return; } _discoveredForScene = SessionState.SessionId; LayoutDiscovery.Discover(); LayoutReflow.Forget(); LayoutBars.Forget(); LayoutUpright.Forget(); _entries.Clear(); _byId.Clear(); foreach (LayoutTarget item in LayoutDiscovery.All) { if (!_byId.ContainsKey(item.Id)) { Entry entry = new Entry { Target = item }; if (LayoutStore.TryGet(item.Id, out var offset, out var scale, out var rotation, out var size)) { entry.Offset = ClampOffset(offset); entry.Scale = Mathf.Clamp(scale, 0.2f, 5f); entry.Rotation = NormaliseAngle(rotation); entry.Size = ClampOffset(size); } _entries.Add(entry); _byId[item.Id] = entry; } } Diagnostics.Health("Layout engine", ok: true, $"{_entries.Count} adjustable elements found, {LayoutStore.Count} customised"); } public static void LateUpdate() { if (!SessionState.PlayerReady) { return; } EnsureDiscovered(); for (int i = 0; i < _entries.Count; i++) { try { Capture(_entries[i]); } catch { } } LayoutUpright.BeginFrame(); for (int j = 0; j < _entries.Count; j++) { try { ApplyOne(_entries[j]); } catch (Exception ex) { if (!_entries[j].Warned) { _entries[j].Warned = true; Diagnostics.Health(_entries[j].Target.Label, ok: false, "could not be laid out and has been left alone. Reason: " + ex.Message); } } } LayoutReflow.ApplyAll(); } private static void Capture(Entry entry) { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01d8: Unknown result type (might be due to invalid IL or missing references) //IL_01dd: Unknown result type (might be due to invalid IL or missing references) RectTransform val = Resolve(entry); if ((Object)(object)val == (Object)null) { entry.Baseline = null; entry.AppliedPosition = false; entry.AppliedScale = false; entry.AppliedRotation = false; entry.AppliedSize = false; return; } Vector2 anchoredPosition; if (entry.Baseline == null || entry.Baseline.InstanceId != ((Object)val).GetInstanceID()) { if (!((Component)val).gameObject.activeInHierarchy) { entry.PendingStreak = 0; entry.PendingTotal = 0; return; } if (!IsFinite(val.anchoredPosition) || !IsFinite(((Transform)val).localScale)) { return; } anchoredPosition = val.anchoredPosition; if (entry.PendingStreak != 0) { Vector2 val2 = anchoredPosition - entry.PendingPosition; if (!(((Vector2)(ref val2)).sqrMagnitude > 0.01f)) { entry.PendingStreak++; goto IL_0129; } } entry.PendingPosition = anchoredPosition; entry.PendingStreak = 1; goto IL_0129; } goto IL_01e7; IL_01e7: if (((Component)val).gameObject.activeInHierarchy) { LayoutReflow.Observe(entry.Target.Id, val); } return; IL_0129: entry.PendingTotal++; if (entry.PendingStreak < 3 && entry.PendingTotal < 60) { return; } if (entry.PendingTotal >= 60 && entry.PendingStreak < 3) { Diagnostics.Trace(() => "layout: " + entry.Target.Label + " never held still - baseline captured from a moving pose"); } entry.PendingStreak = 0; entry.PendingTotal = 0; entry.Baseline = new Baseline { InstanceId = ((Object)val).GetInstanceID(), AnchoredPosition = anchoredPosition, LocalScale = ((Transform)val).localScale, LocalRotation = ((Transform)val).localRotation, SizeDelta = val.sizeDelta }; goto IL_01e7; } private static void ApplyOne(Entry entry) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_004c: 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_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_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_00e6: 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_00ec: 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_00ff: 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_0109: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0110: 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) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_020d: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0263: Unknown result type (might be due to invalid IL or missing references) //IL_0268: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_028c: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_02af: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Unknown result type (might be due to invalid IL or missing references) //IL_029f: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Unknown result type (might be due to invalid IL or missing references) RectTransform val = Resolve(entry); if ((Object)(object)val == (Object)null || entry.Baseline == null) { return; } Vector2 val2 = Vector2.zero; bool num = !Mathf.Approximately(entry.Scale, 1f); bool flag = !Mathf.Approximately(entry.Rotation, 0f); Quaternion val3 = entry.Baseline.LocalRotation * Quaternion.Euler(0f, 0f, entry.Rotation); if ((num || flag) && ConfigManager.layoutTransformInPlace.Value) { Rect rect = val.rect; Vector3 val4 = default(Vector3); ((Vector3)(ref val4))..ctor((0.5f - val.pivot.x) * ((Rect)(ref rect)).width, (0.5f - val.pivot.y) * ((Rect)(ref rect)).height, 0f); Vector3 val5 = entry.Baseline.LocalRotation * Vector3.Scale(val4, entry.Baseline.LocalScale); Vector3 val6 = val3 * Vector3.Scale(val4, entry.Baseline.LocalScale * entry.Scale); val2 = Vector2.op_Implicit(val5 - val6); if (!IsFinite(val2)) { val2 = Vector2.zero; } } if (entry.Offset != Vector2.zero || val2 != Vector2.zero) { entry.AppliedPosition = true; Vector2 val7 = entry.Baseline.AnchoredPosition + entry.Offset + val2; if (val.anchoredPosition != val7) { val.anchoredPosition = val7; } } else if (entry.AppliedPosition) { entry.AppliedPosition = false; val.anchoredPosition = entry.Baseline.AnchoredPosition; } if (num) { entry.AppliedScale = true; Vector3 val8 = entry.Baseline.LocalScale * entry.Scale; if (((Transform)val).localScale != val8) { ((Transform)val).localScale = val8; } } else if (entry.AppliedScale) { entry.AppliedScale = false; ((Transform)val).localScale = entry.Baseline.LocalScale; } if (flag) { entry.AppliedRotation = true; if (((Transform)val).localRotation != val3) { ((Transform)val).localRotation = val3; } } else if (entry.AppliedRotation) { entry.AppliedRotation = false; ((Transform)val).localRotation = entry.Baseline.LocalRotation; } LayoutUpright.Apply(entry.Target.Id, val, entry.Rotation); bool flag2 = LayoutBars.IsWidthDriven(val); if (entry.Size != Vector2.zero) { entry.AppliedSize = true; Vector2 val9 = ClampSize(entry.Baseline.SizeDelta + entry.Size); if (flag2) { val9.x = val.sizeDelta.x; } if (val.sizeDelta != val9) { val.sizeDelta = val9; } } else if (entry.AppliedSize) { entry.AppliedSize = false; Vector2 sizeDelta = entry.Baseline.SizeDelta; if (flag2) { sizeDelta.x = val.sizeDelta.x; } val.sizeDelta = sizeDelta; } } private static Rect ScreenAabb(RectTransform rt) { //IL_0105: Unknown result type (might be due to invalid IL or missing references) rt.GetWorldCorners(_corners); float x = _corners[0].x; float x2 = _corners[0].x; float y = _corners[0].y; float y2 = _corners[0].y; for (int i = 1; i < 4; i++) { if (_corners[i].x < x) { x = _corners[i].x; } if (_corners[i].x > x2) { x2 = _corners[i].x; } if (_corners[i].y < y) { y = _corners[i].y; } if (_corners[i].y > y2) { y2 = _corners[i].y; } } return new Rect(x, y, x2 - x, y2 - y); } public static void ClampToScreen(LayoutTarget target) { //IL_0050: 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) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014f: 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_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) if (!_byId.TryGetValue(target.Id, out var entry) || entry.Baseline == null) { return; } RectTransform val = Resolve(entry); if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy) { return; } Rect r = ScreenAabb(val); if (!IsFinite(r) || ((Rect)(ref r)).Overlaps(new Rect(0f, 0f, (float)Screen.width, (float)Screen.height))) { return; } float num = 0f; float num2 = 0f; if (((Rect)(ref r)).xMax < 32f) { num = 32f - ((Rect)(ref r)).xMax; } else if (((Rect)(ref r)).xMin > (float)Screen.width - 32f) { num = (float)Screen.width - 32f - ((Rect)(ref r)).xMin; } if (((Rect)(ref r)).yMax < 32f) { num2 = 32f - ((Rect)(ref r)).yMax; } else if (((Rect)(ref r)).yMin > (float)Screen.height - 32f) { num2 = (float)Screen.height - 32f - ((Rect)(ref r)).yMin; } if (num != 0f || num2 != 0f) { Vector2 val2 = UnitsPerPixel(val); entry.Offset = ClampOffset(entry.Offset + new Vector2(num * val2.x, num2 * val2.y)); val.anchoredPosition = entry.Baseline.AnchoredPosition + entry.Offset; Diagnostics.Trace(() => "layout: " + entry.Target.Label + " was fully off screen, pulled back"); } } public static bool TryGetScreenRect(LayoutTarget target, out Rect screenRect, out Vector2 unitsPerPixel) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: 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_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) screenRect = default(Rect); unitsPerPixel = Vector2.one; if (target == null || !_byId.TryGetValue(target.Id, out var value)) { return false; } RectTransform val = Resolve(value); if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy) { return false; } Rect val2 = ScreenAabb(val); if (!IsFinite(val2)) { return false; } if (!((Rect)(ref val2)).Overlaps(new Rect((float)(-Screen.width), (float)(-Screen.height), (float)Screen.width * 3f, (float)Screen.height * 3f))) { return false; } unitsPerPixel = UnitsPerPixel(val); screenRect = val2; return true; } private static Vector2 UnitsPerPixel(RectTransform rt) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) Vector3 val = (((Object)(object)((Transform)rt).parent != (Object)null) ? ((Transform)rt).parent.lossyScale : Vector3.one); return new Vector2((Mathf.Abs(val.x) > 0.0001f) ? (1f / val.x) : 1f, (Mathf.Abs(val.y) > 0.0001f) ? (1f / val.y) : 1f); } public static void Nudge(LayoutTarget target, Vector2 deltaCanvasUnits) { //IL_0017: 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_001d: 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_0027: Unknown result type (might be due to invalid IL or missing references) if (_byId.TryGetValue(target.Id, out var value)) { value.Offset = ClampOffset(value.Offset + deltaCanvasUnits); } } public static void SetScale(LayoutTarget target, float scale) { if (_byId.TryGetValue(target.Id, out var value)) { value.Scale = Mathf.Clamp(scale, 0.2f, 5f); } } public static float GetScale(LayoutTarget target) { if (!_byId.TryGetValue(target.Id, out var value)) { return 1f; } return value.Scale; } public static void SetRotation(LayoutTarget target, float degrees) { if (_byId.TryGetValue(target.Id, out var value)) { value.Rotation = NormaliseAngle(degrees); } } public static float GetRotation(LayoutTarget target) { if (!_byId.TryGetValue(target.Id, out var value)) { return 0f; } return value.Rotation; } public static void Resize(LayoutTarget target, Vector2 delta, Vector2 anchorCompensation) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0041: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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) if (_byId.TryGetValue(target.Id, out var value) && value.Baseline != null) { Vector2 val = ClampOffset(value.Size + delta); Vector2 val2 = value.Baseline.SizeDelta + val; if (!(val2.x < 12f) && !(val2.y < 12f)) { value.Size = val; value.Offset = ClampOffset(value.Offset + anchorCompensation); } } } public static Vector2 GetSize(LayoutTarget target) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (!_byId.TryGetValue(target.Id, out var value)) { return Vector2.zero; } return value.Size; } public static Vector2 GetSizeFor(RectTransform rt) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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) if ((Object)(object)rt == (Object)null) { return Vector2.zero; } for (int i = 0; i < _entries.Count; i++) { Entry entry = _entries[i]; if (!(entry.Size == Vector2.zero) && entry.Cached == rt) { return entry.Size; } } return Vector2.zero; } public static bool TryGetRectInfo(LayoutTarget target, out Vector2 pivot, out Vector2 size) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: 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_001b: 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) //IL_004f: 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) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) pivot = new Vector2(0.5f, 0.5f); size = Vector2.zero; if (!_byId.TryGetValue(target.Id, out var value)) { return false; } RectTransform val = Resolve(value); if ((Object)(object)val == (Object)null) { return false; } pivot = val.pivot; Rect rect = val.rect; size = ((Rect)(ref rect)).size; return true; } public static Vector2 GetOffset(LayoutTarget target) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (!_byId.TryGetValue(target.Id, out var value)) { return Vector2.zero; } return value.Offset; } public static bool IsCustomised(LayoutTarget target) { if (_byId.TryGetValue(target.Id, out var value)) { return IsCustomised(value); } return false; } private static bool IsCustomised(Entry entry) { //IL_0001: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) if (!(entry.Offset != Vector2.zero) && Mathf.Approximately(entry.Scale, 1f) && Mathf.Approximately(entry.Rotation, 0f)) { return entry.Size != Vector2.zero; } return true; } public static void Reset(LayoutTarget target) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) if (!_byId.TryGetValue(target.Id, out var value)) { return; } value.Offset = Vector2.zero; value.Scale = 1f; value.Rotation = 0f; value.Size = Vector2.zero; RectTransform val = Resolve(value); if ((Object)(object)val != (Object)null && value.Baseline != null && value.Baseline.InstanceId == ((Object)val).GetInstanceID()) { val.anchoredPosition = value.Baseline.AnchoredPosition; ((Transform)val).localScale = value.Baseline.LocalScale; ((Transform)val).localRotation = value.Baseline.LocalRotation; Vector2 sizeDelta = value.Baseline.SizeDelta; if (LayoutBars.IsWidthDriven(val)) { sizeDelta.x = val.sizeDelta.x; } val.sizeDelta = sizeDelta; value.AppliedPosition = false; value.AppliedScale = false; value.AppliedRotation = false; value.AppliedSize = false; } } public static void ResetAll() { LayoutStore.Backup(); foreach (Entry entry in _entries) { Reset(entry.Target); } LayoutStore.Clear(); LayoutStore.SaveIfDirty(); } public static void ApplyAll(IDictionary values) { //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) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) LayoutStore.Backup(); foreach (Entry entry in _entries) { if (values != null && values.TryGetValue(entry.Target.Id, out var value) && value != null) { entry.Offset = ClampOffset(new Vector2(value.X, value.Y)); entry.Scale = Mathf.Clamp(value.Scale, 0.2f, 5f); entry.Rotation = NormaliseAngle(value.Rotation); entry.Size = ClampOffset(new Vector2(value.Width, value.Height)); } else { Reset(entry.Target); } } LayoutStore.ReplaceAll(values); LayoutStore.SaveIfDirty(); } public static void Commit() { //IL_0021: 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) foreach (Entry entry in _entries) { LayoutStore.Set(entry.Target.Id, entry.Offset, entry.Scale, entry.Rotation, entry.Size); } LayoutStore.SaveIfDirty(); } public static string Describe() { if (_entries.Count == 0) { return " (nothing discovered yet - elements are found on the first frame in a world)"; } StringBuilder stringBuilder = new StringBuilder(); int num = 0; foreach (Entry entry in _entries) { if (IsCustomised(entry)) { num++; stringBuilder.AppendLine($" {entry.Target.Label,-24} offset {entry.Offset.x,7:0.#},{entry.Offset.y,7:0.#} scale {entry.Scale:0.##} rot {entry.Rotation,4:0} [{entry.Target.Id}]"); } } stringBuilder.AppendLine($" {num} customised of {_entries.Count} adjustable elements. Saved to {LayoutStore.FilePath}"); return stringBuilder.ToString().TrimEnd(Array.Empty()); } private static RectTransform Resolve(Entry entry) { if ((Object)(object)entry.Cached == (Object)null) { entry.Cached = entry.Target.Resolve(); } return entry.Cached; } private static Vector2 ClampSize(Vector2 size) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) if (!IsFinite(size)) { return Vector2.zero; } return new Vector2(Mathf.Max(size.x, 12f), Mathf.Max(size.y, 12f)); } private static Vector2 ClampOffset(Vector2 offset) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) if (!IsFinite(offset)) { return Vector2.zero; } return new Vector2(Mathf.Clamp(offset.x, -4000f, 4000f), Mathf.Clamp(offset.y, -4000f, 4000f)); } private static float NormaliseAngle(float degrees) { if (!IsFinite(degrees)) { return 0f; } degrees %= 360f; if (degrees > 180f) { degrees -= 360f; } if (degrees <= -180f) { degrees += 360f; } return degrees; } private static bool IsFinite(float v) { if (!float.IsNaN(v)) { return !float.IsInfinity(v); } return false; } private static bool IsFinite(Vector2 v) { //IL_0000: 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) if (IsFinite(v.x)) { return IsFinite(v.y); } return false; } private static bool IsFinite(Vector3 v) { //IL_0000: 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_001a: Unknown result type (might be due to invalid IL or missing references) if (IsFinite(v.x) && IsFinite(v.y)) { return IsFinite(v.z); } return false; } private static bool IsFinite(Rect r) { if (IsFinite(((Rect)(ref r)).x) && IsFinite(((Rect)(ref r)).y) && IsFinite(((Rect)(ref r)).width)) { return IsFinite(((Rect)(ref r)).height); } return false; } } internal static class LayoutMenu { [CompilerGenerated] private static class <>O { public static WindowFunction <0>__DrawWindow; } private const string ControlPrefix = "VikingOS."; private const string SearchFieldName = "VikingOS.LayoutSearch"; private const string PresetFieldName = "VikingOS.PresetName"; private const int MaxRows = 160; private static string _presetName = string.Empty; private static int _presetIndex = -1; private static string _presetMessage; private static float _presetMessageUntil; private static Vector2 _scroll; private static string _search = string.Empty; private static bool _changedOnly; private static LayoutTarget _selected; private static readonly Dictionary _fieldText = new Dictionary(); private static string _fieldOwnerId; private static readonly List _filtered = new List(); private static int _filteredOnFrame = -1; private static bool _hasTextFocus; private static readonly int GuiWindowId = StringExtensionMethods.GetStableHashCode("VikingOS_LayoutMenu"); private const float ToggleButtonWidth = 30f; private static Rect _rect; private static Vector2 _committedPos = new Vector2(float.NaN, float.NaN); private static bool _rectInitialised; private static readonly FrameStyle[] FrameStyles = new FrameStyle[4] { FrameStyle.Gilt, FrameStyle.Runic, FrameStyle.Serpent, FrameStyle.Ironbound }; private static readonly string[] FrameBlurbs = new string[4] { "polished rails, acanthus corners", "chiselled band, cut bind-runes", "braided strands, beast heads", "riveted straps, shield boss" }; public static LayoutTarget Selected => _selected; public static bool HasTextFocus => _hasTextFocus; public static Rect CurrentRect => _rect; private static bool Open { get { if (ConfigManager.layoutMenuOpen != null) { return ConfigManager.layoutMenuOpen.Value; } return true; } set { if (ConfigManager.layoutMenuOpen != null) { ConfigManager.layoutMenuOpen.Value = value; } } } private static string TitleText => "Viking OS v0.9.2"; public static void Select(LayoutTarget target) { if (_selected != target) { _selected = target; _fieldText.Clear(); _fieldOwnerId = target?.Id; } } private static void SelectFromList(LayoutTarget target) { Select(target); LayoutEditor.OnMenuSelected(target); } private static void Deselect() { Select(null); LayoutEditor.ClearMenuSelection(); } public static void Reset() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) _selected = null; _search = string.Empty; _changedOnly = false; _scroll = Vector2.zero; _fieldText.Clear(); LayoutPresets.Refresh(); _presetMessage = null; } private static void SampleTextFocus() { string nameOfFocusedControl = GUI.GetNameOfFocusedControl(); _hasTextFocus = !string.IsNullOrEmpty(nameOfFocusedControl) && nameOfFocusedControl.StartsWith("VikingOS.", StringComparison.Ordinal); UIFocus.SetHasTextFocus("VikingOS_LayoutEditor", _hasTextFocus); } public static void ForgetTextFocus() { _hasTextFocus = false; } private static Vector2 ExpandedSize() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) float num = GiltFrameTheme.S(24f); return new Vector2(Mathf.Max(CollapsedSize().x, Mathf.Min(GiltFrameTheme.S(560f), (float)Screen.width * 0.45f)), Mathf.Min(GiltFrameTheme.S(880f), (float)Screen.height - num * 2f)); } private static Vector2 CollapsedSize() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown //IL_000f: 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) float x = GiltFrameTheme.Title.CalcSize(new GUIContent(TitleText)).x; return new Vector2(50f + x + GiltFrameTheme.S(30f) + 22f, 36f + GiltFrameTheme.TitleHeight - 8f); } public static void Draw() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0050: 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_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0035: 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_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: 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) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown Vector2 val = (Open ? ExpandedSize() : CollapsedSize()); if (!_rectInitialised) { _rectInitialised = true; _rect = new Rect(ConfigManager.layoutMenuX.Value, ConfigManager.layoutMenuY.Value, val.x, val.y); } ((Rect)(ref _rect)).width = val.x; ((Rect)(ref _rect)).height = val.y; int guiWindowId = GuiWindowId; Rect rect = _rect; object obj = <>O.<0>__DrawWindow; if (obj == null) { WindowFunction val2 = DrawWindow; <>O.<0>__DrawWindow = val2; obj = (object)val2; } _rect = GUI.Window(guiWindowId, rect, (WindowFunction)obj, GUIContent.none, GUIStyle.none); ClampToScreen(); CommitPositionIfSettled(); SampleTextFocus(); } private static void ClampToScreen() { float num = GiltFrameTheme.S(28f); ((Rect)(ref _rect)).x = Mathf.Clamp(((Rect)(ref _rect)).x, 0f - ((Rect)(ref _rect)).width + num, (float)Screen.width - num); ((Rect)(ref _rect)).y = Mathf.Clamp(((Rect)(ref _rect)).y, 0f, (float)Screen.height - num); } private static void CommitPositionIfSettled() { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) if (!Input.GetMouseButton(0) && (_committedPos.x != ((Rect)(ref _rect)).x || _committedPos.y != ((Rect)(ref _rect)).y)) { _committedPos = new Vector2(((Rect)(ref _rect)).x, ((Rect)(ref _rect)).y); ConfigManager.layoutMenuX.Value = ((Rect)(ref _rect)).x; ConfigManager.layoutMenuY.Value = ((Rect)(ref _rect)).y; } } private static void DrawWindow(int id) { //IL_0029: 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_006a: Unknown result type (might be due to invalid IL or missing references) //IL_009e: 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_0127: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) float width = ((Rect)(ref _rect)).width; float height = ((Rect)(ref _rect)).height; Rect val = default(Rect); ((Rect)(ref val))..ctor(0f, 0f, width, height); GiltFrameTheme.DrawPanelFill(val); GiltFrameTheme.DrawFrame(val); float num = GiltFrameTheme.S(30f); GiltFrameTheme.DrawShadowed(new Rect(32f, 26f, width - 36f - 14f - num - 10f, GiltFrameTheme.TitleHeight - 20f), TitleText, GiltFrameTheme.Title); if (GUI.Button(new Rect(width - 18f - num - 6f, 28f, num, GiltFrameTheme.TitleHeight - 20f), Open ? "▼" : "▲", GiltFrameTheme.Button)) { Open = !Open; } GUI.DragWindow(new Rect(0f, 0f, width - 18f - num - 10f, 18f + GiltFrameTheme.TitleHeight)); if (Open) { GiltFrameTheme.DrawRule(new Rect(40f, 18f + GiltFrameTheme.TitleHeight - 12f, width - 80f, 1f)); DrawContents(val); } } private static void DrawContents(Rect win) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: 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_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Expected O, but got Unknown //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) Rect val = GiltFrameTheme.Body(win); float num = GiltFrameTheme.S(26f); float num2 = GiltFrameTheme.S(8f); float y = ((Rect)(ref val)).y; float num3 = GiltFrameTheme.S(56f); float num4 = GiltFrameTheme.S(112f); GUI.Label(new Rect(((Rect)(ref val)).x, y, num3, num), "Search", GiltFrameTheme.Header); GUI.SetNextControlName("VikingOS.LayoutSearch"); _search = GUI.TextField(new Rect(((Rect)(ref val)).x + num3, y, ((Rect)(ref val)).width - num3 - num4 - num2, num), _search ?? string.Empty, 40, GiltFrameTheme.Field); bool flag = GUI.Toggle(new Rect(((Rect)(ref val)).xMax - num4, y, num4, num), _changedOnly, " Changed only", GiltFrameTheme.Note); if (flag != _changedOnly) { _changedOnly = flag; _scroll = Vector2.zero; } y += num + num2; y = DrawPresetRow(new Rect(((Rect)(ref val)).x, y, ((Rect)(ref val)).width, num), num, num2); y = DrawFrameRow(new Rect(((Rect)(ref val)).x, y, ((Rect)(ref val)).width, num), num, num2); string text = Notice(); float num5 = ((text == null) ? 0f : (GiltFrameTheme.Note.CalcHeight(new GUIContent(text), ((Rect)(ref val)).width) + num2)); float num6 = DetailsHeight(num, num2) + num5; float num7 = Mathf.Max(GiltFrameTheme.S(120f), ((Rect)(ref val)).height - (y - ((Rect)(ref val)).y) - num6 - num2); Rect val2 = new Rect(((Rect)(ref val)).x, y, ((Rect)(ref val)).width, num7); GiltFrameTheme.DrawInset(val2); DrawList(val2, num); y += num7 + num2; DrawDetails(new Rect(((Rect)(ref val)).x, y, ((Rect)(ref val)).width, num6), num, num2, text, num5); bool flag2 = ConfigManager.layoutSectionMode == null || ConfigManager.layoutSectionMode.Value; GiltFrameTheme.DrawShadowed(GiltFrameTheme.FooterLine(win), (flag2 ? "Drag moves the whole panel · Ctrl+drag the piece inside it" : "Drag moves a piece · Ctrl+drag the whole panel · red borders too") + $" · gold corners resize · Alt suspends snapping · click empty space to deselect · {ConfigManager.layoutEditorKey.Value} closes", GiltFrameTheme.Footer); } private static float DrawFrameRow(Rect area, float rowH, float gap) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) if (ConfigManager.frameStyle == null) { return ((Rect)(ref area)).y; } float num = GiltFrameTheme.S(56f); float num2 = GiltFrameTheme.S(26f); float num3 = GiltFrameTheme.S(4f); GUI.Label(new Rect(((Rect)(ref area)).x, ((Rect)(ref area)).y, num, rowH), "Frame", GiltFrameTheme.Header); float num4 = ((Rect)(ref area)).x + num; int num5 = Array.IndexOf(FrameStyles, ConfigManager.frameStyle.Value); if (num5 < 0) { num5 = 0; } if (GUI.Button(new Rect(num4, ((Rect)(ref area)).y, num2, rowH), "◀", GiltFrameTheme.Button)) { Step(num5, -1); } num4 += num2 + num3; float num6 = ((Rect)(ref area)).xMax - num4 - num2 - num3; string text = $"{FrameStyles[num5]} - {FrameBlurbs[num5]}"; if (GUI.Button(new Rect(num4, ((Rect)(ref area)).y, num6, rowH), text, GiltFrameTheme.Button)) { Step(num5, 1); } num4 += num6 + num3; if (GUI.Button(new Rect(num4, ((Rect)(ref area)).y, num2, rowH), "▶", GiltFrameTheme.Button)) { Step(num5, 1); } return ((Rect)(ref area)).y + rowH + gap; } private static void Step(int index, int by) { int num = ((index + by) % FrameStyles.Length + FrameStyles.Length) % FrameStyles.Length; ConfigManager.frameStyle.Value = FrameStyles[num]; } private static float DrawPresetRow(Rect area, float rowH, float gap) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Unknown result type (might be due to invalid IL or missing references) //IL_025b: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Expected O, but got Unknown //IL_027f: Unknown result type (might be due to invalid IL or missing references) float y = ((Rect)(ref area)).y; float num = GiltFrameTheme.S(56f); float num2 = GiltFrameTheme.S(26f); float num3 = GiltFrameTheme.S(64f); float num4 = GiltFrameTheme.S(4f); GUI.Label(new Rect(((Rect)(ref area)).x, y, num, rowH), "Preset", GiltFrameTheme.Header); float num5 = ((Rect)(ref area)).x + num; IReadOnlyList names = LayoutPresets.Names; GUI.enabled = names.Count > 0; if (GUI.Button(new Rect(num5, y, num2, rowH), "◀", GiltFrameTheme.Button)) { CyclePreset(-1); } num5 += num2 + num4; float num6 = ((Rect)(ref area)).xMax - num5 - num2 - num4 - (num3 + num4) * 3f; GUI.enabled = true; GUI.SetNextControlName("VikingOS.PresetName"); string text = GUI.TextField(new Rect(num5, y, num6, rowH), _presetName ?? string.Empty, 48, GiltFrameTheme.Field); if (text != _presetName) { _presetName = text; _presetIndex = -1; } num5 += num6 + num4; GUI.enabled = names.Count > 0; if (GUI.Button(new Rect(num5, y, num2, rowH), "▶", GiltFrameTheme.Button)) { CyclePreset(1); } num5 += num2 + num4; GUI.enabled = true; bool num7 = !string.IsNullOrWhiteSpace(_presetName); bool flag = num7 && LayoutPresets.Exists(_presetName); GUI.enabled = num7; if (GUI.Button(new Rect(num5, y, num3, rowH), flag ? "Update" : "Save", GiltFrameTheme.Button)) { Say(LayoutPresets.Save(_presetName, out var message), message); } num5 += num3 + num4; GUI.enabled = flag; if (GUI.Button(new Rect(num5, y, num3, rowH), "Load", GiltFrameTheme.Primary)) { Say(LayoutPresets.Load(_presetName, out var message2), message2); _fieldText.Clear(); } num5 += num3 + num4; if (GUI.Button(new Rect(num5, y, num3, rowH), "Delete", GiltFrameTheme.Button)) { Say(LayoutPresets.Delete(_presetName, out var message3), message3); _presetIndex = -1; } GUI.enabled = true; y += rowH + gap; if (_presetMessage != null && Time.unscaledTime < _presetMessageUntil) { float num8 = GiltFrameTheme.Note.CalcHeight(new GUIContent(_presetMessage), ((Rect)(ref area)).width); GUI.Label(new Rect(((Rect)(ref area)).x, y, ((Rect)(ref area)).width, num8), _presetMessage, GiltFrameTheme.Note); y += num8 + gap; } return y; } private static void CyclePreset(int direction) { IReadOnlyList names = LayoutPresets.Names; if (names.Count != 0) { if (_presetIndex < 0 || _presetIndex >= names.Count) { _presetIndex = ((direction <= 0) ? (names.Count - 1) : 0); } else { _presetIndex = (_presetIndex + direction + names.Count) % names.Count; } _presetName = names[_presetIndex]; GUI.FocusControl((string)null); } } private static void Say(bool ok, string message) { _presetMessage = message; _presetMessageUntil = Time.unscaledTime + (ok ? 5f : 10f); } private static float DetailsHeight(float rowH, float gap) { return rowH * 6f + gap * 5f; } private static string Notice() { if (_selected == null) { return null; } if (LayoutEngine.TryGetScreenRect(_selected, out var _, out var _)) { return null; } return _selected.Label + " is not on screen right now. Open the panel it belongs to and it will come back - your settings for it are kept either way."; } private static void DrawList(Rect area, float rowH) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) BuildFiltered(); GUILayout.BeginArea(new Rect(((Rect)(ref area)).x + 4f, ((Rect)(ref area)).y + 4f, ((Rect)(ref area)).width - 8f, ((Rect)(ref area)).height - 8f)); _scroll = GUILayout.BeginScrollView(_scroll, Array.Empty()); if (_filtered.Count == 0) { GUILayout.Label(_changedOnly ? "Nothing changed yet. Move something, or clear the filter." : "Nothing matches that search.", GiltFrameTheme.Note, Array.Empty()); } int num = Mathf.Min(_filtered.Count, 160); for (int i = 0; i < num; i++) { LayoutTarget layoutTarget = _filtered[i]; bool flag = layoutTarget == _selected; bool flag2 = LayoutEngine.IsCustomised(layoutTarget); string obj = (layoutTarget.IsGroup ? "▣ " : "· "); string text = (flag2 ? " ●" : string.Empty); GUIStyle val = (flag ? GiltFrameTheme.Primary : (flag2 ? GiltFrameTheme.Value : GiltFrameTheme.Row)); if (GUILayout.Button(obj + layoutTarget.Label + text, val, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(rowH) })) { SelectFromList(layoutTarget); } } if (_filtered.Count > num) { GUILayout.Label($"...and {_filtered.Count - num} more. Narrow the search.", GiltFrameTheme.Note, Array.Empty()); } GUILayout.EndScrollView(); GUILayout.EndArea(); } private static void BuildFiltered() { if (_filteredOnFrame == Time.frameCount) { return; } _filteredOnFrame = Time.frameCount; _filtered.Clear(); string text = (string.IsNullOrEmpty(_search) ? null : _search.ToLowerInvariant()); foreach (LayoutTarget target in LayoutEngine.Targets) { if ((!_changedOnly || LayoutEngine.IsCustomised(target)) && (text == null || target.Label.ToLowerInvariant().Contains(text) || target.Id.ToLowerInvariant().Contains(text))) { _filtered.Add(target); } } } private static void DrawDetails(Rect area, float rowH, float gap, string notice, float noticeH) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_0182: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01e5: Unknown result type (might be due to invalid IL or missing references) //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Unknown result type (might be due to invalid IL or missing references) //IL_024a: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_02b6: 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_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02db: Unknown result type (might be due to invalid IL or missing references) //IL_02e3: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_0326: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_0394: Unknown result type (might be due to invalid IL or missing references) //IL_03d9: Unknown result type (might be due to invalid IL or missing references) //IL_042f: Unknown result type (might be due to invalid IL or missing references) if (_selected == null) { GUI.Label(area, "Pick an element from the list, or click one in the world.", GiltFrameTheme.Note); return; } float y = ((Rect)(ref area)).y; float num = GiltFrameTheme.S(96f); float num2 = GiltFrameTheme.S(112f); LayoutTarget layoutTarget = LayoutEditor.SectionOf(_selected); bool flag = layoutTarget != null && layoutTarget != _selected; GiltFrameTheme.DrawShadowed(new Rect(((Rect)(ref area)).x, y, ((Rect)(ref area)).width - num - num2 - gap * 2f, rowH), _selected.Label, GiltFrameTheme.Header); GUI.enabled = flag; if (GUI.Button(new Rect(((Rect)(ref area)).xMax - num - num2 - gap, y, num2, rowH), flag ? ("▣ " + Shorten(layoutTarget.Label, 12)) : "▣ Whole panel", GiltFrameTheme.Button)) { SelectFromList(layoutTarget); GUI.enabled = true; return; } GUI.enabled = true; if (GUI.Button(new Rect(((Rect)(ref area)).xMax - num, y, num, rowH), "Deselect", GiltFrameTheme.Button)) { Deselect(); return; } y += rowH; if (notice != null) { GUI.Label(new Rect(((Rect)(ref area)).x, y, ((Rect)(ref area)).width, noticeH - gap), notice, GiltFrameTheme.Note); y += noticeH; } GUI.Label(new Rect(((Rect)(ref area)).x, y, ((Rect)(ref area)).width, rowH), _selected.Id, GiltFrameTheme.Note); y += rowH + gap; Vector2 offset = LayoutEngine.GetOffset(_selected); Vector2 size = LayoutEngine.GetSize(_selected); float scale = LayoutEngine.GetScale(_selected); float rotation = LayoutEngine.GetRotation(_selected); float num3 = (((Rect)(ref area)).width - gap) * 0.5f; float num4 = Field(new Rect(((Rect)(ref area)).x, y, num3, rowH), "X", offset.x, "x"); float num5 = Field(new Rect(((Rect)(ref area)).x + num3 + gap, y, num3, rowH), "Y", offset.y, "y"); y += rowH + gap; float num6 = Field(new Rect(((Rect)(ref area)).x, y, num3, rowH), "W", size.x, "w"); float num7 = Field(new Rect(((Rect)(ref area)).x + num3 + gap, y, num3, rowH), "H", size.y, "h"); y += rowH + gap; float num8 = Field(new Rect(((Rect)(ref area)).x, y, num3, rowH), "Scale", scale, "s"); float num9 = Field(new Rect(((Rect)(ref area)).x + num3 + gap, y, num3, rowH), "Turn", rotation, "r"); y += rowH + gap; if (num4 != offset.x || num5 != offset.y) { LayoutEngine.Nudge(_selected, new Vector2(num4 - offset.x, num5 - offset.y)); Commit(); } if (num6 != size.x || num7 != size.y) { LayoutEngine.Resize(_selected, new Vector2(num6 - size.x, num7 - size.y), Vector2.zero); Commit(); } if (num8 != scale) { LayoutEngine.SetScale(_selected, num8); Commit(); } if (num9 != rotation) { LayoutEngine.SetRotation(_selected, num9); Commit(); } float num10 = (((Rect)(ref area)).width - gap * 2f) / 3f; GUI.enabled = LayoutEngine.IsCustomised(_selected); if (GUI.Button(new Rect(((Rect)(ref area)).x, y, num10, rowH), "Reset this", GiltFrameTheme.Button)) { LayoutEngine.Reset(_selected); _fieldText.Clear(); Commit(); } GUI.enabled = true; if (GUI.Button(new Rect(((Rect)(ref area)).x + num10 + gap, y, num10, rowH), "Turn 90°", GiltFrameTheme.Button)) { LayoutEngine.SetRotation(_selected, rotation + 90f); _fieldText.Clear(); Commit(); } int customisedCount = LayoutEngine.CustomisedCount; GUI.enabled = customisedCount > 0; if (GUI.Button(new Rect(((Rect)(ref area)).xMax - num10, y, num10, rowH), $"Reset all {customisedCount}", GiltFrameTheme.Button)) { LayoutEngine.ResetAll(); _fieldText.Clear(); } GUI.enabled = true; } private static float Field(Rect rect, string label, float current, string key) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) float num = GiltFrameTheme.S(46f); GUI.Label(new Rect(((Rect)(ref rect)).x, ((Rect)(ref rect)).y, num, ((Rect)(ref rect)).height), label, GiltFrameTheme.Key); if (_fieldOwnerId != _selected.Id) { _fieldText.Clear(); _fieldOwnerId = _selected.Id; } float result; float result2; if (!_fieldText.TryGetValue(key, out var value)) { value = current.ToString("0.##"); } else if ((!float.TryParse(value, out result) || !Mathf.Approximately(result, current)) && float.TryParse(value, out result2) && !Mathf.Approximately(result2, current)) { value = current.ToString("0.##"); } GUI.SetNextControlName("VikingOS.Field." + key); string text = GUI.TextField(new Rect(((Rect)(ref rect)).x + num, ((Rect)(ref rect)).y, ((Rect)(ref rect)).width - num, ((Rect)(ref rect)).height), value, 10, GiltFrameTheme.Field); _fieldText[key] = text; if (!float.TryParse(text, out var result3)) { return current; } return result3; } private static string Shorten(string value, int max) { if (string.IsNullOrEmpty(value)) { return string.Empty; } if (value.Length > max) { return value.Substring(0, max - 1) + "…"; } return value; } private static void Commit() { LayoutEngine.Commit(); } } internal static class LayoutPresets { [Serializable] private sealed class PresetFile { [JsonProperty("version")] public int Version = 1; [JsonProperty("name")] public string Name = string.Empty; [JsonProperty("elements")] public Dictionary Elements = new Dictionary(); [JsonProperty("settings")] public Dictionary Settings = new Dictionary(); } private const int CurrentVersion = 1; private const string Extension = ".json"; private static readonly List _names = new List(); private static bool _listed; public static string Folder => ModPaths.InConfigDir("presets"); public static IReadOnlyList Names { get { if (!_listed) { Refresh(); } return _names; } } public static void Refresh() { _listed = true; _names.Clear(); try { if (Directory.Exists(Folder)) { string[] files = Directory.GetFiles(Folder, "*.json"); foreach (string path in files) { _names.Add(Path.GetFileNameWithoutExtension(path)); } _names.Sort(StringComparer.OrdinalIgnoreCase); } } catch (Exception ex) { Diagnostics.Health("Layout presets", ok: false, "the presets folder could not be read, so no presets are listed. Reason: " + ex.Message); } } public static bool Exists(string name) { if (!string.IsNullOrEmpty(name)) { return Names.Any((string n) => string.Equals(n, name, StringComparison.OrdinalIgnoreCase)); } return false; } public static bool Save(string name, out string message) { string file = ResolvePath(name, out message); if (file == null) { return false; } try { PresetFile presetFile = new PresetFile { Name = name.Trim(), Elements = LayoutStore.ExportAll(), Settings = CaptureSettings() }; Directory.CreateDirectory(Folder); File.WriteAllText(file, JsonConvert.SerializeObject((object)presetFile, (Formatting)1)); Refresh(); message = $"Saved \"{presetFile.Name}\" - {presetFile.Elements.Count} element(s) and {presetFile.Settings.Count} setting(s)."; Diagnostics.Trace(() => "presets: wrote " + file); return true; } catch (Exception ex) { message = "Could not save \"" + name + "\": " + ex.Message; Plugin.Log.LogError((object)$"preset save failed for \"{name}\". Reason: {ex}"); return false; } } public static bool Load(string name, out string message) { string file = ResolvePath(name, out message); if (file == null) { return false; } if (!File.Exists(file)) { message = "There is no preset called \"" + name + "\"."; return false; } try { PresetFile presetFile = JsonConvert.DeserializeObject(File.ReadAllText(file)); if (presetFile == null) { message = "\"" + name + "\" is empty or unreadable and was NOT applied."; return false; } int settings = RestoreSettings(presetFile.Settings); LayoutEngine.ApplyAll(presetFile.Elements); int elements = presetFile.Elements?.Count ?? 0; message = $"Loaded \"{name}\" - {elements} element(s) and {settings} setting(s)."; Diagnostics.Trace(() => $"presets: applied {file} ({elements} elements, {settings} settings)"); return true; } catch (Exception ex) { message = "\"" + name + "\" could not be read, so nothing was changed: " + ex.Message; Plugin.Log.LogError((object)$"preset load failed for \"{name}\". Reason: {ex}"); return false; } } public static bool Delete(string name, out string message) { string text = ResolvePath(name, out message); if (text == null) { return false; } try { if (!File.Exists(text)) { message = "There is no preset called \"" + name + "\"."; return false; } File.Delete(text); Refresh(); message = "Deleted \"" + name + "\"."; return true; } catch (Exception ex) { message = "Could not delete \"" + name + "\": " + ex.Message; Plugin.Log.LogError((object)$"preset delete failed for \"{name}\". Reason: {ex}"); return false; } } private static Dictionary CaptureSettings() { Dictionary dictionary = new Dictionary(); ConfigEntryBase[] array = ConfigManager.PresetEntries(); foreach (ConfigEntryBase entry in array) { if (entry == null) { continue; } try { dictionary[Key(entry)] = entry.GetSerializedValue(); } catch (Exception ex) { Exception ex2 = ex; Diagnostics.Trace(() => "presets: could not read " + Key(entry) + " - " + ex2.Message); } } return dictionary; } private static int RestoreSettings(Dictionary settings) { if (settings == null || settings.Count == 0) { return 0; } int num = 0; ConfigEntryBase[] array = ConfigManager.PresetEntries(); foreach (ConfigEntryBase entry in array) { if (entry == null || !settings.TryGetValue(Key(entry), out var value) || value == null) { continue; } try { entry.SetSerializedValue(value); num++; } catch (Exception ex) { Exception ex2 = ex; Diagnostics.Trace(() => "presets: could not apply " + Key(entry) + " = \"" + value + "\" - " + ex2.Message); } } return num; } private static string Key(ConfigEntryBase entry) { return entry.Definition.Section + "/" + entry.Definition.Key; } private static string ResolvePath(string name, out string message) { message = null; if (string.IsNullOrWhiteSpace(name)) { message = "Give the preset a name first."; return null; } string text = name.Trim(); if (text.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0) { message = "A preset name cannot contain \\ / : * ? \" < > |"; return null; } if (text.Length > 48) { message = "That name is too long - 48 characters at most."; return null; } return Path.Combine(Folder, text + ".json"); } } internal static class LayoutReflow { private sealed class Lattice { public bool Valid; public int ChildCount; public int LiveChildren; public int FirstChildId; public RectTransform Container; public Vector2 Cell; public float StepX; public float StepY; public Vector2 Origin; public int GridChildren; public int OriginalColumns; public float BaselineWidth; public bool Applied; } private const float SizeTolerance = 0.5f; private const float LatticeTolerance = 1f; private const int MinChildren = 2; private static readonly Dictionary _lattices = new Dictionary(); private static readonly List _kids = new List(); private static readonly List _axis = new List(); public static void Forget() { _lattices.Clear(); } public static void Observe(string id, RectTransform container) { if (!ConfigManager.layoutReflowGrids.Value) { return; } int childCount = ((Transform)container).childCount; Survey(container, out var liveChildren, out var firstChildId); if (_lattices.TryGetValue(id, out var value) && value.ChildCount == childCount && value.LiveChildren == liveChildren && value.FirstChildId == firstChildId) { value.Container = container; return; } Lattice lattice = Derive(container) ?? new Lattice(); lattice.ChildCount = childCount; lattice.LiveChildren = liveChildren; lattice.FirstChildId = firstChildId; lattice.Container = container; lattice.BaselineWidth = VisibleWidth(container); if (value != null) { lattice.Applied = value.Applied; if (value.Container == container && value.BaselineWidth > 0f) { lattice.BaselineWidth = value.BaselineWidth; } } _lattices[id] = lattice; if (lattice.Valid) { Diagnostics.Trace(() => $"layout: {id} is a {lattice.OriginalColumns}-column grid of {lattice.Cell.x:0}x{lattice.Cell.y:0} " + $"cells at {lattice.StepX:0}x{lattice.StepY:0} pitch in {lattice.BaselineWidth:0} units - it will re-flow when resized"); } } public static void ApplyAll() { if (!ConfigManager.layoutReflowGrids.Value) { return; } foreach (KeyValuePair lattice in _lattices) { Lattice value = lattice.Value; if (!value.Valid) { continue; } RectTransform container = value.Container; if (!((Object)(object)container == (Object)null) && ((Component)container).gameObject.activeInHierarchy) { try { ApplyOne(value, container); } catch { value.Valid = false; } } } } private static void ApplyOne(Lattice lattice, RectTransform container) { float num = VisibleWidth(container); if (float.IsNaN(num) || float.IsInfinity(num)) { return; } int num2 = Mathf.Clamp(lattice.OriginalColumns + Mathf.RoundToInt((num - lattice.BaselineWidth) / Mathf.Abs(lattice.StepX)), 1, Mathf.Max(1, lattice.GridChildren)); if (num2 == lattice.OriginalColumns) { if (lattice.Applied) { lattice.Applied = false; Place(container, lattice, lattice.OriginalColumns); } } else { lattice.Applied = true; Place(container, lattice, num2); } } private static void Place(RectTransform container, Lattice lattice, int columns) { //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: 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) int num = 0; Vector2 val2 = default(Vector2); for (int i = 0; i < ((Transform)container).childCount; i++) { Transform child = ((Transform)container).GetChild(i); RectTransform val = (RectTransform)(object)((child is RectTransform) ? child : null); if (val != null && ((Component)val).gameObject.activeSelf) { int num2 = num % columns; int num3 = num / columns; num++; ((Vector2)(ref val2))..ctor(lattice.Origin.x + (float)num2 * lattice.StepX, lattice.Origin.y + (float)num3 * lattice.StepY); if (val.anchoredPosition != val2) { val.anchoredPosition = val2; } } } } private static float VisibleWidth(RectTransform rt) { //IL_0001: 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_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) Rect rect = rt.rect; float num = ((Rect)(ref rect)).width; Transform parent = ((Transform)rt).parent; while ((Object)(object)parent != (Object)null) { RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null); if (val != null) { if ((Object)(object)((Component)parent).GetComponent() != (Object)null || (Object)(object)((Component)parent).GetComponent() != (Object)null) { float num2 = num; rect = val.rect; num = Mathf.Min(num2, ((Rect)(ref rect)).width); } if ((Object)(object)((Component)parent).GetComponent() != (Object)null) { break; } } parent = parent.parent; } return num; } private static void Survey(RectTransform container, out int liveChildren, out int firstChildId) { liveChildren = 0; firstChildId = 0; for (int i = 0; i < ((Transform)container).childCount; i++) { Transform child = ((Transform)container).GetChild(i); RectTransform val = (RectTransform)(object)((child is RectTransform) ? child : null); if (val != null && ((Component)val).gameObject.activeSelf) { if (firstChildId == 0) { firstChildId = ((Object)val).GetInstanceID(); } liveChildren++; } } } private static void CollectLive(RectTransform container) { _kids.Clear(); for (int i = 0; i < ((Transform)container).childCount; i++) { Transform child = ((Transform)container).GetChild(i); RectTransform val = (RectTransform)(object)((child is RectTransform) ? child : null); if (val != null && ((Component)val).gameObject.activeSelf) { _kids.Add(val); } } } private static Lattice Derive(RectTransform container) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: 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_0037: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: 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_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: 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_0179: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0194: 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) //IL_01c8: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01e2: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Unknown result type (might be due to invalid IL or missing references) //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_0314: Unknown result type (might be due to invalid IL or missing references) //IL_0316: Unknown result type (might be due to invalid IL or missing references) CollectLive(container); if (_kids.Count < 2) { return null; } if (!SameNamedChildren()) { return null; } Rect rect = _kids[0].rect; Vector2 size = ((Rect)(ref rect)).size; if (!(size.x > 1f) || !(size.y > 1f)) { return null; } foreach (RectTransform kid in _kids) { rect = kid.rect; Vector2 size2 = ((Rect)(ref rect)).size; if (Mathf.Abs(size2.x - size.x) > 0.5f) { return null; } if (Mathf.Abs(size2.y - size.y) > 0.5f) { return null; } Vector2 anchoredPosition = kid.anchoredPosition; if (float.IsNaN(anchoredPosition.x) || float.IsNaN(anchoredPosition.y)) { return null; } if (float.IsInfinity(anchoredPosition.x) || float.IsInfinity(anchoredPosition.y)) { return null; } } int count; float min; float max; float num = DistinctStep(horizontal: true, out count, out min, out max); float num2 = DistinctStep(horizontal: false, out var count2, out var min2, out var max2); if (count < 2 && count2 < 2) { return null; } if (count >= 2 && float.IsNaN(num)) { return null; } if (count2 >= 2 && float.IsNaN(num2)) { return null; } if (count < 2) { num = size.x + (Mathf.Abs(num2) - size.y); } if (count2 < 2) { num2 = size.y + (Mathf.Abs(num) - size.x); } if (!(num > 0.5f) || !(num2 > 0.5f)) { return null; } Vector2 anchoredPosition2 = _kids[0].anchoredPosition; if (count >= 2 && Mathf.Abs(anchoredPosition2.x - max) < Mathf.Abs(anchoredPosition2.x - min)) { num = 0f - num; } num2 = ((count2 >= 2 && Mathf.Abs(anchoredPosition2.y - min2) < Mathf.Abs(anchoredPosition2.y - max2)) ? num2 : (0f - num2)); foreach (RectTransform kid2 in _kids) { float num3 = (kid2.anchoredPosition.x - anchoredPosition2.x) / num; float num4 = (kid2.anchoredPosition.y - anchoredPosition2.y) / num2; if (Mathf.Abs(num3 - Mathf.Round(num3)) * Mathf.Abs(num) > 1f) { return null; } if (Mathf.Abs(num4 - Mathf.Round(num4)) * Mathf.Abs(num2) > 1f) { return null; } if (Mathf.Round(num3) < -0.5f || Mathf.Round(num4) < -0.5f) { return null; } } return new Lattice { Valid = true, Cell = size, StepX = num, StepY = num2, Origin = anchoredPosition2, GridChildren = _kids.Count, OriginalColumns = Mathf.Max(1, count) }; } private static bool SameNamedChildren() { string name = ((Object)_kids[0]).name; for (int i = 1; i < _kids.Count; i++) { if (!string.Equals(((Object)_kids[i]).name, name, StringComparison.Ordinal)) { return false; } } return true; } private static float DistinctStep(bool horizontal, out int count, out float min, out float max) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) _axis.Clear(); foreach (RectTransform kid in _kids) { float num = (horizontal ? kid.anchoredPosition.x : kid.anchoredPosition.y); bool flag = false; foreach (float item in _axis) { if (Mathf.Abs(item - num) <= 1f) { flag = true; break; } } if (!flag) { _axis.Add(num); } } _axis.Sort(); count = _axis.Count; min = ((_axis.Count > 0) ? _axis[0] : 0f); max = ((_axis.Count > 0) ? _axis[_axis.Count - 1] : 0f); if (_axis.Count < 2) { return float.NaN; } float num2 = _axis[1] - _axis[0]; if (num2 <= 0f) { return float.NaN; } for (int i = 2; i < _axis.Count; i++) { if (Mathf.Abs(_axis[i] - _axis[i - 1] - num2) > 1f) { return float.NaN; } } return num2; } } internal static class LayoutSnap { private static readonly List _guidesX = new List(); private static readonly List _guidesY = new List(); private static float _shownX = float.NaN; private static float _shownY = float.NaN; private static readonly List _widgets = new List(); private static readonly List _widgetsBuilding = new List(); public static float Distance { get { if (ConfigManager.layoutSnapDistance == null) { return 8f; } return ConfigManager.layoutSnapDistance.Value; } } private static Color GuideColour => new Color(GiltFrameTheme.Gold.r, GiltFrameTheme.Gold.g, GiltFrameTheme.Gold.b, 0.85f); public static bool Wanted(Event e) { if (ConfigManager.layoutSnap != null && !ConfigManager.layoutSnap.Value) { return false; } if (e != null) { return !e.alt; } return true; } public static void BeginWidgetRects() { _widgets.Clear(); _widgets.AddRange(_widgetsBuilding); _widgetsBuilding.Clear(); } public static void RegisterWidgetRect(Rect r) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) if (((Rect)(ref r)).width > 1f && ((Rect)(ref r)).height > 1f) { _widgetsBuilding.Add(r); } } public static void Build(LayoutTarget exclude, Rect? excludeRect) { //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) _guidesX.Clear(); _guidesY.Clear(); _shownX = float.NaN; _shownY = float.NaN; _guidesX.Add((float)Screen.width * 0.5f); _guidesX.Add(0f); _guidesX.Add(Screen.width); _guidesY.Add((float)Screen.height * 0.5f); _guidesY.Add(0f); _guidesY.Add(Screen.height); foreach (LayoutTarget target in LayoutEngine.Targets) { if (target != exclude && (target.Depth == 0 || target.IsGroup) && (exclude == null || (!target.Id.StartsWith(exclude.Id + "/", StringComparison.Ordinal) && !exclude.Id.StartsWith(target.Id + "/", StringComparison.Ordinal))) && LayoutEngine.TryGetScreenRect(target, out var screenRect, out var _)) { Add(new Rect(((Rect)(ref screenRect)).x, (float)Screen.height - ((Rect)(ref screenRect)).yMax, ((Rect)(ref screenRect)).width, ((Rect)(ref screenRect)).height)); } } for (int i = 0; i < _widgets.Count; i++) { Rect val = _widgets[i]; if (!excludeRect.HasValue || !SameBox(val, excludeRect.Value)) { Add(val); } } } private static bool SameBox(Rect a, Rect b) { if (Mathf.Abs(((Rect)(ref a)).x - ((Rect)(ref b)).x) < 1f && Mathf.Abs(((Rect)(ref a)).y - ((Rect)(ref b)).y) < 1f && Mathf.Abs(((Rect)(ref a)).width - ((Rect)(ref b)).width) < 1f) { return Mathf.Abs(((Rect)(ref a)).height - ((Rect)(ref b)).height) < 1f; } return false; } private static void Add(Rect r) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) _guidesX.Add(((Rect)(ref r)).xMin); _guidesX.Add(((Rect)(ref r)).center.x); _guidesX.Add(((Rect)(ref r)).xMax); _guidesY.Add(((Rect)(ref r)).yMin); _guidesY.Add(((Rect)(ref r)).center.y); _guidesY.Add(((Rect)(ref r)).yMax); } public static void Clear() { _shownX = float.NaN; _shownY = float.NaN; } public static Vector2 ForBox(Rect wouldBe) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) _shownX = float.NaN; _shownY = float.NaN; return new Vector2(Axis(_guidesX, ((Rect)(ref wouldBe)).xMin, ((Rect)(ref wouldBe)).center.x, ((Rect)(ref wouldBe)).xMax, ref _shownX), Axis(_guidesY, ((Rect)(ref wouldBe)).yMin, ((Rect)(ref wouldBe)).center.y, ((Rect)(ref wouldBe)).yMax, ref _shownY)); } public static Vector2 ForEdges(float x, float y) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) _shownX = float.NaN; _shownY = float.NaN; return new Vector2(Edge(_guidesX, x, ref _shownX), Edge(_guidesY, y, ref _shownY)); } private static float Axis(List guides, float min, float centre, float max, ref float shown) { float num = Distance; float result = 0f; for (int i = 0; i < guides.Count; i++) { float num2 = guides[i]; float num3 = Mathf.Abs(num2 - min); if (num3 < num) { num = num3; result = num2 - min; shown = num2; } num3 = Mathf.Abs(num2 - max); if (num3 < num) { num = num3; result = num2 - max; shown = num2; } num3 = Mathf.Abs(num2 - centre); if (num3 <= num) { num = num3; result = num2 - centre; shown = num2; } } return result; } private static float Edge(List guides, float edge, ref float shown) { float num = Distance; float result = 0f; for (int i = 0; i < guides.Count; i++) { float num2 = Mathf.Abs(guides[i] - edge); if (!(num2 >= num)) { num = num2; result = guides[i] - edge; shown = guides[i]; } } return result; } public static void DrawGuides() { //IL_0027: 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_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) if (!float.IsNaN(_shownX)) { GiltFrameTheme.DrawFill(new Rect(_shownX - 0.5f, 0f, 1f, (float)Screen.height), GuideColour); } if (!float.IsNaN(_shownY)) { GiltFrameTheme.DrawFill(new Rect(0f, _shownY - 0.5f, (float)Screen.width, 1f), GuideColour); } } } internal static class LayoutStore { [Serializable] public sealed class Adjustment { [JsonProperty("x")] public float X; [JsonProperty("y")] public float Y; [JsonProperty("scale")] public float Scale = 1f; [JsonProperty("rot")] public float Rotation; [JsonProperty("w")] public float Width; [JsonProperty("h")] public float Height; } [Serializable] private sealed class LayoutFile { [JsonProperty("version")] public int Version = 1; [JsonProperty("elements")] public Dictionary Elements = new Dictionary(); } private const int CurrentVersion = 1; private static LayoutFile _data = new LayoutFile(); private static bool _dirty; public static string FilePath => ModPaths.InConfigDir("layout.json"); public static int Count => _data.Elements.Count; public static string BackupPath => ModPaths.InConfigDir("layout.backup.json"); public static Dictionary ExportAll() { Dictionary dictionary = new Dictionary(_data.Elements.Count); foreach (KeyValuePair element in _data.Elements) { if (element.Value != null) { dictionary[element.Key] = new Adjustment { X = element.Value.X, Y = element.Value.Y, Scale = element.Value.Scale, Rotation = element.Value.Rotation, Width = element.Value.Width, Height = element.Value.Height }; } } return dictionary; } public static void ReplaceAll(IDictionary values) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) Clear(); if (values == null) { return; } foreach (KeyValuePair value in values) { if (value.Value != null) { Set(value.Key, new Vector2(value.Value.X, value.Value.Y), value.Value.Scale, value.Value.Rotation, new Vector2(value.Value.Width, value.Value.Height)); } } } public static bool TryGet(string id, out Vector2 offset, out float scale, out float rotation, out Vector2 size) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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_0021: 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_0049: 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) if (_data.Elements.TryGetValue(id, out var value)) { offset = new Vector2(value.X, value.Y); scale = value.Scale; rotation = value.Rotation; size = new Vector2(value.Width, value.Height); return true; } offset = Vector2.zero; scale = 1f; rotation = 0f; size = Vector2.zero; return false; } public static void Set(string id, Vector2 offset, float scale, float rotation, Vector2 size) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: 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_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) if (offset == Vector2.zero && Mathf.Approximately(scale, 1f) && Mathf.Approximately(rotation, 0f) && size == Vector2.zero) { if (_data.Elements.Remove(id)) { _dirty = true; } return; } if (!_data.Elements.TryGetValue(id, out var value)) { value = new Adjustment(); _data.Elements[id] = value; } if (value.X != offset.x || value.Y != offset.y || value.Scale != scale || value.Rotation != rotation || value.Width != size.x || value.Height != size.y) { value.X = offset.x; value.Y = offset.y; value.Scale = scale; value.Rotation = rotation; value.Width = size.x; value.Height = size.y; _dirty = true; } } public static void Clear() { if (_data.Elements.Count != 0) { _data.Elements.Clear(); _dirty = true; } } public static void Backup() { try { if (File.Exists(FilePath)) { File.Copy(FilePath, BackupPath, overwrite: true); Diagnostics.Trace(() => "layout: previous layout copied to " + BackupPath + " before reset"); } } catch (Exception ex) { Diagnostics.Health("Saved layout", ok: false, "the pre-reset backup could not be written, so this reset cannot be undone. Reason: " + ex.Message); } } public static void Load() { try { if (!File.Exists(FilePath)) { _data = new LayoutFile(); Diagnostics.Health("Saved layout", ok: true, "no layout file yet - every element is at its default position"); return; } _data = JsonConvert.DeserializeObject(File.ReadAllText(FilePath)) ?? new LayoutFile(); if (_data.Elements == null) { _data.Elements = new Dictionary(); } _dirty = false; Diagnostics.Health("Saved layout", ok: true, $"{_data.Elements.Count} customised element(s) loaded from layout.json"); } catch (Exception ex) { _data = new LayoutFile(); Diagnostics.Health("Saved layout", ok: false, "layout.json could not be read, so every element is at its default position. The file has been left alone. Reason: " + ex.Message); Plugin.Log.LogError((object)ex.ToString()); } } public static void SaveIfDirty() { if (!_dirty) { return; } try { Directory.CreateDirectory(Path.GetDirectoryName(FilePath)); File.WriteAllText(FilePath, JsonConvert.SerializeObject((object)_data, (Formatting)1)); _dirty = false; Diagnostics.Trace(() => $"layout: saved {_data.Elements.Count} customised element(s) to {FilePath}"); } catch (Exception ex) { Diagnostics.Health("Saved layout", ok: false, "layout.json could not be written. Your changes are active but will not survive a restart. Reason: " + ex.Message); Plugin.Log.LogError((object)ex.ToString()); } } } internal sealed class LayoutTarget { public string Id; public string Label; public string Category; public int Depth; public Func Resolve; public bool CanScale = true; public bool IsGroup; } internal static class LayoutDiscovery { private static readonly HashSet Excluded = new HashSet { "hudroot", "Damaged", "LavaWarning", "LoadingBlack", "Loading", "Sleeping", "Teleporting", "VikingOS" }; public const string ObjectPrefix = "VikingOS"; private static readonly Dictionary FriendlyNames = new Dictionary { { "healthpanel", "Health panel" }, { "staminapanel", "Stamina bar" }, { "eitrpanel", "Eitr bar" }, { "adrenalinepanel", "Adrenaline bar" }, { "StatusEffects", "Status effects" }, { "HotKeyBar", "Hotbar" }, { "MiniMap", "Minimap (both)" }, { "small", "Minimap (small)" }, { "large", "Minimap (large)" }, { "crosshair", "Crosshair group" }, { "GuardianPower", "Guardian power" }, { "EventBar", "Event bar" }, { "action_progress", "Action progress bar" }, { "BuildHud", "Build menu" }, { "ShipHud", "Ship HUD" }, { "MountHud", "Mount panel" }, { "Player", "Inventory panel" }, { "Crafting", "Crafting panel" }, { "Info", "Item info panel" }, { "Container", "Container panel" }, { "root", "Chat box" } }; private static readonly (string Category, Func Root)[] Roots = new(string, Func)[14] { ("HUD", () => (!((Object)(object)Hud.instance != (Object)null)) ? null : ((Component)Hud.instance).transform.Find("hudroot")), ("Inventory", () => (!((Object)(object)InventoryGui.instance != (Object)null)) ? null : ((Component)InventoryGui.instance).transform.Find("root")), ("Chat", () => (Transform)(object)((!((Object)(object)Chat.instance != (Object)null) || !((Object)(object)((Terminal)Chat.instance).m_chatWindow != (Object)null)) ? null : ((Terminal)Chat.instance).m_chatWindow)), ("Dialogue", () => (!((Object)(object)Chat.instance != (Object)null)) ? null : ((Component)Chat.instance).transform), ("Messages", () => InGui("TopLeftMessage")), ("Messages", () => InGui("ClosedCaptions")), ("Messages", () => InGui("Tutorial")), ("Messages", () => InGui("JoinCodeOverlay")), ("Trader", () => (!((Object)(object)StoreGui.instance != (Object)null)) ? null : ((Component)StoreGui.instance).transform), ("Texts", () => InGui("TextViewer")), ("Barber", () => InGui("BarberGui")), ("Menus", () => InGui("Menu")), ("Menus", () => InGui("UnifiedPopup")), ("Menus", () => InGui("ConnectionPanel")) }; private static readonly List _found = new List(); private static bool _discovered; private static int MaxDepth { get { if (ConfigManager.layoutDepth == null) { return 2; } return ConfigManager.layoutDepth.Value; } } public static IReadOnlyList All => _found; public static bool HasRun => _discovered; private static Transform IngameGui() { if (!((Object)(object)Hud.instance != (Object)null) || !((Object)(object)((Component)Hud.instance).transform.parent != (Object)null)) { return null; } return ((Component)Hud.instance).transform.parent; } private static Transform InGui(string child) { Transform val = IngameGui(); if (!((Object)(object)val != (Object)null)) { return null; } return val.Find(child); } public static void Discover() { _found.Clear(); (string, Func)[] roots = Roots; for (int i = 0; i < roots.Length; i++) { var (category, func) = roots[i]; Transform val; try { val = func(); } catch { continue; } if (!((Object)(object)val == (Object)null)) { Walk(val, category, ((Object)val).name, 0); } } _discovered = true; Diagnostics.Trace(() => $"layout: discovered {_found.Count} adjustable elements"); } private static void Walk(Transform parent, string category, string pathSoFar, int depth) { if (depth > MaxDepth) { return; } for (int i = 0; i < parent.childCount; i++) { Transform child = parent.GetChild(i); if (!(child is RectTransform) || Excluded.Contains(((Object)child).name) || ((Object)child).name.StartsWith("VikingOS", StringComparison.Ordinal)) { continue; } string text = pathSoFar + "/" + ((Object)child).name; string localPath = text.Substring(text.IndexOf('/') + 1); Func rootResolver = RootResolverFor(category); _found.Add(new LayoutTarget { Id = text, Label = (FriendlyNames.TryGetValue(((Object)child).name, out var value) ? value : ((Object)child).name), Category = category, Depth = depth, IsGroup = IsGroup(child, depth), Resolve = delegate { Transform val = rootResolver(); if (!((Object)(object)val == (Object)null)) { Transform obj = val.Find(localPath); return (RectTransform)(object)((obj is RectTransform) ? obj : null); } return (RectTransform)null; } }); Walk(child, category, text, depth + 1); } } private static bool IsGroup(Transform t, int depth) { if (depth >= MaxDepth) { return false; } if ((Object)(object)((Component)t).GetComponent() != (Object)null) { return true; } int num = 0; for (int i = 0; i < t.childCount; i++) { if (t.GetChild(i) is RectTransform) { num++; } if (num >= 2) { return true; } } return false; } private static Func RootResolverFor(string category) { (string, Func)[] roots = Roots; for (int i = 0; i < roots.Length; i++) { var (text, result) = roots[i]; if (text == category) { return result; } } return () => (Transform)null; } } internal static class LayoutUpright { private sealed class Held { public RectTransform Transform; public Quaternion Baseline; } private sealed class Subtree { public int OwnerId; public List Text = new List(); public bool Applied; } private static readonly Dictionary _subtrees = new Dictionary(); private static readonly HashSet _claimed = new HashSet(); public static void Forget() { _subtrees.Clear(); _claimed.Clear(); } public static void BeginFrame() { _claimed.Clear(); } public static void Apply(string id, RectTransform element, float rotation) { //IL_00c2: 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_010f: 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_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) if (!ConfigManager.layoutUprightText.Value) { return; } bool flag = !Mathf.Approximately(rotation, 0f); if (!_subtrees.TryGetValue(id, out var value) || value.OwnerId != ((Object)element).GetInstanceID()) { if (!flag) { return; } value = Collect(element); _subtrees[id] = value; } if (!flag) { if (!value.Applied) { return; } value.Applied = false; { foreach (Held item in value.Text) { if (!((Object)(object)item.Transform == (Object)null)) { ((Transform)item.Transform).localRotation = item.Baseline; } } return; } } Quaternion val = Quaternion.Euler(0f, 0f, 0f - rotation); value.Applied = true; foreach (Held item2 in value.Text) { if (!((Object)(object)item2.Transform == (Object)null) && _claimed.Add(((Object)item2.Transform).GetInstanceID())) { Quaternion val2 = item2.Baseline * val; if (((Transform)item2.Transform).localRotation != val2) { ((Transform)item2.Transform).localRotation = val2; } } } } private static Subtree Collect(RectTransform element) { Subtree subtree = new Subtree { OwnerId = ((Object)element).GetInstanceID() }; TMP_Text[] componentsInChildren = ((Component)element).GetComponentsInChildren(true); foreach (TMP_Text text in componentsInChildren) { Add(subtree, (Component)(object)text); } Text[] componentsInChildren2 = ((Component)element).GetComponentsInChildren(true); foreach (Text text2 in componentsInChildren2) { Add(subtree, (Component)(object)text2); } return subtree; } private static void Add(Subtree subtree, Component text) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)text == (Object)null) && !(text is TMP_SubMeshUI) && !(text is TMP_SubMesh)) { Transform transform = text.transform; RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null); if (val != null) { subtree.Text.Add(new Held { Transform = val, Baseline = ((Transform)val).localRotation }); } } } } } namespace BarrkUI.Configuration { public static class ConfigManager { public enum ChatStripPlacement { Side, Top, Bottom } private const string MinimumClientVersion = "0.9.2"; private static readonly ConfigSync configSync = new ConfigSync("wubarrk.VikingOS") { DisplayName = "VikingOS", CurrentVersion = "0.9.2", MinimumRequiredVersion = "0.9.2", ModRequired = true }; public static ConfigEntry serverConfigLocked; public static ConfigEntry shareEmotes; public static ConfigEntry goldTheme; public static ConfigEntry themePanels; public static ConfigEntry giltFrames; internal static ConfigEntry frameStyle; public static ConfigEntry uiGoldColour; public static ConfigEntry uiDeriveTones; public static ConfigEntry uiMetalShadow; public static ConfigEntry uiMetalHighlight; public static ConfigEntry uiPanelColour; public static ConfigEntry uiPanelOpacity; public static ConfigEntry uiTextColour; public static ConfigEntry uiMutedTextColour; public static ConfigEntry uiTextScale; public static ConfigEntry uiFontSizeDelta; public static ConfigEntry uiTitleSizeDelta; public static ConfigEntry uiSubTitleSizeDelta; public static ConfigEntry uiHeaderSizeDelta; public static ConfigEntry uiButtonSizeDelta; public static ConfigEntry uiRowSizeDelta; public static ConfigEntry uiFooterSizeDelta; public static ConfigEntry uiFieldSizeDelta; public static ConfigEntry chatStripPlacement; public static ConfigEntry layoutDepth; public static ConfigEntry chatEnabled; public static ConfigEntry alwaysShout; public static ConfigEntry chatTextSize; public static ConfigEntry embeddedEmoji; public static ConfigEntry chatLog; public static ConfigEntry killKgChat; public static ConfigEntry hudClock; public static ConfigEntry hudWeight; public static ConfigEntry hudCompass; public static ConfigEntry hudClockX; public static ConfigEntry hudClockY; public static ConfigEntry hudWeightX; public static ConfigEntry hudWeightY; public static ConfigEntry hudCompassX; public static ConfigEntry hudCompassY; public static ConfigEntry hudClockScale; public static ConfigEntry hudWeightScale; public static ConfigEntry hudCompassScale; public static ConfigEntry hudCompassPins; public static ConfigEntry hudCompassPlayers; public static ConfigEntry hudCompassPinLabel; public static ConfigEntry hudCompassPinRange; public static ConfigEntry hudCompassPinLimit; public static ConfigEntry hudCompassPinSize; public static ConfigEntry shareBoxX; public static ConfigEntry shareBoxY; public static ConfigEntry tradeWindowX; public static ConfigEntry tradeWindowY; public static ConfigEntry layoutEditorKey; public static ConfigEntry layoutTransformInPlace; public static ConfigEntry layoutReflowGrids; public static ConfigEntry layoutUprightText; public static ConfigEntry layoutSnap; public static ConfigEntry layoutSnapDistance; public static ConfigEntry layoutSectionMode; public static ConfigEntry layoutMenuX; public static ConfigEntry layoutMenuY; public static ConfigEntry layoutMenuOpen; public static ConfigEntry debugLogging; public static ConfigEntry debugOverlay; private static Dictionary _legacy; internal static ConfigSync Sync => configSync; public static void Init(ConfigFile config) { //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_025a: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) //IL_09bc: Unknown result type (might be due to invalid IL or missing references) //IL_09c1: Unknown result type (might be due to invalid IL or missing references) LoadLegacy(config); serverConfigLocked = config.Bind("1 - General", "Lock Configuration", true, "If on, the configuration is locked and can be changed by server admins only."); configSync.AddLockingConfigEntry(serverConfigLocked); goldTheme = BindLocal(config, "2 - Theme", "Gold Theme", Legacy("2 - UI Theme", "Gold Theme", fallback: true), "The master switch for everything VikingOS paints onto VALHEIM's own interface: the black-and-gold panel re-skin and the ornate frames. Turn it off and the game's UI looks exactly as it did before you installed the mod - while KEEPING the chat window, emoji, item sharing and the whole layout editor, none of which are decoration. Toggles live. This is the setting for 'I want the features, not the look'."); goldTheme.SettingChanged += delegate { PanelTheme.OnToggled(); }; themePanels = BindLocal(config, "2 - Theme", "Theme Inventory Panels", Legacy("2 - UI Theme", "Theme Inventory Panels", fallback: true), "Re-skins the inventory, container, crafting and item-info panel backgrounds in the VikingOS colours (whole panels, never a mix of vanilla and themed). Toggles live, so you can compare in play. Bars, slots and icons are never touched. Ignored while Gold Theme is off."); themePanels.SettingChanged += delegate { PanelTheme.OnToggled(); }; giltFrames = BindLocal(config, "2 - Theme", "Ornate Frames", Legacy("2 - UI Theme", "Gilt Frames", fallback: true), "Draws the ornate frame - rails, carved corners, crests, the same one the chat window wears - around the inventory and character screen, on the panels' own edges. Independent of the panel re-skin, so you can have the frames on vanilla wood or a themed panel with no frame. Ignored while Gold Theme is off."); frameStyle = BindLocal(config, "2 - Theme", "Frame Style", FrameStyle.Gilt, "Which carving the ornate frames are cut from. GILT is the original: a polished double rail with acanthus corners and a palmette crest. RUNIC is a broad chiselled band with square shoulders, a cut bind-rune at each corner and drilled pits along the edges - the most austere of the four. SERPENT braids two strands down every rail and resolves them into a beast head biting each corner. IRONBOUND is a heavy riveted strap with a bracket at each corner and a shield boss at the crest. All four are drawn at the same size, so switching moves nothing - and all four take their metal from the colours below, so a silver serpent or a black iron rune band is a second setting away."); uiGoldColour = BindLocal(config, "3 - Theme Colours", "Metal Colour", Legacy("2 - UI Theme", "UIGoldColour", new Color(0.8f, 0.62f, 0.26f, 1f)), "The metal every frame, rail and heading is made of. Unless you turn off the derived tones below, the shadow and highlight are worked out from this one colour - so silver, bronze, verdigris or blued steel is a single change. Applies live."); uiDeriveTones = BindLocal(config, "3 - Theme Colours", "Derive Metal Tones", defaultValue: true, "While on, the metal's shadow and highlight are derived from Metal Colour, which is what keeps a recolour looking like one material. Turn it off to set both by hand below - useful for a metal that is not a simple tint of one colour, such as a dark iron with a cold blue sheen."); uiMetalShadow = BindLocal(config, "3 - Theme Colours", "Metal Shadow", new Color(0.26f, 0.17f, 0.05f, 1f), "The deep tone in the carved parts of the frame. Ignored unless Derive Metal Tones is off."); uiMetalHighlight = BindLocal(config, "3 - Theme Colours", "Metal Highlight", new Color(1f, 0.94f, 0.72f, 1f), "The bright tone where the light catches the frame, and the colour of window titles. Ignored unless Derive Metal Tones is off. THIS IS THE ONE TO BRING DOWN if the headings read as too bright."); uiPanelColour = BindLocal(config, "3 - Theme Colours", "Panel Colour", new Color(0.075f, 0.065f, 0.051f, 1f), "The background of every VikingOS window and re-skinned panel. The default is the warm near-black the mod shipped with. Raise it for a lighter, parchment-ish interface; the buttons, list rows and text fields are all derived from it, so they lighten with it instead of staying black on a pale panel."); uiPanelOpacity = BindLocalRanged(config, "3 - Theme Colours", "Panel Opacity", 0.955f, "How solid the window backgrounds are. 1 is opaque; lower it to let the game show through. Below about 0.5 the text starts competing with whatever is behind it.", 0.15f, 1f); uiTextColour = BindLocal(config, "3 - Theme Colours", "Text Colour", new Color(0.9f, 0.86f, 0.75f, 1f), "The main body text in VikingOS windows - values, list rows, field contents."); uiMutedTextColour = BindLocal(config, "3 - Theme Colours", "Muted Text Colour", new Color(0.6f, 0.56f, 0.48f, 1f), "The quieter text: labels, hints, footers and notes. Keep it dimmer than Text Colour or the two stop being distinguishable, which is the whole job they do."); uiGoldColour.SettingChanged += delegate { PanelTheme.OnColourChanged(); }; uiPanelColour.SettingChanged += delegate { PanelTheme.OnColourChanged(); }; uiPanelOpacity.SettingChanged += delegate { PanelTheme.OnColourChanged(); }; uiTextScale = BindLocal(config, "4 - Text Sizes", "Text Scale", Legacy("2 - UI Theme", "UITextScale", 1.05f), "Scales all text in VikingOS windows, and the layout around it. 1 is the theme's designed size. This is the proportional zoom - use it to make everything bigger at once, and the per-kind settings below to change the balance between them."); uiFontSizeDelta = BindLocal(config, "4 - Text Sizes", "All Text Size", Legacy("2 - UI Theme", "UIFontSizeDelta", 3), "FLAT points added to every text size, applied after Text Scale. 0 = the theme's own base sizes. Every setting below is added ON TOP of this one, so this stays the single dial for 'a bit bigger everywhere'."); int defaultValue = Legacy("2 - UI Theme", "UIHeadingSizeDelta", 0); uiTitleSizeDelta = BindLocal(config, "4 - Text Sizes", "Window Title Size", defaultValue, "FLAT points added to WINDOW TITLES only, on top of All Text Size. Negative shrinks them. The title band resizes itself to match, so nothing clips. Use it when the body text is right but the titles are shouting."); uiSubTitleSizeDelta = BindLocal(config, "4 - Text Sizes", "Sub-Title Size", defaultValue, "FLAT points added to SUB-TITLES only - the larger gold headings inside a window - on top of All Text Size."); uiHeaderSizeDelta = BindLocal(config, "4 - Text Sizes", "Small Label Size", defaultValue, "FLAT points added to the SMALL GOLD LABELS only - the caps headings over the chat strip, the pickers and each column of the trade window - on top of All Text Size."); uiButtonSizeDelta = BindLocal(config, "4 - Text Sizes", "Button Text Size", 0, "FLAT points added to BUTTON text only, on top of All Text Size. The chat button bar divides the width it has between five buttons, so this is the setting for 'the labels are too small to read' without enlarging the whole window."); uiRowSizeDelta = BindLocal(config, "4 - Text Sizes", "List Row Size", 0, "FLAT points added to LIST ROWS only - the layout editor's element list, the player list, the emoji footer - on top of All Text Size."); uiFooterSizeDelta = BindLocal(config, "4 - Text Sizes", "Footer Size", 0, "FLAT points added to the FOOTER line at the bottom of a window, on top of All Text Size. The footer band resizes itself to match."); uiFieldSizeDelta = BindLocal(config, "4 - Text Sizes", "Input Field Size", 0, "FLAT points added to TEXT FIELDS only - the layout editor's search and preset name boxes - on top of All Text Size."); chatEnabled = BindServerOwned(config, "5 - Chat", "Enable VikingOS Chat", Legacy("3 - Chat", "Enable VikingOS Chat", fallback: true), "The server's master switch for everything VikingOS does to chat: the shout and emoji strip, the emoji picker and autocomplete, drag-and-drop item sharing, emote rendering and Always Shout. Turn it off and every player on this server keeps Valheim's own chat, untouched - useful when the server already runs another chat mod. Server-owned and read ONCE, when a player joins, so a change here needs a SERVER RESTART to take effect; it cannot be flipped mid-session, because half the overhaul is installed while the game is starting up. Leave it at true unless you have a reason not to. Two things it deliberately does NOT switch off, because neither reaches another player: the fix that stops shouts being rewritten in CAPITALS (removed from the game's code at load, so there is nothing to put back) and each player's own Chat Text Size."); shareEmotes = BindServerOwned(config, "5 - Chat", "Share Emotes", Legacy("3 - Chat", "Share Emotes", fallback: true), "While on, PNG and GIF files the admin drops into config/VikingOS/emotes/ on the SERVER are offered to every player, who then type :filename: in chat to use them. Turning it off publishes an empty emote list. Server-owned, like every chat rule. Reload live with the 'vikingos_emotereload' console command (admins only)."); alwaysShout = BindServerOwned(config, "5 - Chat", "Always Shout", Legacy("3 - Chat", "Always Shout", fallback: false), "While on, every chat message you send goes out as Shout range regardless of typed /w or /s prefix, until you turn it back off. Server-owned: set it in wubarrk.VikingOS.cfg on the SERVER, the same way KG Chat is switched with EnableKGChat in MarketPlace.cfg."); embeddedEmoji = BindLocal(config, "5 - Chat", "Embedded Emoji Library", Legacy("3 - Chat", "Embedded Emoji Library", fallback: true), "The standard emoji set built into VikingOS: ~1,900 emojis under their usual :shortcodes: (:joy:, :fire:, :sob: - the same names Discord uses) plus an animated set that takes priority over its static twins. Type :name: in chat. Costs some video memory for the atlas; turn it off to keep only server emotes and your own emojipacks folder."); chatLog = BindLocal(config, "5 - Chat", "Chat Transcript", Legacy("3 - Chat", "Chat Transcript", fallback: true), "Writes every chat message this machine sees to config/VikingOS/Chats/chat-YYYY-MM-DD.log, one file per day. On a SERVER that is every message it relays, which is the closest thing Valheim has to a shout log. The same folder holds outbox.txt: anything written into that file is broadcast to every player as a shout and the file is then emptied, which is how a headless server can talk without a console."); chatStripPlacement = BindLocal(config, "5 - Chat", "Chat Button Bar", Legacy("3 - Chat", "Chat Button Bar", ChatStripPlacement.Top), "Where the VikingOS chat buttons sit. Top is one row above the chat box, which puts them next to the emoji picker and gives the chat log the full width. Bottom is the same row underneath. Side is the original column beside the chat box. Switching to or from Side widens or narrows the chat box once to match, which you can then adjust like any other layout change."); chatTextSize = BindLocalRanged(config, "5 - Chat", "Chat Text Size", Legacy("3 - Chat", "Chat Text Size", 18f), "Point size of the chat log and input text. Vanilla is 18, which reads small on a 1440p or 4K monitor. Applies live.", 12f, 40f); chatTextSize.SettingChanged += delegate { ChatWindowFix.OnTextSizeChanged(); }; hudClock = BindLocal(config, "6 - HUD Widgets", "Clock", Legacy("5 - HUD Widgets", "Clock", fallback: true), "A small VikingOS clock on the HUD: your local time, server time (EST), and the in-game day and time of day. Drag it anywhere while the cursor is free (inventory, chat or edit mode). Hides with the HUD (Ctrl+F3)."); hudWeight = BindLocal(config, "6 - HUD Widgets", "Weight Meter", Legacy("5 - HUD Widgets", "Weight Meter", fallback: true), "A live carry-weight meter on the HUD - the 45/300 readout with a fill bar, without opening the inventory. Blinks red when overloaded, exactly like the inventory's own number. Drag it anywhere while the cursor is free. Hides with the HUD (Ctrl+F3)."); hudCompass = BindLocal(config, "6 - HUD Widgets", "Compass", defaultValue: true, "A compass across the top of the screen: a sliding tape of the horizon centred on where you are looking, with the eight cardinal points and a bearing in degrees. North is lit, because north is the one you look for. It reads the CAMERA rather than your body, so it turns with the view rather than lagging behind it, and its bearings match the map's. Drag it anywhere while the cursor is free, and drag the corner grip to resize. Hides with the HUD (Ctrl+F3)."); hudCompassPins = BindLocal(config, "6 - HUD Widgets", "Compass Map Pins", defaultValue: true, "Show your map pins on the compass. Every pin the map knows about appears, whoever made it - your own markers, your death and your bed, boss stones, and the pins any other mod leaves behind, portals and shops included. A pin type you have hidden with the map's filter buttons is hidden here too, so the compass and the map always agree."); hudCompassPlayers = BindLocal(config, "6 - HUD Widgets", "Compass Players", defaultValue: true, "Show other players on the compass, as the same small red figure the map uses. Only players sharing their position appear, exactly as on the map."); hudCompassPinLabel = BindLocal(config, "6 - HUD Widgets", "Compass Pin Names", defaultValue: true, "Name whatever you have turned to face, underneath the compass, with how far away it is. Only the mark nearest the centre line is named - a caption on every pin would be a row of overlapping text."); hudCompassPinRange = BindLocalRanged(config, "6 - HUD Widgets", "Compass Pin Range", 0f, "How far away a pin can be and still show on the compass, in metres. 0 means no limit. Raise it to steer towards something across the map; lower it to clear the clutter of a busy base.", 0f, 10000f); hudCompassPinLimit = BindLocalRangedInt(config, "6 - HUD Widgets", "Compass Pin Limit", 24, "The most pins the compass will show at once. The nearest ones win, counted across the whole map rather than across what is in front of you - so the marks do not change as you turn.", 1, 100); hudCompassPinSize = BindLocalRanged(config, "6 - HUD Widgets", "Compass Pin Size", 1f, "How big the pin icons are on the compass, relative to the strip they sit in.", 0.4f, 2f); hudClockX = BindLocal(config, "8 - Window Positions", "Clock X", Legacy("10 - Window Positions", "Clock X", 0.45f), "Where the clock sits, as a fraction of screen width (0 = left edge, 1 = right). Drag the widget to move it - this just remembers where you left it."); hudClockY = BindLocal(config, "8 - Window Positions", "Clock Y", Legacy("10 - Window Positions", "Clock Y", 0.005f), "Where the clock sits, as a fraction of screen height (0 = top, 1 = bottom)."); hudWeightX = BindLocal(config, "8 - Window Positions", "Weight Meter X", Legacy("10 - Window Positions", "Weight Meter X", 0.86f), "Where the weight meter sits, as a fraction of screen width."); hudWeightY = BindLocal(config, "8 - Window Positions", "Weight Meter Y", Legacy("10 - Window Positions", "Weight Meter Y", 0.72f), "Where the weight meter sits, as a fraction of screen height."); hudCompassX = BindLocal(config, "8 - Window Positions", "Compass X", 0.395f, "Where the compass sits, as a fraction of screen width. Drag the widget to move it."); hudCompassY = BindLocal(config, "8 - Window Positions", "Compass Y", 0.078f, "Where the compass sits, as a fraction of screen height. The default clears the clock; set it to 0 to put the compass hard against the top edge."); hudClockScale = BindLocalRanged(config, "8 - Window Positions", "Clock Size", Legacy("10 - Window Positions", "Clock Size", 1f), "How big the clock is. Drag the gold grip in its bottom-right corner to resize - this just remembers where you left it. The box measures itself around the text, so it grows and shrinks as one piece.", 0.5f, 3f); hudWeightScale = BindLocalRanged(config, "8 - Window Positions", "Weight Meter Size", Legacy("10 - Window Positions", "Weight Meter Size", 1f), "How big the weight meter is. Drag the gold grip in its bottom-right corner to resize.", 0.5f, 3f); hudCompassScale = BindLocalRanged(config, "8 - Window Positions", "Compass Size", 1f, "How big the compass is. Drag the gold grip in its bottom-right corner to resize. A wider compass shows the same half-turn of horizon spread over more pixels, so the marks separate rather than the sweep changing.", 0.5f, 3f); shareBoxX = BindLocal(config, "8 - Window Positions", "Share Item Box X", Legacy("10 - Window Positions", "Share Item Box X", -1f), "Where the Share Item box sits, as a fraction of screen width. Drag the box by its title bar to move it - this just remembers where you left it. Below zero means 'not placed yet', and an unplaced box docks itself beside your character panel wherever your layout puts it; set this back to -1 to get that behaviour again."); shareBoxY = BindLocal(config, "8 - Window Positions", "Share Item Box Y", Legacy("10 - Window Positions", "Share Item Box Y", -1f), "Where the Share Item box sits, as a fraction of screen height. Below zero means 'not placed yet' - see Share Item Box X."); tradeWindowX = BindLocal(config, "8 - Window Positions", "Trade Window X", Legacy("10 - Window Positions", "Trade Window X", 320f), "Where the trade window opens. Drag it by its title bar to move it - this just remembers where you left it."); tradeWindowY = BindLocal(config, "8 - Window Positions", "Trade Window Y", Legacy("10 - Window Positions", "Trade Window Y", 180f), "Where the trade window opens. Drag it by its title bar to move it - this just remembers where you left it."); layoutMenuX = BindLocal(config, "8 - Window Positions", "Layout Menu X", Legacy("10 - Window Positions", "Layout Menu X", 24f), "Drag the VikingOS menu by its title bar to move it - this just remembers where you left it."); layoutMenuY = BindLocal(config, "8 - Window Positions", "Layout Menu Y", Legacy("10 - Window Positions", "Layout Menu Y", 24f), "Drag the VikingOS menu by its title bar to move it - this just remembers where you left it."); layoutMenuOpen = BindLocal(config, "8 - Window Positions", "Layout Menu Open", Legacy("10 - Window Positions", "Layout Menu Open", fallback: true), "Whether the VikingOS menu is expanded or rolled up to its title pill. Click the arrow in its title bar to change it."); layoutEditorKey = BindLocal(config, "7 - Layout", "Edit Mode Key", Legacy("11 - Layout", "Edit Mode Key", new KeyboardShortcut((KeyCode)291, Array.Empty())), "Opens and closes layout edit mode, where you can drag any VikingOS-managed UI element to move it, scroll over it to resize it, and right-click it to reset it. Rebind freely - modifier combinations work, and None disables the hotkey in favour of the 'vikingos_layout edit' console command. Ignored while you are typing in chat, the console or a text field - except for function keys, which type nothing and so have nothing to stand down for."); layoutDepth = BindLocalRangedInt(config, "7 - Layout", "Element Depth", Legacy("11 - Layout", "Element Depth", 2), "How far into each UI panel the layout editor looks for things you can move. 2 lists panels and their major parts, which is what most screens want. 3 and 4 reach individual labels, icons and bar fills - far more entries, and the search box becomes the way you find anything. Nothing is lost by lowering it again: positions you have already set are remembered by name and return when you raise it.", 1, 5); layoutDepth.SettingChanged += delegate { LayoutEngine.RediscoverSoon(); }; layoutTransformInPlace = BindLocal(config, "7 - Layout", "Scale And Rotate In Place", Legacy("11 - Layout", "Scale And Rotate In Place", fallback: true), "Unity scales and rotates a UI element around its PIVOT, and Valheim's pivots are rarely the centre - the health panel's is its top-left corner, so resizing it makes it slide down-right and rotating it swings it off the screen entirely. While this is on, VikingOS compensates so elements grow and turn about their own centre, which is what everyone means by 'make it bigger'. Turn it off only if you specifically want raw pivot behaviour."); layoutReflowGrids = BindLocal(config, "7 - Layout", "Re-Flow Grids On Resize", Legacy("11 - Layout", "Re-Flow Grids On Resize", fallback: true), "Valheim positions the slots in the hotbar and in every inventory grid by hand in code rather than with a Unity layout group, so resizing one of those boxes would otherwise change the box and leave the slots exactly where they were. With this on, VikingOS re-flows them to fit: make the hotbar narrower and it wraps onto a second row, make it wider and it unwraps. Only containers whose children really are a uniform grid are ever touched, and only after you have resized one. Reset the size and the game's own arrangement comes back."); layoutSnap = BindLocal(config, "7 - Layout", "Snap While Dragging", Legacy("11 - Layout", "Snap While Dragging", fallback: true), "While arranging, things snap to the screen's centre and edges, to the edges and centres of other panels, and to the VikingOS clock, weight meter and compass - with a gold guide line across the screen showing what you lined up with. Applies to moving an element, to dragging a corner grip to resize one, and to dragging the HUD widgets. Hold Alt to suspend it for as long as you hold it."); layoutSnapDistance = BindLocalRanged(config, "7 - Layout", "Snap Distance", 8f, "How close, in screen pixels, an edge has to come to a guide before it snaps to it. Small values make snapping feel precise but hard to catch; large ones make it hard to place something deliberately NEAR an edge without landing on it. Raise it on a 4K screen, where the same distance is a smaller part of the picture.", 1f, 30f); layoutSectionMode = BindLocal(config, "7 - Layout", "Grab Whole Sections", defaultValue: true, "While on, clicking anywhere inside a panel in edit mode picks up the WHOLE panel - everything in it moves together, which is almost always what you want. Hold Ctrl while you click to reach the individual piece under the cursor instead. Turn this off to go back to the reverse: pieces by default, and the panel only by its red border. Either way, choosing a row from the list above always selects exactly that row."); layoutUprightText = BindLocal(config, "7 - Layout", "Keep Text Upright When Rotated", Legacy("11 - Layout", "Keep Text Upright When Rotated", fallback: true), "Rotating an element rotates everything inside it, labels included - so turning the health bar on its side turns its numbers on their side too. With this on, VikingOS cancels the rotation back out of the text alone: the numbers keep the position the rotation gave them, so they still travel along a vertical bar, but they stay the right way up and readable. Turn it off if you actually want the text to turn with the panel."); killKgChat = BindLocal(config, "9 - Compatibility", "Disable KG Chat", Legacy("4 - Compatibility", "Disable KG Chat", fallback: true), "KG Chat (bundled inside KG Marketplace & Server NPCs) replaces Valheim's chat outright - it DESTROYS the vanilla Chat component, deactivates the vanilla input field and unregisters vanilla's ChatMessage RPC, then installs its own. VikingOS cannot skin, extend or coexist with what is no longer there. While this is on, VikingOS stops that swap from ever happening; the rest of KG Marketplace - the marketplace, NPCs, quests, everything else - is untouched and works normally. NOTE: if you run the server, the tidier fix is KG's own switch - set EnableKGChat=false in the server's MarketPlace.cfg (it defaults to true and is server-side only, so it cannot be set from a client). This setting is for when you are NOT the admin. Turn it OFF to keep KG Chat and give up VikingOS's chat features."); debugLogging = BindLocal(config, "99 - Debug", "Debug Logging", Legacy("99 - Debug", "Debug Logging", fallback: false), "Verbose per-message and per-action logging to the BepInEx console: item shares sent and received, link resolution and why anything was rejected, drag detection, and panel visibility. Off by default because it is noisy. Toggle it live with the 'vikingos_debug' console command, which also prints a status summary."); debugOverlay = BindLocal(config, "99 - Debug", "Debug Overlay", Legacy("99 - Debug", "Debug Overlay", fallback: false), "Draws a compact live state readout in the chat panel: visibility gates, drag state, cached share count. Independent of Debug Logging - useful when the question is 'why is nothing happening' rather than 'what happened'."); _legacy = null; } private static void LoadLegacy(ConfigFile config) { _legacy = new Dictionary(StringComparer.OrdinalIgnoreCase); try { string configFilePath = config.ConfigFilePath; if (string.IsNullOrEmpty(configFilePath) || !File.Exists(configFilePath)) { return; } string section = string.Empty; string[] array = File.ReadAllLines(configFilePath); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length == 0 || text[0] == '#') { continue; } if (text[0] == '[' && text[text.Length - 1] == ']') { section = text.Substring(1, text.Length - 2).Trim(); continue; } int num = text.IndexOf('='); if (num > 0) { _legacy[LegacyKey(section, text.Substring(0, num).Trim())] = text.Substring(num + 1).Trim(); } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("could not read the existing config for migration (non-fatal, 0.8.x settings may return to defaults). Reason: " + ex.Message)); } } private static string LegacyKey(string section, string key) { return section + "\u0001" + key; } private static T Legacy(string oldSection, string oldKey, T fallback) { if (_legacy == null) { return fallback; } if (!_legacy.TryGetValue(LegacyKey(oldSection, oldKey), out var value)) { return fallback; } try { return (T)TomlTypeConverter.ConvertToValue(value, typeof(T)); } catch { return fallback; } } public static ConfigEntryBase[] PresetEntries() { return (ConfigEntryBase[])(object)new ConfigEntryBase[43] { (ConfigEntryBase)hudClock, (ConfigEntryBase)hudWeight, (ConfigEntryBase)hudCompass, (ConfigEntryBase)hudClockX, (ConfigEntryBase)hudClockY, (ConfigEntryBase)hudWeightX, (ConfigEntryBase)hudWeightY, (ConfigEntryBase)hudCompassX, (ConfigEntryBase)hudCompassY, (ConfigEntryBase)hudClockScale, (ConfigEntryBase)hudWeightScale, (ConfigEntryBase)hudCompassScale, (ConfigEntryBase)hudCompassPins, (ConfigEntryBase)hudCompassPlayers, (ConfigEntryBase)hudCompassPinLabel, (ConfigEntryBase)hudCompassPinRange, (ConfigEntryBase)hudCompassPinLimit, (ConfigEntryBase)hudCompassPinSize, (ConfigEntryBase)shareBoxX, (ConfigEntryBase)shareBoxY, (ConfigEntryBase)layoutMenuX, (ConfigEntryBase)layoutMenuY, (ConfigEntryBase)tradeWindowX, (ConfigEntryBase)tradeWindowY, (ConfigEntryBase)frameStyle, (ConfigEntryBase)uiGoldColour, (ConfigEntryBase)uiDeriveTones, (ConfigEntryBase)uiMetalShadow, (ConfigEntryBase)uiMetalHighlight, (ConfigEntryBase)uiPanelColour, (ConfigEntryBase)uiPanelOpacity, (ConfigEntryBase)uiTextColour, (ConfigEntryBase)uiMutedTextColour, (ConfigEntryBase)uiTextScale, (ConfigEntryBase)uiFontSizeDelta, (ConfigEntryBase)uiTitleSizeDelta, (ConfigEntryBase)uiSubTitleSizeDelta, (ConfigEntryBase)uiHeaderSizeDelta, (ConfigEntryBase)uiButtonSizeDelta, (ConfigEntryBase)uiRowSizeDelta, (ConfigEntryBase)uiFooterSizeDelta, (ConfigEntryBase)uiFieldSizeDelta, (ConfigEntryBase)chatTextSize }; } private static ConfigEntry BindServerOwned(ConfigFile config, string section, string key, T defaultValue, string description) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown ConfigEntry val = config.Bind(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { new ConfigManagerAttributes { Browsable = false } })); configSync.AddConfigEntry(val); return val; } private static ConfigEntry BindSynced(ConfigFile config, string section, string key, T defaultValue, string description) { ConfigEntry val = config.Bind(section, key, defaultValue, description); configSync.AddConfigEntry(val); return val; } public static void ApplyTheme() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0068: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: 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) ThemeOptions o = ThemeOptions.Default; o.Frame = ((frameStyle != null) ? frameStyle.Value : FrameStyle.Gilt); o.Metal = uiGoldColour.Value; o.DeriveTones = uiDeriveTones == null || uiDeriveTones.Value; o.Deep = ((uiMetalShadow != null) ? uiMetalShadow.Value : o.Deep); o.Bright = ((uiMetalHighlight != null) ? uiMetalHighlight.Value : o.Bright); o.Panel = ((uiPanelColour != null) ? uiPanelColour.Value : o.Panel); o.PanelOpacity = ((uiPanelOpacity != null) ? uiPanelOpacity.Value : o.PanelOpacity); o.Text = ((uiTextColour != null) ? uiTextColour.Value : o.Text); o.MutedText = ((uiMutedTextColour != null) ? uiMutedTextColour.Value : o.MutedText); o.Scale = uiTextScale.Value; o.BodyDelta = uiFontSizeDelta.Value; o.TitleDelta = ((uiTitleSizeDelta != null) ? uiTitleSizeDelta.Value : 0); o.SubTitleDelta = ((uiSubTitleSizeDelta != null) ? uiSubTitleSizeDelta.Value : 0); o.HeaderDelta = ((uiHeaderSizeDelta != null) ? uiHeaderSizeDelta.Value : 0); o.ButtonDelta = ((uiButtonSizeDelta != null) ? uiButtonSizeDelta.Value : 0); o.RowDelta = ((uiRowSizeDelta != null) ? uiRowSizeDelta.Value : 0); o.FooterDelta = ((uiFooterSizeDelta != null) ? uiFooterSizeDelta.Value : 0); o.FieldDelta = ((uiFieldSizeDelta != null) ? uiFieldSizeDelta.Value : 0); GiltFrameTheme.EnsureBuilt(o); } private static ConfigEntry BindLocal(ConfigFile config, string section, string key, T defaultValue, string description) { return config.Bind(section, key, defaultValue, description); } private static ConfigEntry BindLocalRanged(ConfigFile config, string section, string key, float defaultValue, string description, float min, float max) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown return config.Bind(section, key, Mathf.Clamp(defaultValue, min, max), new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange(min, max), Array.Empty())); } private static ConfigEntry BindLocalRangedInt(ConfigFile config, string section, string key, int defaultValue, string description, int min, int max) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown return config.Bind(section, key, Mathf.Clamp(defaultValue, min, max), new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange(min, max), Array.Empty())); } } } namespace BarrkUI.Compat { internal static class KgChatOverride { private const string KgChatTypeName = "Marketplace.Modules.KG_Chat.KG_Chat"; private const string ApplyMethodName = "ApplyKGChat"; private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.Compat.KGChat"); private static bool _announced; public static void Apply(Harmony harmony) { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected O, but got Unknown try { Type type = AccessTools.TypeByName("Marketplace.Modules.KG_Chat.KG_Chat"); if (type == null) { Diagnostics.Trace(() => "KG Chat not installed - nothing to override."); return; } if (!ConfigManager.killKgChat.Value) { Diagnostics.Health("KG Chat override", ok: true, "KG Chat is installed and VikingOS is configured to leave it alone - VikingOS's chat features will not work while it owns the chat window"); return; } MethodInfo methodInfo = AccessTools.Method(type, "ApplyKGChat", (Type[])null, (Type[])null); if (methodInfo == null) { Diagnostics.Health("KG Chat override", ok: false, "found Marketplace.Modules.KG_Chat.KG_Chat but not its ApplyKGChat method - KG Marketplace has changed. KG Chat will take over the chat window and VikingOS's chat features will not work. Please report this."); return; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(AccessTools.Method(typeof(KgChatOverride), "SuppressInstall", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Diagnostics.Health("KG Chat override", ok: true, "KG Chat install suppressed; the rest of KG Marketplace is untouched"); } catch (Exception ex) { Diagnostics.Health("KG Chat override", ok: false, "could not suppress KG Chat, so it will take over the chat window. Reason: " + ex.Message); Log.LogError((object)ex.ToString()); } } private static bool SuppressInstall() { if (!ConfigManager.killKgChat.Value) { return true; } if (!_announced) { _announced = true; Log.LogInfo((object)"KG Chat tried to replace the vanilla chat window; VikingOS blocked it. The rest of KG Marketplace is unaffected. Set '4 - Compatibility/Disable KG Chat' to false if you would rather keep KG Chat."); } return false; } public static void VerifyOutcome() { try { if (AccessTools.TypeByName("Marketplace.Modules.KG_Chat.KG_Chat") == null || !ConfigManager.killKgChat.Value || (Object)(object)Chat.instance == (Object)null) { return; } if (((Object)((Component)Chat.instance).gameObject).name == "KGChat") { Diagnostics.Health("KG Chat override", ok: false, "KG Chat took over the chat window despite the override - VikingOS's chat features will not work this session. KG Marketplace has probably changed how it installs. Please report this."); return; } Diagnostics.Trace(() => "Verified: vanilla Chat is still the live chat window."); } catch (Exception arg) { Log.LogError((object)$"KG Chat outcome verification failed (non-fatal). Reason: {arg}"); } } } } namespace BarrkUI.ChatOverhaul { [HarmonyPatch(typeof(Chat), "SendText")] internal static class AlwaysShoutPatch { [HarmonyPrefix] private static void Prefix(ref Type type) { if (ChatFeatures.Enabled && ConfigManager.alwaysShout.Value) { type = (Type)2; } } } internal static class ChatCommands { [HarmonyPatch(typeof(Chat), "InputText")] internal static class InputTextPatch { [HarmonyPrefix] private static bool Prefix(Chat __instance) { try { return !TryHandle(((Object)(object)((Terminal)__instance).m_input != (Object)null) ? ((TMP_InputField)((Terminal)__instance).m_input).text : null); } catch (Exception arg) { Log.LogError((object)$"chat command handling failed (non-fatal, the line runs as normal chat). Reason: {arg}"); return true; } } } private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.ChatCommands"); private static bool TryHandle(string typed) { if (string.IsNullOrEmpty(typed) || typed[0] != '/') { return false; } string text = typed.Substring(1); int num = text.IndexOf(' '); string text2 = ((num < 0) ? text : text.Substring(0, num)).ToLowerInvariant(); string rest = ((num < 0) ? string.Empty : text.Substring(num + 1).Trim()); if (text2 == "trade") { Trade(rest); return true; } if (!ChatFeatures.Enabled) { return false; } return WhisperRpc.TryHandleVerb(text2, rest); } private static void Trade(string rest) { if (TradeRpc.Busy) { TradeWindow.BringToFront(); return; } if (string.IsNullOrWhiteSpace(rest)) { if (!ChatFeatures.Enabled) { Notice("Type /trade - the player list needs VikingOS chat, which this server has switched off."); return; } PlayerPicker.Open("TRADE WITH", delegate(string name, long uid) { TradeRpc.Invite(name, uid); }); return; } foreach (KeyValuePair item in WhisperRpc.OnlinePlayers()) { if (string.Equals(item.Key, rest, StringComparison.OrdinalIgnoreCase)) { TradeRpc.Invite(item.Key, item.Value); return; } } Notice("No player called \"" + rest + "\" is online."); } private static void Notice(string text) { Chat instance = Chat.instance; if (!((Object)(object)instance == (Object)null)) { ((Terminal)instance).AddString(text); instance.m_hideTimer = 0f; } } } internal static class ChatFeatures { private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.ChatFeatures"); private static bool _latched; private static bool _enabled = true; public static bool Enabled => _enabled; public static void LatchForSession() { if (_latched) { return; } _latched = true; _enabled = ConfigManager.chatEnabled == null || ConfigManager.chatEnabled.Value; if (_enabled) { Diagnostics.Trace(() => "chat features enabled for this session."); } else { Log.LogInfo((object)"VikingOS chat is switched OFF for this session by the server ('Enable VikingOS Chat' in the server's wubarrk.VikingOS.cfg). The vanilla chat is left alone. Changing it takes a server restart."); } } public static void ResetSession() { _latched = false; _enabled = true; } public static string Describe() { if (!_latched) { return "not decided yet (no world joined)"; } if (!_enabled) { return "off (server switched it off)"; } return "on"; } } [HarmonyPatch] internal static class ChatMessagePatch { private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.Chat"); private static readonly MethodInfo ToUpperMethod = AccessTools.Method(typeof(string), "ToUpper", Type.EmptyTypes, (Type[])null); private static readonly MethodInfo ToLowerInvariantMethod = AccessTools.Method(typeof(string), "ToLowerInvariant", Type.EmptyTypes, (Type[])null); private const int ExpectedRemovalsPerMethod = 2; private static IEnumerable RemoveForcedCase(IEnumerable instructions, string target) { int removed = 0; foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.Calls(instruction, ToUpperMethod) || CodeInstructionExtensions.Calls(instruction, ToLowerInvariantMethod)) { removed++; } else { yield return instruction; } } ReportCaseFix(target, removed); } private static void ReportCaseFix(string target, int removed) { string feature = "Case preservation (" + target + ")"; if (removed == 2) { Diagnostics.Health(feature, ok: true, $"removed {removed} case-forcing calls as expected"); } else if (removed > 0) { Diagnostics.Health(feature, ok: false, $"removed {removed} case-forcing call(s), expected {2}. Valheim has changed this " + "method; case preservation may be partial (one channel fixed, the other not). Please report the game version."); } else { Diagnostics.HealthUnknown(feature, "found no case-forcing calls to remove. Either another chat mod's transpiler already removed them (KG Chat does exactly this, and is harmless here - the calls are gone either way), or Valheim has changed this method and case preservation is dead. To tell which: shout something in mixed case - if it displays as you typed it, this is fine."); } } [HarmonyPatch(typeof(Terminal), "AddString", new Type[] { typeof(PlatformUserID), typeof(string), typeof(Type), typeof(bool) })] [HarmonyTranspiler] private static IEnumerable AddString_PlatformUserID_CaseFix(IEnumerable instructions) { return RemoveForcedCase(instructions, "chat log"); } [HarmonyPatch(typeof(Terminal), "AddString", new Type[] { typeof(string), typeof(string), typeof(Type), typeof(bool) })] [HarmonyTranspiler] private static IEnumerable AddString_Title_CaseFix(IEnumerable instructions) { return RemoveForcedCase(instructions, "titled overload, unused by vanilla"); } [HarmonyPatch(typeof(Chat), "AddInworldText", new Type[] { typeof(GameObject), typeof(long), typeof(Vector3), typeof(Type), typeof(UserInfo), typeof(string) })] [HarmonyTranspiler] private static IEnumerable AddInworldText_CaseFix(IEnumerable instructions) { return RemoveForcedCase(instructions, "floating world text"); } [HarmonyPatch(typeof(Chat), "OnNewChatMessage")] [HarmonyPrefix] private static void OnNewChatMessage_ResolveLinks(long senderID, ref string text) { if (!ChatFeatures.Enabled) { return; } try { if (ItemShareProtocol.ContainsShare(text)) { text = ItemShareProtocol.ResolveLinks(text, senderID); } } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed (non-fatal, item share will show as raw text). Reason: {1}", "OnNewChatMessage_ResolveLinks", arg)); } } [HarmonyPatch(typeof(Terminal), "AddString", new Type[] { typeof(PlatformUserID), typeof(string), typeof(Type), typeof(bool) })] [HarmonyPrefix] private static void AddString_PlatformUserID_Output(ref string text) { Apply(ref text, (string s) => EmoteRenderer.Expand(ItemShareProtocol.ForChatLog(s)), "AddString_PlatformUserID_Output"); } [HarmonyPatch(typeof(Terminal), "AddString", new Type[] { typeof(string), typeof(string), typeof(Type), typeof(bool) })] [HarmonyPrefix] private static void AddString_Title_Output(ref string text) { Apply(ref text, (string s) => EmoteRenderer.Expand(ItemShareProtocol.ForChatLog(s)), "AddString_Title_Output"); } [HarmonyPatch(typeof(Chat), "AddInworldText", new Type[] { typeof(GameObject), typeof(long), typeof(Vector3), typeof(Type), typeof(UserInfo), typeof(string) })] [HarmonyPrefix] private static void AddInworldText_Output(ref string text) { Apply(ref text, (string s) => EmoteRenderer.Expand(ItemShareProtocol.ForWorldText(s)), "AddInworldText_Output"); } [HarmonyPatch(typeof(Chat), "AddInworldText", new Type[] { typeof(GameObject), typeof(long), typeof(Vector3), typeof(Type), typeof(UserInfo), typeof(string) })] [HarmonyPostfix] private static void AddInworldText_AssignSprites(Chat __instance) { if (!ChatFeatures.Enabled) { return; } try { foreach (WorldTextInstance worldText in __instance.m_worldTexts) { EmoteRenderer.AssignTo((TMP_Text)(object)worldText.m_textMeshField); } } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed (non-fatal, floating text shows emote markup as boxes). Reason: {1}", "AddInworldText_AssignSprites", arg)); } } private static void Apply(ref string text, Func stage, string caller) { if (!ChatFeatures.Enabled) { return; } try { text = stage(text); } catch (Exception arg) { Log.LogError((object)$"{caller} failed (non-fatal, item share markup may show literally). Reason: {arg}"); } } } internal static class ChatOverhaulWindow { [HarmonyPatch(typeof(InventoryGui), "OnDropOutside")] internal static class DropOutsidePatch { [HarmonyPrefix] private static bool Prefix(InventoryGui __instance) { try { return !TryInterceptDropOutside(__instance); } catch (Exception arg) { Log.LogError((object)$"drop-zone intercept failed (non-fatal, vanilla drop runs). Reason: {arg}"); return true; } } } private enum DropAction { None, Share, Trade } public const string WindowId = "VikingOS_ChatOverhaulWindow"; private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.ChatOverhaulWindow"); private static GUIStyle _tooltipBody; private static GUIStyle _tooltipBodySource; private static bool _wasDragging; private static ItemData _lastDraggedItem; private static bool _suppressReleaseShare; private static Rect _addonRect; private static bool _addonKnown; private static Rect _frameRect; private static Rect _stripGrip; private static bool _stripGripKnown; private static bool? _widthSyncedFor; private static Rect _invShareRect; private static Rect _invDropZone; private static bool _invShareKnown; private static bool _movingShare; private static Vector2 _shareGrabOffset; private static Vector2 _sharePos; private static bool _chromePressed; private static bool _chromePressedWasFocused; private static float _chromeGraceUntil; private static bool _movingChat; private static Vector2 _moveLastMouse; private const string MoveHint = "Drag the gold frame to move\nMouse wheel here to scale"; private static float _hintHeight; private const float StripGap = 6f; private static GUIStyle _tooltipTitle; private static GUIStyle _tooltipTitleSource; private static bool ChromeBusy { get { if (!_chromePressed) { return Time.unscaledTime < _chromeGraceUntil; } return true; } } private static float SideStripWidth => GiltFrameTheme.S(180f); private static ConfigManager.ChatStripPlacement Placement { get { if (ConfigManager.chatStripPlacement == null) { return ConfigManager.ChatStripPlacement.Top; } return ConfigManager.chatStripPlacement.Value; } } private static bool Horizontal => Placement != ConfigManager.ChatStripPlacement.Side; private static float HorizontalStripHeight => GiltFrameTheme.S(28f) + GiltFrameTheme.S(14f); private static float MinHorizontalStripWidth => GiltFrameTheme.S(7f) * 2f + GiltFrameTheme.S(14f) + GiltFrameTheme.S(4f) * 5f + GiltFrameTheme.S(82f) * 4.75f; private static bool ChatInputFocused() { Chat instance = Chat.instance; if ((Object)(object)instance != (Object)null && (Object)(object)((Terminal)instance).m_chatWindow != (Object)null && ((Component)((Terminal)instance).m_chatWindow).gameObject.activeInHierarchy && (Object)(object)((Terminal)instance).m_input != (Object)null) { return ((TMP_InputField)((Terminal)instance).m_input).isFocused; } return false; } private static bool PanelVisible() { if (!ChatInputFocused()) { return InventoryGui.IsVisible(); } return true; } public static void Tick() { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) try { if (!SessionState.IsLive) { return; } InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance != (Object)null && (Object)(object)instance.m_dragGo != (Object)null && instance.m_dragItem != null) { if (!_wasDragging) { ItemData started = instance.m_dragItem; Diagnostics.Trace(delegate { string[] obj = new string[5] { "drag started: ", started.m_shared?.m_name ?? "?", " (", null, null }; GameObject dropPrefab = started.m_dropPrefab; obj[3] = ((dropPrefab != null) ? ((Object)dropPrefab).name : null) ?? "no drop prefab"; obj[4] = ")."; return string.Concat(obj); }); } _lastDraggedItem = instance.m_dragItem; _wasDragging = true; } else { if (!_wasDragging) { return; } _wasDragging = false; if (_suppressReleaseShare) { _suppressReleaseShare = false; _lastDraggedItem = null; return; } bool visible = PanelVisible(); Vector2 releasedAt = GuiMousePosition(); DropAction dropAction = ActionFor(releasedAt); bool overZone = dropAction != DropAction.None; if (_lastDraggedItem != null && (visible || dropAction == DropAction.Trade) && overZone) { Deliver(dropAction, _lastDraggedItem); } else { Diagnostics.Trace(() => $"drag released without sharing - invBox={_invShareKnown}, panelVisible={visible}, " + string.Format("item={0}, overDropZone={1} ", (_lastDraggedItem != null) ? "yes" : "null", overZone) + $"(mouse {releasedAt.x:F0},{releasedAt.y:F0} vs share box {((Rect)(ref _invDropZone)).x:F0},{((Rect)(ref _invDropZone)).y:F0} " + $"{((Rect)(ref _invDropZone)).width:F0}x{((Rect)(ref _invDropZone)).height:F0})."); } _lastDraggedItem = null; } } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed (non-fatal, item-share drag detection disabled this frame). Reason: {1}", "Tick", arg)); } } private static bool TryInterceptDropOutside(InventoryGui gui) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) if (!SessionState.IsLive) { return false; } if ((Object)(object)gui == (Object)null || (Object)(object)gui.m_dragGo == (Object)null || gui.m_dragItem == null) { return false; } DropAction action = ActionFor(GuiMousePosition()); if (action == DropAction.None) { return false; } if (action == DropAction.Share && !PanelVisible()) { return false; } ItemData item = gui.m_dragItem; gui.SetupDragItem((ItemData)null, (Inventory)null, 1); _suppressReleaseShare = true; Diagnostics.Trace(() => string.Format("drop zone claimed the release: {0} {1}.", action, item.m_shared?.m_name ?? "?")); Deliver(action, item); return true; } private static void Deliver(DropAction action, ItemData item) { switch (action) { case DropAction.Share: ShareItem(item); break; case DropAction.Trade: TradeRpc.AddToOffer(item); break; } } private static void ShareItem(ItemData item) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) Type type = (Type)((!ConfigManager.alwaysShout.Value) ? 1 : 2); ItemShareRpc.Send(item, type); } public static void Draw() { try { if (!SessionState.IsLive) { UIFocus.SetWantsCursor("VikingOS_ChatOverhaulWindow", active: false); return; } bool flag = ChatInputFocused(); bool num = _movingChat || ChatWindowFix.Resizing; TrackChromeClick(flag); bool flag2 = num || ChromeBusy || EmojiPicker.BrowseOpen || PlayerPicker.IsOpen || LayoutEditor.Active; UIFocus.SetWantsCursor("VikingOS_ChatOverhaulWindow", flag || flag2); PumpFrameMove(); if (flag2 && (Object)(object)Chat.instance != (Object)null) { Chat.instance.m_hideTimer = 0f; } ConfigManager.ApplyTheme(); DrawInventoryShareBox(); if (!flag && !flag2) { EmojiPicker.CloseBrowse(); PlayerPicker.Close(); if (Diagnostics.OverlayEnabled) { DrawDebugOverlay(flag); } return; } DrawDocked(flag); if (flag || ChatWindowFix.Resizing) { ChatWindowFix.DrawGrip(); } DrawLinkTooltip(); if (Diagnostics.OverlayEnabled) { DrawDebugOverlay(flag); } } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed (non-fatal, chat overhaul panel hidden this frame). Reason: {1}", "Draw", arg)); } } public static void ResetSession() { _wasDragging = false; _lastDraggedItem = null; _suppressReleaseShare = false; _addonKnown = false; _invShareKnown = false; _movingShare = false; _movingChat = false; _chromePressed = false; _chromeGraceUntil = 0f; EmojiPicker.CloseBrowse(); PlayerPicker.Close(); } private static void TrackChromeClick(bool chatFocused) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Invalid comparison between Unknown and I4 //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Invalid comparison between Unknown and I4 //IL_0022: Unknown result type (might be due to invalid IL or missing references) Event current = Event.current; if (current == null) { return; } if (!_chromePressed && (int)current.type == 0 && current.button == 0 && OverOwnChrome(current.mousePosition)) { _chromePressed = true; _chromePressedWasFocused = chatFocused; } else if (_chromePressed && ((int)current.type == 1 || (int)current.rawType == 1)) { _chromePressed = false; _chromeGraceUntil = Time.unscaledTime + 0.5f; if (_chromePressedWasFocused) { ChatWindowFix.RefocusInput(); } } } private static bool OverOwnChrome(Vector2 mouse) { //IL_000c: 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_0031: 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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) if (_addonKnown && ((Rect)(ref _addonRect)).Contains(mouse)) { return true; } if (_invShareKnown && ((Rect)(ref _invShareRect)).Contains(mouse)) { return true; } Rect panelRect = EmojiPicker.PanelRect; if (((Rect)(ref panelRect)).width > 0f && ((Rect)(ref panelRect)).Contains(mouse)) { return true; } Rect panelRect2 = PlayerPicker.PanelRect; if (((Rect)(ref panelRect2)).width > 0f && ((Rect)(ref panelRect2)).Contains(mouse)) { return true; } Rect panelRect3 = TradeWindow.PanelRect; if (((Rect)(ref panelRect3)).width > 0f) { return ((Rect)(ref panelRect3)).Contains(mouse); } return false; } private static void DrawDocked(bool chatFocused) { //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_02a0: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a8: Unknown result type (might be due to invalid IL or missing references) //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_0330: Unknown result type (might be due to invalid IL or missing references) //IL_033b: Expected O, but got Unknown //IL_036c: Unknown result type (might be due to invalid IL or missing references) //IL_0380: Unknown result type (might be due to invalid IL or missing references) float sideStripWidth = SideStripWidth; float num = 6f; if (ChatWindowFix.TryGetChatGuiRect(out var gui)) { SyncChatWidthToPlacement(); if (Horizontal) { float horizontalStripHeight = HorizontalStripHeight; float num2 = Mathf.Min(Mathf.Max(((Rect)(ref gui)).width, MinHorizontalStripWidth), (float)Screen.width - 36f - 8f); float num3 = Mathf.Min(((Rect)(ref gui)).x, (float)Screen.width - 18f - 4f - num2); num3 = Mathf.Max(22f, num3); bool num4 = Placement == ConfigManager.ChatStripPlacement.Top; bool flag = ((Rect)(ref gui)).y - num - horizontalStripHeight - 18f - 4f >= 0f; _addonRect = ((num4 && flag) ? new Rect(num3, ((Rect)(ref gui)).y - num - horizontalStripHeight, num2, horizontalStripHeight) : new Rect(num3, ((Rect)(ref gui)).yMax + num, num2, horizontalStripHeight)); } else { _addonRect = ((((Rect)(ref gui)).xMax + num + sideStripWidth + 18f + 4f <= (float)Screen.width) ? new Rect(((Rect)(ref gui)).xMax + num, ((Rect)(ref gui)).y, sideStripWidth, ((Rect)(ref gui)).height) : new Rect(((Rect)(ref gui)).x - num - sideStripWidth, ((Rect)(ref gui)).y, sideStripWidth, ((Rect)(ref gui)).height)); } _addonKnown = true; Rect val = Union(gui, _addonRect); float num5 = 22f; Rect val2 = new Rect(((Rect)(ref val)).x - num5, ((Rect)(ref val)).y - num5, ((Rect)(ref val)).width + num5 * 2f, ((Rect)(ref val)).height + num5 * 2f); GiltFrameTheme.DrawFrame(val2); _frameRect = val2; TryStartFrameMove(val2, gui); } if (!_addonKnown) { return; } HandleWheelScale(); EmojiPicker.Draw(_frameRect, chatFocused); GiltFrameTheme.DrawPanelFill(_addonRect); GiltFrameTheme.DrawOutline(_addonRect, new Color(0f, 0f, 0f, 0.35f), 1f); if (Horizontal) { DrawHorizontalStrip(); PlayerPicker.Draw(_addonRect); return; } float num6 = ((Rect)(ref _addonRect)).x + GiltFrameTheme.S(8f); float num7 = ((Rect)(ref _addonRect)).width - GiltFrameTheme.S(16f); float num8 = ((Rect)(ref _addonRect)).y + GiltFrameTheme.S(8f); GiltFrameTheme.DrawShadowed(new Rect(num6, num8, num7, GiltFrameTheme.S(22f)), "BARRKCHAT", GiltFrameTheme.Header); num8 += GiltFrameTheme.S(26f); float num9 = GiltFrameTheme.S(28f); DrawShoutToggle(new Rect(num6, num8, num7, num9)); num8 += num9 + GiltFrameTheme.S(6f); bool browseOpen = EmojiPicker.BrowseOpen; if (GUI.Button(new Rect(num6, num8, num7, num9), browseOpen ? "☺ Emoji: shown" : "☺ Emoji", browseOpen ? GiltFrameTheme.Primary : GiltFrameTheme.Button)) { EmojiPicker.ToggleBrowse(); } num8 += num9 + GiltFrameTheme.S(6f); num8 = DrawWhisperButtons(num6, num8, num7, num9); num8 = DrawTradeButton(num6, num8, num7, num9); _hintHeight = GiltFrameTheme.Note.CalcHeight(new GUIContent("Drag the gold frame to move\nMouse wheel here to scale"), num7); float num10 = Mathf.Max(num8, ((Rect)(ref _addonRect)).yMax - GiltFrameTheme.S(8f) - _hintHeight); GUI.Label(new Rect(num6, num10, num7, _hintHeight), "Drag the gold frame to move\nMouse wheel here to scale", GiltFrameTheme.Note); PlayerPicker.Draw(_addonRect); } private static void DrawHorizontalStrip() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: 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_01b8: Unknown result type (might be due to invalid IL or missing references) float num = GiltFrameTheme.S(7f); float num2 = GiltFrameTheme.S(4f); float num3 = GiltFrameTheme.S(14f); float num4 = GiltFrameTheme.S(28f); float num5 = ((Rect)(ref _addonRect)).y + num; float num6 = ((Rect)(ref _addonRect)).x + num; DrawStripGrip(new Rect(num6, num5, num3, num4)); num6 += num3 + num2; float num7 = ((Rect)(ref _addonRect)).xMax - num - num6; float num8 = Mathf.Max(1f, (num7 - num2 * 4f) / 4.75f); DrawShoutToggle(new Rect(num6, num5, num8, num4)); num6 += num8 + num2; bool browseOpen = EmojiPicker.BrowseOpen; if (GUI.Button(new Rect(num6, num5, num8, num4), browseOpen ? "☺ Emoji: shown" : "☺ Emoji", browseOpen ? GiltFrameTheme.Primary : GiltFrameTheme.Button)) { EmojiPicker.ToggleBrowse(); } num6 += num8 + num2; if (GUI.Button(new Rect(num6, num5, num8, num4), "Whisper", GiltFrameTheme.Button)) { PlayerPicker.Toggle("WHISPER TO", delegate(string name, long uid) { PrefillInput("/w " + name + " "); }); } num6 += num8 + num2; bool flag = (GUI.enabled = WhisperRpc.CanReply); if (GUI.Button(new Rect(num6, num5, num8 * 0.75f, num4), flag ? ("↩ " + Shorten(WhisperRpc.LastFromName, 9)) : "↩ Reply", GiltFrameTheme.Button)) { PrefillInput("/r "); } GUI.enabled = true; num6 += num8 * 0.75f + num2; bool busy = TradeRpc.Busy; if (!GUI.Button(new Rect(num6, num5, num8, num4), busy ? ("⇄ " + Shorten(TradeRpc.PartnerName, 10)) : "⇄ Trade", busy ? GiltFrameTheme.Primary : GiltFrameTheme.Button)) { return; } if (busy) { TradeWindow.BringToFront(); return; } PlayerPicker.Toggle("TRADE WITH", delegate(string name, long uid) { TradeRpc.Invite(name, uid); }); } private static void DrawStripGrip(Rect r) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) _stripGrip = r; _stripGripKnown = true; float num = Mathf.Max(2f, GiltFrameTheme.S(3f)); float num2 = ((Rect)(ref r)).center.x - num * 0.5f; float num3 = ((Rect)(ref r)).center.y - num * 2.5f; Color c = default(Color); ((Color)(ref c))..ctor(GiltFrameTheme.Gold.r, GiltFrameTheme.Gold.g, GiltFrameTheme.Gold.b, 0.75f); for (int i = 0; i < 3; i++) { GiltFrameTheme.DrawFill(new Rect(num2, num3 + (float)i * num * 2f, num, num), c); } } private static void SyncChatWidthToPlacement() { //IL_0077: 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_00ba: Unknown result type (might be due to invalid IL or missing references) bool horizontal = Horizontal; if (_widthSyncedFor.HasValue && _widthSyncedFor.Value == horizontal) { return; } LayoutTarget target; Vector2 unitsPerPixel; if (!_widthSyncedFor.HasValue) { _widthSyncedFor = horizontal; } else if (ChatWindowFix.TryGetChatHandles(out target, out unitsPerPixel)) { _widthSyncedFor = horizontal; float num = SideStripWidth + 6f; float units = num * unitsPerPixel.x * (horizontal ? 1f : (-1f)); LayoutEngine.Resize(target, new Vector2(units, 0f), new Vector2(units * 0.5f, 0f)); LayoutEngine.Commit(); Diagnostics.Trace(() => "chat strip is now " + (horizontal ? "horizontal" : "a side column") + "; " + $"chat box width adjusted by {units:F0} canvas units."); } } private static float DrawWhisperButtons(float x, float y, float w, float h) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) float num = GiltFrameTheme.S(4f); float num2 = (w - num) * 0.55f; if (GUI.Button(new Rect(x, y, num2, h), "Whisper", GiltFrameTheme.Button)) { PlayerPicker.Toggle("WHISPER TO", delegate(string name, long uid) { PrefillInput("/w " + name + " "); }); } bool canReply = WhisperRpc.CanReply; string text = (canReply ? ("↩ " + Shorten(WhisperRpc.LastFromName, 9)) : "↩ Reply"); GUI.enabled = canReply; if (GUI.Button(new Rect(x + num2 + num, y, w - num2 - num, h), text, GiltFrameTheme.Button)) { PrefillInput("/r "); } GUI.enabled = true; return y + h + GiltFrameTheme.S(6f); } private static float DrawTradeButton(float x, float y, float w, float h) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) bool busy = TradeRpc.Busy; string text = (busy ? ("⇄ Trading: " + Shorten(TradeRpc.PartnerName, 10)) : "⇄ Trade"); if (GUI.Button(new Rect(x, y, w, h), text, busy ? GiltFrameTheme.Primary : GiltFrameTheme.Button)) { if (busy) { TradeWindow.BringToFront(); } else { PlayerPicker.Toggle("TRADE WITH", delegate(string name, long uid) { TradeRpc.Invite(name, uid); }); } } return y + h + GiltFrameTheme.S(6f); } private static void PrefillInput(string prefix) { Chat instance = Chat.instance; if (!((Object)(object)((Terminal)(instance?)).m_input == (Object)null)) { ((TMP_InputField)((Terminal)instance).m_input).text = prefix; ((TMP_InputField)((Terminal)instance).m_input).caretPosition = prefix.Length; instance.m_hideTimer = 0f; ChatWindowFix.RefocusInput(); } } private static string Shorten(string value, int max) { if (string.IsNullOrEmpty(value)) { return string.Empty; } if (value.Length > max) { return value.Substring(0, max - 1) + "…"; } return value; } private static void TryStartFrameMove(Rect frame, Rect chatRect) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: 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_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) Event current = Event.current; if (current != null && !_movingChat && (int)current.type == 0 && current.button == 0) { Vector2 mousePosition = current.mousePosition; Rect val = (Rect)((!Horizontal) ? new Rect(((Rect)(ref _addonRect)).x + GiltFrameTheme.S(8f), ((Rect)(ref _addonRect)).y + GiltFrameTheme.S(8f), ((Rect)(ref _addonRect)).width - GiltFrameTheme.S(16f), GiltFrameTheme.S(22f)) : (_stripGripKnown ? _stripGrip : new Rect(0f, 0f, 0f, 0f))); if ((((Rect)(ref frame)).Contains(mousePosition) && !((Rect)(ref chatRect)).Contains(mousePosition) && !((Rect)(ref _addonRect)).Contains(mousePosition)) || (((Rect)(ref val)).width > 0f && ((Rect)(ref val)).Contains(mousePosition))) { _movingChat = true; _moveLastMouse = mousePosition; current.Use(); } } } private static void PumpFrameMove() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Invalid comparison between Unknown and I4 //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Invalid comparison between Unknown and I4 //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Invalid comparison between Unknown and I4 //IL_002f: Unknown result type (might be due to invalid IL or missing references) //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) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0051: 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_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) if (!_movingChat) { return; } Event current = Event.current; if (current == null) { return; } if ((int)current.type == 3 && current.button == 0) { if (ChatWindowFix.TryGetChatHandles(out var target, out var unitsPerPixel)) { Vector2 val = current.mousePosition - _moveLastMouse; _moveLastMouse = current.mousePosition; LayoutEngine.Nudge(target, new Vector2(val.x * unitsPerPixel.x, (0f - val.y) * unitsPerPixel.y)); } current.Use(); } else if ((int)current.type == 1 || (int)current.rawType == 1) { _movingChat = false; LayoutEngine.Commit(); ChatWindowFix.RefocusInput(); current.Use(); } } private static void HandleWheelScale() { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 //IL_0019: 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) Event current = Event.current; if (current != null && (int)current.type == 6 && ((Rect)(ref _addonRect)).Contains(current.mousePosition) && ChatWindowFix.TryGetChatHandles(out var target, out var _)) { float scale = LayoutEngine.GetScale(target); LayoutEngine.SetScale(target, (current.delta.y > 0f) ? (scale / 1.05f) : (scale * 1.05f)); LayoutEngine.Commit(); current.Use(); } } private static Rect Union(Rect a, Rect b) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Min(((Rect)(ref a)).xMin, ((Rect)(ref b)).xMin); float num2 = Mathf.Min(((Rect)(ref a)).yMin, ((Rect)(ref b)).yMin); float num3 = Mathf.Max(((Rect)(ref a)).xMax, ((Rect)(ref b)).xMax); float num4 = Mathf.Max(((Rect)(ref a)).yMax, ((Rect)(ref b)).yMax); return new Rect(num, num2, num3 - num, num4 - num2); } private static void DrawShoutToggle(Rect r) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) bool value = ConfigManager.alwaysShout.Value; GUIStyle val = (value ? GiltFrameTheme.Primary : GiltFrameTheme.Button); if (GUI.Button(r, value ? "Shout: ON" : "Shout: OFF", val)) { ConfigManager.alwaysShout.Value = !value; } } private static void DrawDropZone(Rect r) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0047: 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) //IL_004f: Unknown result type (might be due to invalid IL or missing references) if (!(((Rect)(ref r)).height < GiltFrameTheme.S(30f))) { bool flag = (Object)(object)InventoryGui.instance != (Object)null && (Object)(object)InventoryGui.instance.m_dragGo != (Object)null; bool num = flag && ((Rect)(ref r)).Contains(GuiMousePosition()); GiltFrameTheme.DrawInset(r); if (num) { GiltFrameTheme.DrawSelection(r); } GUI.Label(r, flag ? "Release to share" : "Drag an item\nhere to share", GiltFrameTheme.Note); } } private static void DrawInventoryShareBox() { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) if (!InventoryGui.IsVisible()) { _invShareKnown = false; _movingShare = false; return; } float num = 26f; float num2 = GiltFrameTheme.Header.CalcHeight(new GUIContent("SHARE ITEM"), 1000f); float num3 = GiltFrameTheme.S(104f); float w = Mathf.Max(GiltFrameTheme.S(210f), num * 2f + GiltFrameTheme.Header.CalcSize(new GUIContent("SHARE ITEM")).x); float h = num * 2f + num2 + GiltFrameTheme.S(6f) + num3; if (!TryPlaceShareBox(w, h, out var place)) { _invShareKnown = false; _movingShare = false; return; } HandleShareBoxMove(ref place, num + num2); _invShareRect = place; _invShareKnown = true; GiltFrameTheme.DrawPanelFill(place); GiltFrameTheme.DrawFrame(place); float num4 = ((Rect)(ref place)).x + num; float num5 = ((Rect)(ref place)).y + num; float num6 = ((Rect)(ref place)).width - num * 2f; GiltFrameTheme.DrawShadowed(new Rect(num4, num5, num6, num2), "SHARE ITEM", GiltFrameTheme.Header); DrawShareGrabDots(new Rect(num4, num5, num6, num2)); num5 += num2 + GiltFrameTheme.S(6f); _invDropZone = new Rect(num4, num5, num6, num3); DrawDropZone(_invDropZone); } private static bool TryPlaceShareBox(float w, float h, out Rect place) { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_006e: 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_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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) ConfigEntry shareBoxX = ConfigManager.shareBoxX; ConfigEntry shareBoxY = ConfigManager.shareBoxY; if (shareBoxX != null && shareBoxY != null && shareBoxX.Value >= 0f && shareBoxY.Value >= 0f) { place = ClampToScreen(new Rect(Mathf.Clamp01(shareBoxX.Value) * (float)Screen.width, Mathf.Clamp01(shareBoxY.Value) * (float)Screen.height, w, h)); return true; } if (!PanelFrame.TryGetPlayerFrame(out var frame)) { place = default(Rect); return false; } float num = 30f; Rect val = default(Rect); ((Rect)(ref val))..ctor(((Rect)(ref frame)).xMax + num, ((Rect)(ref frame)).y, w, h); Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(((Rect)(ref frame)).x - num - w, ((Rect)(ref frame)).y, w, h); place = (Fits(val) ? val : (Fits(val2) ? val2 : ClampToScreen(val))); return true; } private static void HandleShareBoxMove(ref Rect place, float handleH) { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Invalid comparison between Unknown and I4 //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Invalid comparison between Unknown and I4 //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Invalid comparison between Unknown and I4 //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: 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_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) Event current = Event.current; if (current == null) { return; } if (_movingShare) { ((Rect)(ref place)).x = _sharePos.x; ((Rect)(ref place)).y = _sharePos.y; } if (!_movingShare) { Rect val = default(Rect); ((Rect)(ref val))..ctor(((Rect)(ref place)).x, ((Rect)(ref place)).y, ((Rect)(ref place)).width, handleH); if ((int)current.type == 0 && current.button == 0 && Cursor.visible && !CarryingItem() && ((Rect)(ref val)).Contains(current.mousePosition)) { _movingShare = true; _sharePos = new Vector2(((Rect)(ref place)).x, ((Rect)(ref place)).y); _shareGrabOffset = current.mousePosition - _sharePos; current.Use(); } } else if ((int)current.type == 1 || (int)current.rawType == 1) { _movingShare = false; if (ConfigManager.shareBoxX != null && ConfigManager.shareBoxY != null) { ConfigManager.shareBoxX.Value = Mathf.Clamp01(_sharePos.x / Mathf.Max(1f, (float)Screen.width)); ConfigManager.shareBoxY.Value = Mathf.Clamp01(_sharePos.y / Mathf.Max(1f, (float)Screen.height)); } current.Use(); } else if ((int)current.type == 3) { _sharePos = current.mousePosition - _shareGrabOffset; _sharePos.x = Mathf.Clamp(_sharePos.x, 0f, Mathf.Max(0f, (float)Screen.width - ((Rect)(ref place)).width)); _sharePos.y = Mathf.Clamp(_sharePos.y, 0f, Mathf.Max(0f, (float)Screen.height - ((Rect)(ref place)).height)); ((Rect)(ref place)).x = _sharePos.x; ((Rect)(ref place)).y = _sharePos.y; current.Use(); } } private static bool CarryingItem() { InventoryGui instance = InventoryGui.instance; if ((Object)(object)instance != (Object)null) { return (Object)(object)instance.m_dragGo != (Object)null; } return false; } private static void DrawShareGrabDots(Rect titleRow) { //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) if (Cursor.visible && !CarryingItem()) { float num = Mathf.Max(2f, GiltFrameTheme.S(3f)); float num2 = num * 2f; float num3 = ((Rect)(ref titleRow)).y + ((Rect)(ref titleRow)).height * 0.5f - num * 0.5f; float num4 = ((Rect)(ref titleRow)).xMax - num; Color c = default(Color); ((Color)(ref c))..ctor(GiltFrameTheme.Gold.r, GiltFrameTheme.Gold.g, GiltFrameTheme.Gold.b, 0.75f); for (int i = 0; i < 3; i++) { GiltFrameTheme.DrawFill(new Rect(num4, num3, num, num), c); num4 -= num2; } } } private static bool Fits(Rect r) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) if (((Rect)(ref r)).xMin < 0f || ((Rect)(ref r)).xMax > (float)Screen.width || ((Rect)(ref r)).yMin < 0f || ((Rect)(ref r)).yMax > (float)Screen.height) { return false; } IReadOnlyList frames = PanelFrame.Frames; for (int i = 0; i < frames.Count; i++) { if (((Rect)(ref r)).Overlaps(frames[i])) { return false; } } return true; } private static DropAction ActionFor(Vector2 mouse) { //IL_0007: 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_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (TradeWindow.DropZoneKnown) { Rect dropZone = TradeWindow.DropZone; if (((Rect)(ref dropZone)).Contains(mouse)) { return DropAction.Trade; } } if (_invShareKnown && ((Rect)(ref _invDropZone)).Contains(mouse)) { return DropAction.Share; } return DropAction.None; } private static bool OverAnyDropZone(Vector2 mouse) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return ActionFor(mouse) != DropAction.None; } private static void DrawDebugOverlay(bool chatFocused) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_027f: Expected O, but got Unknown //IL_02c5: Unknown result type (might be due to invalid IL or missing references) //IL_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02cf: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_02f3: Unknown result type (might be due to invalid IL or missing references) //IL_0336: Unknown result type (might be due to invalid IL or missing references) ConfigManager.ApplyTheme(); InventoryGui instance = InventoryGui.instance; bool flag = (Object)(object)instance != (Object)null && (Object)(object)instance.m_dragGo != (Object)null && instance.m_dragItem != null; Vector2 val = GuiMousePosition(); string text = "session : " + SessionState.Describe() + "\n" + $"gates : chatFocus={chatFocused} invOpen={InventoryGui.IsVisible()} panel={PanelVisible()}\n" + $"cursor : wantsCursor={UIFocus.WantsCursor} textFocus={UIFocus.HasTextFocus}\n" + string.Format("drag : dragging={0} wasDragging={1} held={2}\n", flag, _wasDragging, _lastDraggedItem?.m_shared?.m_name ?? "-") + $"mouse : {val.x:F0},{val.y:F0} overDropZone={OverAnyDropZone(val)}\n" + $"shareBox : {((Rect)(ref _invDropZone)).x:F0},{((Rect)(ref _invDropZone)).y:F0} {((Rect)(ref _invDropZone)).width:F0}x{((Rect)(ref _invDropZone)).height:F0} shown={_invShareKnown} " + string.Format("placed={0} moving={1} panelFrames={2}\n", (ConfigManager.shareBoxX != null && ConfigManager.shareBoxX.Value >= 0f) ? "player" : "docked", _movingShare, PanelFrame.Frames.Count) + $"addon : {((Rect)(ref _addonRect)).x:F0},{((Rect)(ref _addonRect)).y:F0} {((Rect)(ref _addonRect)).width:F0}x{((Rect)(ref _addonRect)).height:F0} docked={_addonKnown} chrome={ChromeBusy}\n" + $"shares : {ItemShareCache.Count} cached alwaysShout={ConfigManager.alwaysShout.Value}"; GUIStyle val2 = TooltipBodyStyle(); float num = 460f; float num2 = val2.CalcHeight(new GUIContent(text), num) + 16f; float num3 = (_addonKnown ? (((Rect)(ref _addonRect)).yMax + 6f) : 6f); Rect r = ClampToScreen(new Rect(_addonKnown ? ((Rect)(ref _addonRect)).x : 6f, num3, num, num2)); GiltFrameTheme.DrawFill(r, new Color(0f, 0f, 0f, 0.78f)); GiltFrameTheme.DrawOutline(r, GiltFrameTheme.Gold, 1f); GUI.Label(new Rect(((Rect)(ref r)).x + 8f, ((Rect)(ref r)).y + 8f, ((Rect)(ref r)).width - 16f, ((Rect)(ref r)).height - 16f), text, val2); } private static void DrawLinkTooltip() { //IL_0026: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Expected O, but got Unknown //IL_0142: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Expected O, but got Unknown //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Unknown result type (might be due to invalid IL or missing references) //IL_0242: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Unknown result type (might be due to invalid IL or missing references) //IL_02d0: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_02bd: Unknown result type (might be due to invalid IL or missing references) TMP_Text val = (TMP_Text)(object)(((Object)(object)Chat.instance != (Object)null) ? ((Terminal)Chat.instance).m_output : null); if ((Object)(object)val == (Object)null) { return; } int num = TMP_TextUtilities.FindIntersectingLink(val, Input.mousePosition, (Camera)null); if (num >= 0 && ItemShareProtocol.TryGetShareIdFromLinkId(((TMP_LinkInfo)(ref val.textInfo.linkInfo[num])).GetLinkID(), out var shareId) && ItemShareCache.TryGet(shareId, out var entry) && entry.TooltipText != null) { GUIStyle val2 = TooltipBodyStyle(); float num2 = GiltFrameTheme.S(364f); Rect val3 = GiltFrameTheme.Body(new Rect(0f, 0f, num2, 0f)); float width = ((Rect)(ref val3)).width; float num3 = (((Object)(object)entry.Icon != (Object)null) ? GiltFrameTheme.S(32f) : 0f); float num4 = (((Object)(object)entry.Icon != (Object)null) ? GiltFrameTheme.S(40f) : 0f); float num5 = val2.CalcHeight(new GUIContent(entry.TooltipText), width - num4); string text = (entry.DisplayName ?? entry.PrefabName ?? string.Empty).ToUpperInvariant(); GUIStyle val4 = TooltipTitleStyle(); float num6 = num2 - 148f; float num7 = GiltFrameTheme.TitleHeight - 20f; float num8 = Mathf.Max(num7, val4.CalcHeight(new GUIContent(text), num6)); float num9 = num8 - num7; float num10 = 18f + GiltFrameTheme.TitleHeight + 18f + GiltFrameTheme.S(12f); float num11 = Mathf.Max(num3, num5) + num10 + num9; Vector2 val5 = GuiMousePosition(); Rect val6 = ClampToScreen(new Rect(val5.x + 16f, val5.y + 16f, num2, num11)); GiltFrameTheme.DrawPanelFill(val6); GiltFrameTheme.DrawFrame(val6); GiltFrameTheme.DrawShadowed(new Rect(((Rect)(ref val6)).x + 74f, ((Rect)(ref val6)).y + 18f + 8f, num6, num8), text, val4); GiltFrameTheme.DrawRule(new Rect(((Rect)(ref val6)).x + 18f + 22f, ((Rect)(ref val6)).y + 18f + GiltFrameTheme.TitleHeight - 12f + num9, num2 - 80f, 1f)); Rect val7 = GiltFrameTheme.Body(val6); ((Rect)(ref val7)).y = ((Rect)(ref val7)).y + num9; ((Rect)(ref val7)).height = ((Rect)(ref val7)).height - num9; if ((Object)(object)entry.Icon != (Object)null) { DrawSprite(new Rect(((Rect)(ref val7)).x, ((Rect)(ref val7)).y, num3, num3), entry.Icon); GUI.Label(new Rect(((Rect)(ref val7)).x + num4, ((Rect)(ref val7)).y, ((Rect)(ref val7)).width - num4, ((Rect)(ref val7)).height), entry.TooltipText, val2); } else { GUI.Label(val7, entry.TooltipText, val2); } } } private static GUIStyle TooltipTitleStyle() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown if (_tooltipTitle != null && _tooltipTitleSource == GiltFrameTheme.Title) { return _tooltipTitle; } _tooltipTitleSource = GiltFrameTheme.Title; _tooltipTitle = new GUIStyle(GiltFrameTheme.Title) { wordWrap = true, clipping = (TextClipping)0 }; return _tooltipTitle; } private static GUIStyle TooltipBodyStyle() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown if (_tooltipBody != null && _tooltipBodySource == GiltFrameTheme.Value) { return _tooltipBody; } _tooltipBodySource = GiltFrameTheme.Value; _tooltipBody = new GUIStyle(GiltFrameTheme.Value) { wordWrap = true, alignment = (TextAnchor)0, clipping = (TextClipping)0, richText = true }; return _tooltipBody; } private static void DrawSprite(Rect r, Sprite sprite) { //IL_0012: 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_0018: 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) Texture2D texture = sprite.texture; if (!((Object)(object)texture == (Object)null)) { Rect textureRect = sprite.textureRect; GUI.DrawTextureWithTexCoords(r, (Texture)(object)texture, new Rect(((Rect)(ref textureRect)).x / (float)((Texture)texture).width, ((Rect)(ref textureRect)).y / (float)((Texture)texture).height, ((Rect)(ref textureRect)).width / (float)((Texture)texture).width, ((Rect)(ref textureRect)).height / (float)((Texture)texture).height)); } } private static Vector2 GuiMousePosition() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) Vector3 mousePosition = Input.mousePosition; return new Vector2(mousePosition.x, (float)Screen.height - mousePosition.y); } private static Rect ClampToScreen(Rect r) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) ((Rect)(ref r)).x = Mathf.Clamp(((Rect)(ref r)).x, 0f, Mathf.Max(0f, (float)Screen.width - ((Rect)(ref r)).width)); ((Rect)(ref r)).y = Mathf.Clamp(((Rect)(ref r)).y, 0f, Mathf.Max(0f, (float)Screen.height - ((Rect)(ref r)).height)); return r; } } internal static class ChatRelay { [HarmonyPatch] internal static class RoutedRpcPatch { [HarmonyPatch(typeof(ZRoutedRpc), "HandleRoutedRPC")] [HarmonyPostfix] private static void HandleRoutedRPC_Postfix(RoutedRPCData data) { Observe(data); } [HarmonyPatch(typeof(ZRoutedRpc), "RouteRPC")] [HarmonyPostfix] private static void RouteRPC_Postfix(RoutedRPCData rpcData) { Observe(rpcData); } } private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.ChatRelay"); private const string ChatMessageRpc = "ChatMessage"; private const string ItemShareRpcName = "VikingOS_ChatItem"; private static readonly int ChatMessageHash = StringExtensionMethods.GetStableHashCode("ChatMessage"); private static readonly int ItemShareHash = StringExtensionMethods.GetStableHashCode("VikingOS_ChatItem"); private const string OutboxName = "outbox.txt"; private const float OutboxPollSeconds = 1f; private static float _nextOutboxPoll; private static string _writtenHeaderFor; private const float SameMessageWindow = 0.75f; private const int SeenCapacity = 256; private static readonly Dictionary _seen = new Dictionary(); private static float _nextSeenSweep; public static string ChatsDir => ModPaths.InConfigDir("Chats"); private static bool Enabled { get { if (ConfigManager.chatLog != null) { return ConfigManager.chatLog.Value; } return true; } } private static bool FirstSighting(string key) { float unscaledTime = Time.unscaledTime; if (_seen.TryGetValue(key, out var value) && unscaledTime - value < 0.75f) { _seen[key] = unscaledTime; return false; } _seen[key] = unscaledTime; if (unscaledTime >= _nextSeenSweep || _seen.Count > 256) { _nextSeenSweep = unscaledTime + 5f; List list = new List(); foreach (KeyValuePair item in _seen) { if (unscaledTime - item.Value >= 0.75f) { list.Add(item.Key); } } foreach (string item2 in list) { _seen.Remove(item2); } } return true; } private static void Observe(RoutedRPCData data) { if (!Enabled || data == null || data.m_parameters == null || (data.m_methodHash != ChatMessageHash && data.m_methodHash != ItemShareHash)) { return; } try { bool flag = data.m_methodHash == ItemShareHash; if (TryReadChat(data.m_parameters, out var type, out var name, out var id, out var text) && FirstSighting(string.Join("\u0001", id ?? string.Empty, name ?? string.Empty, type.ToString(CultureInfo.InvariantCulture), flag ? "item" : "text", text ?? string.Empty))) { Append(type, name, id, text, flag); } } catch (Exception ex) { Log.LogError((object)("chat transcript failed for one message (non-fatal). Reason: " + ex.Message)); } } private static bool TryReadChat(ZPackage p, out int type, out string name, out string id, out string text) { type = 0; name = null; id = null; text = null; int pos = p.GetPos(); try { p.SetPos(0); p.ReadSingle(); p.ReadSingle(); p.ReadSingle(); type = p.ReadInt(); name = p.ReadString(); id = p.ReadString(); text = p.ReadString(); } finally { p.SetPos(pos); } if (string.IsNullOrEmpty(text)) { return !string.IsNullOrEmpty(name); } return true; } private static void Append(int type, string name, string id, string text, bool share) { DateTime now = DateTime.Now; string text2 = Path.Combine(ChatsDir, $"chat-{now:yyyy-MM-dd}.log"); Directory.CreateDirectory(ChatsDir); StringBuilder stringBuilder = new StringBuilder(); if (_writtenHeaderFor != text2 && !File.Exists(text2)) { stringBuilder.AppendLine($"# VikingOS chat transcript - {now:yyyy-MM-dd}"); stringBuilder.AppendLine("# time | channel | player (platform id) | message"); } _writtenHeaderFor = text2; string text3 = Channel(type) + (share ? "+item" : string.Empty); stringBuilder.AppendLine($"{now:HH:mm:ss} | {text3,-8} | {name} ({id}) | {text}"); File.AppendAllText(text2, stringBuilder.ToString(), Encoding.UTF8); } private static string Channel(int type) { return type switch { 0 => "whisper", 1 => "normal", 2 => "shout", 3 => "ping", _ => "type" + type.ToString(CultureInfo.InvariantCulture), }; } public static void Pump() { if (!Enabled || Time.unscaledTime < _nextOutboxPoll) { return; } _nextOutboxPoll = Time.unscaledTime + 1f; if (ZRoutedRpc.instance == null) { return; } string path = Path.Combine(ChatsDir, "outbox.txt"); try { if (!File.Exists(path)) { return; } List list = new List(); string[] array = File.ReadAllLines(path); for (int i = 0; i < array.Length; i++) { string text = array[i]?.Trim(); if (!string.IsNullOrEmpty(text) && !text.StartsWith("#", StringComparison.Ordinal)) { list.Add(text); } } if (list.Count == 0) { return; } WriteStub(path); foreach (string item in list) { Broadcast(item); } } catch (IOException) { } catch (Exception ex2) { Log.LogError((object)("outbox pump failed (non-fatal). Reason: " + ex2.Message)); } } private static void Broadcast(string line) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_0060: Unknown result type (might be due to invalid IL or missing references) string text = "SERVER"; string text2 = line; int num = line.IndexOf(": ", StringComparison.Ordinal); if (num > 0 && num <= 32) { text = line.Substring(0, num); text2 = line.Substring(num + 2); } UserInfo val = new UserInfo { Name = text, UserId = PlatformUserID.None }; ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "ChatMessage", new object[4] { Vector3.zero, 2, val, text2 }); Log.LogInfo((object)("outbox -> all: " + text + ": " + text2)); } private static void WriteStub(string path) { File.WriteAllText(path, "# VikingOS outbox. Any line written below is broadcast to every player as a shout, and" + Environment.NewLine + "# this file is then reset to these three lines. Prefix a line with \"Name: \" to choose the" + Environment.NewLine + "# displayed sender; without one it goes out as SERVER. Lines starting with # are ignored." + Environment.NewLine, Encoding.UTF8); } public static void Init() { try { Directory.CreateDirectory(ChatsDir); string path = Path.Combine(ChatsDir, "outbox.txt"); if (!File.Exists(path) || string.IsNullOrWhiteSpace(File.ReadAllText(path))) { WriteStub(path); } } catch (Exception ex) { Log.LogError((object)("could not create " + ChatsDir + " (chat transcript disabled). Reason: " + ex.Message)); } } } [HarmonyPatch] internal static class ChatWindowFix { private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.ChatWindow"); private static LayoutTarget _chatTarget; private static bool _resizing; private static Vector2 _startMouse; private const float GripSize = 18f; public static bool Resizing => _resizing; [HarmonyPatch(typeof(Chat), "Awake")] [HarmonyPostfix] private static void Chat_Awake_Postfix(Chat __instance) { try { NormaliseRoot(__instance); FixAnchors(__instance); ApplyTextSize(__instance); } catch (Exception ex) { Diagnostics.Health("Chat window", ok: false, "the chat box could not be restructured - resizing it may misplace the input line. Reason: " + ex.Message); Log.LogError((object)ex.ToString()); } } private static void NormaliseRoot(Chat chat) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown //IL_0097: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //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_0128: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Expected O, but got Unknown //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0160: Unknown result type (might be due to invalid IL or missing references) //IL_016d: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)chat == (Object)null || (Object)(object)((Terminal)chat).m_output == (Object)null) { return; } Transform parent = ((Transform)((TMP_Text)((Terminal)chat).m_output).rectTransform).parent; RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null); if (val == null) { return; } RectTransform val2 = null; foreach (Transform item in (Transform)val) { Transform val3 = item; if (((Object)val3).name == "bkg") { RectTransform val4 = (RectTransform)(object)((val3 is RectTransform) ? val3 : null); if (val4 != null) { val2 = val4; break; } } } if (!((Object)(object)val2 == (Object)null)) { Vector2 val5 = val2.anchorMin - Vector2.zero; if (!(((Vector2)(ref val5)).sqrMagnitude > 0.001f)) { val5 = val2.anchorMax - Vector2.one; if (!(((Vector2)(ref val5)).sqrMagnitude > 0.001f)) { Vector2 val6 = (val2.offsetMin + val2.offsetMax) * 0.5f; if (((Vector2)(ref val6)).sqrMagnitude < 0.25f) { return; } val.anchoredPosition += val6; foreach (Transform item2 in (Transform)val) { object obj = (object)item2; RectTransform val7 = (RectTransform)((obj is RectTransform) ? obj : null); if (val7 != null) { val7.offsetMin -= val6; val7.offsetMax -= val6; } } Diagnostics.Health("Chat window", ok: true, $"chat root rect normalised onto its content (was displaced {val6.x:F0},{val6.y:F0})"); return; } } } Diagnostics.Trace(() => "chat root not normalised: no full-stretch bkg child to measure the content displacement from."); } private static void FixAnchors(Chat chat) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)chat == (Object)null) && !((Object)(object)((Terminal)chat).m_input == (Object)null)) { Transform transform = ((Component)((Terminal)chat).m_input).transform; RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null); if (val != null) { Reanchor(val, new Vector2(0f, 0f), new Vector2(1f, 0f)); Diagnostics.Health("Chat window", ok: true, "input line re-anchored - the chat box resizes as one window"); } } } private static void Reanchor(RectTransform rt, Vector2 newMin, Vector2 newMax) { //IL_0011: 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_001a: 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_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0066: 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_0075: 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_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) Transform parent = ((Transform)rt).parent; RectTransform val = (RectTransform)(object)((parent is RectTransform) ? parent : null); if (val != null) { Rect rect = val.rect; Vector2 size = ((Rect)(ref rect)).size; Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor((rt.anchorMin.x - newMin.x) * size.x, (rt.anchorMin.y - newMin.y) * size.y); Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor((rt.anchorMax.x - newMax.x) * size.x, (rt.anchorMax.y - newMax.y) * size.y); Vector2 offsetMin = rt.offsetMin + val2; Vector2 offsetMax = rt.offsetMax + val3; rt.anchorMin = newMin; rt.anchorMax = newMax; rt.offsetMin = offsetMin; rt.offsetMax = offsetMax; } } public static void ApplyTextSize(Chat chat) { if ((Object)(object)chat == (Object)null) { return; } float fontSize = ((ConfigManager.chatTextSize != null) ? ConfigManager.chatTextSize.Value : 18f); if ((Object)(object)((Terminal)chat).m_output != (Object)null) { ((TMP_Text)((Terminal)chat).m_output).fontSize = fontSize; } if ((Object)(object)((Terminal)chat).m_input != (Object)null) { TMP_Text[] componentsInChildren = ((Component)((Terminal)chat).m_input).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { componentsInChildren[i].fontSize = fontSize; } } } public static void OnTextSizeChanged() { try { ApplyTextSize(Chat.instance); } catch (Exception arg) { Log.LogError((object)$"applying the chat text size failed (non-fatal). Reason: {arg}"); } } public static void RefocusInput() { Chat instance = Chat.instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)((Terminal)instance).m_input == (Object)null)) { instance.m_hideTimer = 0f; ((Component)((Terminal)instance).m_input).gameObject.SetActive(true); ((Terminal)instance).m_input.ActivateInputField(); } } private static LayoutTarget ChatTarget() { if (_chatTarget != null && LayoutEngine.TryGetScreenRect(_chatTarget, out var _, out var _)) { return _chatTarget; } foreach (LayoutTarget target in LayoutEngine.Targets) { if (target.Category == "Chat" && target.Depth == 0) { _chatTarget = target; return target; } } return null; } public static bool TryGetChatHandles(out LayoutTarget target, out Vector2 unitsPerPixel) { //IL_0001: 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) unitsPerPixel = Vector2.one; target = ChatTarget(); Rect screenRect; if (target != null) { return LayoutEngine.TryGetScreenRect(target, out screenRect, out unitsPerPixel); } return false; } public static bool TryGetChatGuiRect(out Rect gui) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) gui = default(Rect); LayoutTarget layoutTarget = ChatTarget(); if (layoutTarget == null) { return false; } if (!LayoutEngine.TryGetScreenRect(layoutTarget, out var screenRect, out var _)) { return false; } gui = new Rect(((Rect)(ref screenRect)).x, (float)Screen.height - ((Rect)(ref screenRect)).y - ((Rect)(ref screenRect)).height, ((Rect)(ref screenRect)).width, ((Rect)(ref screenRect)).height); return true; } public static void DrawGrip() { //IL_0080: 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_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Invalid comparison between Unknown and I4 //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Invalid comparison between Unknown and I4 //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Invalid comparison between Unknown and I4 //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0113: 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_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0135: 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) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) LayoutTarget layoutTarget = ChatTarget(); if (layoutTarget == null || !LayoutEngine.TryGetScreenRect(layoutTarget, out var screenRect, out var unitsPerPixel)) { return; } Rect val = default(Rect); ((Rect)(ref val))..ctor(((Rect)(ref screenRect)).x, (float)Screen.height - ((Rect)(ref screenRect)).y - ((Rect)(ref screenRect)).height, ((Rect)(ref screenRect)).width, ((Rect)(ref screenRect)).height); Rect r = default(Rect); ((Rect)(ref r))..ctor(((Rect)(ref val)).xMax - 18f - 2f, ((Rect)(ref val)).yMax - 18f - 2f, 18f, 18f); GiltFrameTheme.DrawInset(r); Event current = Event.current; if (current == null) { return; } if (!_resizing && (int)current.type == 0 && current.button == 0 && ((Rect)(ref r)).Contains(current.mousePosition)) { _resizing = true; _startMouse = current.mousePosition; current.Use(); } else if (_resizing && (int)current.type == 3 && current.button == 0) { Vector2 val2 = current.mousePosition - _startMouse; _startMouse = current.mousePosition; if (LayoutEngine.TryGetRectInfo(layoutTarget, out var pivot, out var _)) { float num = val2.x * unitsPerPixel.x; float num2 = val2.y * unitsPerPixel.y; Vector2 anchorCompensation = default(Vector2); ((Vector2)(ref anchorCompensation))..ctor(pivot.x * num, (0f - (1f - pivot.y)) * num2); LayoutEngine.Resize(layoutTarget, new Vector2(num, num2), anchorCompensation); current.Use(); } } else if (_resizing && ((int)current.type == 1 || (int)current.rawType == 1)) { _resizing = false; LayoutEngine.Commit(); RefocusInput(); current.Use(); } } } internal static class EmojiPicker { private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.EmojiPicker"); public const string WindowId = "VikingOS_EmojiPicker"; private static bool _browseOpen; private static Vector2 _scroll; private static string _hoveredName; private static bool _hoveredAnimated; private static Rect _panelRect; private static int _lastDrawnFrame = -1; private const int MaxSuggestions = 14; private static readonly List _matches = new List(); public static bool BrowseOpen => _browseOpen; public static Rect PanelRect => _panelRect; public static void ToggleBrowse() { _browseOpen = !_browseOpen; if (_browseOpen) { _lastDrawnFrame = Time.frameCount; } } public static void CloseBrowse() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) _browseOpen = false; _panelRect = default(Rect); ReleaseFocus(); } private static void ReleaseFocus() { UIFocus.SetWantsCursor("VikingOS_EmojiPicker", active: false); UIFocus.SetHasTextFocus("VikingOS_EmojiPicker", active: false); } public static void Watchdog() { if (!_browseOpen) { ReleaseFocus(); } else if (Time.frameCount - _lastDrawnFrame > 2) { CloseBrowse(); } } public static void Draw(Rect anchor, bool chatFocused) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Invalid comparison between Unknown and I4 //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Invalid comparison between Unknown and I4 try { _panelRect = default(Rect); if (_browseOpen) { UIFocus.SetWantsCursor("VikingOS_EmojiPicker", active: true); UIFocus.SetHasTextFocus("VikingOS_EmojiPicker", active: true); _lastDrawnFrame = Time.frameCount; Event current = Event.current; if (current != null && (int)current.type == 4 && (int)current.keyCode == 27) { CloseBrowse(); current.Use(); } else { DrawBrowse(anchor); } } else { ReleaseFocus(); if (chatFocused) { DrawAutocomplete(anchor); } } } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed (non-fatal, picker hidden this frame). Reason: {1}", "Draw", arg)); } } private static void DrawBrowse(Rect anchor) { //IL_0053: 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) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_0074: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) IReadOnlyList previews = EmoteRenderer.Previews; if (previews.Count != 0) { float num = Mathf.Clamp(((Rect)(ref anchor)).width, GiltFrameTheme.S(340f), GiltFrameTheme.S(640f)); float num2 = GiltFrameTheme.S(300f); Rect val = (_panelRect = ClampToScreen(new Rect(((Rect)(ref anchor)).x, ((Rect)(ref anchor)).y - num2 - 8f, num, num2))); GiltFrameTheme.DrawPanelFill(val); GiltFrameTheme.DrawFrame(val); Rect val2 = GiltFrameTheme.Body(val); float num3 = GiltFrameTheme.S(22f); GiltFrameTheme.DrawShadowed(new Rect(((Rect)(ref val2)).x, ((Rect)(ref val2)).y, ((Rect)(ref val2)).width - num3 - 4f, num3), $"{previews.Count} EMOJI - CLICK TO CHAT ONE", GiltFrameTheme.Header); if (GUI.Button(new Rect(((Rect)(ref val2)).xMax - num3, ((Rect)(ref val2)).y, num3, num3), "×", GiltFrameTheme.Button)) { _browseOpen = false; } float num4 = GiltFrameTheme.S(20f); string text = ((_hoveredName == null) ? "type :name: in chat by hand, or click" : (":" + _hoveredName + ":" + (_hoveredAnimated ? " (animated)" : ""))); GiltFrameTheme.DrawShadowed(new Rect(((Rect)(ref val2)).x, ((Rect)(ref val2)).yMax - num4, ((Rect)(ref val2)).width, num4), text, GiltFrameTheme.Note); Rect val3 = new Rect(((Rect)(ref val2)).x, ((Rect)(ref val2)).y + num3 + 4f, ((Rect)(ref val2)).width, ((Rect)(ref val2)).height - num3 - num4 - 10f); GiltFrameTheme.DrawInset(val3); DrawGrid(val3, previews); } } private static void DrawGrid(Rect area, IReadOnlyList previews) { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: 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_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) float num = GiltFrameTheme.S(34f); float num2 = 3f; float num3 = num + num2; Rect val = default(Rect); ((Rect)(ref val))..ctor(((Rect)(ref area)).x + 4f, ((Rect)(ref area)).y + 4f, ((Rect)(ref area)).width - 8f, ((Rect)(ref area)).height - 8f); int num4 = Mathf.Max(1, Mathf.FloorToInt((((Rect)(ref val)).width - 14f) / num3)); int num5 = (previews.Count + num4 - 1) / num4; Rect val2 = default(Rect); ((Rect)(ref val2))..ctor(0f, 0f, ((Rect)(ref val)).width - 14f, (float)num5 * num3); _scroll = GUI.BeginScrollView(val, _scroll, val2); _hoveredName = null; int num6 = Mathf.Max(0, Mathf.FloorToInt(_scroll.y / num3)); int num7 = Mathf.Min(num5 - 1, Mathf.CeilToInt((_scroll.y + ((Rect)(ref val)).height) / num3)); Vector2 mousePosition = Event.current.mousePosition; Rect val3 = default(Rect); for (int i = num6; i <= num7; i++) { for (int j = 0; j < num4; j++) { int num8 = i * num4 + j; if (num8 >= previews.Count) { break; } EmoteRenderer.Preview preview = previews[num8]; ((Rect)(ref val3))..ctor((float)j * num3, (float)i * num3, num, num); bool num9 = ((Rect)(ref val3)).Contains(mousePosition); if (num9) { _hoveredName = preview.Name; _hoveredAnimated = preview.Animated; GiltFrameTheme.DrawFill(val3, GiltFrameTheme.Metal(0.25f)); } DrawPreview(val3, preview); if (num9 && (int)Event.current.type == 0 && Event.current.button == 0) { Insert(preview.Name); Event.current.Use(); } } } GUI.EndScrollView(); } private static void DrawPreview(Rect box, EmoteRenderer.Preview p) { //IL_0089: 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) if (!((Object)(object)p.Tex == (Object)null)) { float num = ((Rect)(ref box)).width; float num2 = ((Rect)(ref box)).height; if (p.WidthOverHeight > 1f) { num2 = ((Rect)(ref box)).height / p.WidthOverHeight; } else if (p.WidthOverHeight < 1f) { num = ((Rect)(ref box)).width * p.WidthOverHeight; } GUI.DrawTextureWithTexCoords(new Rect(((Rect)(ref box)).x + (((Rect)(ref box)).width - num) * 0.5f, ((Rect)(ref box)).y + (((Rect)(ref box)).height - num2) * 0.5f, num, num2), (Texture)(object)p.Tex, p.Uv); } } private static void DrawAutocomplete(Rect anchor) { //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_012e: 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_0135: 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) //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_028b: Unknown result type (might be due to invalid IL or missing references) string text = CurrentFragment(); if (text == null) { return; } _matches.Clear(); IReadOnlyList previews = EmoteRenderer.Previews; for (int i = 0; i < 2; i++) { if (_matches.Count >= 14) { break; } for (int j = 0; j < previews.Count; j++) { if (_matches.Count >= 14) { break; } EmoteRenderer.Preview preview = previews[j]; if (((i == 0) ? preview.Name.StartsWith(text, StringComparison.OrdinalIgnoreCase) : (preview.Name.IndexOf(text, StringComparison.OrdinalIgnoreCase) > 0)) && !_matches.Contains(preview)) { _matches.Add(preview); } } } if (_matches.Count == 0) { return; } float num = GiltFrameTheme.S(30f); float num2 = 3f; float num3 = Mathf.Min(((Rect)(ref anchor)).width, (float)_matches.Count * (num + num2) + 10f); float num4 = num + GiltFrameTheme.S(24f); Rect val = (_panelRect = ClampToScreen(new Rect(((Rect)(ref anchor)).x, ((Rect)(ref anchor)).y - num4 - 6f, Mathf.Max(num3, GiltFrameTheme.S(160f)), num4))); GiltFrameTheme.DrawPanelFill(val); GiltFrameTheme.DrawOutline(val, GiltFrameTheme.Gold, 1f); _hoveredName = null; Vector2 mousePosition = Event.current.mousePosition; float num5 = ((Rect)(ref val)).x + 5f; Rect val2 = default(Rect); foreach (EmoteRenderer.Preview match in _matches) { ((Rect)(ref val2))..ctor(num5, ((Rect)(ref val)).y + 4f, num, num); bool num6 = ((Rect)(ref val2)).Contains(mousePosition); if (num6) { _hoveredName = match.Name; GiltFrameTheme.DrawFill(val2, GiltFrameTheme.Metal(0.25f)); } DrawPreview(val2, match); if (num6 && (int)Event.current.type == 0 && Event.current.button == 0) { Insert(match.Name); Event.current.Use(); } num5 += num + num2; } string text2 = ((_hoveredName != null) ? (":" + _hoveredName + ":") : (":" + text + "...")); GiltFrameTheme.DrawShadowed(new Rect(((Rect)(ref val)).x + 5f, ((Rect)(ref val)).yMax - GiltFrameTheme.S(20f), ((Rect)(ref val)).width - 10f, GiltFrameTheme.S(18f)), text2, GiltFrameTheme.Note); } private static string CurrentFragment() { Chat instance = Chat.instance; if ((Object)(object)instance == (Object)null || (Object)(object)((Terminal)instance).m_input == (Object)null) { return null; } string text = ((TMP_InputField)((Terminal)instance).m_input).text; if (string.IsNullOrEmpty(text)) { return null; } int num = text.LastIndexOf(':'); if (num < 0) { return null; } string text2 = text.Substring(num + 1); if (text2.Length < 1 || text2.Length > 24) { return null; } string text3 = text2; foreach (char c in text3) { if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c < '0' || c > '9') && c != '_' && c != '-') { return null; } } return text2; } private static void Insert(string name) { try { Chat instance = Chat.instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)((Terminal)instance).m_input == (Object)null)) { string text = ((TMP_InputField)((Terminal)instance).m_input).text ?? ""; int num = text.LastIndexOf(':'); string text2 = ((num >= 0 && CurrentFragment() != null) ? text.Substring(0, num) : text) + ":" + name + ": "; ((TMP_InputField)((Terminal)instance).m_input).text = text2; TMP_InputField input = (TMP_InputField)(object)((Terminal)instance).m_input; if (input != null) { input.ActivateInputField(); input.caretPosition = text2.Length; input.stringPosition = text2.Length; } } } catch (Exception arg) { Log.LogError((object)$"inserting an emoji failed (non-fatal). Reason: {arg}"); } } private static Rect ClampToScreen(Rect r) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) ((Rect)(ref r)).x = Mathf.Clamp(((Rect)(ref r)).x, 0f, Mathf.Max(0f, (float)Screen.width - ((Rect)(ref r)).width)); ((Rect)(ref r)).y = Mathf.Clamp(((Rect)(ref r)).y, 0f, Mathf.Max(0f, (float)Screen.height - ((Rect)(ref r)).height)); return r; } } internal static class EmoteLibrary { [HarmonyPatch] internal static class SessionPatch { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static ConsoleEvent <>9__3_0; public static Comparison <>9__3_3; public static ConsoleEvent <>9__3_1; internal void b__3_0(ConsoleEventArgs args) { <>c__DisplayClass3_0 CS$<>8__locals1 = new <>c__DisplayClass3_0 { args = args }; Library.RequestReload(delegate(string msg) { Terminal context = CS$<>8__locals1.args.Context; if (context != null) { context.AddString("vikingos_emotereload: " + msg); } }); } internal void b__3_1(ConsoleEventArgs args) { List list = Library.Entries(); list.Sort((BlobLibrary.Entry a, BlobLibrary.Entry b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase)); Terminal context = args.Context; if (context != null) { context.AddString(RunMode.HasUI ? $"vikingos_emotes: {EmoteRenderer.Count} emoji(s) ready in all - {list.Count} of them this server's own:" : $"vikingos_emotes: offering {list.Count} server emote(s):"); } foreach (BlobLibrary.Entry item in list) { string text = ((RunMode.HasUI && !EmoteRenderer.IsReady(item.Name)) ? " (downloading...)" : ""); Terminal context2 = args.Context; if (context2 != null) { context2.AddString(" :" + item.Name.ToLowerInvariant() + ":" + ((item.Kind == BlobLibrary.BlobKind.Gif) ? " (animated)" : "") + text); } } } internal int b__3_3(BlobLibrary.Entry a, BlobLibrary.Entry b) { return string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase); } } [CompilerGenerated] private sealed class <>c__DisplayClass3_0 { public ConsoleEventArgs args; internal void b__2(string msg) { Terminal context = args.Context; if (context != null) { context.AddString("vikingos_emotereload: " + msg); } } } private static bool _commandsRegistered; [HarmonyPatch(typeof(ZNet), "Awake")] [HarmonyPostfix] private static void ZNet_Awake_Postfix() { try { Library.OnSessionStart(); Diagnostics.Health("Emotes", ok: true, "library registered for this session"); } catch (Exception ex) { Diagnostics.Health("Emotes", ok: false, "the emote library could not start, emotes are plain text this session. Reason: " + ex.Message); Log.LogError((object)ex.ToString()); } } [HarmonyPatch(typeof(ZNet), "Shutdown")] [HarmonyPostfix] private static void ZNet_Shutdown_Postfix() { try { Library.OnSessionEnd(); } catch (Exception ex) { Log.LogError((object)ex.ToString()); } } [HarmonyPatch(typeof(Terminal), "InitTerminal")] [HarmonyPostfix] private static void Terminal_InitTerminal_Postfix() { //IL_0040: 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_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown if (_commandsRegistered) { return; } _commandsRegistered = true; try { object obj = <>c.<>9__3_0; if (obj == null) { ConsoleEvent val = delegate(ConsoleEventArgs args) { Library.RequestReload(delegate(string msg) { Terminal context = args.Context; if (context != null) { context.AddString("vikingos_emotereload: " + msg); } }); }; <>c.<>9__3_0 = val; obj = (object)val; } new ConsoleCommand("vikingos_emotereload", "rescans the server's config/VikingOS/emotes folder and offers any new emotes to every player, without a restart. Admins only.", (ConsoleEvent)obj, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); object obj2 = <>c.<>9__3_1; if (obj2 == null) { ConsoleEvent val2 = delegate(ConsoleEventArgs args) { List list = Library.Entries(); list.Sort((BlobLibrary.Entry a, BlobLibrary.Entry b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase)); Terminal context = args.Context; if (context != null) { context.AddString(RunMode.HasUI ? $"vikingos_emotes: {EmoteRenderer.Count} emoji(s) ready in all - {list.Count} of them this server's own:" : $"vikingos_emotes: offering {list.Count} server emote(s):"); } foreach (BlobLibrary.Entry item in list) { string text = ((RunMode.HasUI && !EmoteRenderer.IsReady(item.Name)) ? " (downloading...)" : ""); Terminal context2 = args.Context; if (context2 != null) { context2.AddString(" :" + item.Name.ToLowerInvariant() + ":" + ((item.Kind == BlobLibrary.BlobKind.Gif) ? " (animated)" : "") + text); } } }; <>c.<>9__3_1 = val2; obj2 = (object)val2; } new ConsoleCommand("vikingos_emotes", "lists this world's SERVER emotes and the total emoji count. Type :name: in chat; standard names (:joy:, :fire:) come from the embedded library.", (ConsoleEvent)obj2, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } catch (Exception arg) { Log.LogError((object)$"could not register the emote console commands (non-fatal). Reason: {arg}"); } } } private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.Emotes"); private static readonly CustomSyncedValue SyncedCatalogue = new CustomSyncedValue(ConfigManager.Sync, "vikingos_emotecatalogue", ""); public static readonly BlobLibrary Library = new BlobLibrary("emote", "VikingOS_Emote", SyncedCatalogue, () => ModPaths.InConfigDir("emotes"), ModPaths.InConfigDir("emotecache"), new BlobLibrary.Limits { MaxBytes = 4194304, MaxWidth = 512, MaxHeight = 256, MaxCount = 256, AcceptGif = true, OversizeRewriter = TranscodeOversizeGif }, () => ChatFeatures.Enabled && (ConfigManager.shareEmotes == null || ConfigManager.shareEmotes.Value), () => (MonoBehaviour)(object)Plugin.Instance, delegate(string s) { Log.LogInfo((object)s); }, delegate(string s) { Log.LogWarning((object)s); }, delegate(string s) { Log.LogError((object)s); }); private static byte[] TranscodeOversizeGif(string path, byte[] bytes) { try { if (!GifDecoder.TryDecode(bytes, out var width, out var height, out var frames)) { return null; } float num = Mathf.Min(1f, Mathf.Min(512f / (float)width, 256f / (float)height)); for (int i = 0; i < 4; i++) { int num2 = Mathf.Max(16, Mathf.RoundToInt((float)width * num)); int num3 = Mathf.Max(16, Mathf.RoundToInt((float)height * num)); int num4 = Math.Min(frames.Count, 16); float num5 = 0f; foreach (GifDecoder.Frame item in frames) { num5 += Mathf.Max(0.02f, item.DelaySeconds); } List list = new List(num4); for (int j = 0; j < num4; j++) { GifDecoder.Frame frame = frames[(int)((long)j * (long)frames.Count / num4)]; list.Add(new GifEncoder.Frame { Pixels = GifEncoder.Resize(frame.Pixels, width, height, num2, num3), DelaySeconds = num5 / (float)num4 }); } byte[] array = GifEncoder.Encode(num2, num3, list); if (array != null && array.Length <= 4194304) { return array; } num *= 0.7f; } return null; } catch (Exception ex) { Log.LogWarning((object)("transcoding '" + Path.GetFileName(path) + "' failed (the file is skipped). Reason: " + ex.Message)); return null; } } public static void Init() { try { Directory.CreateDirectory(ModPaths.InConfigDir("emotes")); } catch (Exception ex) { Log.LogWarning((object)("could not create the emotes folder (non-fatal): " + ex.Message)); } if (RunMode.HasUI) { Library.Changed += EmoteRenderer.OnLibraryChanged; } } } internal static class EmoteRenderer { private sealed class Emote { public string Markup; } public sealed class Preview { public string Name; public Texture2D Tex; public Rect Uv; public float WidthOverHeight; public bool Animated; } private sealed class Prepared { public string Name; public List Frames; public int W; public float Fps; public bool Animated => Frames.Count > 1; } private sealed class Page { public int W; public int MaxH; public int CellH; public int X; public int Y; public Color32[] Pixels; public int UsedH; public int TexH; public TMP_SpriteAsset Asset; public bool TryPlace(int w, out int x, out int y) { if (X + w > W) { X = 0; Y += CellH; } if (Y + CellH > MaxH) { x = 0; y = 0; return false; } x = X; y = Y; X += w; UsedH = Y + CellH; return true; } } [HarmonyPatch] internal static class ChatHookPatch { [HarmonyPatch(typeof(Chat), "Awake")] [HarmonyPostfix] private static void Chat_Awake_Postfix() { RequestBuild(); AssignToChat(); } } private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.Emotes"); private const int AnimCellH = 56; private const int StaticCellH = 48; private const int MaxAspect = 4; private const int AnimPageW = 4096; private const int AnimPageMaxH = 2048; private const int StaticPageW = 2048; private const int StaticPageMaxH = 2048; private const int MaxGifFrames = 14; private const double BuildBudgetMs = 6.0; private static readonly Regex TokenRegex = new Regex(":([A-Za-z0-9_\\-]{2,24}):", RegexOptions.Compiled); private static readonly List _previews = new List(); private static readonly Dictionary _emotes = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly List _assets = new List(); private static readonly List _textures = new List(); private static Coroutine _build; private static bool _rebuildQueued; private static readonly MethodInfo LoadImageMethod = typeof(ImageConversion).GetMethod("LoadImage", new Type[3] { typeof(Texture2D), typeof(byte[]), typeof(bool) }) ?? typeof(ImageConversion).GetMethod("LoadImage", new Type[2] { typeof(Texture2D), typeof(byte[]) }); public static IReadOnlyList Previews => _previews; public static int PreviewVersion { get; private set; } public static int Count => _emotes.Count; public static bool IsReady(string name) { return _emotes.ContainsKey(name); } public static void OnLibraryChanged() { RequestBuild(); } public static void RequestBuild() { if (RunMode.HasUI && !((Object)(object)Plugin.Instance == (Object)null)) { if (_build != null) { _rebuildQueued = true; } else { _build = ((MonoBehaviour)Plugin.Instance).StartCoroutine(BuildRoutine()); } } } public static string Expand(string text) { if (!RunMode.HasUI) { return text; } if (string.IsNullOrEmpty(text)) { return text; } if (text.IndexOf(':') < 0) { return text; } if (_emotes.Count == 0) { return text; } Emote value; return TokenRegex.Replace(text, (Match match) => (!_emotes.TryGetValue(match.Groups[1].Value, out value)) ? match.Value : value.Markup); } private static IEnumerator BuildRoutine() { Stopwatch watch = new Stopwatch(); watch.Start(); List list = EmoteSources.Gather(); List prepared = new List(list.Count); double totalMilliseconds = watch.Elapsed.TotalMilliseconds; foreach (EmoteSource item in list) { Prepared prepared2 = null; try { prepared2 = Decode(item); } catch (Exception ex) { Log.LogWarning((object)("emote '" + item.Name + "' failed to decode - skipped. Reason: " + ex.Message)); } if (prepared2 != null) { prepared.Add(prepared2); } if (watch.Elapsed.TotalMilliseconds - totalMilliseconds > 6.0) { yield return null; totalMilliseconds = watch.Elapsed.TotalMilliseconds; } } prepared.Sort(delegate(Prepared a, Prepared b) { if (a.Animated == b.Animated) { return string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase); } return (!a.Animated) ? 1 : (-1); }); try { Commit(prepared); } catch (Exception arg) { Log.LogError((object)$"building the emote atlas failed (non-fatal, emotes show as text). Reason: {arg}"); } Log.LogInfo((object)$"emote atlas: {_emotes.Count} emote(s) across {_assets.Count} page(s) in {watch.Elapsed.TotalSeconds:0.0}s of background work."); _build = null; if (_rebuildQueued) { _rebuildQueued = false; RequestBuild(); } } private static Prepared Decode(EmoteSource source) { //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Expected O, but got Unknown byte[] array = source.Load?.Invoke(); if (array == null) { return null; } int num = (source.Gif ? 56 : 48); int maxW = num * 4; if (source.Gif) { if (!GifDecoder.TryDecode(array, out var width, out var height, out var frames)) { return null; } int num2 = Mathf.Min(frames.Count, 14); float num3 = 0f; foreach (GifDecoder.Frame item in frames) { num3 += Mathf.Max(0.02f, item.DelaySeconds); } int num4 = FitWidth(width, height, num, maxW); List list = new List(num2); for (int i = 0; i < num2; i++) { GifDecoder.Frame frame = frames[(int)((long)i * (long)frames.Count / num2)]; list.Add(GifEncoder.Resize(frame.Pixels, width, height, num4, num)); } return new Prepared { Name = source.Name, Frames = list, W = num4, Fps = ((num2 > 1) ? Mathf.Clamp((float)frames.Count / num3, 1f, 30f) : 1f) }; } Texture2D val = null; try { val = new Texture2D(2, 2, (TextureFormat)4, false); if (!LoadImage(val, array)) { return null; } int num5 = FitWidth(((Texture)val).width, ((Texture)val).height, num, maxW); Color32[] pixels = val.GetPixels32(); FlipRows(pixels, ((Texture)val).width, ((Texture)val).height); return new Prepared { Name = source.Name, Frames = new List { GifEncoder.Resize(pixels, ((Texture)val).width, ((Texture)val).height, num5, num) }, W = num5, Fps = 1f }; } finally { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)val); } } } private static int FitWidth(int srcW, int srcH, int cellH, int maxW) { if (srcW <= 0 || srcH <= 0) { return cellH; } return Mathf.Clamp(Mathf.RoundToInt((float)cellH * ((float)srcW / (float)srcH)), 8, maxW); } private static void FlipRows(Color32[] pixels, int w, int h) { Color32[] array = (Color32[])(object)new Color32[w]; for (int i = 0; i < h / 2; i++) { int num = i * w; int num2 = (h - 1 - i) * w; Array.Copy(pixels, num, array, 0, w); Array.Copy(pixels, num2, pixels, num, w); Array.Copy(array, 0, pixels, num2, w); } } private static void Commit(List prepared) { //IL_0342: Unknown result type (might be due to invalid IL or missing references) //IL_0347: Unknown result type (might be due to invalid IL or missing references) //IL_0352: Unknown result type (might be due to invalid IL or missing references) //IL_0359: Unknown result type (might be due to invalid IL or missing references) //IL_0362: Expected O, but got Unknown //IL_0420: Unknown result type (might be due to invalid IL or missing references) //IL_0425: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Expected O, but got Unknown //IL_050f: Unknown result type (might be due to invalid IL or missing references) //IL_0514: Unknown result type (might be due to invalid IL or missing references) //IL_051c: Unknown result type (might be due to invalid IL or missing references) //IL_053f: Unknown result type (might be due to invalid IL or missing references) //IL_0549: Unknown result type (might be due to invalid IL or missing references) //IL_0577: Unknown result type (might be due to invalid IL or missing references) //IL_0581: Unknown result type (might be due to invalid IL or missing references) //IL_058e: Expected O, but got Unknown //IL_05a3: Unknown result type (might be due to invalid IL or missing references) //IL_05a8: Unknown result type (might be due to invalid IL or missing references) //IL_05dd: Unknown result type (might be due to invalid IL or missing references) //IL_05ea: Expected O, but got Unknown //IL_06ba: Unknown result type (might be due to invalid IL or missing references) //IL_06c4: Expected O, but got Unknown //IL_070f: Unknown result type (might be due to invalid IL or missing references) //IL_0714: Unknown result type (might be due to invalid IL or missing references) List list = new List(); Page page = new Page { W = 4096, MaxH = 2048, CellH = 56, Pixels = (Color32[])(object)new Color32[8388608] }; Page page2 = null; List<(Prepared, Page, int, List<(int, int)>)> list2 = new List<(Prepared, Page, int, List<(int, int)>)>(); bool flag = false; int num = 0; foreach (Prepared item12 in prepared) { if (item12.Animated) { List<(int, int)> list3 = new List<(int, int)>(item12.Frames.Count); bool flag2 = true; foreach (Color32[] frame in item12.Frames) { _ = frame; if (!page.TryPlace(item12.W, out var x, out var y)) { flag2 = false; break; } list3.Add((x, y)); } if (!flag2) { num++; continue; } flag = true; list2.Add((item12, page, 0, list3)); continue; } if (page2 == null || !page2.TryPlace(item12.W, out var x2, out var y2)) { page2 = new Page { W = 2048, MaxH = 2048, CellH = 48, Pixels = (Color32[])(object)new Color32[4194304] }; list.Add(page2); if (!page2.TryPlace(item12.W, out x2, out y2)) { continue; } } list2.Add((item12, page2, 0, new List<(int, int)> { (x2, y2) })); } if (num > 0) { Log.LogWarning((object)($"the animation page is full - {num} animated emote(s) were not rendered. " + "Fewer or shorter animated GIFs will bring them back.")); } List list4 = new List(); if (flag) { list4.Add(page); } list4.AddRange(list); if (list4.Count == 0) { Swap(new Dictionary(StringComparer.OrdinalIgnoreCase), new List(), new List(), new List()); return; } foreach (var item13 in list2) { Prepared item = item13.Item1; Page item2 = item13.Item2; List<(int, int)> item3 = item13.Item4; for (int i = 0; i < item.Frames.Count; i++) { (int, int) tuple = item3[i]; int item4 = tuple.Item1; int item5 = tuple.Item2; Color32[] sourceArray = item.Frames[i]; for (int j = 0; j < item2.CellH; j++) { Array.Copy(sourceArray, j * item.W, item2.Pixels, (item5 + j) * item2.W + item4, item.W); } } } List list5 = new List(); List list6 = new List(); Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); List list7 = new List(); Dictionary dictionary2 = new Dictionary(); foreach (Page item14 in list4) { int num2 = Mathf.Max(4, (item14.UsedH + 3) / 4 * 4); Texture2D val = new Texture2D(item14.W, num2, (TextureFormat)4, false) { name = "VikingOS_Emotes", filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; Color32[] array = (Color32[])(object)new Color32[item14.W * num2]; for (int k = 0; k < item14.UsedH; k++) { Array.Copy(item14.Pixels, k * item14.W, array, (num2 - 1 - k) * item14.W, item14.W); } val.SetPixels32(array); val.Apply(false, false); TMP_SpriteAsset val2 = ScriptableObject.CreateInstance(); ((Object)val2).name = "VikingOS_Emotes_" + list5.Count; val2.spriteSheet = (Texture)(object)val; Shader val3 = Shader.Find("TextMeshPro/Sprite"); ((TMP_Asset)val2).material = new Material(((Object)(object)val3 != (Object)null) ? val3 : Shader.Find("Sprites/Default")) { mainTexture = (Texture)(object)val }; TrySetFaceInfo(val2, item14.CellH); TrySetVersion(val2); list5.Add(val2); list6.Add(val); dictionary2[item14] = 0; item14.TexH = num2; item14.Asset = val2; } foreach (var item15 in list2) { Prepared item6 = item15.Item1; Page item7 = item15.Item2; List<(int, int)> item8 = item15.Item4; TMP_SpriteAsset asset = item7.Asset; int num3 = dictionary2[item7]; for (int l = 0; l < item8.Count; l++) { (int, int) tuple2 = item8[l]; int item9 = tuple2.Item1; int item10 = tuple2.Item2; int index = dictionary2[item7]++; TMP_SpriteGlyph val4 = new TMP_SpriteGlyph { index = (uint)index, glyphRect = new GlyphRect(item9, item7.TexH - item10 - item7.CellH, item6.W, item7.CellH), metrics = new GlyphMetrics((float)item6.W, (float)item7.CellH, 0f, (float)item7.CellH * 0.82f, (float)(item6.W + 2)), scale = 1f }; asset.spriteGlyphTable.Add(val4); TMP_SpriteCharacter item11 = new TMP_SpriteCharacter(65534u, val4) { name = ((l == 0) ? item6.Name.ToLowerInvariant() : $"{item6.Name.ToLowerInvariant()}~{l}"), scale = 1f }; asset.spriteCharacterTable.Add(item11); } dictionary[item6.Name] = new Emote { Markup = (item6.Animated ? $"" : ("")) }; var (num4, num5) = item8[0]; list7.Add(new Preview { Name = item6.Name.ToLowerInvariant(), Tex = (Texture2D)item7.Asset.spriteSheet, Uv = new Rect((float)num4 / (float)item7.W, (float)(item7.TexH - num5 - item7.CellH) / (float)item7.TexH, (float)item6.W / (float)item7.W, (float)item7.CellH / (float)item7.TexH), WidthOverHeight = (float)item6.W / (float)item7.CellH, Animated = item6.Animated }); } foreach (TMP_SpriteAsset item16 in list5) { item16.UpdateLookupTables(); } for (int m = 1; m < list5.Count; m++) { list5[0].fallbackSpriteAssets = list5[0].fallbackSpriteAssets ?? new List(); list5[0].fallbackSpriteAssets.Add(list5[m]); } list7.Sort((Preview a, Preview b) => string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase)); Swap(dictionary, list5, list6, list7); } private static void Swap(Dictionary emotes, List assets, List textures, List previews) { foreach (TMP_SpriteAsset asset in _assets) { if ((Object)(object)asset != (Object)null) { Object.Destroy((Object)(object)asset); } } foreach (Texture2D texture in _textures) { if ((Object)(object)texture != (Object)null) { Object.Destroy((Object)(object)texture); } } _assets.Clear(); _textures.Clear(); _emotes.Clear(); _previews.Clear(); _assets.AddRange(assets); _textures.AddRange(textures); _previews.AddRange(previews); foreach (KeyValuePair emote in emotes) { _emotes[emote.Key] = emote.Value; } PreviewVersion++; AssignToChat(); } public static void AssignTo(TMP_Text text) { if (!((Object)(object)text == (Object)null) && _assets.Count != 0 && text.spriteAsset != _assets[0]) { text.spriteAsset = _assets[0]; } } public static void AssignToChat() { if (_assets.Count == 0) { return; } try { Chat instance = Chat.instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)((Terminal)instance).m_output == (Object)null)) { if (((TMP_Text)((Terminal)instance).m_output).spriteAsset != _assets[0]) { ((TMP_Text)((Terminal)instance).m_output).spriteAsset = _assets[0]; ((Graphic)((Terminal)instance).m_output).SetAllDirty(); } ItemIconSprites.EnsureAttached(); } } catch (Exception arg) { Log.LogError((object)$"assigning the emote atlas to chat failed (non-fatal). Reason: {arg}"); } } private static bool LoadImage(Texture2D tex, byte[] bytes) { if (LoadImageMethod == null) { return false; } object[] parameters = ((LoadImageMethod.GetParameters().Length != 3) ? new object[2] { tex, bytes } : new object[3] { tex, bytes, false }); return (bool)LoadImageMethod.Invoke(null, parameters); } private static void TrySetFaceInfo(TMP_SpriteAsset asset, int cellH) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) try { FieldInfo fieldInfo = FindField(((object)asset).GetType(), "m_FaceInfo"); if (!(fieldInfo == null)) { FaceInfo val = default(FaceInfo); ((FaceInfo)(ref val)).pointSize = cellH; ((FaceInfo)(ref val)).scale = 1f; ((FaceInfo)(ref val)).lineHeight = (float)cellH * 1.1f; ((FaceInfo)(ref val)).ascentLine = (float)cellH * 0.82f; ((FaceInfo)(ref val)).descentLine = (float)(-cellH) * 0.18f; FaceInfo val2 = val; fieldInfo.SetValue(asset, val2); } } catch (Exception ex) { Log.LogWarning((object)("could not set the emote atlas face info - emotes may render oversized. Reason: " + ex.Message)); } } private static void TrySetVersion(TMP_SpriteAsset asset) { try { FindField(((object)asset).GetType(), "m_Version")?.SetValue(asset, "1.1.0"); } catch { } } private static FieldInfo FindField(Type type, string name) { while (type != null) { FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field; } type = type.BaseType; } return null; } } internal sealed class EmoteSource { public string Name; public bool Gif; public int Priority; public Func Load; } internal static class EmoteSources { private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.Emotes"); private const string TwemojiPrefix = "BarrkUI.EmojiAssets.twemoji."; private const string AnimPrefix = "BarrkUI.EmojiAssets.anim."; private const string MapResource = "BarrkUI.EmojiAssets.emojimap.txt"; public static List Gather() { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); if (ConfigManager.embeddedEmoji == null || ConfigManager.embeddedEmoji.Value) { AddEmbedded(dictionary); } AddLocalPacks(dictionary); AddServer(dictionary); return new List(dictionary.Values); } private static void Add(Dictionary byName, EmoteSource source) { if (!byName.TryGetValue(source.Name, out var value) || value.Priority < source.Priority) { byName[source.Name] = source; } } private static void AddEmbedded(Dictionary byName) { try { Assembly assembly = typeof(EmoteSources).Assembly; Dictionary dictionary = ReadMap(assembly); HashSet hashSet = new HashSet(assembly.GetManifestResourceNames(), StringComparer.Ordinal); if (!hashSet.Contains("BarrkUI.EmojiAssets.emojimap.txt")) { Diagnostics.Health("Embedded emoji", ok: false, "no embedded resource is named 'BarrkUI.EmojiAssets.emojimap.txt', so the built-in emoji library is empty. The resource names come from RootNamespace in the .csproj (still 'BarrkUI' by design) - if that was changed, EmoteSources' prefix constants must change with it."); return; } foreach (KeyValuePair item in dictionary) { string resource = "BarrkUI.EmojiAssets.twemoji." + item.Value + ".png"; if (hashSet.Contains(resource)) { Add(byName, new EmoteSource { Name = item.Key, Gif = false, Priority = 0, Load = () => ReadResource(assembly, resource) }); } } foreach (string item2 in hashSet) { if (item2.StartsWith("BarrkUI.EmojiAssets.anim.", StringComparison.Ordinal) && item2.EndsWith(".gif", StringComparison.Ordinal)) { string name = item2.Substring("BarrkUI.EmojiAssets.anim.".Length, item2.Length - "BarrkUI.EmojiAssets.anim.".Length - 4); string captured = item2; Add(byName, new EmoteSource { Name = name, Gif = true, Priority = 1, Load = () => ReadResource(assembly, captured) }); } } } catch (Exception arg) { Log.LogError((object)$"reading the embedded emoji library failed (non-fatal, embedded emojis unavailable). Reason: {arg}"); } } private static Dictionary ReadMap(Assembly assembly) { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); using Stream stream = assembly.GetManifestResourceStream("BarrkUI.EmojiAssets.emojimap.txt"); if (stream == null) { return dictionary; } using StreamReader streamReader = new StreamReader(stream); string text; while ((text = streamReader.ReadLine()) != null) { int num = text.IndexOf(' '); if (num > 0 && num < text.Length - 1) { dictionary[text.Substring(0, num)] = text.Substring(num + 1); } } return dictionary; } private static byte[] ReadResource(Assembly assembly, string name) { using Stream stream = assembly.GetManifestResourceStream(name); if (stream == null) { return null; } byte[] array = new byte[stream.Length]; int i; int num; for (i = 0; i < array.Length; i += num) { num = stream.Read(array, i, array.Length - i); if (num <= 0) { break; } } return (i == array.Length) ? array : null; } private static void AddLocalPacks(Dictionary byName) { try { string path = ModPaths.InConfigDir("emojipacks"); if (!Directory.Exists(path)) { return; } string[] files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories); foreach (string text in files) { string text2 = Path.GetExtension(text).ToLowerInvariant(); if (text2 != ".png" && text2 != ".gif") { continue; } string captured = text; Add(byName, new EmoteSource { Name = Path.GetFileNameWithoutExtension(text).ToLowerInvariant(), Gif = (text2 == ".gif"), Priority = 2, Load = delegate { try { return File.ReadAllBytes(captured); } catch { return (byte[])null; } } }); } } catch (Exception arg) { Log.LogError((object)$"scanning emojipacks failed (non-fatal, local packs unavailable). Reason: {arg}"); } } private static void AddServer(Dictionary byName) { foreach (BlobLibrary.Entry item in EmoteLibrary.Library.Entries()) { BlobLibrary.Entry captured = item; Add(byName, new EmoteSource { Name = item.Name, Gif = (item.Kind == BlobLibrary.BlobKind.Gif), Priority = 3, Load = () => EmoteLibrary.Library.TryReadBytes(captured) }); } } } internal static class ItemIconSprites { private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.ItemIcons"); private const int Cell = 48; private const int PageSize = 1024; private const string SpritePrefix = "buiitem_"; private static readonly Dictionary _markup = new Dictionary(); private static Texture2D _atlas; private static TMP_SpriteAsset _asset; private static int _cursorX; private static int _cursorY; private static bool _full; public static bool TryGetSpriteName(ItemShareEntry entry, out string spriteName) { spriteName = null; try { if (!RunMode.HasUI || (Object)(object)entry?.Icon == (Object)null) { return false; } string text = SpriteNameFor(entry); if (_markup.TryGetValue(text, out var value)) { spriteName = value; EnsureAttached(); return value != null; } bool flag = Bake(text, entry.Icon); _markup[text] = (flag ? text : null); if (flag) { spriteName = text; EnsureAttached(); } return flag; } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed (non-fatal, share line falls back to text). Reason: {1}", "TryGetSpriteName", arg)); return false; } } private static string SpriteNameFor(ItemShareEntry entry) { StringBuilder stringBuilder = new StringBuilder("buiitem_", "buiitem_".Length + entry.PrefabName.Length + 4); string prefabName = entry.PrefabName; foreach (char c in prefabName) { stringBuilder.Append(char.IsLetterOrDigit(c) ? char.ToLowerInvariant(c) : '_'); } stringBuilder.Append('_').Append(entry.Variant); return stringBuilder.ToString(); } private static bool Bake(string name, Sprite icon) { //IL_007e: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: 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_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Expected O, but got Unknown //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_021f: Unknown result type (might be due to invalid IL or missing references) //IL_022f: Expected O, but got Unknown if (_full) { return false; } Texture2D texture = icon.texture; if ((Object)(object)texture == (Object)null) { return false; } EnsureAtlas(); if (_cursorY + 48 > 1024) { _full = true; Log.LogWarning((object)$"item icon page is full after {_markup.Count} icons - further shares show as text only this session."); return false; } int cx = _cursorX; int cy = _cursorY; Rect textureRect = icon.textureRect; RenderTexture temporary = RenderTexture.GetTemporary(48, 48, 0, (RenderTextureFormat)0); RenderTexture active = RenderTexture.active; try { GL.Clear(false, true, Color.clear); Graphics.Blit((Texture)(object)texture, temporary, new Vector2(((Rect)(ref textureRect)).width / (float)((Texture)texture).width, ((Rect)(ref textureRect)).height / (float)((Texture)texture).height), new Vector2(((Rect)(ref textureRect)).x / (float)((Texture)texture).width, ((Rect)(ref textureRect)).y / (float)((Texture)texture).height)); RenderTexture.active = temporary; _atlas.ReadPixels(new Rect(0f, 0f, 48f, 48f), cx, 1024 - cy - 48, false); _atlas.Apply(false); } finally { RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); } _cursorX += 48; if (_cursorX + 48 > 1024) { _cursorX = 0; _cursorY += 48; } int count = _asset.spriteGlyphTable.Count; TMP_SpriteGlyph val = new TMP_SpriteGlyph { index = (uint)count, glyphRect = new GlyphRect(cx, 1024 - cy - 48, 48, 48), metrics = new GlyphMetrics(48f, 48f, 0f, 39.36f, 50f), scale = 1f }; _asset.spriteGlyphTable.Add(val); _asset.spriteCharacterTable.Add(new TMP_SpriteCharacter(65534u, val) { name = name, scale = 1f }); _asset.UpdateLookupTables(); Diagnostics.Trace(() => $"baked item icon \"{name}\" into atlas cell ({cx},{cy})."); return true; } private static void EnsureAtlas() { //IL_0027: 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_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Expected O, but got Unknown //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown if (!((Object)(object)_atlas != (Object)null) || !((Object)(object)_asset != (Object)null)) { _atlas = new Texture2D(1024, 1024, (TextureFormat)4, false) { name = "VikingOS_ItemIcons", filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1, hideFlags = (HideFlags)61 }; Color32[] pixels = (Color32[])(object)new Color32[1048576]; _atlas.SetPixels32(pixels); _atlas.Apply(false); _asset = ScriptableObject.CreateInstance(); ((Object)_asset).name = "VikingOS_ItemIcons"; _asset.spriteSheet = (Texture)(object)_atlas; ((Object)_asset).hideFlags = (HideFlags)61; Shader val = Shader.Find("TextMeshPro/Sprite"); ((TMP_Asset)_asset).material = new Material(((Object)(object)val != (Object)null) ? val : Shader.Find("Sprites/Default")) { mainTexture = (Texture)(object)_atlas }; TrySetFaceInfo(_asset); } } public static void EnsureAttached() { if ((Object)(object)_asset == (Object)null) { return; } Chat instance = Chat.instance; if ((Object)(object)instance == (Object)null || (Object)(object)((Terminal)instance).m_output == (Object)null) { return; } TMP_SpriteAsset spriteAsset = ((TMP_Text)((Terminal)instance).m_output).spriteAsset; if ((Object)(object)spriteAsset == (Object)null) { ((TMP_Text)((Terminal)instance).m_output).spriteAsset = _asset; ((Graphic)((Terminal)instance).m_output).SetAllDirty(); } else if (spriteAsset != _asset) { spriteAsset.fallbackSpriteAssets = spriteAsset.fallbackSpriteAssets ?? new List(); if (!spriteAsset.fallbackSpriteAssets.Contains(_asset)) { spriteAsset.fallbackSpriteAssets.Add(_asset); ((Graphic)((Terminal)instance).m_output).SetAllDirty(); } } } public static void Clear() { if ((Object)(object)_asset != (Object)null) { Object.Destroy((Object)(object)_asset); } if ((Object)(object)_atlas != (Object)null) { Object.Destroy((Object)(object)_atlas); } _asset = null; _atlas = null; _markup.Clear(); _cursorX = 0; _cursorY = 0; _full = false; } private static void TrySetFaceInfo(TMP_SpriteAsset asset) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) try { FieldInfo fieldInfo = null; Type type = ((object)asset).GetType(); while (type != null && fieldInfo == null) { fieldInfo = type.GetField("m_FaceInfo", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); type = type.BaseType; } if (fieldInfo == null) { return; } FieldInfo fieldInfo2 = fieldInfo; FaceInfo val = default(FaceInfo); ((FaceInfo)(ref val)).pointSize = 48f; ((FaceInfo)(ref val)).scale = 1f; ((FaceInfo)(ref val)).lineHeight = 52.800003f; ((FaceInfo)(ref val)).ascentLine = 39.36f; ((FaceInfo)(ref val)).descentLine = -8.64f; fieldInfo2.SetValue(asset, val); Type type2 = ((object)asset).GetType(); while (type2 != null) { FieldInfo field = type2.GetField("m_Version", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { field.SetValue(asset, "1.1.0"); break; } type2 = type2.BaseType; } } catch (Exception ex) { Log.LogWarning((object)("could not set the item icon face info - icons may render oversized. Reason: " + ex.Message)); } } } internal sealed class ItemShareEntry { public long SenderId; public string PrefabName; public int Quality; public int Variant; public float Durability; public string CrafterName; public string DisplayName; public string TooltipText; public Sprite Icon; } internal static class ItemShareCache { private const int MaxEntries = 300; private static readonly Dictionary _entries = new Dictionary(); private static readonly Queue _order = new Queue(); public static int Count => _entries.Count; public static void Add(string shareId, ItemShareEntry entry) { if (_entries.ContainsKey(shareId)) { _entries[shareId] = entry; return; } _entries[shareId] = entry; _order.Enqueue(shareId); while (_order.Count > 300) { string key = _order.Dequeue(); _entries.Remove(key); } } public static bool TryGet(string shareId, out ItemShareEntry entry) { return _entries.TryGetValue(shareId, out entry); } public static void Clear() { _entries.Clear(); _order.Clear(); } } internal static class ItemShareProtocol { private static readonly char SentinelStart = '\ue000'; private static readonly char SentinelEnd = '\ue001'; private static readonly char EscapedOpen = '\ue002'; private static readonly char EscapedClose = '\ue003'; private static readonly Regex SentinelPattern = new Regex("\ue000([A-Za-z0-9-]+)\ue001", RegexOptions.Compiled); public const string LinkIdPrefix = "VikingOS_item:"; private static readonly Regex EscapedTagPattern = new Regex("\ue002[^\ue003]*\ue003", RegexOptions.Compiled); public static string Wrap(string shareId) { return $"{SentinelStart}{shareId}{SentinelEnd}"; } public static bool ContainsShare(string text) { if (text != null) { return text.IndexOf(SentinelStart) >= 0; } return false; } public static string ResolveLinks(string text, long senderId) { if (!ContainsShare(text)) { return text; } return SentinelPattern.Replace(text, delegate(Match match) { string shareId = match.Groups[1].Value; if (!TryGetOriginId(shareId, out var originId)) { Diagnostics.Trace(() => "share \"" + shareId + "\" rejected: id carries no parseable origin."); return "[shared item]"; } if (originId != senderId) { Diagnostics.Trace(() => $"share \"{shareId}\" rejected: minted by {originId:x} but the message came from {senderId:x} (replayed or spoofed)."); return "[shared item]"; } if (ItemShareCache.TryGet(shareId, out var entry) && entry.DisplayName != null) { Diagnostics.Trace(() => "share \"" + shareId + "\" resolved to \"" + entry.DisplayName + "\" (" + entry.PrefabName + ")."); string spriteName; string text2 = (ItemIconSprites.TryGetSpriteName(entry, out spriteName) ? $"{EscapedOpen}sprite name=\"{spriteName}\"{EscapedClose}" : "✦"); return string.Format("{0}link=\"{1}{2}\"{3}", EscapedOpen, "VikingOS_item:", shareId, EscapedClose) + $"{text2} {entry.DisplayName}{EscapedOpen}/link{EscapedClose}"; } Diagnostics.Trace(() => "share \"" + shareId + "\" has no cache entry - message did not arrive via VikingOS_ChatItem."); return "[shared item]"; }); } private static bool NeedsOutputPass(string text) { if (text != null) { if (text.IndexOf(EscapedOpen) < 0) { return text.IndexOf(SentinelStart) >= 0; } return true; } return false; } public static string ForChatLog(string text) { if (!NeedsOutputPass(text)) { return text; } text = SentinelPattern.Replace(text, "[shared item]"); return text.Replace(EscapedOpen, '<').Replace(EscapedClose, '>'); } public static string ForWorldText(string text) { if (!NeedsOutputPass(text)) { return text; } text = SentinelPattern.Replace(text, "[shared item]"); return EscapedTagPattern.Replace(text, string.Empty); } public static bool TryGetOriginId(string shareId, out long originId) { originId = 0L; if (string.IsNullOrEmpty(shareId)) { return false; } int num = shareId.IndexOf('-'); if (num <= 0) { return false; } return long.TryParse(shareId.Substring(0, num), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out originId); } public static bool TryGetShareIdFromLinkId(string linkId, out string shareId) { if (linkId != null && linkId.StartsWith("VikingOS_item:")) { shareId = linkId.Substring("VikingOS_item:".Length); return true; } shareId = null; return false; } } internal static class ItemShareRpc { [HarmonyPatch] internal static class RegisterPatch { [HarmonyPatch(typeof(Chat), "Awake")] [HarmonyPostfix] private static void Chat_Awake_Postfix() { try { if (ZRoutedRpc.instance == null) { Diagnostics.Health("Item sharing", ok: false, "Chat.Awake ran with no ZRoutedRpc, so the RPC could not be registered. Sharing is disabled for this session."); return; } ZRoutedRpc.instance.Register("VikingOS_ChatItem", (Method)RPC_ChatItem); Diagnostics.Health("Item sharing", ok: true, "VikingOS_ChatItem registered for this session"); } catch (Exception ex) { Diagnostics.Health("Item sharing", ok: false, "registering VikingOS_ChatItem threw, so sharing is disabled for this session. Reason: " + ex.Message); Log.LogError((object)ex.ToString()); } } } private const string RpcName = "VikingOS_ChatItem"; private const int PayloadVersion = 1; private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.ItemShareRpc"); private static long _counter; public static bool Send(ItemData item, Type type) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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_0084: 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) //IL_018f: Unknown result type (might be due to invalid IL or missing references) //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Expected I4, but got Unknown //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Expected O, but got Unknown try { if (item?.m_shared == null || (Object)(object)item.m_dropPrefab == (Object)null) { Log.LogWarning((object)"Send: item has no m_shared/m_dropPrefab, refusing to share an item with nothing to identify it by."); return false; } if ((Object)(object)ZNet.instance == (Object)null || ZRoutedRpc.instance == null || (Object)(object)Player.m_localPlayer == (Object)null) { return false; } ZDOID localPlayerCharacterID = ZNet.instance.LocalPlayerCharacterID; if (localPlayerCharacterID == ZDOID.None) { return false; } long userID = ((ZDOID)(ref localPlayerCharacterID)).UserID; string prefabName = ((Object)item.m_dropPrefab).name; string shareId = $"{userID:x}-{++_counter:x}"; ItemShareCache.Add(shareId, BuildEntry(userID, prefabName, item.m_quality, item.m_variant, item.m_durability, item.m_crafterName)); ZPackage payload = WritePayload(shareId, prefabName, item.m_quality, item.m_variant, item.m_durability, item.m_crafterName ?? string.Empty); string text = "shared " + ItemShareProtocol.Wrap(shareId); Vector3 pos = ((Character)Player.m_localPlayer).GetHeadPoint(); int channel = (int)type; Diagnostics.Trace(() => $"sending share \"{shareId}\": {prefabName} q{item.m_quality} v{item.m_variant} " + $"dur{item.m_durability:F1} as {type}, payload {payload.Size()} bytes."); int recipients = 0; Chat.CheckPermissionsAndSendChatMessageRPCsAsync((SendChatMessageRPCHandler)delegate(long user, bool filterText) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) UserInfo val = default(UserInfo); string text2 = default(string); Chat.GetChatMessageData(text, filterText, ref val, ref text2); ZRoutedRpc.instance.InvokeRoutedRPC(user, "VikingOS_ChatItem", new object[5] { pos, channel, val, text2, payload }); recipients++; Diagnostics.Trace(() => $"share \"{shareId}\" dispatched to {user:x} (recipient {recipients}, filtered={filterText})."); }); return true; } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed - item not shared. Reason: {1}", "Send", arg)); return false; } } private static void RPC_ChatItem(long sender, Vector3 pos, int type, UserInfo user, string text, ZPackage payload) { //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) //IL_0032: 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) //IL_005f: Unknown result type (might be due to invalid IL or missing references) try { if ((Object)(object)Chat.instance == (Object)null) { return; } ReadPayload(sender, payload); Type channel = (Type)type; if (!InSpeakingRange(pos, channel)) { Diagnostics.Trace(() => $"share message from {sender:x} cached but not displayed: out of {channel} range."); } else { Chat.instance.OnNewChatMessage((GameObject)null, sender, pos, channel, user, text); } } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed for sender={1}. Reason: {2}", "RPC_ChatItem", sender, arg)); } } private static bool InSpeakingRange(Vector3 pos, Type type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_002d: Unknown result type (might be due to invalid IL or missing references) //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 ((int)type == 2 || (int)type == 3) { return true; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return false; } Talker component = ((Component)localPlayer).GetComponent(); if ((Object)(object)component == (Object)null) { return true; } float num = (((int)type == 0) ? component.m_visperDistance : component.m_normalDistance); return Vector3.Distance(((Component)localPlayer).transform.position, pos) < num; } private static ZPackage WritePayload(string shareId, string prefabName, int quality, int variant, float durability, string crafterName) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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_0028: 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_0037: 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_0050: Expected O, but got Unknown ZPackage val = new ZPackage(); val.Write(1); val.Write(1); val.Write(shareId); val.Write(prefabName); val.Write(quality); val.Write(variant); val.Write(durability); val.Write(crafterName ?? string.Empty); val.SetPos(0); return val; } private static void ReadPayload(long sender, ZPackage payload) { if (payload == null) { return; } int num = payload.ReadInt(); if (num != 1) { Log.LogWarning((object)$"Ignoring item share payload version {num} from {sender} (this build speaks {1})."); return; } int num2 = payload.ReadInt(); for (int i = 0; i < num2; i++) { string shareId = payload.ReadString(); string prefabName = payload.ReadString(); int quality = payload.ReadInt(); int variant = payload.ReadInt(); float durability = payload.ReadSingle(); string crafterName = payload.ReadString(); if (!ItemShareProtocol.TryGetOriginId(shareId, out var originId) || originId != sender) { Log.LogWarning((object)$"Dropping item share \"{shareId}\" from {sender}: id does not belong to that sender."); continue; } ItemShareEntry entry = BuildEntry(sender, prefabName, quality, variant, durability, crafterName); ItemShareCache.Add(shareId, entry); Diagnostics.Trace(() => $"received share \"{shareId}\" from {sender:x}: {prefabName} q{quality} v{variant} " + "-> \"" + entry.DisplayName + "\", icon=" + (((Object)(object)entry.Icon != (Object)null) ? "yes" : "no") + ", tooltip=" + ((entry.TooltipText != null) ? (entry.TooltipText.Length + " chars") : "none") + ". " + $"Cache now holds {ItemShareCache.Count}."); } } private static ItemShareEntry BuildEntry(long sender, string prefabName, int quality, int variant, float durability, string crafterName) { ItemShareEntry itemShareEntry = new ItemShareEntry { SenderId = sender, PrefabName = (prefabName ?? "unknown"), Quality = quality, Variant = variant, Durability = durability, CrafterName = (crafterName ?? string.Empty), DisplayName = (prefabName ?? "unknown"), TooltipText = null, Icon = null }; if (string.IsNullOrEmpty(prefabName) || (Object)(object)ObjectDB.instance == (Object)null) { return itemShareEntry; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(prefabName); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent() : null); if ((Object)(object)val == (Object)null || val.m_itemData?.m_shared == null) { Log.LogWarning((object)("BuildEntry: prefab \"" + prefabName + "\" not found in this client's ObjectDB (different mod list?) - falling back to the raw prefab name for display.")); return itemShareEntry; } ItemData val2 = val.m_itemData.Clone(); val2.m_quality = Mathf.Max(1, quality); val2.m_variant = ClampVariant(variant, val2.m_shared); val2.m_durability = durability; val2.m_crafterName = crafterName ?? string.Empty; val2.m_dropPrefab = itemPrefab; val2.m_worldLevel = Game.m_worldLevel; itemShareEntry.Variant = val2.m_variant; itemShareEntry.DisplayName = ((Localization.instance != null) ? Localization.instance.Localize(val2.m_shared.m_name) : val2.m_shared.m_name); string tooltip = val2.GetTooltip(-1); itemShareEntry.TooltipText = ((Localization.instance != null) ? Localization.instance.Localize(tooltip) : tooltip); itemShareEntry.Icon = val2.GetIcon(); return itemShareEntry; } private static int ClampVariant(int variant, SharedData shared) { Sprite[] icons = shared.m_icons; int num = ((icons != null) ? icons.Length : 0); if (num == 0) { return 0; } return Mathf.Clamp(variant, 0, num - 1); } } internal static class PlayerPicker { private const int MaxRows = 12; private static bool _open; private static string _title = string.Empty; private static Action _onPick; private static Vector2 _scroll; private static Rect _rect; public static Rect PanelRect { get { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (!_open) { return new Rect(0f, 0f, 0f, 0f); } return _rect; } } public static bool IsOpen => _open; public static void Open(string title, Action onPick) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) _open = true; _title = title ?? string.Empty; _onPick = onPick; _scroll = Vector2.zero; } public static void Close() { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) _open = false; _onPick = null; _rect = new Rect(0f, 0f, 0f, 0f); } public static void Toggle(string title, Action onPick) { if (_open && string.Equals(_title, title, StringComparison.Ordinal)) { Close(); } else { Open(title, onPick); } } public static void Draw(Rect anchor) { //IL_0119: 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) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) if (!_open) { return; } List> list = new List>(WhisperRpc.OnlinePlayers()); float num = GiltFrameTheme.S(34f); float num2 = 26f; float num3 = GiltFrameTheme.S(26f); float num4 = (float)Mathf.Clamp(list.Count, 1, 12) * (num + 3f) + 8f; float num5 = num2 * 2f + num3 + GiltFrameTheme.S(6f) + num4; float num6 = Mathf.Clamp(((Rect)(ref anchor)).width, GiltFrameTheme.S(320f), Mathf.Max(GiltFrameTheme.S(320f), (float)Screen.width * 0.34f)); float num7 = ((Rect)(ref anchor)).y - num5 - GiltFrameTheme.S(6f); if (num7 < 0f) { num7 = ((Rect)(ref anchor)).yMax + GiltFrameTheme.S(6f); } float num8 = Mathf.Clamp(((Rect)(ref anchor)).x, 0f, Mathf.Max(0f, (float)Screen.width - num6)); _rect = new Rect(num8, Mathf.Clamp(num7, 0f, Mathf.Max(0f, (float)Screen.height - num5)), num6, num5); GiltFrameTheme.DrawPanelFill(_rect); GiltFrameTheme.DrawFrame(_rect); float num9 = ((Rect)(ref _rect)).x + num2; float num10 = ((Rect)(ref _rect)).y + num2; float num11 = ((Rect)(ref _rect)).width - num2 * 2f; string text = ((list.Count > 0) ? $"{_title} ({list.Count})" : _title); GiltFrameTheme.DrawShadowed(new Rect(num9, num10, num11, num3), text, GiltFrameTheme.Header); num10 += num3 + GiltFrameTheme.S(6f); if (list.Count == 0) { GUI.Label(new Rect(num9, num10, num11, num4), "Nobody else is on this server right now.", GiltFrameTheme.Note); return; } GUILayout.BeginArea(new Rect(num9, num10, num11, num4)); _scroll = GUILayout.BeginScrollView(_scroll, Array.Empty()); for (int i = 0; i < list.Count; i++) { if (GUILayout.Button(list[i].Key, GiltFrameTheme.Row, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(num) })) { KeyValuePair keyValuePair = list[i]; Action onPick = _onPick; Close(); onPick?.Invoke(keyValuePair.Key, keyValuePair.Value); break; } } GUILayout.EndScrollView(); GUILayout.EndArea(); } } internal static class WhisperRpc { [HarmonyPatch] internal static class RegisterPatch { [HarmonyPatch(typeof(Chat), "Awake")] [HarmonyPostfix] private static void Chat_Awake_Postfix() { try { if (ZRoutedRpc.instance == null) { Diagnostics.Health("Whisper", ok: false, "Chat.Awake ran with no ZRoutedRpc, so the whisper RPC could not be registered. Whispers are disabled for this session."); return; } ZRoutedRpc.instance.Register("VikingOS_Whisper", (Action)RPC_Whisper); Diagnostics.Health("Whisper", ok: true, "VikingOS_Whisper registered for this session"); } catch (Exception ex) { Diagnostics.Health("Whisper", ok: false, "registering VikingOS_Whisper threw, so whispers are disabled for this session. Reason: " + ex.Message); Log.LogError((object)ex.ToString()); } } } internal static class ForTesting { public static string LastReceivedText = string.Empty; public static long LastReceivedFrom; public static int ReceivedCount; public static long ReplyTargetId => _lastFromId; public static string ReplyTargetName => _lastFromName; public static void Forget() { LastReceivedText = string.Empty; LastReceivedFrom = 0L; ReceivedCount = 0; } } private const string RpcName = "VikingOS_Whisper"; private const string Colour = "#E39BFF"; private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.Whisper"); private static long _lastFromId; private static string _lastFromName; public const string Usage = "/w · /r replies to the last whisper you got"; public static bool CanReply { get { if (_lastFromId != 0L) { return !string.IsNullOrEmpty(_lastFromName); } return false; } } public static string LastFromName => _lastFromName; public static void ResetSession() { _lastFromId = 0L; _lastFromName = null; } public static bool TryHandleVerb(string verb, string rest) { switch (verb) { case "w": case "whisper": case "msg": case "tell": SendToTypedName(rest); return true; case "r": case "reply": Reply(rest); return true; default: return false; } } private static void SendToTypedName(string rest) { string name; long uid; string text; if (string.IsNullOrEmpty(rest)) { Notice("Usage: /w · /r replies to the last whisper you got."); } else if (!TryMatchName(rest, out name, out uid, out text)) { string text2 = rest.Split(new char[1] { ' ' })[0]; Notice("No player called \"" + text2 + "\" is online. Whisper reaches players on this server only."); } else if (string.IsNullOrWhiteSpace(text)) { Notice("Say something to " + name + "."); } else { Send(uid, name, text); } } private static void Reply(string text) { if (!CanReply) { Notice("Nobody has whispered you yet, so there is nobody to reply to."); } else if (string.IsNullOrWhiteSpace(text)) { Notice("Usage: /r · replies to " + _lastFromName + "."); } else { Send(_lastFromId, _lastFromName, text); } } public static void Send(long targetUid, string targetName, string text) { try { if (ZRoutedRpc.instance == null || (Object)(object)Player.m_localPlayer == (Object)null) { return; } if (targetUid == 0L) { Notice("That player cannot be reached."); return; } string playerName = Player.m_localPlayer.GetPlayerName(); ZRoutedRpc.instance.InvokeRoutedRPC(targetUid, "VikingOS_Whisper", new object[2] { playerName, text }); Show("[you → " + targetName + "]", text); Diagnostics.Trace(() => $"whisper -> {targetName} ({targetUid:x}): {text.Length} chars."); } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed - whisper not sent. Reason: {1}", "Send", arg)); Notice("That whisper could not be sent."); } } private static void RPC_Whisper(long sender, string fromName, string text) { try { if ((Object)(object)Chat.instance == (Object)null) { return; } string text2 = Sanitise(fromName, 32); string safeText = Sanitise(text, 500); if (!string.IsNullOrEmpty(safeText)) { _lastFromId = sender; _lastFromName = (string.IsNullOrEmpty(text2) ? "someone" : text2); ForTesting.LastReceivedText = safeText; ForTesting.LastReceivedFrom = sender; ForTesting.ReceivedCount++; Show("[" + _lastFromName + " → you]", safeText); Diagnostics.Trace(() => $"whisper <- {_lastFromName} ({sender:x}): {safeText.Length} chars."); } } catch (Exception arg) { Log.LogError((object)string.Format("{0} failed for sender={1}. Reason: {2}", "RPC_Whisper", sender, arg)); } } private static string Sanitise(string value, int maxLength) { if (string.IsNullOrEmpty(value)) { return string.Empty; } string text = value.Replace('<', ' ').Replace('>', ' ').Trim(); if (text.Length <= maxLength) { return text; } return text.Substring(0, maxLength); } private static void Show(string tag, string text) { Chat instance = Chat.instance; if (!((Object)(object)instance == (Object)null)) { ((Terminal)instance).AddString("" + tag + " " + text); instance.m_hideTimer = 0f; } } private static void Notice(string text) { Chat instance = Chat.instance; if (!((Object)(object)instance == (Object)null)) { ((Terminal)instance).AddString("" + text + ""); instance.m_hideTimer = 0f; } } private static bool TryMatchName(string rest, out string name, out long uid, out string text) { name = null; uid = 0L; text = null; int num = -1; foreach (KeyValuePair item in OnlinePlayers()) { if (item.Key.Length > num && rest.StartsWith(item.Key, StringComparison.OrdinalIgnoreCase)) { num = item.Key.Length; name = item.Key; uid = item.Value; text = rest.Substring(item.Key.Length).Trim(); } } return num >= 0; } public static IEnumerable> OnlinePlayers() { if ((Object)(object)ZNet.instance == (Object)null) { yield break; } ZDOID self = ZNet.instance.LocalPlayerCharacterID; foreach (PlayerInfo player in ZNet.instance.GetPlayerList()) { if (!(player.m_characterID == ZDOID.None) && !(player.m_characterID == self) && !string.IsNullOrEmpty(player.m_name)) { string name = player.m_name; ZDOID characterID = player.m_characterID; yield return new KeyValuePair(name, ((ZDOID)(ref characterID)).UserID); } } } } internal static class WhisperTest { private static readonly ManualLogSource Log = Logger.CreateLogSource("VikingOS.WhisperTest"); private const string Hostile = "hello BIG world"; public static void Run(ConsoleEventArgs args) { TestReport testReport = new TestReport(args.Context); if ((Object)(object)Player.m_localPlayer == (Object)null || (Object)(object)ZNet.instance == (Object)null || ZRoutedRpc.instance == null) { testReport.Line("vikingos_whispertest: not in a world yet (" + SessionState.Describe() + ")."); return; } if (!ChatFeatures.Enabled) { testReport.Line("vikingos_whispertest: VikingOS chat is switched off on this server, so whisper is not installed."); return; } try { long uID = ZNet.GetUID(); string playerName = Player.m_localPlayer.GetPlayerName(); testReport.Line($"whispertest: whispering yourself ({playerName}, {uID:x}). A routed RPC aimed at your"); testReport.Line(" own uid is handled in process, so the whole path runs for real."); long num = TranscriptLength(); WhisperRpc.ForTesting.Forget(); WhisperRpc.Send(uID, playerName, "hello BIG world"); testReport.Check(WhisperRpc.ForTesting.ReceivedCount == 1, $"the whisper came back round to the receiving handler (got {WhisperRpc.ForTesting.ReceivedCount})"); testReport.Check(WhisperRpc.ForTesting.LastReceivedFrom == uID, "it arrived attributed to you, which is the uid a reply will aim at"); string text = WhisperRpc.ForTesting.LastReceivedText ?? string.Empty; testReport.Check(text.IndexOf('<') < 0 && text.IndexOf('>') < 0, "the markup was STRIPPED - a peer cannot reformat your chat window through a whisper"); if (text.IndexOf('<') >= 0 || text.IndexOf('>') >= 0) { testReport.Line(" received: " + text); } testReport.Check(text.Contains("hello") && text.Contains("world"), "the actual words survived - the sanitiser took the markup and nothing else"); testReport.Check(WhisperRpc.CanReply, "/r is now live, so a whisper you receive is answerable"); testReport.Check(WhisperRpc.ForTesting.ReplyTargetId == uID, $"/r would answer {WhisperRpc.ForTesting.ReplyTargetName} ({WhisperRpc.ForTesting.ReplyTargetId:x})"); long num2 = TranscriptLength(); testReport.Check(num2 == num, "NOTHING was written to the chat transcript (" + Path.GetFileName(TranscriptPath()) + " " + $"unchanged at {num2} bytes)"); testReport.Line(" Check the chat window: one [you -> name] line and one [name -> you] line,"); testReport.Line(" both violet, with the markup showing as plain text."); } catch (Exception ex) { testReport.Fail("the test threw: " + ex.Message); Log.LogError((object)ex.ToString()); } testReport.Summary(); } private static string TranscriptPath() { return ModPaths.InConfigDir(Path.Combine("Chats", $"chat-{DateTime.Now:yyyy-MM-dd}.log")); } private static long TranscriptLength() { try { string text = TranscriptPath(); return File.Exists(text) ? new FileInfo(text).Length : 0; } catch (Exception ex) { Log.LogWarning((object)("could not measure the transcript: " + ex.Message)); return -1L; } } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } }