Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ZariRules v1.3.2
BepInEx/plugins/ZariRules/ZariRules.dll
Decompiled 2 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using Splatform; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("ZariRules")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.3.2.0")] [assembly: AssemblyInformationalVersion("1.3.2")] [assembly: AssemblyProduct("ZariRules")] [assembly: AssemblyTitle("ZariRules")] [assembly: AssemblyVersion("1.3.2.0")] 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; } } } namespace ZariRules { internal static class CompatibilityProbe { internal const string EaqsGuid = "randyknapp.mods.equipmentandquickslots"; internal const string EpicLootGuid = "randyknapp.mods.epicloot"; internal static bool VerifyGameBuild(out string reason) { Guid moduleVersionId = typeof(Player).Assembly.ManifestModule.ModuleVersionId; if (!GameBuildContracts.IsSupported(moduleVersionId)) { reason = $"unsupported assembly_valheim MVID {moduleVersionId}; expected verified Valheim 1.0.12 or 1.0.7 Windows/Linux build"; return false; } reason = string.Empty; return true; } internal static bool VerifyMethod(Type type, string name, BindingFlags flags, Type returnType, Type[] parameters, string expectedIlSha256, out MethodInfo? method, out string reason) { method = type.GetMethod(name, flags, null, parameters, null); if (method == null || method.ReturnType != returnType) { reason = "missing or changed " + type.FullName + "." + name + "(" + string.Join(",", parameters.Select((Type x) => x.FullName)) + ")"; return false; } byte[] array = method.GetMethodBody()?.GetILAsByteArray(); if (array == null) { reason = "no IL body for " + type.FullName + "." + name; return false; } using SHA256 sHA = SHA256.Create(); string text = BitConverter.ToString(sHA.ComputeHash(array)).Replace("-", string.Empty).ToLowerInvariant(); string b = GameBuildContracts.ExpectedIlHash(type.Assembly.ManifestModule.ModuleVersionId, expectedIlSha256); if (!string.Equals(text, b, StringComparison.Ordinal)) { reason = "IL contract mismatch for " + type.FullName + "." + name + ": " + text; return false; } reason = string.Empty; return true; } internal static bool VerifyEaqs(out bool installed, out string reason) { installed = Chainloader.PluginInfos.TryGetValue("randyknapp.mods.equipmentandquickslots", out var value); if (!installed) { reason = "EAQS absent; base-inventory mode"; return true; } string text = value.Metadata.Version.ToString(); reason = "EAQS " + text + "; game death contracts and patch owners checked separately"; return true; } internal static string InstalledPluginVersion(string guid) { if (!Chainloader.PluginInfos.TryGetValue(guid, out var value)) { return "absent"; } return value.Metadata.Version.ToString(); } internal static bool HasOnlyAllowedPatchOwners(MethodBase method, IReadOnlyCollection<string> allowed, out string reason) { Patches patchInfo = Harmony.GetPatchInfo(method); if (patchInfo == null) { reason = string.Empty; return true; } string[] array = patchInfo.Owners.Where((string owner) => !allowed.Contains(owner)).Distinct<string>(StringComparer.Ordinal).OrderBy<string, string>((string owner) => owner, StringComparer.Ordinal) .ToArray(); if (array.Length == 0) { reason = string.Empty; return true; } reason = "unexpected Harmony owner(s) on " + method.DeclaringType?.FullName + "." + method.Name + ": " + string.Join(",", array); return false; } } internal static class DeathContext { internal const string HarmonyId = "zari.rules.death-context"; private static readonly DeathScopeTracker<Player> Scopes = new DeathScopeTracker<Player>(); private static Harmony? harmony; internal static bool Ready { get; private set; } internal static bool Install(out string reason) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0051: 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_0062: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Expected O, but got Unknown if (!CompatibilityProbe.VerifyMethod(typeof(Player), "OnDeath", BindingFlags.Instance | BindingFlags.Public, typeof(void), Type.EmptyTypes, "76b17b9f1894281bde973d01f97a8f330b955e275d4556ceea1ead4ed56f2c21", out MethodInfo method, out reason)) { return false; } try { harmony = new Harmony("zari.rules.death-context"); HarmonyMethod val = new HarmonyMethod(typeof(DeathContext), "Prefix", (Type[])null) { priority = 800 }; HarmonyMethod val2 = new HarmonyMethod(typeof(DeathContext), "Finalizer", (Type[])null); val2.priority = 0; val2.after = new string[1] { "randyknapp.mods.equipmentandquickslots" }; HarmonyMethod val3 = val2; harmony.Patch((MethodBase)method, val, (HarmonyMethod)null, (HarmonyMethod)null, val3, (HarmonyMethod)null); Ready = true; reason = "Player.OnDeath scope"; return true; } catch (Exception ex) { Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } reason = ex.GetType().Name + ": " + ex.Message; return false; } } internal static bool TryGet(Player player, out DeathScopeTracker<Player>.Scope? scope) { return Scopes.TryGetCurrent(player, out scope); } internal static void Reset() { Scopes.Clear(); } internal static void Uninstall() { Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } Ready = false; Reset(); } private static void Prefix(Player __instance, out DeathScopeTracker<Player>.Scope? __state) { __state = null; if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !ZariRulesPlugin.Instance.Rules.IsServerConfigurationReady) { return; } __state = Scopes.Open(__instance, ZariRulesPlugin.Instance.Rules.KeepInventoryOnDeath.Value, ZariRulesPlugin.Instance.Rules.KeepSkillsOnDeath.Value); try { Diagnostics.OnDeathStarted(__instance); } catch (Exception ex) { ZariRulesPlugin.LogError("ZR901", "feature=Diagnostics phase=death-start reason=" + ex.GetType().Name); } } private static Exception? Finalizer(Player __instance, Exception? __exception, DeathScopeTracker<Player>.Scope? __state) { if (__state != null) { try { Diagnostics.OnDeathFinished(__instance, __state, __exception == null); } catch (Exception ex) { ZariRulesPlugin.LogError("ZR901", "feature=Diagnostics phase=death-finish reason=" + ex.GetType().Name); } finally { try { Scopes.Close(__instance, __state); } catch (Exception ex2) { ZariRulesPlugin.LogError("ZR901", "feature=DeathContext phase=close reason=" + ex2.GetType().Name); } } } return __exception; } } internal static class DeathInventoryFeature { internal const string HarmonyId = "zari.rules.keep-inventory"; private static Harmony? harmony; internal static bool Ready { get; private set; } internal static bool Install(out string reason) { //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Expected O, but got Unknown //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Expected O, but got Unknown if (!DeathContext.Ready) { reason = "death context unavailable"; return false; } if (!CompatibilityProbe.VerifyEaqs(out bool installed, out string reason2)) { reason = reason2; return false; } if (!CompatibilityProbe.VerifyMethod(typeof(Player), "CreateTombStone", BindingFlags.Instance | BindingFlags.Public, typeof(void), Type.EmptyTypes, "00f13b0d81783d11221910d3b2090f27918f53957ea98b114af49d151dacbd98", out MethodInfo method, out reason) || !CompatibilityProbe.VerifyMethod(typeof(Player), "OnDeath", BindingFlags.Instance | BindingFlags.Public, typeof(void), Type.EmptyTypes, "76b17b9f1894281bde973d01f97a8f330b955e275d4556ceea1ead4ed56f2c21", out MethodInfo method2, out reason) || !CompatibilityProbe.VerifyMethod(typeof(Character), "CheckDeath", BindingFlags.Instance | BindingFlags.NonPublic, typeof(void), Type.EmptyTypes, "fef54e1a3e6de1ea05ab81ffd5346eaea2c503b00ccefcc342c4ae862caaa095", out MethodInfo method3, out reason)) { return false; } HashSet<string> allowed = new HashSet<string>(StringComparer.Ordinal) { "randyknapp.mods.equipmentandquickslots" }; HashSet<string> allowed2 = new HashSet<string>(StringComparer.Ordinal) { "randyknapp.mods.equipmentandquickslots", "zari.rules.death-context" }; if (!CompatibilityProbe.HasOnlyAllowedPatchOwners(method, allowed, out reason) || !CompatibilityProbe.HasOnlyAllowedPatchOwners(method2, allowed2, out reason) || !CompatibilityProbe.HasOnlyAllowedPatchOwners(method3, allowed, out reason)) { return false; } try { harmony = new Harmony("zari.rules.keep-inventory"); harmony.Patch((MethodBase)method, new HarmonyMethod(typeof(DeathInventoryFeature), "Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Ready = true; reason = $"K1 Player.CreateTombStone; {reason2}; eaqsInstalled={installed}"; return true; } catch (Exception ex) { Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } reason = ex.GetType().Name + ": " + ex.Message; return false; } } internal static void Uninstall() { Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } Ready = false; } internal static bool VerifyPatchOwners(out string reason) { if (CompatibilityProbe.HasOnlyAllowedPatchOwners(AccessTools.Method(typeof(Player), "CreateTombStone", (Type[])null, (Type[])null), (IReadOnlyCollection<string>)(object)new string[2] { "zari.rules.keep-inventory", "randyknapp.mods.equipmentandquickslots" }, out reason) && CompatibilityProbe.HasOnlyAllowedPatchOwners(AccessTools.Method(typeof(Player), "OnDeath", (Type[])null, (Type[])null), (IReadOnlyCollection<string>)(object)new string[3] { "zari.rules.death-context", "zari.rules.keep-skills", "randyknapp.mods.equipmentandquickslots" }, out reason)) { return CompatibilityProbe.HasOnlyAllowedPatchOwners(AccessTools.Method(typeof(Character), "CheckDeath", (Type[])null, (Type[])null), (IReadOnlyCollection<string>)(object)new string[2] { "zari.rules.diagnostics", "randyknapp.mods.equipmentandquickslots" }, out reason); } return false; } private static bool Prefix(Player __instance) { if (!Ready || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || !DeathContext.TryGet(__instance, out DeathScopeTracker<Player>.Scope scope) || scope == null || !scope.KeepInventory) { return true; } scope.TombstoneSuppressed = true; Diagnostics.Info("ZR202", "tombstoneBranch=suppressed transferredByZariRules=0"); return false; } } internal sealed class DeathScopeTracker<TKey> where TKey : class { internal sealed class Scope { internal bool KeepInventory { get; } internal bool KeepSkills { get; } internal bool TombstoneSuppressed { get; set; } internal Scope(bool keepInventory, bool keepSkills) { KeepInventory = keepInventory; KeepSkills = keepSkills; } } private readonly Dictionary<TKey, Stack<Scope>> scopes = new Dictionary<TKey, Stack<Scope>>(); internal Scope Open(TKey key, bool keepInventory, bool keepSkills) { if (!scopes.TryGetValue(key, out Stack<Scope> value)) { value = new Stack<Scope>(); scopes.Add(key, value); } Scope scope = new Scope(keepInventory, keepSkills); value.Push(scope); return scope; } internal bool TryGetCurrent(TKey key, out Scope? scope) { if (scopes.TryGetValue(key, out Stack<Scope> value) && value.Count > 0) { scope = value.Peek(); return true; } scope = null; return false; } internal void Close(TKey key, Scope scope) { if (!scopes.TryGetValue(key, out Stack<Scope> value) || value.Count == 0 || value.Peek() != scope) { throw new InvalidOperationException("Попытка закрыть неактивный death scope."); } value.Pop(); if (value.Count == 0) { scopes.Remove(key); } } internal void Clear() { scopes.Clear(); } } internal static class Diagnostics { private sealed class Snapshot { internal long Sequence { get; set; } internal int Stacks { get; private set; } internal int Units { get; private set; } internal string ItemDigest { get; private set; } = string.Empty; internal string SkillDigest { get; private set; } = string.Empty; internal HashSet<ItemData> References { get; } = new HashSet<ItemData>(ReferenceComparer<ItemData>.Instance); private Snapshot() { } internal static Snapshot Capture(Player player) { Snapshot snapshot = new Snapshot(); List<string> list = new List<string>(); foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems()) { snapshot.References.Add(allItem); snapshot.Stacks++; snapshot.Units += allItem.m_stack; string text = string.Join(";", from pair in allItem.m_customData.OrderBy<KeyValuePair<string, string>, string>((KeyValuePair<string, string> pair) => pair.Key, StringComparer.Ordinal) select pair.Key + "=" + pair.Value); string text2 = (((Object)(object)allItem.m_dropPrefab == (Object)null) ? "<null>" : Utils.GetPrefabName(allItem.m_dropPrefab)); list.Add(string.Join("|", text2, allItem.m_stack, allItem.m_quality, allItem.m_variant, allItem.m_durability.ToString("R"), allItem.m_gridPos.x, allItem.m_gridPos.y, allItem.m_equipped, text)); } list.Sort(StringComparer.Ordinal); snapshot.ItemDigest = Hash(string.Join("\n", list)); IEnumerable<string> values = from skill in ((Character)player).GetSkills().GetSkillList() orderby (int)skill.m_info.m_skill select $"{(int)skill.m_info.m_skill}:{FloatBits(skill.m_level):x8}:{FloatBits(skill.m_accumulator):x8}"; snapshot.SkillDigest = Hash(string.Join(";", values)); return snapshot; } private static int FloatBits(float value) { return BitConverter.ToInt32(BitConverter.GetBytes(value), 0); } private static string Hash(string value) { using SHA256 sHA = SHA256.Create(); return BitConverter.ToString(sHA.ComputeHash(Encoding.UTF8.GetBytes(value))).Replace("-", string.Empty).ToLowerInvariant(); } } private sealed class ReferenceComparer<T> : IEqualityComparer<T> where T : class { internal static readonly ReferenceComparer<T> Instance = new ReferenceComparer<T>(); public bool Equals(T x, T y) { return x == y; } public int GetHashCode(T obj) { return RuntimeHelpers.GetHashCode(obj); } } internal const string HarmonyId = "zari.rules.diagnostics"; private static readonly Dictionary<Player, Snapshot> BeforeDeath = new Dictionary<Player, Snapshot>(); private static Harmony? harmony; private static long sequence; internal static bool Install(out string reason) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown if (!CompatibilityProbe.VerifyMethod(typeof(Character), "CheckDeath", BindingFlags.Instance | BindingFlags.NonPublic, typeof(void), Type.EmptyTypes, "fef54e1a3e6de1ea05ab81ffd5346eaea2c503b00ccefcc342c4ae862caaa095", out MethodInfo method, out reason)) { return false; } try { harmony = new Harmony("zari.rules.diagnostics"); HarmonyMethod val = new HarmonyMethod(typeof(Diagnostics), "CheckDeathPrefix", (Type[])null); val.priority = 800; val.before = new string[1] { "randyknapp.mods.equipmentandquickslots" }; HarmonyMethod val2 = val; harmony.Patch((MethodBase)method, val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); reason = "read-only Character.CheckDeath observer"; return true; } catch (Exception ex) { Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } reason = ex.GetType().Name + ": " + ex.Message; return false; } } internal static void Info(string code, string message) { try { ZariRulesPlugin.Instance.Logger.LogInfo((object)(code + " " + message)); } catch { } } internal static void OnDeathStarted(Player player) { if (ZariRulesPlugin.Instance.Rules.DebugLogging.Value) { Snapshot snapshot = Snapshot.Capture(player); if (!BeforeDeath.TryGetValue(player, out Snapshot value)) { value = snapshot; } long num = ++sequence; long num2 = (value.Sequence = num); BeforeDeath[player] = value; Info("ZR200", $"death={num2} started preEaqsStacks={value.Stacks} preEaqsUnits={value.Units} visibleStacks={snapshot.Stacks} visibleUnits={snapshot.Units}"); Info("ZR201", string.Format("death={0} eaqsVersion={1} pendingCount=not-read", num2, CompatibilityProbe.InstalledPluginVersion("randyknapp.mods.equipmentandquickslots"))); } } internal static void OnDeathFinished(Player player, DeathScopeTracker<Player>.Scope scope, bool successful) { if (ZariRulesPlugin.Instance.Rules.DebugLogging.Value && BeforeDeath.TryGetValue(player, out Snapshot value)) { Snapshot snapshot = Snapshot.Capture(player); bool flag = value.ItemDigest == snapshot.ItemDigest && value.References.SetEquals(snapshot.References); bool flag2 = value.SkillDigest == snapshot.SkillDigest; Info("ZR204", $"death={value.Sequence} finished={successful.ToString().ToLowerInvariant()} stacks={snapshot.Stacks} units={snapshot.Units} itemDigestEqual={flag.ToString().ToLowerInvariant()} skillDigestEqual={flag2.ToString().ToLowerInvariant()} tombstoneSuppressed={scope.TombstoneSuppressed.ToString().ToLowerInvariant()}"); BeforeDeath.Remove(player); } } internal static void ResetSession() { BeforeDeath.Clear(); sequence = 0L; } internal static void Uninstall() { Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } ResetSession(); } private static void CheckDeathPrefix(Character __instance) { //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_0050: Expected O, but got Unknown //IL_0055: Expected O, but got Unknown try { if (ZariRulesPlugin.Instance.Rules.DebugLogging.Value && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && !__instance.IsDead() && !(__instance.GetHealth() > 0f)) { BeforeDeath[(Player)__instance] = Snapshot.Capture((Player)__instance); } } catch (Exception ex) { ZariRulesPlugin.LogError("ZR901", "feature=Diagnostics phase=pre-death reason=" + ex.GetType().Name); } } } internal static class GameBuildContracts { internal static readonly Guid WindowsClient = new Guid("b8a6fd30-3061-43b3-99f2-11c2e315bc54"); internal static readonly Guid LinuxServer = new Guid("e8e9a680-25ea-4b87-bdd4-07412665a2ad"); internal static readonly Guid LegacyWindowsClient = new Guid("db11c804-ebef-403d-8e77-ac219f14bf46"); internal static readonly Guid LegacyLinuxServer = new Guid("0ee5b4bc-8894-42ff-b5dc-b038511e2bfc"); internal static bool IsSupported(Guid mvid) { if (!(mvid == WindowsClient) && !(mvid == LinuxServer) && !(mvid == LegacyWindowsClient)) { return mvid == LegacyLinuxServer; } return true; } internal static string ExpectedIlHash(Guid mvid, string clientHash) { if (mvid == WindowsClient) { return clientHash switch { "76b17b9f1894281bde973d01f97a8f330b955e275d4556ceea1ead4ed56f2c21" => "94a716985990cdfbef2dab44cde6a20c0ddc85ffe65be3b779670aa468339ba7", "00f13b0d81783d11221910d3b2090f27918f53957ea98b114af49d151dacbd98" => "c4771274beb528d85938ca69e5cadb3d9a906a709a67c732c63d8a2ff02f1059", "807a60cdbe58ac91d5620c9f1bbeb6d866a7b0085851c37edc19c08933c48591" => "e3196a9480de19a817132384a4947f5cff2a78d18c73779758bef4ff8e341e8d", "146dc8c182d22edbcc9f2192f3edb621ec03f219bf327c7315ed6f910563a798" => "3715e25250ae63a5a476a287186fded73554c1da919f7d95c794bdb96561fb19", "bf1b5c65eee0066748cbd0b77e326d2e5e3cd2786f3fa80c2d063dccd4522b7a" => "44735573fcec61a54b9e5d998e5ca5704899d4cda93e7246eb4427bce862b8ea", "0d778f0dea28e91896454793f46dc19c0a456883b218ca2113747744a0dd6ba6" => "ade188b9421fb218374901295da958023f47db81d64729e302f0c43042e261af", "0a477dbd4078ac2966eba61c40b1382a8b572b01e39bafeef72681da3a3522fa" => "6fbfa5d44d14c504ba016c163a807933de874e52621e28dde6b672f5a38b2151", "3acb4e2da64e100830c9912ba3dceb86211cd08eccd7b4739fe1e2cf24e95c68" => "d580ea92edcb6c7597328c6762634f54f6977b12abb253bef693a85f7307d64e", "1febeff1fc10e2e78fe1fa15b5ef3ac6dea400e0795c7e26969a1ebd25d64bfb" => "d07178720ccb367e61dee4cb30149ebb1ab37b20bd3a71df15bb42c82c24fc7e", _ => clientHash, }; } if (mvid == LegacyLinuxServer) { return clientHash switch { "0d778f0dea28e91896454793f46dc19c0a456883b218ca2113747744a0dd6ba6" => "2d5538172782de67019d39e75b0e7ef3de1138b0714c3611822c256c38525076", "76b17b9f1894281bde973d01f97a8f330b955e275d4556ceea1ead4ed56f2c21" => "d7a0608475b68e73155b6b013d2fb120054a0b546f58a14365c7f00ccbbdf23f", "00f13b0d81783d11221910d3b2090f27918f53957ea98b114af49d151dacbd98" => "f5c48166fceba41b88101c905968f2c262500a96c99a7b13bcb71fce5db07db8", "807a60cdbe58ac91d5620c9f1bbeb6d866a7b0085851c37edc19c08933c48591" => "af82486e3d28756396e11d0fc467fb5dc76abd9abb1c8b25665d67599247dc06", "146dc8c182d22edbcc9f2192f3edb621ec03f219bf327c7315ed6f910563a798" => "f50af2280c1f078c07be5b9c2a7e7ea3e0155d072a9d7e03f56c4236e50bd095", "bf1b5c65eee0066748cbd0b77e326d2e5e3cd2786f3fa80c2d063dccd4522b7a" => "4fa96ee109e0f3c7cc47e51e716707f5092db65df236c4232e6789098dff9e82", "0a477dbd4078ac2966eba61c40b1382a8b572b01e39bafeef72681da3a3522fa" => "98b819c45679502cd6cdf3ed277e82ce4ef406ec512cb3c2ea4c69f3f673d2c8", "3acb4e2da64e100830c9912ba3dceb86211cd08eccd7b4739fe1e2cf24e95c68" => "249b687a4a7c042248fd71eaf8603f7689de523e9391fa00b75ba632bc985f6e", "1febeff1fc10e2e78fe1fa15b5ef3ac6dea400e0795c7e26969a1ebd25d64bfb" => "2d858424cc340899fcd60b5e2a6cae6e5ecdf83740d46b06524bdaf7e5ec8018", _ => clientHash, }; } if (mvid == LinuxServer) { return clientHash switch { "76b17b9f1894281bde973d01f97a8f330b955e275d4556ceea1ead4ed56f2c21" => "67755886372660c97917c425b7044392277d616b08d0e4b650204d822d12a57c", "00f13b0d81783d11221910d3b2090f27918f53957ea98b114af49d151dacbd98" => "879a784c42f298551ce6bc35b7df42021f51ea647080db4b83d947cee7a793d5", "146dc8c182d22edbcc9f2192f3edb621ec03f219bf327c7315ed6f910563a798" => "cbd7faf66c4a1f1dd70790e57adddc157aa5a90e35ab9a32627b901e0d2e561d", "bf1b5c65eee0066748cbd0b77e326d2e5e3cd2786f3fa80c2d063dccd4522b7a" => "e377de4c79ca316e14e6c0dccfbd264f0d4d8db421b8af7d37b4604aafef033d", "0d778f0dea28e91896454793f46dc19c0a456883b218ca2113747744a0dd6ba6" => "374ff6598caba1aa57a9269740c94d88e1847f124e8393a20e0ace4e04f6c857", "0a477dbd4078ac2966eba61c40b1382a8b572b01e39bafeef72681da3a3522fa" => "7ef5ab570cb12616af2f282a0912cc94a2981ad3efec04e68ddbca4f3991b34d", "3acb4e2da64e100830c9912ba3dceb86211cd08eccd7b4739fe1e2cf24e95c68" => "cff6ba19bd1e26fcd3aa27fcba87be6dcb894f67caa0c1e17273a40313729ada", "1febeff1fc10e2e78fe1fa15b5ef3ac6dea400e0795c7e26969a1ebd25d64bfb" => "c1812adc1cab5ae250f487c6dfa9ee9d41d41a38dc205ec842018b4beab79ee1", _ => clientHash, }; } return clientHash; } } internal static class HammerDurabilityFeature { internal const string HarmonyId = "zari.rules.hammer-durability"; private static readonly HammerDurabilityTracker<SharedData> Tracker = new HammerDurabilityTracker<SharedData>(); private static Harmony? harmony; internal static bool Ready { get; private set; } internal static bool Install(out string reason) { //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Expected O, but got Unknown //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Expected O, but got Unknown //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Expected O, but got Unknown //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Expected O, but got Unknown //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) //IL_01a3: Expected O, but got Unknown if (Ready) { reason = "unbreakable building hammer and tools active"; return true; } MethodInfo methodInfo = AccessTools.Method(typeof(Player), "GetPlaceDurability", new Type[1] { typeof(ItemData) }, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(Humanoid), "DrainEquipedItemDurability", new Type[2] { typeof(ItemData), typeof(float) }, (Type[])null); MethodInfo methodInfo3 = AccessTools.DeclaredMethod(typeof(ItemDrop), "Awake", Type.EmptyTypes, (Type[])null); MethodInfo methodInfo4 = AccessTools.DeclaredMethod(typeof(ObjectDB), "Awake", Type.EmptyTypes, (Type[])null); MethodInfo methodInfo5 = AccessTools.DeclaredMethod(typeof(ObjectDB), "CopyOtherDB", new Type[1] { typeof(ObjectDB) }, (Type[])null); if (methodInfo == null || methodInfo2 == null || methodInfo3 == null || methodInfo4 == null || methodInfo5 == null) { reason = "missing or changed Player/Humanoid/ObjectDB durability contracts"; return false; } try { harmony = new Harmony("zari.rules.hammer-durability"); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(HammerDurabilityFeature), "GetPlaceDurabilityPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(HammerDurabilityFeature), "DrainEquipedItemDurabilityPrefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeof(HammerDurabilityFeature), "ItemAwakePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); HarmonyMethod val = new HarmonyMethod(typeof(HammerDurabilityFeature), "DatabasePostfix", (Type[])null) { priority = 0 }; harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo5, (HarmonyMethod)null, val, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Ready = true; reason = "Player.GetPlaceDurability + Humanoid.DrainEquipedItemDurability + ItemDrop/ObjectDB postfixes"; return true; } catch (Exception ex) { Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } harmony = null; Tracker.Restore(SetUseDurability); reason = ex.GetType().Name + ": " + ex.Message; return false; } } internal static void Apply(string source) { if (!Ready) { return; } RegisterDatabase(ObjectDB.instance); ItemDrop[] array = Resources.FindObjectsOfTypeAll<ItemDrop>(); for (int i = 0; i < array.Length; i++) { TrackInstance(array[i]); } bool flag = IsActive(); int num = Tracker.Apply(flag, SetUseDurability); if (flag && (Object)(object)Player.m_localPlayer != (Object)null && ((Humanoid)Player.m_localPlayer).GetInventory() != null) { foreach (ItemData allItem in ((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems()) { if (IsEligible(allItem)) { float maxDurability = allItem.GetMaxDurability(); if (allItem.m_durability < maxDurability) { allItem.m_durability = maxDurability; } } } } Diagnostics.Info("ZR330", $"hammerDurability=applied active={flag} tracked={num} source={source}"); } internal static void ResetSession() { Tracker.Restore(SetUseDurability); } internal static void Uninstall() { Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } harmony = null; Ready = false; Tracker.Restore(SetUseDurability); } internal static bool IsEligible(ItemData? item) { if (item?.m_shared == null) { return false; } string prefabName = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : null); string name = item.m_shared.m_name; string pieceTableName = (((Object)(object)item.m_shared.m_buildPieces != (Object)null) ? ((Object)item.m_shared.m_buildPieces).name : null); bool hasBuildPieces = (Object)(object)item.m_shared.m_buildPieces != (Object)null; return HammerDurabilityRules.IsEligible(prefabName, name, pieceTableName, hasBuildPieces, ZariRulesPlugin.Instance.Rules.UnbreakableHammer.Value, ZariRulesPlugin.Instance.Rules.UnbreakableBuildingTools.Value); } private static bool IsActive() { if (ZariRulesPlugin.Instance.Rules.IsServerConfigurationReady) { if (!ZariRulesPlugin.Instance.Rules.UnbreakableHammer.Value) { return ZariRulesPlugin.Instance.Rules.UnbreakableBuildingTools.Value; } return true; } return false; } private static void SetUseDurability(SharedData shared, bool useDurability) { shared.m_useDurability = useDurability; } private static bool GetPlaceDurabilityPrefix(ItemData __0, ref float __result) { if (IsActive() && IsEligible(__0)) { __result = 0f; return false; } return true; } private static bool DrainEquipedItemDurabilityPrefix(ItemData __0) { if (IsActive() && IsEligible(__0)) { return false; } return true; } private static void ItemAwakePostfix(ItemDrop __instance) { SharedData val = TrackInstance(__instance); if (val != null && IsActive() && IsEligible(__instance.m_itemData)) { val.m_useDurability = false; } } private static void DatabasePostfix(ObjectDB __instance) { RegisterDatabase(__instance); Tracker.Apply(IsActive(), SetUseDurability); } private static void RegisterDatabase(ObjectDB? database) { if (database?.m_items == null) { return; } foreach (GameObject item in database.m_items) { ItemDrop val = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null); SharedData val2 = val?.m_itemData?.m_shared; if (val2 != null) { bool isEligible = IsEligible(val?.m_itemData); Tracker.TrackCanonical(val2, val2.m_useDurability, isEligible); } } } private static SharedData? TrackInstance(ItemDrop? itemDrop) { SharedData val = itemDrop?.m_itemData?.m_shared; object obj; if (itemDrop == null) { obj = null; } else { ItemData itemData = itemDrop.m_itemData; if (itemData == null) { obj = null; } else { GameObject dropPrefab = itemData.m_dropPrefab; obj = ((dropPrefab != null) ? dropPrefab.GetComponent<ItemDrop>() : null); } } SharedData val2 = ((ItemDrop)(obj?)).m_itemData?.m_shared; if (val != null && val2 != null && Tracker.TrackInstance(val, val2)) { return val; } return null; } } internal static class HammerDurabilityRules { internal static bool IsHammer(string? prefabName, string? itemName, string? pieceTableName) { if (!string.IsNullOrEmpty(prefabName) && (string.Equals(prefabName, "Hammer", StringComparison.OrdinalIgnoreCase) || prefabName.IndexOf("Hammer", StringComparison.OrdinalIgnoreCase) >= 0)) { return true; } if (!string.IsNullOrEmpty(itemName) && (string.Equals(itemName, "$item_hammer", StringComparison.OrdinalIgnoreCase) || itemName.IndexOf("hammer", StringComparison.OrdinalIgnoreCase) >= 0)) { return true; } if (!string.IsNullOrEmpty(pieceTableName) && (string.Equals(pieceTableName, "_PieceTableHammer", StringComparison.OrdinalIgnoreCase) || pieceTableName.IndexOf("Hammer", StringComparison.OrdinalIgnoreCase) >= 0)) { return true; } return false; } internal static bool IsEligible(string? prefabName, string? itemName, string? pieceTableName, bool hasBuildPieces, bool unbreakableHammer, bool unbreakableBuildingTools) { if (!hasBuildPieces) { return false; } if (unbreakableBuildingTools) { return true; } if (unbreakableHammer && IsHammer(prefabName, itemName, pieceTableName)) { return true; } return false; } } internal sealed class HammerDurabilityTracker<T> where T : class { private sealed class CanonicalEntry { internal T Canonical { get; } internal CanonicalEntry(T canonical) { Canonical = canonical; } } private sealed class ReferenceComparer : IEqualityComparer<T> { internal static readonly ReferenceComparer Instance = new ReferenceComparer(); public bool Equals(T? x, T? y) { return x == y; } public int GetHashCode(T obj) { return RuntimeHelpers.GetHashCode(obj); } } private readonly Dictionary<T, bool> baselines = new Dictionary<T, bool>(ReferenceComparer.Instance); private readonly Dictionary<T, bool> eligibility = new Dictionary<T, bool>(ReferenceComparer.Instance); private readonly List<WeakReference<T>> instances = new List<WeakReference<T>>(); private ConditionalWeakTable<T, CanonicalEntry> entriesByInstance = new ConditionalWeakTable<T, CanonicalEntry>(); internal void TrackCanonical(T canonical, bool baselineUseDurability, bool isEligible) { eligibility[canonical] = isEligible; if (!baselines.ContainsKey(canonical)) { baselines.Add(canonical, baselineUseDurability); } TrackInstance(canonical, canonical); } internal bool TrackInstance(T instance, T canonical) { if (!baselines.ContainsKey(canonical)) { return false; } if (entriesByInstance.TryGetValue(instance, out CanonicalEntry _)) { return true; } entriesByInstance.Add(instance, new CanonicalEntry(canonical)); instances.Add(new WeakReference<T>(instance)); return true; } internal int Apply(bool active, Action<T, bool> setUseDurability) { int num = 0; bool value3 = default(bool); for (int num2 = instances.Count - 1; num2 >= 0; num2--) { CanonicalEntry value; bool value2; if (!instances[num2].TryGetTarget(out var target)) { instances.RemoveAt(num2); } else if (entriesByInstance.TryGetValue(target, out value) && baselines.TryGetValue(value.Canonical, out value2)) { if (active && eligibility.TryGetValue(value.Canonical, out value3) && value3) { setUseDurability(target, arg2: false); num++; } else { setUseDurability(target, value2); } } } return num; } internal void Restore(Action<T, bool> setUseDurability) { Apply(active: false, setUseDurability); baselines.Clear(); eligibility.Clear(); instances.Clear(); entriesByInstance = new ConditionalWeakTable<T, CanonicalEntry>(); } } internal static class HealthHudFeature { private static readonly Color NormalColor = new Color(0.16f, 0.88f, 0.67f, 1f); private static readonly Color WoundedColor = new Color(0.92f, 0.68f, 0.2f, 1f); private static readonly Color CriticalColor = new Color(1f, 0.18f, 0.16f, 1f); private static GameObject? canvasObject; private static GameObject? panelObject; private static RectTransform? panelRect; private static CanvasGroup? panelGroup; private static Image? fillImage; private static TMP_Text? valueText; private static TMP_Text? statusText; private static Image? edgeVignetteImage; private static Sprite? edgeVignetteSprite; private static Image[] edgeImages = Array.Empty<Image>(); private static Hud? ownerHud; private static HealthHudSnapshot lastSnapshot; private static string lastLanguage = string.Empty; private static float lastPositionX = float.NaN; private static float lastPositionY = float.NaN; private static float lastScale = float.NaN; internal static bool Install(out string reason) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 ResetSession(); if ((int)SystemInfo.graphicsDeviceType == 4) { reason = "headless graphics device; UI disabled"; return true; } reason = "independent overlay; no Hud or BetterUI patches"; return true; } internal static void Tick() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)SystemInfo.graphicsDeviceType == 4) { return; } Hud instance = Hud.instance; Player localPlayer = Player.m_localPlayer; if (!ZariRulesPlugin.Instance.Rules.HealthIndicatorEnabled.Value || !((Object)(object)instance != (Object)null) || !((Object)(object)localPlayer != (Object)null) || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting() || !instance.IsVisible() || Hud.IsUserHidden() || InventoryGui.IsVisible() || Menu.IsVisible()) { SetVisible(visible: false); return; } if ((Object)(object)canvasObject == (Object)null || (Object)(object)ownerHud != (Object)(object)instance) { DestroyUi(); if (!CreateUi(instance)) { return; } } HealthHudSnapshot healthHudSnapshot = HealthHudRules.Evaluate(((Character)localPlayer).GetHealth(), ((Character)localPlayer).GetMaxHealth()); if (!healthHudSnapshot.IsValid) { SetVisible(visible: false); return; } UpdateLayout(); Localization instance2 = Localization.instance; string text = ((instance2 != null) ? instance2.GetSelectedLanguage() : null) ?? "English"; if (!SameHealth(healthHudSnapshot, lastSnapshot) || !string.Equals(text, lastLanguage, StringComparison.Ordinal)) { UpdateContent(healthHudSnapshot, text); lastSnapshot = healthHudSnapshot; lastLanguage = text; } bool flag = healthHudSnapshot.State == HealthHudState.Critical && ZariRulesPlugin.Instance.Rules.HealthIndicatorPulse.Value; float num = (flag ? (0.5f + 0.5f * Mathf.Sin(Time.unscaledTime * (float)Math.PI * 2.5f)) : 1f); panelGroup.alpha = (flag ? (0.78f + 0.22f * num) : 1f); SetEdges(healthHudSnapshot.State, num); SetVisible(visible: true); } internal static void ResetSession() { DestroyUi(); lastSnapshot = default(HealthHudSnapshot); lastLanguage = string.Empty; } internal static void Uninstall() { ResetSession(); } private static bool SameHealth(HealthHudSnapshot left, HealthHudSnapshot right) { if (left.IsValid == right.IsValid && left.Current == right.Current && left.Maximum == right.Maximum && left.Percent == right.Percent) { return left.State == right.State; } return false; } private static bool CreateUi(Hud hud) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown //IL_00b0: 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_0139: 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_01a9: 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_01d3: 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_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: 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_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_0295: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02eb: Unknown result type (might be due to invalid IL or missing references) //IL_030e: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Unknown result type (might be due to invalid IL or missing references) //IL_0329: Unknown result type (might be due to invalid IL or missing references) //IL_0334: Unknown result type (might be due to invalid IL or missing references) //IL_033e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)hud.m_healthText == (Object)null || (Object)(object)hud.m_healthText.font == (Object)null) { return false; } ownerHud = hud; canvasObject = new GameObject("ZariRules.HealthHud", new Type[4] { typeof(RectTransform), typeof(Canvas), typeof(CanvasScaler), typeof(CanvasGroup) }); Object.DontDestroyOnLoad((Object)(object)canvasObject); Canvas component = canvasObject.GetComponent<Canvas>(); component.renderMode = (RenderMode)0; component.sortingOrder = 50; CanvasScaler component2 = canvasObject.GetComponent<CanvasScaler>(); component2.uiScaleMode = (ScaleMode)1; component2.referenceResolution = new Vector2(1920f, 1080f); component2.matchWidthOrHeight = 0.5f; CanvasGroup component3 = canvasObject.GetComponent<CanvasGroup>(); component3.interactable = false; component3.blocksRaycasts = false; panelObject = ((Component)CreateImage("Panel", canvasObject.transform, new Color(0.025f, 0.035f, 0.045f, 0.92f), out Image image)).gameObject; ((Graphic)image).raycastTarget = false; panelRect = panelObject.GetComponent<RectTransform>(); panelRect.sizeDelta = new Vector2(280f, 44f); panelGroup = panelObject.AddComponent<CanvasGroup>(); panelGroup.interactable = false; panelGroup.blocksRaycasts = false; Image image2; RectTransform val = CreateImage("Track", (Transform)(object)panelRect, new Color(0.12f, 0.14f, 0.16f, 1f), out image2); val.anchorMin = Vector2.zero; val.anchorMax = new Vector2(1f, 0f); val.offsetMin = new Vector2(10f, 6f); val.offsetMax = new Vector2(-10f, 12f); Image image3; RectTransform obj = CreateImage("Fill", (Transform)(object)val, NormalColor, out image3); obj.anchorMin = Vector2.zero; obj.anchorMax = Vector2.one; obj.offsetMin = Vector2.zero; obj.offsetMax = Vector2.zero; fillImage = image3; valueText = CreateText("Value", (Transform)(object)panelRect, hud.m_healthText.font, 17f, (TextAlignmentOptions)513); valueText.enableAutoSizing = true; valueText.fontSizeMin = 13f; valueText.fontSizeMax = 17f; SetRect(valueText.rectTransform, new Vector2(10f, 14f), new Vector2(-95f, -3f)); statusText = CreateText("Status", (Transform)(object)panelRect, hud.m_healthText.font, 12f, (TextAlignmentOptions)516); SetRect(statusText.rectTransform, new Vector2(175f, 14f), new Vector2(-10f, -4f)); edgeVignetteSprite = CreateVignetteSprite(); RectTransform obj2 = CreateImage("EdgeVignette", canvasObject.transform, Color.clear, out edgeVignetteImage); obj2.anchorMin = Vector2.zero; obj2.anchorMax = Vector2.one; obj2.offsetMin = Vector2.zero; obj2.offsetMax = Vector2.zero; edgeVignetteImage.sprite = edgeVignetteSprite; ((Graphic)edgeVignetteImage).raycastTarget = false; edgeImages = CreateEdges(canvasObject.transform); UpdateLayout(); return true; } private static void UpdateContent(HealthHudSnapshot snapshot, string language) { //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_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_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_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: 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_0102: 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) Color color = (Color)(snapshot.State switch { HealthHudState.Critical => CriticalColor, HealthHudState.Wounded => WoundedColor, _ => NormalColor, }); bool flag = language.StartsWith("Russian", StringComparison.OrdinalIgnoreCase) || language.StartsWith("Рус", StringComparison.OrdinalIgnoreCase); string text = snapshot.State switch { HealthHudState.Critical => flag ? "КРИТИЧНО" : "CRITICAL", HealthHudState.Wounded => flag ? "РАНЕН" : "WOUNDED", _ => flag ? "НОРМА" : "NORMAL", }; valueText.text = $"{Mathf.CeilToInt(snapshot.Current)} / {Mathf.CeilToInt(snapshot.Maximum)} · {snapshot.Percent}%"; ((Graphic)valueText).color = Color.white; statusText.text = text; ((Graphic)statusText).color = color; ((Graphic)fillImage).color = color; ((Graphic)fillImage).rectTransform.anchorMax = new Vector2(snapshot.Fraction, 1f); } private static void UpdateLayout() { //IL_0084: 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_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: 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_00c3: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Clamp01(ZariRulesPlugin.Instance.Rules.HealthIndicatorPositionX.Value); float num2 = Mathf.Clamp01(ZariRulesPlugin.Instance.Rules.HealthIndicatorPositionY.Value); float num3 = Mathf.Clamp(ZariRulesPlugin.Instance.Rules.HealthIndicatorScale.Value, 0.5f, 2f); if (num != lastPositionX || num2 != lastPositionY || num3 != lastScale) { RectTransform? obj = panelRect; RectTransform? obj2 = panelRect; Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(num, num2); obj2.anchorMax = val; obj.anchorMin = val; panelRect.pivot = new Vector2(0.5f, 0.5f); panelRect.anchoredPosition = Vector2.zero; ((Transform)panelRect).localScale = Vector3.one * num3; lastPositionX = num; lastPositionY = num2; lastScale = num3; } } private static RectTransform CreateImage(string name, Transform parent, Color color, out Image image) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_004b: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[3] { typeof(RectTransform), typeof(CanvasRenderer), typeof(Image) }); val.transform.SetParent(parent, false); image = val.GetComponent<Image>(); ((Graphic)image).color = color; ((Graphic)image).raycastTarget = false; return val.GetComponent<RectTransform>(); } private static TMP_Text CreateText(string name, Transform parent, TMP_FontAsset font, float size, TextAlignmentOptions alignment) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown //IL_0074: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[2] { typeof(RectTransform), typeof(CanvasRenderer) }); val.SetActive(false); val.transform.SetParent(parent, false); TextMeshProUGUI val2 = val.AddComponent<TextMeshProUGUI>(); ((TMP_Text)val2).font = font; if ((Object)(object)font != (Object)null && (Object)(object)((TMP_Asset)font).material != (Object)null) { ((TMP_Text)val2).fontSharedMaterial = ((TMP_Asset)font).material; } ((TMP_Text)val2).fontSize = size; ((TMP_Text)val2).alignment = alignment; ((Graphic)val2).raycastTarget = false; ((TMP_Text)val2).textWrappingMode = (TextWrappingModes)0; val.SetActive(true); return (TMP_Text)(object)val2; } private static Image[] CreateEdges(Transform parent) { //IL_0034: 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_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_0078: 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_0093: 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_0090: 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_00b5: 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_00c8: 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_00db: 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_00f0: 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_00df: 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_0125: 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) Image[] array = (Image[])(object)new Image[4]; for (int i = 0; i < array.Length; i++) { RectTransform val = CreateImage("CriticalEdge" + i, parent, new Color(1f, 0.05f, 0.03f, 0f), out array[i]); RectTransform val2 = val; val2.anchorMin = (Vector2)(i switch { 0 => new Vector2(0f, 1f), 1 => Vector2.zero, 2 => Vector2.zero, _ => new Vector2(1f, 0f), }); val2 = val; val2.anchorMax = (Vector2)(i switch { 0 => Vector2.one, 1 => new Vector2(1f, 0f), 2 => new Vector2(0f, 1f), _ => Vector2.one, }); val.pivot = val.anchorMin; val.anchoredPosition = Vector2.zero; val.sizeDelta = ((i < 2) ? new Vector2(0f, 3f) : new Vector2(3f, 0f)); } return array; } private static Sprite CreateVignetteSprite() { //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_0016: 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_0025: Expected O, but got Unknown //IL_011e: 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_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) Texture2D val = new Texture2D(64, 64, (TextureFormat)4, false) { name = "ZariRules_EdgeGlow", wrapMode = (TextureWrapMode)1, filterMode = (FilterMode)1 }; Color32[] array = (Color32[])(object)new Color32[4096]; for (int i = 0; i < 64; i++) { float num = (float)i / 63f; float num2 = Mathf.Min(num, 1f - num) * 2f; for (int j = 0; j < 64; j++) { float num3 = (float)j / 63f; float num4 = Mathf.Min(num3, 1f - num3) * 2f; float num5 = 1f - Mathf.Clamp01(Mathf.Min(num4, num2)); byte b = (byte)(Mathf.Clamp01(Mathf.Pow(Mathf.SmoothStep(0f, 1f, num5), 2f)) * 255f); array[i * 64 + j] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, b); } } val.SetPixels32(array); val.Apply(); return Sprite.Create(val, new Rect(0f, 0f, 64f, 64f), new Vector2(0.5f, 0.5f)); } private static void SetEdges(HealthHudState state, float pulseFactor) { //IL_0062: 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_0094: 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_008e: 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) Color clear = default(Color); float num; float num2; switch (state) { case HealthHudState.Critical: ((Color)(ref clear))..ctor(1f, 0.12f, 0.1f, 1f); num = 0.22f + 0.16f * pulseFactor; num2 = 0.8f; break; case HealthHudState.Wounded: ((Color)(ref clear))..ctor(0.95f, 0.65f, 0.15f, 1f); num = 0.04f; num2 = 0.4f; break; default: clear = Color.clear; num = 0f; num2 = 0f; break; } clear.a = num; if ((Object)(object)edgeVignetteImage != (Object)null) { ((Graphic)edgeVignetteImage).color = clear; } Color color = clear; color.a = num * num2; Image[] array = edgeImages; for (int i = 0; i < array.Length; i++) { ((Graphic)array[i]).color = color; } } private static void SetRect(RectTransform rect, Vector2 offsetMin, Vector2 offsetMax) { //IL_0001: 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_0017: 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) rect.anchorMin = Vector2.zero; rect.anchorMax = Vector2.one; rect.offsetMin = offsetMin; rect.offsetMax = offsetMax; } private static void SetVisible(bool visible) { if ((Object)(object)canvasObject != (Object)null && canvasObject.activeSelf != visible) { canvasObject.SetActive(visible); } } private static void DestroyUi() { if ((Object)(object)edgeVignetteSprite != (Object)null) { if ((Object)(object)edgeVignetteSprite.texture != (Object)null) { Object.Destroy((Object)(object)edgeVignetteSprite.texture); } Object.Destroy((Object)(object)edgeVignetteSprite); edgeVignetteSprite = null; } edgeVignetteImage = null; if ((Object)(object)canvasObject != (Object)null) { Object.Destroy((Object)(object)canvasObject); } canvasObject = null; panelObject = null; panelRect = null; panelGroup = null; fillImage = null; valueText = null; statusText = null; edgeImages = Array.Empty<Image>(); ownerHud = null; lastSnapshot = default(HealthHudSnapshot); lastLanguage = string.Empty; lastPositionX = float.NaN; lastPositionY = float.NaN; lastScale = float.NaN; } } internal enum HealthHudState { Normal, Wounded, Critical } internal readonly struct HealthHudSnapshot { internal bool IsValid { get; } internal float Current { get; } internal float Maximum { get; } internal float Fraction { get; } internal int Percent { get; } internal HealthHudState State { get; } internal HealthHudSnapshot(bool isValid, float current, float maximum, float fraction, int percent, HealthHudState state) { IsValid = isValid; Current = current; Maximum = maximum; Fraction = fraction; Percent = percent; State = state; } } internal static class HealthHudRules { internal static HealthHudSnapshot Evaluate(float current, float maximum) { if (float.IsNaN(current) || float.IsInfinity(current) || float.IsNaN(maximum) || float.IsInfinity(maximum) || maximum <= 0f) { return default(HealthHudSnapshot); } float num = Math.Min(Math.Max(current, 0f), maximum); float num2 = num / maximum; HealthHudState state = ((num2 <= 0.25f) ? HealthHudState.Critical : ((num2 <= 0.5f) ? HealthHudState.Wounded : HealthHudState.Normal)); return new HealthHudSnapshot(isValid: true, num, maximum, num2, (int)Math.Round(num2 * 100f, MidpointRounding.AwayFromZero), state); } } internal enum MapPinCategory : byte { Boss, Trader, Dungeon } internal readonly struct MapPinData : IEquatable<MapPinData> { internal string Prefab { get; } internal float X { get; } internal float Y { get; } internal float Z { get; } internal MapPinCategory Category { get; } internal MapPinData(string prefab, float x, float y, float z, MapPinCategory category) { Prefab = prefab ?? string.Empty; X = x; Y = y; Z = z; Category = category; } public bool Equals(MapPinData other) { if (Prefab == other.Prefab && X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z)) { return Category == other.Category; } return false; } public override bool Equals(object? obj) { if (obj is MapPinData other) { return Equals(other); } return false; } public override int GetHashCode() { return (((((((Prefab.GetHashCode() * 397) ^ X.GetHashCode()) * 397) ^ Y.GetHashCode()) * 397) ^ Z.GetHashCode()) * 397) ^ (int)Category; } } internal static class MapPinRules { internal const int MaxLocations = 2048; internal const int MaxPayloadBytes = 262144; internal static bool TryClassify(string prefab, out MapPinCategory category, out string token, out string nameEn, out string nameRu) { category = MapPinCategory.Dungeon; token = string.Empty; nameEn = string.Empty; nameRu = string.Empty; if (string.IsNullOrEmpty(prefab)) { return false; } if (string.Equals(prefab, "Eikthyrnir", StringComparison.OrdinalIgnoreCase)) { category = MapPinCategory.Boss; token = "$enemy_eikthyr"; nameEn = "Eikthyr"; nameRu = "Эйктюр"; return true; } if (string.Equals(prefab, "GDKing", StringComparison.OrdinalIgnoreCase)) { category = MapPinCategory.Boss; token = "$enemy_gdking"; nameEn = "The Elder"; nameRu = "Древний"; return true; } if (string.Equals(prefab, "Bonemass", StringComparison.OrdinalIgnoreCase)) { category = MapPinCategory.Boss; token = "$enemy_bonemass"; nameEn = "Bonemass"; nameRu = "Масса Костей"; return true; } if (string.Equals(prefab, "Dragonqueen", StringComparison.OrdinalIgnoreCase)) { category = MapPinCategory.Boss; token = "$enemy_dragonqueen"; nameEn = "Moder"; nameRu = "Моудер"; return true; } if (string.Equals(prefab, "GoblinKing", StringComparison.OrdinalIgnoreCase)) { category = MapPinCategory.Boss; token = "$enemy_goblinking"; nameEn = "Yagluth"; nameRu = "Яглут"; return true; } if (string.Equals(prefab, "Mistlands_DvergrBossEntrance1", StringComparison.OrdinalIgnoreCase)) { category = MapPinCategory.Boss; token = "$enemy_seekerqueen"; nameEn = "The Queen"; nameRu = "Королева"; return true; } if (string.Equals(prefab, "FaderLocation", StringComparison.OrdinalIgnoreCase)) { category = MapPinCategory.Boss; token = "$enemy_fader"; nameEn = "Fader"; nameRu = "Фейдер"; return true; } if (string.Equals(prefab, "Vendor_BlackForest", StringComparison.OrdinalIgnoreCase)) { category = MapPinCategory.Trader; token = "$npc_haldor"; nameEn = "Haldor"; nameRu = "Хальдор"; return true; } if (string.Equals(prefab, "Hildir_camp", StringComparison.OrdinalIgnoreCase)) { category = MapPinCategory.Trader; token = "$npc_hildir"; nameEn = "Hildir"; nameRu = "Хильдир"; return true; } if (string.Equals(prefab, "BogWitch_Camp", StringComparison.OrdinalIgnoreCase)) { category = MapPinCategory.Trader; token = "$npc_bogwitch"; nameEn = "Bog Witch"; nameRu = "Болотная ведьма"; return true; } if (prefab.StartsWith("ForestCryptHildir", StringComparison.OrdinalIgnoreCase) || prefab.StartsWith("CryptHildir", StringComparison.OrdinalIgnoreCase) || prefab.StartsWith("Hildir_crypt", StringComparison.OrdinalIgnoreCase)) { category = MapPinCategory.Dungeon; token = "$location_hildir_crypt"; nameEn = "Smoldering Tomb"; nameRu = "Тлеющая гробница"; return true; } if (prefab.StartsWith("CaveHildir", StringComparison.OrdinalIgnoreCase) || prefab.StartsWith("Hildir_cave", StringComparison.OrdinalIgnoreCase)) { category = MapPinCategory.Dungeon; token = "$location_hildir_cave"; nameEn = "Howling Cavern"; nameRu = "Воющая пещера"; return true; } if (prefab.StartsWith("PlainsFortHildir", StringComparison.OrdinalIgnoreCase) || prefab.StartsWith("Hildir_plainsfortress", StringComparison.OrdinalIgnoreCase)) { category = MapPinCategory.Dungeon; token = "$location_hildir_tower"; nameEn = "Sealed Tower"; nameRu = "Запечатанная башня"; return true; } if (prefab.StartsWith("SunkenCrypt", StringComparison.OrdinalIgnoreCase)) { category = MapPinCategory.Dungeon; token = "$location_sunkencrypt"; nameEn = "Sunken Crypt"; nameRu = "Затонувшие склепы"; return true; } if (prefab.StartsWith("Crypt", StringComparison.OrdinalIgnoreCase) || string.Equals(prefab, "ForestCrypt", StringComparison.OrdinalIgnoreCase) || string.Equals(prefab, "HalfBurried_ForestCrypt", StringComparison.OrdinalIgnoreCase)) { category = MapPinCategory.Dungeon; token = "$location_forestcrypt"; nameEn = "Burial Chambers"; nameRu = "Погребальные склепы"; return true; } if (prefab.StartsWith("TrollCave", StringComparison.OrdinalIgnoreCase) || string.Equals(prefab, "BearCave", StringComparison.OrdinalIgnoreCase)) { category = MapPinCategory.Dungeon; token = "$location_trollcave"; nameEn = "Troll Cave"; nameRu = "Пещера тролля"; return true; } if (prefab.StartsWith("MountainCave", StringComparison.OrdinalIgnoreCase)) { category = MapPinCategory.Dungeon; token = "$location_mountaincave"; nameEn = "Frost Cave"; nameRu = "Морозная пещера"; return true; } if (prefab.StartsWith("Mistlands_DvergrTownEntrance", StringComparison.OrdinalIgnoreCase)) { category = MapPinCategory.Dungeon; token = "$location_infestedmine"; nameEn = "Infested Mine"; nameRu = "Зараженная шахта"; return true; } if (prefab.StartsWith("CharredFortress", StringComparison.OrdinalIgnoreCase)) { category = MapPinCategory.Dungeon; token = "$location_charredfortress"; nameEn = "Charred Fortress"; nameRu = "Обугленная крепость"; return true; } if (prefab.StartsWith("MorgenHole", StringComparison.OrdinalIgnoreCase)) { category = MapPinCategory.Dungeon; token = "$location_morgenhole"; nameEn = "Putrid Hole"; nameRu = "Зловонная яма"; return true; } return false; } internal static byte[] Encode(IReadOnlyList<MapPinData> locations) { using MemoryStream memoryStream = new MemoryStream(); using BinaryWriter binaryWriter = new BinaryWriter(memoryStream); int num = Math.Min(locations.Count, 2048); binaryWriter.Write(num); for (int i = 0; i < num; i++) { MapPinData mapPinData = locations[i]; binaryWriter.Write((byte)mapPinData.Category); binaryWriter.Write(mapPinData.Prefab ?? string.Empty); binaryWriter.Write(mapPinData.X); binaryWriter.Write(mapPinData.Y); binaryWriter.Write(mapPinData.Z); } binaryWriter.Flush(); return memoryStream.ToArray(); } internal static List<MapPinData> Decode(byte[] data) { if (data == null || data.Length < 4 || data.Length > 262144) { throw new InvalidDataException("Invalid map pins payload size."); } using MemoryStream input = new MemoryStream(data, writable: false); using BinaryReader binaryReader = new BinaryReader(input); int num = binaryReader.ReadInt32(); if (num < 0 || num > 2048) { throw new InvalidDataException("Invalid map pin count."); } List<MapPinData> list = new List<MapPinData>(num); for (int i = 0; i < num; i++) { byte category = binaryReader.ReadByte(); string prefab = binaryReader.ReadString(); float x = binaryReader.ReadSingle(); float y = binaryReader.ReadSingle(); float z = binaryReader.ReadSingle(); list.Add(new MapPinData(prefab, x, y, z, (MapPinCategory)category)); } return list; } } internal static class MapPinsFeature { internal const string RpcName = "ZariRules_MapPins_V1"; internal const string RequestRpcName = "ZariRules_MapPins_Request_V1"; private const float RequestIntervalSeconds = 5f; private static readonly HashSet<ZRpc> Registered = new HashSet<ZRpc>(); private static readonly Dictionary<ZRpc, float> NextResponseAt = new Dictionary<ZRpc, float>(); private static readonly List<MapPinData> ServerLocations = new List<MapPinData>(); private static readonly List<MapPinData> ClientLocations = new List<MapPinData>(); private static readonly List<PinData> ActivePins = new List<PinData>(); private static FieldInfo? locationInstancesField; private static FieldInfo? locationsGeneratedField; private static FieldInfo? hasGeneratedField; private static FieldInfo? pinsField; private static bool serverLocationsCached; private static bool pinsApplied; private static bool locationsReceived; private static float nextRequestAt; internal static bool Install(out string reason) { locationInstancesField = typeof(ZoneSystem).GetField("m_locationInstances", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); locationsGeneratedField = typeof(ZoneSystem).GetField("m_locationsGenerated", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); hasGeneratedField = typeof(Minimap).GetField("m_hasGenerated", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); pinsField = typeof(Minimap).GetField("m_pins", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (locationInstancesField == null || locationsGeneratedField == null || hasGeneratedField == null || pinsField == null) { reason = "missing or changed ZoneSystem/Minimap location contracts"; return false; } reason = "server-authoritative non-persistent map pins for bosses, traders, and dungeons"; return true; } internal static void Tick() { ZNet instance = ZNet.instance; if (!((Object)(object)instance == (Object)null)) { RegisterPeers(instance); if (instance.IsServer()) { EnsureServerLocations(); } else { RequestLocations(instance); } UpdateClientPins(); } } internal static void ReapplyPins() { pinsApplied = false; UpdateClientPins(); } internal static void ResetSession() { foreach (ZRpc item in Registered) { item.Unregister("ZariRules_MapPins_V1"); item.Unregister("ZariRules_MapPins_Request_V1"); } Registered.Clear(); NextResponseAt.Clear(); ServerLocations.Clear(); ClientLocations.Clear(); serverLocationsCached = false; ClearActivePins(); pinsApplied = false; locationsReceived = false; nextRequestAt = 0f; } internal static void Uninstall() { ResetSession(); locationInstancesField = null; locationsGeneratedField = null; hasGeneratedField = null; pinsField = null; } internal static bool TryClassify(string prefab, out MapPinCategory category, out string token, out string nameEn, out string nameRu) { return MapPinRules.TryClassify(prefab, out category, out token, out nameEn, out nameRu); } internal static byte[] Encode(IReadOnlyList<MapPinData> locations) { return MapPinRules.Encode(locations); } internal static List<MapPinData> Decode(byte[] data) { return MapPinRules.Decode(data); } private static void EnsureServerLocations() { //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_00b1: 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_00da: 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) //IL_0115: 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_0121: 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) if (serverLocationsCached) { return; } ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)instance == (Object)null || locationsGeneratedField == null || locationInstancesField == null) { return; } object value = locationsGeneratedField.GetValue(instance); if (!(value is bool) || !(bool)value) { return; } ServerLocations.Clear(); object? value2 = locationInstancesField.GetValue(instance); IEnumerable enumerable = value2 as IEnumerable; if (value2 is IDictionary dictionary) { enumerable = dictionary.Values; } if (enumerable != null) { foreach (object item in enumerable) { if (item is LocationInstance val && val.m_location != null) { string text = val.m_location.m_prefabName ?? string.Empty; if (string.IsNullOrEmpty(text)) { text = val.m_location.m_name ?? string.Empty; } if (TryClassify(text, out MapPinCategory category, out string _, out string _, out string _)) { ServerLocations.Add(new MapPinData(text, val.m_position.x, val.m_position.y, val.m_position.z, category)); } } } } ServerLocations.Sort((MapPinData a, MapPinData b) => a.Category.CompareTo(b.Category)); serverLocationsCached = true; Diagnostics.Info("ZR115", $"mapPins=cached count={ServerLocations.Count}"); } private static void RegisterPeers(ZNet net) { HashSet<ZRpc> current = new HashSet<ZRpc>(); if (net.IsServer()) { foreach (ZNetPeer peer in net.GetPeers()) { if (peer != null && peer.IsReady()) { current.Add(peer.m_rpc); Register(peer.m_rpc); } } } else { ZNetPeer serverPeer = net.GetServerPeer(); if (serverPeer != null && serverPeer.IsReady()) { current.Add(serverPeer.m_rpc); Register(serverPeer.m_rpc); } } Registered.RemoveWhere(delegate(ZRpc rpc) { if (current.Contains(rpc) && rpc.IsConnected()) { return false; } rpc.Unregister("ZariRules_MapPins_V1"); rpc.Unregister("ZariRules_MapPins_Request_V1"); NextResponseAt.Remove(rpc); if (!net.IsServer()) { locationsReceived = false; nextRequestAt = 0f; ClientLocations.Clear(); ClearActivePins(); pinsApplied = false; } return true; }); } private static void Register(ZRpc rpc) { if (rpc != null && Registered.Add(rpc)) { rpc.Register<ZPackage>("ZariRules_MapPins_V1", (Action<ZRpc, ZPackage>)OnMapPins); rpc.Register<ZPackage>("ZariRules_MapPins_Request_V1", (Action<ZRpc, ZPackage>)OnRequest); } } private static void RequestLocations(ZNet net) { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown if (!locationsReceived && !(Time.unscaledTime < nextRequestAt) && ZariRulesPlugin.Instance.Rules.IsServerConfigurationReady && ZariRulesPlugin.Instance.Rules.RevealMapPins.Value) { ZNetPeer serverPeer = net.GetServerPeer(); if (serverPeer != null && serverPeer.IsReady() && Registered.Contains(serverPeer.m_rpc) && serverPeer.m_rpc.IsConnected()) { nextRequestAt = Time.unscaledTime + 5f; serverPeer.m_rpc.Invoke("ZariRules_MapPins_Request_V1", new object[1] { (object)new ZPackage() }); } } } private static void OnRequest(ZRpc rpc, ZPackage package) { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown ZNet instance = ZNet.instance; if (!((Object)(object)instance == (Object)null) && instance.IsServer() && package != null && package.Size() == 0 && serverLocationsCached && IsCurrentReadyPeer(instance, rpc) && ZariRulesPlugin.Instance.Rules.IsServerConfigurationReady && ZariRulesPlugin.Instance.Rules.RevealMapPins.Value) { float unscaledTime = Time.unscaledTime; if (!NextResponseAt.TryGetValue(rpc, out var value) || !(unscaledTime < value)) { NextResponseAt[rpc] = unscaledTime + 5f; rpc.Invoke("ZariRules_MapPins_V1", new object[1] { (object)new ZPackage(Encode(ServerLocations)) }); } } } private static bool IsCurrentReadyPeer(ZNet net, ZRpc rpc) { if (!Registered.Contains(rpc) || !rpc.IsConnected()) { return false; } if (!net.IsServer()) { ZNetPeer serverPeer = net.GetServerPeer(); if (serverPeer != null && serverPeer.IsReady()) { return serverPeer.m_rpc == rpc; } return false; } foreach (ZNetPeer peer in net.GetPeers()) { if (peer != null && peer.IsReady() && peer.m_rpc == rpc) { return true; } } return false; } private static void OnMapPins(ZRpc rpc, ZPackage package) { try { if (package == null || package.Size() > 262144) { return; } ZNet instance = ZNet.instance; if (!((Object)(object)instance == (Object)null) && !instance.IsServer() && IsCurrentReadyPeer(instance, rpc)) { ZNetPeer serverPeer = instance.GetServerPeer(); if (serverPeer != null && serverPeer.m_rpc == rpc) { List<MapPinData> collection = Decode(package.GetArray()); ClientLocations.Clear(); ClientLocations.AddRange(collection); locationsReceived = true; pinsApplied = false; Diagnostics.Info("ZR116", $"mapPins=received count={ClientLocations.Count}"); } } } catch (Exception ex) { ZariRulesPlugin.LogError("ZR917", "feature=MapPins error=" + ex.GetType().Name + ": " + ex.Message); } } private static void UpdateClientPins() { //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_01d6: 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_01f1: 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_01f6: 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_0206: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: 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) //IL_0193: 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_01a9: Unknown result type (might be due to invalid IL or missing references) Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null || hasGeneratedField == null || (Object)(object)Player.m_localPlayer == (Object)null) { return; } object value = hasGeneratedField.GetValue(instance); bool flag = default(bool); int num; if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } if (((uint)num & (flag ? 1u : 0u)) == 0 || !ZariRulesPlugin.Instance.Rules.IsServerConfigurationReady || !ZariRulesPlugin.Instance.Rules.RevealMapPins.Value) { if (ActivePins.Count > 0) { ClearActivePins(); } pinsApplied = false; } else { if (pinsApplied) { return; } ZNet instance2 = ZNet.instance; IReadOnlyList<MapPinData> readOnlyList = ((instance2 != null && instance2.IsServer()) ? ServerLocations : ClientLocations); if (readOnlyList.Count == 0) { return; } ClearActivePins(); Localization instance3 = Localization.instance; string text = ((instance3 != null) ? instance3.GetSelectedLanguage() : null) ?? "English"; bool russian = text.StartsWith("Russian", StringComparison.OrdinalIgnoreCase) || text.StartsWith("Рус", StringComparison.OrdinalIgnoreCase); Vector3 val = default(Vector3); foreach (MapPinData item in readOnlyList) { ((Vector3)(ref val))..ctor(item.X, item.Y, item.Z); if (HasNearbyPin(instance, val, 25f) || !TryClassify(item.Prefab, out MapPinCategory category, out string token, out string nameEn, out string nameRu)) { continue; } string text2 = LocalizePinName(token, nameEn, nameRu, russian); Sprite val2 = null; if (category == MapPinCategory.Trader && instance.m_locationIcons != null) { for (int i = 0; i < instance.m_locationIcons.Count; i++) { LocationSpriteData val3 = instance.m_locationIcons[i]; if (string.Equals(val3.m_name, item.Prefab, StringComparison.OrdinalIgnoreCase)) { val2 = val3.m_icon; break; } } } PinType val4 = (PinType)(category switch { MapPinCategory.Boss => 9, MapPinCategory.Trader => ((Object)(object)val2 != (Object)null) ? 8 : 3, _ => 3, }); PinData val5 = instance.AddPin(val, val4, text2, false, false, 0L, default(PlatformUserID)); if ((Object)(object)val2 != (Object)null) { val5.m_icon = val2; val5.m_doubleSize = true; } ActivePins.Add(val5); } pinsApplied = true; Diagnostics.Info("ZR117", $"mapPins=applied count={ActivePins.Count}"); } } private static string LocalizePinName(string token, string defaultEn, string defaultRu, bool russian) { if (Localization.instance != null && !string.IsNullOrEmpty(token)) { string text = Localization.instance.Localize(token); if (!string.IsNullOrEmpty(text) && text != token && !text.StartsWith("$", StringComparison.Ordinal)) { return text; } } if (!russian) { return defaultEn; } return defaultRu; } private static bool HasNearbyPin(Minimap minimap, Vector3 position, float radius) { //IL_0018: 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_001e: 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_007f: Unknown result type (might be due to invalid IL or missing references) float num = radius * radius; foreach (PinData activePin in ActivePins) { if (Vector3.SqrMagnitude(activePin.m_pos - position) < num) { return true; } } try { if (pinsField?.GetValue(minimap) is List<PinData> list) { for (int i = 0; i < list.Count; i++) { PinData val = list[i]; if (val != null && Vector3.SqrMagnitude(val.m_pos - position) < num) { return true; } } } } catch { } return false; } private static void ClearActivePins() { Minimap instance = Minimap.instance; foreach (PinData activePin in ActivePins) { if ((Object)(object)instance != (Object)null) { instance.RemovePin(activePin); } } ActivePins.Clear(); } } internal static class MapRevealFeature { private static FieldInfo? hasGeneratedField; private static FieldInfo? exploredField; private static FieldInfo? fogField; private static Minimap? revealedMap; internal static bool Install(out string reason) { hasGeneratedField = typeof(Minimap).GetField("m_hasGenerated", BindingFlags.Instance | BindingFlags.NonPublic); exploredField = typeof(Minimap).GetField("m_explored", BindingFlags.Instance | BindingFlags.NonPublic); fogField = typeof(Minimap).GetField("m_fogTexture", BindingFlags.Instance | BindingFlags.NonPublic); MethodInfo method = typeof(Minimap).GetMethod("ExploreAll", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null); if (hasGeneratedField?.FieldType != typeof(bool) || method?.ReturnType != typeof(void) || exploredField?.FieldType != typeof(BitArray) || fogField?.FieldType != typeof(Texture2D)) { reason = "missing or changed Minimap.m_hasGenerated/ExploreAll contract"; hasGeneratedField = null; return false; } reason = "bulk fog reveal after profile map generation, preserving shared-map channels"; return true; } internal static void Tick() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Invalid comparison between Unknown and I4 if (hasGeneratedField == null || !ZariRulesPlugin.Instance.Rules.RevealFullMap.Value || !ZariRulesPlugin.Instance.Rules.IsServerConfigurationReady || (Object)(object)Player.m_localPlayer == (Object)null || (int)SystemInfo.graphicsDeviceType == 4) { return; } FieldInfo fieldInfo = hasGeneratedField; Minimap instance = Minimap.instance; if ((Object)(object)instance == (Object)null || instance == revealedMap) { return; } object value = fieldInfo.GetValue(instance); if (!(value is bool) || !(bool)value || !(exploredField.GetValue(instance) is BitArray bitArray)) { return; } object? value2 = fogField.GetValue(instance); Texture2D val = (Texture2D)((value2 is Texture2D) ? value2 : null); if (val == null) { return; } Color32[] pixels = val.GetPixels32(); if (pixels.Length != bitArray.Length) { revealedMap = instance; ZariRulesPlugin.LogError("ZR915", "MapReveal: fog and exploration dimensions differ"); return; } for (int i = 0; i < pixels.Length; i++) { pixels[i].r = 0; } val.SetPixels32(pixels); val.Apply(); bitArray.SetAll(value: true); revealedMap = instance; Diagnostics.Info("ZR110", "mapReveal=completed"); } internal static void ResetSession() { revealedMap = null; } internal static void Uninstall() { ResetSession(); hasGeneratedField = null; exploredField = null; fogField = null; } } internal static class PlantGrowthFeature { internal const string HarmonyId = "zari.rules.plant-growth"; private static Harmony? harmony; internal static bool Ready { get; private set; } internal static bool Install(out string reason) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Expected O, but got Unknown //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown if (Ready) { reason = "plant growth multiplier active"; return true; } MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(Plant), "GetGrowTime", Type.EmptyTypes, (Type[])null); if (methodInfo == null || methodInfo.IsStatic || methodInfo.ReturnType != typeof(float)) { reason = "missing Plant.GetGrowTime contract"; return false; } try { harmony = new Harmony("zari.rules.plant-growth"); harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(PlantGrowthFeature), "GetGrowTimePostfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Ready = true; reason = "Plant.GetGrowTime postfix"; return true; } catch (Exception ex) { Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } harmony = null; reason = ex.GetType().Name + ": " + ex.Message; return false; } } internal static void Uninstall() { Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } harmony = null; Ready = false; } private static void GetGrowTimePostfix(ref float __result) { if (ZariRulesPlugin.Instance.Rules.IsServerConfigurationReady) { double value = ZariRulesPlugin.Instance.Rules.PlantGrowthMultiplier.Value; if (RuleMath.IsSupportedMultiplier(value)) { __result = (float)((double)__result / value); } } } } internal static class ProductionSpeedController { internal const string HarmonyId = "zari.rules.production-speed"; private static readonly HashSet<string> Prefabs = new HashSet<string>(StringComparer.Ordinal) { "smelter", "blastfurnace", "charcoal_kiln" }; private static Harmony? harmony; internal static bool Ready { get; private set; } internal static bool Install(out string reason) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Expected O, but got Unknown //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Expected O, but got Unknown if (!CompatibilityProbe.VerifyMethod(typeof(Smelter), "UpdateSmelter", BindingFlags.Instance | BindingFlags.NonPublic, typeof(void), Type.EmptyTypes, "146dc8c182d22edbcc9f2192f3edb621ec03f219bf327c7315ed6f910563a798", out MethodInfo method, out reason) || !CompatibilityProbe.HasOnlyAllowedPatchOwners(method, (IReadOnlyCollection<string>)(object)Array.Empty<string>(), out reason)) { return false; } try { harmony = new Harmony("zari.rules.production-speed"); harmony.Patch((MethodBase)method, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(ProductionSpeedController), "Transpiler", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); Ready = true; reason = "Smelter.UpdateSmelter: whole simulation ticks; real-time ZDO remainder; native duration/fuel/queue unchanged"; return true; } catch (Exception ex) { Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } reason = ex.GetType().Name + ": " + ex.Message; return false; } } internal static void ApplyToExisting(string source) { if (Ready) { double value = ZariRulesPlugin.Instance.Rules.ProductionSpeedMultiplier.Value; if (!RuleMath.TryProductionTick(value, out float tick, out string error)) { ZariRulesPlugin.LogError("ZR900", "feature=ProductionSpeed status=unavailable reason=" + error); } else { Diagnostics.Info("ZR310", $"production prefabs=smelter,blastfurnace,charcoal_kiln multiplier={value:R} tickSeconds={tick:R} source={source}"); } } } internal static void Uninstall() { Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } Ready = false; } internal static bool VerifyPatchOwners(out string reason) { if (CompatibilityProbe.HasOnlyAllowedPatchOwners(AccessTools.Method(typeof(Smelter), "Awake", (Type[])null, (Type[])null), (IReadOnlyCollection<string>)(object)Array.Empty<string>(), out reason)) { return CompatibilityProbe.HasOnlyAllowedPatchOwners(AccessTools.Method(typeof(Smelter), "UpdateSmelter", (Type[])null, (Type[])null), (IReadOnlyCollection<string>)(object)new string[1] { "zari.rules.production-speed" }, out reason); } return false; } private static float GetTickSeconds(Smelter smelter) { if (!Ready || !Prefabs.Contains(Utils.GetPrefabName(((Component)smelter).gameObject)) || !RuleMath.TryProductionTick(ZariRulesPlugin.Instance.Rules.ProductionSpeedMultiplier.Value, out float tick, out string _)) { return 1f; } return tick; } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator) { return ProductionTimingPatch.Rewrite(instructions, generator, AccessTools.Method(typeof(ProductionSpeedController), "GetTickSeconds", (Type[])null, (Type[])null)); } } internal static class ProductionTimingPatch { internal static IEnumerable<CodeInstruction> Rewrite(IEnumerable<CodeInstruction> instructions, ILGenerator generator, MethodInfo tickGetter) { //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Expected O, but got Unknown //IL_0260: Unknown result type (might be due to invalid IL or missing references) //IL_0267: Expected O, but got Unknown //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Expected O, but got Unknown //IL_0296: Unknown result type (might be due to invalid IL or missing references) //IL_029c: Expected O, but got Unknown //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Expected O, but got Unknown //IL_02ba: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Expected O, but got Unknown //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02d9: Expected O, but got Unknown //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Expected O, but got Unknown //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Expected O, but got Unknown //IL_0306: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Expected O, but got Unknown //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Expected O, but got Unknown //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_0329: Expected O, but got Unknown //IL_0339: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Expected O, but got Unknown List<CodeInstruction> list = instructions.ToList(); List<int> list2 = new List<int>(); List<int> list3 = new List<int>(); for (int i = 0; i + 1 < list.Count; i++) { if (!(list[i].opcode != OpCodes.Ldc_R4) && object.Equals(list[i].operand, 1f)) { if (list[i + 1].opcode == OpCodes.Sub) { list2.Add(i); } else if (list[i + 1].opcode == OpCodes.Bge || list[i + 1].opcode == OpCodes.Bge_S) { list3.Add(i); } } } if (list2.Count != 1 || list3.Count != 1) { throw new InvalidOperationException($"Expected one accumulator subtraction and comparison, found {list2.Count}/{list3.Count}."); } int num = list2[0] - 1; int num2 = num - 1; int index = list3[0] - 1; if (num2 < 0 || (list[num2].opcode != OpCodes.Br && list[num2].opcode != OpCodes.Br_S) || !(list[num2].operand is Label item) || !list[index].labels.Contains(item) || !CodeInstructionExtensions.IsLdloc(list[num], (LocalBuilder)null) || !CodeInstructionExtensions.IsStloc(list[list2[0] + 2], (LocalBuilder)null) || list[num].opcode != list[index].opcode || !object.Equals(list[num].operand, list[index].operand)) { throw new InvalidOperationException("Unexpected accumulator loop entry/local contract."); } LocalBuilder localBuilder = generator.DeclareLocal(typeof(float)); CodeInstruction val = new CodeInstruction(list[num].opcode, list[num].operand); CodeInstruction val2 = new CodeInstruction(list[list2[0] + 2].opcode, list[list2[0] + 2].operand); list.InsertRange(list3[0] + 2, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[4] { new CodeInstruction(val.opcode, val.operand), new CodeInstruction(OpCodes.Ldloc, (object)localBuilder), new CodeInstruction(OpCodes.Mul, (object)null), new CodeInstruction(val2.opcode, val2.operand) }); CodeInstruction[] array = (CodeInstruction[])(object)new CodeInstruction[7] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)tickGetter), new CodeInstruction(OpCodes.Stloc, (object)localBuilder), new CodeInstruction(val.opcode, val.operand), new CodeInstruction(OpCodes.Ldloc, (object)localBuilder), new CodeInstruction(OpCodes.Div, (object)null), new CodeInstruction(val2.opcode, val2.operand) }; array[0].labels.AddRange(list[num2].labels); list[num2].labels.Clear(); list.InsertRange(num2, array); return list; } } internal static class RecipeNotificationFeature { private sealed class NotificationItem { internal string Author { get; } internal List<string> Recipes { get; } internal NotificationItem(string author, List<string> recipes) { Author = author; Recipes = recipes; } } private const int MaxQueueSize = 6; private const float FadeInDuration = 0.3f; private const float HoldDuration = 4.4f; private const float FadeOutDuration = 0.3f; private const float TotalDuration = 5.0000005f; private static readonly Queue<NotificationItem> Queue = new Queue<NotificationItem>(); private static GameObject? canvasObject; private static GameObject? panelObject; private static CanvasGroup? panelGroup; private static TMP_Text? titleText; private static TMP_Text? bodyText; private static Hud? ownerHud; private static NotificationItem? currentItem; private static float currentTimer; internal static bool Install(out string reason) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 ResetSession(); if ((int)SystemInfo.graphicsDeviceType == 4) { reason = "headless graphics device; UI disabled"; return true; } reason = "independent HUD notification banner below minimap with localization and queue"; return true; } internal static void QueueNotification(string author, IReadOnlyList<string> recipes) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 if (recipes != null && recipes.Count != 0 && (int)SystemInfo.graphicsDeviceType != 4) { if (Queue.Count >= 6) { Queue.Dequeue(); } Queue.Enqueue(new NotificationItem(author, recipes.Distinct<string>(StringComparer.Ordinal).ToList())); } } internal static void Tick() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)SystemInfo.graphicsDeviceType == 4) { return; } Hud instance = Hud.instance; Player localPlayer = Player.m_localPlayer; if (!((Object)(object)instance != (Object)null) || !((Object)(object)localPlayer != (Object)null) || ((Character)localPlayer).IsDead() || ((Character)localPlayer).IsTeleporting() || !instance.IsVisible() || Hud.IsUserHidden() || InventoryGui.IsVisible() || Menu.IsVisible()) { SetVisible(visible: false); return; } if ((Object)(object)canvasObject == (Object)null || (Object)(object)ownerHud != (Object)(object)instance) { DestroyUi(); if (!CreateUi(instance)) { return; } } if (currentItem == null) { if (Queue.Count == 0) { SetVisible(visible: false); return; } currentItem = Queue.Dequeue(); currentTimer = 0f; DisplayCurrent(currentItem); Diagnostics.Info("ZR124", $"recipeNotification=shown count={currentItem.Recipes.Count}"); } currentTimer += Time.unscaledDeltaTime; float num; if (currentTimer < 0.3f) { num = Mathf.Clamp01(currentTimer / 0.3f); } else if (currentTimer < 4.7000003f) { num = 1f; } else if (currentTimer < 5.0000005f) { num = Mathf.Clamp01((5.0000005f - currentTimer) / 0.3f); } else { currentItem = null; num = 0f; } if ((Object)(object)panelGroup != (Object)null) { panelGroup.alpha = num; } SetVisible(num > 0.01f); } internal static void ResetSession() { Queue.Clear(); currentItem = null; currentTimer = 0f; DestroyUi(); } internal static void Uninstall() { ResetSession(); } private static bool CreateUi(Hud hud) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0072: Expected O, but got Unknown //IL_00b0: 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_0127: 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_0147: 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_0171: 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_01e7: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: 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) //IL_021c: 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_0278: 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_02a5: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_031