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 EpicLoot ProgressionFix v0.1.54
plugins/EpicLootProgressionFix.dll
Decompiled 8 minutes 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.Globalization; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Sockets; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Security.Authentication; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Common; using EpicLoot; using EpicLoot.Adventure; using EpicLoot.Biomes; using EpicLoot.Crafting; using EpicLoot.CraftingV2; using EpicLoot.Data; using EpicLoot.GatedItemType; using EpicLoot.Magic.MagicItemEffects; using EpicLoot.MagicItemEffects; using EpicLoot.MagicItemEffects.Shards; using EpicLoot.src.Magic.MagicItemEffects.Helpers; using EpicLoot_UnityLib; using HarmonyLib; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Splatform; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace EpicLootProgressionFix { internal static class AchievementDiscord { private static readonly HashSet<string> ObservedUnlocks = new HashSet<string>(); private static FieldInfo discordInstance; private static MethodInfo sendMessage; private static object chat; private static object defaultRoute; private static ManualLogSource logger; [ThreadStatic] private static int suppressedUnlocks; internal static void Initialize(Harmony harmony, ManualLogSource log) { //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Expected O, but got Unknown //IL_0170: Expected O, but got Unknown //IL_0170: Expected O, but got Unknown if (Chainloader.PluginInfos.TryGetValue("RustyMods.DiscordBot", out var value)) { logger = log; Assembly assembly = ((object)value.Instance).GetType().Assembly; Type type = assembly.GetType("DiscordBot.Discord"); Type type2 = assembly.GetType("DiscordBot.Webhook"); Type type3 = assembly.GetType("DiscordBot.WebhookRoute"); if (type == null || type2 == null || type3 == null) { throw new InvalidOperationException("DiscordBot achievement relay API changed."); } discordInstance = AccessTools.Field(type, "instance"); sendMessage = AccessTools.Method(type, "SendMessage", new Type[5] { type2, typeof(string), typeof(string), typeof(List<string>), type3 }, (Type[])null); if (discordInstance == null || sendMessage == null) { throw new InvalidOperationException("Achievement relay API changed."); } EnglishText.Initialize(); chat = Enum.Parse(type2, "Chat"); defaultRoute = Enum.Parse(type3, "Default"); harmony.Patch((MethodBase)AccessTools.Method(typeof(Achievements), "AchievementEvent", (Type[])null, (Type[])null), new HarmonyMethod(typeof(AchievementDiscord), "BeforeUnlock", (Type[])null), new HarmonyMethod(typeof(AchievementDiscord), "AfterUnlock", (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(AchievementDiscord), "AfterUnlockTree", (Type[])null), (HarmonyMethod)null); } } private static void BeforeUnlock(bool synchronize, out int __state) { __state = suppressedUnlocks; if (!synchronize) { suppressedUnlocks++; } } private static void AfterUnlockTree(int __state) { suppressedUnlocks = __state; } private static void AfterUnlock(Achievement ach) { if ((Object)(object)ach == (Object)null || !ObservedUnlocks.Add(ach.m_id) || suppressedUnlocks != 0 || !Plugin.DiscordAchievements.Value || !Plugin.Ready) { return; } Player localPlayer = Player.m_localPlayer; ZRpc val = (((Object)(object)ZNet.instance != (Object)null) ? ZNet.instance.GetServerRPC() : null); if ((Object)(object)localPlayer == (Object)null || val == null || !val.IsConnected()) { return; } try { object value = discordInstance.GetValue(null); if (value == null) { throw new InvalidOperationException("DiscordBot is not ready to relay the achievement."); } string text = English(ach.m_name); string text2 = English(ach.m_description); if (string.IsNullOrWhiteSpace(text) || string.IsNullOrWhiteSpace(text2)) { throw new InvalidOperationException("Achievement " + ach.m_id + " has no English name or requirement description."); } string text3 = PlainText(localPlayer.GetPlayerName()); string text4 = text3 + " earned the achievement \"" + text + "\" [" + text2 + "]"; sendMessage.Invoke(value, new object[5] { chat, text3, DiscordSystemMessages.Box(text4), null, defaultRoute }); } catch (Exception ex) { logger.LogError((object)("Could not announce achievement " + ach.m_id + ": " + ex.GetBaseException().Message)); } } private static string English(string text) { if (!EnglishText.TryTranslate(text, out var english)) { throw new InvalidOperationException("Missing English achievement text: " + english); } return PlainText(english); } private static string PlainText(string text) { text = Regex.Replace(text ?? "", "<[^>]*>", "").Replace("\\n", " "); return Regex.Replace(text, "\\s+", " ").Trim(); } } [HarmonyPatch(typeof(SE_CustomFinder), "UpdateStatusEffect")] internal static class AndvaranautTracking { private enum TargetFix { Circle, Located } private const float ScanInterval = 1f; private const float PingInterval = 5f; private const float TurnPingGap = 1.5f; private const float MinimumApproach = 2f; private const float TeleportDistance = 200f; private static readonly FieldRef<SE_Finder, Beacon> RingBeacon = AccessTools.FieldRefAccess<SE_Finder, Beacon>("m_beacon"); private static readonly FieldRef<List<Beacon>> Beacons = AccessTools.StaticFieldRefAccess<List<Beacon>>(AccessTools.Field(typeof(Beacon), "m_instances")); private static SE_CustomFinder finder; private static string targetKey; private static Vector3 targetPosition; private static TargetFix targetFix; private static bool beyondSearchRadius; private static bool pingedWhileFacing; private static float scanTimer; private static float checkTimer; private static float sincePing; private static Vector3 checkPosition; private static void Postfix(SE_CustomFinder __instance, float dt) { //IL_008f: 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_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: 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_0133: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)((StatusEffect)__instance).m_character != (Object)(object)localPlayer) { return; } List<Type> requiredComponentTypes = __instance.RequiredComponentTypes; if (requiredComponentTypes == null || !requiredComponentTypes.Contains(typeof(TreasureMapChest))) { return; } if ((Object)(object)__instance != (Object)(object)finder) { finder = __instance; targetKey = null; scanTimer = 1f; } sincePing += dt; if ((Object)(object)RingBeacon.Invoke((SE_Finder)(object)__instance) != (Object)null) { targetKey = null; return; } Vector3 position = ((Component)localPlayer).transform.position; bool flag = false; scanTimer += dt; if (scanTimer >= 1f) { scanTimer = 0f; string text = targetKey; TargetFix targetFix = AndvaranautTracking.targetFix; FindTarget(localPlayer, position); flag = targetKey != text || AndvaranautTracking.targetFix != targetFix; } if (targetKey != null) { float num = Utils.DistanceXZ(position, targetPosition); bool flag2 = num > Plugin.AndvaranautSearchRadius.Value; if (flag || flag2 != beyondSearchRadius) { beyondSearchRadius = flag2; pingedWhileFacing = false; checkTimer = 0f; checkPosition = position; } if (beyondSearchRadius) { PingWhenFacing((SE_Finder)(object)__instance, localPlayer, position); } else { PingWhenApproaching((SE_Finder)(object)__instance, localPlayer, position, num, dt); } } } private static void PingWhenFacing(SE_Finder ring, Player player, Vector3 position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) Vector3 lookDir = ((Character)player).GetLookDir(); Vector3 val = targetPosition - position; lookDir.y = 0f; val.y = 0f; float value = Plugin.AndvaranautFacingAngle.Value; if (value <= 0f || ((Vector3)(ref lookDir)).sqrMagnitude < 0.0001f || Vector3.Angle(lookDir, val) > value) { pingedWhileFacing = false; } else if (!(sincePing < (pingedWhileFacing ? 5f : 1.5f))) { Ping(ring, player); pingedWhileFacing = true; } } private static void PingWhenApproaching(SE_Finder ring, Player player, Vector3 position, float distance, float dt) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) checkTimer += dt; if (!(checkTimer < 5f)) { checkTimer = 0f; float num = Utils.DistanceXZ(checkPosition, position); float num2 = Utils.DistanceXZ(checkPosition, targetPosition) - distance; checkPosition = position; if (num <= 200f && num2 >= Mathf.Max(2f, num / 2f)) { Ping(ring, player); } } } private static void Ping(SE_Finder ring, Player player) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) Transform transform = ((Component)player).transform; ring.m_pingEffectFar.Create(transform.position, transform.rotation, transform, 1f, -1, ((Character)player).GetZDOID()); sincePing = 0f; } private static void FindTarget(Player player, Vector3 position) { //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0104: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) targetKey = null; float nearest = ((Plugin.AndvaranautMaxRange.Value > 0f) ? Plugin.AndvaranautMaxRange.Value : float.MaxValue); AdventureSaveData adventureSaveData = PlayerExtensions_Adventure.GetAdventureSaveData(player); long playerID = player.GetPlayerID(); foreach (TreasureMapChestInfo unfoundTreasureChest in adventureSaveData.GetUnfoundTreasureChests()) { Vector3 located; TargetFix targetFix = (LocateChest(unfoundTreasureChest, playerID, out located) ? TargetFix.Located : TargetFix.Circle); if (targetFix == TargetFix.Circle) { located = SerializableVector3.op_Implicit(unfoundTreasureChest.Position) + SerializableVector3.op_Implicit(unfoundTreasureChest.MinimapCircleOffset); } Consider($"treasure:{unfoundTreasureChest.Interval}:{unfoundTreasureChest.Biome}", located, targetFix, position, ref nearest); } foreach (BountyInfo inProgressBounty in adventureSaveData.GetInProgressBounties()) { Vector3 located2; TargetFix targetFix2 = (LocateBounty(inProgressBounty.ID, position, out located2) ? TargetFix.Located : TargetFix.Circle); if (targetFix2 == TargetFix.Circle) { located2 = SerializableVector3.op_Implicit(inProgressBounty.Position) + SerializableVector3.op_Implicit(inProgressBounty.MinimapCircleOffset); } Consider(inProgressBounty.ID, located2, targetFix2, position, ref nearest); } } private static void Consider(string key, Vector3 candidate, TargetFix fix, Vector3 position, ref float nearest) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) float num = Utils.DistanceXZ(position, candidate); if (!(num >= nearest)) { nearest = num; targetKey = key; targetPosition = candidate; targetFix = fix; } } private static bool LocateChest(TreasureMapChestInfo map, long playerId, out Vector3 located) { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) foreach (Beacon item in Beacons.Invoke()) { TreasureMapChest val = (((Object)(object)item != (Object)null) ? ((Component)item).GetComponent<TreasureMapChest>() : null); ZNetView val2 = (((Object)(object)val != (Object)null) ? ((Component)val).GetComponent<ZNetView>() : null); if (!((Object)(object)val2 == (Object)null) && val2.IsValid() && val.Interval == map.Interval && val.Biome == map.Biome && val2.GetZDO().GetLong("creator", 0L) == playerId) { located = ((Component)val).transform.position; return true; } } located = default(Vector3); return false; } private static bool LocateBounty(string bountyId, Vector3 position, out Vector3 located) { //IL_0007: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) float num = float.MaxValue; located = default(Vector3); foreach (Character allCharacter in Character.GetAllCharacters()) { ZNetView val = (((Object)(object)allCharacter != (Object)null && !allCharacter.IsDead()) ? ((Component)allCharacter).GetComponent<ZNetView>() : null); if (!((Object)(object)val == (Object)null) && val.IsValid() && !(val.GetZDO().GetString("BountyID", "") != bountyId)) { float num2 = Utils.DistanceXZ(position, ((Component)allCharacter).transform.position); if (!(num2 >= num)) { num = num2; located = ((Component)allCharacter).transform.position; } } } return num < float.MaxValue; } } [HarmonyPatch] internal static class KeepBountyBeacons { private static MethodBase TargetMethod() { return AccessTools.Method(typeof(BountyTarget).Assembly.GetType("EpicLoot.Adventure.BountyTargetComponent+Character_OnDamaged_Patch"), "Postfix", (Type[])null, (Type[])null) ?? throw new InvalidOperationException("EpicLoot's bounty beacon removal moved."); } private static bool Prefix() { return false; } } [HarmonyPatch(typeof(AutoMeads), "OnIncomingHit")] internal static class AutomaticMeadPrediction { private static bool Prefix() { return false; } } [HarmonyPatch(typeof(Character), "ApplyDamage")] internal static class AutomaticMeadConsumption { private static void Prefix(Character __instance, out float __state) { __state = (((Object)(object)__instance == (Object)(object)Player.m_localPlayer) ? __instance.GetHealth() : 0f); } private static void Postfix(Character __instance, float __state) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val == null || (Object)(object)val != (Object)(object)Player.m_localPlayer) { return; } float health = ((Character)val).GetHealth(); if (health <= 0f || health >= __state || ((Character)val).IsDead() || !PlayerExtensions.HasActiveMagicEffect(val, MagicEffectType.AutoMead) || !ModifyWithLowHealth.PlayerHasLowHealth(val)) { return; } Inventory inventory = ((Humanoid)val).GetInventory(); if (inventory == null) { return; } SEMan sEMan = ((Character)val).GetSEMan(); foreach (ItemData item in inventory.GetAllItemsOfType((ItemType)2, false)) { if (AutoMeads.HasHealthRegen(item)) { StatusEffect consumeStatusEffect = item.m_shared.m_consumeStatusEffect; if (!sEMan.HaveStatusEffect(consumeStatusEffect.NameHash()) && !sEMan.HaveStatusEffectCategory(consumeStatusEffect.m_category) && ((Humanoid)val).ConsumeItem(inventory, item, false)) { break; } } } } } internal static class BlockAfterArmor { private static readonly Func<Character, short, WeakSpot> WeakSpotOf = AccessTools.MethodDelegate<Func<Character, short, WeakSpot>>(AccessTools.Method(typeof(Character), "GetWeakSpot", (Type[])null, (Type[])null), (object)null, true); private static HitData reducedHit; private static DamageModifier reducedHitModifier; internal static void Initialize(Harmony harmony) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown harmony.Patch((MethodBase)AccessTools.Method(typeof(Humanoid), "BlockAttack", (Type[])null, (Type[])null), new HarmonyMethod(typeof(BlockAfterArmor), "ReduceBeforeBlock", (Type[])null) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(Character), "RPC_Damage", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(BlockAfterArmor), "ReduceOnce", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); } private static void ReduceBeforeBlock(Humanoid __instance, HitData hit) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val != null) { BlockedHits.ConvertBeforeBlock(val, hit); hit.ApplyResistance(((Character)val).GetDamageModifiers(WeakSpotOf((Character)(object)val, hit.m_weakSpot)), ref reducedHitModifier); hit.ApplyArmor(((Character)val).GetBodyArmor()); reducedHit = hit; } } private static void ApplyResistance(HitData hit, DamageModifiers modifiers, out DamageModifier significantModifier) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Expected I4, but got Unknown if (hit == reducedHit) { significantModifier = (DamageModifier)(int)reducedHitModifier; } else { hit.ApplyResistance(modifiers, ref significantModifier); } } private static void ApplyArmor(HitData hit, float armor) { if (hit == reducedHit) { reducedHit = null; } else { hit.ApplyArmor(armor); } } private static IEnumerable<CodeInstruction> ReduceOnce(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> code = instructions.ToList(); MethodInfo block = AccessTools.Method(typeof(Character), "BlockAttack", (Type[])null, (Type[])null); MethodInfo resistance = AccessTools.Method(typeof(HitData), "ApplyResistance", new Type[2] { typeof(DamageModifiers), typeof(DamageModifier).MakeByRefType() }, (Type[])null); MethodInfo armor = AccessTools.Method(typeof(HitData), "ApplyArmor", new Type[1] { typeof(float) }, (Type[])null); int num = code.FindIndex((CodeInstruction instruction) => CodeInstructionExtensions.Calls(instruction, block)); List<int> list = (from i in Enumerable.Range(0, code.Count) where CodeInstructionExtensions.Calls(code[i], resistance) select i).ToList(); List<int> list2 = (from i in Enumerable.Range(0, code.Count) where CodeInstructionExtensions.Calls(code[i], armor) select i).ToList(); if (num < 0 || list.Count != 1 || list2.Count != 2 || list[0] < num || list2[0] < list[0]) { throw new InvalidOperationException("Valheim's hit order changed; expected the block before one resistance and two armor steps."); } code[list[0]].opcode = OpCodes.Call; code[list[0]].operand = AccessTools.Method(typeof(BlockAfterArmor), "ApplyResistance", (Type[])null, (Type[])null); foreach (int item in list2) { code[item].opcode = OpCodes.Call; code[item].operand = AccessTools.Method(typeof(BlockAfterArmor), "ApplyArmor", (Type[])null, (Type[])null); } return code; } } [HarmonyPatch] internal static class BlockedHits { [HarmonyPatch(typeof(AvoidDamageTaken_Character_RPC_Damage_Patch), "ShouldTakeDamage")] private static class NoFeintWhileBlocking { private static bool Prefix(Character __0, HitData hit, ref bool __result) { if (hit == null || !WillBlock(__0, hit) || !__0.HaveStamina(0f)) { return true; } __result = true; return false; } } internal static readonly Func<Humanoid, ItemData> CurrentBlocker = AccessTools.MethodDelegate<Func<Humanoid, ItemData>>(AccessTools.Method(typeof(Humanoid), "GetCurrentBlocker", (Type[])null, (Type[])null), (object)null, true); internal static bool WillBlock(Character character, HitData hit) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) Humanoid val = (Humanoid)(object)((character is Humanoid) ? character : null); if (val != null && hit.m_blockable && ((Character)val).IsBlocking() && Vector3.Dot(hit.m_dir, ((Component)val).transform.forward) <= 0f) { return CurrentBlocker(val) != null; } return false; } [HarmonyPatch(typeof(IncomingPhysicalConversion), "ModifyIncoming")] [HarmonyPrefix] private static bool GeneralConversionOnly(bool IsBlocked) { return !IsBlocked; } internal static void ConvertBeforeBlock(Player player, HitData hit) { if ((Object)(object)player != (Object)(object)Player.m_localPlayer || !WillBlock((Character)(object)player, hit)) { return; } float totalActiveMagicEffectValue = PlayerExtensions.GetTotalActiveMagicEffectValue(player, MagicEffectType.PhysToFireOnBlock, 0.01f, (ItemData)null); float totalActiveMagicEffectValue2 = PlayerExtensions.GetTotalActiveMagicEffectValue(player, MagicEffectType.PhysToFrostOnBlock, 0.01f, (ItemData)null); float totalActiveMagicEffectValue3 = PlayerExtensions.GetTotalActiveMagicEffectValue(player, MagicEffectType.PhysToPoisonOnBlock, 0.01f, (ItemData)null); float totalActiveMagicEffectValue4 = PlayerExtensions.GetTotalActiveMagicEffectValue(player, MagicEffectType.PhysToLightningOnBlock, 0.01f, (ItemData)null); float num = totalActiveMagicEffectValue + totalActiveMagicEffectValue2 + totalActiveMagicEffectValue3 + totalActiveMagicEffectValue4; float num2 = hit.m_damage.m_blunt + hit.m_damage.m_slash + hit.m_damage.m_pierce; if (!(num <= 0f) && !(num2 <= 0f)) { float num3 = 1f - PlayerExtensions.GetTotalActiveMagicEffectValue(player, MagicEffectType.PhysToFire, 0.01f, (ItemData)null) - PlayerExtensions.GetTotalActiveMagicEffectValue(player, MagicEffectType.PhysToFrost, 0.01f, (ItemData)null) - PlayerExtensions.GetTotalActiveMagicEffectValue(player, MagicEffectType.PhysToPoison, 0.01f, (ItemData)null) - PlayerExtensions.GetTotalActiveMagicEffectValue(player, MagicEffectType.PhysToLightning, 0.01f, (ItemData)null); if (!(num3 <= 0f)) { float num4 = Mathf.Min(1f, num / num3); float num5 = num2 * num4 / num; hit.m_damage.m_fire += num5 * totalActiveMagicEffectValue; hit.m_damage.m_frost += num5 * totalActiveMagicEffectValue2; hit.m_damage.m_poison += num5 * totalActiveMagicEffectValue3; hit.m_damage.m_lightning += num5 * totalActiveMagicEffectValue4; hit.m_damage.m_blunt *= 1f - num4; hit.m_damage.m_slash *= 1f - num4; hit.m_damage.m_pierce *= 1f - num4; } } } } internal static class BonusHits { [HarmonyPatch] private static class StrikeMultipliers { internal static readonly ConditionalWeakTable<HitData, StrongBox<float>> Factors = new ConditionalWeakTable<HitData, StrongBox<float>>(); private static IEnumerable<MethodBase> TargetMethods() { return Required(AccessTools.Method(typeof(ChanceToCritOnHit), "ModifyOutgoingHit", (Type[])null, (Type[])null), AccessTools.Method(typeof(ChanceDoubleDamage), "ModifyOutgoingHit", (Type[])null, (Type[])null)); } private static void Prefix(HitData hit, out float __state) { __state = ((hit == null) ? 0f : hit.GetTotalDamage()); } private static void Postfix(HitData hit, float __state) { if (hit == null || !(__state > 0f)) { return; } float totalDamage = hit.GetTotalDamage(); if (totalDamage != __state && totalDamage > 0f) { if (!Factors.TryGetValue(hit, out var value)) { value = new StrongBox<float>(1f); Factors.Add(hit, value); } value.Value *= totalDamage / __state; } } } [HarmonyPatch] private static class BeforeStrikeMultipliers { private static IEnumerable<MethodBase> TargetMethods() { return Required(AccessTools.Method(typeof(MeteorSummoner), "OnDamageDealt", (Type[])null, (Type[])null), AccessTools.Method(typeof(EikthyrShockingCharge), "OnDamageDealt", (Type[])null, (Type[])null)); } private static void Prefix(HitData hit, out DamageTypes? __state) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) __state = null; if (hit != null && StrikeMultipliers.Factors.TryGetValue(hit, out var value) && value.Value > 0f) { __state = hit.m_damage; ((DamageTypes)(ref hit.m_damage)).Modify(1f / value.Value); } } private static void Finalizer(HitData hit, DamageTypes? __state) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) if (hit != null && __state.HasValue) { hit.m_damage = __state.Value; } } } private static IEnumerable<MethodBase> Required(params MethodBase[] methods) { if (methods.Any((MethodBase method) => method == null)) { throw new InvalidOperationException("EpicLoot's crit, double damage, meteor or charge moved."); } return methods; } } internal static class BountyTargetStrength { private static readonly int BountyIdKey = StringExtensionMethods.GetStableHashCode("BountyID"); private static readonly int BountyDataKey = StringExtensionMethods.GetStableHashCode("BountyData"); private static readonly int IsAddKey = StringExtensionMethods.GetStableHashCode("IsAdd"); private static readonly FieldRef<Character, ZNetView> NetViewOf = AccessTools.FieldRefAccess<Character, ZNetView>("m_nview"); private static readonly Func<BountyInfo, bool, float> HealthModifier = AccessTools.MethodDelegate<Func<BountyInfo, bool, float>>(AccessTools.Method(typeof(BountyTarget), "GetMaxHealthModifier", (Type[])null, (Type[])null), (object)null, true); private static PropertyInfo baseValuesOf; private static object baseHealth; internal static void Initialize(Harmony harmony) { //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Expected O, but got Unknown //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Expected O, but got Unknown //IL_01c4: Expected O, but got Unknown if (Chainloader.PluginInfos.TryGetValue("MidnightsFX.StarLevelSystem", out var value)) { Assembly assembly = ((object)value.Instance).GetType().Assembly; Type type = assembly.GetType("StarLevelSystem.Data.CompositeLazyCache"); Type type2 = assembly.GetType("StarLevelSystem.common.DataObjects+CharacterCacheEntry"); Type type3 = assembly.GetType("StarLevelSystem.common.DataObjects+CreatureBaseAttribute"); Type type4 = assembly.GetType("StarLevelSystem.modules.Modifiers.CreatureModifiers"); MethodInfo methodInfo = ((type2 == null) ? null : AccessTools.Method(type, "ApplyPersistedStatOverrides", new Type[2] { typeof(ZDO), type2 }, (Type[])null)); baseValuesOf = AccessTools.Property(type2, "CreatureBaseValueModifiers"); baseHealth = ((type3 != null && Enum.IsDefined(type3, "BaseHealth")) ? Enum.Parse(type3, "BaseHealth") : null); MethodInfo[] array = new MethodInfo[4] { AccessTools.Method(type, "GetAndSetLocalCache", (Type[])null, (Type[])null), AccessTools.Method(assembly.GetType("StarLevelSystem.modules.Damage.DamagePatches+ModifyDamagePerLevel"), "DetermineDamageFactor", (Type[])null, (Type[])null), AccessTools.Method(type4, "SelectModifiersForCreature", (Type[])null, (Type[])null), AccessTools.Method(type4, "TryRollEvolutionModifier", (Type[])null, (Type[])null) }; if (methodInfo == null || baseValuesOf == null || baseHealth == null || array.Any((MethodInfo method) => method == null || method.GetParameters().FirstOrDefault()?.ParameterType != typeof(Character))) { throw new InvalidOperationException("StarLevelSystem's creature stats changed."); } Type typeFromHandle = typeof(BountyTargetStrength); harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeFromHandle, "RestoreBonus", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); MethodInfo[] array2 = array; foreach (MethodInfo methodInfo2 in array2) { harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeFromHandle, "AsOrdinary", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeFromHandle, "AsBoss", (Type[])null), (HarmonyMethod)null); } } } private static void RestoreBonus(ZDO __0, object __1) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown string text = ((__0 == null || __1 == null) ? "" : __0.GetString(BountyDataKey, "")); if (text.Length != 0) { BountyInfo arg; try { arg = BountyInfo.FromPackage(new ZPackage(text)); } catch (Exception) { return; } ((IDictionary)baseValuesOf.GetValue(__1))[baseHealth] = HealthModifier(arg, __0.GetBool(IsAddKey, false)); } } private static void AsOrdinary(Character __0, out bool __state) { ZNetView val = (((Object)(object)__0 != (Object)null && __0.m_boss) ? NetViewOf.Invoke(__0) : null); ZDO val2 = (((Object)(object)val != (Object)null) ? val.GetZDO() : null); __state = val2 != null && val2.GetString(BountyIdKey, "").Length > 0; if (__state) { __0.m_boss = false; } } private static void AsBoss(Character __0, bool __state) { if (__state) { __0.m_boss = true; } } } [HarmonyPatch] internal static class BowAmmoDamage { private delegate void EnchantmentModifier(Player player, ItemData item, ref DamageTypes damage); private delegate void ShardModifier(ItemData item, ref DamageTypes damage); private static readonly EnchantmentModifier ApplyEnchantments = AccessTools.MethodDelegate<EnchantmentModifier>(AccessTools.Method(typeof(ModifyDamage), "ApplyMagicDamageModifiers", (Type[])null, (Type[])null), (object)null, true); private static readonly ShardModifier ApplyShards = AccessTools.MethodDelegate<ShardModifier>(AccessTools.Method(typeof(ModifyDamage), "ApplyShardWeaponModifiers", (Type[])null, (Type[])null), (object)null, true); private static readonly FieldRef<Attack, Humanoid> CharacterOf = AccessTools.FieldRefAccess<Attack, Humanoid>("m_character"); private static readonly FieldRef<Attack, ItemData> AmmoOf = AccessTools.FieldRefAccess<Attack, ItemData>("m_ammoItem"); private static ItemData firingWeapon; private static ItemData firingAmmo; private static DamageTypes? ammoDamage; [HarmonyPatch(typeof(Attack), "FireProjectileBurst")] [HarmonyPrefix] private static void Fire(Attack __instance) { Player localPlayer = Player.m_localPlayer; ItemData weapon = __instance.GetWeapon(); ItemData val = AmmoOf.Invoke(__instance); if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)CharacterOf.Invoke(__instance) != (Object)(object)localPlayer) && weapon != null && val != null && val != weapon && !ItemDataExtensions.IsMagic(val)) { firingWeapon = weapon; firingAmmo = val; } } [HarmonyPatch(typeof(Attack), "FireProjectileBurst")] [HarmonyFinalizer] private static void Fired() { firingWeapon = (firingAmmo = null); ammoDamage = null; } [HarmonyPatch(typeof(ItemData), "GetDamage", new Type[] { typeof(int), typeof(float) })] [HarmonyPostfix] [HarmonyPriority(800)] private static void KeepAmmoDamage(ItemData __instance, DamageTypes __result) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (__instance == firingAmmo && firingAmmo != null) { ammoDamage = __result; } } [HarmonyPatch(typeof(ItemData), "GetDamage", new Type[] { typeof(int), typeof(float) })] [HarmonyPostfix] [HarmonyPriority(0)] private static void UseWeaponModifiers(ItemData __instance, ref DamageTypes __result) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) if (__instance == firingAmmo && firingAmmo != null && ammoDamage.HasValue) { __result = ammoDamage.Value; ammoDamage = null; ApplyEnchantments(Player.m_localPlayer, firingWeapon, ref __result); ApplyShards(firingWeapon, ref __result); } } } [HarmonyPatch(typeof(BulkupEffect), "GetHealthRegenWithBulkUp")] internal static class BulkUpRegen { private static bool Prefix(float regen, ref float __result) { float num = default(float); __result = (PlayerExtensions.HasActiveMagicEffect(Player.m_localPlayer, MagicEffectType.BulkUp, ref num, 0.01f, (ItemData)null) ? (regen * (1f - Mathf.Clamp01(num))) : regen); return false; } } [HarmonyPatch] internal static class ChainLightningJumps { private static readonly FieldRef<Aoe, Character> OwnerOf = AccessTools.FieldRefAccess<Aoe, Character>("m_owner"); private static readonly FieldRef<Aoe, HitData> SettingsOf = AccessTools.FieldRefAccess<Aoe, HitData>("m_hitData"); private static readonly FieldRef<Aoe, float> ChainChanceOf = AccessTools.FieldRefAccess<Aoe, float>("m_chainChance"); private static readonly FieldRef<Aoe, int> StatusEffectOf = AccessTools.FieldRefAccess<Aoe, int>("m_statusEffectHash"); private static readonly ConditionalWeakTable<HitData, object> Chains = new ConditionalWeakTable<HitData, object>(); private static readonly object Chain = new object(); [HarmonyPatch(typeof(ChainLightning), "TriggerChainLightningEffect")] [HarmonyPrefix] private static bool Strike(Character target, Player player) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Expected O, but got Unknown GameObject prefab = ZNetScene.instance.GetPrefab("ChainLightning"); Aoe val = (((Object)(object)prefab == (Object)null) ? null : Object.Instantiate<GameObject>(prefab, ((Component)target).transform.position, Quaternion.identity).GetComponent<Aoe>()); if ((Object)(object)val == (Object)null) { return false; } HitSource.MarkBonusSource(((Component)val).gameObject); OwnerOf.Invoke(val) = (Character)(object)player; ChainChanceOf.Invoke(val) = 0.8f; val.m_chainStartChanceFalloff = 0.8f; val.m_damage.m_lightning *= PlayerExtensions.GetTotalActiveMagicEffectValue(player, MagicEffectType.ChainLightning, 0.01f, (ItemData)null); HitData val2 = new HitData { m_damage = val.m_damage, m_blockable = val.m_blockable, m_dodgeable = val.m_dodgeable, m_pushForce = val.m_attackForce, m_backstabBonus = val.m_backstabBonus, m_statusEffectHash = StatusEffectOf.Invoke(val), m_toolTier = (short)val.m_toolTier, m_skill = (SkillType)999 }; SettingsOf.Invoke(val) = val2; Chains.Add(val2, Chain); return false; } [HarmonyPatch(typeof(Aoe), "CustomFixedUpdate")] [HarmonyPrefix] private static void RollChainChance(Aoe __instance) { if (__instance.m_chainStartChance > 0f && (Object)(object)__instance.m_chainObj != (Object)null && IsChain(__instance)) { __instance.m_chainStartChance = ChainChanceOf.Invoke(__instance); } } internal static bool IsChain(Aoe aoe) { HitData val = SettingsOf.Invoke(aoe); object value; if (val != null) { return Chains.TryGetValue(val, out value); } return false; } } internal static class ChestSupplySwitch { private delegate bool ContainerSwitch(Container container, Humanoid character, bool hold, bool alt, ref bool handled); private const KeyCode Key = (KeyCode)108; private const string UseKeyText = " + $KEY_Use</b></color>] $hud_crafting $piece_chestwood "; private static ContainerSwitch switchContainer; private static Func<Player, bool> takeInput; private static bool switching; internal static void Initialize(Harmony harmony, ManualLogSource log) { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Expected O, but got Unknown //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Expected O, but got Unknown //IL_01ae: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Expected O, but got Unknown if (!Chainloader.PluginInfos.TryGetValue("Azumatt.AzuCraftyBoxes", out var value)) { return; } Assembly assembly = ((object)value.Instance).GetType().Assembly; MethodInfo methodInfo = AccessTools.Method(assembly.GetType("AzuCraftyBoxes.Patches.ChestBlockInteraction"), "Prefix", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(assembly.GetType("AzuCraftyBoxes.Patches.CraftyToggle"), "HoverLine", new Type[1] { typeof(bool) }, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(typeof(Player), "TakeInput", Type.EmptyTypes, (Type[])null); if (methodInfo == null || methodInfo2 == null || methodInfo3 == null) { throw new InvalidOperationException("AzuCraftyBoxes' chest switch moved."); } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(ChestSupplySwitch), "OnlyOnSwitchKey", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(ChestSupplySwitch), "ShowSwitchKey", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(Player), "Update", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(ChestSupplySwitch), "SwitchOnKey", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); switchContainer = AccessTools.MethodDelegate<ContainerSwitch>(methodInfo, (object)null, true); takeInput = AccessTools.MethodDelegate<Func<Player, bool>>(methodInfo3, (object)null, true); if (Chainloader.PluginInfos.TryGetValue("goldenrevolver.quick_stack_store", out var value2)) { MethodInfo methodInfo4 = AccessTools.Method(((object)value2.Instance).GetType().Assembly.GetType("QuickStackStore.KeybindChecker"), "IsKeyDown", new Type[1] { typeof(KeyboardShortcut) }, (Type[])null); if (methodInfo4 == null) { throw new InvalidOperationException("Quick Stack's hotkey check moved."); } harmony.Patch((MethodBase)methodInfo4, new HarmonyMethod(typeof(ChestSupplySwitch), "NotOnSwitchKey", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } log.LogInfo((object)"AzuCraftyBoxes' chest supply switch is on Shift + L instead of Shift + E."); } private static bool OnKeyboard() { return !ZInput.IsGamepadActive(); } private static void OnlyOnSwitchKey(ref bool __3) { if (!switching && OnKeyboard()) { __3 = false; } } private static void SwitchOnKey(Player __instance) { if ((Object)(object)__instance != (Object)(object)Player.m_localPlayer || !Input.GetKeyDown((KeyCode)108) || !ZInput.GetButton("AltPlace") || !OnKeyboard() || !takeInput(__instance)) { return; } GameObject hoverObject = ((Humanoid)__instance).GetHoverObject(); Container val = (((Object)(object)hoverObject == (Object)null) ? null : hoverObject.GetComponentInParent<Container>()); if ((Object)(object)val == (Object)null) { return; } bool handled = false; switching = true; try { switchContainer(val, (Humanoid)(object)__instance, hold: false, alt: true, ref handled); } finally { switching = false; } } private static IEnumerable<CodeInstruction> ShowSwitchKey(IEnumerable<CodeInstruction> instructions) { List<CodeInstruction> list = instructions.ToList(); List<CodeInstruction> list2 = list.Where((CodeInstruction instruction) => instruction.opcode == OpCodes.Ldstr && (string)instruction.operand == " + $KEY_Use</b></color>] $hud_crafting $piece_chestwood ").ToList(); if (list2.Count != 1) { throw new InvalidOperationException("AzuCraftyBoxes' chest switch hover text changed."); } list2[0].opcode = OpCodes.Call; list2[0].operand = AccessTools.Method(typeof(ChestSupplySwitch), "SwitchKeyText", (Type[])null, (Type[])null); return list; } private static string SwitchKeyText() { //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (!OnKeyboard()) { return " + $KEY_Use</b></color>] $hud_crafting $piece_chestwood "; } return " + $KEY_Use</b></color>] $hud_crafting $piece_chestwood ".Replace("$KEY_Use", ((object)(KeyCode)108/*cast due to .constrained prefix*/).ToString()); } private static bool NotOnSwitchKey(KeyboardShortcut __0, ref bool __result) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 if ((int)((KeyboardShortcut)(ref __0)).MainKey != 108 || ((KeyboardShortcut)(ref __0)).Modifiers.Any() || !ZInput.GetButton("AltPlace")) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(CoinHoarder), "GetCoinHoarderValue")] internal static class CoinHoarderBonus { private static readonly Func<Player, int> TotalCoins = AccessTools.MethodDelegate<Func<Player, int>>(AccessTools.Method(typeof(CoinHoarder).Assembly.GetType("EpicLoot.General.CoinPurse"), "GetTotalCoins", new Type[1] { typeof(Player) }, (Type[])null), (object)null, true); private static bool Prefix(Player player, float effectValue, ref float __result) { if ((Object)(object)player == (Object)null) { return true; } float num = TotalCoins(player); if (num > 1000f) { return true; } __result = ((num <= 0f || effectValue <= 0f) ? 0f : (num / 1000f * (Mathf.Log10(effectValue * 1000f) * 6.258f / 150f))); return false; } } internal static class ComfortRoomPanel { private static FieldRef<Player, PieceTable> placeModePieces; internal static void Initialize(Harmony harmony, ManualLogSource log) { //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Expected O, but got Unknown if (Chainloader.PluginInfos.TryGetValue("hardwire99.comfortme", out var value)) { Type type = ((object)value.Instance).GetType().Assembly.GetType("ComfortMe.HudUi"); MethodInfo methodInfo = ((type == null) ? null : AccessTools.Method(type, "HoldingPlaceTool", Type.EmptyTypes, (Type[])null)); if (methodInfo == null || !methodInfo.IsStatic || methodInfo.ReturnType != typeof(bool)) { throw new InvalidOperationException("ComfortMe's build tool check moved."); } placeModePieces = AccessTools.FieldRefAccess<Player, PieceTable>("m_buildPieces"); harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(ComfortRoomPanel), "OnlyWithHammer", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); log.LogInfo((object)"ComfortMe's This room panel shows only with the hammer."); } } private static void OnlyWithHammer(ref bool __result) { if (__result) { Player localPlayer = Player.m_localPlayer; PieceTable val = (((Object)(object)localPlayer != (Object)null) ? placeModePieces.Invoke(localPlayer) : null); __result = (Object)(object)val != (Object)null && ((Object)val).name == PieceTables.Hammer; } } } [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] internal static class CraftingBonus { private static readonly FieldRef<InventoryGui, Recipe> CraftRecipe = AccessTools.FieldRefAccess<InventoryGui, Recipe>("m_craftRecipe"); private static readonly FieldRef<InventoryGui, ItemData> CraftUpgradeItem = AccessTools.FieldRefAccess<InventoryGui, ItemData>("m_craftUpgradeItem"); internal static void Initialize(Harmony harmony, ManualLogSource logger) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown if (Chainloader.PluginInfos.TryGetValue("Azumatt.AzuAntiArthriticCrafting", out var value)) { MethodInfo methodInfo = AccessTools.Method(((object)value.Instance)?.GetType().Assembly.GetType("AzuAntiArthriticCrafting.Patches.SequentialSkillBonus"), "Postfix", (Type[])null, (Type[])null); if (methodInfo == null) { throw new InvalidOperationException("AAA_Crafting's sequential skill bonus changed."); } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(CraftingBonus), "SkipStreak", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); logger.LogInfo((object)"AAA_Crafting's sequential bonus streak is disabled; each crafting bonus adds one full craft."); } } private static bool SkipStreak() { return false; } private static int BonusPerRoll(int bonusAmount, InventoryGui gui, int amount) { Recipe val = CraftRecipe.Invoke(gui); ItemData val2 = CraftUpgradeItem.Invoke(gui); int num2 = default(int); ItemData val3 = default(ItemData); int num = bonusAmount * val.GetAmount((val2 == null) ? 1 : (val2.m_quality + 1), ref num2, ref val3, 1); if (val2 == null && !((Humanoid)Player.m_localPlayer).GetInventory().CanAddItem(((Component)val.m_item).gameObject, amount + num)) { return 0; } return num; } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions, ILGenerator generator) { //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Expected O, but got Unknown //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Expected O, but got Unknown //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Expected O, but got Unknown //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Expected O, but got Unknown //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01cd: Expected O, but got Unknown List<CodeInstruction> list = instructions.ToList(); FieldInfo bonusAmount = AccessTools.Field(typeof(InventoryGui), "m_craftBonusAmount"); int num = list.FindIndex((CodeInstruction x) => CodeInstructionExtensions.LoadsField(x, bonusAmount, false)); if (num < 0 || list.FindLastIndex((CodeInstruction x) => CodeInstructionExtensions.LoadsField(x, bonusAmount, false)) != num || num + 6 >= list.Count || list[num + 1].opcode != OpCodes.Add || !CodeInstructionExtensions.IsStloc(list[num + 2], (LocalBuilder)null) || !CodeInstructionExtensions.IsLdloc(list[num + 3], (LocalBuilder)null) || !CodeInstructionExtensions.IsLdloc(list[num + 4], (LocalBuilder)null) || !SameLocal(list[num + 4], list[num + 2]) || list[num + 5].opcode != OpCodes.Add || !CodeInstructionExtensions.IsStloc(list[num + 6], (LocalBuilder)null) || !SameLocal(list[num + 6], list[num + 3])) { throw new InvalidOperationException("Valheim's crafting bonus changed; expected one bonus accumulation."); } LocalBuilder localBuilder = generator.DeclareLocal(typeof(int)); list[num + 4].opcode = OpCodes.Ldloc; list[num + 4].operand = localBuilder; list.InsertRange(num + 1, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[5] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(list[num + 3].opcode, list[num + 3].operand), new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(CraftingBonus), "BonusPerRoll", (Type[])null, (Type[])null)), new CodeInstruction(OpCodes.Dup, (object)null), new CodeInstruction(OpCodes.Stloc, (object)localBuilder) }); return list; } private static bool SameLocal(CodeInstruction first, CodeInstruction second) { if (first.operand is LocalVariableInfo localVariableInfo && second.operand is LocalVariableInfo localVariableInfo2) { return localVariableInfo.LocalIndex == localVariableInfo2.LocalIndex; } return false; } } internal static class CraftingHistory { private sealed class MigrationRecord { [JsonProperty(/*Could not decode attribute arguments.*/)] public int Version = 1; [JsonProperty(/*Could not decode attribute arguments.*/)] public string[] Items = Array.Empty<string>(); } private const string StateKey = "valheim.epiclootprogressionfix.crafting-migration"; private static readonly FieldRef<Player, HashSet<string>> KnownMaterials = AccessTools.FieldRefAccess<Player, HashSet<string>>("m_knownMaterial"); private static readonly FieldRef<PlayerProfile, byte[]> SavedPlayerData = AccessTools.FieldRefAccess<PlayerProfile, byte[]>("m_playerData"); private static readonly JsonSerializerSettings JsonSettings = new JsonSerializerSettings { TypeNameHandling = (TypeNameHandling)0 }; private static FieldInfo acquireCharacterFromTemplate; private static ManualLogSource logger; private static Player owner; private static PlayerProfile profile; private static HashSet<string> legacyCredits; private static bool spawning; private static bool freshCharacter; private static ZNetScene conversionScene; private static Dictionary<string, HashSet<string>> conversionSources; internal static string Problem { get; private set; } internal static void Initialize(Harmony harmony, ManualLogSource log) { //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown logger = log; if (Chainloader.PluginInfos.TryGetValue("org.bepinex.plugins.servercharacters", out var value)) { if (value.Metadata.Version != new Version(1, 4, 17)) { throw new InvalidOperationException("Crafting migration requires ServerCharacters 1.4.17 when installed."); } acquireCharacterFromTemplate = AccessTools.Field(((object)value.Instance).GetType().Assembly.GetType("ServerCharacters.ClientSide", throwOnError: true), "acquireCharacterFromTemplate"); if (acquireCharacterFromTemplate == null || !acquireCharacterFromTemplate.IsStatic || acquireCharacterFromTemplate.FieldType != typeof(bool)) { throw new MissingFieldException("ServerCharacters character initialization changed."); } } MethodInfo methodInfo = AccessTools.Method(typeof(Game), "SpawnPlayer", (Type[])null, (Type[])null); HarmonyMethod obj = Patch("BeforeSpawn"); HarmonyMethod val = new HarmonyMethod(typeof(CraftingHistory), "AfterSpawn", (Type[])null); val.priority = 0; val.after = new string[1] { "org.bepinex.plugins.servercharacters" }; harmony.Patch((MethodBase)methodInfo, obj, val, (HarmonyMethod)null, Patch("SpawnFailed"), (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(Player), "Load", (Type[])null, (Type[])null), Patch("BeforeLoad"), Patch("AfterLoad"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(Player), "Save", (Type[])null, (Type[])null), Patch("BeforeSave"), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static HarmonyMethod Patch(string name) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Expected O, but got Unknown return new HarmonyMethod(typeof(CraftingHistory), name, (Type[])null); } private static void Reset() { owner = null; profile = null; legacyCredits = null; Problem = null; } private static void BeforeSpawn() { Reset(); spawning = true; freshCharacter = SavedPlayerData.Invoke(Game.instance.GetPlayerProfile()) == null || (acquireCharacterFromTemplate != null && (bool)acquireCharacterFromTemplate.GetValue(null)); } private static void AfterSpawn() { spawning = false; Attach(freshCharacter); } private static void SpawnFailed(Exception __exception) { if (__exception != null) { spawning = false; Reset(); } } private static void BeforeLoad(Player __instance) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer) { Reset(); } } private static void AfterLoad(Player __instance) { if (!spawning && (Object)(object)__instance == (Object)(object)Player.m_localPlayer) { Attach(fresh: false); } } private static void BeforeSave(Player __instance) { if (spawning && freshCharacter && (Object)(object)__instance == (Object)(object)Player.m_localPlayer && !__instance.m_customData.ContainsKey("valheim.epiclootprogressionfix.crafting-migration")) { __instance.m_customData["valheim.epiclootprogressionfix.crafting-migration"] = JsonConvert.SerializeObject((object)new MigrationRecord(), JsonSettings); } } private static bool CreationRecipe(Recipe recipe) { if ((Object)(object)recipe != (Object)null && (Object)(object)recipe.m_item != (Object)null && recipe.m_amount > 0) { if (!((Object)(object)recipe.m_craftingStation == (Object)null)) { return !recipe.m_craftingStation.m_upgrader; } return true; } return false; } private static void Attach(bool fresh) { Reset(); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } try { PlayerProfile playerProfile = Game.instance.GetPlayerProfile(); if (playerProfile.GetPlayerID() != localPlayer.GetPlayerID()) { throw new InvalidOperationException("The loaded character does not match its crafting profile."); } HashSet<string> hashSet; if (localPlayer.m_customData.TryGetValue("valheim.epiclootprogressionfix.crafting-migration", out var value)) { MigrationRecord migrationRecord = JsonConvert.DeserializeObject<MigrationRecord>(value, JsonSettings); if (migrationRecord == null || migrationRecord.Version != 1 || migrationRecord.Items == null || migrationRecord.Items.Any(string.IsNullOrEmpty)) { throw new InvalidDataException("Invalid saved crafting migration; original data has been left intact."); } hashSet = new HashSet<string>(migrationRecord.Items, StringComparer.Ordinal); } else { hashSet = new HashSet<string>(StringComparer.Ordinal); if (!fresh) { ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null || !instance.m_recipes.Any(CreationRecipe)) { throw new InvalidOperationException("Crafting recipes are unavailable; migration was not saved."); } foreach (Recipe item in instance.m_recipes.Where(CreationRecipe)) { ItemData itemData = item.m_item.m_itemData; if (EpicLoot.IsAllowedMagicItemType(itemData) && KnownMaterials.Invoke(localPlayer).Contains(itemData.m_shared.m_name) && !LootDenyList.IsDenied(((Object)((Component)item.m_item).gameObject).name)) { hashSet.Add(itemData.m_shared.m_name); } } } localPlayer.m_customData["valheim.epiclootprogressionfix.crafting-migration"] = JsonConvert.SerializeObject((object)new MigrationRecord { Items = hashSet.OrderBy<string, string>((string name) => name, StringComparer.Ordinal).ToArray() }, JsonSettings); logger.LogInfo((object)$"Crafting migration saved {hashSet.Count} legacy credits for this character."); } owner = localPlayer; profile = playerProfile; legacyCredits = hashSet; } catch (Exception ex) { Problem = "Crafting history could not load: " + ex.GetBaseException().Message; logger.LogError((object)Problem); } } internal static bool IsUnlocked(string prefabName) { Player localPlayer = Player.m_localPlayer; if (string.IsNullOrEmpty(prefabName) || (Object)(object)localPlayer == (Object)null || (Object)(object)localPlayer != (Object)(object)owner || profile == null || legacyCredits == null || Game.instance.GetPlayerProfile() != profile || localPlayer.GetPlayerID() != profile.GetPlayerID()) { return false; } GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab(prefabName) : null); ItemDrop val2 = (((Object)(object)val != (Object)null) ? val.GetComponent<ItemDrop>() : null); if ((Object)(object)val2 == (Object)null) { return false; } string name = val2.m_itemData.m_shared.m_name; Dictionary<string, float> crafts = profile.m_playerStats[0].m_itemCraftStats; if (legacyCredits.Contains(name)) { return true; } if (ConversionSources().TryGetValue(name, out var value)) { if (!value.Any(Crafted)) { if (Crafted(name)) { return HasCreationRecipe(); } return false; } return true; } if (Crafted(name)) { return true; } if (prefabName == "FishingRod" && KnownMaterials.Invoke(localPlayer).Contains(name)) { return !HasCreationRecipe(); } return false; bool Crafted(string item) { if (crafts.TryGetValue(item, out var value2)) { return value2 > 0f; } return false; } bool HasCreationRecipe() { return ObjectDB.instance.m_recipes.Any((Recipe recipe) => CreationRecipe(recipe) && recipe.m_item.m_itemData.m_shared.m_name == name); } } private static Dictionary<string, HashSet<string>> ConversionSources() { ZNetScene instance = ZNetScene.instance; if (conversionSources != null && (Object)(object)conversionScene == (Object)(object)instance) { return conversionSources; } Dictionary<string, HashSet<string>> dictionary = new Dictionary<string, HashSet<string>>(StringComparer.Ordinal); if ((Object)(object)instance != (Object)null) { foreach (GameObject prefab in instance.m_prefabs) { if ((Object)(object)prefab == (Object)null) { continue; } CookingStation[] componentsInChildren = prefab.GetComponentsInChildren<CookingStation>(true); for (int i = 0; i < componentsInChildren.Length; i++) { foreach (ItemConversion item in componentsInChildren[i].m_conversion ?? new List<ItemConversion>()) { if (!((Object)(object)item?.m_from == (Object)null) && !((Object)(object)item.m_to == (Object)null)) { string name = item.m_to.m_itemData.m_shared.m_name; if (!dictionary.TryGetValue(name, out var value)) { value = (dictionary[name] = new HashSet<string>(StringComparer.Ordinal)); } value.Add(item.m_from.m_itemData.m_shared.m_name); } } } } } conversionScene = instance; conversionSources = dictionary; return dictionary; } } [HarmonyPatch(typeof(GatedItemTypeHelper), "CheckIfItemNeedsGate", new Type[] { typeof(GatedItemTypeMode), typeof(string) })] internal static class CraftedEquipmentGate { private static bool Prefix(GatedItemTypeMode mode, string itemName, ref bool __result) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 if ((int)mode != 4 || (Object)(object)Player.m_localPlayer == (Object)null) { return true; } __result = !CraftingHistory.IsUnlocked(itemName); return false; } } internal static class CreatureAreaDamage { private static readonly int FactorKey = StringExtensionMethods.GetStableHashCode("epicloot_progression_creature_damage_factor"); private static readonly FieldRef<Aoe, ZNetView> NetViewOf = AccessTools.FieldRefAccess<Aoe, ZNetView>("m_nview"); private static readonly FieldRef<Attack, Humanoid> AttackerOf = AccessTools.FieldRefAccess<Attack, Humanoid>("m_character"); private static readonly FieldRef<SpawnAbility, Character> SpawnerOf = AccessTools.FieldRefAccess<SpawnAbility, Character>("m_owner"); private static readonly ConditionalWeakTable<Aoe, StrongBox<float>> Factors = new ConditionalWeakTable<Aoe, StrongBox<float>>(); private static Func<Character, float> factorOf; private static float creating = 1f; internal static void Initialize(Harmony harmony) { //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Expected O, but got Unknown //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Expected O, but got Unknown //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Expected O, but got Unknown //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_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Expected O, but got Unknown //IL_01b1: Expected O, but got Unknown //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: 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_01e1: Expected O, but got Unknown //IL_01e1: Expected O, but got Unknown //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Expected O, but got Unknown //IL_021d: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Expected O, but got Unknown if (Chainloader.PluginInfos.TryGetValue("MidnightsFX.StarLevelSystem", out var value)) { MethodInfo methodInfo = AccessTools.Method(((object)value.Instance).GetType().Assembly.GetType("StarLevelSystem.modules.Damage.DamagePatches+ModifyDamagePerLevel"), "DetermineDamageFactor", new Type[1] { typeof(Character) }, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(Aoe), "OnHit", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(typeof(Attack), "DoAreaAttack", (Type[])null, (Type[])null); MethodInfo methodInfo4 = AccessTools.EnumeratorMoveNext((MethodBase)AccessTools.Method(typeof(SpawnAbility), "Spawn", (Type[])null, (Type[])null)); if (methodInfo == null || methodInfo.ReturnType != typeof(float) || methodInfo2 == null || methodInfo3 == null || methodInfo4 == null) { throw new InvalidOperationException("StarLevelSystem's damage factor or the game's area effects changed."); } factorOf = AccessTools.MethodDelegate<Func<Character, float>>(methodInfo, (object)null, true); Type typeFromHandle = typeof(CreatureAreaDamage); harmony.Patch((MethodBase)AccessTools.Method(typeof(Aoe), "Setup", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeFromHandle, "RememberArea", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeFromHandle, "ScaleHits", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(Projectile), "Setup", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeFromHandle, "ScaleProjectile", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(Character), "OnDeath", (Type[])null, (Type[])null), new HarmonyMethod(typeFromHandle, "BeginDeath", (Type[])null) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeFromHandle, "EndCreating", (Type[])null), (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeFromHandle, "BeginAreaAttack", (Type[])null) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeFromHandle, "EndCreating", (Type[])null), (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(EffectList), "Create", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeFromHandle, "RememberCreated", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeFromHandle, "RememberSpawned", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); } } private static float FactorFor(Character owner, HitData hitData, bool usesHit) { if (!((Object)(object)owner == (Object)null) && !owner.IsPlayer() && !(hitData != null && usesHit)) { return factorOf(owner); } return 1f; } private static Character PartOf(Aoe area) { ZNetView val = NetViewOf.Invoke(area); if (!Object.op_Implicit((Object)(object)val)) { return null; } return ((Component)val).GetComponent<Character>(); } private static void Remember(Aoe area, float factor) { Factors.Remove(area); Factors.Add(area, new StrongBox<float>(factor)); ZNetView val = NetViewOf.Invoke(area); if (factor != 1f && Object.op_Implicit((Object)(object)val) && val.IsValid() && val.IsOwner()) { val.GetZDO().Set(FactorKey, factor); } } private static void RememberArea(Aoe __instance, Character owner, HitData hitData) { if (!Object.op_Implicit((Object)(object)PartOf(__instance))) { Remember(__instance, FactorFor(owner, hitData, __instance.m_useAttackSettings)); } } private static IEnumerable<CodeInstruction> ScaleHits(IEnumerable<CodeInstruction> instructions) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Expected O, but got Unknown //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown MethodInfo damage = AccessTools.Method(typeof(Aoe), "GetDamage", Type.EmptyTypes, (Type[])null); List<CodeInstruction> code = instructions.ToList(); List<int> list = (from i in Enumerable.Range(0, code.Count) where CodeInstructionExtensions.Calls(code[i], damage) select i).ToList(); if (damage == null || list.Count != 1) { throw new InvalidOperationException("The game's area hits changed."); } code.InsertRange(list[0] + 1, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[2] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(CreatureAreaDamage), "Scale", (Type[])null, (Type[])null)) }); return code; } private static DamageTypes Scale(DamageTypes damage, Aoe area) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) Character val = PartOf(area); float num = ((!Object.op_Implicit((Object)(object)val)) ? Factors.GetValue(area, Synced).Value : (val.IsPlayer() ? 1f : factorOf(val))); if (num != 1f) { ((DamageTypes)(ref damage)).Modify(num); } return damage; } private static StrongBox<float> Synced(Aoe area) { ZNetView val = NetViewOf.Invoke(area); return new StrongBox<float>((Object.op_Implicit((Object)(object)val) && val.IsValid()) ? val.GetZDO().GetFloat(FactorKey, 1f) : 1f); } private static void ScaleProjectile(Projectile __instance, Character owner, HitData hitData) { float num = FactorFor(owner, hitData, usesHit: true); if (num != 1f) { ((DamageTypes)(ref __instance.m_damage)).Modify(num); } } private static void BeginDeath(Character __instance, out float? __state) { __state = creating; creating = ((__instance.IsPlayer() || !__instance.IsOwner()) ? 1f : factorOf(__instance)); } private static void BeginAreaAttack(Attack __instance, out float? __state) { __state = creating; Humanoid val = AttackerOf.Invoke(__instance); creating = ((!Object.op_Implicit((Object)(object)val) || ((Character)val).IsPlayer()) ? 1f : factorOf((Character)(object)val)); } private static void EndCreating(float? __state) { if (__state.HasValue) { creating = __state.Value; } } private static void RememberCreated(GameObject[] __result) { if (creating == 1f || __result == null) { return; } foreach (GameObject val in __result) { Aoe val2 = (Object.op_Implicit((Object)(object)val) ? val.GetComponent<Aoe>() : null); if (Object.op_Implicit((Object)(object)val2)) { Remember(val2, creating); } } } private static IEnumerable<CodeInstruction> RememberSpawned(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod) { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Expected O, but got Unknown FieldInfo fieldInfo = AccessTools.Field(__originalMethod.DeclaringType, "<>4__this"); List<CodeInstruction> code = instructions.ToList(); List<int> list = (from i in Enumerable.Range(0, code.Count) where code[i].operand is MethodInfo { Name: "Instantiate" } methodInfo && methodInfo.ReturnType == typeof(GameObject) select i).ToList(); if (fieldInfo == null || list.Count != 1) { throw new InvalidOperationException("The game's spawn ability changed."); } code.InsertRange(list[0] + 1, (IEnumerable<CodeInstruction>)(object)new CodeInstruction[4] { new CodeInstruction(OpCodes.Dup, (object)null), new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(OpCodes.Ldfld, (object)fieldInfo), new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(CreatureAreaDamage), "Spawned", (Type[])null, (Type[])null)) }); return code; } private static void Spawned(GameObject spawned, SpawnAbility ability) { Character val = SpawnerOf.Invoke(ability); Aoe val2 = (Object.op_Implicit((Object)(object)spawned) ? spawned.GetComponent<Aoe>() : null); if (Object.op_Implicit((Object)(object)val2) && Object.op_Implicit((Object)(object)val) && !val.IsPlayer()) { Remember(val2, factorOf(val)); } } } internal static class DamageTakenEffects { internal static void Initialize(Harmony harmony) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown Assembly assembly = typeof(ModifyDamage).Assembly; MethodInfo methodInfo = AccessTools.Method(assembly.GetType("EpicLoot.src.Magic.MagicItemEffects.Helpers.SharedCharacterRpcDamagePatch"), "Prefix", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(assembly.GetType("EpicLoot.src.Magic.MagicItemEffects.Helpers.SharedPlayerPostArmorDamagePatch"), "Postfix", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null) { throw new InvalidOperationException("EpicLoot's damage-taken effects moved."); } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(DamageTakenEffects), "SkipFall", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(DamageTakenEffects), "NotForFalls", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } private static bool SkipFall(HitData hit, ref bool __result) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 if (hit == null || (int)hit.m_hitType != 3) { return true; } __result = true; return false; } private static bool NotForFalls(HitData hit) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 if (hit != null) { return (int)hit.m_hitType != 3; } return true; } } internal static class DeathFeedWithoutEmbed { private static MethodInfo sendMessage; private static object deathFeed; internal static void Initialize(Harmony harmony) { //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Expected O, but got Unknown if (Chainloader.PluginInfos.TryGetValue("RustyMods.DiscordBot", out var value)) { Assembly assembly = ((object)value.Instance).GetType().Assembly; Type type = assembly.GetType("DiscordBot.Discord"); Type type2 = assembly.GetType("DiscordBot.Webhook"); Type type3 = assembly.GetType("DiscordBot.WebhookRoute"); if (type == null || type2 == null || type3 == null || !type2.IsEnum || !Enum.IsDefined(type2, "DeathFeed")) { throw new InvalidOperationException("DiscordBot webhook API changed."); } MethodInfo methodInfo = AccessTools.Method(type, "SendEmbedMessage", new Type[6] { type2, typeof(string), typeof(string), typeof(string), typeof(string), type3 }, (Type[])null); sendMessage = AccessTools.Method(type, "SendMessage", new Type[5] { type2, typeof(string), typeof(string), typeof(List<string>), type3 }, (Type[])null); if (methodInfo == null || sendMessage == null) { throw new InvalidOperationException("DiscordBot webhook API changed."); } deathFeed = Enum.Parse(type2, "DeathFeed"); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(DeathFeedWithoutEmbed), "SendEmbedMessage", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } private static bool SendEmbedMessage(object __instance, object[] __args) { if (!object.Equals(__args[0], deathFeed)) { return true; } string text = (string)__args[2]; if (string.IsNullOrWhiteSpace(text)) { return true; } sendMessage.Invoke(__instance, new object[5] { __args[0], __args[3], DeathMessageFormatting.ForDiscord(text), null, __args[5] }); return false; } } internal static class DeathLeaderboard { private sealed class DeliveryState { public DateTime RecordingSinceUtc; public DateTime CompletedUtc; public DateTime PendingUtc; public string PendingContent; public DateTime RetryAfterUtc; } private sealed class Ranking { public string PlayerId; public string Name; public int Count; public DateTime LatestUtc; } private static ManualLogSource logger; private static FieldInfo database; private static FieldInfo configuration; private static FieldInfo deaths; private static PropertyInfo recordDate; private static PropertyInfo recordName; private static PropertyInfo recordPlayer; private static MethodInfo findAll; private static MethodInfo recordDeath; private static MethodInfo insertDeathRecord; private static ConstructorInfo createDeathRecord; private static HashSet<string> joinedPlayers; private static readonly Dictionary<ZRpc, ZDOID> recordedCharacters = new Dictionary<ZRpc, ZDOID>(); private static readonly int deathMessage = StringExtensionMethods.GetStableHashCode("OnDeath"); private static TimeZoneInfo warsaw; private static volatile bool running; private static DateTime nextCheckUtc; private static bool announced; internal static void Initialize(Harmony harmony, ManualLogSource log) { //IL_02a4: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Expected O, but got Unknown //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02e8: Expected O, but got Unknown //IL_0349: Unknown result type (might be due to invalid IL or missing references) //IL_0357: Expected O, but got Unknown //IL_0380: Unknown result type (might be due to invalid IL or missing references) //IL_038d: Expected O, but got Unknown //IL_03b5: Unknown result type (might be due to invalid IL or missing references) //IL_03c3: Expected O, but got Unknown if (Plugin.DailyDeathLeaderboard.Value && Chainloader.PluginInfos.TryGetValue("nwesterhausen.DiscordConnector", out var value)) { if (value.Metadata.Version != new Version(3, 1, 3)) { throw new InvalidOperationException("Death leaderboard requires DiscordConnector 3.1.3."); } logger = log; Assembly assembly = ((object)value.Instance).GetType().Assembly; database = AccessTools.Field(((object)value.Instance).GetType(), "StaticDatabase"); configuration = AccessTools.Field(((object)value.Instance).GetType(), "StaticConfig"); deaths = AccessTools.Field(assembly.GetType("DiscordConnector.Records.Database"), "DeathCollection"); Type type = assembly.GetType("DiscordConnector.Records.SimpleStat", throwOnError: true); recordDate = AccessTools.Property(type, "Date"); recordName = AccessTools.Property(type, "Name"); recordPlayer = AccessTools.Property(type, "PlayerId"); findAll = ((deaths == null) ? null : AccessTools.Method(deaths.FieldType, "FindAll", (Type[])null, (Type[])null)); insertDeathRecord = ((deaths == null) ? null : AccessTools.Method(deaths.FieldType, "Insert", new Type[1] { type }, (Type[])null)); createDeathRecord = AccessTools.Constructor(type, new Type[5] { typeof(string), typeof(string), typeof(float), typeof(float), typeof(float) }, false); Type type2 = assembly.GetType("DiscordConnector.Handlers", throwOnError: true); recordDeath = AccessTools.Method(type2, "Death", (Type[])null, (Type[])null); joinedPlayers = (HashSet<string>)(AccessTools.Field(type2, "joinedPlayers")?.GetValue(null)); if (database == null || configuration == null || findAll == null || recordDate == null || recordName == null || recordPlayer == null || recordDeath == null || joinedPlayers == null || insertDeathRecord == null || createDeathRecord == null) { throw new InvalidOperationException("DiscordConnector death-record API changed."); } try { warsaw = TimeZoneInfo.FindSystemTimeZoneById("Europe/Warsaw"); } catch (TimeZoneNotFoundException) { warsaw = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time"); } harmony.Patch((MethodBase)AccessTools.Method(type2, "Join", (Type[])null, (Type[])null), new HarmonyMethod(typeof(DeathLeaderboard), "FirstSpawnOnly", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(ZRoutedRpc), "RPC_RoutedRPC", (Type[])null, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(DeathLeaderboard), "ObserveDeathMessage", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(deaths.DeclaringType, "InsertSimpleStatRecord", new Type[4] { deaths.FieldType, typeof(string), typeof(string), typeof(Vector3) }, (Type[])null), new HarmonyMethod(typeof(DeathLeaderboard), "StoreDeath", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(ZNet), "Disconnect", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(typeof(DeathLeaderboard), "ForgetPeer", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)AccessTools.Method(typeof(ZNet), "Shutdown", (Type[])null, (Type[])null), new HarmonyMethod(typeof(DeathLeaderboard), "ClearDeaths", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); logger.LogInfo((object)"Daily death leaderboard initialized: 06:00 Europe/Warsaw, preceding 24 hours."); } } private static bool FirstSpawnOnly(ZNetPeer peer) { if (peer != null) { return !joinedPlayers.Contains(peer.m_socket.GetHostName()); } return true; } private static IEnumerable<CodeInstruction> ObserveDeathMessage(IEnumerable<CodeInstruction> instructions, MethodBase __originalMethod) { LocalVariableInfo data = __originalMethod.GetMethodBody().LocalVariables.Single((LocalVariableInfo local) => local.LocalType == typeof(RoutedRPCData)); MethodInfo deserialize = AccessTools.Method(typeof(RoutedRPCData), "Deserialize", (Type[])null, (Type[])null); int changes = 0; foreach (CodeInstruction instruction in instructions) { yield return instruction; if (CodeInstructionExtensions.Calls(instruction, deserialize)) { yield return new CodeInstruction(OpCodes.Ldarg_1, (object)null); yield return new CodeInstruction(OpCodes.Ldloc, (object)data.LocalIndex); yield return new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(DeathLeaderboard), "ReceiveDeath", (Type[])null, (Type[])null)); changes++; } } if (changes != 1) { throw new InvalidOperationException("Native death-message routing changed."); } } private static void ReceiveDeath(ZRpc rpc, RoutedRPCData data) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0077: 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_009d: 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_00e6: Unknown result type (might be due to invalid IL or missing references) if (!ZNet.instance.IsServer() || data.m_methodHash != deathMessage || data.m_targetPeerID != 0L) { return; } ZNetPeer val = ZNet.instance.GetPeers().Find((ZNetPeer candidate) => candidate.m_rpc == rpc); if (val == null || !val.IsReady() || data.m_senderPeerID != val.m_uid || val.m_characterID == ZDOID.None || data.m_targetZDO != val.m_characterID || (recordedCharacters.TryGetValue(rpc, out var value) && value == data.m_targetZDO) || !joinedPlayers.Contains(val.m_socket.GetHostName())) { return; } try { recordDeath.Invoke(null, new object[1] { val }); recordedCharacters[rpc] = data.m_targetZDO; } catch (Exception ex) { logger.LogError((object)("Could not record death: " + ex.GetBaseException().Message)); } } private static bool StoreDeath(object collection, string playerName, string playerHostName, Vector3 pos) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) if (collection != deaths.GetValue(database.GetValue(null))) { return true; } object obj = createDeathRecord.Invoke(new object[5] { playerName, playerHostName, pos.x, pos.y, pos.z }); insertDeathRecord.Invoke(collection, new object[1] { obj }); return false; } private static void ForgetPeer(ZNetPeer peer) { if (peer != null) { recordedCharacters.Remove(peer.m_rpc); } } private static void ClearDeaths() { recordedCharacters.Clear(); } internal static void Tick() { if (logger == null || running || (Object)(object)ZNet.instance == (Object)null || !ZNet.instance.IsDedicated() || DateTime.UtcNow < nextCheckUtc) { return; } nextCheckUtc = DateTime.UtcNow.AddMinutes(1.0); string path = Path.Combine(Paths.BepInExRootPath, "death-leaderboard"); string path2 = Path.Combine(path, ZNet.instance.GetWorldUID().ToString(CultureInfo.InvariantCulture) + (Plugin.DeathLeaderboardDryRun.Value ? "-preview.dat" : ".dat")); bool preview = Plugin.DeathLeaderboardDryRun.Value; running = true; Task.Run(async delegate { try { await Check(path2, preview); } catch (Exception ex) { logger.LogError((object)("Death leaderboard failed: " + ex.GetBaseException().Message)); nextCheckUtc = DateTime.UtcNow.AddMinutes(5.0); } finally { running = false; } }); } private static async Task Check(string path, bool preview) { object value = configuration.GetValue(null); if (!(bool)Read(value, "CollectStatsEnabled") || !(bool)Read(value, "StatsDeathEnabled")) { throw new InvalidOperationException("Enable DiscordConnector player statistics and death statistics before reporting."); } object value2 = deaths.GetValue(database.GetValue(null)); if (value2 == null) { throw new InvalidOperationException("DiscordConnector death database is not initialized."); } DateTime now = DateTime.UtcNow; DeliveryState state = (File.Exists(path) ? JsonConvert.DeserializeObject<DeliveryState>(File.ReadAllText(path)) : new DeliveryState { RecordingSinceUtc = now }); if (state == null || state.RecordingSinceUtc == default(DateTime)) { throw new InvalidDataException("Invalid death leaderboard state; restore its backup before reporting."); } if (!File.Exists(path)) { Save(path, state); } DateTime end = LatestDeadline(now); if (!announced) { string text = Compose(value2, end); logger.LogInfo((object)("Death leaderboard database readable; first full report after " + state.RecordingSinceUtc.AddHours(24.0).ToString("O") + ".")); if (preview) { logger.LogInfo((object)("Death leaderboard preview (not delivered):\n" + text)); } announced = true; } if (state.PendingUtc != default(DateTime)) { SkipUncertain(path, state, "was interrupted by a server stop"); } if (end <= state.CompletedUtc || end.AddHours(-24.0) < state.RecordingSinceUtc || now < state.RetryAfterUtc) { return; } string text2 = Compose(value2, end); if (preview) { logger.LogInfo((object)("Death leaderboard preview (not delivered):\n" + text2)); } else { if (!Uri.TryCreate((string)Read(Read(value, "PrimaryWebhook"), "Url"), UriKind.Absolute, out Uri result) || result.Scheme != "https" || (result.Host != "discord.com" && result.Host != "discordapp.com") || !Regex.IsMatch(result.AbsolutePath, "^/api(?:/v[0-9]+)?/webhooks/[0-9]+/[A-Za-z0-9_-]+$")) { throw new InvalidOperationException("Configure a valid DiscordConnector primary Discord webhook before reporting."); } UriBuilder uriBuilder = new UriBuilder(result) { Query = "wait=true" }; state.PendingUtc = end; state.PendingContent = text2; Save(path, state); using HttpClient client = new HttpClient(new HttpClientHandler { AllowAutoRedirect = false }) { Timeout = TimeSpan.FromSeconds(30.0) }; using StringContent body = new StringContent(JsonConvert.SerializeObject((object)new { content = text2, allowed_mentions = new { parse = new string[0] } }), Encoding.UTF8, "application/json"); HttpResponseMessage httpResponseMessage; try { httpResponseMessage = await client.PostAsync(uriBuilder.Uri, body); } catch (Exception ex) { if (NotSent(ex)) { Retry(path, state, now.AddMinutes(15.0), "Discord could not be reached (" + ex.GetType().Name + ")"); } else { SkipUncertain(path, state, "got no answer from Discord (" + ex.GetType().Name + ")"); } return; } using (httpResponseMessage) { int statusCode = (int)httpResponseMessage.StatusCode; if (statusCode == 429) { HttpResponseMessage response = httpResponseMessage; double value3 = RetryAfterSeconds(response, await httpResponseMessage.Content.ReadAsStringAsync()); Retry(path, state, now.AddSeconds(value3), "Discord rate limited the report"); return; } if (statusCode >= 500) { SkipUncertain(path, state, "failed with HTTP " + statusCode + " from Discord"); return; } if (!httpResponseMessage.IsSuccessStatusCode) { Retry(path, state, now.AddMinutes(15.0), "Discord refused it with HTTP " + statusCode + "; check the webhook"); return; } } } state.CompletedUtc = end; state.PendingUtc = default(DateTime); state.PendingContent = null; Save(path, state); logger.LogInfo((object)("Death leaderboard " + (preview ? "previewed" : "delivered") + " for " + end.ToString("O"))); } private static void Retry(string path, DeliveryState state, DateTime retryAfterUtc, string reason) { state.PendingUtc = default(DateTime); state.PendingContent = null; state.RetryAfterUtc = retryAfterUtc; Save(path, state); logger.LogWarning((object)("Death leaderboard not delivered: " + reason + ". Retrying after " + retryAfterUtc.ToString("O") + ".")); } private static void SkipUncertain(string path, DeliveryState state, string reason) { logger.LogWarning((object)("Death leaderboard delivery for " + state.PendingUtc.ToString("O") + " " + reason + "; it will not be resent, to avoid a duplicate. If Discord does not show it, post this text manually:\n" + state.PendingContent)); if (state.PendingUtc > state.CompletedUtc) { state.CompletedUtc = state.PendingUtc; } state.PendingUtc = default(DateTime); state.PendingContent = null; Save(path, state); } private static bool NotSent(Exception error) { for (Exception ex = error; ex != null; ex = ex.InnerException) { if (ex is AuthenticationException) { return true; } if (ex is WebException ex2 && (ex2.Status == WebExceptionStatus.NameResolutionFailure || ex2.Status == WebExceptionStatus.ProxyNameResolutionFailure || ex2.Status == WebExceptionStatus.ConnectFailure || ex2.Status == WebExceptionStatus.SecureChannelFailure || ex2.Status == WebExceptionStatus.TrustFailure)) { return true; } if (ex is SocketException ex3 && (ex3.SocketErrorCode == SocketError.HostNotFound || ex3.SocketErrorCode == SocketError.TryAgain || ex3.SocketErrorCode == SocketError.NoData || ex3.SocketErrorCode == SocketError.ConnectionRefused || ex3.SocketErrorCode == SocketError.NetworkDown || ex3.SocketErrorCode == SocketError.NetworkUnreachable || ex3.SocketErrorCode == SocketError.HostUnreachable)) { return true; } } return false; } private static double RetryAfterSeconds(HttpResponseMessage response, string body) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Invalid comparison between Unknown and I4 //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Invalid comparison between Unknown and I4 double num = (response.Headers.RetryAfter?.Delta?.TotalSeconds).GetValueOrDefault(); try { JToken val = JObject.Parse(body)["retry_after"]; if (val != null && ((int)val.Type == 7 || (int)val.Type == 6)) { num = Math.Max(num, (double)val); } } catch (JsonReaderException) { } return Math.Max(300.0, num); } internal static DateTime LatestDeadline(DateTime utcNow) { DateTime dateTime = TimeZoneInfo.ConvertTimeFromUtc(utcNow, warsaw); DateTime dateTime2 = DateTime.SpecifyKind(dateTime.Date.AddHours(6.0), DateTimeKind.Unspecified); if (dateTime < dateTime2) { dateTime2 = dateTime2.AddDays(-1.0); } return TimeZoneInfo.ConvertTimeToUtc(dateTime2, warsaw); } private static string Compose(object collection, DateTime end) { DateTime dateTime = end.AddHours(-24.0); Dictionary<string, Ranking> dictionary = new Dictionary<string, Ranking>(StringComparer.Ordinal); foreach (object item in (IEnumerable)findAll.Invoke(collection, null)) { DateTime dateTime2 = ((DateTime)recordDate.GetValue(item)).ToUniversalTime(); if (!(dateTime2 < dateTime) && !(dateTime2 >= end)) { string text = (string)recordPlayer.GetValue(item); if (string.IsNullOrEmpty(text)) { throw new InvalidDataException("Death record has no player identity."); } if (!dictionary.TryGetValue(text, out var value)) { Ranking obj = new Ranking { PlayerId = text }; value = obj; dictionary[text] = obj; } value.Count++; if (dateTime2 >= value.LatestUtc) { value.LatestUtc = dateTime2; value.Name = PlainName((string)recordName.GetValue(item)); } } } StringBuilder stringBuilder = new StringBuilder("Ranking zgonów — ostatnie 24 godziny\n\n"); List<Ranking> list = dictionary.Values.OrderByDescending((Ranking row) => row.Count).ThenBy<Ranking, string>((Ranking row) => row.Name, StringComparer.Ordinal).ThenBy<Ranking, string>((Ranking row) => row.PlayerId, StringComparer.Ordinal) .ToList(); if (list.Count == 0) { stringBuilder.Append("Nikt nie zginął."); } int num = 0; int num2 = -1; for (int num3 = 0; num3 < list.Count; num3++) { Ranking ranking = list[num3]; if (ranking.Count != num2) { num = num3 + 1; } num2 = ranking.Count; string text2 = $"{num}. {ranking.Name}: {ranking.Count}\n"; if (stringBuilder.Length + text2.Length > 1850) { stringBuilder.Append("Pozostali gracze: ").Append(list.Count - num3).Append(".\n"); break; } stringBuilder.Append(text2); } stringBuilder.Append("\nŁącznie zgonów: ").Append(list.Sum((Ranking row) => row.Count)); return DiscordSystemMessages.Box(stringBuilder.ToString()); } private static string PlainName(string name) { name = Regex.Replace(name ?? "", "<[^>]*>", ""); name = new string(name.Where((char character) => !char.IsControl(character) && char.GetUnicodeCategory(character) != UnicodeCategory.Format).ToArray()).Replace('`', '\''); name = Regex.Replace(name, "\\s+", " ").Trim(); if (name.Length == 0) { return "Gracz"; } if (StringInfo.ParseCombiningCharacters(name).Length <= 60) { return name; } return new StringInfo(name).SubstringByTextElements(0, 60); } private static object Read(object instance, string name) { return AccessTools.Property(instance.GetType(), name)?.GetValue(instance) ?? throw new MissingMemberException("DiscordConnector setting unavailable: " + name); } private static void Save(string path, DeliveryState state) { Directory.CreateDirectory(Path.GetDirectoryName(path)); string text = path + ".tmp"; byte[] bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject((object)state, (Formatting)1)); using (FileStream fileStream = new FileStream(text, FileMode.Create, FileAccess.Write, FileShare.None)) { fileStream.Write(bytes, 0, bytes.Length); fileStream.Flush(flushToDisk: true); } if (File.Exists(path)) { File.Replace(text, path, null); } else { File.Move(text, path); } } } internal static class DeathMessageFormatting { private const string PlayerColor = "<color=#FF5555>"; private static MethodInfo cacheEntryOf; private static PropertyInfo untranslatedNameOf; private static ManualLogSource logger; internal static void Initialize(H