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 DvergrCraftsmanship v1.0.0
DvergrCraftsmanship.dll
Decompiled 3 days agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("DvergrCraftsmanship")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Building piece structural integrity scales with the placer's Crafting skill.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+f3756847c415b2999f2881c9dc56dd5b204d5c17")] [assembly: AssemblyProduct("DvergrCraftsmanship")] [assembly: AssemblyTitle("DvergrCraftsmanship")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.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 DvergrCraftsmanship { internal static class CraftsmanshipService { private static readonly MethodInfo CheckCanRemovePieceMethod = AccessTools.Method(typeof(Player), "CheckCanRemovePiece", (Type[])null, (Type[])null); private static readonly MethodInfo GetBuildStaminaMethod = AccessTools.Method(typeof(Player), "GetBuildStamina", (Type[])null, (Type[])null); private static readonly MethodInfo ClearCachedSupportMethod = AccessTools.Method(typeof(WearNTear), "ClearCachedSupport", (Type[])null, (Type[])null); private static readonly FieldInfo ClearCachedSupportField = AccessTools.Field(typeof(WearNTear), "m_clearCachedSupport"); private static readonly FieldInfo SkillsPlayerField = AccessTools.Field(typeof(Skills), "m_player"); private static readonly FieldInfo CharacterZanimField = AccessTools.Field(typeof(Character), "m_zanim"); private static readonly FieldInfo HudHoverNameField = AccessTools.Field(typeof(Hud), "m_hoverName"); private static bool s_hasPendingPlacement; private static long s_pendingPlayerId; private static float s_pendingSkillLevel; private static float s_pendingMultiplier; internal static void CapturePlacementSkill(Player player) { s_hasPendingPlacement = false; if (IsEnabled() && !((Object)(object)player == (Object)null)) { float craftingSkillLevel = GetCraftingSkillLevel(player); s_pendingPlayerId = player.GetPlayerID(); s_pendingSkillLevel = craftingSkillLevel; s_pendingMultiplier = ComputeMultiplier(craftingSkillLevel); s_hasPendingPlacement = true; } } internal static void ClearPendingPlacement() { s_hasPendingPlacement = false; } internal static void StampPieceFromPendingPlacement(Piece piece, long creator) { if (!s_hasPendingPlacement || (Object)(object)piece == (Object)null || creator != s_pendingPlayerId) { return; } try { WearNTear component = ((Component)piece).GetComponent<WearNTear>(); if ((Object)(object)component != (Object)null) { StampWearNTear(component, s_pendingSkillLevel, s_pendingMultiplier, force: true); } } finally { ClearPendingPlacement(); } } internal static void RegisterReinforceRpc(WearNTear wear) { if ((Object)(object)wear == (Object)null) { return; } ZNetView component = ((Component)wear).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.GetZDO() != null) { component.Register<float, float>("DvergrCraft_Reinforce", (Action<long, float, float>)delegate(long _, float skillLevel, float multiplier) { TryApplyReinforcement(wear, skillLevel, multiplier); }); } } internal static void ApplyCraftsmanshipToSupportLoss(WearNTear wear, float maxSupport, ref float horizontalLoss, ref float verticalLoss) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) if (!IsEnabled() || (Object)(object)wear == (Object)null || maxSupport <= 0f) { return; } ZNetView component = ((Component)wear).GetComponent<ZNetView>(); bool flag = (Object)(object)component != (Object)null && component.IsValid(); bool flag2 = flag && component.IsOwner(); ZDO val = (flag ? component.GetZDO() : null); string prefabName = Utils.GetPrefabName(((Object)((Component)wear).gameObject).name); if (val == null) { SupportTraceLog($"Support material patch hit for {prefabName}: no valid ZDO, material={wear.m_materialType}, owner={flag2}, validView={flag}, baseMax={maxSupport:0.###}, frame={Time.frameCount}"); return; } float storedMultiplier = GetStoredMultiplier(val, 1f); float num = val.GetFloat(ModConstants.ZdoCraftSkillHash, 0f); float num2 = val.GetFloat(ZDOVars.s_support, -1f); if (storedMultiplier <= 1f) { SupportTraceLog($"Support material patch hit for {prefabName}: no bonus, material={wear.m_materialType}, owner={flag2}, skill={num:0.#}, multiplier={storedMultiplier:0.###}, max={maxSupport:0.###}, hLoss={horizontalLoss:0.###}, vLoss={verticalLoss:0.###}, currentSupport={num2:0.###}, frame={Time.frameCount}"); } else { float num3 = horizontalLoss; float num4 = verticalLoss; horizontalLoss /= storedMultiplier; verticalLoss /= storedMultiplier; SupportTraceLog($"Support material patch hit for {prefabName}: material={wear.m_materialType}, owner={flag2}, skill={num:0.#}, multiplier={storedMultiplier:0.###}, max={maxSupport:0.###}, hLoss={num3:0.###}->{horizontalLoss:0.###}, vLoss={num4:0.###}->{verticalLoss:0.###}, currentSupport={num2:0.###}, frame={Time.frameCount}"); } } internal static bool TryHandleReinforceRepair(Player player, ItemData toolItem, Piece repairPiece) { if (!IsEnabled() || !ModConfig.EnableReinforce.Value || (Object)(object)player == (Object)null || toolItem == null) { return false; } if (!((Character)player).InPlaceMode()) { return false; } Piece hoveringPiece = player.GetHoveringPiece(); if ((Object)(object)hoveringPiece == (Object)null) { DebugLog("Reinforce skipped: no hovering piece."); return false; } WearNTear component = ((Component)hoveringPiece).GetComponent<WearNTear>(); if ((Object)(object)component == (Object)null || !IsFullHealth(component)) { return false; } float craftingSkillLevel = GetCraftingSkillLevel(player); float num = ComputeMultiplier(craftingSkillLevel); if (!CanImprove(component, craftingSkillLevel, num)) { DebugLog($"Reinforce skipped: Crafting {craftingSkillLevel:0} / x{num:0.###} not enough above stored " + $"(need +{ModConfig.MinimumReinforceSkillDelta.Value} skill)."); return false; } if (!HasRepairAccess(player, hoveringPiece)) { return true; } if (!RequestReinforcement(component, craftingSkillLevel, num)) { return false; } ConsumeRepairSwing(player, hoveringPiece, toolItem, craftingSkillLevel, num); return true; } internal static int GetCraftingSkillLevelForTierNotification(Skills skills) { if (!IsEnabled() || !ModConfig.EnableTierNotifications.Value || (Object)(object)skills == (Object)null) { return -1; } return Mathf.FloorToInt(skills.GetSkillLevel((SkillType)107)); } internal static void ShowTierNotification(Skills skills, int oldLevel) { if (oldLevel < 0 || !IsEnabled() || !ModConfig.EnableTierNotifications.Value || (Object)(object)skills == (Object)null) { return; } int newLevel = Mathf.FloorToInt(skills.GetSkillLevel((SkillType)107)); int crossedTierThreshold = GetCrossedTierThreshold(oldLevel, newLevel); if (crossedTierThreshold > 0) { object? obj = SkillsPlayerField?.GetValue(skills); Player val = (Player)((obj is Player) ? obj : null); if (!((Object)(object)val == (Object)null)) { ((Character)val).Message((MessageType)1, "Dvergr Craftsmanship: " + GetTierName(crossedTierThreshold) + " reached. Future builds gain stronger integrity.", 0, (Sprite)null, false); } } } internal static void AppendIntegrityHoverText(Hud hud, Player player) { if (!IsEnabled()) { return; } ConfigEntry<bool> showIntegrityHoverText = ModConfig.ShowIntegrityHoverText; if (showIntegrityHoverText == null || !showIntegrityHoverText.Value || (Object)(object)hud == (Object)null || (Object)(object)player == (Object)null) { return; } Piece hoveringPiece = player.GetHoveringPiece(); if ((Object)(object)hoveringPiece == (Object)null) { return; } WearNTear component = ((Component)hoveringPiece).GetComponent<WearNTear>(); if ((Object)(object)component == (Object)null) { return; } ZDO zdo = GetZdo(component); if (zdo == null) { return; } float storedMultiplier = GetStoredMultiplier(zdo, 0f); if (storedMultiplier <= 0f) { return; } float num = zdo.GetFloat(ModConstants.ZdoCraftSkillHash, 0f); string text = ((Localization.instance != null) ? Localization.instance.Localize(hoveringPiece.m_name) : hoveringPiece.m_name); string arg = FormatBonusPercent(GetSupportLossReductionPercent(storedMultiplier)); string text2 = $"{arg}% support loss (Crafting {num:0})"; object obj = HudHoverNameField?.GetValue(hud); if (obj != null) { PropertyInfo property = obj.GetType().GetProperty("text"); if (!(property == null) && property.CanRead && property.CanWrite) { string text3 = property.GetValue(obj) as string; string value = (string.IsNullOrWhiteSpace(text3) ? (text + "\n" + text2) : (text3 + "\n" + text2)); property.SetValue(obj, value); } } } private static bool IsEnabled() { return ModConfig.EnableMod?.Value ?? false; } private static float GetStoredMultiplier(ZDO zdo, float defaultValue) { if (zdo == null) { return defaultValue; } return zdo.GetFloat(ModConstants.ZdoIntegrityMultiplierHash, defaultValue); } private static float GetSupportLossReductionPercent(float multiplier) { if (!(multiplier <= 0f)) { return (1f - 1f / multiplier) * 100f; } return 0f; } private static float GetCraftingSkillLevel(Player player) { Skills skills = ((Character)player).GetSkills(); return Mathf.Clamp((skills != null) ? skills.GetSkillLevel((SkillType)107) : 0f, 0f, 100f); } private static float ComputeMultiplier(float skillLevel) { float num = Mathf.Clamp(ModConfig.MaxIntegrityBonusPercent.Value, 20f, 60f); return 1f + Mathf.Clamp01(skillLevel / 100f) * (num / 100f); } private static void StampWearNTear(WearNTear wear, float skillLevel, float multiplier, bool force) { ZNetView component = ((Component)wear).GetComponent<ZNetView>(); if (!((Object)(object)component == (Object)null) && component.IsValid() && component.IsOwner()) { ZDO zDO = component.GetZDO(); if (zDO != null && (force || CanImprove(zDO, skillLevel, multiplier))) { zDO.Set(ModConstants.ZdoCraftSkillHash, skillLevel); zDO.Set(ModConstants.ZdoIntegrityMultiplierHash, multiplier); MarkSupportDirty(wear); DebugLog($"Stamped {((Object)wear).name}: Crafting {skillLevel:0}, integrity x{multiplier:0.###}"); } } } private static bool RequestReinforcement(WearNTear wear, float skillLevel, float multiplier) { ZNetView component = ((Component)wear).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return false; } ZDO zDO = component.GetZDO(); if (zDO == null || !CanImprove(zDO, skillLevel, multiplier)) { return false; } if (component.IsOwner()) { return TryApplyReinforcement(wear, skillLevel, multiplier); } component.InvokeRPC("DvergrCraft_Reinforce", new object[2] { skillLevel, multiplier }); return true; } private static bool TryApplyReinforcement(WearNTear wear, float skillLevel, float multiplier) { ZNetView component = ((Component)wear).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || !component.IsOwner()) { return false; } ZDO zDO = component.GetZDO(); if (zDO == null || !CanImprove(zDO, skillLevel, multiplier)) { return false; } zDO.Set(ModConstants.ZdoCraftSkillHash, skillLevel); zDO.Set(ModConstants.ZdoIntegrityMultiplierHash, multiplier); MarkSupportDirty(wear); DebugLog($"Reinforced {((Object)wear).name}: Crafting {skillLevel:0}, integrity x{multiplier:0.###}"); return true; } private static bool CanImprove(WearNTear wear, float skillLevel, float multiplier) { ZDO zdo = GetZdo(wear); if (zdo != null) { return CanImprove(zdo, skillLevel, multiplier); } return false; } private static bool CanImprove(ZDO zdo, float skillLevel, float multiplier) { float num = zdo.GetFloat(ModConstants.ZdoCraftSkillHash, 0f); float num2 = zdo.GetFloat(ModConstants.ZdoIntegrityMultiplierHash, 1f); int num3 = Mathf.Max(1, ModConfig.MinimumReinforceSkillDelta.Value); if (skillLevel >= num + (float)num3) { return multiplier > num2; } return false; } private static bool HasRepairAccess(Player player, Piece piece) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (!PrivateArea.CheckAccess(((Component)piece).transform.position, 0f, true, false)) { return false; } if (CheckCanRemovePieceMethod == null) { ManualLogSource log = DvergrCraftsmanshipPlugin.Log; if (log != null) { log.LogWarning((object)"Unable to validate build-station repair access; reinforcement skipped."); } return false; } object obj = CheckCanRemovePieceMethod.Invoke(player, new object[1] { piece }); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } private static bool IsFullHealth(WearNTear wear) { ZDO zdo = GetZdo(wear); if (zdo != null) { return zdo.GetFloat(ZDOVars.s_health, wear.m_health) >= wear.m_health; } return false; } private static ZDO GetZdo(WearNTear wear) { if ((Object)(object)wear == (Object)null) { return null; } ZNetView component = ((Component)wear).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return null; } return component.GetZDO(); } private static void MarkSupportDirty(WearNTear wear) { ClearCachedSupportField?.SetValue(wear, true); ClearCachedSupportMethod?.Invoke(wear, Array.Empty<object>()); } private static void ConsumeRepairSwing(Player player, Piece piece, ItemData toolItem, float skillLevel, float multiplier) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) player.FaceLookDirection(); TriggerRepairAnimation(player, toolItem); piece.m_placeEffect.Create(((Component)piece).transform.position, ((Component)piece).transform.rotation, (Transform)null, 1f, -1, default(ZDOID)); string arg = ((Localization.instance != null) ? Localization.instance.Localize(piece.m_name) : piece.m_name); float supportLossReductionPercent = GetSupportLossReductionPercent(multiplier); ((Character)player).Message((MessageType)1, $"Reinforced {arg}: Crafting {skillLevel:0}, support loss -{supportLossReductionPercent:0.#}%", 0, (Sprite)null, false); ConsumeBuildStamina(player); ((Character)player).UseEitr(toolItem.m_shared.m_attack.m_attackEitr); if (toolItem.m_shared.m_useDurability) { toolItem.m_durability -= toolItem.m_shared.m_useDurabilityDrain; } } private static void TriggerRepairAnimation(Player player, ItemData toolItem) { object obj = CharacterZanimField?.GetValue(player); if (obj != null) { AccessTools.Method(obj.GetType(), "SetTrigger", new Type[1] { typeof(string) }, (Type[])null)?.Invoke(obj, new object[1] { toolItem.m_shared.m_attack.m_attackAnimation }); } } private static void ConsumeBuildStamina(Player player) { if (GetBuildStaminaMethod?.Invoke(player, Array.Empty<object>()) is float num) { ((Character)player).UseStamina(num); } } private static int GetCrossedTierThreshold(int oldLevel, int newLevel) { int result = 0; int[] array = new int[4] { 25, 50, 75, 100 }; foreach (int num in array) { if (oldLevel < num && newLevel >= num) { result = num; } } return result; } private static string GetTierName(int threshold) { return threshold switch { 25 => "Apprentice Craftsman", 50 => "Journeyman Craftsman", 75 => "Artisan Craftsman", 100 => "Master Craftsman", _ => "Craftsman", }; } private static string FormatBonusPercent(float value) { if (!(Math.Abs(value - Mathf.Round(value)) < 0.05f)) { return value.ToString("+0.#;-0.#;0"); } return value.ToString("+0;-0;0"); } private static void DebugLog(string message) { ConfigEntry<bool> debugLogging = ModConfig.DebugLogging; if (debugLogging != null && debugLogging.Value) { ManualLogSource log = DvergrCraftsmanshipPlugin.Log; if (log != null) { log.LogInfo((object)message); } } } private static void SupportTraceLog(string message) { DebugLog(message); } } [BepInPlugin("com.cdjensen.dvergrcraftsmanship", "Dvergr Craftsmanship", "1.0.0")] public sealed class DvergrCraftsmanshipPlugin : BaseUnityPlugin { internal static ManualLogSource Log; private Harmony harmony; private void Awake() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; ModConfig.Bind(((BaseUnityPlugin)this).Config); harmony = new Harmony("com.cdjensen.dvergrcraftsmanship"); harmony.PatchAll(typeof(DvergrCraftsmanshipPlugin).Assembly); Log.LogInfo((object)"Dvergr Craftsmanship 1.0.0 loaded."); } private void OnDestroy() { Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } } internal static class ModConfig { internal static ConfigEntry<bool> EnableMod; internal static ConfigEntry<float> MaxIntegrityBonusPercent; internal static ConfigEntry<bool> EnableReinforce; internal static ConfigEntry<int> MinimumReinforceSkillDelta; internal static ConfigEntry<bool> EnableTierNotifications; internal static ConfigEntry<bool> ShowIntegrityHoverText; internal static ConfigEntry<bool> DebugLogging; internal static ConfigEntry<bool> EnableAnalysisMode; internal static ConfigEntry<bool> ShowPrefabName; internal static ConfigEntry<bool> ShowRawStructuralValue; internal static ConfigEntry<bool> ShowCurrentStructuralValue; internal static ConfigEntry<bool> ShowCraftingLossReduction; internal static void Bind(ConfigFile config) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown EnableMod = config.Bind<bool>("DvergrCraftsmanship", "EnableMod", true, "Enable Crafting-skill-based structural integrity bonuses."); MaxIntegrityBonusPercent = config.Bind<float>("DvergrCraftsmanship", "MaxIntegrityBonusPercent", 40f, new ConfigDescription("Maximum craftsmanship bonus at Crafting skill 100. Default 40 means support loss is divided by 1.4 at skill 100.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 60f), Array.Empty<object>())); EnableReinforce = config.Bind<bool>("DvergrCraftsmanship", "EnableReinforce", true, "Allow hammer repair on full-health pieces to reinforce them when the repairer's Crafting skill is high enough."); MinimumReinforceSkillDelta = config.Bind<int>("DvergrCraftsmanship", "MinimumReinforceSkillDelta", 5, new ConfigDescription("Minimum Crafting skill improvement required to reinforce an already-crafted piece.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 100), Array.Empty<object>())); EnableTierNotifications = config.Bind<bool>("DvergrCraftsmanship", "EnableTierNotifications", true, "Show a short message when Crafting reaches Dvergr Craftsmanship thresholds: 25, 50, 75, and 100."); ShowIntegrityHoverText = config.Bind<bool>("DvergrCraftsmanship", "ShowIntegrityHoverText", true, "Show a concise Crafting skill and support-loss reduction line while hammer-hovering crafted pieces."); DebugLogging = config.Bind<bool>("DvergrCraftsmanship", "DebugLogging", false, "Enable verbose debug logging for placement stamps and reinforcement."); EnableAnalysisMode = config.Bind<bool>("Analysis", "EnableAnalysisMode", true, "Show a verbose [Analysis] structural diagnostics block while hammer-hovering any WearNTear piece."); ShowPrefabName = config.Bind<bool>("Analysis", "ShowPrefabName", true, "In analysis mode, show localized display name and real prefab name."); ShowRawStructuralValue = config.Bind<bool>("Analysis", "ShowRawStructuralValue", true, "In analysis mode, show vanilla baseline maxSupport/minSupport/loss values from material type (unmodified by this mod)."); ShowCurrentStructuralValue = config.Bind<bool>("Analysis", "ShowCurrentStructuralValue", true, "In analysis mode, show the piece's live support value from WearNTear.GetSupport()."); ShowCraftingLossReduction = config.Bind<bool>("Analysis", "ShowCraftingLossReduction", true, "In analysis mode, show this mod's Crafting-skill loss reduction when ZDO data exists, otherwise 'no data'."); } } internal static class ModConstants { internal const string ModName = "Dvergr Craftsmanship"; internal const string ModVersion = "1.0.0"; internal const string ModGuid = "com.cdjensen.dvergrcraftsmanship"; internal const string ConfigFolder = "DvergrCraftsmanship"; internal const string AnalysisConfigFolder = "Analysis"; internal const string ZdoIntegrityMultiplier = "DvergrCraft_IntegrityMult"; internal const string ZdoCraftSkill = "DvergrCraft_CraftSkill"; internal const string RpcReinforce = "DvergrCraft_Reinforce"; internal static readonly int ZdoIntegrityMultiplierHash = StringExtensionMethods.GetStableHashCode("DvergrCraft_IntegrityMult"); internal static readonly int ZdoCraftSkillHash = StringExtensionMethods.GetStableHashCode("DvergrCraft_CraftSkill"); } internal static class StructuralAnalysis { private static readonly FieldInfo HudHoverNameField = AccessTools.Field(typeof(Hud), "m_hoverName"); private static readonly MethodInfo GetSupportMethod = AccessTools.Method(typeof(WearNTear), "GetSupport", (Type[])null, (Type[])null); internal static void AppendHoverText(Hud hud, Player player) { //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) ConfigEntry<bool> enableAnalysisMode = ModConfig.EnableAnalysisMode; if (enableAnalysisMode == null || !enableAnalysisMode.Value || (Object)(object)hud == (Object)null || (Object)(object)player == (Object)null) { return; } Piece hoveringPiece = player.GetHoveringPiece(); if ((Object)(object)hoveringPiece == (Object)null) { return; } WearNTear component = ((Component)hoveringPiece).GetComponent<WearNTear>(); if (!((Object)(object)component == (Object)null) && TryGetHoverTextProperty(hud, out var hoverName, out var textProperty, out var current)) { List<string> list = new List<string> { "[Analysis]" }; ConfigEntry<bool> showPrefabName = ModConfig.ShowPrefabName; if (showPrefabName != null && showPrefabName.Value) { string text = ((Localization.instance != null) ? Localization.instance.Localize(hoveringPiece.m_name) : hoveringPiece.m_name); string prefabName = Utils.GetPrefabName(((Object)((Component)component).gameObject).name); list.Add(text + " | prefab: " + prefabName); } ConfigEntry<bool> showRawStructuralValue = ModConfig.ShowRawStructuralValue; if (showRawStructuralValue != null && showRawStructuralValue.Value) { GetVanillaBaseline(component.m_materialType, out var maxSupport, out var minSupport, out var horizontalLoss, out var verticalLoss); list.Add($"Raw: max={maxSupport:0.###} min={minSupport:0.###} " + $"hLoss={horizontalLoss:0.###} vLoss={verticalLoss:0.###} ({component.m_materialType})"); } ConfigEntry<bool> showCurrentStructuralValue = ModConfig.ShowCurrentStructuralValue; if (showCurrentStructuralValue != null && showCurrentStructuralValue.Value) { list.Add($"Current support: {GetCurrentSupport(component):0.###}"); } ConfigEntry<bool> showCraftingLossReduction = ModConfig.ShowCraftingLossReduction; if (showCraftingLossReduction != null && showCraftingLossReduction.Value) { list.Add(FormatCraftingReduction(component)); } if (list.Count > 1) { string text2 = string.Join("\n", list); string value = (string.IsNullOrWhiteSpace(current) ? text2 : (current + "\n" + text2)); textProperty.SetValue(hoverName, value); } } } private static bool TryGetHoverTextProperty(Hud hud, out object hoverName, out PropertyInfo textProperty, out string current) { hoverName = HudHoverNameField?.GetValue(hud); textProperty = null; current = null; if (hoverName == null) { return false; } textProperty = hoverName.GetType().GetProperty("text"); if (textProperty == null || !textProperty.CanRead || !textProperty.CanWrite) { return false; } current = textProperty.GetValue(hoverName) as string; return true; } private static float GetCurrentSupport(WearNTear wear) { if ((Object)(object)wear == (Object)null || GetSupportMethod == null) { return 0f; } object obj = GetSupportMethod.Invoke(wear, null); if (obj is float) { return (float)obj; } return 0f; } private static string FormatCraftingReduction(WearNTear wear) { ZNetView component = ((Component)wear).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid()) { return "Crafting reduction: no data"; } ZDO zDO = component.GetZDO(); if (zDO == null) { return "Crafting reduction: no data"; } float num = zDO.GetFloat(ModConstants.ZdoIntegrityMultiplierHash, 0f); if (num <= 1f) { return "Crafting reduction: no data"; } float num2 = zDO.GetFloat(ModConstants.ZdoCraftSkillHash, 0f); float num3 = (1f - 1f / num) * 100f; return $"Crafting reduction: {num3:0.#}% support loss (Crafting {num2:0})"; } private static void GetVanillaBaseline(MaterialType materialType, out float maxSupport, out float minSupport, out float horizontalLoss, out float verticalLoss) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected I4, but got Unknown switch ((int)materialType) { case 0: maxSupport = 100f; minSupport = 10f; verticalLoss = 0.125f; horizontalLoss = 0.2f; break; case 3: maxSupport = 140f; minSupport = 10f; verticalLoss = 0.1f; horizontalLoss = 1f / 6f; break; case 1: maxSupport = 1000f; minSupport = 100f; verticalLoss = 0.125f; horizontalLoss = 1f; break; case 2: maxSupport = 1500f; minSupport = 20f; verticalLoss = 1f / 13f; horizontalLoss = 1f / 13f; break; case 4: maxSupport = 1500f; minSupport = 100f; verticalLoss = 0.125f; horizontalLoss = 0.5f; break; case 5: maxSupport = 2000f; minSupport = 100f; verticalLoss = 0.1f; horizontalLoss = 1f / 3f; break; case 6: maxSupport = 5000f; minSupport = 100f; verticalLoss = 1f / 15f; horizontalLoss = 0.25f; break; case 7: maxSupport = 1000f; minSupport = 100f; verticalLoss = 0.125f; horizontalLoss = 1f / 3f; break; case 8: maxSupport = 200f; minSupport = 10f; verticalLoss = 1f / 13f; horizontalLoss = 0.2f; break; default: maxSupport = 0f; minSupport = 0f; verticalLoss = 0f; horizontalLoss = 0f; break; } } } } namespace DvergrCraftsmanship.Patches { [HarmonyPatch(typeof(Player), "PlacePiece")] internal static class PlayerPlacePiecePatch { private static void Prefix(Player __instance) { CraftsmanshipService.CapturePlacementSkill(__instance); } private static void Finalizer() { CraftsmanshipService.ClearPendingPlacement(); } } [HarmonyPatch(typeof(Piece), "SetCreator")] internal static class PieceSetCreatorPatch { private static void Postfix(Piece __instance, long uid) { CraftsmanshipService.StampPieceFromPendingPlacement(__instance, uid); } } [HarmonyPatch(typeof(WearNTear), "Awake")] internal static class WearNTearAwakePatch { private static void Postfix(WearNTear __instance) { CraftsmanshipService.RegisterReinforceRpc(__instance); } } [HarmonyPatch(typeof(WearNTear), "GetMaterialProperties")] internal static class WearNTearGetMaterialPropertiesPatch { private static void Postfix(WearNTear __instance, ref float maxSupport, ref float minSupport, ref float horizontalLoss, ref float verticalLoss) { CraftsmanshipService.ApplyCraftsmanshipToSupportLoss(__instance, maxSupport, ref horizontalLoss, ref verticalLoss); } } [HarmonyPatch(typeof(Player), "Repair")] internal static class PlayerRepairPatch { private static bool Prefix(Player __instance, ItemData toolItem, Piece repairPiece) { return !CraftsmanshipService.TryHandleReinforceRepair(__instance, toolItem, repairPiece); } } [HarmonyPatch(typeof(Hud), "UpdateCrosshair")] internal static class HudUpdateCrosshairPatch { private static void Postfix(Hud __instance, Player player) { CraftsmanshipService.AppendIntegrityHoverText(__instance, player); StructuralAnalysis.AppendHoverText(__instance, player); } } [HarmonyPatch(typeof(Skills), "RaiseSkill")] internal static class SkillsRaiseSkillPatch { private static void Prefix(Skills __instance, SkillType skillType, ref int __state) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Invalid comparison between Unknown and I4 __state = (((int)skillType == 107) ? CraftsmanshipService.GetCraftingSkillLevelForTierNotification(__instance) : (-1)); } private static void Postfix(Skills __instance, SkillType skillType, int __state) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Invalid comparison between Unknown and I4 if ((int)skillType == 107) { CraftsmanshipService.ShowTierNotification(__instance, __state); } } } }