diff --git a/BuildingDemolish/BepInExPlugin.cs b/BuildingDemolish/BepInExPlugin.cs index cc7c0c8..068d687 100644 --- a/BuildingDemolish/BepInExPlugin.cs +++ b/BuildingDemolish/BepInExPlugin.cs @@ -6,7 +6,7 @@ namespace BuildingDemolish { - [BepInPlugin("aedenthorn.BuildingDemolish", "BuildingDemolish", "0.3.2")] + [BepInPlugin("aedenthorn.BuildingDemolish", "Building Demolish", "0.4.0")] public class BepInExPlugin : BaseUnityPlugin { private static readonly bool isDebug = true; @@ -57,65 +57,70 @@ private void Update() { if (!AedenthornUtils.IgnoreKeyPresses(true) && AedenthornUtils.CheckKeyDown(hotKey.Value)) { - Player player = Player.m_localPlayer; - Dbgl($"Ka-boom"); - Collider[] array = Physics.OverlapSphere(player.transform.position, destroyRadius.Value, destroyMask); - for (int i = 0; i < array.Length; i++) + int count = DemolishPieces(destroyRadius.Value); + Dbgl($"Demolished {count} pieces."); + } + } + + private static int DemolishPieces(float radius) + { + Player player = Player.m_localPlayer; + if (!player) + return 0; + int count = 0; + Collider[] array = Physics.OverlapSphere(player.transform.position, radius, destroyMask); + for (int i = 0; i < array.Length; i++) + { + Piece piece = array[i].GetComponentInParent(); + if (piece) { - Piece piece = array[i].GetComponentInParent(); - if (piece) + if (!piece.IsCreator() && (piece.GetCreator() != 0 || !allowDestroyUncreated.Value)) + { + continue; + } + if (!piece.m_canBeRemoved) + { + continue; + } + if (Location.IsInsideNoBuildLocation(piece.transform.position)) + { + continue; + } + if (!PrivateArea.CheckAccess(piece.transform.position, 0f, true, false)) + { + continue; + } + if (requireCraftingStation.Value && !Traverse.Create(player).Method("CheckCanRemovePiece", new object[] { piece }).GetValue()) + { + continue; + } + ZNetView component = piece.GetComponent(); + if (component == null) + { + continue; + } + if (!piece.CanBeRemoved()) + { + continue; + } + count++; + WearNTear component2 = piece.GetComponent(); + if (component2) + { + component2.Remove(); + } + else { - if (!piece.IsCreator() && (piece.GetCreator() != 0 || !allowDestroyUncreated.Value)) - { - continue; - } - if (!piece.m_canBeRemoved) - { - continue; - } - if (Location.IsInsideNoBuildLocation(piece.transform.position)) - { - continue; - } - if (!PrivateArea.CheckAccess(piece.transform.position, 0f, true, false)) - { - continue; - } - if (requireCraftingStation.Value && !Traverse.Create(player).Method("CheckCanRemovePiece", new object[] { piece }).GetValue()) - { - continue; - } - ZNetView component = piece.GetComponent(); - if (component == null) - { - continue; - } - if (!piece.CanBeRemoved()) - { - continue; - } - WearNTear component2 = piece.GetComponent(); - if (component2) - { - component2.Remove(); - } - else - { - component.ClaimOwnership(); - piece.DropResources(); - piece.m_placeEffect.Create(piece.transform.position, piece.transform.rotation, piece.gameObject.transform, 1f); - player.m_removeEffects.Create(piece.transform.position, Quaternion.identity, null, 1f); - ZNetScene.instance.Destroy(piece.gameObject); - } - ItemDrop.ItemData rightItem = player.GetRightItem(); - if (rightItem != null) - { - player.FaceLookDirection(); - Traverse.Create(player).Field("m_zanim").GetValue().SetTrigger(rightItem.m_shared.m_attack.m_attackAnimation); - } + component.ClaimOwnership(); + piece.DropResources(); + piece.m_placeEffect.Create(piece.transform.position, piece.transform.rotation, piece.gameObject.transform, 1f); + player.m_removeEffects.Create(piece.transform.position, Quaternion.identity, null, 1f); + ZNetScene.instance.Destroy(piece.gameObject); } + } } + return count; } [HarmonyPatch(typeof(Console), "InputText")] @@ -126,14 +131,31 @@ static bool Prefix(Console __instance) if (!modEnabled.Value) return true; string text = __instance.m_input.text; - if (text.ToLower().Equals("buildingdemolish reset")) + if (text.ToLower().Equals($"{typeof(BepInExPlugin).Namespace.ToLower()} reset")) { + Traverse.Create(__instance).Method("AddString", new object[] { text }).GetValue(); context.Config.Reload(); context.Config.Save(); - //if (debugEnabled.Value) - // Player.m_debugMode = true; + Traverse.Create(__instance).Method("AddString", new object[] { $"{context.Info.Metadata.Name} config reloaded" }).GetValue(); + return false; + } + if (text.ToLower().Equals($"{typeof(BepInExPlugin).Namespace.ToLower()} demolish")) + { + Traverse.Create(__instance).Method("AddString", new object[] { text }).GetValue(); + int count = DemolishPieces(destroyRadius.Value); + Traverse.Create(__instance).Method("AddString", new object[] { $"{context.Info.Metadata.Name} demolished {count} pieces" }).GetValue(); + return false; + } + if (text.ToLower().StartsWith($"{typeof(BepInExPlugin).Namespace.ToLower()} demolish ")) + { Traverse.Create(__instance).Method("AddString", new object[] { text }).GetValue(); - Traverse.Create(__instance).Method("AddString", new object[] { "config reloaded" }).GetValue(); + if(int.TryParse(text.Split(' ')[2], out int radius)) + { + int count = DemolishPieces(radius); + Traverse.Create(__instance).Method("AddString", new object[] { $"{context.Info.Metadata.Name} demolished {count} pieces" }).GetValue(); + } + else + Traverse.Create(__instance).Method("AddString", new object[] { $"{context.Info.Metadata.Name} syntax error" }).GetValue(); return false; } return true; diff --git a/BuildingRepair/AedenthornUtils.cs b/BuildingRepair/AedenthornUtils.cs new file mode 100644 index 0000000..f8b100f --- /dev/null +++ b/BuildingRepair/AedenthornUtils.cs @@ -0,0 +1,33 @@ +using UnityEngine; + +public class AedenthornUtils +{ + public static bool IgnoreKeyPresses(bool extra = false) + { + if (!extra) + return ZNetScene.instance == null || Player.m_localPlayer == null || Minimap.IsOpen() || Console.IsVisible() || TextInput.IsVisible() || ZNet.instance.InPasswordDialog() || Chat.instance?.HasFocus() == true; + return ZNetScene.instance == null || Player.m_localPlayer == null || Minimap.IsOpen() || Console.IsVisible() || TextInput.IsVisible() || ZNet.instance.InPasswordDialog() || Chat.instance?.HasFocus() == true || StoreGui.IsVisible() || InventoryGui.IsVisible() || Menu.IsVisible() || TextViewer.instance?.IsVisible() == true; + } + public static bool CheckKeyDown(string value) + { + try + { + return Input.GetKeyDown(value.ToLower()); + } + catch + { + return false; + } + } + public static bool CheckKeyHeld(string value, bool req = true) + { + try + { + return Input.GetKey(value.ToLower()); + } + catch + { + return !req; + } + } +} diff --git a/BuildingRepair/BepInExPlugin.cs b/BuildingRepair/BepInExPlugin.cs new file mode 100644 index 0000000..866099b --- /dev/null +++ b/BuildingRepair/BepInExPlugin.cs @@ -0,0 +1,141 @@ +using BepInEx; +using BepInEx.Configuration; +using HarmonyLib; +using System.Reflection; +using UnityEngine; + +namespace BuildingRepair +{ + [BepInPlugin("aedenthorn.BuildingRepair", "Building Repair", "0.1.1")] + public class BepInExPlugin : BaseUnityPlugin + { + private static readonly bool isDebug = true; + private static BepInExPlugin context; + + public static ConfigEntry modEnabled; + public static ConfigEntry nexusID; + + public static ConfigEntry allowRepairOther; + public static ConfigEntry requireCraftingStation; + public static ConfigEntry repairRadius; + public static ConfigEntry hotKey; + public static ConfigEntry repairMessage; + public static int destroyMask = LayerMask.GetMask(new string[] + { + "Default", + "static_solid", + "Default_small", + "piece", + "piece_nonsolid", + "terrain", + "vehicle" + }); + + public static void Dbgl(string str = "", bool pref = true) + { + if (isDebug) + Debug.Log((pref ? typeof(BepInExPlugin).Namespace + " " : "") + str); + } + private void Awake() + { + context = this; + modEnabled = Config.Bind("General", "Enabled", true, "Enable this mod"); + nexusID = Config.Bind("General", "NexusID", 1277, "Nexus mod ID for updates"); + repairRadius = Config.Bind("General", "RepairRadius", 20, "Radius of repair"); + allowRepairOther = Config.Bind("General", "AllowRepairOther", false, "Aloow repairing other player's pieces"); + requireCraftingStation = Config.Bind("General", "RequireCraftingStation", true, "Require a nearby crafting station to repair corresponding pieces (this is a vanilla requirement)"); + hotKey = Config.Bind("General", "HotKey", "'", "Hotkey to initiate repair"); + repairMessage = Config.Bind("General", "RepairMessage", "Repaired {0} pieces.", "Repair message text."); + + if (!modEnabled.Value) + return; + + //if (debugEnabled.Value) + // Player.m_debugMode = true; + + Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), null); + } + private void Update() + { + if (!AedenthornUtils.IgnoreKeyPresses(true) && AedenthornUtils.CheckKeyDown(hotKey.Value)) + { + int count = repairPieces(repairRadius.Value); + Dbgl($"Repaired {count} pieces."); + } + } + + private static int repairPieces(float radius) + { + Player player = Player.m_localPlayer; + if (!player) + return 0; + int count = 0; + Collider[] array = Physics.OverlapSphere(player.transform.position, radius, destroyMask); + for (int i = 0; i < array.Length; i++) + { + Piece piece = array[i].GetComponentInParent(); + if (piece) + { + if (!piece.IsCreator() && !allowRepairOther.Value) + { + continue; + } + if (requireCraftingStation.Value && !Traverse.Create(player).Method("CheckCanRemovePiece", new object[] { piece }).GetValue()) + { + continue; + } + ZNetView component = piece.GetComponent(); + if (component == null) + { + continue; + } + WearNTear wnt = piece.GetComponent(); + if (!wnt || !wnt.Repair()) + continue; + count++; + } + } + Player.m_localPlayer.Message(MessageHud.MessageType.Center, string.Format(repairMessage.Value, count)); + return count; + } + + [HarmonyPatch(typeof(Console), "InputText")] + static class InputText_Patch + { + static bool Prefix(Console __instance) + { + if (!modEnabled.Value) + return true; + string text = __instance.m_input.text; + if (text.ToLower().Equals($"{typeof(BepInExPlugin).Namespace.ToLower()} reset")) + { + Traverse.Create(__instance).Method("AddString", new object[] { text }).GetValue(); + context.Config.Reload(); + context.Config.Save(); + Traverse.Create(__instance).Method("AddString", new object[] { $"{context.Info.Metadata.Name} config reloaded" }).GetValue(); + return false; + } + if (text.ToLower().Equals($"{typeof(BepInExPlugin).Namespace.ToLower()} repair")) + { + Traverse.Create(__instance).Method("AddString", new object[] { text }).GetValue(); + int count = repairPieces(repairRadius.Value); + Traverse.Create(__instance).Method("AddString", new object[] { $"{context.Info.Metadata.Name} repaired {count} pieces" }).GetValue(); + return false; + } + if (text.ToLower().StartsWith($"{typeof(BepInExPlugin).Namespace.ToLower()} repair ")) + { + Traverse.Create(__instance).Method("AddString", new object[] { text }).GetValue(); + if(int.TryParse(text.Split(' ')[2], out int radius)) + { + int count = repairPieces(radius); + Traverse.Create(__instance).Method("AddString", new object[] { $"{context.Info.Metadata.Name} repaired {count} pieces" }).GetValue(); + } + else + Traverse.Create(__instance).Method("AddString", new object[] { $"{context.Info.Metadata.Name} syntax error" }).GetValue(); + return false; + } + return true; + } + } + } +} \ No newline at end of file diff --git a/BuildingRepair/BuildingRepair.csproj b/BuildingRepair/BuildingRepair.csproj new file mode 100644 index 0000000..250eb8c --- /dev/null +++ b/BuildingRepair/BuildingRepair.csproj @@ -0,0 +1,6 @@ + + + 1.0.0 + + + \ No newline at end of file diff --git a/BuildingRepair/Properties/AssemblyInfo.cs b/BuildingRepair/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..44b42f1 --- /dev/null +++ b/BuildingRepair/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("BuildingRepair")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("BuildingRepair")] +[assembly: AssemblyCopyright("Copyright © 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("683cb9ad-97c5-4eea-8e12-80086b3c5380")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/ConfigurationManager/SettingSearcher.cs b/ConfigurationManager/SettingSearcher.cs index 2eed63e..f532642 100644 --- a/ConfigurationManager/SettingSearcher.cs +++ b/ConfigurationManager/SettingSearcher.cs @@ -50,6 +50,7 @@ public static void CollectSettings(out IEnumerable results, ou { BepInExPlugin.Dbgl($"plugin: {plugin.Info.Metadata.Name} enabled {plugin.enabled}"); } + //BepInExPlugin.Dbgl($"plugin: {plugin.Info.Metadata.Name} enabled {plugin.enabled}"); var type = plugin.GetType(); diff --git a/CustomWeapons/BepInExPlugin.cs b/CustomWeapons/BepInExPlugin.cs index 507cb79..ff795a0 100644 --- a/CustomWeapons/BepInExPlugin.cs +++ b/CustomWeapons/BepInExPlugin.cs @@ -10,7 +10,7 @@ namespace CustomWeaponStats { - [BepInPlugin("aedenthorn.CustomWeaponStats", "Custom Weapon Stats", "0.5.0")] + [BepInPlugin("aedenthorn.CustomWeaponStats", "Custom Weapon Stats", "0.5.1")] public partial class BepInExPlugin : BaseUnityPlugin { private static BepInExPlugin context; @@ -115,7 +115,7 @@ static void Postfix(ref float __result) [HarmonyPatch(typeof(Attack), "Start")] static class Attack_Start_Patch { - static void Prefix(ref ItemDrop.ItemData weapon, ref ItemDrop.ItemData.SharedData __state) + static void Prefix(ref ItemDrop.ItemData weapon, ref WeaponState __state) { if (!modEnabled.Value) return; @@ -124,7 +124,7 @@ static void Prefix(ref ItemDrop.ItemData weapon, ref ItemDrop.ItemData.SharedDat Dbgl($"pre damage {weapon.m_shared.m_damages.m_slash}"); - __state = weapon.m_shared; + __state = new WeaponState(weapon); weapon.m_shared.m_useDurabilityDrain *= globalUseDurabilityMultiplier.Value; weapon.m_shared.m_holdDurationMin *= globalHoldDurationMinMultiplier.Value; @@ -145,12 +145,27 @@ static void Prefix(ref ItemDrop.ItemData weapon, ref ItemDrop.ItemData.SharedDat Dbgl($"post damage {weapon.m_shared.m_damages.m_slash}"); } - static void Postfix(ref ItemDrop.ItemData weapon, ItemDrop.ItemData.SharedData __state) + static void Postfix(ref ItemDrop.ItemData weapon, WeaponState __state) { if (!modEnabled.Value) return; - weapon.m_shared = __state; + weapon.m_shared.m_useDurabilityDrain = __state.useDurabilityDrain; + weapon.m_shared.m_holdDurationMin = __state.holdDurationMin; + weapon.m_shared.m_holdStaminaDrain = __state.holdStaminaDrain; + weapon.m_shared.m_attackForce = __state.attackForce; + weapon.m_shared.m_backstabBonus = __state.backstabBonus; + weapon.m_shared.m_damages.m_damage = __state.damage; + weapon.m_shared.m_damages.m_blunt = __state.blunt; + weapon.m_shared.m_damages.m_slash = __state.slash; + weapon.m_shared.m_damages.m_pierce = __state.pierce; + weapon.m_shared.m_damages.m_chop = __state.chop; + weapon.m_shared.m_damages.m_pickaxe = __state.pickaxe; + weapon.m_shared.m_damages.m_fire = __state.fire; + weapon.m_shared.m_damages.m_frost = __state.frost; + weapon.m_shared.m_damages.m_lightning = __state.lightning; + weapon.m_shared.m_damages.m_poison = __state.poison; + weapon.m_shared.m_damages.m_spirit = __state.spirit; } } diff --git a/CustomWeapons/WeaponState.cs b/CustomWeapons/WeaponState.cs new file mode 100644 index 0000000..236a5a3 --- /dev/null +++ b/CustomWeapons/WeaponState.cs @@ -0,0 +1,44 @@ +namespace CustomWeaponStats +{ + public class WeaponState : ItemDrop.ItemData.SharedData + { + + public float useDurabilityDrain; + public float holdDurationMin; + public float holdStaminaDrain; + public float attackForce; + public float backstabBonus; + public float damage; + public float blunt; + public float slash; + public float pierce; + public float chop; + public float pickaxe; + public float fire; + public float frost; + public float lightning; + public float poison; + public float spirit; + + public WeaponState(ItemDrop.ItemData weapon) + { + + useDurabilityDrain = weapon.m_shared.m_useDurabilityDrain; + holdDurationMin = weapon.m_shared.m_holdDurationMin; + holdStaminaDrain = weapon.m_shared.m_holdStaminaDrain; + attackForce = weapon.m_shared.m_attackForce; + backstabBonus = weapon.m_shared.m_backstabBonus; + damage = weapon.m_shared.m_damages.m_damage; + blunt = weapon.m_shared.m_damages.m_blunt; + slash = weapon.m_shared.m_damages.m_slash; + pierce = weapon.m_shared.m_damages.m_pierce; + chop = weapon.m_shared.m_damages.m_chop; + pickaxe = weapon.m_shared.m_damages.m_pickaxe; + fire = weapon.m_shared.m_damages.m_fire; + frost = weapon.m_shared.m_damages.m_frost; + lightning = weapon.m_shared.m_damages.m_lightning; + poison = weapon.m_shared.m_damages.m_poison; + spirit = weapon.m_shared.m_damages.m_spirit; + } + } +} \ No newline at end of file diff --git a/ValheimMods.sln b/ValheimMods.sln index 204cdc6..00a57c6 100644 --- a/ValheimMods.sln +++ b/ValheimMods.sln @@ -188,6 +188,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RepeatActions", "RepeatActi EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CustomItemInfoDisplay", "CustomItemInfoDisplay\CustomItemInfoDisplay.csproj", "{DCFD5456-8398-4A2B-8FF8-9A710D3DC29C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildingRepair", "BuildingRepair\BuildingRepair.csproj", "{683CB9AD-97C5-4EEA-8E12-80086B3C5380}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -550,6 +552,10 @@ Global {DCFD5456-8398-4A2B-8FF8-9A710D3DC29C}.Debug|Any CPU.Build.0 = Debug|Any CPU {DCFD5456-8398-4A2B-8FF8-9A710D3DC29C}.Release|Any CPU.ActiveCfg = Release|Any CPU {DCFD5456-8398-4A2B-8FF8-9A710D3DC29C}.Release|Any CPU.Build.0 = Release|Any CPU + {683CB9AD-97C5-4EEA-8E12-80086B3C5380}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {683CB9AD-97C5-4EEA-8E12-80086B3C5380}.Debug|Any CPU.Build.0 = Debug|Any CPU + {683CB9AD-97C5-4EEA-8E12-80086B3C5380}.Release|Any CPU.ActiveCfg = Release|Any CPU + {683CB9AD-97C5-4EEA-8E12-80086B3C5380}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE