Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Glorpheim v1.5.0
glorpheim.dll
Decompiled a month ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Glorpheim.Configuration; using Glorpheim.Features; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using ServerSync; using Splatform; using TMPro; using UnityEngine; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("glorpheim")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.5.0.0")] [assembly: AssemblyInformationalVersion("1.5.0+bf56bd51b2b8b50029c220db45a3e0aa04d0413e")] [assembly: AssemblyProduct("glorpheim")] [assembly: AssemblyTitle("glorpheim")] [assembly: AssemblyVersion("1.5.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 Glorpheim { [BepInPlugin("com.rafael.glorpheim", "glorpheim", "1.5.0")] public sealed class GlorpheimPlugin : BaseUnityPlugin { public const string PluginGuid = "com.rafael.glorpheim"; public const string PluginName = "glorpheim"; public const string PluginVersion = "1.5.0"; private Harmony _harmony; internal static GlorpheimPlugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } internal static ModConfig Cfg { get; private set; } private void Awake() { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; ConfigSync configSync = new ConfigSync("com.rafael.glorpheim") { DisplayName = "glorpheim", CurrentVersion = "1.5.0", MinimumRequiredVersion = "1.5.0", ModRequired = false }; Cfg = new ModConfig(((BaseUnityPlugin)this).Config, configSync); _harmony = new Harmony("com.rafael.glorpheim"); _harmony.PatchAll(Assembly.GetExecutingAssembly()); InstantRested.Init(); FloatingDrops.Init(); BiggerStacks.Init(); Log.LogInfo((object)"glorpheim 1.5.0 loaded"); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } } namespace Glorpheim.Features { [HarmonyPatch] internal static class AutoRepair { private static readonly Func<InventoryGui, bool> HaveRepairableItems = AccessTools.MethodDelegate<Func<InventoryGui, bool>>(AccessTools.Method(typeof(InventoryGui), "HaveRepairableItems", (Type[])null, (Type[])null), (object)null, true); private static readonly Action<InventoryGui> RepairOneItem = AccessTools.MethodDelegate<Action<InventoryGui>>(AccessTools.Method(typeof(InventoryGui), "RepairOneItem", (Type[])null, (Type[])null), (object)null, true); private static Coroutine _running; [HarmonyPatch(typeof(CraftingStation), "Interact")] [HarmonyPostfix] private static void CraftingStation_Interact_Postfix(CraftingStation __instance, Humanoid user, bool repeat) { if (repeat || !GlorpheimPlugin.Cfg.AutoRepairEnabled.Value || !__instance.m_canRepair) { return; } Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !((Object)(object)user != (Object)(object)localPlayer) && !((Object)(object)localPlayer.GetCurrentCraftingStation() != (Object)(object)__instance)) { if (_running != null) { ((MonoBehaviour)GlorpheimPlugin.Instance).StopCoroutine(_running); } _running = ((MonoBehaviour)GlorpheimPlugin.Instance).StartCoroutine(RepairAll(__instance)); } } private static IEnumerator RepairAll(CraftingStation station) { int repaired = 0; while (repaired < 100) { InventoryGui instance = InventoryGui.instance; Player localPlayer = Player.m_localPlayer; if ((Object)(object)instance == (Object)null || (Object)(object)localPlayer == (Object)null || !InventoryGui.IsVisible() || (Object)(object)localPlayer.GetCurrentCraftingStation() != (Object)(object)station || !HaveRepairableItems(instance)) { break; } RepairOneItem(instance); repaired++; float value = GlorpheimPlugin.Cfg.AutoRepairDelay.Value; if (value > 0f) { yield return (object)new WaitForSeconds(value); } } if (repaired > 1 && (Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message((MessageType)2, $"Repaired {repaired} items", 0, (Sprite)null, false); } _running = null; } } [HarmonyPatch] internal static class BiggerStacks { [HarmonyPatch] private static class KeepStacksOnLoad { private static MethodBase TargetMethod() { return typeof(Inventory).GetMethods(BindingFlags.Instance | BindingFlags.NonPublic).First(delegate(MethodInfo m) { ParameterInfo[] parameters = m.GetParameters(); return m.Name == "AddItem" && parameters.Length > 2 && parameters[0].ParameterType == typeof(int) && parameters[1].ParameterType == typeof(int); }); } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { foreach (CodeInstruction instruction in instructions) { if (instruction.opcode == OpCodes.Ldfld && object.Equals(instruction.operand, MaxStackSize)) { yield return CodeInstructionExtensions.MoveLabelsFrom(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(BiggerStacks), "LoadLimit", (Type[])null, (Type[])null)), instruction); } else { yield return instruction; } } } } private static readonly FieldInfo LoadedItems = AccessTools.Field(typeof(ItemDrop), "s_instances"); private static readonly FieldInfo MaxStackSize = AccessTools.Field(typeof(SharedData), "m_maxStackSize"); private static readonly Dictionary<string, int> VanillaStack = new Dictionary<string, int>(); private static string _parsedItemsSource; private static HashSet<string> _items = new HashSet<string>(); private static HashSet<string> FoodIngredients = new HashSet<string>(); internal static void Init() { GlorpheimPlugin.Cfg.BiggerStacksEnabled.SettingChanged += delegate { ApplyAll(); }; GlorpheimPlugin.Cfg.BiggerStacksMultiplier.SettingChanged += delegate { ApplyAll(); }; GlorpheimPlugin.Cfg.BiggerStacksIncludeFood.SettingChanged += delegate { ApplyAll(); }; GlorpheimPlugin.Cfg.BiggerStacksIncludeFoodIngredients.SettingChanged += delegate { ApplyAll(); }; GlorpheimPlugin.Cfg.BiggerStacksItems.SettingChanged += delegate { ApplyAll(); }; } [HarmonyPatch(typeof(ObjectDB), "Awake")] [HarmonyPostfix] [HarmonyPriority(0)] private static void ObjectDBAwakePostfix() { ApplyAll(); } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] [HarmonyPostfix] [HarmonyPriority(0)] private static void CopyOtherDBPostfix() { ApplyAll(); } [HarmonyPatch(typeof(ItemDrop), "Awake")] [HarmonyPostfix] private static void ItemDropAwakePostfix(ItemDrop __instance) { Apply(__instance.m_itemData); } private static int LoadLimit(SharedData shared) { if (shared.m_maxStackSize <= 1) { return shared.m_maxStackSize; } return int.MaxValue; } private static void ApplyAll() { ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null) { return; } FindFoodIngredients(instance); foreach (GameObject item in instance.m_items) { ItemDrop val = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null); if (!((Object)(object)val == (Object)null)) { if (!VanillaStack.ContainsKey(((Object)item).name)) { VanillaStack[((Object)item).name] = val.m_itemData.m_shared.m_maxStackSize; } Apply(val.m_itemData, ((Object)item).name); } } if (LoadedItems?.GetValue(null) is List<ItemDrop> list) { foreach (ItemDrop item2 in list) { if ((Object)(object)item2 != (Object)null) { Apply(item2.m_itemData); } } } Inventory val2 = (((Object)(object)Player.m_localPlayer != (Object)null) ? ((Humanoid)Player.m_localPlayer).GetInventory() : null); if (val2 == null) { return; } foreach (ItemData allItem in val2.GetAllItems()) { Apply(allItem); } } private static void Apply(ItemData item) { if ((Object)(object)item?.m_dropPrefab != (Object)null) { Apply(item, ((Object)item.m_dropPrefab).name); } } private static void Apply(ItemData item, string prefabName) { if (item?.m_shared != null && VanillaStack.TryGetValue(prefabName, out var value) && value > 1) { bool flag = GlorpheimPlugin.Cfg.BiggerStacksEnabled.Value && (IsListed(prefabName) || (GlorpheimPlugin.Cfg.BiggerStacksIncludeFood.Value && IsFood(item.m_shared)) || (GlorpheimPlugin.Cfg.BiggerStacksIncludeFoodIngredients.Value && FoodIngredients.Contains(prefabName))); item.m_shared.m_maxStackSize = (flag ? (value * GlorpheimPlugin.Cfg.BiggerStacksMultiplier.Value) : value); } } private static void FindFoodIngredients(ObjectDB db) { List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>(); foreach (Recipe recipe in db.m_recipes) { if ((Object)(object)recipe == (Object)null || !recipe.m_enabled || (Object)(object)recipe.m_item == (Object)null) { continue; } Requirement[] resources = recipe.m_resources; foreach (Requirement val in resources) { if ((Object)(object)val?.m_resItem != (Object)null) { list.Add(new KeyValuePair<string, string>(((Object)val.m_resItem).name, ((Object)recipe.m_item).name)); } } } HashSet<GameObject> hashSet = new HashSet<GameObject>(); foreach (GameObject item in db.m_items) { ItemDrop val2 = (((Object)(object)item != (Object)null) ? item.GetComponent<ItemDrop>() : null); PieceTable val3 = (((Object)(object)val2 != (Object)null) ? val2.m_itemData.m_shared.m_buildPieces : null); if ((Object)(object)val3 == (Object)null) { continue; } foreach (GameObject piece in val3.m_pieces) { if ((Object)(object)piece == (Object)null || !hashSet.Add(piece)) { continue; } CookingStation componentInChildren = piece.GetComponentInChildren<CookingStation>(); if ((Object)(object)componentInChildren != (Object)null) { list.AddRange(from c in componentInChildren.m_conversion where (Object)(object)c?.m_from != (Object)null && (Object)(object)c.m_to != (Object)null select new KeyValuePair<string, string>(((Object)c.m_from).name, ((Object)c.m_to).name)); } Smelter componentInChildren2 = piece.GetComponentInChildren<Smelter>(); if ((Object)(object)componentInChildren2 != (Object)null) { list.AddRange(from c in componentInChildren2.m_conversion where (Object)(object)c?.m_from != (Object)null && (Object)(object)c.m_to != (Object)null select new KeyValuePair<string, string>(((Object)c.m_from).name, ((Object)c.m_to).name)); } } } HashSet<string> hashSet2 = new HashSet<string>(from p in db.m_items select (!((Object)(object)p != (Object)null)) ? null : p.GetComponent<ItemDrop>() into d where (Object)(object)d != (Object)null && IsFood(d.m_itemData.m_shared) select ((Object)d).name); HashSet<string> hashSet3 = new HashSet<string>(); bool flag = true; while (flag) { flag = false; foreach (KeyValuePair<string, string> item2 in list) { if (hashSet2.Contains(item2.Value) && hashSet2.Add(item2.Key)) { hashSet3.Add(item2.Key); flag = true; } } } if (!hashSet3.SetEquals(FoodIngredients)) { FoodIngredients = hashSet3; GlorpheimPlugin.Log.LogInfo((object)string.Format("BiggerStacks food ingredients ({0}): {1}", hashSet3.Count, string.Join(", ", hashSet3.OrderBy((string n) => n)))); } } private static bool IsListed(string prefabName) { string value = GlorpheimPlugin.Cfg.BiggerStacksItems.Value; if (value != _parsedItemsSource) { _items = new HashSet<string>(from s in value.Split(new char[1] { ',' }) select s.Trim() into s where s.Length > 0 select s, StringComparer.OrdinalIgnoreCase); _parsedItemsSource = value; } return _items.Contains(prefabName); } private static bool IsFood(SharedData shared) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 if ((int)shared.m_itemType == 2) { if (!(shared.m_food > 0f) && !(shared.m_foodStamina > 0f)) { return shared.m_foodEitr > 0f; } return true; } return false; } } [HarmonyPatch] internal static class DeathMessages { private const string RpcName = "Glorpheim_DeathMessage"; private static readonly FieldRef<Character, HitData> LastHitRef = AccessTools.FieldRefAccess<Character, HitData>("m_lastHit"); private static readonly FieldRef<Chat, float> HideTimerRef = AccessTools.FieldRefAccess<Chat, float>("m_hideTimer"); private static readonly Random s_random = new Random(); private static readonly string[] SlainBy = new string[7] { "{0} was slain by {1}.", "{0} was murdered by {1}.", "{0} was cut down by {1}.", "{0} was mauled by {1}.", "{0} was removed from this world by {1}.", "{0} tried to run from {1}.", "{0}'s corpse run was sponsored by {1}." }; private static readonly string[] Fall = new string[4] { "{0} fell to their death.", "{0} didn't bounce.", "{0} invented gravity.", "{0} thought they could fly." }; private static readonly string[] Drowning = new string[3] { "{0} drowned.", "{0} forgot to breathe.", "{0} was swallowed by the sea." }; private static readonly string[] Burning = new string[2] { "{0} was burned to death.", "{0} went up in flames." }; private static readonly string[] Freezing = new string[2] { "{0} froze to death.", "{0} should have brought a cloak." }; private static readonly string[] PoisonedBy = new string[2] { "{0} was poisoned to death by {1}.", "{0} couldn't shake off {1}'s poison." }; private static readonly string[] Poisoned = new string[1] { "{0} was poisoned to death." }; private static readonly string[] Self = new string[2] { "{0} took the easy way out.", "{0} gave up." }; private static readonly string[] Unknown = new string[2] { "{0} died.", "{0} died mysteriously." }; [HarmonyPatch(typeof(Game), "Start")] [HarmonyPostfix] private static void Game_Start_Postfix() { if (ZRoutedRpc.instance != null) { ZRoutedRpc.instance.Register<string>("Glorpheim_DeathMessage", (Action<long, string>)RPC_DeathMessage); } } [HarmonyPatch(typeof(Player), "OnDeath")] [HarmonyPostfix] private static void Player_OnDeath_Postfix(Player __instance) { if (!GlorpheimPlugin.Cfg.DeathMessagesEnabled.Value || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || ZRoutedRpc.instance == null) { return; } try { string text = Describe(__instance, LastHitRef.Invoke((Character)(object)__instance)); ZRoutedRpc.instance.InvokeRoutedRPC(0L, "Glorpheim_DeathMessage", new object[1] { text }); } catch (Exception arg) { GlorpheimPlugin.Log.LogWarning((object)$"DeathMessages: could not announce death: {arg}"); } } private static void RPC_DeathMessage(long sender, string text) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) if (!GlorpheimPlugin.Cfg.DeathMessagesEnabled.Value || string.IsNullOrWhiteSpace(text)) { return; } text = Sanitize(text); if (text.Length > 300) { text = text.Substring(0, 300); } if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsDedicated()) { GlorpheimPlugin.Log.LogInfo((object)text); return; } Chat instance = Chat.instance; if (!((Object)(object)instance == (Object)null)) { string text2 = ColorUtility.ToHtmlStringRGBA(GlorpheimPlugin.Cfg.DeathMessagesColor.Value); ((Terminal)instance).AddString("<color=#" + text2 + ">" + text + "</color>"); HideTimerRef.Invoke(instance) = 0f; } } private static string Describe(Player victim, HitData hit) { //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Expected I4, but got Unknown string text = Sanitize(victim.GetPlayerName()); if (hit == null) { return Pick(Unknown, text); } Character attacker = hit.GetAttacker(); string text2 = (((Object)(object)attacker != (Object)null) ? KillerName(attacker) : null); HitType hitType = hit.m_hitType; switch (hitType - 1) { case 0: case 1: if (text2 == null) { return Pick(Unknown, text); } return Pick(SlainBy, text, text2); case 2: return Pick(Fall, text); case 3: return Pick(Drowning, text); case 4: if (text2 == null) { return Pick(Burning, text); } return Pick(SlainBy, text, text2); case 5: return Pick(Freezing, text); case 6: if (text2 == null) { return Pick(Poisoned, text); } return Pick(PoisonedBy, text, text2); case 7: return text + " was swept away by the water."; case 8: return text + " was suffocated by smoke."; case 9: return text + " fell off the edge of the world."; case 10: return text + " was crushed."; case 11: return text + " was run over by a cart."; case 12: return text + " was crushed by a falling tree."; case 13: return Pick(Self, text); case 14: return text + " was buried under a collapsing building."; case 15: return text + " was shot by a ballista."; case 16: return text + " was hit by a boat."; case 17: return text + " was impaled by a falling stalactite."; case 18: return text + " was flattened by a catapult."; case 19: return text + " was burned to ash by cinders."; case 20: return text + " was boiled alive."; case 21: return text + " tried to swim in lava."; case 22: return text + " was incinerated."; case 23: return text + " was crushed by a drawbridge."; default: if (text2 == null) { return Pick(Unknown, text); } return Pick(SlainBy, text, text2); } } private static string KillerName(Character attacker) { Player val = (Player)(object)((attacker is Player) ? attacker : null); if (val != null) { return Sanitize(val.GetPlayerName()); } string text = Sanitize(Localization.instance.Localize(attacker.m_name)); if (attacker.IsBoss()) { return text; } if (attacker.IsTamed()) { Tameable component = ((Component)attacker).GetComponent<Tameable>(); string text2 = (((Object)(object)component != (Object)null) ? Sanitize(component.GetText()).Trim() : ""); if (text2.Length <= 0) { return "a tamed " + text; } return text2 + " the " + text; } int num = attacker.GetLevel() - 1; if (num > 0) { return $"a {num}-star {text}"; } return Article(text) + " " + text; } private static string Article(string noun) { if (noun.Length <= 0 || "aeiouAEIOU".IndexOf(noun[0]) < 0) { return "a"; } return "an"; } private static string Pick(string[] templates, params object[] args) { return string.Format(templates[s_random.Next(templates.Length)], args); } private static string Sanitize(string text) { return (text ?? "").Replace('<', ' ').Replace('>', ' '); } } [HarmonyPatch(typeof(EnvMan), "SetTargetWind")] internal static class FairWinds { private const float WorldRadius = 10500f; [HarmonyPrefix] private static void Prefix(EnvMan __instance, ref Vector3 dir) { //IL_0038: 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_009f: 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_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: 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_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) if (!GlorpheimPlugin.Cfg.FairWindsEnabled.Value || __instance.m_debugWind) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).InInterior() || Utils.LengthXZ(((Component)localPlayer).transform.position) > 10500f - __instance.m_edgeOfWorldWidth) { return; } Ship localShip = Ship.GetLocalShip(); if ((Object)(object)localShip == (Object)null) { return; } Vector3 forward = ((Component)localShip).transform.forward; forward.y = 0f; if (!(((Vector3)(ref forward)).sqrMagnitude < 0.0001f)) { ((Vector3)(ref forward)).Normalize(); float value = GlorpheimPlugin.Cfg.FairWindsMaxWindAngle.Value; float num = Vector3.SignedAngle(forward, dir, Vector3.up); if (Mathf.Abs(num) > value) { dir = Quaternion.AngleAxis(Mathf.Sign(num) * value, Vector3.up) * forward; } } } } [HarmonyPatch(typeof(Plant), "GetGrowTime")] internal static class FasterCrops { [HarmonyPostfix] private static void Postfix(ref float __result) { if (GlorpheimPlugin.Cfg.FasterCropsEnabled.Value) { float value = GlorpheimPlugin.Cfg.FasterCropsSpeedMultiplier.Value; if (value > 0f) { __result /= value; } } } } [HarmonyPatch] internal static class FasterStations { private static readonly FieldInfo CookTimeField = AccessTools.Field(typeof(ItemConversion), "m_cookTime"); private static readonly MethodInfo OvercookFactorMethod = AccessTools.Method(typeof(FasterStations), "OvercookFactor", (Type[])null, (Type[])null); private static float s_cookingMultiplier; private static float Multiplier() { if (!GlorpheimPlugin.Cfg.FasterStationsEnabled.Value) { return 0f; } float value = GlorpheimPlugin.Cfg.FasterStationsSpeedMultiplier.Value; if (!(value > 0f)) { return 0f; } return value; } [HarmonyPatch(typeof(Smelter), "UpdateSmelter")] [HarmonyPrefix] private static void Smelter_Prefix(Smelter __instance, out float __state) { __state = __instance.m_secPerProduct; float num = Multiplier(); if (num > 0f) { __instance.m_secPerProduct = __state / num; } } [HarmonyPatch(typeof(Smelter), "UpdateSmelter")] [HarmonyPostfix] private static void Smelter_Postfix(Smelter __instance, float __state) { __instance.m_secPerProduct = __state; } private static float OvercookFactor() { if (!(s_cookingMultiplier > 0f)) { return 2f; } return 1f + s_cookingMultiplier; } [HarmonyPatch(typeof(CookingStation), "UpdateCooking")] [HarmonyPrefix] private static void CookingStation_Prefix(CookingStation __instance, out float __state) { s_cookingMultiplier = Multiplier(); __state = s_cookingMultiplier; if (__state <= 0f) { return; } foreach (ItemConversion item in __instance.m_conversion) { item.m_cookTime /= __state; } } [HarmonyPatch(typeof(CookingStation), "UpdateCooking")] [HarmonyPostfix] private static void CookingStation_Postfix(CookingStation __instance, float __state) { s_cookingMultiplier = 0f; if (__state <= 0f) { return; } foreach (ItemConversion item in __instance.m_conversion) { item.m_cookTime *= __state; } } [HarmonyPatch(typeof(CookingStation), "UpdateCooking")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> CookingStation_Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); bool flag = false; for (int i = 0; i + 2 < list.Count; i++) { if (CodeInstructionExtensions.LoadsField(list[i], CookTimeField, false) && list[i + 1].opcode == OpCodes.Ldc_R4 && list[i + 1].operand is float num && num == 2f && list[i + 2].opcode == OpCodes.Mul) { list[i + 1] = new CodeInstruction(OpCodes.Call, (object)OvercookFactorMethod); flag = true; break; } } if (!flag) { GlorpheimPlugin.Log.LogWarning((object)"FasterStations: overcook check not found in CookingStation.UpdateCooking; items will burn faster too."); } return list; } [HarmonyPatch(typeof(Fermenter), "GetStatus")] [HarmonyPrefix] private static void Fermenter_Prefix(Fermenter __instance, out float __state) { __state = __instance.m_fermentationDuration; float num = Multiplier(); if (num > 0f) { __instance.m_fermentationDuration = __state / num; } } [HarmonyPatch(typeof(Fermenter), "GetStatus")] [HarmonyPostfix] private static void Fermenter_Postfix(Fermenter __instance, float __state) { __instance.m_fermentationDuration = __state; } [HarmonyPatch(typeof(Beehive), "UpdateBees")] [HarmonyPrefix] private static void Beehive_Prefix(Beehive __instance, out float __state) { __state = __instance.m_secPerUnit; float num = Multiplier(); if (num > 0f) { __instance.m_secPerUnit = __state / num; } } [HarmonyPatch(typeof(Beehive), "UpdateBees")] [HarmonyPostfix] private static void Beehive_Postfix(Beehive __instance, float __state) { __instance.m_secPerUnit = __state; } [HarmonyPatch(typeof(SapCollector), "UpdateTick")] [HarmonyPrefix] private static void SapCollector_Prefix(SapCollector __instance, out float __state) { __state = __instance.m_secPerUnit; float num = Multiplier(); if (num > 0f) { __instance.m_secPerUnit = __state / num; } } [HarmonyPatch(typeof(SapCollector), "UpdateTick")] [HarmonyPostfix] private static void SapCollector_Postfix(SapCollector __instance, float __state) { __instance.m_secPerUnit = __state; } } [HarmonyPatch] internal static class FloatingDrops { private static readonly FieldRef<ItemDrop, Floating> CachedFloating = AccessTools.FieldRefAccess<ItemDrop, Floating>("m_floating"); private static readonly FieldInfo LoadedItems = AccessTools.Field(typeof(ItemDrop), "s_instances"); internal static void Init() { GlorpheimPlugin.Cfg.FloatingDropsEnabled.SettingChanged += delegate { ApplyToLoadedItems(); }; } [HarmonyPatch(typeof(ItemDrop), "Awake")] [HarmonyPostfix] private static void ItemDrop_Awake_Postfix(ItemDrop __instance) { Apply(__instance, seedLiquidLevel: false); } private static void ApplyToLoadedItems() { if (LoadedItems.GetValue(null) is List<ItemDrop> list) { for (int i = 0; i < list.Count; i++) { Apply(list[i], seedLiquidLevel: true); } } } private static void Apply(ItemDrop item, bool seedLiquidLevel) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)item == (Object)null) { return; } Floating component = ((Component)item).GetComponent<Floating>(); bool flag = (Object)(object)component != (Object)null && AddedByUs(item); if (!GlorpheimPlugin.Cfg.FloatingDropsEnabled.Value) { if (flag) { Object.Destroy((Object)(object)component); CachedFloating.Invoke(item) = null; } } else if (!((Object)(object)component != (Object)null) && CanFloat(item)) { component = ((Component)item).gameObject.AddComponent<Floating>(); CachedFloating.Invoke(item) = component; if (seedLiquidLevel) { SeedLiquidLevel(component, ((Component)item).transform.position); } } } private static bool AddedByUs(ItemDrop item) { GameObject dropPrefab = item.m_itemData.m_dropPrefab; if ((Object)(object)dropPrefab != (Object)null) { return (Object)(object)dropPrefab.GetComponent<Floating>() == (Object)null; } return false; } private static bool CanFloat(ItemDrop item) { ZNetView component = ((Component)item).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return false; } if (component.GetZDO().GetBool(ZDOVars.s_piece, false)) { return false; } if ((Object)(object)((Component)item).GetComponent<Rigidbody>() != (Object)null) { return (Object)(object)((Component)item).GetComponentInChildren<Collider>() != (Object)null; } return false; } private static void SeedLiquidLevel(Floating floating, Vector3 position) { //IL_0000: 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) float liquidLevel = Floating.GetLiquidLevel(position, 1f, (LiquidType)0); if (!(liquidLevel <= position.y)) { floating.Increment((LiquidType)0); floating.SetLiquidLevel(liquidLevel, (LiquidType)0, (Component)null); } } } [HarmonyPatch] internal static class FreeCultivator { private static bool s_freeToolInUse; private static readonly HashSet<string> s_tools = new HashSet<string>(StringComparer.OrdinalIgnoreCase); private static string s_toolsSource; private static bool IsFreeTool(ItemData item) { if (item == null || !GlorpheimPlugin.Cfg.FreeCultivatorEnabled.Value) { return false; } string text = GlorpheimPlugin.Cfg.FreeCultivatorTools.Value ?? ""; if (text != s_toolsSource) { s_tools.Clear(); string[] array = text.Split(new char[1] { ',' }); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length > 0) { s_tools.Add(text2); } } s_toolsSource = text; } if ((Object)(object)item.m_dropPrefab != (Object)null) { return s_tools.Contains(((Object)item.m_dropPrefab).name); } return false; } [HarmonyPatch(typeof(Player), "UpdatePlacement")] [HarmonyPrefix] private static void UpdatePlacement_Prefix(Player __instance) { s_freeToolInUse = IsFreeTool(((Humanoid)__instance).RightItem); } [HarmonyPatch(typeof(Player), "UpdatePlacement")] [HarmonyPostfix] private static void UpdatePlacement_Postfix() { s_freeToolInUse = false; } [HarmonyPatch(typeof(Player), "GetBuildStamina")] [HarmonyPostfix] private static void GetBuildStamina_Postfix(ref float __result) { if (s_freeToolInUse) { __result = 0f; } } [HarmonyPatch(typeof(Player), "GetPlaceDurability")] [HarmonyPostfix] private static void GetPlaceDurability_Postfix(ItemData tool, ref float __result) { if (GlorpheimPlugin.Cfg.FreeCultivatorEnabled.Value && (Object)(object)tool?.m_dropPrefab != (Object)null && ((Object)tool.m_dropPrefab).name == "Cultivator") { __result = 0f; } } [HarmonyPatch(typeof(Player), "HaveStamina")] [HarmonyPrefix] private static bool HaveStamina_Prefix(ref bool __result) { if (!s_freeToolInUse) { return true; } __result = true; return false; } } [HarmonyPatch(typeof(Chat), "SendText")] internal static class GlobalChat { [HarmonyPrefix] private static bool Prefix(Type type, string text) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Invalid comparison between Unknown and I4 //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown if (!GlorpheimPlugin.Cfg.GlobalChatEnabled.Value || (int)type != 1 || (Object)(object)Player.m_localPlayer == (Object)null) { return true; } Chat.CheckPermissionsAndSendChatMessageRPCsAsync((SendChatMessageRPCHandler)delegate(long user, bool filterText) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) UserInfo val = default(UserInfo); string text2 = default(string); Chat.GetChatMessageData(text, filterText, ref val, ref text2); ZRoutedRpc.instance.InvokeRoutedRPC(user, "ChatMessage", new object[4] { ((Character)Player.m_localPlayer).GetHeadPoint(), 1, val, text2 }); }); return false; } } [HarmonyPatch] internal static class InstantRested { private const float FallbackVanillaDelay = 20f; internal static void Init() { GlorpheimPlugin.Cfg.InstantRestedEnabled.SettingChanged += delegate { ApplyToLocalPlayer(); }; GlorpheimPlugin.Cfg.InstantRestedDelay.SettingChanged += delegate { ApplyToLocalPlayer(); }; } [HarmonyPatch(typeof(SE_Cozy), "Setup")] [HarmonyPostfix] private static void SE_Cozy_Setup_Postfix(SE_Cozy __instance) { Apply(__instance); } private static void ApplyToLocalPlayer() { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null)) { StatusEffect statusEffect = ((Character)localPlayer).GetSEMan().GetStatusEffect(SEMan.s_statusEffectResting); SE_Cozy val = (SE_Cozy)(object)((statusEffect is SE_Cozy) ? statusEffect : null); if (val != null) { Apply(val); } } } private static void Apply(SE_Cozy se) { if (((StatusEffect)se).NameHash() == SEMan.s_statusEffectResting) { se.m_delay = (GlorpheimPlugin.Cfg.InstantRestedEnabled.Value ? GlorpheimPlugin.Cfg.InstantRestedDelay.Value : VanillaDelay()); } } private static float VanillaDelay() { if ((Object)(object)ObjectDB.instance != (Object)null) { StatusEffect statusEffect = ObjectDB.instance.GetStatusEffect(SEMan.s_statusEffectResting); SE_Cozy val = (SE_Cozy)(object)((statusEffect is SE_Cozy) ? statusEffect : null); if (val != null) { return val.m_delay; } } return 20f; } } [HarmonyPatch] internal static class KeepFoodOnDeath { [HarmonyPatch(typeof(Player), "OnDeath")] [HarmonyPrefix] private static void Player_OnDeath_Prefix(Player __instance, out List<Food> __state) { __state = new List<Food>(__instance.GetFoods()); } [HarmonyPatch(typeof(Player), "OnDeath")] [HarmonyPostfix] private static void Player_OnDeath_Postfix(Player __instance, List<Food> __state) { if (GlorpheimPlugin.Cfg.KeepFoodOnDeathEnabled.Value && __state.Count != 0) { List<Food> foods = __instance.GetFoods(); if (foods.Count == 0) { foods.AddRange(__state); } } } } [HarmonyPatch(typeof(InventoryGui), "SetupRequirement")] internal static class NearbyChestCounts { private const string NearbyChestsGuid = "NearbyChests"; private static bool? s_nearbyChestsLoaded; private static bool NearbyChestsLoaded { get { bool? flag = s_nearbyChestsLoaded; if (!flag.HasValue) { bool? flag2 = (s_nearbyChestsLoaded = Chainloader.PluginInfos.ContainsKey("NearbyChests")); return flag2.Value; } return flag == true; } } [HarmonyPostfix] private static void Postfix(Transform elementRoot, Requirement req, Player player, int quality, int craftMultiplier, bool __result) { if (__result && !((Object)(object)req.m_resItem == (Object)null) && !((Object)(object)player == (Object)null) && GlorpheimPlugin.Cfg.NearbyChestCountsEnabled.Value && NearbyChestsLoaded) { int num = req.GetAmount(quality) * craftMultiplier; int num2 = ((Humanoid)player).GetInventory().CountItems(req.m_resItem.m_itemData.m_shared.m_name, -1, true); TMP_Text component = ((Component)elementRoot.Find("res_amount")).GetComponent<TMP_Text>(); component.textWrappingMode = (TextWrappingModes)0; component.overflowMode = (TextOverflowModes)0; component.text = $"{num} <size=80%>({num2})</size>"; } } } [HarmonyPatch] internal static class NewRecipeHighlight { private const string CustomDataKey = "glorpheim.unseen_recipes"; private const string MarkName = "glorpheim_new"; private const char Separator = '\n'; private static readonly FieldInfo AvailableRecipes = AccessTools.Field(typeof(InventoryGui), "m_availableRecipes"); private static readonly Type RecipeDataPair = AccessTools.Inner(typeof(InventoryGui), "RecipeDataPair"); private static readonly PropertyInfo PairRecipe = AccessTools.Property(RecipeDataPair, "Recipe"); private static readonly PropertyInfo PairElement = AccessTools.Property(RecipeDataPair, "InterfaceElement"); private static readonly HashSet<string> s_unseen = new HashSet<string>(); private static Player s_loadedFor; private static bool s_userSelecting; private static bool Enabled => GlorpheimPlugin.Cfg.NewRecipeHighlightEnabled.Value; private static HashSet<string> Unseen(Player player) { if ((Object)(object)s_loadedFor != (Object)(object)player) { s_loadedFor = player; s_unseen.Clear(); if ((Object)(object)player != (Object)null && player.m_customData.TryGetValue("glorpheim.unseen_recipes", out var value) && !string.IsNullOrEmpty(value)) { s_unseen.UnionWith(value.Split(new char[1] { '\n' })); } } return s_unseen; } private static void Save(Player player) { if (s_unseen.Count == 0) { player.m_customData.Remove("glorpheim.unseen_recipes"); } else { player.m_customData["glorpheim.unseen_recipes"] = string.Join('\n'.ToString(), s_unseen); } } private static string RecipeKey(Recipe recipe) { if (!((Object)(object)recipe != (Object)null) || !((Object)(object)recipe.m_item != (Object)null)) { return null; } return recipe.m_item.m_itemData.m_shared.m_name; } [HarmonyPatch(typeof(Player), "AddKnownRecipe")] [HarmonyPrefix] private static void AddKnownRecipe_Prefix(Player __instance, Recipe recipe, out bool __state) { string text = RecipeKey(recipe); __state = text != null && __instance.IsRecipeKnown(text); } [HarmonyPatch(typeof(Player), "AddKnownRecipe")] [HarmonyPostfix] private static void AddKnownRecipe_Postfix(Player __instance, Recipe recipe, bool __state) { string text = RecipeKey(recipe); if (!__state && text != null && Enabled && !((Object)(object)__instance != (Object)(object)Player.m_localPlayer) && __instance.IsRecipeKnown(text) && Unseen(__instance).Add(text)) { Save(__instance); } } [HarmonyPatch(typeof(InventoryGui), "AddRecipeToList")] [HarmonyPostfix] private static void AddRecipeToList_Postfix(InventoryGui __instance, Player player, Recipe recipe) { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown string text = RecipeKey(recipe); if (text != null && Enabled && !((Object)(object)player == (Object)null) && Unseen(player).Contains(text)) { IList list = (IList)AvailableRecipes.GetValue(__instance); if (list.Count != 0) { AddMark((GameObject)PairElement.GetValue(list[list.Count - 1])); } } } private static void AddMark(GameObject row) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: 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_00a8: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: 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_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: 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_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) Color value = GlorpheimPlugin.Cfg.NewRecipeHighlightColor.Value; Transform val = row.transform.Find("selected"); GameObject val2; if ((Object)(object)val != (Object)null) { val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, row.transform); val2.transform.SetSiblingIndex(val.GetSiblingIndex()); Image[] componentsInChildren = val2.GetComponentsInChildren<Image>(true); foreach (Image obj in componentsInChildren) { ((Graphic)obj).color = value; ((Graphic)obj).raycastTarget = false; } } else { val2 = new GameObject("glorpheim_new", new Type[2] { typeof(RectTransform), typeof(Image) }); RectTransform val3 = (RectTransform)val2.transform; ((Transform)val3).SetParent(row.transform, false); ((Transform)val3).SetAsFirstSibling(); val3.anchorMin = Vector2.zero; val3.anchorMax = Vector2.one; Vector2 offsetMin = (val3.offsetMax = Vector2.zero); val3.offsetMin = offsetMin; Image component = val2.GetComponent<Image>(); ((Graphic)component).color = value; ((Graphic)component).raycastTarget = false; } ((Object)val2).name = "glorpheim_new"; val2.SetActive(true); } [HarmonyPatch(typeof(InventoryGui), "OnSelectedRecipe")] [HarmonyPrefix] private static void OnSelectedRecipe_Prefix() { s_userSelecting = true; } [HarmonyPatch(typeof(InventoryGui), "OnSelectedRecipe")] [HarmonyFinalizer] private static void OnSelectedRecipe_Finalizer() { s_userSelecting = false; } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipeGamepadInput")] [HarmonyPrefix] private static void UpdateRecipeGamepadInput_Prefix() { s_userSelecting = true; } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipeGamepadInput")] [HarmonyFinalizer] private static void UpdateRecipeGamepadInput_Finalizer() { s_userSelecting = false; } [HarmonyPatch(typeof(InventoryGui), "SetRecipe")] [HarmonyPostfix] private static void SetRecipe_Postfix(InventoryGui __instance, int index) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Expected O, but got Unknown //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Expected O, but got Unknown //IL_00a5: Unknown result type (might be due to invalid IL or missing references) Player localPlayer = Player.m_localPlayer; if (!s_userSelecting || index < 0 || (Object)(object)localPlayer == (Object)null) { return; } IList list = (IList)AvailableRecipes.GetValue(__instance); if (index >= list.Count) { return; } string text = RecipeKey((Recipe)PairRecipe.GetValue(list[index])); if (text == null || !Unseen(localPlayer).Remove(text)) { return; } Save(localPlayer); foreach (object item in list) { if (!(RecipeKey((Recipe)PairRecipe.GetValue(item)) != text)) { Transform val = ((GameObject)PairElement.GetValue(item)).transform.Find("glorpheim_new"); if ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(false); } } } } } [HarmonyPatch] internal static class RecipeSearch { [HarmonyPatch(typeof(ZInput), "TryGetButtonState")] private static class ZInput_TryGetButtonState { private static bool Prefix(string name, ref bool __result) { if (!BlockGameInput || name.StartsWith("Mouse", StringComparison.Ordinal)) { return true; } __result = false; return false; } } [HarmonyPatch(typeof(ZInput), "TryGetKeyStateLowLevel")] private static class ZInput_TryGetKeyStateLowLevel { private static bool Prefix(KeyCode keyCode, ref bool __result) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Invalid comparison between Unknown and I4 //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Invalid comparison between Unknown and I4 //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Invalid comparison between Unknown and I4 //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Invalid comparison between Unknown and I4 if (!BlockGameInput || ((int)keyCode >= 323 && (int)keyCode <= 329) || (int)keyCode == 306 || (int)keyCode == 305 || (int)keyCode == 8 || (int)keyCode == 127) { return true; } __result = false; return false; } } [CompilerGenerated] private static class <>O { public static UnityAction<string> <0>__OnTextChanged; public static UnityAction <1>__OnClearPressed; } private const string FieldName = "glorpheim_RecipeSearch"; private const float Gap = 8f; private const float MinWidth = 120f; private const float MaxWidth = 320f; private const float MaxHeight = 36f; private static readonly string[] NoWords = new string[0]; private static readonly Action<InventoryGui, bool> UpdateCraftingPanel = AccessTools.MethodDelegate<Action<InventoryGui, bool>>(AccessTools.Method(typeof(InventoryGui), "UpdateCraftingPanel", (Type[])null, (Type[])null), (object)null, true); private static readonly FieldInfo BuildSearchField = AccessTools.Field(typeof(BuildUi), "m_searchField"); private static TMP_InputField s_field; private static MethodInfo s_activateInputField; private static GameObject s_clearButton; private static string[] s_words = NoWords; private static int s_blockUntilFrame = -1; private static bool s_warnedMissingSource; private static bool Enabled => GlorpheimPlugin.Cfg.RecipeSearchEnabled.Value; private static bool BlockGameInput { get { if ((Object)(object)s_field != (Object)null) { if (!s_field.isFocused || !((Component)s_field).gameObject.activeInHierarchy) { return Time.frameCount == s_blockUntilFrame; } return true; } return false; } } [HarmonyPatch(typeof(InventoryGui), "UpdateRecipeList")] [HarmonyPrefix] private static void UpdateRecipeList_Prefix(List<Recipe> recipes) { if (s_words.Length != 0 && Enabled) { recipes.RemoveAll((Recipe recipe) => !Matches(recipe)); } } private static bool Matches(Recipe recipe) { ItemDrop item = recipe.m_item; if ((Object)(object)item == (Object)null) { return true; } string text = Localization.instance.Localize(item.m_itemData.m_shared.m_name); string name = ((Object)item).name; string[] array = s_words; foreach (string word in array) { if (!Contains(text, word) && !Contains(name, word)) { return false; } } return true; } private static bool Contains(string text, string word) { return CultureInfo.InvariantCulture.CompareInfo.IndexOf(text, word, CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace) >= 0; } private static void SetTerm(string text) { s_words = (string.IsNullOrEmpty(text) ? NoWords : text.Split(new char[2] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries)); } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] private static void SearchFieldFocused_Postfix(ref bool __result) { if (BlockGameInput) { __result = true; } } [HarmonyPatch(typeof(InventoryGui), "Update")] [HarmonyPostfix] private static void Update_Postfix() { if (!((Object)(object)s_field == (Object)null) && Enabled && !s_field.isFocused && ((Component)s_field).gameObject.activeInHierarchy && InventoryGui.IsVisible() && (!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !TextInput.IsVisible() && !Menu.IsVisible() && !Minimap.IsOpen() && ZInput.GetKeyDown((KeyCode)102, true)) { Focus(); } } private static void Focus() { if (s_activateInputField == null) { s_activateInputField = ((object)s_field).GetType().GetMethod("ActivateInputField", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null) ?? AccessTools.Method(typeof(TMP_InputField), "ActivateInputField", (Type[])null, (Type[])null); } s_activateInputField.Invoke(s_field, null); } [HarmonyPatch(typeof(InventoryGui), "Show")] [HarmonyPostfix] private static void Show_Postfix(InventoryGui __instance) { if (!Enabled) { if ((Object)(object)s_field != (Object)null) { ((Component)s_field).gameObject.SetActive(false); } return; } if ((Object)(object)s_field == (Object)null) { Create(__instance); } if ((Object)(object)s_field != (Object)null) { ((Component)s_field).gameObject.SetActive(true); } } [HarmonyPatch(typeof(InventoryGui), "Hide")] [HarmonyPostfix] private static void Hide_Postfix() { if (!((Object)(object)s_field == (Object)null) && (s_words.Length != 0 || s_field.isFocused)) { s_field.DeactivateInputField(false); s_field.SetTextWithoutNotify(""); SetTerm(""); if ((Object)(object)s_clearButton != (Object)null) { s_clearButton.SetActive(false); } } } private static void Create(InventoryGui gui) { //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Expected O, but got Unknown //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Expected O, but got Unknown //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Expected O, but got Unknown //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Expected O, but got Unknown //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Expected O, but got Unknown //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_0259: Expected O, but got Unknown //IL_0281: Unknown result type (might be due to invalid IL or missing references) //IL_028d: Unknown result type (might be due to invalid IL or missing references) TMP_InputField val = (TMP_InputField)(((Object)(object)Hud.instance != (Object)null && (Object)(object)Hud.instance.m_buildUi != (Object)null) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val == (Object)null) { if (!s_warnedMissingSource) { s_warnedMissingSource = true; GlorpheimPlugin.Log.LogWarning((object)"RecipeSearch: the build menu search field was not found, the recipe search box is unavailable"); } return; } RectTransform component = ((Component)gui.m_tabUpgrade).GetComponent<RectTransform>(); Transform parent = ((Transform)component).parent; RectTransform val2 = (RectTransform)(object)((parent is RectTransform) ? parent : null); if ((Object)(object)val2 == (Object)null || (Object)(object)((Component)val2).GetComponent<LayoutGroup>() != (Object)null) { Transform obj = (((Object)(object)val2 != (Object)null) ? ((Transform)val2).parent : ((Transform)component).parent); val2 = (RectTransform)(object)((obj is RectTransform) ? obj : null); } if (!((Object)(object)val2 == (Object)null)) { GameObject obj2 = Object.Instantiate<GameObject>(((Component)val).gameObject, (Transform)(object)val2, false); ((Object)obj2).name = "glorpheim_RecipeSearch"; obj2.SetActive(true); s_field = obj2.GetComponent<TMP_InputField>(); s_field.onValueChanged = new OnChangeEvent(); s_field.onEndEdit = new SubmitEvent(); s_field.onSubmit = new SubmitEvent(); s_field.onSelect = new SelectionEvent(); s_field.onDeselect = new SelectionEvent(); Traverse.Create((object)s_field).Field("OnInputSubmit").SetValue((object)null); s_field.SetTextWithoutNotify(""); s_field.lineType = (LineType)0; s_field.characterLimit = 40; s_field.restoreOriginalTextOnEscape = false; TMP_InputField obj3 = s_field; Navigation navigation = default(Navigation); ((Navigation)(ref navigation)).mode = (Mode)0; ((Selectable)obj3).navigation = navigation; ((UnityEvent<string>)(object)s_field.onValueChanged).AddListener((UnityAction<string>)OnTextChanged); ((UnityEvent<string>)(object)s_field.onEndEdit).AddListener((UnityAction<string>)delegate { s_blockUntilFrame = Time.frameCount; }); ((UnityEvent<string>)(object)s_field.onDeselect).AddListener((UnityAction<string>)delegate { s_blockUntilFrame = Time.frameCount; }); Graphic placeholder = s_field.placeholder; TMP_Text val3 = (TMP_Text)(object)((placeholder is TMP_Text) ? placeholder : null); if (val3 != null && string.IsNullOrEmpty(val3.text)) { val3.text = "Search..."; } RectTransform val4 = (RectTransform)obj2.transform; float height = Layout(gui, component, val2, val4); CreateClearButton(gui, val4, height); GlorpheimPlugin.Log.LogDebug((object)$"RecipeSearch: box under '{((Object)val2).name}' at {val4.anchoredPosition}, size {val4.sizeDelta}"); } } private static float Layout(InventoryGui gui, RectTransform tab, RectTransform parent, RectTransform rect) { //IL_0003: 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_0010: 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_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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_004f: 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_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_0166: 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_00ac: Unknown result type (might be due to invalid IL or missing references) Vector2 val = LocalCorner(parent, tab, 2); Vector2 val2 = LocalCorner(parent, tab, 3); float num = Mathf.Min(val.y - val2.y, 36f); float num2 = (val.y + val2.y) * 0.5f; float num3 = val.x + 8f; Rect rect2 = parent.rect; float num4 = ((Rect)(ref rect2)).xMax - 8f; RectTransform[] array = new RectTransform[2]; Image craftingStationIcon = gui.m_craftingStationIcon; array[0] = ((craftingStationIcon != null) ? ((Graphic)craftingStationIcon).rectTransform : null); TMP_Text craftingStationName = gui.m_craftingStationName; array[1] = ((craftingStationName != null) ? craftingStationName.rectTransform : null); RectTransform[] array2 = (RectTransform[])(object)array; foreach (RectTransform val3 in array2) { if (!((Object)(object)val3 == (Object)null)) { float x = LocalCorner(parent, val3, 1).x; if (x > num3 + 120f) { num4 = Mathf.Min(num4, x - 8f); } } } float num5 = Mathf.Clamp(num4 - num3, 120f, 320f); Vector2 val4 = default(Vector2); ((Vector2)(ref val4))..ctor(0f, 1f); rect.anchorMax = val4; rect.anchorMin = val4; rect.pivot = new Vector2(0f, 1f); rect2 = parent.rect; float num6 = num3 - ((Rect)(ref rect2)).xMin; float num7 = num2 + num * 0.5f; rect2 = parent.rect; rect.anchoredPosition = new Vector2(num6, num7 - ((Rect)(ref rect2)).yMax); rect.sizeDelta = new Vector2(num5, num); ((Transform)rect).localScale = Vector3.one; return num; } private static Vector2 LocalCorner(RectTransform space, RectTransform target, int corner) { //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_001b: Unknown result type (might be due to invalid IL or missing references) Vector3[] array = (Vector3[])(object)new Vector3[4]; target.GetWorldCorners(array); return Vector2.op_Implicit(((Transform)space).InverseTransformPoint(array[corner])); } private static void CreateClearButton(InventoryGui gui, RectTransform field, float height) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: 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_00ac: 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) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0103: 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_01a0: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) //IL_0229: Expected O, but got Unknown //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0261: 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) GameObject val = new GameObject("ClearButton", new Type[3] { typeof(RectTransform), typeof(Image), typeof(Button) }); RectTransform val2 = (RectTransform)val.transform; ((Transform)val2).SetParent((Transform)(object)field, false); Vector2 val3 = default(Vector2); ((Vector2)(ref val3))..ctor(1f, 0.5f); val2.anchorMax = val3; val2.anchorMin = val3; val2.pivot = new Vector2(1f, 0.5f); val2.anchoredPosition = new Vector2(-2f, 0f); val2.sizeDelta = new Vector2(height, height); ((Graphic)val.GetComponent<Image>()).color = Color.clear; GameObject val4 = new GameObject("Text", new Type[1] { typeof(RectTransform) }); RectTransform val5 = (RectTransform)val4.transform; ((Transform)val5).SetParent((Transform)(object)val2, false); val5.anchorMin = Vector2.zero; val5.anchorMax = Vector2.one; val3 = (val5.offsetMin = (val5.offsetMax = Vector2.zero)); TextMeshProUGUI val7 = val4.AddComponent<TextMeshProUGUI>(); TMP_Text componentInChildren = ((Component)gui.m_tabCraft).GetComponentInChildren<TMP_Text>(true); if ((Object)(object)componentInChildren != (Object)null) { ((TMP_Text)val7).font = componentInChildren.font; ((TMP_Text)val7).fontSharedMaterial = componentInChildren.fontSharedMaterial; ((TMP_Text)val7).fontSize = componentInChildren.fontSize; } ((TMP_Text)val7).text = "X"; ((TMP_Text)val7).alignment = (TextAlignmentOptions)514; ((TMP_Text)val7).enableAutoSizing = true; ((TMP_Text)val7).fontSizeMin = 8f; ((TMP_Text)val7).fontSizeMax = height * 0.7f; ((Graphic)val7).raycastTarget = false; Button component = val.GetComponent<Button>(); ((Selectable)component).targetGraphic = (Graphic)(object)val7; ColorBlock colors = ((Selectable)component).colors; ((ColorBlock)(ref colors)).normalColor = new Color(0.8f, 0.78f, 0.7f, 1f); ((ColorBlock)(ref colors)).highlightedColor = Color.white; ((ColorBlock)(ref colors)).pressedColor = new Color(0.6f, 0.6f, 0.6f, 1f); ((ColorBlock)(ref colors)).selectedColor = ((ColorBlock)(ref colors)).normalColor; ((Selectable)component).colors = colors; ButtonClickedEvent onClick = component.onClick; object obj = <>O.<1>__OnClearPressed; if (obj == null) { UnityAction val8 = OnClearPressed; <>O.<1>__OnClearPressed = val8; obj = (object)val8; } ((UnityEvent)onClick).AddListener((UnityAction)obj); RectTransform textViewport = s_field.textViewport; if ((Object)(object)textViewport != (Object)null) { textViewport.offsetMax = new Vector2(Mathf.Min(textViewport.offsetMax.x, 0f - (height + 2f)), textViewport.offsetMax.y); } s_clearButton = val; s_clearButton.SetActive(false); } private static void OnTextChanged(string text) { SetTerm(text); if ((Object)(object)s_clearButton != (Object)null) { s_clearButton.SetActive(s_words.Length != 0); } InventoryGui instance = InventoryGui.instance; if (!((Object)(object)instance == (Object)null) && InventoryGui.IsVisible() && !((Object)(object)Player.m_localPlayer == (Object)null)) { UpdateCraftingPanel(instance, arg2: false); if ((Object)(object)instance.m_recipeListScroll != (Object)null) { instance.m_recipeListScroll.value = 1f; } } } private static void OnClearPressed() { if (!((Object)(object)s_field == (Object)null)) { s_field.DeactivateInputField(false); s_field.text = ""; } } } [HarmonyPatch] internal static class RequireMod { [HarmonyPatch(typeof(ZNet), "OnNewConnection")] [HarmonyPrefix] [HarmonyPriority(800)] private static void Prefix(ZNet __instance) { GlorpheimPlugin.Cfg.Sync.ModRequired = GlorpheimPlugin.Cfg.RequireMod.Value && __instance.IsServer(); } } [HarmonyPatch(typeof(Game), "UpdateSleeping")] internal static class SleepWithFewer { private const double SleepCooldownSeconds = 10.0; private static readonly FieldRef<Game, bool> SleepingRef = AccessTools.FieldRefAccess<Game, bool>("m_sleeping"); private static readonly FieldRef<Game, double> LastSleepTimeRef = AccessTools.FieldRefAccess<Game, double>("m_lastSleepTime"); private static readonly List<long> s_sleepers = new List<long>(); [HarmonyPrefix] private static bool Prefix(Game __instance) { if (!GlorpheimPlugin.Cfg.SleepWithFewerEnabled.Value) { return true; } if (!ZNet.instance.IsServer()) { return false; } ref bool reference = ref SleepingRef.Invoke(__instance); ref double reference2 = ref LastSleepTimeRef.Invoke(__instance); if (reference) { if (!EnvMan.instance.IsTimeSkipping() && !CinematicsManager.IsPlaying()) { reference2 = ZNet.instance.GetTimeSeconds(); reference = false; ZRoutedRpc.instance.InvokeRoutedRPC(0L, "SleepStop", Array.Empty<object>()); } return false; } if (EnvMan.instance.IsTimeSkipping() || (!EnvMan.IsAfternoon() && !EnvMan.IsNight()) || ZNet.instance.GetTimeSeconds() - reference2 < 10.0 || !EnoughPlayersInBed()) { return false; } EnvMan.instance.SkipToMorning(); reference = true; foreach (long s_sleeper in s_sleepers) { ZRoutedRpc.instance.InvokeRoutedRPC(s_sleeper, "SleepStart", Array.Empty<object>()); } return false; } private static bool EnoughPlayersInBed() { s_sleepers.Clear(); List<ZDO> allCharacterZDOS = ZNet.instance.GetAllCharacterZDOS(); if (allCharacterZDOS.Count == 0) { return false; } foreach (ZDO item in allCharacterZDOS) { if (item.GetBool(ZDOVars.s_inBed, false)) { s_sleepers.Add(item.GetOwner()); } } int num = Mathf.Clamp(GlorpheimPlugin.Cfg.SleepWithFewerRequiredSleepers.Value, 1, allCharacterZDOS.Count); return s_sleepers.Count >= num; } } [HarmonyPatch] internal static class StationStorage { [HarmonyPatch] private static class ScaledCapacity { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(Smelter), "OnAddOre", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Smelter), "OnAddFuel", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Smelter), "CanUseItems", (Type[])null, (Type[])null); } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { foreach (CodeInstruction instruction in instructions) { if (CodeInstructionExtensions.LoadsField(instruction, MaxOreField, false)) { yield return CodeInstructionExtensions.MoveLabelsFrom(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(StationStorage), "MaxOre", (Type[])null, (Type[])null)), instruction); } else if (CodeInstructionExtensions.LoadsField(instruction, MaxFuelField, false)) { yield return CodeInstructionExtensions.MoveLabelsFrom(new CodeInstruction(OpCodes.Call, (object)AccessTools.Method(typeof(StationStorage), "MaxFuel", (Type[])null, (Type[])null)), instruction); } else { yield return instruction; } } } } [HarmonyPatch] private static class ScaledHover { private static IEnumerable<MethodBase> TargetMethods() { yield return AccessTools.Method(typeof(Smelter), "OnHoverAddOre", (Type[])null, (Type[])null); yield return AccessTools.Method(typeof(Smelter), "OnHoverAddFuel", (Type[])null, (Type[])null); } [HarmonyPriority(800)] private static void Prefix(Smelter __instance, out int[] __state) { __state = new int[2] { __instance.m_maxOre, __instance.m_maxFuel }; __instance.m_maxOre = MaxOre(__instance); __instance.m_maxFuel = MaxFuel(__instance); } private static void Finalizer(Smelter __instance, int[] __state) { if (__state != null) { __instance.m_maxOre = __state[0]; __instance.m_maxFuel = __state[1]; } } } private static readonly FieldInfo MaxOreField = AccessTools.Field(typeof(Smelter), "m_maxOre"); private static readonly FieldInfo MaxFuelField = AccessTools.Field(typeof(Smelter), "m_maxFuel"); private static readonly Func<Smelter, int> GetQueueSize = AccessTools.MethodDelegate<Func<Smelter, int>>(AccessTools.Method(typeof(Smelter), "GetQueueSize", (Type[])null, (Type[])null), (object)null, true); private static readonly Func<Smelter, float> GetFuel = AccessTools.MethodDelegate<Func<Smelter, float>>(AccessTools.Method(typeof(Smelter), "GetFuel", (Type[])null, (Type[])null), (object)null, true); private static readonly Func<Smelter, Inventory, ItemData> FindCookableItem = AccessTools.MethodDelegate<Func<Smelter, Inventory, ItemData>>(AccessTools.Method(typeof(Smelter), "FindCookableItem", (Type[])null, (Type[])null), (object)null, true); private static readonly Func<Smelter, Switch, Humanoid, ItemData, bool> OnAddOre = AccessTools.MethodDelegate<Func<Smelter, Switch, Humanoid, ItemData, bool>>(AccessTools.Method(typeof(Smelter), "OnAddOre", (Type[])null, (Type[])null), (object)null, true); private static readonly Func<Smelter, Switch, Humanoid, ItemData, bool> OnAddFuel = AccessTools.MethodDelegate<Func<Smelter, Switch, Humanoid, ItemData, bool>>(AccessTools.Method(typeof(Smelter), "OnAddFuel", (Type[])null, (Type[])null), (object)null, true); private const int ShiftAddAmount = 10; private static bool _batching; private static bool _holdRepeat; private static int CapacityMultiplier() { if (!GlorpheimPlugin.Cfg.StationStorageEnabled.Value) { return 1; } return Math.Max(1, GlorpheimPlugin.Cfg.StationStorageCapacityMultiplier.Value); } private static int MaxOre(Smelter smelter) { return smelter.m_maxOre * CapacityMultiplier(); } private static int MaxFuel(Smelter smelter) { return smelter.m_maxFuel * CapacityMultiplier(); } private static int BatchSize(Humanoid user) { if (_batching || !GlorpheimPlugin.Cfg.StationStorageEnabled.Value || (Object)(object)user == (Object)null || (Object)(object)user != (Object)(object)Player.m_localPlayer) { return 1; } if (!ZInput.GetKey((KeyCode)304, true) && !ZInput.GetKey((KeyCode)303, true)) { return 1; } return 10; } [HarmonyPatch(typeof(Switch), "Interact")] [HarmonyPrefix] private static void Switch_Interact_Prefix(bool hold) { _holdRepeat = hold; } [HarmonyPatch(typeof(Switch), "Interact")] [HarmonyFinalizer] private static void Switch_Interact_Finalizer() { _holdRepeat = false; } [HarmonyPatch(typeof(Smelter), "OnAddOre")] [HarmonyPrefix] private static bool Smelter_OnAddOre_Prefix(Smelter __instance, Switch sw, Humanoid user, ItemData item, ref bool __result) { int num = BatchSize(user); if (num <= 1) { return true; } if (_holdRepeat) { __result = false; return false; } int num2 = MaxOre(__instance) - GetQueueSize(__instance); if (num2 <= 0) { return true; } Inventory inventory = user.GetInventory(); ItemData val = item ?? FindCookableItem(__instance, inventory); int i = 0; string text = null; _batching = true; try { for (; i < num && i < num2; i++) { if (val == null || !inventory.ContainsItem(val)) { val = ((item != null) ? inventory.GetItem(item.m_shared.m_name, -1, false) : FindCookableItem(__instance, inventory)); } if (i > 0 && val == null) { break; } string text2 = val?.m_shared.m_name; if (!OnAddOre(__instance, sw, user, val)) { break; } text = text2; } } finally { _batching = false; } if (i > 1 && text != null) { ((Character)user).Message((MessageType)2, $"$msg_added {text} x{i}", 0, (Sprite)null, false); } __result = i > 0; return false; } [HarmonyPatch(typeof(Smelter), "OnAddFuel")] [HarmonyPrefix] private static bool Smelter_OnAddFuel_Prefix(Smelter __instance, Switch sw, Humanoid user, ItemData item, ref bool __result) { int num = BatchSize(user); if (num <= 1) { return true; } if (_holdRepeat) { __result = false; return false; } int num2 = Mathf.FloorToInt((float)MaxFuel(__instance) - GetFuel(__instance)); if (num2 <= 0) { return true; } int i = 0; _batching = true; try { for (; i < num && i < num2; i++) { if (!OnAddFuel(__instance, sw, user, item)) { break; } } } finally { _batching = false; } if (i > 1) { ((Character)user).Message((MessageType)2, $"$msg_added {__instance.m_fuelItem.m_itemData.m_shared.m_name} x{i}", 0, (Sprite)null, false); } __result = i > 0; return false; } [HarmonyPatch(typeof(Smelter), "OnHoverAddOre")] [HarmonyPostfix] [HarmonyPriority(0)] private static void Smelter_OnHoverAddOre_Postfix(Smelter __instance, ref string __result) { AppendHint(ref __result, __instance.m_addOreTooltip); } [HarmonyPatch(typeof(Smelter), "OnHoverAddFuel")] [HarmonyPostfix] [HarmonyPriority(0)] private static void Smelter_OnHoverAddFuel_Postfix(Smelter __instance, ref string __result) { AppendHint(ref __result, "$piece_smelter_add " + __instance.m_fuelItem.m_itemData.m_shared.m_name); } private static void AppendHint(ref string text, string action) { if (GlorpheimPlugin.Cfg.StationStorageEnabled.Value && !ZInput.GamepadActive && Localization.instance != null) { string text2 = Localization.instance.Localize(action); string text3 = Localization.instance.Localize($"[<b><color=yellow>$button_lshift</color> + <color=yellow>$KEY_Use</color></b>] {text2} (x{10})"); int num = (string.IsNullOrEmpty(text2) ? (-1) : text.IndexOf(text2, StringComparison.Ordinal)); if (num < 0) { text = text + "\n" + text3; return; } int num2 = text.IndexOf('\n', num); text = ((num2 < 0) ? (text + "\n" + text3) : text.Insert(num2, "\n" + text3)); } } } } namespace Glorpheim.Features.PortalHarpoon { internal static class CreatureCapsule { private const string KeyPrefab = "glorpheim.portalharpoon.prefab"; private const string KeyData = "glorpheim.portalharpoon.zdo"; private const string KeyName = "glorpheim.portalharpoon.name"; private const string KeyLevel = "glorpheim.portalharpoon.level"; internal static bool IsLoaded(ItemData item) { return item?.m_customData.ContainsKey("glorpheim.portalharpoon.zdo") ?? false; } internal static string Describe(ItemData item) { if (!IsLoaded(item)) { return null; } item.m_customData.TryGetValue("glorpheim.portalharpoon.name", out var value); item.m_customData.TryGetValue("glorpheim.portalharpoon.level", out var value2); int.TryParse(value2, out var result); StringBuilder stringBuilder = new StringBuilder(Localization.instance.Localize(value ?? "?")); for (int i = 1; i < result; i++) { stringBuilder.Append(" ★"); } return stringBuilder.ToString(); } internal static bool Capture(ItemData item, Character creature) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown ZNetView component = ((Component)creature).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return false; } ZDO zDO = component.GetZDO(); ZPackage val = new ZPackage(); zDO.Serialize(val); Tameable component2 = ((Component)creature).GetComponent<Tameable>(); item.m_customData["glorpheim.portalharpoon.prefab"] = Utils.GetPrefabName(((Component)creature).gameObject); item.m_customData["glorpheim.portalharpoon.zdo"] = val.GetBase64(); item.m_customData["glorpheim.portalharpoon.name"] = (((Object)(object)component2 != (Object)null) ? component2.GetHoverName() : creature.m_name); item.m_customData["glorpheim.portalharpoon.level"] = creature.GetLevel().ToString(); component.ClaimOwnership(); ZNetScene.instance.Destroy(((Component)creature).gameObject); return true; } internal static GameObject Release(ItemData item, Vector3 position, Quaternion rotation) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Expected O, but got Unknown //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) if (!IsLoaded(item)) { return null; } item.m_customData.TryGetValue("glorpheim.portalharpoon.prefab", out var value); GameObject val = (string.IsNullOrEmpty(value) ? null : ZNetScene.instance.GetPrefab(value)); if ((Object)(object)val == (Object)null) { GlorpheimPlugin.Log.LogWarning((object)("PortalHarpoon: stored creature prefab '" + value + "' does not exist")); return null; } ZDO val2; try { val2 = ZDOMan.instance.CreateNewZDO(position, StringExtensionMethods.GetStableHashCode(value)); val2.Deserialize(new ZPackage(item.m_customData["glorpheim.portalharpoon.zdo"])); } catch (Exception arg) { GlorpheimPlugin.Log.LogError((object)$"PortalHarpoon: could not restore stored creature: {arg}"); return null; } val2.SetPosition(position); val2.SetRotation(rotation); uint dataRevision = val2.DataRevision; val2.DataRevision = dataRevision + 1; ZNetView.m_useInitZDO = true; ZNetView.m_initZDO = val2; GameObject result; try { result = Object.Instantiate<GameObject>(val, position, rotation); } finally { ZNetView.m_initZDO = null; ZNetView.m_useInitZDO = false; } Clear(item); return result; } internal static void Clear(ItemData item) { item.m_customData.Remove("glorpheim.portalharpoon.prefab"); item.m_customData.Remove("glorpheim.portalharpoon.zdo"); item.m_customData.Remove("glorpheim.portalharpoon.name"); item.m_customData.Remove("glorpheim.portalharpoon.level"); } } [HarmonyPatch] internal static class PortalHarpoonFeature { private static readonly int ReleaseRayMask = LayerMask.GetMask(new string[7] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "terrain", "vehicle" }); private static bool Enabled => PortalHarpoonItem.Enabled; [HarmonyPatch(typeof(Projectile), "OnHit")] [HarmonyPrefix] private static bool Projectile_OnHit_Prefix(Projectile __instance, Collider collider, Vector3 hitPoint, Character ___m_owner, ItemData ___m_weapon) { //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) if (Enabled && !((Object)(object)collider == (Object)null)) { Player val = (Player)(object)((___m_owner is Player) ? ___m_owner : null); if (val != null && PortalHarpoonItem.IsPortalHarpoon(___m_weapon)) { GameObject val2 = Projectile.FindHitObject(collider); Character val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponent<Character>() : null); Tameable val4 = (((Object)(object)val3 != (Object)null) ? ((Component)val3).GetComponent<Tameable>() : null); if ((Object)(object)val4 == (Object)null || val3.IsPlayer() || val3.IsBoss() || val3.IsDead()) { return true; } if (CreatureCapsule.IsLoaded(___m_weapon)) { ((Character)val).Message((MessageType)2, "$msg_portalharpoon_full", 0, (Sprite)null, false); return true; } string hoverName = val4.GetHoverName(); if (!CreatureCapsule.Capture(___m_weapon, val3)) { return true; } ((Character)val).Message((MessageType)2, hoverName + " $msg_portalharpoon_captured", 0, (Sprite)null, false); __instance.m_hitEffects.Create(hitPoint, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); ZNetScene.instance.Destroy(((Component)__instance).gameObject); return false; } } return true; } [HarmonyPatch(typeof(Player), "SetControls")] [HarmonyPrefix] private static void Player_SetControls_Prefix(Player __instance, ref bool block, ref bool blockHold) { if (!Enabled || !block || (Object)(object)__instance != (Object)(object)Player.m_localPlayer) { return; } ItemData currentWeapon = ((Humanoid)__instance).GetCurrentWeapon(); if (PortalHarpoonItem.IsPortalHarpoon(currentWeapon) && CreatureCapsule.IsLoaded(currentWeapon)) { block = false; blockHold = false; if (!((Character)__instance).IsDead() && !((Character)__instance).IsTeleporting() && !((Character)__instance).IsAttached() && !((Character)__instance).InPlaceMode() && !((Character)__instance).InAttack()) { TryRelease(__instance, currentWeapon); } } } private static void TryRelease(Player player, ItemData weapon) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Unknown result type (might be due to invalid IL or missing references) GameCamera instance = GameCamera.instance; RaycastHit val = default(RaycastHit); if ((Object)(object)instance == (Object)null || !Physics.Raycast(((Component)instance).transform.position, ((Component)instance).transform.forward, ref val, 1000f, ReleaseRayMask)) { ((Character)player).Message((MessageType)2, "$msg_portalharpoon_nospot", 0, (Sprite)null, false); return; } Vector3 val2 = ((RaycastHit)(ref val)).point + Vector3.up * 0.1f; Vector3 val3 = ((Component)player).transform.position - val2; val3.y = 0f; Quaternion rotation = ((((Vector3)(ref val3)).sqrMagnitude > 0.01f) ? Quaternion.LookRotation(((Vector3)(ref val3)).normalized) : ((Component)player).transform.rotation); string text = CreatureCapsule.Describe(weapon); if ((Object)(object)CreatureCapsule.Release(weapon, val2, rotation) != (Object)null) { ((Character)player).Message((MessageType)2, text + " $msg_portalharpoon_released", 0, (Sprite)null, false); } } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) })] [HarmonyPostfix] private static void ItemData_GetTooltip_Postfix(ItemData item, bool crafting, ref string __result) { if (!(!Enabled || crafting) && PortalHarpoonItem.IsPortalHarpoon(item)) { string text = CreatureCapsule.Describe(item); string text2 = ((text != null) ? ("<color=#7fd67f>" + Localization.instance.Localize("$item_portalharpoon_holds") + ": " + text + "</color>") : ("<color=#9a9a9a>" + Localization.instance.Localize("$item_portalharpoon_empty") + "</color>")); __result = __result + "\n\n" + text2; } } } [HarmonyPatch] internal static class PortalHarpoonItem { internal const string PrefabName = "PortalHarpoon"; internal const string ItemName = "$item_portalharpoon"; private const string SourcePrefab = "SpearChitin"; private const string WorkbenchPrefab = "piece_workbench"; private static readonly Color IconTint = new Color(0.35f, 0.7f, 0.35f); private static readonly Dictionary<string, string> Words = new Dictionary<string, string> { ["item_portalharpoon"] = "Portal Harpoon", ["item_portalharpoon_description"] = "An Abyssal Harpoon threaded with surtling fire and greydwarf sight. A tameable creature it strikes is pulled inside; right click to set it down somewhere else. Stars, taming and name survive the trip.", ["item_portalharpoon_holds"] = "Holds", ["item_portalharpoon_empty"] = "Empty. Hit a tameable creature to store it.", ["msg_portalharpoon_captured"] = "stored in the harpoon", ["msg_portalharpoon_released"] = "released", ["msg_portalharpoon_full"] = "The harpoon already holds a creature", ["msg_portalharpoon_nospot"] = "Nowhere to release the creature there" }; private static readonly MethodInfo UpdateRegisters = AccessTools.Method(typeof(ObjectDB), "UpdateRegisters", (Type[])null, (Type[])null); private static readonly MethodInfo AddWord = AccessTools.Method(typeof(Localization), "AddWord", (Type[])null, (Type[])null); private static GameObject s_holder; private static GameObject s_prefab; private static Recipe s_recipe; internal static bool Enabled => GlorpheimPlugin.Cfg.PortalHarpoonEnabled.Value; internal static bool IsPortalHarpoon(ItemData item) { if (item != null && item.m_shared != null) { return item.m_shared.m_name == "$item_portalharpoon"; } return false; } [HarmonyPatch(typeof(ObjectDB), "Awake")] [HarmonyPostfix] private static void ObjectDB_Awake_Postfix(ObjectDB __instance) { if (Enabled) { Register(__instance); } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] [HarmonyPostfix] private static void ObjectDB_CopyOtherDB_Postfix(ObjectDB __instance) { if (Enabled) { Register(__instance); } } [HarmonyPatch(typeof(ZNetScene), "Awake")] [HarmonyPrefix] private static void ZNetScene_Awake_Prefix(ZNetScene __instance) { if (Enabled && !((Object)(object)s_prefab == (Object)null) && !__instance.m_prefabs.Contains(s_prefab)) { __instance.m_prefabs.Add(s_prefab); } } [HarmonyPatch(typeof(Localization), "SetupLanguage")] [HarmonyPostfix] private static void Localization_SetupLanguage_Postfix(Localization __instance) { if (Enabled) { AddWords(__instance); } } private static void Register(ObjectDB db) { if (db.m_items.Count != 0 && (!((Object)(object)s_prefab == (Object)null) || CreatePrefab(db))) { bool flag = false; if (!db.m_items.Contains(s_prefab)) { db.m_items.Add(s_prefab); flag = true; } if ((Object)(object)s_recipe == (Object)null) { s_recipe = CreateRecipe(db); } if ((Object)(object)s_recipe != (Object)null && !db.m_recipes.Contains(s_recipe)) { db.m_recipes.Add(s_recipe); } if (flag) { UpdateRegisters.Invoke(db, null); } if (Localization.instance != null) { AddWords(Localization.instance); } } } private static bool CreatePrefab(ObjectDB db) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Expected O, but got Unknown //IL_00c0: Unknown result type (might be due to invalid IL or missing references) GameObject itemPrefab = db.GetItemPrefab("SpearChitin"); if ((Object)(object)itemPrefab == (Object)null) { GlorpheimPlugin.Log.LogWarning((object)"PortalHarpoon: item prefab 'SpearChitin' not found, item not added"); return false; } s_holder = new GameObject("glorpheim_prefabs"); s_holder.SetActive(false); Object.DontDestroyOnLoad((Object)(object)s_holder); s_prefab = Object.Instantiate<GameObject>(itemPrefab, s_holder.transform); ((Object)s_prefab).name = "PortalHarpoon"; SharedData shared = s_prefab.GetComponent<ItemDrop>().m_itemData.m_shared; shared.m_name = "$item_portalharpoon"; shared.m_description = "$item_portalharpoon_description"; Sprite[] array = (Sprite[])(object)new Sprite[shared.m_icons.Length]; for (int i = 0; i < array.Length; i++) { array[i] = shared.m_icons[i]; try { array[i] = TintSprite(shared.m_icons[i], IconTint) ?? shared.m_icons[i]; } catch (Exception ex) { GlorpheimPlugin.Log.LogWarning((object)("PortalHarpoon: could not tint icon, using the Abyssal Harpoon one: " + ex.Message)); } } shared.m_icons = array; return true; } private static Recipe CreateRecipe(ObjectDB db) { //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Expected O, but got Unknown //IL_010a: 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_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Expected O, but got Unknown ItemDrop item = GetItem(db, "SpearChitin"); ItemDrop item2 = GetItem(db, "GreydwarfEye"); ItemDrop item3 = GetItem(db, "SurtlingCore"); if ((Object)(object)item == (Object)null || (Object)(object)item2 == (Object)null || (Object)(object)item3 == (Object)null) { GlorpheimPlugin.Log.LogWarning((object)"PortalHarpoon: recipe ingredients missing, item cannot be crafted"); return null; } CraftingStation val = FindStation(db, "piece_workbench") ?? db.GetRecipe(item.m_itemData)?.m_craftingStation; Recipe val2 = ScriptableObject.CreateInstance<Recipe>(); ((Object)val2).name = "Recipe_PortalHarpoon"; val2.m_item = s_prefab.GetComponent<ItemDrop>(); val2.m_amount = 1; val2.m_enabled = true; val2.m_craftingStation = val; val2.m_repairStation = val; val2.m_minStationLevel = 1; val2.m_resources = (Requirement[])(object)new Requirement[3] { new Requirement { m_resItem = item, m_amount = 1, m_amountPerLevel = 0 }, new Requirement { m_resItem = item2, m_amount = 20, m_amountPerLevel = 10 }, new Requirement { m_resItem = item3, m_amount = 5, m_amountPerLevel = 2 } }; return val2; } private static ItemDrop GetItem(ObjectDB db, string prefabName) { GameObject itemPrefab = db.GetItemPrefab(prefabName); if (!((Object)(object)itemPrefab != (Object)null)) { return null; } return itemPrefab.GetComponent<ItemDrop>(); } private static CraftingStation FindStation(ObjectDB db, string prefabName) { foreach (Recipe recipe in db.m_recipes) { CraftingStation craftingStation = recipe.m_craftingStation; if ((Object)(object)craftingStation != (Object)null && ((Object)craftingStation).name == prefabName) { return craftingStation; } } return null; } private static void AddWords(Localization localization) { foreach (KeyValuePair<string, string> word in Words) { AddWord.Invoke(localization, new object[2] { word.Key, word.Value }); } } private static Sprite TintSprite(Sprite sprite, Color tint) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Expected O, but got Unknown //IL_009e: 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_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0109: 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_015d: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)sprite == (Object)null || (Object)(object)sprite.texture == (Object)null || (int)SystemInfo.graphicsDeviceType == 4) { return null; } Texture2D texture = sprite.texture; Rect textureRect = sprite.textureRect; int num = Mathf.RoundToInt(((Rect)(ref textureRect)).width); int num2 = Mathf.RoundToInt(((Rect)(ref textureRect)).height); if (num <= 0 || num2 <= 0) { return null; } RenderTexture active = RenderTexture.active; RenderTexture temporary = RenderTexture.GetTemporary(((Texture)texture).width, ((Texture)texture).height, 0, (RenderTextureFormat)0, (RenderTextureReadWrite)2); Texture2D val; try { Graphics.Blit((Texture)(object)texture, temporary); RenderTexture.active = temporary; val = new Texture2D(num, num2, (TextureFormat)4, false); val.ReadPixels(new Rect(((Rect)(ref textureRect)).x, ((Rect)(ref textureRect)).y, (float)num, (float)num2), 0, 0); } finally { RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); } Color[] pixels = val.GetPixels(); for (int i = 0; i < pixels.Length; i++) { Color val2 = pixels[i]; pixels[i] = new Color(val2.r * tint.r, val2.g * tint.g, val2.b * tint.b, val2.a); } val.SetPixels(pixels); val.Apply(); ((Object)val).name = ((Object)sprite.texture).name + "_portal"; Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)num, (float)num2), new Vector2(0.5f, 0.5f), sprite.pixelsPerUnit); ((Object)obj).name = ((Object)sprite).name + "_portal"; return obj; } } } namespace Glorpheim.Features.ItemLink { [HarmonyPatch] internal static class ChatCursor { private static bool Enabled => GlorpheimPlugin.Cfg.ItemLinkEnabled.Value; private static bool ChatFocused { get { if ((Object)(object)Chat.instance != (Object)null) { return Chat.instance.HasFocus(); } return false; } } [HarmonyPatch(typeof(GameCamera), "UpdateMouseCapture")] [HarmonyPostfix] private static void GameCamera_UpdateMouseCapture_Postfix() { if (Enabled && ChatFocused) { ZCursor.LockState = (CursorLockMode)0; ZCursor.Show(); } } [HarmonyPatch(typeof(ZInput), "TryGetKeyStateLowLevel")] [HarmonyPrefix] private static bool ZInput_TryGetKeyStateLowLevel_Prefix(KeyCode keyCode, ref bool __result) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Invalid comparison between Unknown and I4 if (!Enabled || (int)keyCode != 323 || !ChatFocused || !PointerOverChat()) { return true; } __result = false; return false; } private static bool PointerOverChat() { //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) Chat instance = Chat.instance; RectTransform val = (((Object)(object)instance != (Object)null) ? ((Terminal)instance).m_chatWindow : null); if ((Object)(object)val == (Object)null || !((Component)val).gameObject.activeInHierarchy) { return false; } Canvas componentInParent = ((Component)val).GetComponentInParent<Canvas>(); Camera val2 = (((Object)(object)componentInParent == (Object)null || (int)componentInParent.renderMode == 0) ? null : componentInParent.worldCamera); return RectTransformUtility.RectangleContainsScreenPoint(val, Vector2.op_Implicit(ZInput.pointerPosition), val2); } } [HarmonyPatch] internal static class ChatLinks { private sealed class Pending { public long Sender; public List<(string Label, ItemData Item)> Links; public float ArrivedAt; } private const string LinkPrefix = "glorpheim:"; private const string LinkColor = "#8FD3FF"; private const float PendingSeconds = 15f; private const int MaxLinks = 256; private const int RetrofitDepth = 10; private static readonly FieldRef<Terminal, List<string>> ChatBuffer = AccessTools.FieldRefAccess<Terminal, List<string>>("m_chatBuffer"); private static readonly Action<Terminal> UpdateChat = AccessTools.MethodDelegate<Action<Terminal>>(AccessTools.Method(typeof(Terminal), "UpdateChat", (Type[])null, (Type[])null), (object)null, true); private static readonly List<Pending> s_pending = new List<Pending>(); private static readonly Dictionary<int, ItemData> s_links = new Dictionary<int, ItemData>(); private static readonly Queue<int> s_linkOrder = new Queue<int>(); private static int s_nextId; private static readonly Dictionary<PlatformUserID, long> s_senders = new Dictionary<PlatformUserID, long>(); private static readonly List<(string Line, long Sender)> s_recentLines = new List<(string, long)>(); private static GameObject s_tooltip; private static GameObject s_tooltipPrefab; private static Vector3 s_tooltipBodyPosition; internal static void Clear() { s_pending.Clear(); s_links.Clear(); s_linkOrder.Clear(); s_senders.Clear(); s_recentLines.Clear(); HideTooltip(); } internal static void Add(long sender, List<(string Label, ItemData Item)> links) { PrunePending(); Pending pending = new Pending { Sender = sender, Links = links, ArrivedAt = Time.realtimeSinceStartup }; s_pending.Add(pending); Retrofit(pending); } [HarmonyPatch(typeof(Terminal), "AddString", new Type[] { typeof(PlatformUserID), typeof(string), typeof(Type), typeof(bool) })] [HarmonyPrefix] private static void Terminal_AddString_Prefix(Terminal __instance, PlatformUserID user, ref string text, out (long Sender, string LastLine) __state) { /