using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Ezomic.Core; using HarmonyLib; using Microsoft.CodeAnalysis; using SoftReferenceableAssets; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("Thijssen Software")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (c) 2026 Robbin Thijssen")] [assembly: AssemblyDescription("Load smelters, kilns and fires several at a time, and build upgrades to make them hold more.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+df6ae78643f784eea9d41d4d1ef029efbac06ea6")] [assembly: AssemblyProduct("Kynda")] [assembly: AssemblyTitle("Kynda")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Ezomic.Shared { public static class Prefabs { private sealed class Kept { internal string Name; internal Func Build; internal bool Item; internal string Tool; internal GameObject Prefab; internal int Failures; internal bool Abandoned; } private static ManualLogSource _log; private static GameObject _holder; private static readonly List Standing = new List(); private const int MaxFailures = 5; private static readonly HashSet Complained = new HashSet(); private static FieldRef> _named; private static MethodInfo _updateRegisters; public static ManualLogSource Log { get { return _log ?? (_log = Logger.CreateLogSource("Prefabs")); } set { _log = value; } } public static Transform Holder { get { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Expected O, but got Unknown if ((Object)(object)_holder == (Object)null) { _holder = new GameObject(Log.SourceName + "Prefabs"); _holder.SetActive(false); Object.DontDestroyOnLoad((Object)(object)_holder); } return _holder.transform; } } public static void Keep(string name, Func build, bool item = false, string buildTool = null) { if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); } if (build == null) { throw new ArgumentNullException("build"); } foreach (Kept item2 in Standing) { if (!(item2.Name != name)) { item2.Build = build; item2.Item = item; item2.Tool = buildTool; item2.Failures = 0; item2.Abandoned = false; return; } } Standing.Add(new Kept { Name = name, Build = build, Item = item, Tool = buildTool }); Log.LogInfo((object)("Keeping " + name + " registered.")); } public static void Drop(string name) { Standing.RemoveAll((Kept k) => k.Name == name); } public static void Tick() { if (Standing.Count == 0) { return; } ZNetScene instance = ZNetScene.instance; if (!((Object)(object)instance == (Object)null)) { for (int i = 0; i < Standing.Count; i++) { Apply(Standing[i], instance); } } } private static void Apply(Kept kept, ZNetScene scene) { if (!kept.Abandoned && (!((Object)(object)kept.Prefab == (Object)null) || TryBuild(kept))) { if ((Object)(object)scene.GetPrefab(kept.Name) == (Object)null) { Register(kept.Prefab); } if (kept.Item) { RegisterItem(kept.Prefab); } if (!string.IsNullOrEmpty(kept.Tool)) { AddToTool(kept.Prefab, kept.Tool); } } } private static bool TryBuild(Kept kept) { GameObject val = null; try { val = kept.Build(); } catch (Exception ex) { Log.LogWarning((object)("Building " + kept.Name + " failed: " + ex.Message)); } if ((Object)(object)val != (Object)null) { kept.Prefab = val; kept.Failures = 0; if (((Object)val).name != kept.Name) { ((Object)val).name = kept.Name; } return true; } if (++kept.Failures < 5) { return false; } kept.Abandoned = true; Log.LogError((object)(kept.Name + " could not be built after " + 5 + " attempts and will not be retried. Anything already built with it in a world is untouched; it simply will not be placeable this session.")); return false; } public static bool Known(string name) { if ((Object)(object)ZNetScene.instance != (Object)null) { return (Object)(object)ZNetScene.instance.GetPrefab(name) != (Object)null; } return false; } public static GameObject Clone(GameObject source, string name) { if ((Object)(object)source == (Object)null) { return null; } bool forceDisableInit = ZNetView.m_forceDisableInit; ZNetView.m_forceDisableInit = true; GameObject val; try { val = Object.Instantiate(source, Holder); } finally { ZNetView.m_forceDisableInit = forceDisableInit; } ((Object)val).name = name; return val; } public static GameObject Donor(string commaSeparated, out string chosen) { chosen = null; if ((Object)(object)ZNetScene.instance == (Object)null) { return null; } string[] array = (commaSeparated ?? "").Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length != 0) { GameObject prefab = ZNetScene.instance.GetPrefab(text); if (!((Object)(object)prefab == (Object)null)) { chosen = text; return prefab; } } } return null; } public static bool Register(GameObject prefab) { ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null || (Object)(object)prefab == (Object)null) { return false; } if ((Object)(object)instance.GetPrefab(((Object)prefab).name) != (Object)null) { return true; } if (!instance.m_prefabs.Contains(prefab)) { instance.m_prefabs.Add(prefab); } try { NamedPrefabs(instance)[StringExtensionMethods.GetStableHashCode(((Object)prefab).name)] = prefab; } catch (Exception ex) { ComplainOnce("scene:" + ((Object)prefab).name, "Could not register " + ((Object)prefab).name + " with ZNetScene: " + ex.Message); return false; } Log.LogInfo((object)("Registered " + ((Object)prefab).name + " with ZNetScene.")); return true; } public static bool RegisterItem(GameObject prefab) { ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null || (Object)(object)prefab == (Object)null) { return false; } if (instance.m_items == null || instance.m_items.Count == 0) { return false; } if ((Object)(object)instance.GetItemPrefab(((Object)prefab).name) != (Object)null) { return true; } if (!instance.m_items.Contains(prefab)) { instance.m_items.Add(prefab); } try { UpdateRegisters(instance); } catch (Exception ex) { ComplainOnce("db:" + ((Object)prefab).name, "Could not refresh ObjectDB for " + ((Object)prefab).name + ": " + ex.Message); return false; } Log.LogInfo((object)("Registered " + ((Object)prefab).name + " with ObjectDB.")); return true; } public static PieceTable ToolPieces(string toolPrefab) { if ((Object)(object)ObjectDB.instance == (Object)null || string.IsNullOrEmpty(toolPrefab)) { return null; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(toolPrefab); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent() : null); if ((Object)(object)val == (Object)null || val.m_itemData == null || val.m_itemData.m_shared == null) { return null; } PieceTable buildPieces = val.m_itemData.m_shared.m_buildPieces; if (!((Object)(object)buildPieces != (Object)null) || buildPieces.m_pieces == null) { return null; } return buildPieces; } public static bool InTool(GameObject prefab, string toolPrefab) { PieceTable val = ToolPieces(toolPrefab); if ((Object)(object)val != (Object)null && (Object)(object)prefab != (Object)null) { return val.m_pieces.Contains(prefab); } return false; } public static bool AddToTool(GameObject prefab, string toolPrefab) { if ((Object)(object)prefab == (Object)null) { return false; } PieceTable val = ToolPieces(toolPrefab); if ((Object)(object)val == (Object)null) { return false; } if (val.m_pieces.Contains(prefab)) { return true; } val.m_pieces.Add(prefab); Log.LogInfo((object)(((Object)prefab).name + " added to the " + toolPrefab + ".")); return true; } private static void ComplainOnce(string key, string message) { if (Complained.Add(key)) { Log.LogError((object)message); } } private static Dictionary NamedPrefabs(ZNetScene scene) { if (_named == null) { _named = AccessTools.FieldRefAccess>("m_namedPrefabs"); } return _named.Invoke(scene); } private static void UpdateRegisters(ObjectDB db) { if (_updateRegisters == null) { _updateRegisters = AccessTools.Method(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null); } if (_updateRegisters == null) { throw new MissingMethodException("ObjectDB.UpdateRegisters"); } _updateRegisters.Invoke(db, null); } } } namespace Kynda { internal static class BatchAdd { private static readonly MethodInfo SmelterGetFuel = AccessTools.Method(typeof(Smelter), "GetFuel", (Type[])null, (Type[])null); private static readonly MethodInfo SmelterGetQueueSize = AccessTools.Method(typeof(Smelter), "GetQueueSize", (Type[])null, (Type[])null); private static readonly MethodInfo SmelterFindCookable = AccessTools.Method(typeof(Smelter), "FindCookableItem", (Type[])null, (Type[])null); private static readonly FieldInfo SmelterNView = AccessTools.Field(typeof(Smelter), "m_nview"); private static readonly FieldInfo FireplaceNView = AccessTools.Field(typeof(Fireplace), "m_nview"); private static bool Ready { get { if (SmelterGetFuel != null && SmelterGetQueueSize != null && SmelterFindCookable != null && SmelterNView != null) { return FireplaceNView != null; } return false; } } public static bool Verify() { List list = new List(); if (SmelterGetFuel == null) { list.Add("Smelter.GetFuel"); } if (SmelterGetQueueSize == null) { list.Add("Smelter.GetQueueSize"); } if (SmelterFindCookable == null) { list.Add("Smelter.FindCookableItem"); } if (SmelterNView == null) { list.Add("Smelter.m_nview"); } if (FireplaceNView == null) { list.Add("Fireplace.m_nview"); } if (list.Count == 0) { return true; } KyndaPlugin.Log.LogError((object)("Game members this mod reflects on are missing - batching is disabled: " + string.Join(", ", list.ToArray()))); return false; } private static int Extra(int perAdd) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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) KeyCode value = KyndaConfig.BatchModifier.Value; if ((int)value != 0 && !Input.GetKey(value)) { return 0; } return Mathf.Max(0, perAdd - 1); } internal unsafe static string BatchHint(int perAdd) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (perAdd <= 1) { return ""; } KeyCode value = KyndaConfig.BatchModifier.Value; if ((int)value != 0) { return "\n[" + ((object)(*(KeyCode*)(&value))/*cast due to .constrained prefix*/).ToString() + "] x" + perAdd; } return "\nx" + perAdd + " per press"; } [HarmonyPostfix] [HarmonyPatch(typeof(Smelter), "OnAddFuel")] private static void BatchFuel(Smelter __instance, bool __result, Humanoid user) { if (!__result || (Object)(object)user == (Object)null || !Ready) { return; } int num = Extra(KyndaConfig.SmelterItemsPerAdd.Value); if (num <= 0) { return; } object? value = SmelterNView.GetValue(__instance); ZNetView val = (ZNetView)((value is ZNetView) ? value : null); if ((Object)(object)val == (Object)null || !val.IsValid()) { return; } Inventory inventory = user.GetInventory(); if (inventory == null || (Object)(object)__instance.m_fuelItem == (Object)null) { return; } string name = __instance.m_fuelItem.m_itemData.m_shared.m_name; float num2 = (float)SmelterGetFuel.Invoke(__instance, null) + 1f; int num3 = 0; for (int i = 0; i < num; i++) { if (num2 > (float)(__instance.m_maxFuel - 1)) { break; } if (!inventory.HaveItem(name, true)) { break; } inventory.RemoveItem(name, 1, -1, true); val.InvokeRPC("RPC_AddFuel", Array.Empty()); num2 += 1f; num3++; } Report(__instance.m_name, "fuel", num3); } [HarmonyPostfix] [HarmonyPatch(typeof(Smelter), "OnAddOre")] private static void BatchOre(Smelter __instance, bool __result, Humanoid user) { if (!__result || (Object)(object)user == (Object)null || !Ready) { return; } int num = Extra(KyndaConfig.SmelterItemsPerAdd.Value); if (num <= 0) { return; } object? value = SmelterNView.GetValue(__instance); ZNetView val = (ZNetView)((value is ZNetView) ? value : null); if ((Object)(object)val == (Object)null || !val.IsValid()) { return; } Inventory inventory = user.GetInventory(); if (inventory == null) { return; } int num2 = (int)SmelterGetQueueSize.Invoke(__instance, null) + 1; int num3 = 0; for (int i = 0; i < num; i++) { if (num2 >= __instance.m_maxOre) { break; } object? obj = SmelterFindCookable.Invoke(__instance, new object[1] { inventory }); ItemData val2 = (ItemData)((obj is ItemData) ? obj : null); if (val2 == null || (Object)(object)val2.m_dropPrefab == (Object)null) { break; } inventory.RemoveItem(val2, 1); val.InvokeRPC("RPC_AddOre", new object[1] { ((Object)val2.m_dropPrefab).name }); num2++; num3++; } Report(__instance.m_name, "ore", num3); } [HarmonyPostfix] [HarmonyPatch(typeof(Fireplace), "UseItem")] private static void BatchFireplaceUseItem(Fireplace __instance, bool __result, Humanoid user, ItemData item) { if (__result && !((Object)(object)user == (Object)null) && item != null && !((Object)(object)__instance.m_fuelItem == (Object)null) && !(item.m_shared.m_name != __instance.m_fuelItem.m_itemData.m_shared.m_name)) { TopUpFire(__instance, user); } } [HarmonyPostfix] [HarmonyPatch(typeof(Fireplace), "Interact")] private static void BatchFireplaceInteract(Fireplace __instance, bool __result, Humanoid user, bool hold, bool alt) { if (!(!__result || hold) && !((Object)(object)user == (Object)null) && Ready) { object? value = FireplaceNView.GetValue(__instance); ZNetView val = (ZNetView)((value is ZNetView) ? value : null); if (!((Object)(object)val == (Object)null) && val.IsValid() && (!__instance.m_canTurnOff || alt || !(val.GetZDO().GetFloat(ZDOVars.s_fuel, 0f) > 0f))) { TopUpFire(__instance, user); } } } private static void TopUpFire(Fireplace fireplace, Humanoid user) { int num = Extra(KyndaConfig.FireplaceItemsPerAdd.Value); if (num <= 0 || !Ready || fireplace.m_infiniteFuel || !fireplace.m_canRefill) { return; } object? value = FireplaceNView.GetValue(fireplace); ZNetView val = (ZNetView)((value is ZNetView) ? value : null); if ((Object)(object)val == (Object)null || !val.IsValid()) { return; } Inventory inventory = user.GetInventory(); if (inventory == null || (Object)(object)fireplace.m_fuelItem == (Object)null) { return; } string name = fireplace.m_fuelItem.m_itemData.m_shared.m_name; float num2 = val.GetZDO().GetFloat(ZDOVars.s_fuel, 0f) + 1f; int num3 = 0; for (int i = 0; i < num; i++) { if ((float)Mathf.CeilToInt(num2) >= fireplace.m_maxFuel) { break; } if (!inventory.HaveItem(name, true)) { break; } inventory.RemoveItem(name, 1, -1, true); val.InvokeRPC("RPC_AddFuel", Array.Empty()); num2 += 1f; num3++; } Report(fireplace.m_name, "logs", num3); } private static void Report(string station, string what, int added) { if (KyndaConfig.Verbose.Value && added != 0) { KyndaPlugin.Log.LogInfo((object)(station + ": batched " + added + " extra " + what + ".")); } } } internal static class HoverHint { [HarmonyPostfix] [HarmonyPatch(typeof(Smelter), "OnHoverAddFuel")] private static void SmelterFuelHover(Smelter __instance, ref string __result) { if (__instance.m_maxFuel > 0) { __result += BatchAdd.BatchHint(KyndaConfig.SmelterItemsPerAdd.Value); } } [HarmonyPostfix] [HarmonyPatch(typeof(Smelter), "OnHoverAddOre")] private static void SmelterOreHover(Smelter __instance, ref string __result) { if (__instance.m_maxOre > 0) { __result += BatchAdd.BatchHint(KyndaConfig.SmelterItemsPerAdd.Value); } } [HarmonyPostfix] [HarmonyPatch(typeof(Fireplace), "GetHoverText")] private static void FireplaceHover(Fireplace __instance, ref string __result) { if (!string.IsNullOrEmpty(__result) && __instance.m_canRefill && !__instance.m_infiniteFuel) { __result += BatchAdd.BatchHint(KyndaConfig.FireplaceItemsPerAdd.Value); } } public static void Apply(Harmony harmony) { try { harmony.PatchAll(typeof(HoverHint)); } catch (Exception ex) { KyndaPlugin.Log.LogWarning((object)("Could not add the batch hint to hover text - batching still works, it just will not announce itself: " + ex.Message)); } } } internal static class IconRender { private const int Size = 512; private const int Layer = 31; public static Sprite Shoot(GameObject prefab, string name) { //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_0216: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0073: 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_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Expected O, but got Unknown //IL_00ae: 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_0105: Unknown result type (might be due to invalid IL or missing references) //IL_010a: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Unknown result type (might be due to invalid IL or missing references) //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_0358: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_0370: Unknown result type (might be due to invalid IL or missing references) //IL_037a: Expected O, but got Unknown //IL_03af: Unknown result type (might be due to invalid IL or missing references) //IL_03c3: Unknown result type (might be due to invalid IL or missing references) //IL_03d7: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Unknown result type (might be due to invalid IL or missing references) //IL_0435: Unknown result type (might be due to invalid IL or missing references) //IL_0316: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: 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) GameObject val = null; GameObject val2 = null; RenderTexture val3 = null; RenderTexture active = RenderTexture.active; try { bool forceDisableInit = ZNetView.m_forceDisableInit; ZNetView.m_forceDisableInit = true; try { val = Object.Instantiate(prefab); } finally { ZNetView.m_forceDisableInit = forceDisableInit; } ((Object)val).name = name + "_icon_subject"; val.transform.position = new Vector3(0f, -8000f, 0f); val.transform.rotation = Quaternion.identity; SetLayer(val, 31); Bounds val4 = Framing(val); if (((Bounds)(ref val4)).size == Vector3.zero) { return null; } val2 = new GameObject(name + "_icon_rig"); val2.transform.position = ((Bounds)(ref val4)).center; val2.transform.rotation = Quaternion.Euler(22f, 32f, 0f); Camera val5 = val2.AddComponent(); val5.orthographic = true; val5.clearFlags = (CameraClearFlags)2; val5.cullingMask = int.MinValue; ((Behaviour)val5).enabled = false; Vector3 extents = ((Bounds)(ref val4)).extents; float magnitude = ((Vector3)(ref extents)).magnitude; val5.orthographicSize = magnitude * 1.06f; val5.nearClipPlane = 0.01f; val5.farClipPlane = magnitude * 8f; ((Component)val5).transform.position = ((Bounds)(ref val4)).center - ((Component)val5).transform.forward * magnitude * 4f; Light(val2.transform, magnitude); val3 = (val5.targetTexture = RenderTexture.GetTemporary(512, 512, 24, (RenderTextureFormat)0, (RenderTextureReadWrite)2)); bool fog = RenderSettings.fog; AmbientMode ambientMode = RenderSettings.ambientMode; Color ambientLight = RenderSettings.ambientLight; float ambientIntensity = RenderSettings.ambientIntensity; Color[] array; Color[] array2; try { RenderSettings.fog = false; RenderSettings.ambientMode = (AmbientMode)3; RenderSettings.ambientLight = new Color(0.34f, 0.35f, 0.38f); RenderSettings.ambientIntensity = 1f; array = Expose(val5, val3, Color.black); array2 = Expose(val5, val3, Color.white); } finally { RenderSettings.fog = fog; RenderSettings.ambientMode = ambientMode; RenderSettings.ambientLight = ambientLight; RenderSettings.ambientIntensity = ambientIntensity; } Color[] array3 = (Color[])(object)new Color[array.Length]; int num = 0; for (int i = 0; i < array3.Length; i++) { float num2 = 1f - (array2[i].r - array[i].r); num2 = Mathf.Clamp01(Mathf.Max(num2, Mathf.Max(1f - (array2[i].g - array[i].g), 1f - (array2[i].b - array[i].b)))); array3[i] = ((num2 <= 0.004f) ? new Color(0f, 0f, 0f, 0f) : new Color(array[i].r / num2, array[i].g / num2, array[i].b / num2, num2)); if (num2 > 0.5f) { num++; } } Texture2D val6 = new Texture2D(512, 512, (TextureFormat)4, false) { filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1, name = name + "_icon", hideFlags = (HideFlags)61 }; val6.SetPixels(array3); val6.Apply(); KyndaPlugin.Log.LogInfo((object)$"Icon for {name}: {512}px, subject {((Bounds)(ref val4)).size.x:0.00}x{((Bounds)(ref val4)).size.y:0.00}x{((Bounds)(ref val4)).size.z:0.00}m, {(float)num * 100f / (float)array3.Length:0}% of the frame covered."); Dump(val6, name); return Sprite.Create(val6, new Rect(0f, 0f, 512f, 512f), new Vector2(0.5f, 0.5f)); } catch (Exception ex) { KyndaPlugin.Log.LogWarning((object)("Could not photograph " + name + " for its icon: " + ex.Message + " - falling back to the png beside the dll.")); return null; } finally { RenderTexture.active = active; if ((Object)(object)val3 != (Object)null) { RenderTexture.ReleaseTemporary(val3); } if ((Object)(object)val2 != (Object)null) { Object.DestroyImmediate((Object)(object)val2); } if ((Object)(object)val != (Object)null) { Object.DestroyImmediate((Object)(object)val); } } } private static Color[] Expose(Camera camera, RenderTexture target, Color background) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) camera.backgroundColor = new Color(background.r, background.g, background.b, 1f); camera.Render(); RenderTexture.active = target; Texture2D val = new Texture2D(512, 512, (TextureFormat)4, false); try { val.ReadPixels(new Rect(0f, 0f, 512f, 512f), 0, 0); val.Apply(); return val.GetPixels(); } finally { Object.DestroyImmediate((Object)(object)val); } } private static void Dump(Texture2D texture, string name) { if (KyndaConfig.Verbose == null || !KyndaConfig.Verbose.Value) { return; } try { Type type = AccessTools.TypeByName("UnityEngine.ImageConversion"); MethodInfo methodInfo = ((type != null) ? AccessTools.Method(type, "EncodeToPNG", new Type[1] { typeof(Texture2D) }, (Type[])null) : null); if (!(methodInfo == null) && methodInfo.Invoke(null, new object[1] { texture }) is byte[] bytes) { string text = Path.Combine(Path.GetDirectoryName(typeof(IconRender).Assembly.Location), name + "_rendered.png"); File.WriteAllBytes(text, bytes); KyndaPlugin.Log.LogInfo((object)("Wrote " + text + " to look at.")); } } catch (Exception ex) { KyndaPlugin.Log.LogWarning((object)("Could not dump the icon: " + ex.Message)); } } private static Bounds Framing(GameObject subject) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) Bounds result = default(Bounds); bool flag = false; Renderer[] componentsInChildren = subject.GetComponentsInChildren(false); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && val.enabled && !(val is ParticleSystemRenderer)) { if (!flag) { result = val.bounds; flag = true; } else { ((Bounds)(ref result)).Encapsulate(val.bounds); } } } if (!flag) { return new Bounds(subject.transform.position, Vector3.zero); } return result; } private static void Light(Transform rig, float reach) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) Transform transform = new GameObject("key").transform; transform.SetParent(rig, false); transform.localRotation = Quaternion.Euler(28f, -22f, 0f); Light obj = ((Component)transform).gameObject.AddComponent(); obj.type = (LightType)1; obj.color = new Color(1f, 0.96f, 0.88f); obj.intensity = 1.35f; obj.cullingMask = int.MinValue; Transform transform2 = new GameObject("fill").transform; transform2.SetParent(rig, false); transform2.localRotation = Quaternion.Euler(-14f, 158f, 0f); Light obj2 = ((Component)transform2).gameObject.AddComponent(); obj2.type = (LightType)1; obj2.color = new Color(0.72f, 0.78f, 0.92f); obj2.intensity = 0.55f; obj2.cullingMask = int.MinValue; } private static void SetLayer(GameObject root, int layer) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) root.layer = layer; foreach (Transform item in root.transform) { SetLayer(((Component)item).gameObject, layer); } } } internal static class KyndaConfig { public static ConfigEntry SmelterItemsPerAdd; public static ConfigEntry FireplaceItemsPerAdd; public static ConfigEntry BatchModifier; public static ConfigEntry Verbose; public static ConfigEntry DonorCarrierLocations; public static ConfigEntry Enabled; public static ConfigEntry Donor; public static ConfigEntry Station; public static ConfigEntry Range; public static ConfigEntry MaxPerStation; public static ConfigEntry TexelsPerMetre; public static ConfigEntry ShowLink; public static ConfigEntry LinkHeight; public static ConfigEntry PrefabSearch; public static ConfigEntry TestMode; public static ConfigEntry VariantMode; public static ConfigEntry SkinTrials; public static ConfigEntry DumpShader; private const string TestCost = "Wood:1"; public static string CostNow(UpgradeDef def) { if (!TestMode.Value && def.Cost != null) { return def.Cost.Value; } return "Wood:1"; } public static void Bind(ConfigFile config) { TestMode = config.Bind("Diagnostics", "TestMode", false, "Makes both upgrades cost one wood, so they can be built and looked at without bronze. Announced in the log on startup so it is hard to leave on."); DonorCarrierLocations = config.Bind("Diagnostics", "DonorCarrierLocations", "Vendor,Hildir", "Fallback only, and normally unused. A missing donor material is now loaded straight out of its own bundle by name, so no location has to be summoned for it. These location prefabs are soft-ref loaded only if that direct load finds nothing under the wanted name - a game update renaming an asset, or one of the few assets that exist solely inside a containing prefab. Comma-separated name fragments; blank turns the fallback off."); Verbose = config.Bind("Diagnostics", "Verbose", false, "Log each batched add and why it stopped."); VariantMode = config.Bind("Diagnostics", "VariantMode", false, "Put every candidate model on the hammer as its own piece at one wood each, named 'var: ...', so they can be built side by side and compared. DESTRUCTIVE WHEN TURNED OFF: anything built from a variant vanishes with it, because its prefab name stops existing. Build them somewhere you do not mind losing."); SkinTrials = config.Bind("Diagnostics", "SkinTrials", "", "Comma-separated donor prefabs. Puts one copy of each upgrade on the hammer per donor, named 'skin: ...', so the same model can be seen wearing every candidate surface side by side. Empty turns it off. DESTRUCTIVE WHEN TURNED OFF, exactly as VariantMode is: anything built from a trial vanishes when its prefab name stops existing."); DumpShader = config.Bind("Diagnostics", "DumpShader", false, "List every property of each borrowed material's shader, with its type. Needed before our own texture can be written into one."); PrefabSearch = config.Bind("Diagnostics", "PrefabSearch", "", "Comma-separated words. Every loaded prefab whose name contains one is listed in the log, which is how to find a prefab worth borrowing a material from. Empty turns it off. Scans everything loaded, so empty it again when you are done."); Enabled = config.Bind("Upgrades", "Enabled", true, "Add the two buildable upgrades that raise a nearby station's capacity. They register prefabs, so a world that later loads without this mod discards every one already built rather than reporting an error - which is what the version gate exists to prevent."); Donor = config.Bind("Upgrades", "Donor", "piece_chest_barrel", "Prefab cloned for its machinery - ZNetView, Piece, WearNTear, placement rules. Its look, collision and icon are all replaced, so this is not a visual choice. Falls back to piece_chest_wood. Needs a restart."); Station = config.Bind("Upgrades", "Station", "forge", "Prefab name of the crafting station you must stand near to build these. The forge, because both upgrades are held together with nails and a workbench could never have made them. Empty or an unknown name leaves the donor's, which is the workbench."); Range = config.Bind("Upgrades", "Range", 4f, "How close an upgrade must be to the station it feeds."); MaxPerStation = config.Bind("Upgrades", "MaxPerStation", 1, "How many upgrades of one kind count for a single station. One, because these are a one-time improvement rather than something to stack - the capacity figures are chosen to land on a round number exactly once. Raising it stacks them again; a bin that is not counting says so when you look at it."); TexelsPerMetre = config.Bind("Upgrades", "TexelsPerMetre", 28f, "How coarse the borrowed texture is drawn, in texels per metre. Vanilla's props and piles run 24 to 54; its structural pieces run far finer and are the wrong thing to match. Higher is finer and eventually reads as flat colour, because the grain becomes smaller than a pixel on screen. A group too big for its donor's slice of the atlas is drawn coarser than this rather than tiled - the log says when."); ShowLink = config.Bind("Upgrades", "ShowLink", true, "Draw the game's own station-link effect from an upgrade to the station it feeds when you look at it - the same run of motes a chopping block draws to its workbench. Off is silent."); LinkHeight = config.Bind("Upgrades", "LinkHeight", 0.8f, "How far up the upgrade the link starts, in metres. The default leaves it around the top of both pieces; at 0 it comes out of the ground."); UpgradePrefabs.Trough.Name = config.Bind("Trough", "Name", "Tun", "Name shown on the hammer and when you look at one."); UpgradePrefabs.Trough.Stations = config.Bind("Trough", "Stations", "smelter", "Station prefabs this upgrades, comma separated. A station not named here is left alone even if it is the right kind, and a bin standing next to one says it is feeding nothing rather than pretending."); UpgradePrefabs.Trough.Cost = config.Bind("Trough", "Cost", "FineWood:20,IronNails:15", "Build cost, as Item:Amount pairs. The iron nails put it a biome beyond the smelter it upgrades, so it is an improvement you return to make rather than part of the original build."); UpgradePrefabs.Trough.Model = config.Bind("Trough", "Model", "kynda_tun_camp.obj", "The OBJ loaded from beside the DLL. Its .col sidecar supplies the collision and its _icon.png the hammer icon, both matched by name - so dropping in a new model brings its own shape and picture with it."); UpgradePrefabs.Trough.Scale = config.Bind("Trough", "Scale", 1f, "Overall size of the trough. Scales the collision with it, since the boxes are children of the piece."); UpgradePrefabs.Trough.SkinDonors = config.Bind("Trough", "SkinDonors", "@fi_village_wood:keep,coal=@coal_pile:keep,ore=@copper_ore:0.02/0.30/0.46/0.22", "Which vanilla prefab this piece borrows its surface from. A bare prefab name covers the whole piece, which is the usual case and matches how vanilla builds a piece - one texture carrying every substance it is made of. group=prefab pairs override a single group. Empty uses the general list. Ore and coal keep their own surfaces either way: they are what is in the piece rather than what it is made of, and vanilla gives a smelter's ore heap its own material too."); UpgradePrefabs.Trough.OreCapacity = config.Bind("Trough", "OreCapacity", 20, "Extra ore a smelter or furnace holds per trough. Vanilla's 10 becomes 30."); UpgradePrefabs.Trough.FuelCapacity = config.Bind("Trough", "FuelCapacity", 40, "Extra coal a smelter or furnace holds per trough. Vanilla's 20 becomes 60. Twice the ore figure on purpose - a smelter burns two coal per ore, so matching them would run the fuel out before the ore."); UpgradePrefabs.Woodrack.Stations = config.Bind("Woodrack", "Stations", "charcoal_kiln", "Station prefabs this upgrades, comma separated. A station not named here is left alone even if it is the right kind."); UpgradePrefabs.Woodrack.Name = config.Bind("Woodrack", "Name", "Woodrack", "Name shown on the hammer and when you look at one."); UpgradePrefabs.Woodrack.Cost = config.Bind("Woodrack", "Cost", "FineWood:25,DeerHide:20,BronzeNails:25", "Build cost, as Item:Amount pairs. The bronze nails put it a tier behind the charcoal kiln it serves, so it is something you come back and add rather than raise alongside the kiln itself."); UpgradePrefabs.Woodrack.Model = config.Bind("Woodrack", "Model", "kynda_rack_camp.obj", "The OBJ loaded from beside the DLL, with its .col and _icon.png matched by name."); UpgradePrefabs.Woodrack.Scale = config.Bind("Woodrack", "Scale", 1f, "Overall size of the woodrack. Scales the collision with it, since the boxes are children of the piece."); UpgradePrefabs.Woodrack.SkinDonors = config.Bind("Woodrack", "SkinDonors", "@wood_item:keep,frame=@woodwall:keep,roof=@straw_roof:keep,roofalpha=@straw_roof_alpha:keep", "Which vanilla prefab this piece borrows its surface from. A bare prefab name covers the whole piece; group=prefab pairs override a single group. Empty uses the general list."); UpgradePrefabs.Woodrack.OreCapacity = config.Bind("Woodrack", "OreCapacity", 25, "Extra wood a charcoal kiln holds per woodrack. Vanilla's 25 becomes 50."); BatchModifier = config.Bind("Batching", "BatchModifier", (KeyCode)304, "Hold this while interacting to add a batch instead of one. Plain use stays vanilla, so nothing is taken away - the batch is an option you reach for."); SmelterItemsPerAdd = config.Bind("Batching", "SmelterItemsPerAdd", 3, "Ore or coal added per press at a smelter, kiln, blast furnace, windmill, spinning wheel or eitr refinery. Stops early at the station's capacity or when you run out. 1 restores vanilla."); FireplaceItemsPerAdd = config.Bind("Batching", "FireplaceItemsPerAdd", 3, "Logs added per press at a campfire, hearth or torch. 1 restores vanilla."); } } [BepInPlugin("ezomic.valheim.kynda", "Kynda", "1.0.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class KyndaPlugin : BaseUnityPlugin { public const string PluginGuid = "ezomic.valheim.kynda"; public const string PluginName = "Kynda"; public const string PluginVersion = "1.0.2"; public const string PluginAuthor = "Robbin Thijssen"; private const string CoreGuid = "ezomic.valheim.core"; internal static bool CorePresent; internal static ManualLogSource Log; private Harmony _harmony; private void Awake() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; KyndaConfig.Bind(((BaseUnityPlugin)this).Config); SoftAssets.MakeEverythingLoadable(); TryRegisterWithCore(); _harmony = new Harmony("ezomic.valheim.kynda"); _harmony.PatchAll(typeof(ScenePatches)); if (BatchAdd.Verify()) { _harmony.PatchAll(typeof(BatchAdd)); HoverHint.Apply(_harmony); } Log.LogInfo((object)"Kynda 1.0.2 by Robbin Thijssen - ready."); if (KyndaConfig.TestMode.Value) { Log.LogWarning((object)"TEST MODE: both upgrades cost one wood. Turn TestMode off in the config before playing for real."); } } private void TryRegisterWithCore() { CorePresent = Chainloader.PluginInfos.ContainsKey("ezomic.valheim.core"); if (!CorePresent) { Log.LogWarning((object)"Core is not installed, so there is no version gate. The upgrades still work, but a world loaded without this mod discards every one already built - and nothing will stop that happening."); } else { RegisterWithCore(); } } [MethodImpl(MethodImplOptions.NoInlining)] private void RegisterWithCore() { Suite.Register("ezomic.valheim.kynda", "Kynda", "1.0.2", ((BaseUnityPlugin)this).Config, (Requirement)0, (Assembly)null); } private void OnDestroy() { if (_harmony != null) { _harmony.UnpatchSelf(); } } private void Update() { if (!((Object)(object)ZNetScene.instance == (Object)null) && !((Object)(object)ObjectDB.instance == (Object)null)) { UpgradePrefabs.Register(); Skins.Tick(); UpgradePrefabs.RefreshIcons(); } } } internal sealed class ModelData { public Mesh Mesh; public string[] Groups; } internal static class ObjMesh { public static ModelData Load(string path) { if (!File.Exists(path)) { KyndaPlugin.Log.LogWarning((object)("No model at " + path)); return null; } try { return Parse(File.ReadAllLines(path), Path.GetFileNameWithoutExtension(path)); } catch (Exception ex) { KyndaPlugin.Log.LogError((object)("Could not read " + path + ": " + ex.Message)); return null; } } private static ModelData Parse(string[] lines, string name) { //IL_029c: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02aa: Expected O, but got Unknown //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_037c: Unknown result type (might be due to invalid IL or missing references) //IL_0381: Unknown result type (might be due to invalid IL or missing references) List list = new List(); List list2 = new List(); List list3 = new List(); List list4 = new List(); List list5 = new List(); List> list6 = new List>(); Dictionary index = new Dictionary(); Dictionary lookup = new Dictionary(); List list7 = new List(); List list8 = new List(); List list9 = new List(); List outShades = new List(); CultureInfo invariantCulture = CultureInfo.InvariantCulture; List triangles = Bucket("", list5, list6, index); for (int i = 0; i < lines.Length; i++) { string text = lines[i].Trim(); if (text.Length == 0 || text[0] == '#') { continue; } string[] array = text.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length < 2) { continue; } switch (array[0]) { case "v": if (array.Length >= 4) { list.Add(new Vector3(float.Parse(array[1], invariantCulture), float.Parse(array[2], invariantCulture), float.Parse(array[3], invariantCulture))); if (array.Length >= 7) { list4.Add(new Color(float.Parse(array[4], invariantCulture), float.Parse(array[5], invariantCulture), float.Parse(array[6], invariantCulture), 1f)); } } break; case "vt": if (array.Length >= 3) { list2.Add(new Vector2(float.Parse(array[1], invariantCulture), float.Parse(array[2], invariantCulture))); } break; case "vn": if (array.Length >= 4) { list3.Add(new Vector3(float.Parse(array[1], invariantCulture), float.Parse(array[2], invariantCulture), float.Parse(array[3], invariantCulture))); } break; case "usemtl": triangles = Bucket(array[1].Trim(), list5, list6, index); break; case "f": AddFace(array, list, list2, list3, list4, lookup, list7, list8, list9, outShades, triangles); break; } } for (int num = list6.Count - 1; num >= 0; num--) { if (list6[num].Count == 0) { list6.RemoveAt(num); list5.RemoveAt(num); } } if (list7.Count == 0 || list6.Count == 0) { KyndaPlugin.Log.LogError((object)("Model " + name + " has no geometry.")); return null; } Mesh val = new Mesh { name = name }; if (list7.Count > 65535) { val.indexFormat = (IndexFormat)1; KyndaPlugin.Log.LogInfo((object)(name + " needs 32 bit indices (" + list7.Count + " verts).")); } val.SetVertices(list7); if (list8.Count == list7.Count) { val.SetUVs(0, list8); } val.subMeshCount = list6.Count; for (int j = 0; j < list6.Count; j++) { val.SetTriangles(list6[j], j); } if (list9.Count == list7.Count) { val.SetNormals(list9); } else { val.RecalculateNormals(); } Color[] array2 = (Color[])(object)new Color[list7.Count]; for (int k = 0; k < array2.Length; k++) { array2[k] = Color.white; } val.colors = array2; val.RecalculateBounds(); val.RecalculateTangents(); int num2 = 0; for (int l = 0; l < list6.Count; l++) { num2 += list6[l].Count; } KyndaPlugin.Log.LogInfo((object)string.Format("Loaded {0}: {1} verts, {2} tris, parts [{3}]", name, list7.Count, num2 / 3, string.Join(", ", list5.ToArray()))); return new ModelData { Mesh = val, Groups = list5.ToArray() }; } private static List Bucket(string material, List names, List> buckets, Dictionary index) { if (index.TryGetValue(material, out var value)) { return buckets[value]; } index[material] = buckets.Count; names.Add(material); buckets.Add(new List()); return buckets[buckets.Count - 1]; } private static void AddFace(string[] parts, List positions, List uvs, List normals, List shades, Dictionary lookup, List outPositions, List outUvs, List outNormals, List outShades, List triangles) { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_0098: 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_00c3: Unknown result type (might be due to invalid IL or missing references) List list = new List(parts.Length - 1); for (int i = 1; i < parts.Length; i++) { string text = parts[i]; if (!lookup.TryGetValue(text, out var value)) { string[] fields = text.Split(new char[1] { '/' }); int num = Index(fields, 0, positions.Count); if (num < 0) { continue; } outPositions.Add(positions[num]); outShades.Add((num < shades.Count) ? shades[num] : Color.white); int num2 = Index(fields, 1, uvs.Count); outUvs.Add((num2 >= 0) ? uvs[num2] : Vector2.zero); int num3 = Index(fields, 2, normals.Count); outNormals.Add((num3 >= 0) ? normals[num3] : Vector3.up); value = (lookup[text] = outPositions.Count - 1); } list.Add(value); } for (int j = 2; j < list.Count; j++) { triangles.Add(list[0]); triangles.Add(list[j - 1]); triangles.Add(list[j]); } } private static int Index(string[] fields, int slot, int count) { if (slot >= fields.Length) { return -1; } string text = fields[slot]; if (string.IsNullOrEmpty(text)) { return -1; } if (!int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return -1; } if (result > 0) { result--; } else if (result < 0) { result = count + result; } if (result < 0 || result >= count) { return -1; } return result; } } internal static class PropIndex { private static Dictionary _index; public static GameObject Find(string name) { if ((Object)(object)ZNetScene.instance != (Object)null) { GameObject prefab = ZNetScene.instance.GetPrefab(name); if ((Object)(object)prefab != (Object)null) { return prefab; } } if (_index == null) { BuildIndex(); } if (!_index.TryGetValue(name, out var value)) { return null; } return value; } public static void Forget() { _index = null; } private static void BuildIndex() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) _index = new Dictionary(StringComparer.OrdinalIgnoreCase); GameObject[] array = Resources.FindObjectsOfTypeAll(); foreach (GameObject val in array) { if ((Object)(object)val == (Object)null || (Object)(object)val.transform.parent != (Object)null || (Object)(object)val.GetComponentInChildren(true) == (Object)null) { continue; } Scene scene = val.scene; bool flag = ((Scene)(ref scene)).IsValid(); if (_index.TryGetValue(((Object)val).name, out var value)) { if (flag) { continue; } scene = value.scene; if (!((Scene)(ref scene)).IsValid()) { continue; } } _index[((Object)val).name] = val; } KyndaPlugin.Log.LogInfo((object)("Prop index built: " + _index.Count + " candidates with meshes.")); } public static void Search(string keywords) { if (string.IsNullOrEmpty(keywords)) { return; } if (_index == null) { BuildIndex(); } string[] array = keywords.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length == 0) { continue; } List list = new List(); foreach (KeyValuePair item in _index) { if (item.Key.IndexOf(text, StringComparison.OrdinalIgnoreCase) >= 0) { string text2 = item.Key.ToLowerInvariant(); if (!text2.Contains("destruction") && !text2.Contains("broken") && !text2.Contains("lod") && !text2.Contains("vfx") && !text2.Contains("sfx")) { list.Add(item.Key); } } } list.Sort(); KyndaPlugin.Log.LogInfo((object)("Prefabs matching '" + text + "' (" + list.Count + "): " + string.Join(", ", list.GetRange(0, Math.Min(40, list.Count)).ToArray()))); } } } internal static class ScenePatches { [HarmonyPostfix] [HarmonyPatch(typeof(ZNetScene), "Awake")] private static void OnSceneAwake() { int num = SmelterCapacity.AttachToPrefabs(); if (num > 0) { KyndaPlugin.Log.LogInfo((object)("Capacity component added to " + num + " station prefab(s).")); } UpgradePrefabs.Register(); PropIndex.Search(KyndaConfig.PrefabSearch.Value); } [HarmonyPostfix] [HarmonyPatch(typeof(ObjectDB), "Awake")] private static void OnObjectDbAwake() { Skins.Invalidate(); UpgradeBin.ForgetConnectionPrefab(); UpgradePrefabs.Register(); } [HarmonyPostfix] [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] private static void OnObjectDbCopy() { Skins.Invalidate(); UpgradeBin.ForgetConnectionPrefab(); UpgradePrefabs.Register(); } } internal static class Skins { private sealed class LateSkin { public MeshRenderer Renderer; public Mesh Mesh; public Vector2[] OriginalUv; public string[] Groups; public IDictionary Overrides; } private static readonly Dictionary Donors = new Dictionary(StringComparer.OrdinalIgnoreCase) { { "wood", new string[3] { "piece_chest_wood", "wood_wall_log", "darkwood_beam" } }, { "frame", new string[3] { "wood_beam", "wood_wall_log", "wood_pole" } }, { "iron", new string[3] { "piece_artisanstation", "forge", "piece_cauldron" } }, { "stone", new string[3] { "stone_wall_2x1", "piece_stonecutter", "smelter" } }, { "coal", new string[3] { "coal_pile", "Coal", "charcoal_kiln" } }, { "ore", new string[3] { "CopperOre", "TinOre", "IronOre" } } }; private static readonly Dictionary Cache = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary Atlas = new Dictionary(StringComparer.OrdinalIgnoreCase); private static readonly Dictionary TexPx = new Dictionary(StringComparer.OrdinalIgnoreCase); private const string EndSuffix = "_end"; public const string Everything = "*"; private static readonly HashSet Contents = new HashSet(StringComparer.OrdinalIgnoreCase) { "ore", "coal" }; private static float _nextSummon; private static string _summonFault; private static readonly HashSet FlipV = new HashSet(StringComparer.Ordinal); private static readonly List _late = new List(); private static float _nextLate; private static readonly HashSet _dumped = new HashSet(StringComparer.Ordinal); public static void Invalidate() { Cache.Clear(); Atlas.Clear(); TexPx.Clear(); PropIndex.Forget(); } private static string Named(string group, IDictionary overrides) { if (overrides == null) { return null; } if (overrides.TryGetValue(group, out var value) && !string.IsNullOrEmpty(value)) { return value; } string text = Base(group); if (overrides.TryGetValue(text, out value) && !string.IsNullOrEmpty(value)) { return value; } if (Contents.Contains(text)) { return null; } if (!overrides.TryGetValue("*", out value) || string.IsNullOrEmpty(value)) { return null; } return value; } private static bool IsEnd(string group) { if (group != null && group.Length > "_end".Length) { return group.EndsWith("_end", StringComparison.OrdinalIgnoreCase); } return false; } private static string Base(string group) { if (!IsEnd(group)) { return group; } return group.Substring(0, group.Length - "_end".Length); } private static string Key(string group, IDictionary overrides) { string text = Named(group, overrides); if (!string.IsNullOrEmpty(text)) { return group + "|" + text; } return group; } private static Material FindMaterial(string name) { if (string.IsNullOrEmpty(name)) { return null; } Material val = null; Material[] array = Resources.FindObjectsOfTypeAll(); foreach (Material val2 in array) { if ((Object)(object)val2 == (Object)null || (Object)(object)val2.shader == (Object)null) { continue; } if (((Object)val2).name == name) { return val2; } if (!((Object)(object)val != (Object)null)) { if (string.Equals(((Object)val2).name, name, StringComparison.OrdinalIgnoreCase)) { val = val2; } else if (((Object)val2).name.StartsWith(name, StringComparison.OrdinalIgnoreCase)) { val = val2; } } } if ((Object)(object)val == (Object)null) { Material val3 = SoftAssets.LoadMaterial(name); if ((Object)(object)val3 != (Object)null) { return val3; } List list = new List(); array = Resources.FindObjectsOfTypeAll(); foreach (Material val4 in array) { if (!((Object)(object)val4 == (Object)null) && ((Object)val4).name != null && ((Object)val4).name.IndexOf(name.Split(new char[1] { '_' })[0], StringComparison.OrdinalIgnoreCase) >= 0) { if (!list.Contains(((Object)val4).name)) { list.Add(((Object)val4).name); } if (list.Count >= 12) { break; } } } KyndaPlugin.Log.LogWarning((object)("No loaded material called '" + name + "'. It only exists once something using it has loaded. Loaded names sharing its prefix: " + ((list.Count == 0) ? "none" : string.Join(", ", list.ToArray())))); SummonDonorCarriers(); } return val; } private static void SummonDonorCarriers() { try { SummonDonorCarriersInner(); } catch (Exception ex) { if (_summonFault == null) { _summonFault = ex.ToString(); KyndaPlugin.Log.LogError((object)("Carrier summon failed: " + _summonFault)); } } } private static void SummonDonorCarriersInner() { if (Time.time < _nextSummon) { return; } ZoneSystem instance = ZoneSystem.instance; if ((Object)(object)instance == (Object)null || instance.m_locations == null) { return; } _nextSummon = Time.time + 30f; string[] array = (KyndaConfig.DonorCarrierLocations.Value ?? "").Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length == 0) { return; } int num = 0; int num2 = 0; foreach (ZoneLocation location in instance.m_locations) { if (location == null) { continue; } num++; string prefabName = location.m_prefabName; if (string.IsNullOrEmpty(prefabName)) { continue; } string[] array2 = array; foreach (string text in array2) { if (prefabName.IndexOf(text.Trim(), StringComparison.OrdinalIgnoreCase) < 0) { continue; } num2++; try { if (location.m_prefab.IsValid && !location.m_prefab.IsLoaded && !location.m_prefab.IsLoading) { location.m_prefab.LoadAsync(); KyndaPlugin.Log.LogInfo((object)("Summoned location asset '" + prefabName + "' for its donor materials.")); } } catch (Exception) { } break; } } KyndaPlugin.Log.LogInfo((object)("Carrier summon pass: " + num + " locations, " + num2 + " matched.")); } public static Material[] SkinAndWatch(MeshRenderer renderer, Mesh mesh, string[] groups, IDictionary overrides) { Material[] array = Skin(groups, overrides); for (int i = 0; i < groups.Length; i++) { if (!((Object)(object)array[i] != (Object)null) && Key(groups[i], overrides).Contains("@")) { _late.Add(new LateSkin { Renderer = renderer, Mesh = mesh, OriginalUv = (((Object)(object)mesh != (Object)null) ? mesh.uv : null), Groups = groups, Overrides = overrides }); KyndaPlugin.Log.LogInfo((object)"A skin donor is not loaded yet - it will be applied when its location streams in."); break; } } return array; } public static void Tick() { if (_late.Count == 0 || Time.realtimeSinceStartup < _nextLate) { return; } _nextLate = Time.realtimeSinceStartup + 5f; for (int num = _late.Count - 1; num >= 0; num--) { LateSkin lateSkin = _late[num]; if ((Object)(object)lateSkin.Renderer == (Object)null || (Object)(object)lateSkin.Mesh == (Object)null) { _late.RemoveAt(num); } else { Material[] array = Skin(lateSkin.Groups, lateSkin.Overrides); bool flag = false; for (int i = 0; i < lateSkin.Groups.Length; i++) { if ((Object)(object)array[i] == (Object)null && Key(lateSkin.Groups[i], lateSkin.Overrides).Contains("@")) { flag = true; } } if (!flag) { if (lateSkin.OriginalUv != null) { lateSkin.Mesh.uv = lateSkin.OriginalUv; } ((Renderer)lateSkin.Renderer).sharedMaterials = array; Remap(lateSkin.Mesh, lateSkin.Groups, lateSkin.Overrides); MeshRenderer[] array2 = Object.FindObjectsOfType(); foreach (MeshRenderer val in array2) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)lateSkin.Renderer)) { MeshFilter component = ((Component)val).GetComponent(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component.sharedMesh != (Object)(object)lateSkin.Mesh)) { ((Renderer)val).sharedMaterials = array; } } } _late.RemoveAt(num); KyndaPlugin.Log.LogInfo((object)"A late skin donor arrived and was applied, standing pieces included."); } } } } public static Material[] Skin(string[] groups, IDictionary overrides) { Material[] array = (Material[])(object)new Material[groups.Length]; for (int i = 0; i < groups.Length; i++) { array[i] = For(groups[i], overrides); } return array; } public unsafe static Material For(string group, IDictionary overrides) { //IL_041a: Unknown result type (might be due to invalid IL or missing references) //IL_041c: Unknown result type (might be due to invalid IL or missing references) //IL_0437: Unknown result type (might be due to invalid IL or missing references) //IL_0439: Unknown result type (might be due to invalid IL or missing references) //IL_042c: Unknown result type (might be due to invalid IL or missing references) //IL_042e: Unknown result type (might be due to invalid IL or missing references) //IL_0433: Unknown result type (might be due to invalid IL or missing references) //IL_044e: Unknown result type (might be due to invalid IL or missing references) //IL_04b1: Unknown result type (might be due to invalid IL or missing references) //IL_02e4: Unknown result type (might be due to invalid IL or missing references) //IL_036c: Unknown result type (might be due to invalid IL or missing references) //IL_036e: Unknown result type (might be due to invalid IL or missing references) string text = Key(group, overrides); if (Cache.TryGetValue(text, out var value)) { return value; } string text2 = Base(group); string text3 = Named(group, overrides); string[] value2; if (!string.IsNullOrEmpty(text3)) { value2 = new string[1] { text3 }; } else if (!Donors.TryGetValue(text2, out value2)) { value2 = Donors["wood"]; } string[] array = value2; Rect val = default(Rect); foreach (string text4 in array) { string text5 = text4.Trim(); if (text5.StartsWith("@")) { string text6 = text5.Substring(1); ((Rect)(ref val))..ctor(0f, 0f, 1f, 1f); if (text6.EndsWith(":keep", StringComparison.OrdinalIgnoreCase)) { Material val2 = FindMaterial(text6.Substring(0, text6.Length - 5)); if (!((Object)(object)val2 == (Object)null)) { Texture texture = val2.GetTexture("_MainTex"); if (!((Object)(object)texture == (Object)null)) { Cache[text] = val2; Atlas.Remove(text); FlipV.Remove(text); TexPx[text] = Mathf.Max(1, texture.width); KyndaPlugin.Log.LogInfo((object)("'" + text + "' skinned with the material " + ((Object)val2).name + " found by name, vanilla UVs kept, " + texture.width + "px.")); return val2; } } continue; } int num = text6.IndexOf(':'); bool flag = false; if (num > 0) { string[] array2 = text6.Substring(num + 1).Split(new char[1] { '/' }); if (array2.Length == 4 && array2[3].StartsWith("~")) { flag = true; array2[3] = array2[3].Substring(1); } if (array2.Length == 4 && float.TryParse(array2[0], NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array2[1], NumberStyles.Float, CultureInfo.InvariantCulture, out var result2) && float.TryParse(array2[2], NumberStyles.Float, CultureInfo.InvariantCulture, out var result3) && float.TryParse(array2[3], NumberStyles.Float, CultureInfo.InvariantCulture, out var result4) && result3 > 0f && result4 > 0f) { ((Rect)(ref val))..ctor(result, result2, result3, result4); } else { KyndaPlugin.Log.LogWarning((object)("Could not read the rect in '" + text5 + "' - expected @name:x/y/w/h. Using the whole sheet, which will look like every tile at once.")); } text6 = text6.Substring(0, num); } Material val3 = FindMaterial(text6); if ((Object)(object)val3 == (Object)null) { continue; } Texture texture2 = val3.GetTexture("_MainTex"); if (!((Object)(object)texture2 == (Object)null)) { Cache[text] = val3; Atlas[text] = val; TexPx[text] = Mathf.Max(1, texture2.width); if (flag) { FlipV.Add(text); } else { FlipV.Remove(text); } ManualLogSource log = KyndaPlugin.Log; string[] obj = new string[12] { "'", text, "' skinned with the material ", ((Object)val3).name, " found by name (shader ", ((Object)val3.shader).name, "), rect ", null, null, null, null, null }; Rect val4 = val; obj[7] = ((object)(*(Rect*)(&val4))/*cast due to .constrained prefix*/).ToString(); obj[8] = (flag ? ", V flipped" : ""); obj[9] = ", "; obj[10] = texture2.width.ToString(); obj[11] = "px."; log.LogInfo((object)string.Concat(obj)); return val3; } continue; } GameObject val5 = PropIndex.Find(text5); if (!((Object)(object)val5 == (Object)null)) { MeshRenderer val6 = MainRenderer(val5); if ((Object)(object)val6 != (Object)null) { Material sharedMaterial = ((Renderer)val6).sharedMaterial; Texture texture3 = sharedMaterial.GetTexture("_MainTex"); Regions((Renderer)(object)val6, out var side, out var cap); Rect value3 = (IsEnd(group) ? cap : ((!IsMetal(text2)) ? side : MetalRegion(texture3, text4, side))); Cache[text] = sharedMaterial; Atlas[text] = value3; TexPx[text] = Mathf.Max(1, texture3.width); KyndaPlugin.Log.LogInfo((object)$"'{text}' skinned with {((Object)sharedMaterial).name} from {text4}/{((Object)val6).name} (shader {((Object)sharedMaterial.shader).name}), atlas {Atlas[text]}, {TexPx[text]}px."); DumpShader(sharedMaterial); return sharedMaterial; } } } KyndaPlugin.Log.LogWarning((object)("No material found for group '" + text + "'.")); if (!text.Contains("@")) { Cache[text] = null; } return null; } private unsafe static void DumpShader(Material material) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Invalid comparison between Unknown and I4 //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Invalid comparison between Unknown and I4 //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Invalid comparison between Unknown and I4 if (!KyndaConfig.DumpShader.Value || (Object)(object)material == (Object)null || (Object)(object)material.shader == (Object)null || !_dumped.Add(((Object)material.shader).name)) { return; } Shader shader = material.shader; int propertyCount = shader.GetPropertyCount(); KyndaPlugin.Log.LogInfo((object)("SHADER " + ((Object)shader).name + ": " + propertyCount + " properties.")); for (int i = 0; i < propertyCount; i++) { string propertyName = shader.GetPropertyName(i); ShaderPropertyType propertyType = shader.GetPropertyType(i); string text = ""; if ((int)propertyType == 4) { Texture texture = material.GetTexture(propertyName); text = (((Object)(object)texture == (Object)null) ? " (unset)" : (" = " + ((Object)texture).name + " " + texture.width + "x" + texture.height)); } else if ((int)propertyType == 0) { text = " = " + ((object)material.GetColor(propertyName)/*cast due to .constrained prefix*/).ToString(); } else if ((int)propertyType == 2 || (int)propertyType == 3) { text = " = " + material.GetFloat(propertyName); } KyndaPlugin.Log.LogInfo((object)(" " + propertyName + " (" + ((object)(*(ShaderPropertyType*)(&propertyType))/*cast due to .constrained prefix*/).ToString() + ")" + text)); } } private static List> Islands(int[] indices, Vector2[] uv) { Dictionary dictionary = new Dictionary(); foreach (int num in indices) { if (num >= 0 && num < uv.Length && !dictionary.ContainsKey(num)) { dictionary[num] = num; } } for (int j = 0; j + 2 < indices.Length; j += 3) { int num2 = indices[j]; int num3 = indices[j + 1]; int num4 = indices[j + 2]; if (dictionary.ContainsKey(num2) && dictionary.ContainsKey(num3) && dictionary.ContainsKey(num4)) { Join(dictionary, num2, num3); Join(dictionary, num2, num4); } } List list = new List(dictionary.Keys); Dictionary> dictionary2 = new Dictionary>(); foreach (int item in list) { int key = Find(dictionary, item); if (!dictionary2.TryGetValue(key, out var value)) { value = (dictionary2[key] = new List()); } value.Add(item); } return new List>(dictionary2.Values); } private static int Find(Dictionary parent, int v) { while (parent[v] != v) { parent[v] = parent[parent[v]]; v = parent[v]; } return v; } private static void Join(Dictionary parent, int a, int b) { int num = Find(parent, a); int num2 = Find(parent, b); if (num != num2) { parent[num] = num2; } } private static Rect Cluster(List rects) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //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_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) Rect val = default(Rect); ((Rect)(ref val))..ctor(0f, 0f, 0f, 0f); if (rects == null || rects.Count == 0) { return val; } List list = new List(rects); int num = 0; bool flag; do { flag = false; num++; for (int i = 0; i < list.Count; i++) { if (flag) { break; } for (int j = i + 1; j < list.Count; j++) { Rect val2 = list[i]; Rect val3 = list[j]; if (!(((Rect)(ref val2)).xMin > ((Rect)(ref val3)).xMax + 1f / 128f) && !(((Rect)(ref val3)).xMin > ((Rect)(ref val2)).xMax + 1f / 128f) && !(((Rect)(ref val2)).yMin > ((Rect)(ref val3)).yMax + 1f / 128f) && !(((Rect)(ref val3)).yMin > ((Rect)(ref val2)).yMax + 1f / 128f)) { float num2 = Mathf.Min(((Rect)(ref val2)).xMin, ((Rect)(ref val3)).xMin); float num3 = Mathf.Min(((Rect)(ref val2)).yMin, ((Rect)(ref val3)).yMin); list[i] = new Rect(num2, num3, Mathf.Max(((Rect)(ref val2)).xMax, ((Rect)(ref val3)).xMax) - num2, Mathf.Max(((Rect)(ref val2)).yMax, ((Rect)(ref val3)).yMax) - num3); list.RemoveAt(j); flag = true; break; } } } } while (flag && num < 4096); Rect result = val; foreach (Rect item in list) { Rect current = item; if (((Rect)(ref current)).width * ((Rect)(ref current)).height > ((Rect)(ref result)).width * ((Rect)(ref result)).height) { result = current; } } return result; } private static MeshRenderer MainRenderer(GameObject donor) { MeshRenderer result = null; int num = 0; MeshRenderer[] componentsInChildren = donor.GetComponentsInChildren(true); foreach (MeshRenderer val in componentsInChildren) { Material sharedMaterial = ((Renderer)val).sharedMaterial; if ((Object)(object)sharedMaterial == (Object)null || (Object)(object)sharedMaterial.shader == (Object)null || !sharedMaterial.HasProperty("_MainTex") || (Object)(object)sharedMaterial.GetTexture("_MainTex") == (Object)null) { continue; } MeshFilter component = ((Component)val).GetComponent(); Mesh val2 = (((Object)(object)component != (Object)null) ? component.sharedMesh : null); if ((Object)(object)val2 == (Object)null) { continue; } int num2; try { if (!val2.isReadable) { continue; } num2 = val2.triangles.Length; goto IL_00a4; } catch { } continue; IL_00a4: if (num2 > num) { num = num2; result = val; } } return result; } private static bool IsMetal(string family) { return string.Equals(family, "iron", StringComparison.OrdinalIgnoreCase); } private static Rect MetalRegion(Texture sheet, string donor, Rect fallback) { //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_029e: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)sheet == (Object)null) { return fallback; } int num = Mathf.Clamp(sheet.width, 8, 64); int num2 = Mathf.Clamp(sheet.height, 8, 64); RenderTexture val = null; RenderTexture active = RenderTexture.active; Texture2D val2 = null; Color[] pixels; try { val = RenderTexture.GetTemporary(num, num2, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2); Graphics.Blit(sheet, val); RenderTexture.active = val; val2 = new Texture2D(num, num2, (TextureFormat)5, false); val2.ReadPixels(new Rect(0f, 0f, (float)num, (float)num2), 0, 0); val2.Apply(); pixels = val2.GetPixels(); } catch (Exception ex) { KyndaPlugin.Log.LogWarning((object)("Could not read " + donor + "'s sheet to find its metal: " + ex.Message)); return fallback; } finally { RenderTexture.active = active; if ((Object)(object)val != (Object)null) { RenderTexture.ReleaseTemporary(val); } if ((Object)(object)val2 != (Object)null) { Object.Destroy((Object)(object)val2); } } if (pixels == null || pixels.Length < num * num2) { return fallback; } float[] array = new float[num]; float num3 = 0f; for (int i = 0; i < num; i++) { float num4 = 0f; for (int j = 0; j < num2; j++) { num4 += Saturation(pixels[j * num + i]); } array[i] = num4 / (float)num2; num3 += array[i]; } num3 /= (float)num; if (!Run(array, num3, out var from, out var to)) { return Grey(donor, fallback); } float[] array2 = new float[num2]; for (int k = 0; k < num2; k++) { float num5 = 0f; for (int l = from; l <= to; l++) { num5 += Saturation(pixels[k * num + l]); } array2[k] = num5 / (float)(to - from + 1); } if (!Run(array2, num3, out var from2, out var to2)) { from2 = 0; to2 = num2 - 1; } Rect result = default(Rect); ((Rect)(ref result))..ctor(((float)from + 1f) / (float)num, ((float)from2 + 1f) / (float)num2, Mathf.Max(1f, (float)(to - from) - 1f) / (float)num, Mathf.Max(1f, (float)(to2 - from2) - 1f) / (float)num2); KyndaPlugin.Log.LogInfo((object)$"{donor}'s metal is the {to - from + 1}x{to2 - from2 + 1} px block at {((Rect)(ref result)).x:0.000},{((Rect)(ref result)).y:0.000} - saturation {Mean(array, from, to):0.00} against {num3:0.00} across the sheet."); return result; } private static bool Run(float[] slices, float overall, out int from, out int to) { from = 0; to = -1; float num = Mathf.Min(overall * 0.5f, 0.18f); int num2 = 0; int num3 = -1; int num4 = -1; for (int i = 0; i < slices.Length; i++) { if (slices[i] <= num) { if (num4 < 0) { num4 = i; } if (i - num4 > num3 - num2) { num2 = num4; num3 = i; } } else { num4 = -1; } } if (num3 - num2 < 2) { return false; } from = num2; to = num3; return true; } private static float Saturation(Color c) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) float num = Mathf.Max(c.r, Mathf.Max(c.g, c.b)); float num2 = Mathf.Min(c.r, Mathf.Min(c.g, c.b)); if (!(num <= 0.0001f)) { return (num - num2) / num; } return 0f; } private static float Mean(float[] slices, int from, int to) { float num = 0f; for (int i = from; i <= to; i++) { num += slices[i]; } return num / (float)Mathf.Max(1, to - from + 1); } private static Rect Grey(string donor, Rect fallback) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) KyndaPlugin.Log.LogInfo((object)(donor + " has no unsaturated block - it is all one substance, so metal parts will wear the same surface as the rest of it.")); return fallback; } private static void Regions(Renderer renderer, out Rect side, out Rect cap) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Unknown result type (might be due to invalid IL or missing references) //IL_0366: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) //IL_0381: Unknown result type (might be due to invalid IL or missing references) //IL_0386: Unknown result type (might be due to invalid IL or missing references) //IL_0390: Unknown result type (might be due to invalid IL or missing references) //IL_0395: Unknown result type (might be due to invalid IL or missing references) //IL_03a4: Unknown result type (might be due to invalid IL or missing references) //IL_03a9: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0155: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_03cb: Unknown result type (might be due to invalid IL or missing references) //IL_03cd: Unknown result type (might be due to invalid IL or missing references) //IL_04e3: Unknown result type (might be due to invalid IL or missing references) //IL_04e8: Unknown result type (might be due to invalid IL or missing references) //IL_03ec: Unknown result type (might be due to invalid IL or missing references) //IL_03ee: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_051b: Unknown result type (might be due to invalid IL or missing references) //IL_0520: Unknown result type (might be due to invalid IL or missing references) //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01bc: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_0501: Unknown result type (might be due to invalid IL or missing references) //IL_0504: Unknown result type (might be due to invalid IL or missing references) //IL_0511: Unknown result type (might be due to invalid IL or missing references) //IL_0513: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: Unknown result type (might be due to invalid IL or missing references) Rect val = default(Rect); ((Rect)(ref val))..ctor(0f, 0f, 1f, 1f); side = val; cap = val; MeshFilter val2 = (((Object)(object)renderer != (Object)null) ? ((Component)renderer).GetComponent() : null); Mesh val3 = (((Object)(object)val2 != (Object)null) ? val2.sharedMesh : null); if ((Object)(object)val3 == (Object)null) { return; } Vector3[] vertices; Vector2[] uv; int[] triangles; try { if (!val3.isReadable) { return; } vertices = val3.vertices; uv = val3.uv; triangles = val3.triangles; } catch { return; } if (uv == null || uv.Length == 0 || triangles == null || triangles.Length < 3 || vertices == null || vertices.Length == 0) { return; } float[] array = new float[3]; List[] array2 = new List[3] { new List(), new List(), new List() }; for (int i = 0; i + 2 < triangles.Length; i += 3) { int num = triangles[i]; int num2 = triangles[i + 1]; int num3 = triangles[i + 2]; if (num >= uv.Length || num2 >= uv.Length || num3 >= uv.Length || num >= vertices.Length || num2 >= vertices.Length || num3 >= vertices.Length) { continue; } Vector3 val4 = Vector3.Cross(vertices[num2] - vertices[num], vertices[num3] - vertices[num]); float magnitude = ((Vector3)(ref val4)).magnitude; if (!(magnitude <= 1E-09f)) { Vector3 val5 = val4 / magnitude; int num4 = ((!(Mathf.Abs(val5.x) >= Mathf.Abs(val5.y)) || !(Mathf.Abs(val5.x) >= Mathf.Abs(val5.z))) ? ((Mathf.Abs(val5.y) >= Mathf.Abs(val5.z)) ? 1 : 2) : 0); array[num4] += magnitude * 0.5f; float num5 = Mathf.Min(uv[num].x, Mathf.Min(uv[num2].x, uv[num3].x)); float num6 = Mathf.Max(uv[num].x, Mathf.Max(uv[num2].x, uv[num3].x)); float num7 = Mathf.Min(uv[num].y, Mathf.Min(uv[num2].y, uv[num3].y)); float num8 = Mathf.Max(uv[num].y, Mathf.Max(uv[num2].y, uv[num3].y)); float num9 = num6 - num5; float num10 = num8 - num7; if (!(num9 <= 0.005f) && !(num10 <= 0.005f) && !(num9 > 1f) && !(num10 > 1f)) { array2[num4].Add(new Rect(num5, num7, num9, num10)); } } } float num11 = array[0] + array[1] + array[2]; if (num11 <= 0f) { return; } int num12 = 0; for (int j = 1; j < 3; j++) { if (array[j] < array[num12]) { num12 = j; } } Rect[] array3 = (Rect[])(object)new Rect[3] { Cluster(array2[0]), Cluster(array2[1]), Cluster(array2[2]) }; Rect val6 = array3[0]; Rect[] array4 = array3; for (int k = 0; k < array4.Length; k++) { Rect val7 = array4[k]; if (((Rect)(ref val7)).width * ((Rect)(ref val7)).height > ((Rect)(ref val6)).width * ((Rect)(ref val6)).height) { val6 = val7; } } if (((Rect)(ref val6)).width > 0f) { side = val6; } KyndaPlugin.Log.LogInfo((object)$"{((Object)renderer).name}: surface {array[0] / num11 * 100f:0}/{array[1] / num11 * 100f:0}/{array[2] / num11 * 100f:0}% by axis, fields {((Rect)(ref array3[0])).width:0.000}x{((Rect)(ref array3[0])).height:0.000} / {((Rect)(ref array3[1])).width:0.000}x{((Rect)(ref array3[1])).height:0.000} / {((Rect)(ref array3[2])).width:0.000}x{((Rect)(ref array3[2])).height:0.000}."); float num13 = array[num12] / num11; Rect val8 = array3[num12]; if (num13 <= 0.3f && ((Rect)(ref val8)).width > 0f && val8 != side) { cap = val8; return; } cap = side; KyndaPlugin.Log.LogInfo((object)$"{((Object)renderer).name} has no separate end patch - its thinnest axis is {num13 * 100f:0}% of its surface. Sawn ends will use the side grain."); } public static void Remap(Mesh mesh, string[] groups, IDictionary overrides) { //IL_0230: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0241: Unknown result type (might be due to invalid IL or missing references) //IL_0246: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_026d: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_0276: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02ed: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_02f1: Unknown result type (might be due to invalid IL or missing references) //IL_02fb: 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_032c: 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_0335: Unknown result type (might be due to invalid IL or missing references) //IL_033a: Unknown result type (might be due to invalid IL or missing references) //IL_033f: Unknown result type (might be due to invalid IL or missing references) //IL_0379: Unknown result type (might be due to invalid IL or missing references) //IL_03e6: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Unknown result type (might be due to invalid IL or missing references) //IL_040a: Unknown result type (might be due to invalid IL or missing references) //IL_040f: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)mesh == (Object)null || groups == null) { return; } Vector2[] uv = mesh.uv; if (uv == null || uv.Length == 0) { return; } int num = Mathf.Min(groups.Length, mesh.subMeshCount); float num2 = Mathf.Max(1f, KyndaConfig.TexelsPerMetre.Value); bool[] array = new bool[uv.Length]; Vector2 val = default(Vector2); Vector2 val2 = default(Vector2); for (int i = 0; i < num; i++) { string text = Key(groups[i], overrides); if (!Atlas.TryGetValue(text, out var value) || !TexPx.TryGetValue(text, out var value2) || value2 <= 0) { continue; } int[] triangles = mesh.GetTriangles(i); if (triangles.Length == 0) { continue; } if (IsEnd(groups[i])) { int[] array2 = triangles; foreach (int num3 in array2) { if (num3 >= 0 && num3 < uv.Length && !array[num3]) { array[num3] = true; float num4 = Mathf.Clamp01(uv[num3].y); if (FlipV.Contains(text)) { num4 = 1f - num4; } uv[num3] = new Vector2(((Rect)(ref value)).x + Mathf.Clamp01(uv[num3].x) * ((Rect)(ref value)).width, ((Rect)(ref value)).y + num4 * ((Rect)(ref value)).height); } } KyndaPlugin.Log.LogInfo((object)$"'{text}' aimed at the end-grain patch at {((Rect)(ref value)).x:0.000},{((Rect)(ref value)).y:0.000} {((Rect)(ref value)).width:0.000}x{((Rect)(ref value)).height:0.000} ({Mathf.RoundToInt(((Rect)(ref value)).width * (float)value2)} texels across)."); continue; } List> list = Islands(triangles, uv); float num5 = float.MaxValue; float num6 = 0f; foreach (List item in list) { ((Vector2)(ref val))..ctor(float.MaxValue, float.MaxValue); ((Vector2)(ref val2))..ctor(float.MinValue, float.MinValue); foreach (int item2 in item) { val = Vector2.Min(val, uv[item2]); val2 = Vector2.Max(val2, uv[item2]); } Vector2 val3 = val2 - val; if (val3.x <= 0f || val3.y <= 0f) { continue; } float num7 = num2 / (float)value2; num7 = Mathf.Min(num7, ((Rect)(ref value)).width / val3.x); num7 = Mathf.Min(num7, ((Rect)(ref value)).height / val3.y); num5 = Mathf.Min(num5, num7 * (float)value2); num6 = Mathf.Max(num6, num7 * (float)value2); Vector2 val4 = (val + val2) * 0.5f; Vector2 val5 = new Vector2(((Rect)(ref value)).x + ((Rect)(ref value)).width * 0.5f, ((Rect)(ref value)).y + ((Rect)(ref value)).height * 0.5f) - val4 * num7; foreach (int item3 in item) { if (!array[item3]) { array[item3] = true; uv[item3] = new Vector2(Mathf.Clamp(uv[item3].x * num7 + val5.x, ((Rect)(ref value)).xMin, ((Rect)(ref value)).xMax), FlipV.Contains(text) ? (((Rect)(ref value)).yMax - (Mathf.Clamp(uv[item3].y * num7 + val5.y, ((Rect)(ref value)).yMin, ((Rect)(ref value)).yMax) - ((Rect)(ref value)).yMin)) : Mathf.Clamp(uv[item3].y * num7 + val5.y, ((Rect)(ref value)).yMin, ((Rect)(ref value)).yMax)); } } } if (!(num6 <= 0f)) { KyndaPlugin.Log.LogInfo((object)$"'{text}' laid out at {num5:0}-{num6:0} texels/m (wanted {num2:0}) across {list.Count} parts, in a {((Rect)(ref value)).width:0.000}x{((Rect)(ref value)).height:0.000} rect."); } } mesh.uv = uv; } } internal class SmelterCapacity : MonoBehaviour { private static readonly List All = new List(); private Smelter _smelter; private int _baseOre; private int _baseFuel; private bool Fuelled => _baseFuel > 0; public Vector3 ConnectionPoint { get { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) Collider componentInChildren = ((Component)this).GetComponentInChildren(); if ((Object)(object)componentInChildren != (Object)null) { Bounds bounds = componentInChildren.bounds; return ((Bounds)(ref bounds)).center; } return ((Component)this).transform.position + Vector3.up; } } private void Awake() { _smelter = ((Component)this).GetComponent(); if ((Object)(object)_smelter == (Object)null) { ((Behaviour)this).enabled = false; return; } _baseOre = _smelter.m_maxOre; _baseFuel = _smelter.m_maxFuel; All.Add(this); ((MonoBehaviour)this).InvokeRepeating("Recompute", 1f, 3f); } private void OnDestroy() { All.Remove(this); } private bool Serves(UpgradeDef def) { if (def == null || def.Stations == null) { return false; } string prefabName = Utils.GetPrefabName(((Component)this).gameObject); string[] array = (def.Stations.Value ?? "").Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { if (string.Equals(array[i].Trim(), prefabName, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } private void Recompute() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_smelter == (Object)null)) { UpgradeDef upgradeDef = UpgradePrefabs.For(Fuelled); int num = ((KyndaConfig.Enabled.Value && Serves(upgradeDef)) ? Mathf.Min(UpgradeBin.CountNear(((Component)this).transform.position, Fuelled), Mathf.Max(0, KyndaConfig.MaxPerStation.Value)) : 0); int num2 = num * Mathf.Max(0, upgradeDef.OreCapacity.Value); int num3 = ((upgradeDef.FuelCapacity != null) ? (num * Mathf.Max(0, upgradeDef.FuelCapacity.Value)) : 0); if (_baseOre > 0) { _smelter.m_maxOre = _baseOre + num2; } if (_baseFuel > 0) { _smelter.m_maxFuel = _baseFuel + num3; } } } public static SmelterCapacity Nearest(Vector3 point, bool fuelled) { //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) float value = KyndaConfig.Range.Value; SmelterCapacity result = null; float num = float.MaxValue; foreach (SmelterCapacity item in All) { if (!((Object)(object)item == (Object)null) && !((Object)(object)item._smelter == (Object)null) && item.Fuelled == fuelled && item.Serves(UpgradePrefabs.For(fuelled))) { float num2 = Vector3.Distance(((Component)item).transform.position, point); if (!(num2 > value) && !(num2 >= num)) { result = item; num = num2; } } } return result; } public static string NearestUsing(Vector3 point, bool fuelled) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) SmelterCapacity smelterCapacity = Nearest(point, fuelled); if ((Object)(object)smelterCapacity == (Object)null) { return null; } Smelter smelter = smelterCapacity._smelter; List list = new List(); if (smelter.m_maxOre > 0) { list.Add("ore " + smelter.m_maxOre); } if (smelter.m_maxFuel > 0) { list.Add("fuel " + smelter.m_maxFuel); } return smelter.m_name + " (" + string.Join(", ", list.ToArray()) + ")"; } public static int AttachToPrefabs() { ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null) { return 0; } int num = 0; foreach (GameObject prefab in instance.m_prefabs) { if (!((Object)(object)prefab == (Object)null) && !((Object)(object)prefab.GetComponent() == (Object)null) && !((Object)(object)prefab.GetComponent() != (Object)null)) { prefab.AddComponent(); num++; } } return num; } } internal static class SoftAssets { private static Dictionary _paths; private static bool _pathsFailed; private static readonly Dictionary _loaded = new Dictionary(StringComparer.OrdinalIgnoreCase); public static void MakeEverythingLoadable() { try { Runtime.MakeAllAssetsLoadable(); } catch (Exception ex) { KyndaPlugin.Log.LogWarning((object)("Could not enable the extended asset manifest: " + ex.Message + ". Location-only materials will fall back to summoning their carrier.")); } } public unsafe static Material LoadMaterial(string name) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) if (string.IsNullOrEmpty(name)) { return null; } if (_loaded.TryGetValue(name, out var value) && (Object)(object)value != (Object)null) { return value; } try { if (!TryFindId(name, ".mat", out var id)) { return null; } SoftReference val = default(SoftReference); val..ctor(id); LoadResult val2 = val.Load(); if ((int)val2 != 0) { KyndaPlugin.Log.LogWarning((object)("The asset '" + name + "' is listed but would not load (" + ((object)(*(LoadResult*)(&val2))/*cast due to .constrained prefix*/).ToString() + ").")); return null; } Material asset = val.Asset; if ((Object)(object)asset == (Object)null) { return null; } _loaded[name] = asset; KyndaPlugin.Log.LogInfo((object)("Loaded the material '" + name + "' straight from its bundle, no location needed.")); return asset; } catch (Exception ex) { KyndaPlugin.Log.LogWarning((object)("Could not load '" + name + "' through the asset loader: " + ex.Message)); return null; } } private static bool TryFindId(string name, string extension, out AssetID id) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) id = default(AssetID); if (_paths == null && !_pathsFailed) { try { _paths = Runtime.GetAllAssetPathsInBundleMappedToAssetID(); KyndaPlugin.Log.LogInfo((object)("Asset manifest: " + _paths.Count + " assets addressable by name.")); } catch (Exception ex) { _pathsFailed = true; KyndaPlugin.Log.LogWarning((object)("Could not read the asset manifest: " + ex.Message)); } } if (_paths == null) { return false; } string value = "/" + name + extension; foreach (KeyValuePair path in _paths) { if (path.Key != null && path.Key.EndsWith(value, StringComparison.OrdinalIgnoreCase)) { AssetID value2 = path.Value; if (((AssetID)(ref value2)).IsValid) { id = path.Value; return true; } } } return false; } } internal static class UpgradeModel { public static bool Apply(GameObject prefab, string modelFile, IDictionary skins) { //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) string directoryName = Path.GetDirectoryName(typeof(UpgradeModel).Assembly.Location); if (string.IsNullOrWhiteSpace(modelFile)) { return false; } ModelData modelData = ObjMesh.Load(Path.Combine(directoryName, modelFile)); if (modelData == null || (Object)(object)modelData.Mesh == (Object)null) { KyndaPlugin.Log.LogWarning((object)("No " + modelFile + " beside the dll - falling back to the donor's look.")); return false; } MeshRenderer[] componentsInChildren = prefab.GetComponentsInChildren(true); foreach (MeshRenderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null)) { Object.DestroyImmediate((Object)(object)((Component)val).gameObject); } } GameObject val2 = new GameObject("upgrade_visual"); val2.transform.SetParent(prefab.transform, false); val2.AddComponent().sharedMesh = modelData.Mesh; MeshRenderer obj = val2.AddComponent(); ((Renderer)obj).sharedMaterials = Skins.SkinAndWatch(obj, modelData.Mesh, modelData.Groups, skins); Skins.Remap(modelData.Mesh, modelData.Groups, skins); ReplaceColliders(prefab, Path.Combine(directoryName, Path.GetFileNameWithoutExtension(modelFile) + ".col")); KyndaPlugin.Log.LogInfo((object)string.Format("{0}: {1} verts, {2} tris, groups [{3}].", modelFile, modelData.Mesh.vertexCount, modelData.Mesh.triangles.Length / 3, string.Join(", ", modelData.Groups))); return true; } private static void ReplaceColliders(GameObject prefab, string path) { //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_0129: Expected O, but got Unknown //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) if (!File.Exists(path)) { KyndaPlugin.Log.LogWarning((object)("No " + Path.GetFileName(path) + " beside the dll - keeping the donor's collision.")); return; } List list = new List(); string[] array = File.ReadAllLines(path); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length != 0 && !text.StartsWith("#")) { string[] array2 = text.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array2.Length >= 7 && array2[0] == "box") { list.Add(array2); } } } if (list.Count == 0) { return; } Collider[] componentsInChildren = prefab.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } CultureInfo invariantCulture = CultureInfo.InvariantCulture; GameObject val = new GameObject("upgrade_collision"); val.transform.SetParent(prefab.transform, false); int num = 0; foreach (string[] item in list) { GameObject val2 = new GameObject("box_" + num++); val2.transform.SetParent(val.transform, false); val2.transform.localPosition = new Vector3(float.Parse(item[1], invariantCulture), float.Parse(item[2], invariantCulture), float.Parse(item[3], invariantCulture)); if (item.Length >= 11) { val2.transform.localRotation = new Quaternion(float.Parse(item[7], invariantCulture), float.Parse(item[8], invariantCulture), float.Parse(item[9], invariantCulture), float.Parse(item[10], invariantCulture)); } val2.AddComponent().size = new Vector3(float.Parse(item[4], invariantCulture), float.Parse(item[5], invariantCulture), float.Parse(item[6], invariantCulture)); } KyndaPlugin.Log.LogInfo((object)(Path.GetFileName(path) + ": " + list.Count + " collision boxes.")); } } internal sealed class UpgradeDef { public string PrefabName; public ConfigEntry Name; public ConfigEntry Cost; public ConfigEntry Model; public ConfigEntry Scale; public string LiteralName; public string LiteralModel; public string LiteralSkinDonors; public bool IsTrial; public ConfigEntry SkinDonors; public float LiteralScale; public ConfigEntry OreCapacity; public ConfigEntry FuelCapacity; public string Description; public bool ServesFuelled; public ConfigEntry Stations; public GameObject Prefab; public bool IconLive; public IDictionary Skins { get { string text = ((SkinDonors != null) ? SkinDonors.Value : LiteralSkinDonors); if (string.IsNullOrEmpty(text)) { return null; } Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); string[] array = text.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { '=' }); if (array2.Length == 1) { string text2 = array2[0].Trim(); if (text2.Length > 0) { dictionary["*"] = text2; } } else if (array2.Length == 2) { string text3 = array2[0].Trim(); string text4 = array2[1].Trim(); if (text3.Length > 0 && text4.Length > 0) { dictionary[text3] = text4; } } } if (dictionary.Count <= 0) { return null; } return dictionary; } } public string NameValue { get { if (Name == null) { return LiteralName; } return Name.Value; } } public string ModelValue { get { if (Model == null) { return LiteralModel; } return Model.Value; } } public float ScaleValue { get { if (Scale != null) { return Scale.Value; } if (!(LiteralScale > 0f)) { return 1f; } return LiteralScale; } } } internal class UpgradeBin : MonoBehaviour, Hoverable { private static readonly List All = new List(); public bool m_servesFuelled; private Piece _piece; private GameObject _connection; private bool _placed; private static int _pokesDescribed; private static GameObject _connectionPrefab; private static bool _connectionSearched; private void Awake() { _piece = ((Component)this).GetComponent(); ZNetView component = ((Component)this).GetComponent(); _placed = (Object)(object)component != (Object)null && component.GetZDO() != null; if (_placed) { All.Add(this); } } private void OnDestroy() { StopConnectionEffect(); if (_placed) { All.Remove(this); } } private void PokeEffect(float timeout = 1f) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0095: 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_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011a: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) if (!_placed || !KyndaConfig.ShowLink.Value) { return; } SmelterCapacity smelterCapacity = SmelterCapacity.Nearest(((Component)this).transform.position, m_servesFuelled); if ((Object)(object)smelterCapacity == (Object)null) { return; } Vector3 val = ((Component)this).transform.position + Vector3.up * KyndaConfig.LinkHeight.Value; Vector3 connectionPoint = smelterCapacity.ConnectionPoint; if ((Object)(object)_connection == (Object)null) { GameObject val2 = ConnectionPrefab(); if ((Object)(object)val2 == (Object)null) { return; } _connection = Object.Instantiate(val2, val, Quaternion.identity); } Vector3 span = connectionPoint - val; if (!(((Vector3)(ref span)).sqrMagnitude < 0.0001f)) { if (!_connection.activeSelf) { _connection.SetActive(true); } _connection.transform.position = val; _connection.transform.rotation = Quaternion.LookRotation(((Vector3)(ref span)).normalized); _connection.transform.localScale = new Vector3(1f, 1f, ((Vector3)(ref span)).magnitude); Describe(val, connectionPoint, span); ((MonoBehaviour)this).CancelInvoke("StopConnectionEffect"); ((MonoBehaviour)this).Invoke("StopConnectionEffect", timeout); } } private void Describe(Vector3 from, Vector3 to, Vector3 span) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) if (_pokesDescribed < 3 && !((Object)(object)_connection == (Object)null)) { _pokesDescribed++; KyndaPlugin.Log.LogInfo((object)$"Link poke {_pokesDescribed}: {from} -> {to}, {((Vector3)(ref span)).magnitude:0.00}m, active {_connection.activeSelf}/{_connection.activeInHierarchy}, {_connection.GetComponentsInChildren(true).Length} particle system(s), {_connection.GetComponentsInChildren(true).Length} renderer(s)."); } } private void StopConnectionEffect() { if (!((Object)(object)_connection == (Object)null)) { Object.Destroy((Object)(object)_connection); _connection = null; } } private static GameObject ConnectionPrefab() { if (_connectionSearched) { return _connectionPrefab; } _connectionSearched = true; ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null) { return null; } foreach (GameObject prefab in instance.m_prefabs) { if (!((Object)(object)prefab == (Object)null)) { StationExtension component = prefab.GetComponent(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component.m_connectionPrefab == (Object)null)) { _connectionPrefab = component.m_connectionPrefab; KyndaPlugin.Log.LogInfo((object)("Link effect borrowed from " + ((Object)prefab).name + " (" + ((Object)_connectionPrefab).name + ").")); return _connectionPrefab; } } } KyndaPlugin.Log.LogWarning((object)"No StationExtension with a connection effect is loaded - upgrades will not draw a link to their station."); return null; } public static void ForgetConnectionPrefab() { _connectionPrefab = null; _connectionSearched = false; } public static int CountNear(Vector3 point, bool fuelled) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) float value = KyndaConfig.Range.Value; int num = 0; foreach (UpgradeBin item in All) { if (!((Object)(object)item == (Object)null) && item.m_servesFuelled == fuelled && Vector3.Distance(((Component)item).transform.position, point) <= value) { num++; } } return num; } private int CloserToStation(Vector3 station) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) float num = Vector3.Distance(((Component)this).transform.position, station); float value = KyndaConfig.Range.Value; int num2 = 0; foreach (UpgradeBin item in All) { if (!((Object)(object)item == (Object)null) && !((Object)(object)item == (Object)(object)this) && item.m_servesFuelled == m_servesFuelled) { float num3 = Vector3.Distance(((Component)item).transform.position, station); if (!(num3 > value) && (num3 < num || (num3 == num && ((Object)item).GetInstanceID() < ((Object)this).GetInstanceID()))) { num2++; } } } return num2; } public string GetHoverName() { if (!((Object)(object)_piece != (Object)null)) { return ""; } return _piece.m_name; } public string GetHoverText() { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) PokeEffect(); string hoverName = GetHoverName(); SmelterCapacity smelterCapacity = SmelterCapacity.Nearest(((Component)this).transform.position, m_servesFuelled); if ((Object)(object)smelterCapacity == (Object)null) { return Localization.instance.Localize(hoverName + "\nnot beside anything it can feed"); } if (CloserToStation(((Component)smelterCapacity).transform.position) >= Mathf.Max(1, KyndaConfig.MaxPerStation.Value)) { return Localization.instance.Localize(hoverName + "\nalready upgraded - this one adds nothing"); } return Localization.instance.Localize(hoverName); } } internal static class UpgradePrefabs { public static readonly UpgradeDef Trough = new UpgradeDef { PrefabName = "kynda_tun", Description = "Smelter improvement. A cask of ore and a cask of coal. A smelter beside it holds more of both.", ServesFuelled = true }; public static readonly UpgradeDef Woodrack = new UpgradeDef { PrefabName = "kynda_woodrack", Description = "Kiln improvement. Split logs, stacked and under cover. A charcoal kiln beside it holds more wood.", ServesFuelled = false }; public static readonly UpgradeDef[] All = new UpgradeDef[2] { Trough, Woodrack }; private static List _variants; private static List _trials; private static GameObject _holder; public static bool Ready { get { if ((Object)(object)ZNetScene.instance == (Object)null) { return false; } foreach (UpgradeDef item in Active()) { if ((Object)(object)ZNetScene.instance.GetPrefab(item.PrefabName) == (Object)null) { return false; } } return true; } } public static UpgradeDef For(bool fuelled) { if (!fuelled) { return Woodrack; } return Trough; } private static List Variants() { if (_variants != null) { return _variants; } _variants = new List(); if (!KyndaConfig.VariantMode.Value) { return _variants; } string[] files = Directory.GetFiles(Path.GetDirectoryName(typeof(UpgradePrefabs).Assembly.Location), "kynda_*.obj"); for (int i = 0; i < files.Length; i++) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(files[i]); string text = fileNameWithoutExtension.ToLowerInvariant(); bool flag = text.Contains("trough") || text.Contains("tun"); if (flag || text.Contains("rack")) { _variants.Add(new UpgradeDef { PrefabName = "kynda_var_" + fileNameWithoutExtension, LiteralName = Pretty(fileNameWithoutExtension), LiteralModel = fileNameWithoutExtension + ".obj", Description = "Comparison variant. Not a real piece - turn VariantMode off and it stops existing.", ServesFuelled = flag, Stations = (flag ? Trough : Woodrack).Stations, LiteralSkinDonors = (flag ? Trough : Woodrack).SkinDonors.Value, OreCapacity = (flag ? Trough.OreCapacity : Woodrack.OreCapacity), FuelCapacity = (flag ? Trough.FuelCapacity : null), LiteralScale = (flag ? Trough : Woodrack).ScaleValue, IsTrial = true }); } } if (_variants.Count > 0) { KyndaPlugin.Log.LogWarning((object)("VARIANT MODE: " + _variants.Count + " comparison piece(s) on the hammer at one wood each. Anything built from them is destroyed when VariantMode goes off.")); } return _variants; } private static string Merge(UpgradeDef host, string donor) { List list = new List(); if (host.SkinDonors != null && !string.IsNullOrEmpty(host.SkinDonors.Value)) { list.AddRange(host.SkinDonors.Value.Split(new char[1] { ',' })); } string[] array = donor.Split(new char[1] { '+' }); foreach (string obj in array) { string text = obj.Trim(); if (text.Length == 0) { continue; } int num = text.IndexOf('='); string group = ((num > 0) ? text.Substring(0, num).Trim() : null); list.RemoveAll(delegate(string existing) { string text2 = existing.Trim(); int num2 = text2.IndexOf('='); if (group == null) { return num2 <= 0; } return num2 > 0 && text2.Substring(0, num2).Trim().Equals(group, StringComparison.OrdinalIgnoreCase); }); list.Add(text); } return string.Join(",", list.ToArray()); } private static string Pretty(string stem) { return "var: " + stem.Replace("kynda_", "").Replace("_", " "); } private static List SkinTrials() { if (_trials != null) { return _trials; } _trials = new List(); string value = KyndaConfig.SkinTrials.Value; if (string.IsNullOrEmpty(value)) { return _trials; } string[] array = value.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length == 0) { continue; } bool flag = true; bool flag2 = true; string text2 = text; int num = text.IndexOf(':'); if (num > 0) { string text3 = text.Substring(0, num).Trim(); text2 = text.Substring(num + 1).Trim(); flag = text3.Equals("tun", StringComparison.OrdinalIgnoreCase) || text3.Equals("trough", StringComparison.OrdinalIgnoreCase); flag2 = text3.Equals("rack", StringComparison.OrdinalIgnoreCase); if (!flag && !flag2) { KyndaPlugin.Log.LogWarning((object)("SkinTrials: '" + text3 + "' is not a piece. Use rack: or tun:, or leave the prefix off for both.")); continue; } } if (text2.Length == 0) { continue; } UpgradeDef[] all = All; foreach (UpgradeDef upgradeDef in all) { if (!(upgradeDef.ServesFuelled ? (!flag) : (!flag2))) { _trials.Add(new UpgradeDef { PrefabName = "kynda_skin_" + upgradeDef.PrefabName + "_" + text2, LiteralName = "skin: " + upgradeDef.NameValue.ToLowerInvariant() + " " + text2, LiteralModel = upgradeDef.ModelValue, LiteralSkinDonors = Merge(upgradeDef, text2), Description = "Skin trial on " + text2 + ". Not a real piece - clear SkinTrials and it stops existing.", ServesFuelled = upgradeDef.ServesFuelled, Stations = upgradeDef.Stations, OreCapacity = upgradeDef.OreCapacity, FuelCapacity = upgradeDef.FuelCapacity, LiteralScale = upgradeDef.ScaleValue, IsTrial = true }); } } } if (_trials.Count > 0) { KyndaPlugin.Log.LogWarning((object)("SKIN TRIALS: " + _trials.Count + " piece(s) on the hammer at one wood each, named 'skin: ...'. Anything built from them is destroyed when SkinTrials is cleared.")); } return _trials; } private static IEnumerable Active() { UpgradeDef[] all = All; for (int i = 0; i < all.Length; i++) { yield return all[i]; } foreach (UpgradeDef item in Variants()) { yield return item; } foreach (UpgradeDef item2 in SkinTrials()) { yield return item2; } } public static bool Register() { if (!KyndaConfig.Enabled.Value) { return true; } if ((Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return false; } if (Ready && InHammer()) { return true; } foreach (UpgradeDef item in Active()) { if ((Object)(object)item.Prefab == (Object)null) { item.Prefab = Build(item); } if ((Object)(object)item.Prefab == (Object)null) { return false; } } AddToScene(); AddToHammer(); return Ready; } private static GameObject Donor() { ZNetScene instance = ZNetScene.instance; string[] array = new string[2] { KyndaConfig.Donor.Value, "piece_chest_wood" }; foreach (string text in array) { if (!string.IsNullOrEmpty(text)) { GameObject prefab = instance.GetPrefab(text); if ((Object)(object)prefab != (Object)null) { return prefab; } KyndaPlugin.Log.LogWarning((object)("Upgrade donor '" + text + "' does not exist.")); } } return null; } private static GameObject Build(UpgradeDef def) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) GameObject val = Donor(); if ((Object)(object)val == (Object)null) { return null; } if ((Object)(object)_holder == (Object)null) { _holder = new GameObject("KyndaUpgradeHolder"); _holder.SetActive(false); Object.DontDestroyOnLoad((Object)(object)_holder); } bool forceDisableInit = ZNetView.m_forceDisableInit; ZNetView.m_forceDisableInit = true; GameObject val2; try { val2 = Object.Instantiate(val, _holder.transform); } finally { ZNetView.m_forceDisableInit = forceDisableInit; } ((Object)val2).name = def.PrefabName; Container[] componentsInChildren = val2.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { Object.DestroyImmediate((Object)(object)componentsInChildren[i]); } ParticleSystem[] componentsInChildren2 = val2.GetComponentsInChildren(true); foreach (ParticleSystem val3 in componentsInChildren2) { if (!((Object)(object)val3 == (Object)null)) { KyndaPlugin.Log.LogInfo((object)("Stripped inherited particle system '" + ((Object)val3).name + "' from " + def.PrefabName + ".")); Object.DestroyImmediate((Object)(object)val3); } } Piece component = val2.GetComponent(); if ((Object)(object)component != (Object)null) { component.m_name = def.NameValue; component.m_description = def.Description; component.m_resources = Requirements(KyndaConfig.CostNow(def)); component.m_category = (PieceCategory)(!def.IsTrial); component.m_isUpgrade = true; CraftingStation val4 = StationNamed(KyndaConfig.Station.Value); if ((Object)(object)val4 != (Object)null) { component.m_craftingStation = val4; } } UpgradeModel.Apply(val2, def.ModelValue, def.Skins); float num = Mathf.Max(0.05f, def.ScaleValue); val2.transform.localScale = new Vector3(num, num, num); (val2.GetComponent() ?? val2.AddComponent()).m_servesFuelled = def.ServesFuelled; if ((Object)(object)component != (Object)null) { Sprite val5 = LoadIcon(def) ?? IconRender.Shoot(val2, def.PrefabName); if ((Object)(object)val5 != (Object)null) { component.m_icon = val5; } } KyndaPlugin.Log.LogInfo((object)("Built " + def.PrefabName + " from " + ((Object)val).name + ".")); return val2; } private static CraftingStation StationNamed(string name) { if (string.IsNullOrEmpty(name)) { return null; } GameObject val = PropIndex.Find(name); if ((Object)(object)val == (Object)null) { KyndaPlugin.Log.LogWarning((object)("No prefab called '" + name + "' for the crafting station requirement - the upgrades keep the donor's, which is the workbench.")); return null; } CraftingStation obj = val.GetComponent() ?? val.GetComponentInChildren(true); if ((Object)(object)obj == (Object)null) { KyndaPlugin.Log.LogWarning((object)("'" + name + "' exists but is not a crafting station - the upgrades keep the donor's.")); } return obj; } private static Sprite LoadIcon(UpgradeDef def) { //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Expected O, but got Unknown //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0148: Unknown result type (might be due to invalid IL or missing references) string directoryName = Path.GetDirectoryName(typeof(UpgradePrefabs).Assembly.Location); string modelValue = def.ModelValue; if (string.IsNullOrEmpty(modelValue)) { return null; } string text = Path.Combine(directoryName, Path.GetFileNameWithoutExtension(modelValue) + "_icon.png"); if (!File.Exists(text)) { KyndaPlugin.Log.LogWarning((object)("No icon beside the dll for " + def.PrefabName + " - it will wear the donor's, which is a picture of something else. Expected " + Path.GetFileName(text) + ".")); return null; } try { Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false) { filterMode = (FilterMode)1, wrapMode = (TextureWrapMode)1 }; if (!LoadPng(val, File.ReadAllBytes(text))) { return null; } ((Object)val).name = def.PrefabName + "_icon"; ((Object)val).hideFlags = (HideFlags)61; KyndaPlugin.Log.LogInfo((object)$"Icon for {def.PrefabName}: {Path.GetFileName(text)} ({((Texture)val).width}x{((Texture)val).height})."); return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f)); } catch (Exception ex) { KyndaPlugin.Log.LogError((object)("Could not read " + text + ": " + ex.Message)); return null; } } private static bool LoadPng(Texture2D texture, byte[] data) { Type type = AccessTools.TypeByName("UnityEngine.ImageConversion"); if (type == null) { KyndaPlugin.Log.LogWarning((object)"UnityEngine.ImageConversion is missing - cannot read icons."); return false; } MethodInfo methodInfo = AccessTools.Method(type, "LoadImage", new Type[2] { typeof(Texture2D), typeof(byte[]) }, (Type[])null) ?? AccessTools.Method(type, "LoadImage", new Type[3] { typeof(Texture2D), typeof(byte[]), typeof(bool) }, (Type[])null); if (methodInfo == null) { KyndaPlugin.Log.LogWarning((object)"No LoadImage overload found on UnityEngine.ImageConversion."); return false; } object[] parameters = ((methodInfo.GetParameters().Length != 3) ? new object[2] { texture, data } : new object[3] { texture, data, false }); return (bool)methodInfo.Invoke(null, parameters); } private static Requirement[] Requirements(string spec) { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Expected O, but got Unknown List list = new List(); string[] array = (spec ?? "").Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(new char[1] { ':' }); if (array2.Length != 2) { continue; } string text = array2[0].Trim(); if (text.Length != 0 && int.TryParse(array2[1].Trim(), out var result) && result > 0) { GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(text); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent() : null); if ((Object)(object)val == (Object)null) { KyndaPlugin.Log.LogWarning((object)("Cost mentions unknown item '" + text + "'.")); continue; } list.Add(new Requirement { m_resItem = val, m_amount = result, m_recover = true }); } } return list.ToArray(); } private static void AddToScene() { ZNetScene instance = ZNetScene.instance; foreach (UpgradeDef item in Active()) { if (!((Object)(object)item.Prefab == (Object)null) && !((Object)(object)instance.GetPrefab(item.PrefabName) != (Object)null)) { if (!instance.m_prefabs.Contains(item.Prefab)) { instance.m_prefabs.Add(item.Prefab); } try { ((Dictionary)AccessTools.Field(typeof(ZNetScene), "m_namedPrefabs").GetValue(instance))[StringExtensionMethods.GetStableHashCode(item.PrefabName)] = item.Prefab; } catch (Exception ex) { KyndaPlugin.Log.LogError((object)("Could not register " + item.PrefabName + ": " + ex.Message)); } } } } private static bool InHammer() { PieceTable val = HammerPieces(); if ((Object)(object)val == (Object)null) { return false; } foreach (UpgradeDef item in Active()) { if ((Object)(object)item.Prefab == (Object)null) { return false; } if (!val.m_pieces.Contains(item.Prefab)) { return false; } } return true; } private static PieceTable HammerPieces() { if ((Object)(object)ObjectDB.instance == (Object)null) { return null; } GameObject itemPrefab = ObjectDB.instance.GetItemPrefab("Hammer"); ItemDrop val = (((Object)(object)itemPrefab != (Object)null) ? itemPrefab.GetComponent() : null); if ((Object)(object)val == (Object)null || val.m_itemData == null || val.m_itemData.m_shared == null) { return null; } PieceTable buildPieces = val.m_itemData.m_shared.m_buildPieces; if (!((Object)(object)buildPieces != (Object)null) || buildPieces.m_pieces == null) { return null; } return buildPieces; } public static void RefreshIcons() { foreach (UpgradeDef item in Active()) { if ((Object)(object)item.Prefab == (Object)null || item.IconLive) { continue; } Piece component = item.Prefab.GetComponent(); if ((Object)(object)component == (Object)null) { item.IconLive = true; continue; } MeshRenderer componentInChildren = item.Prefab.GetComponentInChildren(true); if ((Object)(object)componentInChildren == (Object)null) { item.IconLive = true; continue; } bool flag = true; Material[] sharedMaterials = ((Renderer)componentInChildren).sharedMaterials; for (int i = 0; i < sharedMaterials.Length; i++) { if ((Object)(object)sharedMaterials[i] == (Object)null) { flag = false; } } if (flag) { Sprite val = IconRender.Shoot(item.Prefab, item.PrefabName); item.IconLive = true; if (!((Object)(object)val == (Object)null)) { component.m_icon = val; KyndaPlugin.Log.LogInfo((object)("Re-shot " + item.PrefabName + "'s icon from the skinned piece.")); } } } } private static void AddToHammer() { PieceTable val = HammerPieces(); if ((Object)(object)val == (Object)null) { return; } int num = 0; foreach (UpgradeDef item in Active()) { if ((Object)(object)item.Prefab == (Object)null) { return; } if (val.m_pieces.Contains(item.Prefab)) { continue; } int num2 = -1; if (item.Stations != null && !string.IsNullOrEmpty(item.Stations.Value)) { string b = item.Stations.Value.Split(new char[1] { ',' })[0].Trim(); for (int i = 0; i < val.m_pieces.Count; i++) { GameObject val2 = val.m_pieces[i]; if (!((Object)(object)val2 == (Object)null) && string.Equals(((Object)val2).name, b, StringComparison.OrdinalIgnoreCase)) { num2 = i + 1; break; } } } if (num2 >= 0) { val.m_pieces.Insert(num2, item.Prefab); } else { val.m_pieces.Add(item.Prefab); } num++; } if (num > 0) { KyndaPlugin.Log.LogInfo((object)(num + " upgrade(s) added to the hammer, each beside its station.")); } } } }