diff --git a/CHANGELOG.md b/CHANGELOG.md index cfa1e50..acb11dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `Fixed` for any bug fixes. - `Security` in case of vulnerabilities. +## [0.4.5] - 2025-05-21 + +### Added + +- Added support for "corruption" blood mastery to be used in mastery API commands + +### Fixed + +- Updated support for more player attacks +- Fixed support for detecting blood type changes +- Fixed ability to disable weapon mastery system + ## [0.4.4] - 2025-05-19 ### Changed diff --git a/XPRising/Hooks/BuffHook.cs b/XPRising/Hooks/BuffHook.cs index 81a46a8..1007417 100644 --- a/XPRising/Hooks/BuffHook.cs +++ b/XPRising/Hooks/BuffHook.cs @@ -7,6 +7,7 @@ using Unity.Collections; using Unity.Entities; using XPRising.Systems; +using XPRising.Transport; using XPRising.Utils; using XPRising.Utils.Prefabs; using XPShared; @@ -149,6 +150,13 @@ private static void Postfix(BuffDebugSystem __instance) var guid = __instance.EntityManager.GetComponentData(entity); DebugTool.LogPrefabGuid(guid, "BuffDebugSystemPost:", LogSystem.Buff); + if (BloodlineSystem.BuffToBloodTypeMap.TryGetValue(guid, out _)) + { + // If we have gained a blood type, update the stat bonus + ApplyPlayerBloodType(__instance.EntityManager, entity); + continue; + } + switch (guid.GuidHash) { // Detect equipping a spell source (ring/necklace) so we can reapply the player level correctly @@ -181,6 +189,17 @@ private static void Postfix(BuffDebugSystem __instance) } } + private static void ApplyPlayerBloodType(EntityManager entityManager, Entity entity) + { + if (!entityManager.TryGetComponentData(entity, out var entityOwner) || + !entityManager.TryGetComponentData(entityOwner.Owner, out var playerCharacter) || + !entityManager.TryGetComponentData(playerCharacter.UserEntity, out var user)) return; + + BuffUtil.ApplyStatBuffOnDelay(user, playerCharacter.UserEntity, entityOwner); + var currentBlood = BloodlineSystem.BloodMasteryType(entityOwner); + ClientActionHandler.SendActiveBloodMasteryData(user, currentBlood); + } + private static void ApplyPlayerLevel(EntityManager entityManager, Entity entity) { if (!entityManager.TryGetComponentData(entity, out var entityOwner) || diff --git a/XPRising/Hooks/ScriptSpawnServerHook.cs b/XPRising/Hooks/ScriptSpawnServerHook.cs deleted file mode 100644 index 9fdaad2..0000000 --- a/XPRising/Hooks/ScriptSpawnServerHook.cs +++ /dev/null @@ -1,57 +0,0 @@ -using BepInEx.Logging; -using HarmonyLib; -using ProjectM; -using ProjectM.Network; -using ProjectM.Shared.Systems; -using Unity.Collections; -using Unity.Entities; -using XPRising.Systems; -using XPRising.Transport; -using XPRising.Utils; - -namespace XPRising.Hooks; - -[HarmonyPatch] -public class ScriptSpawnServerHook -{ - private static EntityManager EntityManager => Plugin.Server.EntityManager; - - [HarmonyPatch(typeof(ScriptSpawnServer), nameof(ScriptSpawnServer.OnUpdate))] - [HarmonyPrefix] - static void OnUpdatePrefix(ScriptSpawnServer __instance) - { - if (!Plugin.BloodlineSystemActive) return; - - var entities = __instance.__query_1231292170_0.ToEntityArray(Allocator.Temp); - try - { - foreach (var entity in entities) - { - var prefabGuid = Helper.GetPrefabGUID(entity); - if (prefabGuid != BuffUtil.AppliedBuff && - EntityManager.HasComponent(entity) && - EntityManager.TryGetComponentData(entity, out var entityOwner) && - EntityManager.TryGetComponentData(entityOwner, out var playerCharacter) && - EntityManager.TryGetComponentData(playerCharacter.UserEntity, out var userData)) - { - // If we have gained a blood type, update the stat bonus - if (BloodlineSystem.BuffToBloodTypeMap.TryGetValue(prefabGuid, out _)) - { - BuffUtil.ApplyStatBuffOnDelay(userData, playerCharacter.UserEntity, entityOwner); - var currentBlood = BloodlineSystem.BloodMasteryType(entityOwner); - ClientActionHandler.SendActiveBloodMasteryData(userData, currentBlood); - } - } - } - } - catch (Exception e) - { - Plugin.Log(Plugin.LogSystem.Bloodline, LogLevel.Error, $"ScriptSpawnServerHookPre: {e.Message}", true); - } - finally - { - entities.Dispose(); - } - } - -} \ No newline at end of file diff --git a/XPRising/Hooks/StatChangeSystemHook.cs b/XPRising/Hooks/StatChangeSystemHook.cs index 66cfeb7..3b0b933 100644 --- a/XPRising/Hooks/StatChangeSystemHook.cs +++ b/XPRising/Hooks/StatChangeSystemHook.cs @@ -17,7 +17,10 @@ public class StatChangeSystemHook private static void ApplyStatChangesPostfix( StatChangeSystem __instance, NativeArray statChanges) - { + { + // Currently this is only used to track damage events. We can skip any/all handling if weapon mastery is disabled + if (!Plugin.WeaponMasterySystemActive) return; + for (var i = 0; i < statChanges.Length; i++) { var statChangeEvent = statChanges[i]; diff --git a/XPRising/Systems/BloodlineSystem.cs b/XPRising/Systems/BloodlineSystem.cs index 46aeeeb..ead2c6a 100644 --- a/XPRising/Systems/BloodlineSystem.cs +++ b/XPRising/Systems/BloodlineSystem.cs @@ -13,7 +13,7 @@ public class BloodlineSystem { public static readonly Dictionary BuffToBloodTypeMap = new() { - // TODO work out if we need to have all tiers, or just T1 for each + // Seems like we only need to check against the T1 options { new PrefabGUID((int)Effects.AB_BloodBuff_Worker_Tier1), GlobalMasterySystem.MasteryType.BloodWorker }, { new PrefabGUID((int)Effects.AB_BloodBuff_Warrior_Tier1), GlobalMasterySystem.MasteryType.BloodWarrior }, { new PrefabGUID((int)Effects.AB_BloodBuff_Scholar_Tier1), GlobalMasterySystem.MasteryType.BloodScholar }, diff --git a/XPRising/Systems/GlobalMasterySystem.cs b/XPRising/Systems/GlobalMasterySystem.cs index d22b663..cf4c94d 100644 --- a/XPRising/Systems/GlobalMasterySystem.cs +++ b/XPRising/Systems/GlobalMasterySystem.cs @@ -1,8 +1,4 @@ using ProjectM; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; using System.Text.Json; using BepInEx.Logging; using ProjectM.Network; @@ -106,6 +102,7 @@ public enum MasteryCategory { "none", MasteryType.BloodNone }, { "mutant", MasteryType.BloodMutant }, { "creature", MasteryType.BloodCreature }, + { "corruption", MasteryType.BloodCorruption }, { "warrior", MasteryType.BloodWarrior }, { "rogue", MasteryType.BloodRogue }, { "brute", MasteryType.BloodBrute }, diff --git a/XPRising/Utils/MasteryHelper.cs b/XPRising/Utils/MasteryHelper.cs index 81d26d9..7ecdae6 100644 --- a/XPRising/Utils/MasteryHelper.cs +++ b/XPRising/Utils/MasteryHelper.cs @@ -30,6 +30,7 @@ public static GlobalMasterySystem.MasteryType GetMasteryTypeForEffect(int effect case Effects.AB_Vampire_Claws_Primary_MeleeAttack_Unholy_Hit03: case Effects.AB_Vampire_Claws_Primary_Mounted_Hit: case Effects.AB_Vampire_Claws_Puncture_Area: + case Effects.AB_Vampire_Claws_Puncture_Unholy_Area: case Effects.AB_Vampire_Claws_SkeweringLeap_HitBox_Buff: case Effects.AB_Vampire_Claws_SkeweringLeap_Unholy_HitBox_Buff: case Effects.AB_Vampire_Claws_VaultSlash_Hit: @@ -111,8 +112,10 @@ public static GlobalMasterySystem.MasteryType GetMasteryTypeForEffect(int effect case Effects.AB_Pistols_Primary_Attack_Projectile_Mounted_01: case Effects.AB_Pistols_Primary_Attack_Projectile_Mounted_02: case Effects.AB_Pistols_FanTheHammer_Projectile: - case Effects.AB_Pistols_ExplosiveShot_Shot_Projectile: case Effects.AB_Pistols_ExplosiveShot_Shot_ExplosiveImpact: + case Effects.AB_Pistols_ExplosiveShot_Shot_ExplosiveImpact_DoubleBarrel: + case Effects.AB_Pistols_ExplosiveShot_Shot_Projectile: + case Effects.AB_Pistols_ExplosiveShot_Shot_Recast_Projectile: case Effects.AB_Pistols_Primary_Attack_VeilOfBlood_Projectile_01: case Effects.AB_Pistols_Primary_Attack_VeilOfBlood_Projectile_02: case Effects.AB_Pistols_Primary_Attack_VeilOfBones_Projectile_01: @@ -151,8 +154,9 @@ public static GlobalMasterySystem.MasteryType GetMasteryTypeForEffect(int effect case Effects.AB_Vampire_Spear_Primary_MeleeAttack_Hit02: case Effects.AB_Vampire_Spear_Primary_MeleeAttack_Hit03: case Effects.AB_Vampire_Spear_Primary_Mounted_Hit: - case Effects.AB_Spear_AThousandSpears_Stab_Hit: case Effects.AB_Spear_AThousandSpears_Recast_Impale_Hit: + case Effects.AB_Spear_AThousandSpears_Stab_Hit: + case Effects.AB_Spear_AThousandSpears_Stab_BallLightning: return GlobalMasterySystem.MasteryType.WeaponSpear; case Effects.AB_Vampire_Sword_Primary_MeleeAttack_Hit01: case Effects.AB_Vampire_Sword_Primary_MeleeAttack_Hit02: @@ -204,20 +208,24 @@ public static GlobalMasterySystem.MasteryType GetMasteryTypeForEffect(int effect case Effects.AB_Vampire_VeilOfShadow_TriggerBonusEffects: case Effects.AB_Vampire_VeilOfStorm_TriggerBonusEffects: // Blood - case Effects.AB_Blood_BloodRite_AreaTrigger: case Effects.AB_Blood_BloodFountain_Ground_Impact: - case Effects.AB_Blood_SanguineCoil_Projectile: - case Effects.AB_Blood_BloodStorm_Projectile: - case Effects.AB_Blood_BloodStorm_PostBuffAttack: - case Effects.AB_Blood_VampiricCurse_Buff: - case Effects.AB_Blood_Shadowbolt_Projectile: - case Effects.AB_Blood_Shadowbolt_VampiricCurse_Buff: - case Effects.AB_Blood_BloodRite_SpellMod_DamageOnAttackBuff: - case Effects.AB_Blood_CrimsonBeam_Channel: case Effects.AB_Blood_BloodFountain_Spellmod_Recast_Ground_Impact: + case Effects.AB_Blood_BloodRite_AreaTrigger: case Effects.AB_Blood_BloodRite_Projectile: + case Effects.AB_Blood_BloodRite_SpellMod_DamageOnAttackBuff: + case Effects.AB_Blood_BloodStorm_PostBuffAttack: + case Effects.AB_Blood_BloodStorm_Projectile: + case Effects.AB_Blood_CarrionSwarm_BatProjectile_Left_01: + case Effects.AB_Blood_CarrionSwarm_BatProjectile_Left_02: + case Effects.AB_Blood_CarrionSwarm_BatProjectile_Right_01: + case Effects.AB_Blood_CarrionSwarm_BatProjectile_Right_02: + case Effects.AB_Blood_CrimsonBeam_Channel: + case Effects.AB_Blood_SanguineCoil_Projectile: + case Effects.AB_Blood_Shadowbolt_Projectile: case Effects.AB_Blood_Shadowbolt_SpellMod_Area: case Effects.AB_Blood_Shadowbolt_SpellMod_ForkProjectile: + case Effects.AB_Blood_Shadowbolt_VampiricCurse_Buff: + case Effects.AB_Blood_VampiricCurse_Buff: case Effects.AB_Blood_VampiricCurse_Buff_Lesser: case Effects.AB_Blood_VampiricCurse_Projectile: case Effects.AB_Blood_VampiricCurse_SpellMod_Area: @@ -234,6 +242,7 @@ public static GlobalMasterySystem.MasteryType GetMasteryTypeForEffect(int effect case Effects.AB_Chaos_ChaosBarrage_Projectile: case Effects.AB_Chaos_MercilessCharge_EndImpact: case Effects.AB_Chaos_MercilessCharge_Phase: + case Effects.AB_Chaos_RainOfChaos_SpellMod_BonusMeteor: case Effects.AB_Chaos_RainOfChaos_SpellMod_BurnDebuff: case Effects.AB_Chaos_RainOfChaos_SpellMod_MegaMeteor: case Effects.AB_Chaos_RainOfChaos_Throw_Meteor: @@ -262,7 +271,9 @@ public static GlobalMasterySystem.MasteryType GetMasteryTypeForEffect(int effect case Effects.AB_Frost_Shared_SpellMod_FrostWeapon_Buff: case Effects.AB_FrostBarrier_Pulse: case Effects.AB_FrostBarrier_Recast_Cone: + case Effects.AB_FrostCone_Cone: // Illusion + case Effects.AB_Illusion_Curse_Debuff: case Effects.AB_Illusion_Mosquito_Area_Explosion: case Effects.AB_Illusion_Mosquito_Summon: case Effects.AB_Illusion_PhantomAegis_SpellMod_Explode: @@ -332,8 +343,8 @@ public static GlobalMasterySystem.MasteryType GetMasteryTypeForEffect(int effect case Effects.AB_Unholy_WardOfTheDamned_Recast_Cone: case Effects.AB_Unholy_WardOfTheDamned_Buff: return GlobalMasterySystem.MasteryType.Spell; - case Effects.AB_Shapeshift_Bear_MeleeAttack_Hit: // Should this give unarmed mastery? - case Effects.AB_Bear_Shapeshift_AreaAttack_Hit: // Should this give unarmed mastery? + case Effects.AB_Shapeshift_Bear_MeleeAttack_Hit: + case Effects.AB_Bear_Shapeshift_AreaAttack_Hit: return GlobalMasterySystem.MasteryType.WeaponClaws; // Effects that shouldn't do anything to mastery. case Effects.AB_FeedBoss_03_Complete_AreaDamage: // Boss death explosion @@ -405,7 +416,7 @@ public static GlobalMasterySystem.MasteryType GetMasteryTypeForEffect(int effect case Buffs.Buff_General_Corruption_Area_Debuff_T01_Healing: case Buffs.Buff_General_Corruption_Area_T01: case Buffs.Buff_General_Corruption_Area_T01_Healing: - Plugin.Log(Plugin.LogSystem.Mastery, LogLevel.Warning, $"{effect} has been through mastery type as being ignored - check this"); + Plugin.Log(Plugin.LogSystem.Mastery, LogLevel.Info, $"{effect} has been through mastery helper as being ignored - check this"); ignore = true; return GlobalMasterySystem.MasteryType.None; // As these are DoTs, discard them @@ -424,6 +435,8 @@ public static GlobalMasterySystem.MasteryType GetMasteryTypeForEffect(int effect case (int)Units.CHAR_Gloomrot_SpiderTank_Zapper: case (int)Units.CHAR_Unholy_SkeletonWarrior_Summon: case (int)Units.CHAR_Gloomrot_TractorBeamer: + case (int)Effects.AB_Vampire_Horse_Severance_Buff: + Plugin.Log(Plugin.LogSystem.Mastery, LogLevel.Info, $"{effect} has been through mastery helper as being ignored - check this"); ignore = true; return GlobalMasterySystem.MasteryType.None; }