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 v0.1.0
DvergrCraftsmanship.dll
Decompiled a day agousing System; 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("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0+bee29c368a3b3a04c8242bab80c2c7dd5e5d3f95")] [assembly: AssemblyProduct("DvergrCraftsmanship")] [assembly: AssemblyTitle("DvergrCraftsmanship")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.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) { 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) { return false; } WearNTear component = ((Component)hoveringPiece).GetComponent<WearNTear>(); if ((Object)(object)component == (Object)null || !IsFullHealth(component)) { return false; } float craftingSkillLevel = GetCraftingSkillLevel(player); float multiplier = ComputeMultiplier(craftingSkillLevel); if (!CanImprove(component, craftingSkillLevel, multiplier)) { return false; } if (!HasRepairAccess(player, hoveringPiece)) { return true; } if (!RequestReinforcement(component, craftingSkillLevel, multiplier)) { return false; } ConsumeRepairSwing(player, hoveringPiece, toolItem, craftingSkillLevel, multiplier); 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); } } } 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; } ZDO zdo = GetZdo(((Component)hoveringPiece).GetComponent<WearNTear>()); 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) { 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) player.FaceLookDirection(); TriggerRepairAnimation(player, toolItem); piece.m_placeEffect.Create(((Component)piece).transform.position, ((Component)piece).transform.rotation, (Transform)null, 1f, -1); 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); 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", "0.1.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 0.1.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 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."); } } internal static class ModConstants { internal const string ModName = "Dvergr Craftsmanship"; internal const string ModVersion = "0.1.0"; internal const string ModGuid = "com.cdjensen.dvergrcraftsmanship"; internal const string ConfigFolder = "DvergrCraftsmanship"; 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"); } } 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, float maxSupport, 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) { return !CraftsmanshipService.TryHandleReinforceRepair(__instance, toolItem); } } [HarmonyPatch(typeof(Hud), "UpdateCrosshair")] internal static class HudUpdateCrosshairPatch { private static void Postfix(Hud __instance, Player player) { CraftsmanshipService.AppendIntegrityHoverText(__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); } } } }