From e5d522dc6a0c66d870d943f0638cf5a3315c5a44 Mon Sep 17 00:00:00 2001 From: Asmotym Date: Sun, 21 Nov 2021 22:27:30 +0100 Subject: [PATCH 1/6] Update skill framework --- SkillFramework/AedenthornUtils.cs | 129 ++++++++++++++++++ SkillFramework/BaseSkill/BaseSkill.cs | 167 +++++++++++++++++++++++ SkillFramework/BaseSkill/ISkill.cs | 42 ++++++ SkillFramework/BepInExPlugin.cs | 186 ++++++++++++++------------ SkillFramework/SkillAPI.cs | 59 ++++++-- SkillFramework/SkillCategories.cs | 16 +++ SkillFramework/SkillInfo.cs | 103 ++++++++++++++ 7 files changed, 604 insertions(+), 98 deletions(-) create mode 100644 SkillFramework/AedenthornUtils.cs create mode 100644 SkillFramework/BaseSkill/BaseSkill.cs create mode 100644 SkillFramework/BaseSkill/ISkill.cs create mode 100644 SkillFramework/SkillCategories.cs diff --git a/SkillFramework/AedenthornUtils.cs b/SkillFramework/AedenthornUtils.cs new file mode 100644 index 0000000..1d07de2 --- /dev/null +++ b/SkillFramework/AedenthornUtils.cs @@ -0,0 +1,129 @@ +using BepInEx.Bootstrap; +using BepInEx.Configuration; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using UnityEngine; + +public class AedenthornUtils +{ + public static bool CheckKeyDown(string value) + { + try + { + return Input.GetKeyDown(value.ToLower()); + } + catch + { + return false; + } + } + public static bool CheckKeyUp(string value) + { + try + { + return Input.GetKeyUp(value.ToLower()); + } + catch + { + return false; + } + } + public static bool CheckKeyHeld(string value, bool req = true) + { + try + { + return Input.GetKey(value.ToLower()); + } + catch + { + return !req; + } + } + + public static void ShuffleList(List list) + { + int n = list.Count; + while (n > 1) + { + n--; + int k = Random.Range(0, n); + var value = list[k]; + list[k] = list[n]; + list[n] = value; + } + } + public static string GetAssetPath(object obj, bool create = false) + { + return GetAssetPath(obj.GetType().Namespace, create); + } + public static string GetAssetPath(string name, bool create = false) + { + string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), name); + if (create && !Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + return path; + } + public static string GetTransformPath(Transform t) + { + if (!t.parent) + { + return t.name; + + } + return GetTransformPath(t.parent) + "/" + t.name; + } + + public static byte[] EncodeToPNG(Texture2D texture) + { + RenderTexture tmp = RenderTexture.GetTemporary( + texture.width, + texture.height, + 0, + RenderTextureFormat.Default, + RenderTextureReadWrite.Default); + + // Blit the pixels on texture to the RenderTexture + Graphics.Blit(texture, tmp); + + // Backup the currently set RenderTexture + RenderTexture previous = RenderTexture.active; + + // Set the current RenderTexture to the temporary one we created + RenderTexture.active = tmp; + + // Create a new readable Texture2D to copy the pixels to it + Texture2D myTexture2D = new Texture2D(texture.width, texture.height, TextureFormat.RGBA32, true, false); + + // Copy the pixels from the RenderTexture to the new Texture + myTexture2D.ReadPixels(new Rect(0, 0, tmp.width, tmp.height), 0, 0); + myTexture2D.Apply(); + + // Reset the active RenderTexture + RenderTexture.active = previous; + + // Release the temporary RenderTexture + RenderTexture.ReleaseTemporary(tmp); + + // "myTexture2D" now has the same pixels from "texture" and it's readable. + + Texture2D newTexture = new Texture2D(texture.width, texture.height); + newTexture.SetPixels(myTexture2D.GetPixels()); + newTexture.Apply(); + return newTexture.EncodeToPNG(); + } + + public static Transform[] GetUICharacterSkillCategoriesParents(UICharacter uICharacter) + { + return new Transform[] + { + uICharacter.daggerproficiency.transform.parent, + uICharacter.ignorpain.transform.parent, + uICharacter.healaura.transform.parent, + uICharacter.goldenhand.transform.parent + }; + } + +} \ No newline at end of file diff --git a/SkillFramework/BaseSkill/BaseSkill.cs b/SkillFramework/BaseSkill/BaseSkill.cs new file mode 100644 index 0000000..a1dddc1 --- /dev/null +++ b/SkillFramework/BaseSkill/BaseSkill.cs @@ -0,0 +1,167 @@ +using BepInEx; +using BepInEx.Configuration; +using System.Collections.Generic; +using System.IO; +using UnityEngine; + +namespace SkillFramework.BaseSkill +{ + public abstract class BaseSkill : ISkill + { + #region Default properties + protected BaseUnityPlugin plugin; + // name and description of the skill used in Localization added in order: + // english, chinese, russian, japanese, ... + protected List skillName; + protected List skillDescription; + // represent the category the skill will be in + public int skillCategory = SkillCategories.Combat; + // plugin section name + protected string configSection; + // skill icon texture + protected Texture2D skillIcon = new Texture2D(1, 1); + // skill icon file name (without file extension, we only use .png) + public string iconName = "frame"; + // config default properties + public int defaultMaxPoints = 5; + public int defaultReqLevel = 2; + // default config entries + public static ConfigEntry maxPoints; + public static ConfigEntry reqLevel; + #endregion + + #region Getters/Setters + protected abstract string skillId + { + get; + set; + } + public string GetSkillID() + { + return skillId; + } + + public override string ToString() + { + return iconName; + } + #endregion + + public ISkill Build(BaseUnityPlugin defaultPlugin, string sectionName) + { + plugin = defaultPlugin; + configSection = sectionName; + + // bind default skill settings + maxPoints = plugin.Config.Bind(configSection, "MaxPoints", defaultMaxPoints, "Maximum skill points for this skill"); + reqLevel = plugin.Config.Bind(configSection, "RequiredLevel", defaultReqLevel, "Character level required for this skill"); + + // bind skill information + SetConfig(); + SetSkillDescription(); + SetSkillName(); + SetSettingChanged(); + SetSkillIcon(); + + BepInExPlugin.Log($"Setup Skill using: {configSection} - {skillCategory} - {defaultMaxPoints} - {defaultReqLevel} - {iconName}"); + + // add skill to the list + AddSkill(); + + return this; + } + + /// + /// This method is called whenever the BepInEx configuration is updated + /// + public virtual void Update() + { + SetSkillDescription(); + + // initialize increase/decrease delegate + SkillInfo skillInfo = SkillAPI.GetSkill(skillId); + + // setup delegate handler if skill is defined + if (skillInfo != null) + { + skillInfo.SetOnDecreaseSkillLevel = OnDecreaseSkillLevel; + skillInfo.SetOnIncreaseSkillLevel = OnIncreaseSkillLevel; + skillInfo.SetPostfixLoadCharacterCustomization = PostfixLoadCharacterCustomization; + skillInfo.SetPrefixSaveCharacterCustomization = PrefixSaveCharacterCustomization; + skillInfo.SetPrefixCharacterCustomizationUpdateStats = PrefixCharacterCustomizationUpdateStats; + skillInfo.SetPostfixCharacterCustomizationUpdateStats = PostfixCharacterCustomizationUpdateStats; + } + } + + /// + /// This method is called when the skill should be added to the game + /// + public virtual void AddSkill() + { + // initialize skill using SkillFramework API + SkillAPI.AddSkill(skillId, skillName, skillDescription, skillCategory, skillIcon, maxPoints.Value, reqLevel.Value, false); + } + + public virtual void SetSkillIcon() + { + string path = Path.Combine(AedenthornUtils.GetAssetPath(plugin), $"{iconName}.png"); + BepInExPlugin.Log($"Setup skill icon {path}"); + if (File.Exists(path)) + skillIcon.LoadImage(File.ReadAllBytes(path)); + } + + #region BepInEx & Basic Skill configuration method to override + public abstract void SetConfig(); + public abstract void SetSkillDescription(); + public abstract void SetSkillName(); + public abstract void SetSettingChanged(); + #endregion + + #region Events Delegates + + public virtual bool OnDecreaseSkillLevel(SkillBox skillBox, SkillInfo skillInfo) + { + // cannot handle skill increase + if (!CanHandleSkillIncreaseDecrease(skillBox, skillId)) + return true; + + // TODO Custom code here + + return true; + } + public virtual bool OnIncreaseSkillLevel(SkillBox skillBox, SkillInfo skillInfo) + { + // cannot handle skill increase + if (!CanHandleSkillIncreaseDecrease(skillBox, skillId)) + return true; + + // TODO Custom code here + + return true; + } + public virtual void PrefixSaveCharacterCustomization(SkillInfo skillInfo, Mainframe mainFrame, CharacterCustomization characterCustomization) + { } + public virtual void PostfixLoadCharacterCustomization(SkillInfo skillInfo, Mainframe mainFrame, CharacterCustomization characterCustomization) + { } + public virtual void PrefixCharacterCustomizationUpdateStats(CharacterCustomization characterCustomization, SkillInfo skillInfo) + { } + public virtual void PostfixCharacterCustomizationUpdateStats(CharacterCustomization characterCustomization, SkillInfo skillInfo) + { } + + #endregion + + #region Helpers + + public virtual bool CanHandleSkillIncreaseDecrease(SkillBox skillBox, string skillId) + { + // procceed to next call if not in the current skill + if (skillId != skillBox.name) + return false; + + return true; + } + + #endregion + + } +} diff --git a/SkillFramework/BaseSkill/ISkill.cs b/SkillFramework/BaseSkill/ISkill.cs new file mode 100644 index 0000000..d5cbdb3 --- /dev/null +++ b/SkillFramework/BaseSkill/ISkill.cs @@ -0,0 +1,42 @@ +using BepInEx; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SkillFramework.BaseSkill +{ + public interface ISkill + { + + ISkill Build(BaseUnityPlugin defaultPlugin, string sectionName); + + void SetConfig(); + + void SetSettingChanged(); + + void SetSkillDescription(); + + void SetSkillIcon(); + + void SetSkillName(); + + void AddSkill(); + + void Update(); + + bool OnIncreaseSkillLevel(SkillBox skillBox, SkillInfo skillInfo); + + bool OnDecreaseSkillLevel(SkillBox skillBox, SkillInfo skillInfo); + + void PrefixSaveCharacterCustomization(SkillInfo skillInfo, Mainframe mainFrame, CharacterCustomization characterCustomization); + + void PostfixLoadCharacterCustomization(SkillInfo skillInfo, Mainframe mainFrame, CharacterCustomization characterCustomization); + + void PrefixCharacterCustomizationUpdateStats(CharacterCustomization characterCustomization, SkillInfo skillInfo); + + void PostfixCharacterCustomizationUpdateStats(CharacterCustomization characterCustomization, SkillInfo skillInfo); + + } +} diff --git a/SkillFramework/BepInExPlugin.cs b/SkillFramework/BepInExPlugin.cs index 61cb311..208beea 100644 --- a/SkillFramework/BepInExPlugin.cs +++ b/SkillFramework/BepInExPlugin.cs @@ -12,7 +12,7 @@ namespace SkillFramework { [BepInPlugin("aedenthorn.SkillFramework", "Skill Framework", "0.2.1")] - public class BepInExPlugin: BaseUnityPlugin + public class BepInExPlugin : BaseUnityPlugin { public static ConfigEntry modEnabled; public static ConfigEntry isDebug; @@ -23,11 +23,12 @@ public class BepInExPlugin: BaseUnityPlugin public static Dictionary> characterSkillLevels = new Dictionary>(); public static Dictionary customSkills = new Dictionary(); - public static void Dbgl(string str = "", bool pref = true) + public static void Log(string message) { if (isDebug.Value) - Debug.Log((pref ? typeof(BepInExPlugin).Namespace + " " : "") + str); + Debug.Log(typeof(BepInExPlugin).Namespace + " - " + message); } + private void Awake() { context = this; @@ -39,6 +40,7 @@ private void Awake() Harmony.CreateAndPatchAll(Assembly.GetExecutingAssembly(), null); } + public static int GetCharacterSkillLevel(string charName, string skillname) { if (!characterSkillLevels.ContainsKey(charName)) @@ -59,30 +61,34 @@ static class UICharacter_Refresh_Patch { static void Postfix(UICharacter __instance) { + // this draw the custom skills in their respective categories + // after each time the UICharacter.Refresh method is called in the game + if (!modEnabled.Value || !customSkills.Any()) return; - Transform[] parents = new Transform[] - { - __instance.daggerproficiency.transform.parent, - __instance.ignorpain.transform.parent, - __instance.healaura.transform.parent, - __instance.goldenhand.transform.parent - }; - foreach (SkillInfo info in customSkills.Values) + + // get categories transform elements + Transform[] parents = AedenthornUtils.GetUICharacterSkillCategoriesParents(__instance); + + foreach (SkillInfo skillInfo in customSkills.Values) { - Transform t = parents[info.category].Find(info.id); - if (!t) + // get current skill transform element + Transform skillTransform = parents[skillInfo.category].Find(skillInfo.id); + + // check if it's defined + if (!skillTransform) { - if (parents[info.category].childCount % 6 == 0) + // check if we should place the skill in a new line + if (parents[skillInfo.category].childCount % 6 == 0) { - // decrease y of lower cats - float height = parents[info.category].GetComponent().spacing.y + __instance.daggerproficiency.transform.GetComponent().sizeDelta.y; - for (int i = info.category + 1; i < parents.Length; i++) + // decrease y of lower categories + float height = parents[skillInfo.category].GetComponent().spacing.y + __instance.daggerproficiency.transform.GetComponent().sizeDelta.y; + for (int i = skillInfo.category + 1; i < parents.Length; i++) { parents[i].parent.GetComponent().anchoredPosition -= new Vector2(0, height); - foreach(Transform c in parents[i]) + foreach (Transform category in parents[i]) { - foreach(Transform cc in c) + foreach (Transform cc in category) { if (cc.name.StartsWith("plus")) cc.GetComponent().anchoredPosition = Vector2.zero; @@ -91,97 +97,71 @@ static void Postfix(UICharacter __instance) } parents[0].parent.parent.GetComponent().sizeDelta += new Vector2(0, height); } - t = Instantiate(__instance.daggerproficiency.transform, parents[info.category]); - t.name = info.id; - t.GetComponentInChildren