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 Hearthmend v1.0.3
plugins/Hearthmend.dll
Decompiled 2 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Jotunn; using Jotunn.Entities; using Jotunn.Managers; using Jotunn.Utils; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyCompany("blackhearthx")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Station auto-repair for the homestead. Each craft station mends what it would fix with the hammer, ships and carts included.")] [assembly: AssemblyFileVersion("1.0.3.0")] [assembly: AssemblyInformationalVersion("1.0.3+c17d3fa031bce2e2b809047b47945fe64757c5a7")] [assembly: AssemblyProduct("Hearthmend")] [assembly: AssemblyTitle("Hearthmend")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.3.0")] [module: UnverifiableCode] [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 Hearthmend { internal static class ModLocalization { internal static void Register() { CustomLocalization localization = LocalizationManager.Instance.GetLocalization(); int num = 0; string[] array = new string[3] { "English", "Portuguese_Brazilian", "Portuguese_European" }; foreach (string language in array) { if (TryLoad(localization, language)) { num++; } } if (num == 0) { string text = "English"; localization.AddTranslation(ref text, FallbackEnglish()); Logger.LogWarning((object)"Hearthmend: Translations folder missing, using the English fallback"); } } private static Dictionary<string, string> FallbackEnglish() { return new Dictionary<string, string> { { "hearthmend_hover", "\n[<color=yellow><b>Hold $KEY_Use</b></color>] Hearthmend: {0}" }, { "hearthmend_on", "<color=#55FF55>on</color>" }, { "hearthmend_off", "<color=#FF5555>off</color>" }, { "hearthmend_toggle_on", "Hearthmend is watching this station" }, { "hearthmend_toggle_off", "Hearthmend won't touch this station" }, { "hearthmend_repaired", "Mended {0} pieces" }, { "hearthmend_morning", "Woke up to {0} pieces mended" } }; } private static bool TryLoad(CustomLocalization loc, string language) { try { string text = FindPath(language); if (string.IsNullOrEmpty(text) || !File.Exists(text)) { return false; } loc.AddJsonFile(language, File.ReadAllText(text)); return true; } catch (Exception ex) { Logger.LogWarning((object)("Hearthmend: failed loading " + language + ": " + ex.Message)); return false; } } private static string FindPath(string language) { string path = Path.Combine("Translations", language, "hearthmend.json"); string text = Path.Combine(Path.GetDirectoryName(typeof(HearthmendPlugin).Assembly.Location) ?? "", path); if (File.Exists(text)) { return text; } string text2 = Path.Combine(Directory.GetCurrentDirectory(), path); if (!File.Exists(text2)) { return null; } return text2; } internal static string L(string token, params object[] args) { string text = ((Localization.instance != null) ? Localization.instance.Localize("$" + token) : ("$" + token)); if (args == null || args.Length == 0) { return text; } try { return string.Format(text, args); } catch { return text; } } } [BepInPlugin("com.blackhearthx.hearthmend", "Hearthmend", "1.0.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class HearthmendPlugin : BaseUnityPlugin { public const string PluginGUID = "com.blackhearthx.hearthmend"; public const string PluginName = "Hearthmend"; public const string PluginVersion = "1.0.3"; private Harmony _harmony; internal static int PieceMask { get; private set; } internal static HearthmendPlugin Instance { get; private set; } private void Awake() { //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown Instance = this; PieceMask = LayerMask.GetMask(new string[6] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "vehicle" }); PluginConfig.Bind(((BaseUnityPlugin)this).Config); ModLocalization.Register(); PrefabManager.OnVanillaPrefabsAvailable += OnVanillaPrefabsAvailable; _harmony = new Harmony("com.blackhearthx.hearthmend"); _harmony.PatchAll(); Logger.LogInfo((object)"Hearthmend 1.0.3 loaded"); } private void Update() { RepairService.UpdateTimerLoop(); } private static void OnVanillaPrefabsAvailable() { PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable; RepairService.RefreshBuildStationCatalog(); } private void OnDestroy() { PrefabManager.OnVanillaPrefabsAvailable -= OnVanillaPrefabsAvailable; Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal static class PluginConfig { internal static ConfigEntry<bool> ModEnabled; internal static ConfigEntry<float> RepairRadius; internal static ConfigEntry<float> MendEvery; internal static ConfigEntry<bool> MendOnWake; internal static ConfigEntry<bool> AllowRepairOther; internal static ConfigEntry<bool> RespectWards; internal static ConfigEntry<bool> ShowNotification; internal static void Bind(ConfigFile cfg) { ModEnabled = cfg.Bind<bool>("1. General", "Mod Enabled", true, "Turn Hearthmend on or off for this profile."); RepairRadius = cfg.Bind<float>("2. Repair", "Repair Radius", 20f, "How far from a watching station (workbench, forge, stonecutter and so on) pieces get mended."); MendEvery = cfg.Bind<float>("2. Repair", "Mend Every (s)", 30f, "While you are near a watching station, it mends the damage around it this often. 0 turns daytime mending off."); MendOnWake = cfg.Bind<bool>("2. Repair", "Mend On Wake", true, "Every station watching near you also mends when you wake up from sleep."); AllowRepairOther = cfg.Bind<bool>("2. Repair", "Allow Repair Other", true, "Also mend pieces built by other players."); RespectWards = cfg.Bind<bool>("2. Repair", "Respect Wards", true, "Skip pieces inside wards you are not allowed to build in."); ShowNotification = cfg.Bind<bool>("3. UI", "Show Notification", true, "Show a small HUD note when something gets mended."); } } internal static class RepairService { internal const string ZdoKey = "BHX_Hearthmend"; private const float HoldRequiredSeconds = 0.6f; private const float TimerScanPeriod = 0.25f; private const float MendGapSeconds = 0.15f; private const float MaxWaveSeconds = 6f; private const float TimerJitterSeconds = 3f; private static readonly List<WearNTear> PendingMends = new List<WearNTear>(256); private static readonly FieldInfo AllStationsField = AccessTools.Field(typeof(CraftingStation), "m_allStations"); private static readonly Collider[] OverlapBuffer = (Collider[])(object)new Collider[4096]; private static bool _warnedBufferFull; private static readonly HashSet<Piece> ProcessedPieces = new HashSet<Piece>(); private static readonly Dictionary<CraftingStation, float> StationTimers = new Dictionary<CraftingStation, float>(32); private static readonly HashSet<string> BuildStationNames = new HashSet<string>(); private static float _nextLoopCheckTime; private static float _holdTimer; private static bool _holdExecuted; internal static void RefreshBuildStationCatalog() { ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null || instance.m_prefabs == null) { return; } BuildStationNames.Clear(); for (int i = 0; i < instance.m_prefabs.Count; i++) { GameObject val = instance.m_prefabs[i]; if ((Object)(object)val == (Object)null) { continue; } Piece component = val.GetComponent<Piece>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component.m_craftingStation == (Object)null)) { string name = component.m_craftingStation.m_name; if (!string.IsNullOrEmpty(name)) { BuildStationNames.Add(name); } } } Logger.LogInfo((object)$"Hearthmend: {BuildStationNames.Count} build station type(s) can watch"); } internal static bool IsHearthmendStation(CraftingStation station) { if ((Object)(object)station == (Object)null) { return false; } if (BuildStationNames.Count == 0) { RefreshBuildStationCatalog(); } return BuildStationNames.Contains(station.m_name); } internal static bool PieceBelongsToStation(CraftingStation station, Piece piece) { if ((Object)(object)station == (Object)null || (Object)(object)piece == (Object)null) { return false; } if ((Object)(object)piece.m_craftingStation == (Object)null) { return true; } return piece.m_craftingStation.m_name == station.m_name; } internal static bool GetEnabled(ZNetView nview) { if ((Object)(object)nview != (Object)null && nview.IsValid()) { return nview.GetZDO().GetBool("BHX_Hearthmend", false); } return false; } internal static void SetEnabled(ZNetView nview, bool enabled) { if (!((Object)(object)nview == (Object)null) && nview.IsValid()) { nview.ClaimOwnership(); nview.GetZDO().Set("BHX_Hearthmend", enabled); } } private static List<CraftingStation> GetStationList() { return AllStationsField?.GetValue(null) as List<CraftingStation>; } internal static void ShowMessage(MessageType type, string message) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Player.m_localPlayer != (Object)null) { ((Character)Player.m_localPlayer).Message(type, message, 0, (Sprite)null, false); return; } MessageHud instance = MessageHud.instance; if (instance != null) { instance.ShowMessage(type, message, 0, (Sprite)null, false, true); } } internal static void UpdateTimerLoop() { //IL_0063: 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_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) if (!PluginConfig.ModEnabled.Value || PluginConfig.MendEvery.Value <= 0f || Time.time < _nextLoopCheckTime) { return; } _nextLoopCheckTime = Time.time + 0.25f; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } List<CraftingStation> stationList = GetStationList(); if (stationList == null || stationList.Count == 0) { return; } Vector3 position = ((Component)localPlayer).transform.position; float num = PluginConfig.RepairRadius.Value + 35f; float num2 = num * num; float time = Time.time; for (int i = 0; i < stationList.Count; i++) { CraftingStation val = stationList[i]; if (!IsHearthmendStation(val)) { continue; } Vector3 val2 = ((Component)val).transform.position - position; if (!(((Vector3)(ref val2)).sqrMagnitude > num2)) { ZNetView component = ((Component)val).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid() && GetEnabled(component) && (!StationTimers.TryGetValue(val, out var value) || !(time < value))) { ScheduleNext(val, time); PerformStationRepair(val, suppressMessage: false); } } } } private static void ScheduleNext(CraftingStation station, float now) { StationTimers[station] = now + PluginConfig.MendEvery.Value + Random.Range(0f, 3f); } internal static void TriggerMorningRepair() { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) if (!PluginConfig.ModEnabled.Value || !PluginConfig.MendOnWake.Value) { return; } Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } List<CraftingStation> stationList = GetStationList(); if (stationList == null || stationList.Count == 0) { return; } Vector3 position = ((Component)localPlayer).transform.position; float num = PluginConfig.RepairRadius.Value + 50f; float num2 = num * num; int num3 = 0; int num4 = 0; float time = Time.time; ProcessedPieces.Clear(); for (int i = 0; i < stationList.Count; i++) { CraftingStation val = stationList[i]; if (!IsHearthmendStation(val)) { continue; } Vector3 val2 = ((Component)val).transform.position - position; if (!(((Vector3)(ref val2)).sqrMagnitude > num2)) { ZNetView component = ((Component)val).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid() && GetEnabled(component)) { num4++; ScheduleNext(val, time); num3 += PerformStationRepair(val, suppressMessage: true, shareProcessed: true); } } } Logger.LogInfo((object)$"Hearthmend: woke up, {num4} station(s) watching nearby, {num3} piece(s) to mend"); if (num3 > 0 && PluginConfig.ShowNotification.Value) { ShowMessage((MessageType)1, ModLocalization.L("hearthmend_morning", num3)); } } internal static int PerformStationRepair(CraftingStation station, bool suppressMessage, bool shareProcessed = false) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01d2: 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) if ((Object)(object)station == (Object)null) { return 0; } float value = PluginConfig.RepairRadius.Value; int num = Physics.OverlapSphereNonAlloc(((Component)station).transform.position, value, OverlapBuffer, HearthmendPlugin.PieceMask); if (num == 0) { return 0; } if (num == OverlapBuffer.Length && !_warnedBufferFull) { _warnedBufferFull = true; Logger.LogWarning((object)$"Hearthmend: {OverlapBuffer.Length} colliders around {station.m_name}, some pieces may be skipped. Try a smaller Repair Radius."); } PendingMends.Clear(); if (!shareProcessed) { ProcessedPieces.Clear(); } bool value2 = PluginConfig.AllowRepairOther.Value; bool value3 = PluginConfig.RespectWards.Value; for (int i = 0; i < num; i++) { Collider val = OverlapBuffer[i]; if ((Object)(object)val == (Object)null) { continue; } Piece componentInParent = ((Component)val).GetComponentInParent<Piece>(); if (!((Object)(object)componentInParent == (Object)null) && PieceBelongsToStation(station, componentInParent) && ProcessedPieces.Add(componentInParent) && (value2 || componentInParent.IsCreator()) && (!value3 || PrivateArea.CheckAccess(((Component)componentInParent).transform.position, 0f, false, true))) { WearNTear component = ((Component)componentInParent).GetComponent<WearNTear>(); if (!((Object)(object)component == (Object)null) && !(component.GetHealthPercentage() >= 1f)) { PendingMends.Add(component); } } } int count = PendingMends.Count; if (count == 0) { return 0; } ((MonoBehaviour)HearthmendPlugin.Instance).StartCoroutine(MendInTurn(PendingMends.ToArray())); PendingMends.Clear(); Logger.LogInfo((object)$"Hearthmend: {station.m_name} is mending {count} piece(s)"); if (!suppressMessage && count > 0 && PluginConfig.ShowNotification.Value && (Object)(object)Player.m_localPlayer != (Object)null && Vector3.Distance(((Component)station).transform.position, ((Component)Player.m_localPlayer).transform.position) <= value) { ShowMessage((MessageType)1, ModLocalization.L("hearthmend_repaired", count)); } return count; } private static IEnumerator MendInTurn(WearNTear[] batch) { WaitForSeconds wait = new WaitForSeconds(Mathf.Min(0.15f, 6f / (float)batch.Length)); for (int i = 0; i < batch.Length; i++) { WearNTear val = batch[i]; if ((Object)(object)val != (Object)null && val.Repair()) { PlayMendEffect(val); } if (i < batch.Length - 1) { yield return wait; } } } private static void PlayMendEffect(WearNTear wear) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) Piece component = ((Component)wear).GetComponent<Piece>(); if (!((Object)(object)component == (Object)null) && component.m_placeEffect != null && component.m_placeEffect.HasEffects()) { Transform transform = ((Component)component).transform; component.m_placeEffect.Create(transform.position, transform.rotation, (Transform)null, 1f, -1, default(ZDOID)); } } internal static void AppendHoverHint(CraftingStation station, ref string result) { if (PluginConfig.ModEnabled.Value && IsHearthmendStation(station)) { ZNetView component = ((Component)station).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid()) { string text = (GetEnabled(component) ? ModLocalization.L("hearthmend_on") : ModLocalization.L("hearthmend_off")); string text2 = ModLocalization.L("hearthmend_hover", text); result += ((Localization.instance != null) ? Localization.instance.Localize(text2) : text2); } } } internal static void TickHoldToggle(Player player) { if ((Object)(object)player != (Object)(object)Player.m_localPlayer || !PluginConfig.ModEnabled.Value) { return; } if (!ZInput.GetButton("Use")) { _holdTimer = 0f; _holdExecuted = false; return; } GameObject hoverObject = ((Humanoid)player).GetHoverObject(); if ((Object)(object)hoverObject == (Object)null) { return; } CraftingStation componentInParent = hoverObject.GetComponentInParent<CraftingStation>(); if (!IsHearthmendStation(componentInParent)) { return; } ZNetView component = ((Component)componentInParent).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return; } _holdTimer += Time.deltaTime; if (!(_holdTimer < 0.6f) && !_holdExecuted) { _holdExecuted = true; bool flag = !GetEnabled(component); SetEnabled(component, flag); ShowMessage((MessageType)2, flag ? ModLocalization.L("hearthmend_toggle_on") : ModLocalization.L("hearthmend_toggle_off")); if (flag) { ScheduleNext(componentInParent, Time.time); PerformStationRepair(componentInParent, suppressMessage: false); } } } } [HarmonyPatch(typeof(CraftingStation), "GetHoverText")] internal static class CraftingStation_GetHoverText_Patch { private static void Postfix(CraftingStation __instance, ref string __result) { RepairService.AppendHoverHint(__instance, ref __result); } } [HarmonyPatch(typeof(Player), "Update")] internal static class Player_Update_HoldToggle_Patch { private static void Postfix(Player __instance) { RepairService.TickHoldToggle(__instance); } } [HarmonyPatch(typeof(Player), "SetSleeping")] internal static class Player_SetSleeping_Patch { private static void Postfix(Player __instance, bool sleep) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer && !sleep) { RepairService.TriggerMorningRepair(); } } } }