using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Permissions; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using DvergerAutomation.Common; using EpicLootAPI; using HarmonyLib; using JetBrains.Annotations; using Jotunn.Configs; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using SimpleJson; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("DvergerAutomation")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("DvergerAutomation")] [assembly: AssemblyCopyright("Copyright © 2021")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")] [assembly: AssemblyFileVersion("0.5.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.5.0.0")] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } } namespace DvergerAutomation { internal class Logger { public static LogLevel Level = (LogLevel)16; public static void EnableDebugLogging(object sender, EventArgs e) { CheckEnableDebugLogging(); } public static void CheckEnableDebugLogging() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (ValConfig.EnableDebugMode.Value) { Level = (LogLevel)32; } else { Level = (LogLevel)16; } } public static void SetDebugLogging(bool state) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (state) { Level = (LogLevel)32; } else { Level = (LogLevel)16; } } public static void LogDebug(string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)Level >= 32) { DvergerAutomation.Log.LogInfo((object)("[DEBUG]" + message)); } } public static void LogInfo(string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)Level >= 16) { DvergerAutomation.Log.LogInfo((object)message); } } public static void LogWarning(string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)Level >= 4) { DvergerAutomation.Log.LogWarning((object)message); } } public static void LogError(string message) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 if ((int)Level >= 2) { DvergerAutomation.Log.LogError((object)message); } } } internal class ValConfig { public static ConfigFile cfg; public static ConfigEntry EnableDebugMode; public static ConfigEntry AutomationEnabled; public static ConfigEntry ScanInterval; public static ConfigEntry ScanRadius; public static ConfigEntry RangePerCore; public static ConfigEntry RequireCores; public const string cfgFolder = "DvergerAutomation"; public ValConfig(ConfigFile cf) { cfg = cf; cfg.SaveOnConfigSet = true; CreateConfigValues(cf); Logger.SetDebugLogging(EnableDebugMode.Value); } private void CreateConfigValues(ConfigFile Config) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown EnableDebugMode = Config.Bind("Client config", "EnableDebugMode", false, new ConfigDescription("Enables Debug logging.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdvanced = true } })); EnableDebugMode.SettingChanged += Logger.EnableDebugLogging; Logger.CheckEnableDebugLogging(); AutomationEnabled = BindServerConfig("Dverger AutoSorter", "Enabled", value: true, "Enables the Dverger AutoSorter: nearby accessible chests act as a shared material pool when crafting at linked stations or building with the Hammer near the sorter."); ScanInterval = BindServerConfig("Dverger AutoSorter", "Scan Interval", 30f, "Seconds between scans for nearby crafting stations and storage chests.", advanced: false, 5f, 300f); ScanRadius = BindServerConfig("Dverger AutoSorter", "Scan Radius", 20f, "Radius (meters) around the AutoSorter in which crafting stations and chests are linked.", advanced: false, 1f, 64f); RangePerCore = BindServerConfig("Dverger AutoSorter", "Range Per Core", 25f, "Extra link radius (meters) added per inserted Surtling Core.", advanced: false, 0f, 100f); RequireCores = BindServerConfig("Dverger AutoSorter", "Require Cores", value: true, "When enabled, the AutoSorter only links stations/chests after at least one Surtling Core is inserted."); } public static ConfigEntry> BindServerConfig(string category, string key, List value, string description, bool advanced = false) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown return cfg.Bind>(category, key, value, new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true, IsAdvanced = advanced } })); } public static ConfigEntry BindServerConfig(string category, string key, float[] value, string description, bool advanced = false, float valMin = 0f, float valMax = 150f) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown return cfg.Bind(category, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange(valMin, valMax), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true, IsAdvanced = advanced } })); } public static ConfigEntry BindServerConfig(string category, string key, bool value, string description, AcceptableValueBase acceptableValues = null, bool advanced = false) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown return cfg.Bind(category, key, value, new ConfigDescription(description, acceptableValues, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true, IsAdvanced = advanced } })); } public static ConfigEntry BindServerConfig(string category, string key, int value, string description, bool advanced = false, int valMin = 0, int valMax = 150) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown return cfg.Bind(category, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange(valMin, valMax), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true, IsAdvanced = advanced } })); } public static ConfigEntry BindServerConfig(string category, string key, float value, string description, bool advanced = false, float valMin = 0f, float valMax = 150f) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown return cfg.Bind(category, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange(valMin, valMax), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true, IsAdvanced = advanced } })); } public static ConfigEntry BindServerConfig(string category, string key, string value, string description, AcceptableValueList acceptableValues = null, bool advanced = false) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown return cfg.Bind(category, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)acceptableValues, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true, IsAdvanced = advanced } })); } } [BepInPlugin("MidngightsFX.DvergerAutomation", "DvergerAutomation", "0.5.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] internal class DvergerAutomation : BaseUnityPlugin { public const string PluginGUID = "MidngightsFX.DvergerAutomation"; public const string PluginName = "DvergerAutomation"; public const string PluginVersion = "0.5.0"; internal static ManualLogSource Log; internal ValConfig cfg; public static CustomLocalization Localization = LocalizationManager.Instance.GetLocalization(); public static AssetBundle EmbeddedResourceBundle; public static Harmony HarmonyInstance { get; private set; } public void Awake() { Log = ((BaseUnityPlugin)this).Logger; cfg = new ValConfig(((BaseUnityPlugin)this).Config); EmbeddedResourceBundle = AssetUtils.LoadAssetBundleFromResources("DvergerAutomation.embedded.automation", typeof(DvergerAutomation).Assembly); HarmonyInstance = Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), "MidngightsFX.DvergerAutomation"); LocalizationLoader.AddLocalizations(); AddPieces(); EpicLootIntegration.Register(); } public void OnDestroy() { EpicLootIntegration.Unregister(); } public void AddPieces() { JotunnPiece.RegisterJotunnPiece(new JotunnPiece.JotunnBuildPiece { Name = "Dverger AutoSorter", Prefab = "DA_Autosorter", Sprite = "DA_Autosorter", Workbench = "forge", Category = "Crafting", PieceCost = new List { new JotunnPiece.PieceCost { prefab = "Stone", amount = 20, refundable = true }, new JotunnPiece.PieceCost { prefab = "Bronze", amount = 8, refundable = true }, new JotunnPiece.PieceCost { prefab = "GreyDwarfEyes", amount = 20, refundable = true }, new JotunnPiece.PieceCost { prefab = "Ectoplasm", amount = 4, refundable = true } } }); } } public class AutomationHub : MonoBehaviour { public Switch CoreSwitch1; public Switch CoreSwitch2; public Switch CoreSwitch3; public Switch CoreSwitch4; public GameObject Core1Visual; public GameObject Core2Visual; public GameObject Core3Visual; public GameObject Core4Visual; public GameObject EnabledVisuals; private const string CoreMaskKey = "DA_cores"; private const string SurtlingCorePrefab = "SurtlingCore"; private ZNetView nview; internal readonly HashSet LinkedStations = new HashSet(); internal readonly List LinkedContainers = new List(); private Coroutine scanLoop; private static int pieceMask; internal int CoreCount { get { int coreMask = GetCoreMask(); int num = 0; for (int i = 0; i < 4; i++) { if ((coreMask & (1 << i)) != 0) { num++; } } return num; } } internal bool IsActive => GetCoreMask() != 0; internal float EffectiveRadius => ValConfig.ScanRadius.Value + (float)CoreCount * ValConfig.RangePerCore.Value; private void Awake() { nview = ((Component)this).GetComponent(); if ((Object)(object)nview != (Object)null && nview.GetZDO() != null) { nview.Register("DA_RefreshCores", (Action)RPC_RefreshCores); WearNTear component = ((Component)this).GetComponent(); if ((Object)(object)component != (Object)null) { component.m_onDestroyed = (Action)Delegate.Combine(component.m_onDestroyed, new Action(OnDestroyedDropCores)); } } WireSwitch(CoreSwitch1, 0); WireSwitch(CoreSwitch2, 1); WireSwitch(CoreSwitch3, 2); WireSwitch(CoreSwitch4, 3); ((MonoBehaviour)this).InvokeRepeating("UpdateVisuals", 1f, 4f); } private void OnEnable() { ContainerNetwork.Register(this); scanLoop = ((MonoBehaviour)this).StartCoroutine(ScanLoopRoutine()); } private void OnDisable() { if (scanLoop != null) { ((MonoBehaviour)this).StopCoroutine(scanLoop); scanLoop = null; } LinkedStations.Clear(); LinkedContainers.Clear(); ContainerNetwork.Unregister(this); } private IEnumerator ScanLoopRoutine() { yield return (object)new WaitForSeconds(2f); while (true) { if (ValConfig.AutomationEnabled.Value && (Object)(object)Player.m_localPlayer != (Object)null) { Scan(); } yield return (object)new WaitForSeconds(Mathf.Max(1f, ValConfig.ScanInterval.Value)); } } private void Scan() { //IL_003d: 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_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) LinkedStations.Clear(); LinkedContainers.Clear(); if (ValConfig.RequireCores.Value && CoreCount == 0) { ContainerNetwork.RebuildStationCache(); return; } float effectiveRadius = EffectiveRadius; Vector3 position = ((Component)this).transform.position; long playerId = (((Object)(object)Game.instance != (Object)null && Game.instance.GetPlayerProfile() != null) ? Game.instance.GetPlayerProfile().GetPlayerID() : 0); foreach (CraftingStation allStation in CraftingStation.m_allStations) { if (!((Object)(object)allStation == (Object)null) && Vector3.Distance(position, ((Component)allStation).transform.position) <= effectiveRadius) { LinkedStations.Add(allStation); } } if (pieceMask == 0) { pieceMask = LayerMask.GetMask(new string[2] { "piece", "piece_nonsolid" }); } Collider[] array = Physics.OverlapSphere(position, effectiveRadius, pieceMask); HashSet hashSet = new HashSet(); Collider[] array2 = array; foreach (Collider val in array2) { if (!((Object)(object)val == (Object)null)) { Container componentInParent = ((Component)val).GetComponentInParent(); if (!((Object)(object)componentInParent == (Object)null) && hashSet.Add(componentInParent) && IsAccessible(componentInParent, playerId)) { LinkedContainers.Add(componentInParent); } } } if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo($"[Autosorter] scan linked {LinkedStations.Count} stations, {LinkedContainers.Count} chests within {effectiveRadius}m."); } ContainerNetwork.RebuildStationCache(); } private static bool IsAccessible(Container container, long playerId) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if (container.m_inventory == null) { return false; } if (!container.CheckAccess(playerId)) { return false; } if (!PrivateArea.CheckAccess(((Component)container).transform.position, 0f, false, false)) { return false; } return true; } private int GetCoreMask() { if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return 0; } return nview.GetZDO().GetInt("DA_cores", 0); } private void SetCoreMask(int mask) { if (!((Object)(object)nview == (Object)null) && nview.IsValid()) { if (!nview.IsOwner()) { nview.ClaimOwnership(); } nview.GetZDO().Set("DA_cores", mask); nview.InvokeRPC(ZNetView.Everybody, "DA_RefreshCores", Array.Empty()); UpdateVisuals(); if (ValConfig.AutomationEnabled.Value && (Object)(object)Player.m_localPlayer != (Object)null) { Scan(); } } } private void RPC_RefreshCores(long sender) { UpdateVisuals(); } private void WireSwitch(Switch sw, int slot) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown if (!((Object)(object)sw == (Object)null)) { sw.m_onUse = new Callback(OnCoreSwitchUsed); sw.m_onHover = (TooltipCallback)(() => GetSwitchHover(slot)); sw.m_name = "$DA_autosorter_name"; } } private int SlotForSwitch(Switch caller) { if ((Object)(object)caller == (Object)(object)CoreSwitch1) { return 0; } if ((Object)(object)caller == (Object)(object)CoreSwitch2) { return 1; } if ((Object)(object)caller == (Object)(object)CoreSwitch3) { return 2; } if ((Object)(object)caller == (Object)(object)CoreSwitch4) { return 3; } return -1; } private bool OnCoreSwitchUsed(Switch caller, Humanoid user, ItemData item) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) int num = SlotForSwitch(caller); if (num < 0) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if (val == null) { return false; } if (!PrivateArea.CheckAccess(((Component)this).transform.position, 0f, true, false)) { return false; } if ((Object)(object)nview == (Object)null || !nview.IsValid()) { return false; } GameObject val2 = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab("SurtlingCore") : null); if ((Object)(object)val2 == (Object)null) { return false; } string name = val2.GetComponent().m_itemData.m_shared.m_name; int coreMask = GetCoreMask(); if ((coreMask & (1 << num)) != 0) { if (!((Humanoid)val).GetInventory().AddItem(val2, 1)) { ((Character)user).Message((MessageType)2, "$inventory_full", 0, (Sprite)null, false); return false; } SetCoreMask(coreMask & ~(1 << num)); ((Character)user).Message((MessageType)2, "$DA_Remove_Core", 0, (Sprite)null, false); } else { if (((Humanoid)val).GetInventory().CountItems(name, -1, true) <= 0) { ((Character)user).Message((MessageType)2, "$DA_Need_Core", 0, (Sprite)null, false); return false; } ((Humanoid)val).GetInventory().RemoveItem(name, 1, -1, true); SetCoreMask(coreMask | (1 << num)); ((Character)user).Message((MessageType)2, "$DA_Add_Core", 0, (Sprite)null, false); } return true; } private string GetSwitchHover(int slot) { string text = (((GetCoreMask() & (1 << slot)) != 0) ? "$DA_Remove_Core" : "$DA_Add_Core"); return Localization.instance.Localize("[$KEY_Use] " + text); } private void UpdateVisuals() { if (!((Object)(object)nview == (Object)null) && nview.IsValid()) { int coreMask = GetCoreMask(); SetActiveSafe(Core1Visual, (coreMask & 1) != 0); SetActiveSafe(Core2Visual, (coreMask & 2) != 0); SetActiveSafe(Core3Visual, (coreMask & 4) != 0); SetActiveSafe(Core4Visual, (coreMask & 8) != 0); SetActiveSafe(EnabledVisuals, coreMask != 0); } } private static void SetActiveSafe(GameObject go, bool active) { if ((Object)(object)go != (Object)null && go.activeSelf != active) { go.SetActive(active); } } private void OnDestroyedDropCores() { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)nview == (Object)null || !nview.IsValid() || !nview.IsOwner()) { return; } int coreCount = CoreCount; if (coreCount <= 0) { return; } GameObject val = (((Object)(object)ObjectDB.instance != (Object)null) ? ObjectDB.instance.GetItemPrefab("SurtlingCore") : null); if (!((Object)(object)val == (Object)null)) { for (int i = 0; i < coreCount; i++) { Vector3 val2 = ((Component)this).transform.position + Vector3.up * 0.5f + Random.insideUnitSphere * 0.3f; Object.Instantiate(val, val2, Random.rotation); } } } } internal static class ContainerNetwork { internal static readonly List Hubs = new List(); private static readonly Dictionary> StationToContainers = new Dictionary>(); private static readonly HashSet RebuildSeen = new HashSet(); private static readonly List Empty = new List(); private static readonly Dictionary AggCounts = new Dictionary(); private static int aggFrame = -1; private static List aggPool; private static readonly List NearPointResult = new List(); private static readonly HashSet NearPointSeen = new HashSet(); private static int nearPointFrame = -1; private static Vector3 nearPointPos; internal static void Register(AutomationHub hub) { if (!Hubs.Contains(hub)) { Hubs.Add(hub); } RebuildStationCache(); } internal static void Unregister(AutomationHub hub) { Hubs.Remove(hub); RebuildStationCache(); } internal static void RebuildStationCache() { StationToContainers.Clear(); foreach (AutomationHub hub in Hubs) { if ((Object)(object)hub == (Object)null) { continue; } foreach (CraftingStation linkedStation in hub.LinkedStations) { if ((Object)(object)linkedStation == (Object)null) { continue; } if (!StationToContainers.TryGetValue(linkedStation, out List value)) { value = new List(); StationToContainers[linkedStation] = value; } RebuildSeen.Clear(); RebuildSeen.UnionWith(value); foreach (Container linkedContainer in hub.LinkedContainers) { if ((Object)(object)linkedContainer != (Object)null && RebuildSeen.Add(linkedContainer)) { value.Add(linkedContainer); } } } } aggFrame = -1; aggPool = null; nearPointFrame = -1; } internal static List GetContainersForStation(CraftingStation station) { if ((Object)(object)station != (Object)null && StationToContainers.TryGetValue(station, out List value)) { return value; } return Empty; } internal static List GetContainersNearPoint(Vector3 point) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) if (nearPointFrame == Time.frameCount && nearPointPos == point) { return NearPointResult; } NearPointResult.Clear(); NearPointSeen.Clear(); foreach (AutomationHub hub in Hubs) { if ((Object)(object)hub == (Object)null || (ValConfig.RequireCores.Value && hub.CoreCount == 0) || Vector3.Distance(((Component)hub).transform.position, point) > hub.EffectiveRadius) { continue; } foreach (Container linkedContainer in hub.LinkedContainers) { if ((Object)(object)linkedContainer != (Object)null && NearPointSeen.Add(linkedContainer)) { NearPointResult.Add(linkedContainer); } } } nearPointFrame = Time.frameCount; nearPointPos = point; return NearPointResult; } internal static int CountInPool(List pool, string name) { if (pool == null || pool.Count == 0) { return 0; } if (aggFrame != Time.frameCount || aggPool != pool) { BuildAggregate(pool); } if (!AggCounts.TryGetValue(name, out var value)) { return 0; } return value; } private static void BuildAggregate(List pool) { bool value = ValConfig.EnableDebugMode.Value; double num = (value ? Time.realtimeSinceStartupAsDouble : 0.0); AggCounts.Clear(); int worldLevel = Game.m_worldLevel; foreach (Container item in pool) { if ((Object)(object)item == (Object)null) { continue; } Inventory inventory = item.GetInventory(); if (inventory == null) { continue; } foreach (ItemData allItem in inventory.GetAllItems()) { if (allItem.m_worldLevel >= worldLevel && !EpicLootIntegration.IsProtectedItem(allItem)) { string name = allItem.m_shared.m_name; AggCounts.TryGetValue(name, out var value2); AggCounts[name] = value2 + allItem.m_stack; } } } aggFrame = Time.frameCount; aggPool = pool; if (value) { double num2 = (Time.realtimeSinceStartupAsDouble - num) * 1000.0; Logger.LogInfo($"[Autosorter] aggregated {pool.Count} chests, {AggCounts.Count} item types in {num2:F2}ms."); } } } internal static class CraftFromStoragePatches { internal static int InCraftRequirements; internal static int InBuildRequirements; internal static int SumContainers(List pool, string name, int quality) { int num = 0; foreach (Container item in pool) { if ((Object)(object)item == (Object)null) { continue; } Inventory inventory = item.GetInventory(); if (inventory == null) { continue; } foreach (ItemData allItem in inventory.GetAllItems()) { if (Matches(allItem, name, quality)) { num += allItem.m_stack; } } } return num; } private static bool Matches(ItemData item, string name, int quality) { if (item == null || item.m_shared == null) { return false; } if (item.m_shared.m_name != name) { return false; } if (quality >= 0 && item.m_quality != quality) { return false; } if (item.m_worldLevel < Game.m_worldLevel) { return false; } return !EpicLootIntegration.IsProtectedItem(item); } internal static void ClaimOwnership(Container container) { if (!((Object)(object)container == (Object)null) && (Object)(object)container.m_nview != (Object)null && container.m_nview.IsValid() && !container.m_nview.IsOwner()) { container.m_nview.ClaimOwnership(); } } internal static int RemoveFromContainers(List pool, string name, int amount, int itemQuality) { int num = 0; foreach (Container item in pool) { if (amount <= 0) { break; } if ((Object)(object)item == (Object)null) { continue; } Inventory inventory = item.GetInventory(); if (inventory == null) { continue; } bool flag = false; List allItems = inventory.GetAllItems(); int num2 = allItems.Count - 1; while (num2 >= 0 && amount > 0) { ItemData val = allItems[num2]; if (Matches(val, name, itemQuality)) { if (!flag) { ClaimOwnership(item); flag = true; } int num3 = Mathf.Min(val.m_stack, amount); inventory.RemoveItem(val, num3); amount -= num3; num += num3; } num2--; } } return num; } } [HarmonyPatch(typeof(Player), "HaveRequirementItems", new Type[] { typeof(Recipe), typeof(bool), typeof(int), typeof(int) })] internal static class Player_HaveRequirementItems_Patch { private static void Postfix(Player __instance, ref bool __result, Recipe piece, bool discover, int qualityLevel, int amount) { if (__result || discover || (Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } CraftingStation currentCraftingStation = __instance.GetCurrentCraftingStation(); if ((Object)(object)currentCraftingStation == (Object)null) { return; } List containersForStation = ContainerNetwork.GetContainersForStation(currentCraftingStation); if (containersForStation.Count == 0) { return; } bool requireOnlyOneIngredient = piece.m_requireOnlyOneIngredient; Requirement[] resources = piece.m_resources; foreach (Requirement val in resources) { if ((Object)(object)val.m_resItem == (Object)null) { continue; } string name = val.m_resItem.m_itemData.m_shared.m_name; int num = val.GetAmount(qualityLevel) * amount; int num2 = 0; for (int j = 1; j < val.m_resItem.m_itemData.m_shared.m_maxQuality + 1; j++) { int num3 = ((Humanoid)__instance).m_inventory.CountItems(name, j, true); if (num3 > num2) { num2 = num3; } } int num4 = num2 + ContainerNetwork.CountInPool(containersForStation, name); if (requireOnlyOneIngredient) { if (num4 >= num) { __result = true; return; } } else if (num4 < num) { return; } } __result = !requireOnlyOneIngredient; } } [HarmonyPatch(typeof(InventoryGui), "SetupRequirementList")] internal static class InventoryGui_SetupRequirementList_Patch { private static void Prefix() { CraftFromStoragePatches.InCraftRequirements++; } [HarmonyPriority(0)] private static void Postfix() { CraftFromStoragePatches.InCraftRequirements--; } } [HarmonyPatch(typeof(Hud), "SetupPieceInfo")] internal static class Hud_SetupPieceInfo_Patch { private static void Prefix() { CraftFromStoragePatches.InBuildRequirements++; } [HarmonyPriority(0)] private static void Postfix() { CraftFromStoragePatches.InBuildRequirements--; } } [HarmonyPatch(typeof(Inventory), "CountItems")] internal static class Inventory_CountItems_Patch { private static void Postfix(Inventory __instance, ref int __result, string name, int quality) { //IL_0052: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(name)) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || __instance != ((Humanoid)localPlayer).m_inventory) { return; } List list; if (CraftFromStoragePatches.InCraftRequirements > 0) { CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation(); if ((Object)(object)currentCraftingStation == (Object)null) { return; } list = ContainerNetwork.GetContainersForStation(currentCraftingStation); } else { if (CraftFromStoragePatches.InBuildRequirements <= 0) { return; } list = ContainerNetwork.GetContainersNearPoint(((Component)localPlayer).transform.position); } if (list.Count != 0) { __result += ((quality < 0) ? ContainerNetwork.CountInPool(list, name) : CraftFromStoragePatches.SumContainers(list, name, quality)); } } } [HarmonyPatch(typeof(Player), "HaveRequirements", new Type[] { typeof(Piece), typeof(RequirementMode) })] internal static class Player_HaveRequirements_Piece_Patch { private static void Postfix(Player __instance, ref bool __result, Piece piece, RequirementMode mode) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) if (__result || (int)mode != 0 || (Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || ((Object)(object)piece.m_craftingStation != (Object)null && (Object)(object)CraftingStation.HaveBuildStationInRange(piece.m_craftingStation.m_name, ((Component)__instance).transform.position) == (Object)null && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)27)) || (piece.m_dlc != null && piece.m_dlc.Length > 0 && !DLCMan.instance.IsDLCInstalled(piece.m_dlc))) { return; } List containersNearPoint = ContainerNetwork.GetContainersNearPoint(((Component)__instance).transform.position); if (containersNearPoint.Count == 0) { return; } Requirement[] resources = piece.m_resources; foreach (Requirement val in resources) { if (!((Object)(object)val.m_resItem == (Object)null) && val.m_amount > 0) { string name = val.m_resItem.m_itemData.m_shared.m_name; if (((Humanoid)__instance).m_inventory.CountItems(name, -1, true) + ContainerNetwork.CountInPool(containersNearPoint, name) < val.m_amount) { return; } } } __result = true; } } [HarmonyPatch(typeof(Player), "ConsumeResources")] internal static class Player_ConsumeResources_Patch { private static void Prefix(Player __instance, Requirement[] requirements, int qualityLevel, int itemQuality, int multiplier) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } CraftingStation currentCraftingStation = __instance.GetCurrentCraftingStation(); List list = (((Object)(object)currentCraftingStation != (Object)null) ? ContainerNetwork.GetContainersForStation(currentCraftingStation) : ContainerNetwork.GetContainersNearPoint(((Component)__instance).transform.position)); if (list.Count == 0) { return; } foreach (Requirement val in requirements) { if ((Object)(object)val.m_resItem == (Object)null) { continue; } int num = val.GetAmount(qualityLevel) * multiplier; if (num > 0) { string name = val.m_resItem.m_itemData.m_shared.m_name; int num2 = ((Humanoid)__instance).m_inventory.CountItems(name, itemQuality, true); int num3 = num - num2; if (num3 > 0) { CraftFromStoragePatches.RemoveFromContainers(list, name, num3, itemQuality); } } } } } internal static class EpicLootIntegration { internal const string EpicLootGUID = "randyknapp.mods.epicloot"; private static readonly List Empty = new List(); private static readonly List ItemsResult = new List(); private static int itemsFrame = -1; internal static bool Active { get; private set; } internal static void Register() { if (Active) { return; } if (!EpicLoot.IsLoaded()) { Logger.LogDebug("[Autosorter] Epic Loot not present; skipping integration."); return; } Active = EpicLoot.RegisterInventoryProvider("MidngightsFX.DvergerAutomation", GetItems, CountItem, RemoveItem, RemoveExactItem); if (Active) { Logger.LogInfo("[Autosorter] Registered inventory provider with Epic Loot " + EpicLoot.GetPluginVersion() + "."); } else { Logger.LogWarning("[Autosorter] Epic Loot is present but refused the inventory provider registration."); } } internal static void Unregister() { if (Active) { EpicLoot.UnregisterInventoryProvider("MidngightsFX.DvergerAutomation"); Active = false; } } internal static bool IsProtectedItem(ItemData item) { if (!Active || item == null || item.m_shared == null) { return false; } if (item.m_shared.m_maxStackSize > 1) { return false; } return item.IsMagicItem(); } private static List Pool() { //IL_002b: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return Empty; } CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation(); if (!((Object)(object)currentCraftingStation != (Object)null)) { return ContainerNetwork.GetContainersNearPoint(((Component)localPlayer).transform.position); } return ContainerNetwork.GetContainersForStation(currentCraftingStation); } private static List GetItems() { if (itemsFrame == Time.frameCount) { return ItemsResult; } ItemsResult.Clear(); foreach (Container item in Pool()) { if (!((Object)(object)item == (Object)null)) { Inventory inventory = item.GetInventory(); if (inventory != null) { ItemsResult.AddRange(inventory.GetAllItems()); } } } itemsFrame = Time.frameCount; return ItemsResult; } private static int CountItem(string name) { if (!string.IsNullOrEmpty(name)) { return ContainerNetwork.CountInPool(Pool(), name); } return 0; } private static int RemoveItem(string name, int amount) { if (string.IsNullOrEmpty(name) || amount <= 0) { return 0; } return CraftFromStoragePatches.RemoveFromContainers(Pool(), name, amount, -1); } private static int RemoveExactItem(ItemData item, int amount) { if (item == null || amount <= 0) { return 0; } foreach (Container item2 in Pool()) { if (!((Object)(object)item2 == (Object)null)) { Inventory inventory = item2.GetInventory(); if (inventory != null && inventory.ContainsItem(item)) { CraftFromStoragePatches.ClaimOwnership(item2); int num = Mathf.Min(item.m_stack, amount); inventory.RemoveItem(item, num); return num; } } } return 0; } } } namespace DvergerAutomation.Common { public static class JotunnPiece { public class LoadedGameObjects { public GameObject Prefab { get; set; } public Sprite Sprite { get; set; } public GameObject ScenePrefab { get; set; } } public class PieceCost { public string prefab { get; set; } public int amount { get; set; } public bool refundable { get; set; } = true; } public class PieceConfigs { public ConfigEntry Enabled { get; set; } public ConfigEntry RequiresWorkbench { get; set; } public ConfigEntry Workbench { get; set; } public ConfigEntry PieceCategory { get; set; } public ConfigEntry PieceCost { get; set; } public List UpdatedCost { get; set; } = new List(); } public class JotunnBuildPiece { public string Name { get; set; } public bool Enabled { get; set; } = true; public string Prefab { get; set; } public string Sprite { get; set; } public string Category { get; set; } = "Misc"; public string Workbench { get; set; } = "piece_workbench"; public List PieceCost { get; set; } = new List(); public LoadedGameObjects Objs { get; set; } public PieceConfigs Cfgs { get; set; } } private static List BuildPieces = new List(); private static bool PiecesReady = false; public static void RegisterJotunnPiece(JotunnBuildPiece jbuildpiece) { LoadedGameObjects loadedGameObjects = new LoadedGameObjects(); loadedGameObjects.Prefab = DvergerAutomation.EmbeddedResourceBundle.LoadAsset(jbuildpiece.Prefab + ".prefab"); loadedGameObjects.Sprite = DvergerAutomation.EmbeddedResourceBundle.LoadAsset(jbuildpiece.Sprite + ".png"); jbuildpiece.Objs = loadedGameObjects; jbuildpiece.Cfgs = new PieceConfigs(); InitialPieceSetup(jbuildpiece); BuildPieces.Add(jbuildpiece); PrefabManager.OnPrefabsRegistered += ResolveAndApplyScenePrefab; void ResolveAndApplyScenePrefab() { IEnumerable source = from obj in Resources.FindObjectsOfTypeAll() where ((Object)obj).name == jbuildpiece.Prefab select obj; if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo($"Found {jbuildpiece.Prefab} scene parent objects: {source.Count()}"); } GameObject val = source.FirstOrDefault(); if ((Object)(object)val == (Object)null) { Logger.LogWarning("Could not find scene prefab '" + jbuildpiece.Prefab + "' after prefab registration; skipping in-place setup for " + jbuildpiece.Name + "."); } else { jbuildpiece.Objs.ScenePrefab = val; PiecesReady = true; ApplyWorkbench(jbuildpiece); ApplyCategory(jbuildpiece); ApplyRecipe(jbuildpiece); } } } private static void InitialPieceSetup(JotunnBuildPiece jbuildpiece) { //IL_028b: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Unknown result type (might be due to invalid IL or missing references) //IL_029d: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Expected O, but got Unknown //IL_02d5: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_031b: Unknown result type (might be due to invalid IL or missing references) //IL_0331: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Expected O, but got Unknown //IL_0357: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Expected O, but got Unknown jbuildpiece.Cfgs.Workbench = ValConfig.BindServerConfig(jbuildpiece.Name ?? "", "Workbench", jbuildpiece.Workbench, "The table required to allow building this piece, eg: 'forge', 'piece_workbench', 'blackforge', 'piece_artisanstation'."); jbuildpiece.Cfgs.Workbench.SettingChanged += RequiredBench_SettingChanged; jbuildpiece.Cfgs.Enabled = ValConfig.BindServerConfig(jbuildpiece.Name ?? "", "Enabled", jbuildpiece.Enabled, "Enable/Disable the " + jbuildpiece.Name + "."); jbuildpiece.Cfgs.Enabled.SettingChanged += BuildRecipeChanged_SettingChanged; jbuildpiece.Cfgs.PieceCategory = ValConfig.BindServerConfig(jbuildpiece.Name ?? "", "Piece Category", jbuildpiece.Category, "Piece category for building.", PieceCategories.GetAcceptableValueList()); jbuildpiece.Cfgs.PieceCategory.SettingChanged += CraftingCategory_SettingChanged; List list = new List(); foreach (PieceCost item in jbuildpiece.PieceCost) { list.Add($"{item.prefab},{item.amount},{item.refundable}"); } string text = string.Join("|", list); jbuildpiece.Cfgs.PieceCost = ValConfig.BindServerConfig(jbuildpiece.Name ?? "", "Building Cost", text, "Cost to build. Find item ids: https://valheim.fandom.com/wiki/Item_IDs Format: resouce_id,amount,refund eg: Wood,8,true|LeatherScraps,4,false", null, advanced: true); if (!PieceRecipeConfigUpdater(jbuildpiece, jbuildpiece.Cfgs.PieceCost.Value, during_runtime: false)) { Logger.LogWarning(jbuildpiece.Name + " has an invalid piece cost. The default will be used instead."); PieceRecipeConfigUpdater(jbuildpiece, text, during_runtime: false); } jbuildpiece.Cfgs.PieceCost.SettingChanged += BuildRecipeChanged_SettingChanged; List list2 = new List(); foreach (PieceCost item2 in jbuildpiece.Cfgs.UpdatedCost) { list2.Add(new RequirementConfig { Item = item2.prefab, Amount = item2.amount, Recover = item2.refundable }); } PieceConfig val = new PieceConfig { CraftingStation = jbuildpiece.Cfgs.Workbench.Value, PieceTable = PieceTables.Hammer, Category = jbuildpiece.Cfgs.PieceCategory.Value, Icon = jbuildpiece.Objs.Sprite, Requirements = list2.ToArray() }; PieceManager.Instance.AddPiece(new CustomPiece(jbuildpiece.Objs.Prefab, true, val)); void BuildRecipeChanged_SettingChanged(object sender, EventArgs e) { if (PiecesReady && !((Object)(object)jbuildpiece.Objs.ScenePrefab == (Object)null)) { if (sender.GetType() == typeof(ConfigEntry)) { ConfigEntry val2 = (ConfigEntry)sender; if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo("Recieved new piece config " + val2.Value); } if (!PieceRecipeConfigUpdater(jbuildpiece, val2.Value)) { return; } } ApplyRecipe(jbuildpiece); } } void CraftingCategory_SettingChanged(object sender, EventArgs e) { if (PiecesReady && !((Object)(object)jbuildpiece.Objs.ScenePrefab == (Object)null)) { ApplyCategory(jbuildpiece); } } void RequiredBench_SettingChanged(object sender, EventArgs e) { if (PiecesReady && !((Object)(object)jbuildpiece.Objs.ScenePrefab == (Object)null)) { ApplyWorkbench(jbuildpiece); } } } private static void ApplyWorkbench(JotunnBuildPiece jbuildpiece) { ConfigEntry requiresWorkbench = jbuildpiece.Cfgs.RequiresWorkbench; if ((requiresWorkbench != null && !requiresWorkbench.Value) || string.IsNullOrEmpty(jbuildpiece.Cfgs.Workbench.Value) || jbuildpiece.Cfgs.Workbench.Value.ToLower() == "none") { Logger.LogInfo("Setting required crafting station to none."); jbuildpiece.Objs.ScenePrefab.GetComponent().m_craftingStation = null; return; } GameObject prefab = PrefabManager.Instance.GetPrefab(jbuildpiece.Cfgs.Workbench.Value); CraftingStation val = ((prefab != null) ? prefab.GetComponent() : null); if ((Object)(object)val == (Object)null) { Logger.LogWarning("Required crafting station does not exist or does not have a crafting station componet, check your prefab name (" + jbuildpiece.Cfgs.Workbench.Value + ")."); return; } if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo("Setting crafting station to " + jbuildpiece.Cfgs.Workbench.Value + "."); } jbuildpiece.Objs.ScenePrefab.GetComponent().m_craftingStation = val; } private static void ApplyCategory(JotunnBuildPiece jbuildpiece) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) PieceCategory? val = PieceManager.Instance.GetPieceCategory(jbuildpiece.Cfgs.PieceCategory.Value); if (!val.HasValue) { val = PieceManager.Instance.AddPieceCategory(jbuildpiece.Cfgs.PieceCategory.Value); } jbuildpiece.Objs.ScenePrefab.GetComponent().m_category = val.Value; } private static void ApplyRecipe(JotunnBuildPiece jbuildpiece) { //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Expected O, but got Unknown //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Expected O, but got Unknown List list = new List(); if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo("Validating and building requirementsConfig"); } foreach (PieceCost item in jbuildpiece.Cfgs.UpdatedCost) { if ((Object)(object)PrefabManager.Instance.GetPrefab(item.prefab) == (Object)null) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo(item.prefab + " is not a valid prefab, skipping recipe update."); } return; } if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo($"Checking entry {item.prefab} amount:{item.amount} refund?:{item.refundable}"); } list.Add(new RequirementConfig { Item = item.prefab, Amount = item.amount, Recover = item.refundable }); } if (jbuildpiece.Cfgs.Enabled.Value) { if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo("Updating Piece."); } List list2 = new List(); foreach (RequirementConfig item2 in list) { Requirement val = new Requirement(); GameObject prefab = PrefabManager.Instance.GetPrefab(item2.Item.Replace("JVLmock_", "")); val.m_resItem = ((prefab != null) ? prefab.GetComponent() : null); val.m_amount = item2.Amount; val.m_recover = item2.Recover; list2.Add(val); } if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo($"Fixed mock requirements {list2.Count}."); } jbuildpiece.Objs.ScenePrefab.GetComponent().m_resources = list2.ToArray(); if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo($"New requirements set {jbuildpiece.Objs.ScenePrefab.GetComponent().m_resources}."); } } else { jbuildpiece.Objs.ScenePrefab.GetComponent().m_enabled = false; } } private static bool PieceRecipeConfigUpdater(JotunnBuildPiece jbuildpiece, string rawrecipe, bool during_runtime = true) { string[] array = rawrecipe.Split(new char[1] { '|' }); List list = new List(); if (array.Length >= 1) { string[] array2 = array; foreach (string text in array2) { string[] array3 = text.Split(new char[1] { ',' }); if (array3.Length != 3) { Logger.LogWarning(text + " is invalid, it does not have enough segments. Proper format is: PREFABNAME,COST,REFUND_BOOL eg: Wood,8,false"); return false; } if (ValConfig.EnableDebugMode.Value) { string text2 = ""; string[] array4 = array3; foreach (string text3 in array4) { text2 = text2 + " " + text3; } } if (during_runtime && (Object)(object)PrefabManager.Instance.GetPrefab(array3[0]) == (Object)null) { Logger.LogWarning(array3[0] + " is an invalid prefab and does not exist."); return false; } if (array3[0].Length == 0 || array3[1].Length == 0 || array3[2].Length == 0) { Logger.LogWarning(text + " is invalid, one segment does not have enough data. Proper format is: PREFABNAME,CRAFT_COST,REFUND_BOOL eg: Wood,8,false"); return false; } if (!bool.TryParse(array3[2], out var result)) { Logger.LogWarning(text + " is invalid, the REFUND_BOOL could not be parsed to (true/false). Proper format is: PREFABNAME,CRAFT_COST,REFUND_BOOL eg: Wood,8,false"); return false; } if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo("prefab: " + array3[0] + " c:" + array3[1] + " u:" + array3[2]); } list.Add(new PieceCost { prefab = array3[0], amount = int.Parse(array3[1]), refundable = result }); } jbuildpiece.Cfgs.UpdatedCost.Clear(); foreach (PieceCost item in list) { jbuildpiece.Cfgs.UpdatedCost.Add(item); } if (ValConfig.EnableDebugMode.Value) { string text4 = ""; foreach (PieceCost item2 in list) { text4 += $" {item2.prefab} c:{item2.amount} r:{item2.refundable}"; } Logger.LogInfo("Updated recipe:" + text4); } return true; } Logger.LogWarning("Invalid recipe: " + rawrecipe + ". defaults will be used. Check your prefab names."); jbuildpiece.Cfgs.UpdatedCost = jbuildpiece.PieceCost; return false; } } internal static class LocalizationLoader { internal static string LocalizationFolder = "Localizations"; internal static void AddLocalizations() { CustomLocalization localization = DvergerAutomation.Localization; string text = Path.Combine(Paths.ConfigPath, "DvergerAutomation", LocalizationFolder); Directory.CreateDirectory(text); string[] manifestResourceNames = Assembly.GetExecutingAssembly().GetManifestResourceNames(); foreach (string text2 in manifestResourceNames) { if (!text2.Contains(LocalizationFolder)) { continue; } string text3 = Regex.Replace(ReadEmbeddedResourceFile(text2), "\\/\\/.*", ""); Dictionary internal_localization = SimpleJson.DeserializeObject>(text3); string[] array = text2.Split(new char[1] { '.' }); if (File.Exists(text + "/" + array[2] + ".json")) { string text4 = File.ReadAllText(text + "/" + array[2] + ".json"); try { Dictionary dictionary = SimpleJson.DeserializeObject>(text4); UpdateLocalizationWithMissingKeys(internal_localization, dictionary); Logger.LogDebug("Reading " + text + "/" + array[2] + ".json"); File.WriteAllText(text + "/" + array[2] + ".json", SimpleJson.SerializeObject((object)dictionary)); string text5 = File.ReadAllText(text + "/" + array[2] + ".json"); localization.AddJsonFile(array[2], text5); } catch { File.WriteAllText(text + "/" + array[2] + ".json", text3); Logger.LogDebug("Reading " + text2); localization.AddJsonFile(array[2], text3); } } else { File.WriteAllText(text + "/" + array[2] + ".json", text3); Logger.LogDebug("Reading " + text2); localization.AddJsonFile(array[2], text3); } Logger.LogDebug("Added localization: '" + array[2] + "'"); } } private static Dictionary UpdateLocalizationWithMissingKeys(Dictionary internal_localization, Dictionary cached_localization) { if (internal_localization.Keys != cached_localization.Keys) { List list = cached_localization.Keys.ToList(); foreach (KeyValuePair item in internal_localization) { list.Remove(item.Key); if (!cached_localization.ContainsKey(item.Key)) { Logger.LogDebug("Adding missing localization key " + item.Key); cached_localization.Add(item.Key, item.Value); } } if (list.Count > 0) { Logger.LogDebug("Removing extra keys " + string.Join(",", list) + "."); foreach (string item2 in list) { cached_localization.Remove(item2); } } } return cached_localization; } private static string ReadEmbeddedResourceFile(string filename) { using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(filename); using StreamReader streamReader = new StreamReader(stream); return streamReader.ReadToEnd(); } } } namespace EpicLootAPI { [Serializable] [PublicAPI] public enum AbilityActivationMode { Passive, Triggerable, Activated } [Serializable] [PublicAPI] public enum AbilityAction { Custom, StatusEffect } [Serializable] [PublicAPI] public class AbilityDefinition { public string ID = ""; public string IconAsset = ""; public AbilityActivationMode ActivationMode; public float Cooldown; public AbilityAction Action; public List ActionParams = new List(); internal static readonly Method API_AddAbility = new Method("AddAbility"); internal static readonly Method API_UpdateAbility = new Method("UpdateAbility"); internal static List Abilities = new List(); [Description("Register a status effect ability which activates on player input")] public AbilityDefinition(string ID, string iconAsset, float cooldown, string statusEffectName) { this.ID = ID; ActivationMode = AbilityActivationMode.Activated; Cooldown = cooldown; Action = AbilityAction.StatusEffect; ActionParams.Add(statusEffectName); IconAsset = iconAsset; Abilities.Add(this); } internal AbilityDefinition(string ID, AbilityActivationMode mode) { this.ID = ID; ActivationMode = mode; } public AbilityDefinition() { } public static void RegisterAll() { foreach (AbilityDefinition item in new List(Abilities)) { item.Register(); } } public bool Register() { string text = JsonConvert.SerializeObject((object)this); if (!(API_AddAbility.Invoke(text)[0] is string value)) { return false; } RunTimeRegistry.Register(this, value); Abilities.Remove(this); EpicLoot.logger.LogDebug("Registered ability: " + ID); return true; } public bool Update() { if (!RunTimeRegistry.TryGetValue(this, out string value)) { return false; } string text = JsonConvert.SerializeObject((object)this); bool flag = (bool)(API_UpdateAbility.Invoke(value, text)[0] ?? ((object)false)); EpicLoot.logger.LogDebug($"Updated ability {ID}: {flag}"); return flag; } } [PublicAPI] public class AbilityProxyDefinition { public readonly AbilityDefinition Ability; public readonly Dictionary Callbacks = new Dictionary(); internal static readonly List ProxyAbilities = new List(); internal static readonly Method API_RegisterProxyAbility = new Method("RegisterProxyAbility"); internal static readonly Method API_UpdateProxyAbility = new Method("UpdateProxyAbility"); [Description("Register a complex ability behavior using Proxy class")] public AbilityProxyDefinition(string ID, AbilityActivationMode mode, Proxy definition) { Ability = new AbilityDefinition(ID, mode); RegisterCallbacks(definition); ProxyAbilities.Add(this); } [Description("Register a complex ability behavior using Proxy class")] public AbilityProxyDefinition(string ID, AbilityActivationMode mode, Type type) { Ability = new AbilityDefinition(ID, mode); if (!typeof(Proxy).IsAssignableFrom(type)) { EpicLoot.logger.LogError("Ability Proxy " + ID + " Type " + type.Name + " does not implement Proxy class"); return; } try { object obj = Activator.CreateInstance(type); RegisterCallbacks((Proxy)obj); ProxyAbilities.Add(this); } catch (Exception ex) { EpicLoot.logger.LogError("Failed to create instance of " + type.Name + ": " + ex.Message); } } private void RegisterCallbacks(Proxy implementation) { Type type = implementation.GetType(); MethodInfo[] methods = typeof(Proxy).GetMethods(); foreach (MethodInfo methodInfo in methods) { try { Type[] array = (from p in methodInfo.GetParameters() select p.ParameterType).ToArray(); MethodInfo method = type.GetMethod(methodInfo.Name, array); if (method == null) { EpicLoot.logger.LogWarning("Method " + methodInfo.Name + " not found in implementation"); continue; } Type type2 = ((!(methodInfo.ReturnType == typeof(void))) ? Expression.GetFuncType(array.Concat(new Type[1] { methodInfo.ReturnType }).ToArray()) : ((array.Length != 0) ? Expression.GetActionType(array) : typeof(Action))); Delegate value = Delegate.CreateDelegate(type2, implementation, method); Callbacks[methodInfo.Name] = value; } catch (Exception ex) { EpicLoot.logger.LogError("Failed to register callback for method " + methodInfo.Name + ": " + ex.Message); } } } public static void RegisterAll() { foreach (AbilityProxyDefinition item in new List(ProxyAbilities)) { item.Register(); } } public bool Register() { string text = JsonConvert.SerializeObject((object)Ability); if (!(API_RegisterProxyAbility.Invoke(text, Callbacks)[0] is string value)) { return false; } RunTimeRegistry.Register(this, value); ProxyAbilities.Remove(this); EpicLoot.logger.LogDebug("Registered proxy ability: " + Ability.ID); return true; } public bool Update() { if (!RunTimeRegistry.TryGetValue(this, out string value)) { return false; } string text = JsonConvert.SerializeObject((object)Ability); bool flag = (bool)(API_UpdateProxyAbility.Invoke(value, text, Callbacks)[0] ?? ((object)false)); EpicLoot.logger.LogDebug($"Updated proxy ability: {Ability.ID}, {flag}"); return flag; } } [Description("Functions are converted into delegates when registered to epic loot")] [PublicAPI] public class Proxy { protected Player Player; public string AbilityID = ""; public float Cooldown; public virtual string CooldownEndKey => "EpicLoot." + AbilityID + ".CooldownEnd"; public virtual void Initialize(Player player, string id, float cooldown) { Player = player; AbilityID = id; Cooldown = cooldown; } public virtual void OnUpdate() { } public virtual bool ShouldTrigger() { return false; } public virtual bool IsOnCooldown() { if (HasCooldown()) { return GetTime() < GetCooldownEndTime(); } return false; } public virtual float TimeUntilCooldownEnds() { return Mathf.Max(0f, GetCooldownEndTime() - GetTime()); } public virtual float PercentCooldownComplete() { if (HasCooldown() && IsOnCooldown()) { return 1f - TimeUntilCooldownEnds() / Cooldown; } return 1f; } public virtual bool CanActivate() { return !IsOnCooldown(); } public virtual void TryActivate() { if (CanActivate()) { Activate(); } } public virtual void Activate() { if (HasCooldown()) { float cooldownEndTime = GetTime() + Cooldown; SetCooldownEndTime(cooldownEndTime); } } public virtual void ActivateCustomAction() { } public virtual void ActivateStatusEffectAction() { } public virtual bool HasCooldown() { return Cooldown > 0f; } public virtual void SetCooldownEndTime(float cooldownEndTime) { if (!((Object)(object)Player == (Object)null)) { ((Character)Player).m_nview.GetZDO().Set(CooldownEndKey, cooldownEndTime); } } public virtual float GetCooldownEndTime() { if ((Object)(object)Player == (Object)null) { return 0f; } return ((Character)Player).m_nview.GetZDO().GetFloat(CooldownEndKey, 0f); } public virtual void OnRemoved() { } protected static float GetTime() { return (float)ZNet.instance.GetTimeSeconds(); } } public static class EpicLoot { [PublicAPI] public static class ChangeReason { public const string Enchant = "Enchant"; public const string Augment = "Augment"; public const string Disenchant = "Disenchant"; public const string Rune = "Rune"; public const string Temper = "Temper"; public const string Socket = "Socket"; public const string Unsocket = "Unsocket"; public const string LootRoll = "LootRoll"; public const string Transfer = "Transfer"; public const string AddSocket = "AddSocket"; public const string Unspecified = "Unspecified"; } public static readonly Logger logger = new Logger(); private static readonly Method API_GetTotalActiveMagicEffectValue = new Method("GetTotalActiveMagicEffectValue"); private static readonly Method API_GetTotalActiveMagicEffectValueForWeapon = new Method("GetTotalActiveMagicEffectValueForWeapon"); private static readonly Method API_HasActiveMagicEffect = new Method("HasActiveMagicEffect"); private static readonly Method API_HasActiveMagicEffectOnWeapon = new Method("HasActiveMagicEffectOnWeapon"); private static readonly Method API_GetTotalActiveSetEffectValue = new Method("GetTotalActiveSetEffectValue"); private static readonly Method API_GetAllActiveMagicEffects = new Method("GetAllActiveMagicEffects"); private static readonly Method API_GetAllSetMagicEffects = new Method("GetAllActiveSetMagicEffects"); private static readonly Method API_GetPlayerTotalActiveMagicEffectValue = new Method("GetTotalPlayerActiveMagicEffectValue"); private static readonly Method API_PlayerHasActiveMagicEffect = new Method("PlayerHasActiveMagicEffect"); private static readonly Method API_HasLegendaryItem = new Method("HasLegendaryItem"); private static readonly Method API_HasLegendarySet = new Method("HasLegendarySet"); private static readonly Method API_RegisterAsset = new Method("RegisterAsset"); private static readonly Method API_GetMagicItemJson = new Method("GetMagicItemJson"); private static readonly Method API_RegisterMagicEffectRequirement = new Method("RegisterMagicEffectRequirement", typeof(string), typeof(Func)); private static readonly Method API_AddMagicItemChangedListener = new Method("AddMagicItemChangedListener", typeof(Action)); private static readonly Method API_RemoveMagicItemChangedListener = new Method("RemoveMagicItemChangedListener", typeof(Action)); private static readonly Method API_AddLootGeneratedListener = new Method("AddLootGeneratedListener", typeof(Action)); private static readonly Method API_RemoveLootGeneratedListener = new Method("RemoveLootGeneratedListener", typeof(Action)); private static readonly Method API_AddBountyCompletedListener = new Method("AddBountyCompletedListener", typeof(Action)); private static readonly Method API_RemoveBountyCompletedListener = new Method("RemoveBountyCompletedListener", typeof(Action)); private static readonly Method API_TryMakeMagicItem = new Method("TryMakeMagicItem"); private static readonly Method API_RollMagicItemJson = new Method("RollMagicItemJson"); private static readonly Method API_ApplyMagicItemJson = new Method("ApplyMagicItemJson"); private static readonly Method API_GetLuckFactor = new Method("GetLuckFactor"); private static readonly Method API_RollEffectCountForRarity = new Method("RollEffectCountForRarity"); private static readonly Method API_GetLegendaryIDs = new Method("GetLegendaryIDs"); private static readonly Method API_GetLegendaryInfoJson = new Method("GetLegendaryInfoJson"); private static readonly Method API_GetAvailableEffectTypes = new Method("GetAvailableEffectTypes"); private static readonly Method API_AddLootTables = new Method("AddLootTables"); private static readonly Method API_UpdateLootTables = new Method("UpdateLootTables"); private static readonly Method API_RegisterInventoryProvider = new Method("RegisterInventoryProvider", typeof(string), typeof(Func>), typeof(Func), typeof(Func), typeof(Func)); private static readonly Method API_UnregisterInventoryProvider = new Method("UnregisterInventoryProvider"); private static readonly Method API_RegisterEquipmentProvider = new Method("RegisterEquipmentProvider", typeof(string), typeof(Func>)); private static readonly Method API_UnregisterEquipmentProvider = new Method("UnregisterEquipmentProvider"); private static readonly Method API_RegisterSacrificeFilter = new Method("RegisterSacrificeFilter", typeof(string), typeof(Func)); private static readonly Method API_UnregisterSacrificeFilter = new Method("UnregisterSacrificeFilter"); private static readonly Method API_InvalidatePlayerEffectCache = new Method("InvalidatePlayerEffectCache"); private static readonly Method API_GetRegisteredProviders = new Method("GetRegisteredProviders"); private static readonly Method API_GetApiVersion = new Method("GetApiVersion"); private static readonly Method API_GetPluginVersion = new Method("GetPluginVersion"); private static readonly Method API_HasEndpoint = new Method("HasEndpoint"); private static readonly Method API_IsMagicItem = new Method("IsMagicItem"); private static readonly Method API_TryGetRarity = new Method("TryGetRarity"); private static readonly Method API_GetRarityCount = new Method("GetRarityCount"); private static readonly Method API_GetRarityColorByIndex = new Method("GetRarityColorByIndex"); private static readonly Method API_GetRarityDisplayNameByIndex = new Method("GetRarityDisplayNameByIndex"); private static readonly Method API_GetItemRarityColor = new Method("GetItemRarityColor"); private static readonly Method API_IsEpicLootItem = new Method("IsEpicLootItem"); private static readonly Method API_IsShardStone = new Method("IsShardStone"); private static readonly Method API_IsRunestone = new Method("IsRunestone"); private static readonly Method API_IsMagicCraftingMaterial = new Method("IsMagicCraftingMaterial"); private static readonly Method API_IsUnidentified = new Method("IsUnidentified"); private static readonly Method API_CanBeMagicItem = new Method("CanBeMagicItem"); private static readonly Method API_ItemHasMagicEffect = new Method("ItemHasMagicEffect"); private static readonly Method API_GetAllMagicEffectTypes = new Method("GetAllMagicEffectTypes"); private static readonly Method API_GetEnchantCostsJson = new Method("GetEnchantCostsJson"); private static readonly Method API_GetSacrificeProductsJson = new Method("GetSacrificeProductsJson"); private static readonly Method API_GetItemDisplayName = new Method("GetItemDisplayName"); private static readonly Method API_GetItemDecoratedName = new Method("GetItemDecoratedName", typeof(ItemData), typeof(string)); private static readonly Method API_ApplyMagicItemBackground = new Method("ApplyMagicItemBackground", typeof(GameObject), typeof(GameObject), typeof(ItemData), typeof(bool)); private static readonly Method API_ApplyMagicItemBackgroundToIcon = new Method("ApplyMagicItemBackgroundToIcon", typeof(GameObject), typeof(ItemData)); [PublicAPI] [Description("Send all your custom conversions, effects, item definitions, etc... to Epic Loot")] public static void RegisterAll() { MaterialConversion.RegisterAll(); MagicItemEffectDefinition.RegisterAll(); AbilityDefinition.RegisterAll(); CustomRecipe.RegisterAll(); Sacrifice.RegisterAll(); TreasureMap.RegisterAll(); SecretStashItem.RegisterAll(); LegendaryInfo.RegisterAll(); LegendarySetInfo.RegisterAll(); BountyTarget.RegisterAll(); AbilityProxyDefinition.RegisterAll(); } [PublicAPI] [Description("Register asset into EpicLoot in order to target them in your definitions")] public static bool RegisterAsset(string name, object asset) { bool flag = (bool)(API_RegisterAsset.Invoke(name, asset)[0] ?? ((object)false)); logger.LogDebug($"Registered asset: {name}, {flag}"); return flag; } [PublicAPI] public static bool RegisterMagicEffectRequirement(string externalRequirement, Func requirement) { bool flag = (bool)(API_RegisterMagicEffectRequirement.Invoke(externalRequirement, requirement)[0] ?? ((object)false)); logger.LogDebug($"Registered magic effect requirement: {externalRequirement}, {flag}"); return flag; } [PublicAPI] public static bool HasLegendaryItem(this Player player, string legendaryItemID) { bool flag = (bool)(API_HasLegendaryItem.Invoke(player, legendaryItemID)[0] ?? ((object)false)); logger.LogDebug($"Has legendary item: {legendaryItemID}, {flag} "); return flag; } [PublicAPI] public static bool HasLegendarySet(this Player player, string legendarySetID, out int count) { count = 0; object[] array = API_HasLegendarySet.Invoke(player, legendarySetID, count); count = (int)(array[3] ?? ((object)0)); bool flag = (bool)(array[0] ?? ((object)false)); logger.LogDebug($"Has legendary set: {legendarySetID}, {flag}, count: {count}"); return flag; } [PublicAPI] public static bool HasActiveMagicEffectOnWeapon(Player player, ItemData item, string effectType, out float effectValue) { effectValue = 0f; object[] array = API_HasActiveMagicEffectOnWeapon.Invoke(player, item, effectType, effectValue); effectValue = (float)(array[4] ?? ((object)0f)); bool flag = (bool)(array[0] ?? ((object)false)); logger.LogDebug($"Has magic effect on weapon: {effectType}, {flag}, value: {effectValue}"); return flag; } [PublicAPI] public static float GetTotalActiveMagicEffectValue(Player player, ItemData item, string effectType, float scale = 1f) { float num = (float)(API_GetTotalActiveMagicEffectValue.Invoke(player, item, effectType, scale)[0] ?? ((object)0f)); logger.LogDebug($"Total magic effect value: {effectType}, amount: {num}"); return num; } [PublicAPI] public static float GetTotalActiveMagicEffectValueForWeapon(Player player, ItemData item, string effectType, float scale = 1f) { float num = (float)(API_GetTotalActiveMagicEffectValueForWeapon.Invoke(player, item, effectType, scale)[0] ?? ((object)0f)); logger.LogDebug($"Total effect on weapon: {effectType}, amount: {num}"); return num; } [PublicAPI] public static bool HasActiveMagicEffect(Player player, string effectType, ItemData item, out float effectValue) { effectValue = 0f; object[] array = API_HasActiveMagicEffect.Invoke(player, effectType, item, effectValue); effectValue = (float)(array[4] ?? ((object)0f)); bool flag = (bool)(array[0] ?? ((object)false)); logger.LogDebug($"Has active effect: {effectType}, {flag}, value: {effectValue}"); return flag; } [PublicAPI] public static float GetTotalActiveSetEffectValue(Player player, string effectType, float scale = 1f) { float num = (float)(API_GetTotalActiveSetEffectValue.Invoke(player, effectType, scale)[0] ?? ((object)0f)); logger.LogDebug($"Total effect value: {effectType}, amount: {num}"); return num; } [PublicAPI] public static List GetAllActiveMagicEffects(this Player player, string effectType = null) { List list = (List)(API_GetAllActiveMagicEffects.Invoke(player, effectType)[0] ?? new List()); if (list.Count <= 0) { return new List(); } List list2 = new List(); list2.DeserializeList(list); return list2; } [PublicAPI] public static List GetAllActiveSetMagicEffects(this Player player, string effectType = null) { List list = (List)(API_GetAllSetMagicEffects.Invoke(player, effectType)[0] ?? new List()); if (list.Count <= 0) { return new List(); } List list2 = new List(); list2.DeserializeList(list); return list2; } private static void DeserializeList(this List output, List input) { foreach (string item in input) { try { T val = JsonConvert.DeserializeObject(item); if (val != null) { output.Add(val); } } catch { logger.LogWarning("Failed to parse " + typeof(T).Name); } } } [PublicAPI] public static float GetTotalActiveMagicEffectValue(this Player player, string effectType, float scale = 1f, ItemData ignoreThisItem = null) { float num = (float)(API_GetPlayerTotalActiveMagicEffectValue.Invoke(player, effectType, scale, ignoreThisItem)[0] ?? ((object)0f)); logger.LogDebug($"Total magic effect: {effectType}, value: {num}"); return num; } [PublicAPI] public static bool HasActiveMagicEffect(this Player player, string effectType, out float effectValue, float scale = 1f, ItemData ignoreThisItem = null) { effectValue = 0f; object[] array = API_PlayerHasActiveMagicEffect.Invoke(player, effectType, effectValue, scale, ignoreThisItem); effectValue = (float)(array[3] ?? ((object)0f)); bool flag = (bool)(array[0] ?? ((object)false)); logger.LogDebug($"Has active magic effect: {effectType}, value: {flag}"); return flag; } [PublicAPI] public static MagicItem GetMagicItem(this ItemData itemData) { string text = (string)(API_GetMagicItemJson.Invoke(itemData)[0] ?? ""); if (string.IsNullOrEmpty(text)) { return null; } return JsonConvert.DeserializeObject(text); } [PublicAPI] public static bool AddMagicItemChangedListener(Action listener) { return (bool)(API_AddMagicItemChangedListener.Invoke(listener)[0] ?? ((object)false)); } [PublicAPI] public static bool RemoveMagicItemChangedListener(Action listener) { return (bool)(API_RemoveMagicItemChangedListener.Invoke(listener)[0] ?? ((object)false)); } [PublicAPI] public static bool AddLootGeneratedListener(Action listener) { return (bool)(API_AddLootGeneratedListener.Invoke(listener)[0] ?? ((object)false)); } [PublicAPI] public static bool RemoveLootGeneratedListener(Action listener) { return (bool)(API_RemoveLootGeneratedListener.Invoke(listener)[0] ?? ((object)false)); } [PublicAPI] public static bool AddBountyCompletedListener(Action listener) { return (bool)(API_AddBountyCompletedListener.Invoke(listener)[0] ?? ((object)false)); } [PublicAPI] public static bool RemoveBountyCompletedListener(Action listener) { return (bool)(API_RemoveBountyCompletedListener.Invoke(listener)[0] ?? ((object)false)); } [PublicAPI] public static bool TryMakeMagicItem(this ItemData item, ItemRarity rarity, float luck = 0f, string? legendaryID = null) { bool flag = (bool)(API_TryMakeMagicItem.Invoke(item, (int)rarity, luck, legendaryID ?? "")[0] ?? ((object)false)); logger.LogDebug($"Made magic item: {item?.m_shared?.m_name}, {rarity}, {flag}"); return flag; } [PublicAPI] public static MagicItem? RollMagicItem(ItemRarity rarity, ItemData item, float luck = 0f) { string text = (string)(API_RollMagicItemJson.Invoke((int)rarity, item, luck)[0] ?? ""); if (string.IsNullOrEmpty(text)) { return null; } try { return JsonConvert.DeserializeObject(text); } catch { logger.LogWarning("Failed to parse rolled magic item"); return null; } } [PublicAPI] public static bool ApplyMagicItem(this ItemData item, MagicItem magicItem) { if (magicItem == null) { return false; } string text = JsonConvert.SerializeObject((object)magicItem); return (bool)(API_ApplyMagicItemJson.Invoke(item, text)[0] ?? ((object)false)); } [PublicAPI] public static float GetLuckFactor(Vector3 position) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) return (float)(API_GetLuckFactor.Invoke(position)[0] ?? ((object)0f)); } [PublicAPI] public static int RollEffectCountForRarity(ItemRarity rarity) { return (int)(API_RollEffectCountForRarity.Invoke((int)rarity)[0] ?? ((object)0)); } [PublicAPI] public static List GetLegendaryIDs(ItemRarity rarity) { return (List)(API_GetLegendaryIDs.Invoke((int)rarity)[0] ?? new List()); } [PublicAPI] public static LegendaryInfo? GetLegendaryInfo(string legendaryID) { string text = (string)(API_GetLegendaryInfoJson.Invoke(legendaryID)[0] ?? ""); if (string.IsNullOrEmpty(text)) { return null; } try { return JsonConvert.DeserializeObject(text); } catch { logger.LogWarning("Failed to parse legendary info for " + legendaryID); return null; } } [PublicAPI] public static List GetAvailableEffectTypes(this ItemData item, ItemRarity rarity, MagicItem? magicItem = null) { string text = ((magicItem == null) ? "" : JsonConvert.SerializeObject((object)magicItem)); return (List)(API_GetAvailableEffectTypes.Invoke(item, text, (int)rarity)[0] ?? new List()); } [PublicAPI] public static bool AddLootTables(string json) { if (!(API_AddLootTables.Invoke(json)[0] is string value)) { return false; } RunTimeRegistry.Register(json, value); logger.LogDebug("Registered external loot tables"); return true; } [PublicAPI] public static bool UpdateLootTables(string originalJson, string json) { if (!RunTimeRegistry.TryGetValue(originalJson, out string value)) { return false; } return (bool)(API_UpdateLootTables.Invoke(value, json)[0] ?? ((object)false)); } [PublicAPI] public static bool RegisterInventoryProvider(string id, Func> getItems, Func countItem, Func removeItem, Func removeExactItem) { bool flag = (bool)(API_RegisterInventoryProvider.Invoke(id, getItems, countItem, removeItem, removeExactItem)[0] ?? ((object)false)); logger.LogDebug($"Registered inventory provider: {id}, {flag}"); return flag; } [PublicAPI] public static bool UnregisterInventoryProvider(string id) { return (bool)(API_UnregisterInventoryProvider.Invoke(id)[0] ?? ((object)false)); } [PublicAPI] public static bool RegisterEquipmentProvider(string id, Func> getExtraEquipped) { bool flag = (bool)(API_RegisterEquipmentProvider.Invoke(id, getExtraEquipped)[0] ?? ((object)false)); logger.LogDebug($"Registered equipment provider: {id}, {flag}"); return flag; } [PublicAPI] public static bool UnregisterEquipmentProvider(string id) { return (bool)(API_UnregisterEquipmentProvider.Invoke(id)[0] ?? ((object)false)); } [PublicAPI] public static void InvalidatePlayerEffectCache(this Player player) { API_InvalidatePlayerEffectCache.Invoke(player); } [PublicAPI] public static bool RegisterSacrificeFilter(string id, Func canSacrifice) { bool flag = (bool)(API_RegisterSacrificeFilter.Invoke(id, canSacrifice)[0] ?? ((object)false)); logger.LogDebug($"Registered sacrifice filter: {id}, {flag}"); return flag; } [PublicAPI] public static bool UnregisterSacrificeFilter(string id) { return (bool)(API_UnregisterSacrificeFilter.Invoke(id)[0] ?? ((object)false)); } [PublicAPI] public static Dictionary> GetRegisteredProviders() { return (Dictionary>)(API_GetRegisteredProviders.Invoke()[0] ?? new Dictionary>()); } [PublicAPI] public static int GetApiVersion() { return (int)(API_GetApiVersion.Invoke()[0] ?? ((object)0)); } [PublicAPI] public static bool IsLoaded() { return GetApiVersion() > 0; } [PublicAPI] public static string GetPluginVersion() { return (string)(API_GetPluginVersion.Invoke()[0] ?? ""); } [PublicAPI] public static bool HasEndpoint(string name) { return (bool)(API_HasEndpoint.Invoke(name)[0] ?? ((object)false)); } [PublicAPI] public static bool IsMagicItem(this ItemData item) { return (bool)(API_IsMagicItem.Invoke(item)[0] ?? ((object)false)); } [PublicAPI] public static bool TryGetRarity(this ItemData item, out ItemRarity rarity) { rarity = ItemRarity.Magic; int num = 0; object[] array = API_TryGetRarity.Invoke(item, num); if ((bool)(array[0] ?? ((object)false))) { rarity = (ItemRarity)(int)(array[2] ?? ((object)0)); return true; } return false; } [PublicAPI] public static string GetDisplayName(this ItemData item) { return (string)(API_GetItemDisplayName.Invoke(item)[0] ?? ""); } [PublicAPI] public static string GetDecoratedName(this ItemData item, string colorOverride = null) { return (string)(API_GetItemDecoratedName.Invoke(item, colorOverride)[0] ?? ""); } [PublicAPI] public static int GetRarityCount() { return (int)(API_GetRarityCount.Invoke()[0] ?? ((object)0)); } [PublicAPI] public static string GetRarityColor(ItemRarity rarity) { return (string)(API_GetRarityColorByIndex.Invoke((int)rarity)[0] ?? "#FFFFFF"); } [PublicAPI] public static string GetRarityDisplayName(ItemRarity rarity) { return (string)(API_GetRarityDisplayNameByIndex.Invoke((int)rarity)[0] ?? ""); } [PublicAPI] public static string GetItemRarityColor(this ItemData item) { return (string)(API_GetItemRarityColor.Invoke(item)[0] ?? "#FFFFFF"); } [PublicAPI] public static bool IsEpicLootItem(this ItemData item) { return (bool)(API_IsEpicLootItem.Invoke(item)[0] ?? ((object)false)); } [PublicAPI] public static bool IsShardStone(this ItemData item) { return (bool)(API_IsShardStone.Invoke(item)[0] ?? ((object)false)); } [PublicAPI] public static bool IsRunestone(this ItemData item) { return (bool)(API_IsRunestone.Invoke(item)[0] ?? ((object)false)); } [PublicAPI] public static bool IsMagicCraftingMaterial(this ItemData item) { return (bool)(API_IsMagicCraftingMaterial.Invoke(item)[0] ?? ((object)false)); } [PublicAPI] public static bool IsUnidentified(this ItemData item) { return (bool)(API_IsUnidentified.Invoke(item)[0] ?? ((object)false)); } [PublicAPI] public static bool CanBeMagicItem(this ItemData item) { return (bool)(API_CanBeMagicItem.Invoke(item)[0] ?? ((object)false)); } [PublicAPI] public static bool HasMagicEffect(this ItemData item, string effectType, bool includeSocketed = true) { return (bool)(API_ItemHasMagicEffect.Invoke(item, effectType, includeSocketed)[0] ?? ((object)false)); } [PublicAPI] public static List GetAllMagicEffectTypes() { return (List)(API_GetAllMagicEffectTypes.Invoke()[0] ?? new List()); } [PublicAPI] public static List GetEnchantCosts(this ItemData item, ItemRarity rarity) { return DeserializeAmounts((string)(API_GetEnchantCostsJson.Invoke(item, (int)rarity)[0] ?? "[]")); } [PublicAPI] public static List GetSacrificeProducts(this ItemData item) { return DeserializeAmounts((string)(API_GetSacrificeProductsJson.Invoke(item)[0] ?? "[]")); } private static List DeserializeAmounts(string json) { try { return JsonConvert.DeserializeObject>(json) ?? new List(); } catch { logger.LogWarning("Failed to parse item amount list"); return new List(); } } [PublicAPI] public static bool ApplyMagicItemBackground(GameObject slotRoot, GameObject equippedOverlay, ItemData item, bool inventoryGrid) { return (bool)(API_ApplyMagicItemBackground.Invoke(slotRoot, equippedOverlay, item, inventoryGrid)[0] ?? ((object)false)); } [PublicAPI] public static bool ApplyMagicItemBackgroundToIcon(GameObject iconObject, ItemData item) { return (bool)(API_ApplyMagicItemBackgroundToIcon.Invoke(iconObject, item)[0] ?? ((object)false)); } } [Serializable] [PublicAPI] public class BountyMinion { public string ID = ""; public int Count; public BountyMinion(string ID, int count) { this.ID = ID; Count = count; } public BountyMinion() { } } [Serializable] [PublicAPI] public class BountyTarget { public Biome Biome; public string TargetID = ""; public int RewardGold; public int RewardIron; public int RewardCoins; public List Adds = new List(); internal static readonly List BountyTargets = new List(); internal static readonly Method API_AddBountyTarget = new Method("AddBountyTarget"); internal static readonly Method API_UpdateBountyTarget = new Method("UpdateBountyTarget"); public BountyTarget(Biome biome, string targetID) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) Biome = biome; TargetID = targetID; BountyTargets.Add(this); } public BountyTarget() { } public static void RegisterAll() { foreach (BountyTarget item in new List(BountyTargets)) { item.Register(); } } public bool Register() { string text = JsonConvert.SerializeObject((object)this); if (!(API_AddBountyTarget.Invoke(text)[0] is string value)) { return false; } RunTimeRegistry.Register(this, value); BountyTargets.Remove(this); EpicLoot.logger.LogDebug("Registered bounty: " + TargetID); return true; } public bool Update() { if (!RunTimeRegistry.TryGetValue(this, out string value)) { return false; } string text = JsonConvert.SerializeObject((object)this); bool flag = (bool)(API_UpdateBountyTarget.Invoke(value, text)[0] ?? ((object)false)); EpicLoot.logger.LogDebug($"Updated bounty target: {TargetID}, {flag}"); return flag; } } [Serializable] [PublicAPI] public class RecipeRequirement { public string item; public int amount; public RecipeRequirement(string item, int amount = 1) { this.item = item; this.amount = amount; } } internal static class RecipeApi { internal const string Obsolete = "Epic Loot removed recipes.json in 0.13.0 and no longer ships a recipe config, so this no longer has anywhere to register into. Add recipes with Jotunn's ItemManager instead."; } [Serializable] [PublicAPI] [Obsolete("Epic Loot removed recipes.json in 0.13.0 and no longer ships a recipe config, so this no longer has anywhere to register into. Add recipes with Jotunn's ItemManager instead.")] public class CustomRecipe { public string name = ""; public string item = ""; public int amount; public string craftingStation = ""; public int minStationLevel = 1; public bool enabled = true; public string repairStation = ""; public List resources = new List(); internal static readonly List Recipes = new List(); internal static readonly Method API_AddRecipe = new Method("AddRecipe"); public CustomRecipe(string name, string item, CraftingTable craftingTable, int amount = 1) { this.name = name; this.item = item; this.amount = amount; craftingStation = craftingTable.GetInternalName(); Recipes.Add(this); } public CustomRecipe() { } [PublicAPI] [Obsolete("Epic Loot removed recipes.json in 0.13.0 and no longer ships a recipe config, so this no longer has anywhere to register into. Add recipes with Jotunn's ItemManager instead.")] public static void RegisterAll() { foreach (CustomRecipe item in new List(Recipes)) { item.Register(); } } [Obsolete("Epic Loot removed recipes.json in 0.13.0 and no longer ships a recipe config, so this no longer has anywhere to register into. Add recipes with Jotunn's ItemManager instead.")] public bool Register() { string text = JsonConvert.SerializeObject((object)this); if (!(API_AddRecipe.Invoke(text)[0] is string value)) { return false; } RunTimeRegistry.Register(this, value); Recipes.Remove(this); EpicLoot.logger.LogDebug("Registered recipe: " + name); return true; } } [PublicAPI] public enum CraftingTable { [InternalName("piece_workbench")] Workbench, [InternalName("piece_cauldron")] Cauldron, [InternalName("forge")] Forge, [InternalName("piece_artisanstation")] ArtisanTable, [InternalName("piece_stonecutter")] StoneCutter, [InternalName("piece_magetable")] MageTable, [InternalName("blackforge")] BlackForge, [InternalName("piece_preptable")] FoodPreparationTable, [InternalName("piece_MeadCauldron")] MeadKetill } internal class InternalName : Attribute { public readonly string internalName; public InternalName(string internalName) { this.internalName = internalName; } } [PublicAPI] public static class EffectType { public static string DvergerCirclet = "DvergerCirclet"; public static string InstantMead = "InstantMead"; public static string AutoMead = "AutoMead"; public static string DecreaseMeadCooldown = "DecreaseMeadCooldown"; public static string Megingjord = "Megingjord"; public static string Wishbone = "Wishbone"; public static string Andvaranaut = "Andvaranaut"; public static string ModifyDamage = "ModifyDamage"; public static string ModifyPhysicalDamage = "ModifyPhysicalDamage"; public static string ModifyElementalDamage = "ModifyElementalDamage"; public static string ModifyDurability = "ModifyDurability"; public static string ModifyDrawStaminaUse = "ModifyDrawStaminaUse"; public static string ReduceWeight = "ReduceWeight"; public static string RemoveSpeedPenalty = "RemoveSpeedPenalty"; public static string ModifyBlockPower = "ModifyBlockPower"; public static string ModifyBlockForce = "ModifyBlockForce"; public static string ModifyParry = "ModifyParry"; public static string ModifyArmor = "ModifyArmor"; public static string ModifyBackstab = "ModifyBackstab"; public static string IncreaseMiningDrop = "IncreaseMiningDrop"; public static string IncreaseTreeDrop = "IncreaseTreeDrop"; public static string IncreaseHealth = "IncreaseHealth"; public static string IncreaseHeatResistance = "IncreaseHeatResistance"; public static string IncreaseStamina = "IncreaseStamina"; public static string IncreaseEitr = "IncreaseEitr"; public static string DecreaseForsakenCooldown = "DecreaseForsakenCooldown"; public static string ModifyHealthRegen = "ModifyHealthRegen"; public static string AddHealthRegen = "AddHealthRegen"; public static string ModifyStaminaRegen = "ModifyStaminaRegen"; public static string ModifyEitrRegen = "ModifyEitrRegen"; public static string AddBluntDamage = "AddBluntDamage"; public static string AddSlashingDamage = "AddSlashingDamage"; public static string AddPiercingDamage = "AddPiercingDamage"; public static string AddFireDamage = "AddFireDamage"; public static string AddFrostDamage = "AddFrostDamage"; public static string AddLightningDamage = "AddLightningDamage"; public static string AddPoisonDamage = "AddPoisonDamage"; public static string AddSpiritDamage = "AddSpiritDamage"; public static string AddFireResistancePercentage = "AddFireResistancePercentage"; public static string AddFrostResistancePercentage = "AddFrostResistancePercentage"; public static string AddLightningResistancePercentage = "AddLightningResistancePercentage"; public static string AddPoisonResistancePercentage = "AddPoisonResistancePercentage"; public static string AddSpiritResistancePercentage = "AddSpiritResistancePercentage"; public static string AddElementalResistancePercentage = "AddElementalResistancePercentage"; public static string AddBluntResistancePercentage = "AddBluntResistancePercentage"; public static string AddSlashingResistancePercentage = "AddSlashingResistancePercentage"; public static string AddPiercingResistancePercentage = "AddPiercingResistancePercentage"; public static string AddChoppingResistancePercentage = "AddChoppingResistancePercentage"; public static string AddPhysicalResistancePercentage = "AddPhysicalResistancePercentage"; public static string ModifyMovementSpeed = "ModifyMovementSpeed"; public static string ModifySprintStaminaUse = "ModifySprintStaminaUse"; public static string ModifyNoise = "ModifyNoise"; public static string ModifyBuildDistance = "ModifyBuildDistance"; public static string ModifyPickupRange = "ModifyPickupRange"; public static string ModifyMagicFireRate = "ModifyMagicFireRate"; public static string AmmoConservation = "AmmoConservation"; public static string ModifyProjectileSpeed = "ModifyProjectileSpeed"; public static string ModifyDodgeStaminaUse = "ModifyDodgeStaminaUse"; public static string ModifyJumpStaminaUse = "ModifyJumpStaminaUse"; public static string ModifyAttackStaminaUse = "ModifyAttackStaminaUse"; public static string ModifyAttackEitrUse = "ModifyAttackEitrUse"; public static string ModifyAttackHealthUse = "ModifyAttackHealthUse"; public static string ModifyBlockStaminaUse = "ModifyBlockStaminaUse"; public static string ModifySummonHealth = "ModifySummonHealth"; public static string ModifySummonDamage = "ModifySummonDamage"; public static string ModifyWispRange = "ModifyWispRange"; public static string Indestructible = "Indestructible"; public static string CoinHoarder = "CoinHoarder"; public static string Weightless = "Weightless"; public static string LifeSteal = "LifeSteal"; public static string EitrLeech = "EitrLeech"; public static string Bloodlust = "Bloodlust"; public static string AddCarryWeight = "AddCarryWeight"; public static string ModifyAttackSpeed = "ModifyAttackSpeed"; public static string Throwable = "Throwable"; public static string Waterproof = "Waterproof"; public static string Warmth = "Warmth"; public static string Paralyze = "Paralyze"; public static string DoubleJump = "DoubleJump"; public static string ExplosiveArrows = "ExplosiveArrows"; public static string QuickDraw = "QuickDraw"; public static string AddSwordsSkill = "AddSwordsSkill"; public static string AddKnivesSkill = "AddKnivesSkill"; public static string AddClubsSkill = "AddClubsSkill"; public static string AddPolearmsSkill = "AddPolearmsSkill"; public static string AddSpearsSkill = "AddSpearsSkill"; public static string AddBlockingSkill = "AddBlockingSkill"; public static string AddAxesSkill = "AddAxesSkill"; public static string AddBowsSkill = "AddBowsSkill"; public static string AddCrossbowsSkill = "AddCrossbowsSkill"; public static string AddUnarmedSkill = "AddUnarmedSkill"; public static string AddPickaxesSkill = "AddPickaxesSkill"; public static string AddFishingSkill = "AddFishingSkill"; public static string AddElementalMagicSkill = "AddElementalMagicSkill"; public static string AddBloodMagicSkill = "AddBloodMagicSkill"; public static string AddMovementSkills = "AddMovementSkills"; public static string AddCrafterSkills = "AddCrafterSkills"; public static string ModifyStaggerDuration = "ModifyStaggerDuration"; public static string QuickLearner = "QuickLearner"; public static string RecallWeapon = "RecallWeapon"; public static string ReflectDamage = "ReflectDamage"; public static string AvoidDamageTaken = "AvoidDamageTaken"; public static string StaggerOnDamageTaken = "StaggerOnDamageTaken"; public static string FeatherFall = "FeatherFall"; public static string ModifyDiscoveryRadius = "ModifyDiscoveryRadius"; public static string FreeBuild = "FreeBuild"; public static string Comfortable = "Comfortable"; public static string ModifyLowHealth = "ModifyLowHealth"; public static string ModifyMovementSpeedLowHealth = "ModifyMovementSpeedLowHealth"; public static string ModifyHealthRegenLowHealth = "ModifyHealthRegenLowHealth"; public static string ModifyStaminaRegenLowHealth = "ModifyStaminaRegenLowHealth"; public static string ModifyEitrRegenLowHealth = "ModifyEitrRegenLowHealth"; public static string ModifyArmorLowHealth = "ModifyArmorLowHealth"; public static string ModifyDamageLowHealth = "ModifyDamageLowHealth"; public static string ModifyBlockPowerLowHealth = "ModifyBlockPowerLowHealth"; public static string ModifyParryLowHealth = "ModifyParryLowHealth"; public static string ModifyAttackSpeedLowHealth = "ModifyAttackSpeedLowHealth"; public static string AvoidDamageTakenLowHealth = "AvoidDamageTakenLowHealth"; public static string LifeStealLowHealth = "LifeStealLowHealth"; public static string Glowing = "Glowing"; public static string Executioner = "Executioner"; public static string Riches = "Riches"; public static string Opportunist = "Opportunist"; public static string Duelist = "Duelist"; public static string Immovable = "Immovable"; public static string ModifyStaggerDamage = "ModifyStaggerDamage"; public static string Luck = "Luck"; public static string ModifyParryWindow = "ModifyParryWindow"; public static string Slow = "Slow"; public static string FrostDamageAOE = "FrostDamageAOE"; public static string DoubleMagicShot = "DoubleMagicShot"; public static string TripleBowShot = "TripleBowShot"; public static string SpellSword = "SpellSword"; public static string BulkUp = "BulkUp"; public static string EitrWeave = "EitrWeave"; public static string DartingThoughts = "DartingThoughts"; public static string HeadHunter = "HeadHunter"; public static string DodgeBuff = "DodgeBuff"; public static string OffSetAttack = "OffSetAttack"; public static string ChainLightning = "ChainLightning"; public static string Apportation = "Apportation"; public static string ModifyFireRate = "ModifyFireRate"; public static string Bulwark = "Bulwark"; public static string Undying = "Undying"; public static string DamageTakenGivesAdrenaline = "DamageTakenGivesAdrenaline"; public static string UseAdrenalineAsStamina = "UseAdrenalineAsStamina"; public static string EitrUseGivesAdrenaline = "EitrUseGivesAdrenaline"; public static string BurningAdrenaline = "BurningAdrenaline"; public static string GainAdrenalineFromHarvesting = "GainAdrenalineFromHarvesting"; public static string SummonBatWhenActivatingAdrenaline = "SummonBatWhenActivatingAdrenaline"; public static string AdrenalineFrostWave = "AdrenalineFrostWave"; public static string GainAdrenalineWhenApplyingPoison = "GainAdrenalineWhenApplyingPoison"; public static string GainAdrenalineWhenSacrificingHealth = "GainAdrenalineWhenSacrificingHealth"; public static string StormFury = "StormFury"; public static string AdrenalineIncreasesHealthRegen = "AdrenalineIncreasesHealthRegen"; public static string AdrenalineCharge = "AdrenalineCharge"; public static string PerfectDodge = "PerfectDodge"; public static string PerfectDodgeGivesHealth = "PerfectDodgeGivesHealth"; public static string PerfectDodgeGivesStamina = "PerfectDodgeGivesStamina"; public static string PerfectDodgeGivesEitr = "PerfectDodgeGivesEitr"; public static string DecreaseDodgeCost = "DecreaseDodgeCost"; public static string IncreaseDamageDuringNighttime = "IncreaseDamageDuringNighttime"; public static string NightStaminaRegenIncrease = "NightStaminaRegenIncrease"; public static string DamageReductionAtNight = "DamageReductionAtNight"; public static string IncreaseDamageDuringDaytime = "IncreaseDamageDuringDaytime"; public static string DayDiscovery = "DayDiscovery"; public static string DayArmor = "DayArmor"; public static string DayStaminaRegen = "DayStaminaRegen"; public static string DayHealthRegen = "DayHealthRegen"; public static string DayBlocker = "DayBlocker"; public static string NightBlocker = "NightBlocker"; public static string PercentHealth = "PercentHealth"; public static string PercentStamina = "PercentStamina"; public static string PercentEitr = "PercentEitr"; public static string HealthGainPerXDamageDone = "HealthGainPerXDamageDone"; public static string HealthOnEitrUse = "HealthOnEitrUse"; public static string LifeGainOnHit = "LifeGainOnHit"; public static string PhysToFire = "PhysToFire"; public static string PhysToFrost = "PhysToFrost"; public static string PhysToPoison = "PhysToPoison"; public static string PhysToLightning = "PhysToLightning"; public static string PhysToFireOnBlock = "PhysToFireOnBlock"; public static string PhysToFrostOnBlock = "PhysToFrostOnBlock"; public static string PhysToPoisonOnBlock = "PhysToPoisonOnBlock"; public static string PhysToLightningOnBlock = "PhysToLightningOnBlock"; public static string ConvertPhysicalDamageToLightning = "ConvertPhysicalDamageToLightning"; public static string EitrImbueAttack = "EitrImbueAttack"; public static string StaminaReturnFromEitr = "StaminaReturnFromEitr"; public static string EnergeticEitr = "EnergeticEitr"; public static string ConvertEitrCostToStaminaCost = "ConvertEitrCostToStaminaCost"; public static string ConsumeEitrFirstForBloodCosts = "ConsumeEitrFirstForBloodCosts"; public static string RunningOnEmpty = "RunningOnEmpty"; public static string EveryXPointsOfEitrIncreasesStamina = "EveryXPointsOfEitrIncreasesStamina"; public static string EitrShield = "EitrShield"; public static string LifeGainOnBlock = "LifeGainOnBlock"; public static string StaminaGainOnBlock = "StaminaGainOnBlock"; public static string EitrGainOnBlock = "EitrGainOnBlock"; public static string Kindling = "Kindling"; public static string DamageBonusFromPlayerWeight = "DamageBonusFromPlayerWeight"; public static string StaminaRegenBonusFromPlayerWeight = "StaminaRegenBonusFromPlayerWeight"; public static string GainMaxStaminaBasedOnPlayerMaxHealth = "GainMaxStaminaBasedOnPlayerMaxHealth"; public static string GainMaxCarryWeightFromRested = "GainMaxCarryWeightFromRested"; public static string DamageIncreaseFromMovementPenalty = "DamageIncreaseFromMovementPenalty"; public static string IncreaseXPGainFromMovementPenalty = "IncreaseXPGainFromMovementPenalty"; public static string CarryWeightForMovementPenalty = "CarryWeightForMovementPenalty"; public static string StaminaIncreaseForMovementPenalty = "StaminaIncreaseForMovementPenalty"; public static string BurdenedBlock = "BurdenedBlock"; public static string AnchoredBlock = "AnchoredBlock"; public static string IncreaseHarvestDamage = "IncreaseHarvestDamage"; public static string IncreaseHarvestXPGain = "IncreaseHarvestXPGain"; public static string BountifulHarvest = "BountifulHarvest"; public static string Mercenary = "Mercenary"; public static string Coinplated = "Coinplated"; public static string Wager = "Wager"; public static string LuckWhileFishing = "LuckWhileFishing"; public static string ChanceDoubleDamage = "ChanceDoubleDamage"; public static string Inspiration = "Inspiration"; public static string LuckyLoot = "LuckyLoot"; public static string SailingSpeed = "SailingSpeed"; public static string PotionEfficacy = "PotionEfficacy"; public static string IncreaseMeleeSkills = "IncreaseMeleeSkills"; public static string IncreaseRangedSkills = "IncreaseRangedSkills"; public static string BloodStaggerBlock = "BloodStaggerBlock"; public static string BloodBaseBlock = "BloodBaseBlock"; public static string Warding = "Warding"; public static string ElementalWarding = "ElementalWarding"; public static string LuckyBlock = "LuckyBlock"; public static string BlockAsDodgeAsBlock = "BlockAsDodgeAsBlock"; public static string BlockAsWoodCuttingAndPickaxes = "BlockAsWoodCuttingAndPickaxes"; public static string StaggerOnBlock = "StaggerOnBlock"; public static string IncreaseAllPoisonDamageDone = "IncreaseAllPoisonDamageDone"; public static string KillsReduceNextBloodCost = "KillsReduceNextBloodCost"; public static string BloodMagicLevelIncreasesHealthRegen = "BloodMagicLevelIncreasesHealthRegen"; public static string ChanceToCritOnHit = "ChanceToCritOnHit"; public static string Bloodrage = "Bloodrage"; public static string BloodDrinker = "BloodDrinker"; public static string Trailblazer = "Trailblazer"; public static string ReduceFallDamage = "ReduceFallDamage"; public static string RollCleanse = "RollCleanse"; public static string StormRider = "StormRider"; public static string StaminaOnKill = "StaminaOnKill"; public static string HeartyEitr = "HeartyEitr"; public static string BurningSpeed = "BurningSpeed"; public static string PerfectDodgeGivesSpeed = "PerfectDodgeGivesSpeed"; public static string NightCarryWeight = "NightCarryWeight"; public static string DaySailingSpeed = "DaySailingSpeed"; public static string ArmorFromMovementPenalty = "ArmorFromMovementPenalty"; public static string ReduceEitrCost = "ReduceEitrCost"; public static string ReduceFishingStaminaCost = "ReduceFishingStaminaCost"; public static string ReduceArmorIncreaseDamage = "ReduceArmorIncreaseDamage"; public static string PoisonToTrueDamage = "PoisonToTrueDamage"; public static string IcyWeight = "IcyWeight"; public static string GainEitrWhenSacrificingHealth = "GainEitrWhenSacrificingHealth"; public static string LuckyCraft = "LuckyCraft"; public static string Conduit = "Conduit"; public static string RestingHealthRegen = "RestingHealthRegen"; public static string TravelLight = "TravelLight"; public static string StrikeCausesLightning = "StrikeCausesLightning"; public static string BatteringRam = "BatteringRam"; public static string ShockingCharge = "ShockingCharge"; public static string ForestsAid = "ForestsAid"; public static string CorpseRot = "CorpseRot"; public static string IcyRetribution = "IcyRetribution"; public static string MeteorSummoner = "MeteorSummoner"; public static string Everflow = "Everflow"; public static string NecroticFire = "NecroticFire"; } public static class Helpers { [PublicAPI] public static void Add(this List list, params T[] items) { list.AddRange(items); } [PublicAPI] public static void AddMinion(this List list, string ID, int count) { list.Add(new BountyMinion(ID, count)); } [PublicAPI] public static void Add(this List list, string item, int amount = 1) { list.Add(new ItemAmount(item, amount)); } [PublicAPI] public static void Add(this List list, string item, int amount = 1) { list.Add(new MaterialConversionRequirement(item, amount)); } internal static string GetInternalName(this CraftingTable table) { MemberInfo[] member = typeof(CraftingTable).GetMember(table.ToString()); if (member.Length == 0) { return table.ToString(); } InternalName internalName = (InternalName)Attribute.GetCustomAttribute(member[0], typeof(InternalName)); if (internalName == null) { return table.ToString(); } return internalName.internalName; } [PublicAPI] public static void Add(this List list, string item, int amount = 1) { list.Add(new RecipeRequirement(item, amount)); } [PublicAPI] public static void Add(this List list, int count, string type, float min = 1f, float max = 1f, float increment = 1f) { list.Add(new SetBonusInfo(count, type, min, max, increment)); } [PublicAPI] public static void Add(this List list, string type, float min = 1f, float max = 1f, float increment = 1f) { list.Add(new GuaranteedMagicEffect(type, min, max, increment)); } } [Serializable] [PublicAPI] public class GuaranteedMagicEffect { public string Type = ""; public ValueDef Values = new ValueDef(); public GuaranteedMagicEffect(string type, ValueDef values) { Type = type; Values = values; } public GuaranteedMagicEffect(string type, float min = 1f, float max = 1f, float increment = 1f) : this(type, new ValueDef(min, max, increment)) { } public GuaranteedMagicEffect() { } } [Serializable] [PublicAPI] public class TextureReplacement { public string ItemID = ""; public string MainTexture = ""; public string ChestTex = ""; public string LegsTex = ""; public TextureReplacement(string itemID, string mainTex = "", string chestTex = "", string legsTex = "") { ItemID = itemID; MainTexture = mainTex; ChestTex = chestTex; LegsTex = legsTex; } public TextureReplacement() { } } [Serializable] [PublicAPI] public class LegendaryInfo { public string ID = ""; public string Name = ""; public string Description = ""; public MagicItemEffectRequirements Requirements = new MagicItemEffectRequirements(); public List GuaranteedMagicEffects = new List(); public int GuaranteedEffectCount = -1; public float SelectionWeight = 1f; public string EquipFx = ""; public FxAttachMode EquipFxMode = FxAttachMode.Player; public List TextureReplacements = new List(); public bool IsSetItem; public bool Enchantable; public List EnchantCost = new List(); private LegendaryType type; internal static readonly List LegendaryItems = new List(); internal static readonly Method API_AddLegendaryItem = new Method("AddLegendaryItem"); internal static readonly Method API_UpdateLegendaryItem = new Method("UpdateLegendaryItem"); public LegendaryInfo(LegendaryType type, string ID, string name, string description) { this.ID = ID; Name = name; Description = description; this.type = type; LegendaryItems.Add(this); } public LegendaryInfo() { } public static void RegisterAll() { foreach (LegendaryInfo item in new List(LegendaryItems)) { item.Register(); } } public bool Register() { string text = JsonConvert.SerializeObject((object)this); if (!(API_AddLegendaryItem.Invoke(type.ToString(), text)[0] is string value)) { return false; } RunTimeRegistry.Register(this, value); LegendaryItems.Remove(this); EpicLoot.logger.LogDebug("Registered legendary item: " + ID); return true; } public bool Update() { if (!RunTimeRegistry.TryGetValue(this, out string value)) { return false; } string text = JsonConvert.SerializeObject((object)this); bool flag = (bool)(API_UpdateLegendaryItem.Invoke(value, text)[0] ?? ((object)false)); EpicLoot.logger.LogDebug($"Updated legendary item: {ID}, {flag}"); return flag; } } [PublicAPI] public enum LegendaryType { Legendary, Mythic } [Serializable] [PublicAPI] public class SetBonusInfo { public int Count; public GuaranteedMagicEffect Effect = new GuaranteedMagicEffect(); public SetBonusInfo(int count, string type, ValueDef values) { Count = count; Effect = new GuaranteedMagicEffect(type, values); } public SetBonusInfo(int count, string type, float min, float max, float increment) : this(count, type, new ValueDef(min, max, increment)) { } public SetBonusInfo() { } } [Serializable] [PublicAPI] public class LegendarySetInfo { public string ID = ""; public string Name = ""; public List LegendaryIDs = new List(); public List SetBonuses = new List(); private LegendaryType type; internal static readonly List LegendarySets = new List(); internal static readonly Method API_AddLegendarySet = new Method("AddLegendarySet"); internal static readonly Method API_UpdateLegendarySet = new Method("UpdateLegendarySet"); public LegendarySetInfo(LegendaryType type, string ID, string name) { this.ID = ID; Name = name; this.type = type; LegendarySets.Add(this); } public LegendarySetInfo() { } public static void RegisterAll() { foreach (LegendarySetInfo item in new List(LegendarySets)) { item.Register(); } } public bool Register() { string text = JsonConvert.SerializeObject((object)this); if (!(API_AddLegendarySet.Invoke(type.ToString(), text)[0] is string value)) { return false; } RunTimeRegistry.Register(this, value); EpicLoot.logger.LogDebug("Registered legendary set: " + ID); return true; } public bool Update() { if (!RunTimeRegistry.TryGetValue(this, out string value)) { return false; } string text = JsonConvert.SerializeObject((object)this); bool flag = (bool)(API_UpdateLegendarySet.Invoke(value, text)[0] ?? ((object)false)); EpicLoot.logger.LogDebug($"Updated legendary set: {ID}, {flag}"); return flag; } } public class Logger { public event Action OnError; public event Action OnDebug; public event Action OnWarning; public void LogError(string message) { this.OnError?.Invoke(message); } public void LogDebug(string message) { this.OnDebug?.Invoke(message); } public void LogWarning(string message) { this.OnWarning?.Invoke(message); } } [Serializable] [PublicAPI] public class MagicItem { public int Version = 3; public ItemRarity Rarity; public List Effects = new List(); public string TypeNameOverride = ""; public int AugmentedEffectIndex = -1; public List AugmentedEffectIndices = new List(); public List TemperedEffectIndices = new List(); public string DisplayName = ""; public string LegendaryID = ""; public string SetID = ""; public bool IsUnidentified; public int SocketCount; public List Sockets = new List(); } [Serializable] [PublicAPI] public class SocketedEffect { public int Version = 2; public MagicItemEffect? Effect; public string SourcePrefab = ""; public ItemRarity SourceRarity; public ShardType ShardType = ShardType.None; public float StackMultiplier = 1f; public SocketedEffect() { } public SocketedEffect(MagicItemEffect effect, string sourcePrefab, ItemRarity sourceRarity) { Effect = effect; SourcePrefab = sourcePrefab; SourceRarity = sourceRarity; } } [PublicAPI] public enum FxAttachMode { None, Player, ItemRoot, EquipRoot } [PublicAPI] public enum ItemRarity { Magic, Rare, Epic, Legendary, Mythic, Ancient } [Serializable] [PublicAPI] public class MagicItemEffect { public int Version = 1; public string EffectType = ""; public float EffectValue; public MagicItemEffect(string type, float value = 1f) { EffectType = type; EffectValue = value; } public MagicItemEffect() { } } [Serializable] [PublicAPI] public class ValueDef { public float MinValue; public float MaxValue; public float Increment; public ValueDef() { } public ValueDef(float min, float max, float increment) { MinValue = min; MaxValue = max; Increment = increment; } public void Set(float min, float max, float increment = 1f) { MinValue = min; MaxValue = max; Increment = increment; } } [Serializable] [PublicAPI] public class ValuesPerRarityDef { public ValueDef Magic = new ValueDef(); public ValueDef Rare = new ValueDef(); public ValueDef Epic = new ValueDef(); public ValueDef Legendary = new ValueDef(); public ValueDef Mythic = new ValueDef(); public ValueDef Ancient = new ValueDef(); } [Serializable] [PublicAPI] public class MagicItemEffectDefinition { public string Type = ""; public string DisplayText = ""; public string Description = ""; public MagicItemEffectRequirements Requirements = new MagicItemEffectRequirements(); public ValuesPerRarityDef ValuesPerRarity = new ValuesPerRarityDef(); public float SelectionWeight = 1f; public bool CanBeAugmented = true; public bool CanBeDisenchanted = true; public string Comment = ""; public List Prefixes = new List(); public List Suffixes = new List(); public string EquipFx = ""; public FxAttachMode EquipFxMode = FxAttachMode.Player; public string Ability = ""; internal static readonly List MagicEffects = new List(); internal static readonly Method API_AddMagicEffect = new Method("AddMagicEffect"); internal static readonly Method API_UpdateMagicEffect = new Method("UpdateMagicEffect"); internal static readonly Method API_GetMagicEffectDefinitionCopy = new Method("GetMagicItemEffectDefinition"); [Description("Adds your new magic item definition to a list, use Register to send to epic loot")] public MagicItemEffectDefinition(string effectType, string displayText = "", string description = "") { Type = effectType; DisplayText = displayText; Description = description; MagicEffects.Add(this); } public MagicItemEffectDefinition() { } public static void RegisterAll() { foreach (MagicItemEffectDefinition item in new List(MagicEffects)) { item.Register(); } } public static MagicItemEffectDefinition Copy(string effectType) { string text = (string)(API_GetMagicEffectDefinitionCopy.Invoke(effectType)[0] ?? ""); if (string.IsNullOrEmpty(text)) { return null; } try { return JsonConvert.DeserializeObject(text); } catch { EpicLoot.logger.LogWarning("Failed to parse magic item effect definition json"); return null; } } public bool Register() { //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_001e: Expected O, but got Unknown MagicEffects.Remove(this); string text = JsonConvert.SerializeObject((object)this, new JsonSerializerSettings { NullValueHandling = (NullValueHandling)0 }); if (!(API_AddMagicEffect.Invoke(text)[0] is string value)) { return false; } RunTimeRegistry.Register(this, value); EpicLoot.logger.LogDebug("Registered magic effect: " + Type); return true; } public bool Update() { if (!RunTimeRegistry.TryGetValue(this, out string value)) { return false; } string text = JsonConvert.SerializeObject((object)this); bool flag = (bool)(API_UpdateMagicEffect.Invoke(value, text)[0] ?? ((object)false)); EpicLoot.logger.LogDebug($"Updated magic effect: {Type}, {flag}"); return flag; } } [Serializable] [PublicAPI] public class MagicItemEffectRequirements { private static List _flags = new List(); public bool NoRoll; public bool ExclusiveSelf = true; public List ExclusiveEffectTypes = new List(); public List MustHaveEffectTypes = new List(); public List AllowedItemTypes = new List(); public List ExcludedItemTypes = new List(); public List AllowedRarities = new List(); public List ExcludedRarities = new List(); public List AllowedSkillTypes = new List(); public List ExcludedSkillTypes = new List(); public List AllowedItemNames = new List(); public List ExcludedItemNames = new List(); public bool? ItemHasPhysicalDamage; public bool? ItemHasElementalDamage; public bool? ItemHasChopDamage; public bool? ItemUsesDurability; public bool? ItemHasNegativeMovementSpeedModifier; public bool? ItemHasBlockPower; public bool? ItemHasParryPower; public bool? ItemHasNoParryPower; public bool? ItemHasArmor; public bool? ItemHasBackstabBonus; public bool? ItemUsesStaminaOnAttack; public bool? ItemUsesEitrOnAttack; public bool? ItemUsesHealthOnAttack; public bool? ItemUsesDrawStaminaOnAttack; public bool? ItemGivesAdrenaline; public bool? ItemHasAdrenaline; public List CustomFlags = new List(); public List ExternalRequirements = new List(); public unsafe void AddAllowedItemTypes(params ItemType[] types) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < types.Length; i++) { ItemType val = types[i]; AllowedItemTypes.Add(((object)(*(ItemType*)(&val))/*cast due to .constrained prefix*/).ToString()); } } public unsafe void AddExcludedItemTypes(params ItemType[] types) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < types.Length; i++) { ItemType val = types[i]; ExcludedItemTypes.Add(((object)(*(ItemType*)(&val))/*cast due to .constrained prefix*/).ToString()); } } } [Serializable] [PublicAPI] public enum MaterialConversionType { Upgrade, Convert, Junk, ShardUpgrade } [Serializable] [PublicAPI] public class MaterialConversionRequirement { public string Item = ""; public int Amount; public MaterialConversionRequirement(string item, int amount = 1) { Item = item; Amount = amount; } public MaterialConversionRequirement() { } } [Serializable] [PublicAPI] public class MaterialConversion { public string Name = ""; public string Product = ""; public int Amount; public MaterialConversionType Type; public List Resources = new List(); internal static readonly Method API_AddMaterialConversion = new Method("AddMaterialConversion"); internal static readonly Method API_UpdateMaterialConversion = new Method("UpdateMaterialConversion"); internal static readonly List MaterialConversions = new List(); [Description("Creates a new material conversion definition.")] public MaterialConversion(MaterialConversionType type, string name, string product, int amount = 1) { Name = name; Product = product; Amount = amount; Type = type; MaterialConversions.Add(this); } public MaterialConversion() { } public static void RegisterAll() { foreach (MaterialConversion item in new List(MaterialConversions)) { item.Register(); } } [Description("serializes to json and sends to EpicLoot")] public bool Register() { string text = JsonConvert.SerializeObject((object)this); if (!(API_AddMaterialConversion.Invoke(text)[0] is string value)) { return false; } MaterialConversions.Remove(this); RunTimeRegistry.Register(this, value); EpicLoot.logger.LogDebug("Registered material conversion: " + Name); return true; } public bool Update() { if (!RunTimeRegistry.TryGetValue(this, out string value)) { return false; } string text = JsonConvert.SerializeObject((object)this); bool flag = (bool)(API_UpdateMaterialConversion.Invoke(value, text)[0] ?? ((object)false)); EpicLoot.logger.LogDebug($"Updated material conversion: {Name}, {flag}"); return flag; } } internal class Method { private const string Namespace = "EpicLoot"; private const string ClassName = "API"; private const string Assembly = "EpicLoot"; private const string API_LOCATION = "EpicLoot.API, EpicLoot"; private static readonly Dictionary CachedTypes = new Dictionary(); private readonly MethodInfo info; public object[] Invoke(params object[] args) { object obj = info?.Invoke(null, args); object[] array = new object[args.Length + 1]; array[0] = obj; Array.Copy(args, 0, array, 1, args.Length); return array; } public Method(string typeNameWithAssembly, string methodName, BindingFlags bindingFlags = BindingFlags.Static | BindingFlags.Public) { if (!TryGetType(typeNameWithAssembly, out Type type)) { return; } if (type == null) { EpicLoot.logger.LogWarning("Type resolution returned null for: '" + typeNameWithAssembly + "'"); return; } info = type.GetMethod(methodName, bindingFlags); if (info == null) { EpicLoot.logger.LogWarning("Failed to find public static method '" + methodName + "' in type '" + type.FullName + "'. Verify the method name is correct, the method exists, and it is marked as public static. "); } } public Method(string methodName, BindingFlags bindingFlags = BindingFlags.Static | BindingFlags.Public) : this("EpicLoot.API, EpicLoot", methodName, bindingFlags) { } private static bool TryGetType(string typeNameWithAssembly, out Type type) { if (CachedTypes.TryGetValue(typeNameWithAssembly, out type)) { return true; } Type type2 = Type.GetType(typeNameWithAssembly); if ((object)type2 == null) { EpicLoot.logger.LogWarning("Failed to resolve type: '" + typeNameWithAssembly + "'. Verify the namespace, class name, and assembly name are correct. Ensure the assembly is loaded and accessible."); return false; } type = type2; CachedTypes[typeNameWithAssembly] = type2; return true; } public Method(string typeNameWithAssembly, string methodName, params Type[] types) { if (!TryGetType(typeNameWithAssembly, out Type type)) { return; } if (type == null) { EpicLoot.logger.LogWarning("Type resolution returned null for: '" + typeNameWithAssembly + "'"); return; } info = type.GetMethod(methodName, types); if (info == null) { EpicLoot.logger.LogWarning("Failed to find public static method '" + methodName + "' in type '" + type.FullName + "'. Verify the method name is correct, the method exists, and it is marked as public static. "); } } public Method(string methodName, params Type[] types) : this("EpicLoot.API, EpicLoot", methodName, types) { } [PublicAPI] public ParameterInfo[] GetParameters() { return info?.GetParameters() ?? Array.Empty(); } [PublicAPI] public static void ClearCache() { CachedTypes.Clear(); } } internal static class RunTimeRegistry { private static readonly Dictionary registry = new Dictionary(); public static void Register(object key, string value) { registry[key] = value; } public static bool TryGetValue(object key, out string value) { return registry.TryGetValue(key, out value); } } [Serializable] [PublicAPI] public class ItemAmount { public string Item = ""; public int Amount; public ItemAmount(string item, int amount = 1) { Item = item; Amount = amount; } public ItemAmount() { } } [Serializable] [PublicAPI] public class Sacrifice { [Description("Conditional, checks item needs to be magic")] public bool IsMagic; [Description("Can be null")] public ItemRarity Rarity; [Description("Conditional, if empty, does not check if item is of correct type")] public List ItemTypes = new List(); [Description("Conditional, if empty, does not check if item shared name is in list")] public List ItemNames = new List(); [Description("Disenchant product entry")] public List Products = new List(); internal static readonly List Sacrifices = new List(); internal static readonly Method API_AddSacrifice = new Method("AddSacrifice"); internal static readonly Method API_UpdateSacrifice = new Method("UpdateSacrifice"); public Sacrifice() { Sacrifices.Add(this); } public unsafe void AddRequiredItemType(params ItemType[] types) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < types.Length; i++) { ItemType val = types[i]; ItemTypes.Add(((object)(*(ItemType*)(&val))/*cast due to .constrained prefix*/).ToString()); } } public static void RegisterAll() { foreach (Sacrifice item in new List(Sacrifices)) { item.Register(); } } public bool Register() { string text = JsonConvert.SerializeObject((object)this); if (!(API_AddSacrifice.Invoke(text)[0] is string value)) { return false; } Sacrifices.Remove(this); RunTimeRegistry.Register(this, value); EpicLoot.logger.LogDebug("Registered sacrifice"); return true; } public bool Update() { if (!RunTimeRegistry.TryGetValue(this, out string value)) { return false; } string text = JsonConvert.SerializeObject((object)this); bool flag = (bool)(API_UpdateSacrifice.Invoke(value, text)[0] ?? ((object)false)); EpicLoot.logger.LogDebug($"Updated sacrifice: {flag}"); return flag; } } [PublicAPI] public enum SecretStashType { Materials, RandomItems, OtherItems, Gamble, Sale } [Serializable] [PublicAPI] public class SecretStashItem { public string Item = ""; public int CoinsCost; public int ForestTokenCost; public int IronBountyTokenCost; public int GoldBountyTokenCost; private SecretStashType type; internal static readonly List SecretStashes = new List(); internal static readonly Method API_AddSecretStashItem = new Method("AddSecretStashItem"); internal static readonly Method API_UpdateSecretStashItem = new Method("UpdateSecretStashItem"); public SecretStashItem(SecretStashType type, string item) { Item = item; this.type = type; SecretStashes.Add(this); } public SecretStashItem() { } public static void RegisterAll() { foreach (SecretStashItem item in new List(SecretStashes)) { item.Register(); } } public bool Register() { string text = JsonConvert.SerializeObject((object)this); if (!(API_AddSecretStashItem.Invoke(type.ToString(), text)[0] is string value)) { return false; } SecretStashes.Remove(this); RunTimeRegistry.Register(this, value); EpicLoot.logger.LogDebug("Registered secret stash " + Item); return true; } public bool Update() { if (!RunTimeRegistry.TryGetValue(this, out string value)) { return false; } string text = JsonConvert.SerializeObject((object)this); bool flag = (bool)(API_UpdateSecretStashItem.Invoke(value, text)[0] ?? ((object)false)); EpicLoot.logger.LogDebug($"Updated secret stash {Item}, {flag}"); return flag; } } [PublicAPI] public enum ShardType { Red = 0, Yellow = 1, Cyan = 2, Black = 3, Green = 4, Orange = 5, Pink = 6, Purple = 7, White = 8, Grey = 9, DarkGreen = 30, DarkPurple = 31, DarkRed = 32, DarkBlue = 33, Golden = 34, LightBlue = 40, LightGreen = 41, Peach = 42, Firewalker = 70, Stormcaller = 71, Eikthyr = 90, Elder = 91, Bonemass = 92, Moder = 93, Yagluth = 94, Queen = 95, Fader = 96, None = 97 } [Serializable] [PublicAPI] public class TreasureMap { public Biome Biome; public int Cost; public int ForestTokens; public int GoldTokens; public int IronTokens; public int Coins; public float MinRadius; public float MaxRadius; internal static readonly List Treasures = new List(); private static readonly Method API_AddTreasureMap = new Method("AddTreasureMap"); private static readonly Method API_UpdateTreasureMap = new Method("UpdateTreasureMap"); public TreasureMap(Biome biome, int cost, float minRadius, float maxRadius) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) Biome = biome; Cost = cost; MinRadius = minRadius; MaxRadius = maxRadius; Treasures.Add(this); } public TreasureMap() { } public static void RegisterAll() { foreach (TreasureMap item in new List(Treasures)) { item.Register(); } } public bool Register() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) string text = JsonConvert.SerializeObject((object)this); if (!(API_AddTreasureMap.Invoke(text)[0] is string value)) { return false; } RunTimeRegistry.Register(this, value); Treasures.Remove(this); EpicLoot.logger.LogDebug($"Added treasure map: {Biome}"); return true; } public bool Update() { //IL_0048: Unknown result type (might be due to invalid IL or missing references) if (!RunTimeRegistry.TryGetValue(this, out string value)) { return false; } string text = JsonConvert.SerializeObject((object)this); bool flag = (bool)(API_UpdateTreasureMap.Invoke(value, text)[0] ?? ((object)false)); EpicLoot.logger.LogDebug($"Updated treasure map: {Biome}, {flag}"); return flag; } } }