diff --git a/ArrowMod.csproj b/ArrowMod.csproj index d8cfe1b..cc92441 100644 --- a/ArrowMod.csproj +++ b/ArrowMod.csproj @@ -1,91 +1,47 @@ - - - + + + + + + net6.0 + + + Latest + + + enable + + + enable + + + false + + + + + + embedded + - Debug - AnyCPU - {DAF59C7B-B568-4A66-BECA-0D8B47971845} - Library - Properties - ArrowMod - ArrowMod - v4.7.2 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false + OnBuildSuccess + + + - - False - ..\..\..\..\Games\SteamLibrary\steamapps\common\TheLongDark\MelonLoader\0Harmony.dll - - - ..\..\..\..\SteamLibrary\steamapps\common\TheLongDark\tld_Data\Managed\Assembly-CSharp.dll - False - - - False - ..\..\..\..\Games\SteamLibrary\steamapps\common\TheLongDark\MelonLoader\Managed\Il2Cppmscorlib.dll - - - - False - ..\..\..\..\Games\SteamLibrary\steamapps\common\TheLongDark\MelonLoader\MelonLoader.dll - - - False - False - - - - False - ..\..\..\..\Games\SteamLibrary\steamapps\common\TheLongDark\MelonLoader\Managed\UnhollowerBaseLib.dll - - - False - ..\..\..\..\Games\SteamLibrary\steamapps\common\TheLongDark\MelonLoader\Managed\UnhollowerRuntimeLib.dll - - - ..\..\..\..\SteamLibrary\steamapps\common\TheLongDark\tld_Data\Managed\UnityEngine.dll - False - - - ..\..\..\..\SteamLibrary\steamapps\common\TheLongDark\tld_Data\Managed\UnityEngine.CoreModule.dll - False - - - - - - - + + - - + + ..\..\..\..\Games\SteamLibrary\steamapps\common\TheLongDark\Mods\ModSettings.dll + - - - xcopy /y "$(ProjectDir)bin\Debug\ArrowMod.dll" "D:\Games\SteamLibrary\steamapps\common\TheLongDark\Mods\" - + + + + - \ No newline at end of file + diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index a1262a3..2174ee7 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -1,20 +1,14 @@ using MelonLoader; using System.Reflection; -using System.Runtime.InteropServices; -using BuildInfo = ArrowMod.BuildInfo; -[assembly: ComVisible(false)] -[assembly: Guid("daf59c7b-b568-4a66-beca-0d8b47971845")] +//This is a C# comment. Comments have no impact on compilation. -[assembly: AssemblyTitle(BuildInfo.Name)] -[assembly: AssemblyDescription(BuildInfo.Description)] -[assembly: AssemblyCompany(BuildInfo.Company)] -[assembly: AssemblyProduct(BuildInfo.Name)] -[assembly: AssemblyCopyright("Created by " + BuildInfo.Author)] -[assembly: AssemblyTrademark(BuildInfo.Company)] -[assembly: AssemblyCulture("")] +[assembly: AssemblyTitle(ArrowMod.BuildInfo.ModName)] +[assembly: AssemblyCopyright($"Created by {ArrowMod.BuildInfo.ModAuthor}")] -[assembly: AssemblyVersion(BuildInfo.Version)] -[assembly: AssemblyFileVersion(BuildInfo.Version)] -[assembly: MelonInfo(typeof(ArrowMod.ArrowMod), BuildInfo.Name, BuildInfo.Version, BuildInfo.Author, BuildInfo.DownloadLink)] +[assembly: AssemblyVersion(ArrowMod.BuildInfo.ModVersion)] +[assembly: AssemblyFileVersion(ArrowMod.BuildInfo.ModVersion)] +[assembly: MelonInfo(typeof(ArrowMod.ArrowMod), ArrowMod.BuildInfo.ModName, ArrowMod.BuildInfo.ModVersion, ArrowMod.BuildInfo.ModAuthor)] + +//This tells MelonLoader that the mod is only for The Long Dark. [assembly: MelonGame("Hinterland", "TheLongDark")] \ No newline at end of file diff --git a/README.md b/README.md index b082d71..3b0d36b 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ This mod for *The Long Dark* allows you to adjust how arrows are crafted. Requir ## Installation +Always up to date instructions: https://xpazeman.com/tld-mod-list/install.html + 1. If you haven't done so already, install MelonLoader by downloading and running [MelonLoader.Installer.exe](https://github.com/HerpDerpinstine/MelonLoader/releases/latest/download/MelonLoader.Installer.exe) 2. Download the latest version of `ArrowMod.dll` from the [releases page](https://github.com/ds5678/tld-ArrowMod/releases/latest) 3. Download the latest version of `ModSettings.dll` from its [release page](https://github.com/zeobviouslyfakeacc/ModSettings/releases/latest) @@ -19,4 +21,6 @@ This mod for *The Long Dark* allows you to adjust how arrows are crafted. Requir ## Notes +Settings change will require game restart. + Many thanks to all TLD moding commniunity for support and assist. diff --git a/src/ArrowMod.cs b/src/ArrowMod.cs index fb56a2e..fac33cd 100644 --- a/src/ArrowMod.cs +++ b/src/ArrowMod.cs @@ -1,24 +1,25 @@ using MelonLoader; -using UnityEngine; namespace ArrowMod { - public static class BuildInfo - { - public const string Name = "ArrowMod"; // Name of the Mod. (MUST BE SET) - public const string Description = "A mod to make arrow crafting more realistic."; // Description for the Mod. (Set as null if none) - public const string Author = "ttr, ds5678"; // Author of the Mod. (MUST BE SET) - public const string Company = null; // Company that made the Mod. (Set as null if none) - public const string Version = "1.7.1"; // Version of the Mod. (MUST BE SET) - public const string DownloadLink = null; // Download Link for the Mod. (Set as null if none) - } - internal class ArrowMod : MelonMod - { - public override void OnApplicationStart() - { - Debug.Log($"[{Info.Name}] Version {Info.Version} loaded!"); - Settings.OnLoad(); - } - } + public static class BuildInfo + { + internal const string ModName = "ArrowMod"; + internal const string ModAuthor = "ttr"; + internal const string ModVersion = "1.8.0"; + } + internal class ArrowMod : MelonMod + { + + public override void OnInitializeMelon() + { + Settings.OnLoad(); + LoggerInstance.Msg($"[{BuildInfo.ModName}] Version {BuildInfo.ModVersion} loaded!"); + } + public static void Log(string msg) + { + MelonLogger.Msg(msg); + } + } } \ No newline at end of file diff --git a/src/Patches.cs b/src/Patches.cs index 5401670..2cdfdb8 100644 --- a/src/Patches.cs +++ b/src/Patches.cs @@ -1,22 +1,29 @@ using MelonLoader; -using UnhollowerBaseLib; using HarmonyLib; using UnityEngine; - +using Il2Cpp; +using Il2CppInterop.Runtime.InteropTypes.Arrays; +using Il2CppTLD.Gear; +using UnityEngine.Playables; +using Il2CppSystem.Linq.Expressions; namespace ArrowMod { internal static class Patches { - [HarmonyPatch(typeof(GameManager), "Awake")] - public class GameManager_Awake + + //[HarmonyPatch(typeof(GameManager), "Awake")] + [HarmonyPatch(typeof(Panel_Crafting), nameof(Panel_Crafting.Initialize))] + public class InterfaceManager_Awake { private static void Postfix() { - + + ArrowMod.Log("Adding blueprints."); if (Settings.options.arrowUseLine) { - BlueprintItem bpi = GameManager.GetBlueprints().AddComponent(); + BlueprintData bpi = new(); + // Inputs bpi.m_KeroseneLitersRequired = 0f; bpi.m_GunpowderKGRequired = 0f; @@ -34,27 +41,24 @@ private static void Postfix() bpi.m_RequiresLitFire = false; bpi.m_RequiredCraftingLocation = CraftingLocation.Workbench; bpi.m_DurationMinutes = Settings.options.arrowCraftTime; // whaever, we need to set this in ItemPassFilter - bpi.m_CraftingAudio = "PLAY_CRAFTINGARROWS"; + bpi.m_CraftingAudio = MakeAudioEvent("PLAY_CRAFTINGARROWS"); + bpi.m_AppliedSkill = SkillType.None; bpi.m_ImprovedSkill = SkillType.None; - bpi.m_RequiredGear = new Il2CppReferenceArray(4) - { - [0] = GetGearItemPrefab("GEAR_Line"), - [1] = GetGearItemPrefab("GEAR_CrowFeather"), - [2] = GetGearItemPrefab("GEAR_ArrowShaft"), - [3] = GetGearItemPrefab("GEAR_ArrowHead") - }; - bpi.m_RequiredGearUnits = new Il2CppStructArray(4) + bpi.m_RequiredGear = new Il2CppReferenceArray(0) { }; + + bpi.m_RequiredGear = new Il2CppReferenceArray(4) { - [0] = 1, - [1] = 3, - [2] = 1, - [3] = 1 + [0] = new BlueprintData.RequiredGearItem() { m_Count = 1, m_Item = GetGearItemPrefab("GEAR_Line") }, + [1] = new BlueprintData.RequiredGearItem() { m_Count = 3, m_Item = GetGearItemPrefab("GEAR_CrowFeather") }, + [2] = new BlueprintData.RequiredGearItem() { m_Count = 1, m_Item = GetGearItemPrefab("GEAR_ArrowShaft") }, + [3] = new BlueprintData.RequiredGearItem() { m_Count = 1, m_Item = GetGearItemPrefab("GEAR_ArrowHead") } }; + InterfaceManager.GetInstance().m_BlueprintManager.m_AllBlueprints.Add(bpi); if (Settings.options.craftFletchingFromBark) { - BlueprintItem bpi2 = GameManager.GetBlueprints().AddComponent(); + BlueprintData bpi2 = new(); // Inputs bpi2.m_KeroseneLitersRequired = 0f; bpi2.m_GunpowderKGRequired = 0f; @@ -72,28 +76,22 @@ private static void Postfix() bpi2.m_RequiresLitFire = false; bpi2.m_RequiredCraftingLocation = CraftingLocation.Workbench; bpi2.m_DurationMinutes = 2 * (Settings.options.arrowCraftTime + Settings.options.craftFletchingFromBarkTime); // whaever, we need to set this in ItemPassFilter - bpi2.m_CraftingAudio = "PLAY_CRAFTINGARROWS"; + bpi2.m_CraftingAudio = MakeAudioEvent("PLAY_CRAFTINGARROWS"); bpi2.m_AppliedSkill = SkillType.None; bpi2.m_ImprovedSkill = SkillType.None; - bpi2.m_RequiredGear = new Il2CppReferenceArray(4) - { - [0] = GetGearItemPrefab("GEAR_Line"), - [1] = GetGearItemPrefab("GEAR_BarkTinder"), - [2] = GetGearItemPrefab("GEAR_ArrowShaft"), - [3] = GetGearItemPrefab("GEAR_ArrowHead") - }; - bpi2.m_RequiredGearUnits = new Il2CppStructArray(4) + bpi2.m_RequiredGear = new Il2CppReferenceArray(4) { - [0] = 1, - [1] = 1, - [2] = 1, - [3] = 1 + [0] = new BlueprintData.RequiredGearItem() { m_Count = 1, m_Item = GetGearItemPrefab("GEAR_Line") }, + [1] = new BlueprintData.RequiredGearItem() { m_Count = 1, m_Item = GetGearItemPrefab("GEAR_BarkTinder") }, + [2] = new BlueprintData.RequiredGearItem() { m_Count = 1, m_Item = GetGearItemPrefab("GEAR_ArrowShaft") }, + [3] = new BlueprintData.RequiredGearItem() { m_Count = 1, m_Item = GetGearItemPrefab("GEAR_ArrowHead") } }; + InterfaceManager.GetInstance().m_BlueprintManager.m_AllBlueprints.Add(bpi2); } } if (Settings.options.craftArrowFromWood) { - BlueprintItem bpi3 = GameManager.GetBlueprints().AddComponent(); + BlueprintData bpi3 = new(); // Inputs bpi3.m_KeroseneLitersRequired = 0f; bpi3.m_GunpowderKGRequired = 0f; @@ -111,17 +109,15 @@ private static void Postfix() bpi3.m_RequiresLitFire = false; bpi3.m_RequiredCraftingLocation = CraftingLocation.Workbench; bpi3.m_DurationMinutes = 180; // with knife it will be 1/2 of this time; it will be much longer than from branch but it takes time to cut arrow from plank - bpi3.m_CraftingAudio = "PLAY_CRAFTINGARROWS"; + bpi3.m_CraftingAudio = MakeAudioEvent("PLAY_CRAFTINGARROWS"); bpi3.m_AppliedSkill = SkillType.None; bpi3.m_ImprovedSkill = SkillType.None; - bpi3.m_RequiredGear = new Il2CppReferenceArray(1) - { - [0] = GetGearItemPrefab("GEAR_Hardwood") - }; - bpi3.m_RequiredGearUnits = new Il2CppStructArray(1) + bpi3.m_RequiredGear = new Il2CppReferenceArray(1) { - [0] = 1 + [0] = new BlueprintData.RequiredGearItem() { m_Count = 1, m_Item = GetGearItemPrefab("GEAR_Hardwood") } }; + InterfaceManager.GetInstance().m_BlueprintManager.m_AllBlueprints.Add(bpi3); + InterfaceManager.GetInstance().m_BlueprintManager.m_AllBlueprints.Sort(); } } } @@ -129,7 +125,7 @@ private static void Postfix() [HarmonyPatch(typeof(Panel_Crafting), "ItemPassesFilter")] private static class Panel_Crafting_ItemPassesFilter { - private static void Postfix(Panel_Crafting __instance, ref bool __result, BlueprintItem bpi) + private static void Postfix(Panel_Crafting __instance, ref bool __result, BlueprintData bpi) { if (bpi?.m_CraftedResult?.name == "GEAR_Arrow") { @@ -137,7 +133,7 @@ private static void Postfix(Panel_Crafting __instance, ref bool __result, Bluepr { __result = false; } - if (bpi.m_RequiredGear[1] == GetGearItemPrefab("GEAR_BarkTinder")) + if (bpi.m_RequiredGear[1].m_Item == GetGearItemPrefab("GEAR_BarkTinder")) { bpi.m_DurationMinutes = (Settings.options.arrowCraftTime + Settings.options.craftFletchingFromBarkTime) * 2; } @@ -156,7 +152,6 @@ private static void Postfix(Panel_Crafting __instance, ref bool __result, Bluepr } } - // based on better mending mod [HarmonyPatch(typeof(Panel_Crafting), "RefreshSelectedBlueprint")] public class Panel_Crafting_RefreshSelectedBlueprint @@ -164,10 +159,11 @@ public class Panel_Crafting_RefreshSelectedBlueprint private static void Postfix(Panel_Crafting __instance) { //__instance.m_SelectedDescription.color = whiteColor; - BlueprintItem bpi = __instance.m_SelectedBPI; + BlueprintData bpi = __instance.m_SelectedBPI; if (bpi) { - if (bpi.m_CraftedResult == GetGearItemPrefab("GEAR_ArrowShaft") && bpi.m_RequiredGear[0] == GetGearItemPrefab("GEAR_Hardwood")) + __instance.m_SelectedDescription.color = whiteColor; + if (bpi.m_CraftedResult == GetGearItemPrefab("GEAR_ArrowShaft") && bpi.m_RequiredGear[0].m_Item == GetGearItemPrefab("GEAR_Hardwood")) { int currentArcherySkill = GameManager.GetSkillArchery().GetCurrentTierNumber() + 1; int requiredArcherySkill = Settings.options.craftArrowFromWoodLevel; @@ -177,7 +173,7 @@ private static void Postfix(Panel_Crafting __instance) __instance.m_SelectedDescription.color = redColor; } } - if (bpi.m_CraftedResult == GetGearItemPrefab("GEAR_Arrow") && bpi.m_RequiredGear[1] == GetGearItemPrefab("GEAR_BarkTinder")) + if (bpi.m_CraftedResult == GetGearItemPrefab("GEAR_Arrow") && bpi.m_RequiredGear[1].m_Item == GetGearItemPrefab("GEAR_BarkTinder")) { int currentArcherySkill = GameManager.GetSkillArchery().GetCurrentTierNumber() + 1; int requiredArcherySkill = Settings.options.craftFletchingFromBarkLevel; @@ -192,13 +188,13 @@ private static void Postfix(Panel_Crafting __instance) } // based on better mending mod - [HarmonyPatch(typeof(BlueprintItem), "CanCraftBlueprint")] - private class BlueprintItem_CanCraftBlueprint + [HarmonyPatch(typeof(BlueprintData), "CanCraftBlueprint")] + private class BlueprintData_CanCraftBlueprint { - private static void Postfix(ref bool __result, BlueprintItem __instance) + private static void Postfix(ref bool __result, BlueprintData __instance) { - if (__instance.m_CraftedResult == GetGearItemPrefab("GEAR_ArrowShaft") && __instance.m_RequiredGear[0] == GetGearItemPrefab("GEAR_Hardwood") && __result) + if (__instance.m_CraftedResult == GetGearItemPrefab("GEAR_ArrowShaft") && __instance.m_RequiredGear[0].m_Item == GetGearItemPrefab("GEAR_Hardwood") && __result) { int currentArcherySkill = GameManager.GetSkillArchery().GetCurrentTierNumber() + 1; int requiredArcherySkill = Settings.options.craftArrowFromWoodLevel; @@ -207,7 +203,7 @@ private static void Postfix(ref bool __result, BlueprintItem __instance) __result = false; } } - if (__instance.m_CraftedResult == GetGearItemPrefab("GEAR_Arrow") && __instance.m_RequiredGear[1] == GetGearItemPrefab("GEAR_BarkTinder") && __result) + if (__instance.m_CraftedResult == GetGearItemPrefab("GEAR_Arrow") && __instance.m_RequiredGear[1].m_Item == GetGearItemPrefab("GEAR_BarkTinder") && __result) { int currentArcherySkill = GameManager.GetSkillArchery().GetCurrentTierNumber() + 1; int requiredArcherySkill = Settings.options.craftFletchingFromBarkLevel; @@ -219,8 +215,35 @@ private static void Postfix(ref bool __result, BlueprintItem __instance) } } - private static GearItem GetGearItemPrefab(string name) => Resources.Load(name).Cast().GetComponent(); - private static ToolsItem GetToolItemPrefab(string name) => Resources.Load(name).Cast().GetComponent(); + //private static GearItem GetGearItemPrefab(string name) => Resources.Load(name).Cast().GetComponent(); + private static GearItem GetGearItemPrefab(string name) + { + return GearItem.LoadGearItemPrefab(name); + } + //private static ToolsItem GetToolItemPrefab(string name) => Resources.Load(name).Cast().GetComponent(); + private static ToolsItem GetToolItemPrefab(string name) + { + return GearItem.LoadGearItemPrefab(name).m_ToolsItem; + } + // from CraftingRevisions by ds5678 and STBlade + public static Il2CppAK.Wwise.Event? MakeAudioEvent(string eventName) + { + if (eventName == null) + { + return null; + } + uint eventId = AkSoundEngine.GetIDFromString(eventName); + if (eventId <= 0 || eventId >= 4294967295) + { + return null; + } + + Il2CppAK.Wwise.Event newEvent = new(); + newEvent.WwiseObjectReference = new WwiseEventReference(); + newEvent.WwiseObjectReference.objectName = eventName; + newEvent.WwiseObjectReference.id = eventId; + return newEvent; + } private static readonly Color whiteColor = new Color(0.7f, 0.7f, 0.7f); private static readonly Color redColor = new Color(0.7f, 0f, 0f); diff --git a/src/Settings.cs b/src/Settings.cs index b6adb23..f530b4a 100644 --- a/src/Settings.cs +++ b/src/Settings.cs @@ -2,9 +2,13 @@ namespace ArrowMod { + internal class ArrowModSettings : JsonModSettings { - [Name("Arrowhead craft time")] + [Section("Arrow Mod Settings")] + + + [Name("Arrowhead craft time")] [Description("Minutes to craft 2 arrowheads. Default is 60, recommended is 20-40")] [Slider(1, 120)] public int arrowHeadCraftTime = 60; @@ -15,7 +19,7 @@ internal class ArrowModSettings : JsonModSettings public int arrowCraftTime = 90; [Name("Use line")] - [Description("Require 1 line to craft an arrow. Note: Due to game limitation, only 3 first ingredients are disaied in crafing menu - eneblaing this will require 4, so arrow head, even if not disaplyed, still is needed.")] + [Description("Require 1 line to craft an arrow.\nNote: Due to game limitation, only 3 first ingredients are disaied in crafing menu - eneblaing this will require 4, so arrow head, even if not disaplyed, still is needed.")] public bool arrowUseLine = false; [Name("Craft Arrowshaft from Hardwood")] @@ -28,7 +32,7 @@ internal class ArrowModSettings : JsonModSettings public int craftArrowFromWoodLevel = 5; [Name("Craft arrow fletchings from Bark")] - [Description("Allow to use birch bark to craft arrow fletchings. NOTE: Require 'Use line' to be turn on. NOTE2: resulting arrow is same as vanilla one, meaning deconstricting it will yeld feathers.")] + [Description("Allow to use birch bark to craft arrow fletchings.\nNOTE: Require 'Use line' to be turn on.\nNOTE2: resulting arrow is same as vanilla one, meaning deconstricting it will yeld feathers.")] public bool craftFletchingFromBark = false; [Name("... skill level")] @@ -41,7 +45,10 @@ internal class ArrowModSettings : JsonModSettings [Slider(0, 20)] public int craftFletchingFromBarkTime = 5; - } + + + + } internal static class Settings { public static ArrowModSettings options;