Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of DvergerAutomation v0.5.0
plugins/DvergerAutomation.dll
Decompiled 11 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.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<bool> EnableDebugMode; public static ConfigEntry<bool> AutomationEnabled; public static ConfigEntry<float> ScanInterval; public static ConfigEntry<float> ScanRadius; public static ConfigEntry<float> RangePerCore; public static ConfigEntry<bool> 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<bool>("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<List<string>> BindServerConfig(string category, string key, List<string> 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<List<string>>(category, key, value, new ConfigDescription(description, (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true, IsAdvanced = advanced } })); } public static ConfigEntry<float[]> 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<float[]>(category, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(valMin, valMax), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true, IsAdvanced = advanced } })); } public static ConfigEntry<bool> 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<bool>(category, key, value, new ConfigDescription(description, acceptableValues, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true, IsAdvanced = advanced } })); } public static ConfigEntry<int> 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<int>(category, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<int>(valMin, valMax), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true, IsAdvanced = advanced } })); } public static ConfigEntry<float> 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<float>(category, key, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(valMin, valMax), new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true, IsAdvanced = advanced } })); } public static ConfigEntry<string> BindServerConfig(string category, string key, string value, string description, AcceptableValueList<string> 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<string>(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<JotunnPiece.PieceCost> { 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<CraftingStation> LinkedStations = new HashSet<CraftingStation>(); internal readonly List<Container> LinkedContainers = new List<Container>(); 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<ZNetView>(); if ((Object)(object)nview != (Object)null && nview.GetZDO() != null) { nview.Register("DA_RefreshCores", (Action<long>)RPC_RefreshCores); WearNTear component = ((Component)this).GetComponent<WearNTear>(); 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<Container> hashSet = new HashSet<Container>(); Collider[] array2 = array; foreach (Collider val in array2) { if (!((Object)(object)val == (Object)null)) { Container componentInParent = ((Component)val).GetComponentInParent<Container>(); 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<object>()); 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<ItemDrop>().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("[<color=yellow><b>$KEY_Use</b></color>] " + 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<GameObject>(val, val2, Random.rotation); } } } } internal static class ContainerNetwork { internal static readonly List<AutomationHub> Hubs = new List<AutomationHub>(); private static readonly Dictionary<CraftingStation, List<Container>> StationToContainers = new Dictionary<CraftingStation, List<Container>>(); private static readonly HashSet<Container> RebuildSeen = new HashSet<Container>(); private static readonly List<Container> Empty = new List<Container>(); private static readonly Dictionary<string, int> AggCounts = new Dictionary<string, int>(); private static int aggFrame = -1; private static List<Container> aggPool; private static readonly List<Container> NearPointResult = new List<Container>(); private static readonly HashSet<Container> NearPointSeen = new HashSet<Container>(); 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<Container> value)) { value = new List<Container>(); 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<Container> GetContainersForStation(CraftingStation station) { if ((Object)(object)station != (Object)null && StationToContainers.TryGetValue(station, out List<Container> value)) { return value; } return Empty; } internal static List<Container> 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<Container> 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<Container> 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<Container> 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<Container> 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<ItemData> 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<Container> 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<Container> 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<Container> 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<Container> 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<Container> Empty = new List<Container>(); private static readonly List<ItemData> ItemsResult = new List<ItemData>(); 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<Container> 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<ItemData> 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<bool> Enabled { get; set; } public ConfigEntry<bool> RequiresWorkbench { get; set; } public ConfigEntry<string> Workbench { get; set; } public ConfigEntry<string> PieceCategory { get; set; } public ConfigEntry<string> PieceCost { get; set; } public List<PieceCost> UpdatedCost { get; set; } = new List<PieceCost>(); } 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> PieceCost { get; set; } = new List<PieceCost>(); public LoadedGameObjects Objs { get; set; } public PieceConfigs Cfgs { get; set; } } private static List<JotunnBuildPiece> BuildPieces = new List<JotunnBuildPiece>(); private static bool PiecesReady = false; public static void RegisterJotunnPiece(JotunnBuildPiece jbuildpiece) { LoadedGameObjects loadedGameObjects = new LoadedGameObjects(); loadedGameObjects.Prefab = DvergerAutomation.EmbeddedResourceBundle.LoadAsset<GameObject>(jbuildpiece.Prefab + ".prefab"); loadedGameObjects.Sprite = DvergerAutomation.EmbeddedResourceBundle.LoadAsset<Sprite>(jbuildpiece.Sprite + ".png"); jbuildpiece.Objs = loadedGameObjects; jbuildpiece.Cfgs = new PieceConfigs(); InitialPieceSetup(jbuildpiece); BuildPieces.Add(jbuildpiece); PrefabManager.OnPrefabsRegistered += ResolveAndApplyScenePrefab; void ResolveAndApplyScenePrefab() { IEnumerable<GameObject> source = from obj in Resources.FindObjectsOfTypeAll<GameObject>() 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<string> list = new List<string>(); 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<RequirementConfig> list2 = new List<RequirementConfig>(); 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<string>)) { ConfigEntry<string> val2 = (ConfigEntry<string>)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<bool> 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<Piece>().m_craftingStation = null; return; } GameObject prefab = PrefabManager.Instance.GetPrefab(jbuildpiece.Cfgs.Workbench.Value); CraftingStation val = ((prefab != null) ? prefab.GetComponent<CraftingStation>() : 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<Piece>().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<Piece>().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<RequirementConfig> list = new List<RequirementConfig>(); 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<Requirement> list2 = new List<Requirement>(); 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<ItemDrop>() : 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<Piece>().m_resources = list2.ToArray(); if (ValConfig.EnableDebugMode.Value) { Logger.LogInfo($"New requirements set {jbuildpiece.Objs.ScenePrefab.GetComponent<Piece>().m_resources}."); } } else { jbuildpiece.Objs.ScenePrefab.GetComponent<Piece>().m_enabled = false; } } private static bool PieceRecipeConfigUpdater(JotunnBuildPiece jbuildpiece, string rawrecipe, bool during_runtime = true) { string[] array = rawrecipe.Split(new char[1] { '|' }); List<PieceCost> list = new List<PieceCost>(); 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<string, string> internal_localization = SimpleJson.DeserializeObject<Dictionary<string, string>>(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<string, string> dictionary = SimpleJson.DeserializeObject<Dictionary<string, string>>(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<string, string> UpdateLocalizationWithMissingKeys(Dictionary<string, string> internal_localization, Dictionary<string, string> cached_localization) { if (internal_localization.Keys != cached_localization.Keys) { List<string> list = cached_localization.Keys.ToList(); foreach (KeyValuePair<string, string> 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<string> ActionParams = new List<string>(); internal static readonly Method API_AddAbility = new Method("AddAbility"); internal static readonly Method API_UpdateAbility = new Method("UpdateAbility"); internal static List<AbilityDefinition> Abilities = new List<AbilityDefinition>(); [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<AbilityDefinition>(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<string, Delegate> Callbacks = new Dictionary<string, Delegate>(); internal static readonly List<AbilityProxyDefinition> ProxyAbilities = new List<AbilityProxyDefinition>(); 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<AbilityProxyDefinition>(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<ItemData, object, string, bool, bool, bool, bool>)); private static readonly Method API_AddMagicItemChangedListener = new Method("AddMagicItemChangedListener", typeof(Action<ItemData, string>)); private static readonly Method API_RemoveMagicItemChangedListener = new Method("RemoveMagicItemChangedListener", typeof(Action<ItemData, string>)); private static readonly Method API_AddLootGeneratedListener = new Method("AddLootGeneratedListener", typeof(Action<ItemData>)); private static readonly Method API_RemoveLootGeneratedListener = new Method("RemoveLootGeneratedListener", typeof(Action<ItemData>)); private static readonly Method API_AddBountyCompletedListener = new Method("AddBountyCompletedListener", typeof(Action<Player, string>)); private static readonly Method API_RemoveBountyCompletedListener = new Method("RemoveBountyCompletedListener", typeof(Action<Player, string>)); 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<List<ItemData>>), typeof(Func<string, int>), typeof(Func<string, int, int>), typeof(Func<ItemData, int, int>)); private static readonly Method API_UnregisterInventoryProvider = new Method("UnregisterInventoryProvider"); private static readonly Method API_RegisterEquipmentProvider = new Method("RegisterEquipmentProvider", typeof(string), typeof(Func<Player, List<ItemData>>)); private static readonly Method API_UnregisterEquipmentProvider = new Method("UnregisterEquipmentProvider"); private static readonly Method API_RegisterSacrificeFilter = new Method("RegisterSacrificeFilter", typeof(string), typeof(Func<ItemData, bool>)); 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<ItemData, object, string, bool, bool, bool, bool> 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<MagicItemEffect> GetAllActiveMagicEffects(this Player player, string effectType = null) { List<string> list = (List<string>)(API_GetAllActiveMagicEffects.Invoke(player, effectType)[0] ?? new List<string>()); if (list.Count <= 0) { return new List<MagicItemEffect>(); } List<MagicItemEffect> list2 = new List<MagicItemEffect>(); list2.DeserializeList(list); return list2; } [PublicAPI] public static List<MagicItemEffect> GetAllActiveSetMagicEffects(this Player player, string effectType = null) { List<string> list = (List<string>)(API_GetAllSetMagicEffects.Invoke(player, effectType)[0] ?? new List<string>()); if (list.Count <= 0) { return new List<MagicItemEffect>(); } List<MagicItemEffect> list2 = new List<MagicItemEffect>(); list2.DeserializeList(list); return list2; } private static void DeserializeList<T>(this List<T> output, List<string> input) { foreach (string item in input) { try { T val = JsonConvert.DeserializeObject<T>(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<MagicItem>(text); } [PublicAPI] public static bool AddMagicItemChangedListener(Action<ItemData, string> listener) { return (bool)(API_AddMagicItemChangedListener.Invoke(listener)[0] ?? ((object)false)); } [PublicAPI] public static bool RemoveMagicItemChangedListener(Action<ItemData, string> listener) { return (bool)(API_RemoveMagicItemChangedListener.Invoke(listener)[0] ?? ((object)false)); } [PublicAPI] public static bool AddLootGeneratedListener(Action<ItemData> listener) { return (bool)(API_AddLootGeneratedListener.Invoke(listener)[0] ?? ((object)false)); } [PublicAPI] public static bool RemoveLootGeneratedListener(Action<ItemData> listener) { return (bool)(API_RemoveLootGeneratedListener.Invoke(listener)[0] ?? ((object)false)); } [PublicAPI] public static bool AddBountyCompletedListener(Action<Player, string> listener) { return (bool)(API_AddBountyCompletedListener.Invoke(listener)[0] ?? ((object)false)); } [PublicAPI] public static bool RemoveBountyCompletedListener(Action<Player, string> 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<MagicItem>(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<string> GetLegendaryIDs(ItemRarity rarity) { return (List<string>)(API_GetLegendaryIDs.Invoke((int)rarity)[0] ?? new List<string>()); } [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<LegendaryInfo>(text); } catch { logger.LogWarning("Failed to parse legendary info for " + legendaryID); return null; } } [PublicAPI] public static List<string> GetAvailableEffectTypes(this ItemData item, ItemRarity rarity, MagicItem? magicItem = null) { string text = ((magicItem == null) ? "" : JsonConvert.SerializeObject((object)magicItem)); return (List<string>)(API_GetAvailableEffectTypes.Invoke(item, text, (int)rarity)[0] ?? new List<string>()); } [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<List<ItemData>> getItems, Func<string, int> countItem, Func<string, int, int> removeItem, Func<ItemData, int, int> 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<Player, List<ItemData>> 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<ItemData, bool> 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<string, List<string>> GetRegisteredProviders() { return (Dictionary<string, List<string>>)(API_GetRegisteredProviders.Invoke()[0] ?? new Dictionary<string, List<string>>()); } [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<string> GetAllMagicEffectTypes() { return (List<string>)(API_GetAllMagicEffectTypes.Invoke()[0] ?? new List<string>()); } [PublicAPI] public static List<ItemAmount> GetEnchantCosts(this ItemData item, ItemRarity rarity) { return DeserializeAmounts((string)(API_GetEnchantCostsJson.Invoke(item, (int)rarity)[0] ?? "[]")); } [PublicAPI] public static List<ItemAmount> GetSacrificeProducts(this ItemData item) { return DeserializeAmounts((string)(API_GetSacrificeProductsJson.Invoke(item)[0] ?? "[]")); } private static List<ItemAmount> DeserializeAmounts(string json) { try { return JsonConvert.DeserializeObject<List<ItemAmount>>(json) ?? new List<ItemAmount>(); } catch { logger.LogWarning("Failed to parse item amount list"); return new List<ItemAmount>(); } } [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<BountyMinion> Adds = new List<BountyMinion>(); internal static readonly List<BountyTarget> BountyTargets = new List<BountyTarget>(); 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<BountyTarget>(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<RecipeRequirement> resources = new List<RecipeRequirement>(); internal static readonly List<CustomRecipe> Recipes = new List<CustomRecipe>(); 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<CustomRecipe>(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